1.先抓包,抓两次包对比知道了。有q和sign是加密的,
2.然后通过hashmap定位到这里
3.在往上跟一下,就可以看见加密得地方了,我就直接贴出来了
4.打开ida发现是动态注册,通过动态注册函数脚本定位到地址:
name: localAESWork sig: ([BI[B)[B module_name: libcryptoDD.so offset: 0x1984d
name: localConnectWork sig: ([B[B)[B module_name: libcryptoDD.so offset: 0x1978d
name: md5_crypt sig: ([BI)[B module_name: libcryptoDD.so offset: 0x1a981
name: localAESWork4Api sig: ([BI)[B module_name: libcryptoDD.so offset: 0x1b1cd
5.首先看aes得加密,在函数里面找一下就发现了疑似aes加密得函数
很明显这里是,在这里就可以dfa攻击,这里得r0猜测就是state块
debugger.addBreakPoint(module.base + 0x14F98 + 1, new BreakPointCallback() {
int round = 0;
//0xbffff678,这个地址是state块的地址,把debug打上看看state块的地址是多少,记住明文不能变,变了state块地址就会变
UnidbgPointer pointerArg;
@Override
public boolean onHit(Emulator<?> emulator, long address) {
RegisterContext context = emulator.getContext();
pointerArg = context.getPointerArg(0);
round += 1;
// System.out.println("次数:"+round);
if (round % 9 == 0) {
pointerArg.setByte(randInt(0, 15), (byte) randInt(0, 0xff));
}
return true;//返回true 就不会在控制台断住
}
});
取到足够多密文后就可以还原出真实密钥了,因为是ecb模式,所以没有iv,
可以通过hook这里得到明文和返回值,先打上断点,获取到返回值得地址,在按blr,后按c,在m(返回值地址)就可以获取到正确密文了
接下来看md5的加密,很容易定位到这个函数
接下来跟踪到这个函数,看了一遍,没有md5找到64轮的特征,
对这个函数进行断点,把输入和输出都都打印一下,还好通过密文对比,发现是标准md5。
然后就看见有一个函数对md5加密值进行了处理
把这个丢给gpt分析下,不过要加上一句要和c的语义保持一致,否则会有问题,在这里我踩坑了
def md5(hex_str1):
def hex_string_to_byte_sequence(hex_str):
# 将十六进制字符串转换为字节序列
byte_sequence = []
for i in range(0, len(hex_str), 2):
byte_value = int(hex_str[i:i+2], 16)
byte_sequence.append(byte_value)
return byte_sequence
def bytesToInt(src, offset):
result=(src[offset + 1] << 16) | (src[offset] << 24) | (src[offset + 2] << 8) | src[offset + 3]
result &= 0xffffffff
if result & 0x80000000:
result = -((result ^ 0xffffffff) + 1)
if result<0:
result = -result
return result
# 十六进制字符串入参
# 转换为byte_sequence
byte_sequence = hex_string_to_byte_sequence(hex_str1)
# 计算结果
offsets = [0, 4, 8, 12]
results = [bytesToInt(byte_sequence, offset) for offset in offsets]
print(results)
v = ''.join(map(str, results))
return v
到这里2个加密都完成了。