so逆向深化及IDA静态分析-3 :
IDA静态分析之so逆向进阶实战
本文介绍一个CackMe的分析过程,不再是单纯的分析逻辑,还包括还原算法。
<该样本为个人编写,如果引用请提前告知,谢谢>
0x1.java层分析
我们首先打开样本,了解一下情况,方便确认突破口。
左侧图为打开后的界面,右侧为输入任意密码并提交后的界面,此时我们可以定位首个关键字 “密码错误”。
接下来我们将样本拖拽到AndroidKiller之中逆向,然后文本转Unicode,搜索该关键字:
搜索到关键字后,我们可以借助其java源码协助分析,也可以直接分析smali。下面以java源码为例:
在Android Killer中点击java源码对应的图标,打开jd-GUI查看该样本的java源码。
根据上图步骤一步步定位到了关键函数setCode,我们进一步追踪。
最终定位到native函数setCode,并确定其所在的so文件为“libJniSoDemo.so”。
0x2.so层分析
定位到so文件的native函数后,我们开始分析so文件(以此路径为例>SoDemo_killer>Project>lib>armeabi-v7a),
将其拖入IDA后,在Exports一栏找到setCode函数
双击查看函数中的ARM指令如下:
接下来我们看下这段ARM指令(具体指令可查询之前共享的指令集或者百度):
.text:00000EA4 EXPORT Java_com_kanxue_sodemo_jnisodemo_setCode
.text:00000EA4 Java_com_kanxue_sodemo_jnisodemo_setCode
.text:00000EA4 ; DATA XREF: LOAD:000001BC↑o
.text:00000EA4 ; __unwind {
.text:00000EA4 MOVS R0, #0 // R0=0
.text:00000EA6 CMP R3, #3 // 比较R3与3
.text:00000EA8 BNE locret_EEA // 如果R3≠3,跳转到locret_EEA
.text:00000EAA SUB.W R1, R2, #0x1F4 // R1=R2-500
.text:00000EAE CMP R1, #0x63 ; 'c' // 比较R1和99
.text:00000EB0 BHI locret_EEA // 如果R1大于99,跳转到locret_EEA
.text:00000EB2 MOV R0, #0x66666667 // R0=0x66666667
.text:00000EBA SMMUL.W R0, R1, R0 // R0=R1*R0
.text:00000EBE MOV R1, #0x51EB851F // R1=0x51EB851F
.text:00000EC6 SMMUL.W R1, R2, R1 // R1=R2*R1
.text:00000ECA ASRS R3, R0, #2 // R3=(R0>>2)
.text:00000ECC ADD.W R12, R3, R0,LSR#31 // R12=R3+(R0>>31)
.text:00000ED0 ASRS R0, R1, #5 // R0=(R1>>5)
.text:00000ED2 ADD.W R1, R0, R1,LSR#31 // R1=R0+(R1>>31)
.text:00000ED6 SUBS R3, R1, #3 // R3=R1-3
.text:00000ED8 MOVS R0, #0 // R0=0
.text:00000EDA CMP R12, R3 // 比较R12和R3
.text:00000EDC IT NE // IT(If-Then) NE(Not-Equal) 如果不相等则执行下一句
.text:00000EDE BXNE LR // 承接上一句的条件,函数返回
.text:00000EE0 SUBW R2, R2, #0x203 // R2=R2-515
.text:00000EE4 CMP R2, R1 // 比较R2和R1
.text:00000EE6 IT EQ // 如果相等则执行下一句
.text:00000EE8 MOVEQ R0, #1 // 承接上一句的条件,R0=1
.text:00000EEA
.text:00000EEA locret_EEA ; CODE XREF: Java_com_kanxue_sodemo_jnisodemo_setCode+4↑j
.text:00000EEA ; Java_com_kanxue_sodemo_jnisodemo_setCode+C↑j
.text:00000EEA BX LR // 函数返回
.text:00000EEA ; End of function Java_com_kanxue_sodemo_jnisodemo_setCode
可参考伪代码插件,按下F5,看到C代码如下:
在函数中,我们只看到了a3和a4,显然a3和a4是我们传入给setCode的两个参数。
参考jd-GUI中的java源码,我们可以得知两个参数是什么。
在setCode中,首先判断了位数是否为3,即 a4 == 3
然后判断了第一位是否为5,即 (a3-500)≤ 99
不同时满足以上两个,则返回0,即 密码有三位,且第一位是5。
后面 if ( (a3 - 500) / 10 == a3 / 100 - 3 && a3 - 515 == a3 / 100 )
则是判断第二位是2,第三位是0,得出密码为520。
以上是算法分析,如果是单纯逻辑分析的话,可以修改逻辑一直返回1,或者修改判断条件,本文重点是算法分析,此处不再赘述。
0x3.算法还原
在算出520的时候,我们已经对算法进行了还原。主要是几个固定条件:
① 密码长度 a4 = 3 ;
② (a3 - 500) ≤ 99 ;
③
(a3 - 500) / 10 = a3 / 100 - 3 ;
④
a3 - 515 = a3 / 100 。
以上算法比较简单就不需要单独写程序来算出密码了,对于比较复杂的运算我们需要编写程序算出密码,也就是所谓的注册机。
0x4.总结
在静态分析中,我们通常从java层入手,顺着逻辑追踪到so层,再对so层进行分析,结合java层的函数找出我们需要的算法,
必要的时候根据密码验证算法进行逆运算,导出密码。