这道题涉及了动态调试so、反调试、基本的ARM汇编等等。以下是逆向得到注册码的过程。
app装入模拟器后可以看出,界面依然是逆向获得注册码的类型。
那就找找看校验验证码的地方在哪里吧。将app用解压软件打开,拿出其中的classes.dex文件,拖出静态分析工具JEB中直接分析,得到的JAVA代码如下:
由上面的代码可以看出,app启动后就加载了动态库crackme, 从从这库中导出了本地函数securityCheck,然后流程才到app的入口onCreate函数中。入口函数的代码也不复杂,只是设定了“输入密码”这个按钮的点击监听函数,然后在监听函数中校验验证码,根据校验的结果显示不同的界面。
现在的问题是校验验证码的代码不在dex文件,而在某个库中。再次打开apk文件查看lib目录,发现只有一个动态库:libcrackme.so。同样,将其拖出,然后拖拽进IDA分析(这里使用的IDA是32位7.0版本)。
首先在左边Function name窗口找到securityCheck在库中对应的函数名Java_com_yaotong_crack
me_MainActivity_securityCheck(名字这么长是由so中导出导出函数的命名规则所致)后双击它,然后在右边显示ARM汇编的窗口中就可以用IDA的F5反汇编功把ARM汇编转成C代码,结果如下:
根据so库中有关java导出函数的参数的约定,第一个参数的类型必然是结构体指针JNIEnv*,第二个参数的类型一定是jobject。而导出函数具有3个参数,那么第三个必然是Java代码中本地函数唯一的参数String。不过JNI中没有String类的定义,而是jstring。这也是JNI的规则。
使用IDA对相关类型重新命名后,可读性就好了许多:
3到8行是相关定义,10和11两个赋值在这里对结果没有影响;12行到21行是两个对全局变量的判断语句,不影响后面的功能;22行是打印函数,仍然没有影响到后面检验验证码的过程。真正的代码从23行才开始,前面就暂且当是花指令处理了。
看来事情并没有那么简单。
所以现在的关键就是把偏移off_628C处的字符串从UTF格式转回它原来的格式;或者也可以动态调试让app自己说出来。
动态调试就和模拟器无关了。由于市面上的模拟器多是用x86来模拟arm,总会有这样那样的问题,用真机调试是最为稳妥的。
此次用来调试的安卓机器是Android6.0的Nexus5,是已经root过的。将手机连接到笔记本上,打开手机的调试选项,Nexus5就能成功连接上了。
然后就是安装apk,需要用adb工具提供的选项来安装,如果成功的话如下图所示:
由于apk启动后的内存并不在本机的内存中,而是在手机上,所以不能想exe一样直接用OllyDbg调试exe一样调试,需要借助几个工具:32位的IDA以及android_server(在IDA安装目录下的dbgsrv目录)。
在本机上打开IDA,android_server则需要推送到真机上运行:
仅是这样IDA还无法连接到它,android_server只是监听在手机的23946端口上而已,还不了解是那种协议,只能看看了。
android_server拖进IDA,左边函数列表窗口选中main(可执行程序默认入口)并跳转过去,为了节省时间点击函数名用F5功能把代码解析C代码。可以发现在248行出现了一个可疑的j_accept函数:
果然是accept函数,毫无疑问是tcp协议的服务器。为了让IDA能调试,必须要用adb把本机的23946端口转发到手机的23946端口上:
若要测试端口是否被成功监听了,可以使用命令查看:
下一步,让app加载到内存中,以被调试的方式启动。Win32下的调试是让调试器以调试的方式打开,Android下也一样,不过使用的是adb工具:
此时被调试的手机就会黑屏,然后弹出一个标题为“Waitting For Debugger”。接下来只需要让调试器附加到这个app上去。启动IDA,然后在菜单栏找到Debugger,打开选中Attach项,再点击它的子菜单中的Remote ARMLinux\Android Debugger,就会弹出一个对话框:
对话框的设置按上图的设定即可,点击OK,就有新的对话框用来选择被调试的进程:
按照app的包名不难找到目标进程。双击它,IDA会卡住几秒,然后换成了类似OD的调试界面:
现在是断点怎么停在securityCheck函数的问题。这个函数由库libcrackme.so导出,用快捷键CTRL+S查看,libcrackme.so其实还没有加载进来。
其实不难理解,手机还在等待调试器,而被调试app的内存由调试器加载。
这里就要用到jdb工具了:
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课