当前位置:网站首页 > 网络安全培训 > 正文

so静态分析进阶练习——一个CreakeMe的分析思路

freebuffreebuf 2018-06-08 284 0

本文来源:i_春秋

i春秋作家:HAI_

原文来自:https://bbs.ichunqiu.com/thread-41371-1-1.html

说明

拿到一个CreakeMe,写一个分析思路。CreakMe主要是对.so文件内容进行分析,当然很多学习Android逆向的在分析到smali代码的时候就已经停止脚步了。在接触到.so文件的时候才是开始进一步的逆向学习,当然这里就要学习ARM汇编了。关于ARM汇编在网上有很多的资料,这里就不再赘述。

导航

请使用:HAI手册

0x01 分析逻辑

1.初始界面


image.png

2.输入数字


image.png

3.输入字符



4.总结

尝试使用App得出这些结论。
1.我们需要一个key。
2.这个key是数字。

0x02 java层逻辑分析

逆向拿到smali代码。
工具:Android Killer。



1.逻辑分析

找到入口MainActivity。

我们看到这里有一段代码:

image.png这段代码的作用就是调用so文件库。我们猜测这个App很有可能把关键key写在了so文件里。

我们从onClick方法定位到关键点。

image.png这里是判断正误的地方,这里看到如果v0和v2的值不相等的话就跳转。并且这里v2的值是1。

我们向上看。


image.png这里有一个调用方法。

在这里我们看到这个是Native层的方法。并且这个方法会返回一个int数据,这里猜测可能会是0或者1。在这里还有一个就是传入的是一个int型数据,根据我们之前的测试,知道这里就是我们从输入框输入的内容。

image.png

2.逻辑图猜测

监听事件——输入key——key方法判断——返回0或1

1为正确,0为错误。

但是我们依然没有找到Key的是指内容。

0x02 Native层分析

so逆向
使用工具:ida



1. key方法分析

找到关键的Key函数。


image.png

这里可以看到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)这个了。

最后我们来看一下流程图。


image.png

2.ur(int)方法分析

说真的。。。分析这个是真的累,不过进步起来还是非常快的。


image.png

2.1 第一段分析

PUSH            {R7,LR} MOV             R7, SP SUB             SP, SP, #0x28

这三行之前说过,相当于ARM在准备阶段。

MOV             R1, R0 STR             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的位置。

这里我们先来看一下流程图。


image.png

如果之前自己分析过循环的话就知道这个肯定是一个循环逻辑。而且再循环里还嵌套了循环和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=2 sp[5]=128

来看loc_42E2部分。
image.png

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

这个时候我们来再看看流程图。

image.png

主要看框起来的内容,这里有一个分支结束了,证明这一个部分结束了。
而另外一边则会返回loc_42E2,这说明什么情况,这个就是典型的for循环。
如果之后有需要就对所有可能出现的状态逻辑图进行一个梳理。

我们这里先来分析一下 loc_42EE部分。


image.png

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这个子程序。
image.png

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方法处继续分析。

image.png

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。


image.png

直接进入第二次循环。

如果是跳转到loc_42FE,则进行深一层次的判断。

2.2 小结

总的来说这个CreakMe是这样子的

for(int i;i*i128) {         if(128%i==0)         {                 while()                 {                 }                 } } if() {  } return ...

整体逻辑结构就是这个了。如果在这个时候进行动态分析的话,也可以很轻松的解决。

经过一些分析,发现这个CreakMe是在进行一个欧拉函数的计算。

就是在计算一个数的和这个数互质的个数。

这里也可以确定到128就是其中内嵌的一个欧拉函数。

那我们很简单自己写一个欧拉函数的计算方法就可以了。

0x03 注册机编写

所谓的注册机,就是根据一定的逻辑来推算出正确结果。

这里我们需要写一个程序来完成欧拉函数的计算。

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。

输入之后

image.png

以上

i春秋推出优享会员制,开通会员可以免费畅享多类课程、实验、CTF赛题等付费内容,并可享有包括会员日专属福利、就业推荐等多种特权福利,更多活动详情可点击:https://bbs.ichunqiu.com/thread-40795-1-1.html了解哦~

转载请注明来自网盾网络安全培训,本文标题:《so静态分析进阶练习——一个CreakeMe的分析思路》

标签:静态分析creakeme

关于我

欢迎关注微信公众号

关于我们

网络安全培训,黑客培训,渗透培训,ctf,攻防

标签列表