-
-
[原创]第2题解题思路
-
发表于: 2015-1-26 19:50 3227
-
0x00
先用dex2jar将classes.dex转化为classes_dex2jar.jar,查看反编译得到的代码发现定义了securityCheck这个native方法和动态加载了crackme这个so文件,所以接下来的工作就是要重点研究libcrackme.so这个文件了。用apktool反编译apk,在AndroidManifest.xml的application节点中添加android:debuggable="true",然后再重新打包生成apk。
0x01
将apk跑了一遍,查看logcat中的日志,并没有发现有价值的线索。于是将libcrackme.so加载到IDA中进行静态分析。然后就看到了一个很熟悉的函数__android_log_print,如图1所示:
图1 静态分析得到关键代码
看到这个函数后我感觉这块代码应该是关键,需要重点分析。
然后顺着往下看,然后在off_628C处发现了惊喜!该处存放着一个字符串
”wojiushidaan”。。。如图2所示:
图2 关键词wojiushidaan
这难道就是答案?不管怎样,将”wojiushidaan”输入到输入框中,弹出显示“验证码校验失败”的toast。看来”wojiushidaan”是骗人的 ╮(╯▽╰)╭继续分析后面的汇编代码,可以看到代码块如图3所示:
图3 比较两个字符串的汇编代码
从上面的代码可以看出,R2寄存器存放着正确开机密码的内存地址,而R0寄存器则存放着用户输入的字符串的内存地址。loc_12A8代码块是一个循环语句,该循环每次都从R2寄存器保存的内存地址中读取一个字节,保存到R3中;从R0寄存器保存的内存地址中读取一个字节,保存到R1中;然后比较R3和R1中的值,如果二者不相等,则跳转到loc_12D0,如果二者相等,则将R2和R0寄存器中的值加1,指向各自对应字符串的下一个字节,然后继续跳转到loc_12A8进行比较,直至正确开机密码中的字符全部读取完毕为止。所以可以看出这里是对用户输入的字符串与系统保存的正确开机密码进行比较,比较结果最后保存到R1寄存器中。由此可以确定这里是整个程序的核心代码,在这里下个断点,动态调试libcrackme.so,仔细查看内存和寄存器中的内容,应该就能找到正确的答案了。
0x02
既然找到了突破点,那就下断点动态调试吧。但是没有我想的那么简单,每次apk刚加载完libcrackme.so,ida就异常退出了,根本没办法进行动态调试。看来libcrackme.so中肯定做了什么操作,触发了某些代码后就使进程异常退出。之前在看一篇脱爱加密壳的文章(文章链接:http://1.honebl.sinaapp.com/?p=243)中,就有提到过反调试。这篇文章中提到:非调试状态下,TracerPid值为零,而在调试状态下此值就是调试器的pid,aijiami会在so里检测当前运行状态。这一点我们可以通过在检测之前,对TracerPid清零绕过它的检测。
看到这里,我想到了一个办法: 既然要保证TracerPid值为零,那么在libcrackme.so中必然会有与0进行比较的CMP语句,而这些CMP语句后面一般会跟着BNE或者BEQ之类的语句。我的想法是找到这些BEQ语句,将它们全部改为B语句。
那就按照文章所提到的方法,在libc.so模块的 fopen函数 ,fgets函数中下断点。
然后动态调试程序,和以前相比,这次在加载完libcrackme.so后,IDA没有再异常退出了。。。~~~~(>_<)~~~~ 然后按F7调试程序,实时关注内存和寄存器中的内容。在libcrackme.so加载到内存后,在偏移地址为12A0的地方加断点。然后继续跟踪内存和寄存器中的值。发现首先进入到libcrackme.so中的偏移地址为1450处的地方,而这条代码在函数sub130c中,所以打开另一个ida,加载libcrackme.so后,重点静态分析sub130c这个函数。在进行动态调试的时候,在运行到某个内存地址时,程序就无法正常运行了,好像进入到了死循环。后来发现这条代码在libcrackme.so中的偏移地址为15F8,如图4所示:
图4 出现异常的代码块
从上面可以看到有CMP R0, #0指令,于是猜测这里可能就是检测TracerPid的代码段。仔细这个代码块的下一个代码块为loc_161C,如下图所示:
图5 loc_161C 代码块
从上图发现,有一个箭头直接指向loc_161C代码块,如下图所示:
图6 直接指向loc_161c 的代码块
从上图可以看出,这里有CMP R0,#0 和 BEQ loc_161c语句。
查看整个函数的结构,我猜测这里也是检测TracerPid的代码块,而且这个代码块最先检测TracerPid,如果在这里将该代码块中的BEQ loc_161c改为B loc_161c,也许就能跳过TracerPid的检测。于是我就将这里的BEQ loc_161c改为B loc_161c语句。即将6F 00 00 0A改为6F 00 00 EA如下图所示:
图7 修改BEQ loc_161c
然后,重现打包运行,并进行动态调试,最后成功在核心代码处断点成功。然后查看R2寄存器所存地址所对应的字符串。如下图所示:
图8 成功获取密码
至此,分析完毕,感觉写文档好难╮(╯▽╰)╭
先用dex2jar将classes.dex转化为classes_dex2jar.jar,查看反编译得到的代码发现定义了securityCheck这个native方法和动态加载了crackme这个so文件,所以接下来的工作就是要重点研究libcrackme.so这个文件了。用apktool反编译apk,在AndroidManifest.xml的application节点中添加android:debuggable="true",然后再重新打包生成apk。
0x01
将apk跑了一遍,查看logcat中的日志,并没有发现有价值的线索。于是将libcrackme.so加载到IDA中进行静态分析。然后就看到了一个很熟悉的函数__android_log_print,如图1所示:
图1 静态分析得到关键代码
看到这个函数后我感觉这块代码应该是关键,需要重点分析。
然后顺着往下看,然后在off_628C处发现了惊喜!该处存放着一个字符串
”wojiushidaan”。。。如图2所示:
图2 关键词wojiushidaan
这难道就是答案?不管怎样,将”wojiushidaan”输入到输入框中,弹出显示“验证码校验失败”的toast。看来”wojiushidaan”是骗人的 ╮(╯▽╰)╭继续分析后面的汇编代码,可以看到代码块如图3所示:
图3 比较两个字符串的汇编代码
从上面的代码可以看出,R2寄存器存放着正确开机密码的内存地址,而R0寄存器则存放着用户输入的字符串的内存地址。loc_12A8代码块是一个循环语句,该循环每次都从R2寄存器保存的内存地址中读取一个字节,保存到R3中;从R0寄存器保存的内存地址中读取一个字节,保存到R1中;然后比较R3和R1中的值,如果二者不相等,则跳转到loc_12D0,如果二者相等,则将R2和R0寄存器中的值加1,指向各自对应字符串的下一个字节,然后继续跳转到loc_12A8进行比较,直至正确开机密码中的字符全部读取完毕为止。所以可以看出这里是对用户输入的字符串与系统保存的正确开机密码进行比较,比较结果最后保存到R1寄存器中。由此可以确定这里是整个程序的核心代码,在这里下个断点,动态调试libcrackme.so,仔细查看内存和寄存器中的内容,应该就能找到正确的答案了。
0x02
既然找到了突破点,那就下断点动态调试吧。但是没有我想的那么简单,每次apk刚加载完libcrackme.so,ida就异常退出了,根本没办法进行动态调试。看来libcrackme.so中肯定做了什么操作,触发了某些代码后就使进程异常退出。之前在看一篇脱爱加密壳的文章(文章链接:http://1.honebl.sinaapp.com/?p=243)中,就有提到过反调试。这篇文章中提到:非调试状态下,TracerPid值为零,而在调试状态下此值就是调试器的pid,aijiami会在so里检测当前运行状态。这一点我们可以通过在检测之前,对TracerPid清零绕过它的检测。
看到这里,我想到了一个办法: 既然要保证TracerPid值为零,那么在libcrackme.so中必然会有与0进行比较的CMP语句,而这些CMP语句后面一般会跟着BNE或者BEQ之类的语句。我的想法是找到这些BEQ语句,将它们全部改为B语句。
那就按照文章所提到的方法,在libc.so模块的 fopen函数 ,fgets函数中下断点。
然后动态调试程序,和以前相比,这次在加载完libcrackme.so后,IDA没有再异常退出了。。。~~~~(>_<)~~~~ 然后按F7调试程序,实时关注内存和寄存器中的内容。在libcrackme.so加载到内存后,在偏移地址为12A0的地方加断点。然后继续跟踪内存和寄存器中的值。发现首先进入到libcrackme.so中的偏移地址为1450处的地方,而这条代码在函数sub130c中,所以打开另一个ida,加载libcrackme.so后,重点静态分析sub130c这个函数。在进行动态调试的时候,在运行到某个内存地址时,程序就无法正常运行了,好像进入到了死循环。后来发现这条代码在libcrackme.so中的偏移地址为15F8,如图4所示:
图4 出现异常的代码块
从上面可以看到有CMP R0, #0指令,于是猜测这里可能就是检测TracerPid的代码段。仔细这个代码块的下一个代码块为loc_161C,如下图所示:
图5 loc_161C 代码块
从上图发现,有一个箭头直接指向loc_161C代码块,如下图所示:
图6 直接指向loc_161c 的代码块
从上图可以看出,这里有CMP R0,#0 和 BEQ loc_161c语句。
查看整个函数的结构,我猜测这里也是检测TracerPid的代码块,而且这个代码块最先检测TracerPid,如果在这里将该代码块中的BEQ loc_161c改为B loc_161c,也许就能跳过TracerPid的检测。于是我就将这里的BEQ loc_161c改为B loc_161c语句。即将6F 00 00 0A改为6F 00 00 EA如下图所示:
图7 修改BEQ loc_161c
然后,重现打包运行,并进行动态调试,最后成功在核心代码处断点成功。然后查看R2寄存器所存地址所对应的字符串。如下图所示:
图8 成功获取密码
至此,分析完毕,感觉写文档好难╮(╯▽╰)╭
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
- [原创]第2题解题思路 3228
- [原创]第1题解题思路 2192
谁下载
谁下载
谁下载
谁下载
看原图
赞赏
雪币:
留言: