这期内容当中小编将会给大家带来有关so静态分析中CreakeMe的分析思路是什么 ,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
拿到一个CreakeMe,写一个分析思路。CreakMe主要是对.so文件内容进行分析,当然很多学习Android逆向的在分析到smali代码的时候就已经停止脚步了。在接触到.so文件的时候才是开始进一步的逆向学习,当然这里就要学习ARM汇编了。关于ARM汇编在网上有很多的资料,这里就不再赘述。
请使用:HAI手册
尝试使用App得出这些结论。
1.我们需要一个key。
2.这个key是数字。
逆向拿到smali代码。
工具:Android Killer。
找到入口MainActivity。
我们看到这里有一段代码:
这段代码的作用就是调用so文件库。我们猜测这个App很有可能把关键key写在了so文件里。
我们从onClick方法定位到关键点。
这里是判断正误的地方,这里看到如果v0和v2的值不相等的话就跳转。并且这里v2的值是1。
我们向上看。
这里有一个调用方法。
在这里我们看到这个是Native层的方法。并且这个方法会返回一个int数据,这里猜测可能会是0或者1。在这里还有一个就是传入的是一个int型数据,根据我们之前的测试,知道这里就是我们从输入框输入的内容。
监听事件——输入key——key方法判断——返回0或1
1为正确,0为错误。
但是我们依然没有找到Key的是指内容。
so逆向
使用工具:ida
找到关键的Key函数。
这里可以看到ARM汇编比smali难的可不是一个度两个度。
为了提升能力,我们还是一句一句的分析。如果是学习的话,请不要依赖F5。
PUSH {R7,LR}
把R7寄存器和LR入栈。
R7的含义就是指向前一个保存的栈帧和链接寄存器在栈上的地址。
这里可能会对LR的作用不知道,简单的说一下,LR的作用一个是保存子程序的返回地址。还有一个是当异常发生时,LR中保存的值等于异常发生时PC的值减4。LR相当于是一个备份。
MOV R7, SP
这里的含义就是标志着caller栈帧的结束及callee的栈帧的开始。相当于是参数准备就绪,我们可以开始执行程序了。
SUB SP, SP, #0x20
这里是给子程序开辟空间。
以上三步结束的时候ARM开始调用部分就结束了。
MOV R3, R2
R2的值给R3。
MOV R12, R1
R1的值给R12
MOV LR, R0
R0=LR。
STR R0, [SP,#0x28+var_10]STR R1, [SP,#0x28+var_14]STR R2, [SP,#0x28+var_18]
这三句一起看,意思就是把R0,R1,R2放入栈中。位置分别是,18,14,10。
LDR R0, [SP,#0x28+var_18]
把栈上10位置的内容拿下来给R0寄存器,我们栈上10的位置是R2。相当于是R0=R2。
MOVS R1, #0x80
R1赋值为80,这里movs和mov的区别在于movs会更改N,Z,C标志。N=0代表整数或者0,N=1代表是整数。此时R1>30,所以N为0。Z表示运算结果。R1不为0则z=1;C标志位一般不会通过加减改变。
STR R0, [SP,#0x28+var_1C]
把R0的内容放在栈C。
MOV R0, R1 ; int
R1的值给R0。
STR R3, [SP,#0x28+var_20]
R3的值原本为R2,这里把这个值放在栈8。
STR.W R12, [SP,#0x28+var_24]
把R12的值放入栈4中。
这里的.W 是wide。指定汇编器必须为这条指令选择一个32位的编码模式。如果办不到,汇编器报错。
STR.W LR, [SP,#0x28+var_28]
LR存入栈0中
BLX j__Z2uri
跳转到 j__Z2uri。这里的注释是ur(int),说明这个函数原型是ur(int)
LDR R1, [SP,#0x28+var_1C]
这里把栈c里的内容放到R1中。这个时候其实我们拿到是我们输入的key。
CMP R1, R0
然后用我们的key 和R0进行比较,这里的R0是最后ur的返回结果。
BNE loc_4490
不一样跳转loc_4490
B loc_448A
否则跳转到loc_448A
这里我们就知道了关键方法就是ur(int)这个了。
最后我们来看一下流程图。
说真的。。。分析这个是真的累,不过进步起来还是非常快的。
PUSH {R7,LR}MOV R7, SPSUB SP, SP, #0x28
这三行之前说过,相当于ARM在准备阶段。
MOV R1, R0STR R0, [SP,#0x30+var_C]LDR R0, [SP,#0x30+var_C]STR R0, [SP,#0x30+var_10]
这一小部分完成之后的效果就是,R1=R0,栈24的部分存为R0,并且给R0重新复制为栈20
LDR R0, [SP,#0x30+var_C]
把R0从栈24拿出来
STR R0, [SP,#0x30+var_14]
然后把R0的值给栈2C的位置。
这里我们先来看一下流程图。
如果之前自己分析过循环的话就知道这个肯定是一个循环逻辑。而且再循环里还嵌套了循环和if语句。
MOVS R0, #2
把立即数2赋值给R0。
STR R0, [SP,#0x30+var_18]
把2这个立即数给栈18位置。
STR R1, [SP,#0x30+var_1C]
我们的R1原本是R0的值,现在把R1的值给栈14位置。
B loc_42E2
无条件跳转到loc_42E2。
目前位置,总结一下,相当于写了
i=2sp[5]=128
来看loc_42E2部分。
LDR R0, [SP,#0x30+var_18]
从栈18中拿到立即数#2。并且给R0。
MULS R0, R0
将两个理解书相乘。现在状态R0=R0*R0,R0=4;
LDR R1, [SP,#0x30+var_14]
从栈1C中拿出数据,这里的数据之前存的是R0的数据,R0则是128。这里有一个小疑问,为什么这里不从栈14出拿数据。
CMP R0, R1
比较R0和R1
BGT loc_433E
如果大于则跳转loc_433E
B loc_42EE
否则跳转到loc_42EE
这个时候我们来再看看流程图。
主要看框起来的内容,这里有一个分支结束了,证明这一个部分结束了。
而另外一边则会返回loc_42E2,这说明什么情况,这个就是典型的for循环。
如果之后有需要就对所有可能出现的状态逻辑图进行一个梳理。
我们这里先来分析一下 loc_42EE部分。
LDR R0, [SP,#0x30+var_14]
从栈1c处拿到数据。此时栈1c出存的数据是128。16进制显示为80
LDR R1, [SP,#0x30+var_18]
从栈18处拿到数据,此时栈18存储的内容是2。
BL sub_13FCC
跳转到sub_13FCC,并且保存下一条的地址,可以使用mov PC,LR返回原处。
我们先来看sub_13FCC这个子程序。
CMP R1, #0
R1和立即数0进行比较。我们来确定一下R1的数值。
BEQ loc_13FBA
如果相等则跳转loc_13FBA
PUSH.W {R0,R1,LR}
把R0,R1,LR入栈
BL sub_13F0C
跳转sub_13F0C,保存LR。
之后还有很长一串,这里有兴趣的可以继续分析下去。这里直接说明结果就是对128进行取余操作。
128%i
我们还是回到之前的ur方法处继续分析。
CMP R1, #0
比较我们取余的结果。
STR R0, [SP,#0x30+var_20]
把R0的值放入栈10,R0的值是128
BNE loc_4334
如果不相等,则跳转至loc_4334。
B loc_42FE
否则跳转loc_42FE
如果是跳转到loc_4334。
直接进入第二次循环。
如果是跳转到loc_42FE,则进行深一层次的判断。
总的来说这个CreakMe是这样子的
for(int i;i*i<128) { if(128%i==0) { while() { } } }if() { }return ...
整体逻辑结构就是这个了。如果在这个时候进行动态分析的话,也可以很轻松的解决。
经过一些分析,发现这个CreakMe是在进行一个欧拉函数的计算。
就是在计算一个数的和这个数互质的个数。
这里也可以确定到128就是其中内嵌的一个欧拉函数。
那我们很简单自己写一个欧拉函数的计算方法就可以了。
所谓的注册机,就是根据一定的逻辑来推算出正确结果。
这里我们需要写一个程序来完成欧拉函数的计算。
int oula(int number) { int res=number; int a=number; for(int i=2;i*i<=a;i++) { if(a%i==0){ res=res/i*(i-1); while(a%i==0) a/=i; } } if(a>1) res=res/a*(a-1); return res; }
最后128的欧拉函数结果是64。
输入之后
上述就是小编为大家分享的so静态分析中CreakeMe的分析思路是什么 了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。