CrackMe1、2分析和逆向的过程
1. CrackMe1、2相关信息
CrackMe1
1、CrackMe1是一个ELF可执行文件,可在Android中独立执行
2、通过adb(Android SDK中默认带有adb工具)将CrackMe1 push到远程Android设备中,建议放在/data/local/tmp目录下
3、打开adb shell,执行su命令进入root权限的shell,使用“chmod 777 /data/local/tmp/CrackMe1”命令给予CrackMe1可执行权限
4、在shell中执行CrackMe1程序,提示"Input Your Answer"
5、输入正确字符串,回车,如果程序输出"True Answer"则表示通过,输出"Wrong Answer"则表示失败
CrackMe2(加壳反调试版本)
CrackMe2与CrackMe1相同,通过adb push到设备中输入正确的答案,如果程序输出"True Answer"则表示通过,输出"Wrong Answer"则表示失败,
CrackMe1
概述
本人首先是对该elf文件进行了简单的逆向分析,发现静态分析什么也看不出来,猜测应该是加了代码混淆,因此决定对该文件进行动态分析。
在配置好调试环境后,我使用ida对运行在安卓虚拟机上的CrackMe1进行动态调试。
在调试过程中,发现有另外的反调试程序阻止调试,以及有混淆密码。
最终通过修改反调试程序的代码以及加断点的方式。成功破解出正确的字符串为:GameSecurity,并成功通过程序测试。
以下为详细的逆向分析过程。
CrackMe1逆向分析过程
静态分析
首先打开ida导入文件进行静态分析,发现main函数的反汇编结果逻辑并不清晰,应该是加了代码混淆。因此静态分析无法起到作用,应该进行动态调试。
然后查看导入表中用到的函数
推测程序可能是通过strncmp和strlen函数进行字符串判定的,因此准备在动态调试过程中为这两个函数下断点。
ida动态调试
在Android studio上安装arm架构的安卓虚拟机,然后在windows上配置adb,通过android_server作为桥梁进行远程调试,使用ida的Debugger的Attach to process功能附加到进程CrackMe1上进行远程调试。
杀掉反调试程序
在调试过程中还有一个问题就是为上述推测的函数加断点后,在后续调试过程中程序会自动退出(有反调试程序),猜测是程序在运行时打开了某一程序进行反调试的检测。因此决定对linux下的open函数加断点(看是否在中间打开了某些进程)
果然,程序继续运行后在open处断开,这时查看栈的参数,并查看对应的二进制代码,发现open函数确实调用了进程,也就是前面遇到的反调试程序
可以看到open函数调用了proc/4821/status 程序阻止调试,因此在这里决定将其修改,以达到继续调试的目的。
将二进制代码随便做出修改,只要open函数无法调用即可。
然后对strlen函数和strncmp函数加断点,继续运行程序。
strlen函数分析
首先程序在strlen函数处断开,查看相关寄存器的内容,看有没有疑似的可疑密码。
发现R4寄存器是我们输入的字符串111,R6寄存器是一串可疑的字符串。
R4
R6
然后在这里猜测是用strlen函数将这两个字符串长度做了对比,怀疑正确的字符串就是0wPBYEQGDjFOpeiKFxHqEQ== 。但是在验证后发现不对,因此只能再试一下strncmp函数。
strncmp函数分析
程序在strncmp处断开后,查看相应寄存器的内容。
发现R4寄存器中是我们输入的字符串111
而R5寄存器中存放可疑字符串GameSecurity。
于是猜测strncmp将这两个字符串进行比对,从而输出结果,因此猜测正确的字符串就是GameSecurity。
验证结果
在有了以上的判断之后,我重新打开程序,输入GameSecurity,这次果然验证通过。
正确的字符串就是GameSecurity。
CrackMe2
概述
对于CrackMe2,分析起来并没有CrackMe1那么容易,在对其进行脱壳后,我用处理CrackMe1的方式处理CrackMe2。CrackMe2在脱壳后运行时会检测默认的23946端口进行反调试,在修改端口之后我按照CrackMe1的方式进行调试,发现除了CrackMe1的反调试程序之外,应该还有另外的手段进行反调试,导致我在输入字符串处和strncmp处所加断点无效,遗憾的是由于技术原因,我并没有找到另外的反调试手段,CrackMe2也没有破解出来,以下是我已经做出来的逆向分析过程。
CrackMe2逆向分析过程
脱壳
对于CrackMe2,首先我将CrackMe2在IDA中打开,对其进行静态分析,发现相较于CrackMe1, 静态分析结果缺少很多关键信息,例如导入表,因此猜测是进行了加壳处理。于是利用strings命令发现其确实加壳。
# 执行 strings CrackMe2
## 输出
UPX!
...//此处省略
...//此处省略
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.95 Copyright (C) 1996-2018 the UPX Team. All Rights Reserved. $
可以看到其加了UPX 3.95的壳, 于是准备对其进行脱壳处理。
对文件进行脱壳处理
静态分析
用ida打开脱壳后的文件,查看相应内容。
与1相同,其 main 函数仍然逻辑不太清晰,还是要进行动态调试
查看其导入函数
导入函数中多了popen 和 pclose函数 , 怀疑popen函数对该文件加了新的反调试。
IDA动态调试
android_server换端口
在按照CrackMe1中的方法用ida连接远程进程时,发现程序会自动退出,而如果不运行android_server进行连接,则程序正常。猜测是程序中有判断是否有远程连接的进程,因此决定修改android_server文件名,并修改监听端口。
我将push 到安卓虚拟机上的android_server文件改成server,并修改其监听端口为12345(原为23946),果然,程序正常运行,可以通过ida进行动态调试。
# 原来使用23946端口
adb forward tcp:23946 tcp:23946
#修改为12345端口
adb forward tcp:12345 tcp:12345
在解决了这个问题后,我仍然像1中那样进行动态调试,在为open函数下断点,杀掉反调试程序后,我遇到一个跳不出来的死循环。
在用IDA的F9跳出之后,程序直接退出,如果在printf函数、strncmp函数处下断点,程序直接跳到最后的printf函数,说明代码的逻辑直接跳过了strncmp函数,或者是根本没有用strncmp函数来比对。
于是我为scanf函数下断点,找到了存放输入的地址( 如下图 ),为该地址下断点,准备看是哪里用到了该地址,结果程序还是直接退出,并没有在该处断开,于是我判断是仍有反调试程序在阻止调试,我并没有完全杀掉反调试程序,在经过一番尝试后我还是没有找到继续调试的方法,于是CrackMe2只能到此为止。
初步分析结果
相对CrackMe1,CrackMe2加了壳,并且在运行时会检测是否有远程调试(监听23946端口),并且相对于CrackMe1,除了使用open函数打开proc/4821/status 程序阻止调试外,应该还有另外的反调试程序,阻止动态调试,该程序在检测到有调试时会跳过strncmp的比较,导致我加断点并没有作用,并且我在输入的字符串处加的断点也没有作用。
有点遗憾,我并没有完成CrackMe2,不过还是尝试了一下,我觉得这个过程还是很有意义的。
时会检测是否有远程调试(监听23946端口),并且相对于CrackMe1,除了使用open函数打开proc/4821/status 程序阻止调试外,应该还有另外的反调试程序,阻止动态调试,该程序在检测到有调试时会跳过strncmp的比较,导致我加断点并没有作用,并且我在输入的字符串处加的断点也没有作用。
有点遗憾,我并没有完成CrackMe2,不过还是尝试了一下,我觉得这个过程还是很有意义的。