寻找加密入口


定位到 libcryptoDD.so文件
ida打开查看,发现不是静态注册
直接丢入unidbg,不做任何开启日志打印一下,发现了它的动态注册
 

图片描述


地址是0x41ed8, 上ida中按下G, 跳转到这个地址,到此我们发现了so中函数的入口

判断aes加密是什么类型

理论部分

  • ECB(Electronic Codebook)模式:
    • ECB模式将数据分成块,然后对每个块进行独立的加密,不考虑上下文。这意味着相同的明文块会产生相同的密文块

      将明文分组,解密后直接成为密文分组,分组之间没有关系

  • CBC(Cipher Block Chaining)模式:
    • CBC模式使用前一个块的密文作为当前块的初始向量(IV),从而在相同的明文块和相同的密钥下产生不同的密文块。这增加了安全性,因为每个块的加密依赖于前一个块的密文。CBC模式适用于大多数加密应用,包括文件加密和网络通信。

这里我是使用frida, hook,先打印一下参数

1

2

3

4

5

6

7

    let CryptoHelper = Java.use("com.luckincoffee.safeboxlib.CryptoHelper");

    CryptoHelper["localAESWork"].implementation = function (bArr, i10, bArr2) {

        console.log(`CryptoHelper.localAESWork is called: bArr=${bArr}, i10=${i10}, bArr2=${bArr2}`);

        let result = this["localAESWork"](bArr, i10, bArr2);

        // console.log(`CryptoHelper.localAESWork result=${result}`);

        return result;

    };

发现实际请求中 bArr2是固定的,且长度是32, 合理怀疑是key, 或者iv

而i10值有时候是2, 有时候是3, 这个分析java层代码可以知道,应该就是标识不同类型的请求的

所bArr这里就是我们的input_data, 我们自己构造加密判断一下它到底是ecb还是cbc

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

    var fragInstances = [];

    // 要查找的类名

    const targetClassName = 'com.luckincoffee.safeboxlib.CryptoHelper';

    console.log(`[+] 开始扫描堆,查找所有 ${targetClassName} 实例...`);

    Java.choose(targetClassName, {

        onMatch: function (instance) {

            fragInstances.push(instance);

        },

        onComplete: function () { }

    });

    var frag = fragInstances && fragInstances.length > 0 ? fragInstances[0] : null;

    let v1 = Java.array('byte', new Array(32).fill(0))

    let v2 = 2

    let v3 = Java.array('byte', [-39,-11,119,92,32,-11,-15,28,107,-40,-69,-126,113,-96,42,-30,7,64,65,79,-113,48,84,98,-86,49,-120,-43,105,70,-49,55]);

    let res = frag.localAESWork(v1,v2,v3)

    console.log("res:", res)

返回内容如下:
 

图片描述


至此, 可以得知,他是ecb加密,而且是128位的分组加密

unidbg简单调试返回内容

将参数增加,hook调用一下so中的localAESWork这个函数看看是否存在问题

图片描述

看到了出现了问题,这时候打印一下trace日志,看看问题出现的具体位置

1

androidEmulator.traceCode(cryptoDDmodule.base, cryptoDDmodule.base + cryptoDDmodule.size);

图片描述

可以清晰的看到,pc指针执行到0x17e6c的位置的时候,出现了错误
我们直接到ida中按下G, 找到这个位置看看具体什么情况

图片描述


看到了,他是一个free函数
而unidbg本质是无法处理free函数的(虽然有的so中有free它有时候不报错,好像是因为malloc和free同时使用的原因???)
所以这里我们在unidbg中直接hook掉free函数的使用看看

1

2

3

4

5

6

7

8

9

10

11

12

13

public void hookZz_hook_free_func() { 

    System.out.println("hookZz_hook_free_func"); 

    // hook free函数 

    HookZz hookZz = HookZz.getInstance(androidEmulator); 

    Module module = memory.findModule("libc.so"); 

    hookZz.replace(module.findSymbolByName("free").getAddress(), new ReplaceCallback() { 

        @Override 

        public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) { 

            return HookStatus.RET(emulator, context.getLR()); 

            // return super.onCall(emulator, context, originFunction); 

        } 

    }); 

}

再次运行发现成功返回值

图片描述

此时,使用unidbg打印一次加密的完整trace留待后用

unidbg + ida算法分析

返回值: 9b4174988fdd7be26d28bb9d970b63b9
trace文件也拿到了

直接在trace文件中查找 0xb9 这个关键词,然后从后往前看,可以发现:

直接根据trace中这些点的pc地址,在ida中查找,可以找到这个位置

发现代码中存在大量的while, if, elseif 等控制语句
这种情况就是内部进行了控制流平坦化的混淆


这里代码就对应了起来,这个函数是sub_189C4,在这里用unidbg console debugger下断点简单查看下


其参数x0寄存器中存储的就是input_data值,

所以,sub_189C4这里应该就是aes函数的主要逻辑部分了

sub_189C4函数分析

这里面的代码也是混淆过的,不太容易看出来具体逻辑
但是发现其中有一些高频出现的函数,比如


这就和aes中的分组加密有点相似的意思了。

详细具体的查看一下几个高频函数内部逻辑

sub_219CC

其中几乎都是异或操作,
是轮密钥加逻辑的可能性比较大

sub_22810

大量异或操作,
怀疑轮密钥加过程,也可能是列混淆过程

sub_223E0

看着有点像是行行位移操作

sub_21BEC

这个就很明显了,字节代换

图片描述

段落引用
aes有9轮循环运算和1轮最终轮运算,
循环运算中又有四个板块 :字节代换,行位移,列混淆,轮密钥加
最终轮缺少 列混淆

我需要查看一下一个加密过程中,这四个函数分别都被调用了多少次

直接在trace文件中进行搜索
0x219cc
0x223e0
0x21bec
0x22810
已经确定了sub_21BEC是字节代换的流程,先查找pc指针到0x21bec的次数
 

图片描述


可以看到是10次
同理查找其他函数的次数,发现
0x219cc 33次
0x223e0 10次
0x21bec 10次
0x22810 9次
重点查看下0x219cc 次数这个,因为字节代换都是从77841行开始,所以77841行之前的0x219cc的计数不能算,
减去的话,就是刚好10次

至此,这四个函数的整体逻辑也算是明白了

白盒AES差分攻击

这时候已经知道了四轮过程,只要通过dfa差分攻击即刻获取到aes的密钥值

到这里算法分析就算是结束了,至于差分攻击如何使用,可以详细问问chatgpt

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐