一、逆向分析 在之前已经介绍了最右这款App的签名算法解析第一篇工作,因为签名算法比较多,所以就分开处理,大家如果要看后续文章,一定要记得去看第一篇文章,不然我也不能保证你不懵逼!上一篇解析完了第一部分算法解析工作,这一篇继续操作,首先用IDA打开so查看第二部分代码,同时IDA动态调试so,具体步骤大家一定要去看第一篇内容,这里不再详细说了,我们动态调试到了第二部分加密算法: 看到这段代码和之前的一段其实差不多,然后再看看静态的伪代码: 看到arm指令的代码和伪代码位置不太一致,但是没关系,我们看关键点,比如arm指令的前几行是SUB和AND操作,而且看到是自减4然后和0xF进行与操作: 所以这时候看到伪代码的地方: 所以有时候发现伪代码和动态调试的代码不一致没关系,只要看到特殊值找到对应代码即可,按照之前的规矩,把伪代码拷贝到之前的C代码中: 首先依然是个变量循环四次,每次递增4,然后是之前打印的四个常量值放在R0-R3寄存器中, 我们把伪代码实现之后打印值发现和动态调试的值是一样的,所以这一块就过去了,继续往下看: 这里发现了一个密钥库,还记得之前在第一篇中我们已经发现了一个密钥库长度是64个字节,我们在看到LDR指令的时候一定要留意这个一般都是加载内存中的数据,看到ADD.W R11, R4, #0x40 这个是在之前的密钥库B1E0基础上加上64,也就是说这个密钥库是和B1E0那个内存中挨着的: 然后我们看看内存中的值: 我们再把这个密钥库弄出来即可: 继续往下走就是和之前一篇一样用四个常量值进行与或非操作了: 不过这里需要介绍一个新指令:LDMIA.W 这个指令是一次性从一个地址中连续取出多个值放到寄存器中,与之对应的还有存储指令,而且还有顺序直说,这个指令的详细说明如下: LDM:(load much)多数据加载,将地址上的值加载到寄存器上
STM:(store much)多数据存储,将寄存器的值存到地址上
主要用途:现场保护、数据复制、参数传送等,共有8种模式(前面4种用于数据块的传输,后面4种是堆栈操作)如下:
1》IA: 每次传送后地址加4,其中的寄存器从左到右执行,例如:STMIA R0,{R1,LR} 先存R1,再存LR
2》IB: 每次传送前地址加4,同上
3》DA: 每次传送后地址减4,其中的寄存器从右到左执行,例如:STMDA R0,{R1,LR} 先存LR,再存R1
4》DB:每次传送前地址减4,同上
5》FD: 满递减堆栈 (每次传送前地址减4)
6》FA: 满递增堆栈 (每次传送后地址减4)
7》ED: 空递减堆栈 (每次传送前地址加4)
8》EA: 空递增堆栈 (每次传送后地址加4)
注意:其中在数据块的传输中是STMMDB和LDMIA对应,STMMIA和LDMDB对应,而在堆栈操作是STMFD和LDMFD对应,STMFA和LDMFA对应 比如这里就是从R11寄存器中的地址也就是第二个密钥库E220中连续取出三个四个字节的数据放到R9,R10,R11中,看到上面寄存器中的值在和密钥库比较: 这个指令后面还会用到,需要记住它,让后往下就是与或非操作了: 这里看到一波与或非操作,但是有点坑爹的是中间多了一条穿插指令,所谓穿插指令就是本来流程是正常的,但是中间无意中多了几行指令,发现这些指令的操作结果值不参与后面的指令执行,那么就是指令穿插,比如这里我们分析之前的文章知道一般在ROR操作之前都是BIC+AND+ORR,但是这里突然来了一个BIC,而且BIC的操作结果R4并没有参与ROR的操作,所以就认为他是个穿插指令,需要记住它因为后面肯定在哪个地方需要他。这里看到之前与或非之后的操作R2是B658E0EC,我们打印C代码看看结果是否正确: 看到这里打印结果是正确的,说明我们的第二个密钥库是正确的,后面就是正常的ROR操作了,大部分内容和第一篇类似: 我们打印了C代码的执行结果,而且这里找到了那条穿插指令的位置,再去动态调试查看寄存器值是否正确: 这样看到打印的值就没问题了,然后后面就和之前的一篇文章一样了,就不在多说了,我们最后直接看轮训后的值: 依然是轮训了四次,我们打印一下C代码结果:
二、技术总结看到了四次轮训结果和上面的一模一样,说明加密算法的第二部分分析完了,这里我们也学习到了一些新知识: 第一、新增LSL循环左移指令,LDMIA批量连续读取多个内存数据 第二、对于分析指令的时候如果发现有一些意外的多余指令可以认为是穿插指令,识别穿插指令的方法就是看到这条指令的操作返回值是否参与后续的流程
三、总结我们在分析arm指令的时候,看到LDR指令需要留意,因为可能是在读取内存中的密钥库,见到LSL指令是乘法或者是除法操作,而一般加密算法都会有密钥库,同时发现这个加密算法是分为四个循环部分,但是都是很类似,后面还会继续把第三和第四部分一起分析,敬请期待!
|