-
-
[分享]hfourx解题报告
-
发表于: 2015-1-25 21:45 2494
-
1. 第一题
下载apk解包,把内部的classes.dex文件直接拿去反编译。用dex2jar和jd-gui可以完美看到反编译结果。
第一题是一个简单的一次代换密码。从输入框中读入英文字符,转换为0-255以内的ASCII码(严谨的说是UTF-8,但是UTF-8兼容ASCII,不需考虑额外的情况就可以得到正确答案),然后在一个预置长度256的汉字数组中按下标找到对应的中文串,最终需要中文串与指定的串一致。因此只需要根据指定的串逆推即可得到答案的ASCII序列,转换成原文得到答案“581026”。
2. 第二题
第二题解开apk包后,还按照第一题的做法,jd-gui内部可以发现关键的验证函数是native实现。因此第二题的验证算法是用JNI实现的。
因此分析“lib/armabi/libcrackme.so”。用IDA打开,可以发现JNI函数的原型Java_com_yaotong_crackme_MainActivity_securityCheck。在函数中,关键代码反编译如下:
此处有个小技巧,准备一份Dalvik和JNI的头文件,载入到IDA可以帮助识别JNIEnv的各种函数。
代码基本是把输入字符转换为UTF-8字节,然后和passwordBuffer逐个字节对比。其中后者是密码的保存的位置。直接用IDA查看得到的“wojiushidaan”并不是正确答案,所以确定他的值被动态修改了。
下一步就是用gdb动态调试,直接获取密码内容。启动程序,然后在Android的shell中运行gdbserver,在pc端连接至调试器。程序本身没有做较强的反调试保护,可以直接附加。按照“/proc/self/maps”中的基地址加上密码的偏移0x00004450,得到了正确的密码“aiyou,bucuoo”。
3. 第三题
第三题同样解开apk,用jd-gui观察,发现只载入了libmobisec.so。再看libmobisec.so,内部比较复杂,但没有看到JNI实现,进一步观察,发现字串明文很少,各种函数内部无意义跳转次数很多,判断apk已经加壳。而另外两个so文件,其中一个其实是一个apk包,解包后得到一个classes.dex,不包含多少有用信息,另一个so文件是密文无法解析。
起初精力主要集中在逆向libmobisec.so,已经成功逆向出了全部的字串解密函数。但是即使这样依然没有任何攻破的希望。此后曾尝试使用gdb从内存中dump一份libmobisec.so,虽然得到了大量明文字串,但是在仔细修复偏移之前依然不能用于分析。
在这一阶段耗费了很多时间,经过多次探索,最终认为最可行的办法是脱出dex文件明文反编译。在“/proc/self/maps”中查看映射模块,发现可疑项libmobisecx.so (deleted),考虑dump下来研究。
* 反调试
然而在dump的过程中遇到了反调试,显示进程已被ptrace。经过查看,反调试的原理是libmobisec.so在gdb附加之前对自己执行ptrace调用,从而排除外部调试器。在前面的分析中已经解密了所有字串,很容易定位到了ptrace的地址0x000104E8,利用IDA的交叉引用,最终定位到了调用点JNI_OnLoad:
为了禁止ptrace调用,最简单的办法就是直接patch这个动态库。使用hex编辑器找到偏移0x111bc,将它的四字节OpCode改为nop:00 f0 20 e3。替换手机内的文件,设为root:root 755权限,重新执行程序,反调试消失。
* Dump
待程序完全运行后,使用gdb附加至进程,观察“maps”文件可得到libmobsecx.so在内存中的映射范围。gdb提供了dump memory <file> <addr-begin> <addr-end>命令,执行后得到了此部分的dump。
查看dump内容,发现是一个dex包,直接使用baksmali反编译,发现文件并不完整。重新dump,同时延长<addr-end>参数,最终得到了可用的dex包。
* 反编译与逆向
Dump得到的是一个odex文件,使用smali套件可以把它反汇编为smali指令,也可以重新编译回dex。可以用dex2jar与jd-gui得到java反编译代码,但是反编译的结果有一部分失败,并不完整,因此需要同时参考smali来逆向。
核心部分位于两个类:b、e。
其中观察e可知是一个类莫斯电码的转换器,e.a(String)可以把一组空格分开的电码转换为对应的文字([a-z0-9]),而转换表也保存在e之中。
b类中包含了解密的核心函数b.run(),函数过程冗长,jd-gui的反编译也完全错误,需要手动分析。其基本流程是:
1. 获取用户输入内容
2. 调用e.a(String)解码电码
3. 使用内置的AES key "GXiQHT1CZ2elMzwpvvAoPA==" 解密 "hjdsUjIT5je69WXIZP7Kzw=="
4. 要求解密后的内容与解码的电码保持一定关系(具体并不重要)
5. 要求电码的前两个字符hashCode()值等于3618
6. 从类e,a中获取f标签的值分别为"7e" "1p",连接得到"7e1p"
7. 要求电码的长度为6且后四个字符是"7e1p"
8. 其余所有内容均为无意义的运算,对于解密并不重要
根据4、5、7三点要求可知,输入的电码,其明文的后4位是"7e1p",而前2位哈希值固定,可以枚举。
Java的字符串hashCode()的计算,对于两个字符"xy"而言,值为(31x+y),其中xy均为ASCII码,编写脚本计算可得前两位只可能为“s5”或“qs”。带入验证,只有“s57e1p”可行。使用e类的转换表逆推,得到答案“... ____ ___. . ..___ .__.”。
本题的逆向结果将附在跟帖中。
4. 第四题
...没搞定,已经能做到动态库注入、dump、hook,时间不够没能完全干掉反调试。
调试:在系统开发选项里选择调试程序“crackme.4”,以及等待调试器附加,在程序运行后可以附加一个jdb。jdb中下断System.loadLibrary,断下后可以用gdb附加到程序,这个时候可以进一步破解。
注入:两种方法,第一种是任何时刻,可以直接在jdb中调用System.load(sopath)来注入一个动态库,另一种是在gdb里调用dlopen来注入。
hook:注入之后可以用libsubstrate.so挂钩子。可以hook掉ptrace和inotify_add_watcher之类的函数破坏反调试。理论可行,不过时间不够,最终没能完成。
经过字符串分析,怀疑第四题的加密部分是用JNI实现在native层的,所以重点大概还是dump一份libmobisec.so。
下载apk解包,把内部的classes.dex文件直接拿去反编译。用dex2jar和jd-gui可以完美看到反编译结果。
第一题是一个简单的一次代换密码。从输入框中读入英文字符,转换为0-255以内的ASCII码(严谨的说是UTF-8,但是UTF-8兼容ASCII,不需考虑额外的情况就可以得到正确答案),然后在一个预置长度256的汉字数组中按下标找到对应的中文串,最终需要中文串与指定的串一致。因此只需要根据指定的串逆推即可得到答案的ASCII序列,转换成原文得到答案“581026”。
2. 第二题
第二题解开apk包后,还按照第一题的做法,jd-gui内部可以发现关键的验证函数是native实现。因此第二题的验证算法是用JNI实现的。
因此分析“lib/armabi/libcrackme.so”。用IDA打开,可以发现JNI函数的原型Java_com_yaotong_crackme_MainActivity_securityCheck。在函数中,关键代码反编译如下:
[FONT="Courier New"] chars = (unsigned __int8 *)((int (__fastcall *)(JNIEnv *, jstring, _DWORD))(*env)->GetStringUTFChars)(env, str, 0); password = (unsigned __int8 *)passwordBuffer; while ( 1 ) { passChar = *password; if ( passChar != *chars ) break; ++password; ++chars; flagTrue = 1; if ( !passChar ) return flagTrue; } return 0;[/FONT]
此处有个小技巧,准备一份Dalvik和JNI的头文件,载入到IDA可以帮助识别JNIEnv的各种函数。
代码基本是把输入字符转换为UTF-8字节,然后和passwordBuffer逐个字节对比。其中后者是密码的保存的位置。直接用IDA查看得到的“wojiushidaan”并不是正确答案,所以确定他的值被动态修改了。
下一步就是用gdb动态调试,直接获取密码内容。启动程序,然后在Android的shell中运行gdbserver,在pc端连接至调试器。程序本身没有做较强的反调试保护,可以直接附加。按照“/proc/self/maps”中的基地址加上密码的偏移0x00004450,得到了正确的密码“aiyou,bucuoo”。
3. 第三题
第三题同样解开apk,用jd-gui观察,发现只载入了libmobisec.so。再看libmobisec.so,内部比较复杂,但没有看到JNI实现,进一步观察,发现字串明文很少,各种函数内部无意义跳转次数很多,判断apk已经加壳。而另外两个so文件,其中一个其实是一个apk包,解包后得到一个classes.dex,不包含多少有用信息,另一个so文件是密文无法解析。
起初精力主要集中在逆向libmobisec.so,已经成功逆向出了全部的字串解密函数。但是即使这样依然没有任何攻破的希望。此后曾尝试使用gdb从内存中dump一份libmobisec.so,虽然得到了大量明文字串,但是在仔细修复偏移之前依然不能用于分析。
在这一阶段耗费了很多时间,经过多次探索,最终认为最可行的办法是脱出dex文件明文反编译。在“/proc/self/maps”中查看映射模块,发现可疑项libmobisecx.so (deleted),考虑dump下来研究。
* 反调试
然而在dump的过程中遇到了反调试,显示进程已被ptrace。经过查看,反调试的原理是libmobisec.so在gdb附加之前对自己执行ptrace调用,从而排除外部调试器。在前面的分析中已经解密了所有字串,很容易定位到了ptrace的地址0x000104E8,利用IDA的交叉引用,最终定位到了调用点JNI_OnLoad:
[FONT="Courier New"].text:000111BC BL sub_86A28 ; nop[/FONT]
为了禁止ptrace调用,最简单的办法就是直接patch这个动态库。使用hex编辑器找到偏移0x111bc,将它的四字节OpCode改为nop:00 f0 20 e3。替换手机内的文件,设为root:root 755权限,重新执行程序,反调试消失。
* Dump
待程序完全运行后,使用gdb附加至进程,观察“maps”文件可得到libmobsecx.so在内存中的映射范围。gdb提供了dump memory <file> <addr-begin> <addr-end>命令,执行后得到了此部分的dump。
查看dump内容,发现是一个dex包,直接使用baksmali反编译,发现文件并不完整。重新dump,同时延长<addr-end>参数,最终得到了可用的dex包。
* 反编译与逆向
Dump得到的是一个odex文件,使用smali套件可以把它反汇编为smali指令,也可以重新编译回dex。可以用dex2jar与jd-gui得到java反编译代码,但是反编译的结果有一部分失败,并不完整,因此需要同时参考smali来逆向。
核心部分位于两个类:b、e。
其中观察e可知是一个类莫斯电码的转换器,e.a(String)可以把一组空格分开的电码转换为对应的文字([a-z0-9]),而转换表也保存在e之中。
b类中包含了解密的核心函数b.run(),函数过程冗长,jd-gui的反编译也完全错误,需要手动分析。其基本流程是:
1. 获取用户输入内容
2. 调用e.a(String)解码电码
3. 使用内置的AES key "GXiQHT1CZ2elMzwpvvAoPA==" 解密 "hjdsUjIT5je69WXIZP7Kzw=="
4. 要求解密后的内容与解码的电码保持一定关系(具体并不重要)
5. 要求电码的前两个字符hashCode()值等于3618
6. 从类e,a中获取f标签的值分别为"7e" "1p",连接得到"7e1p"
7. 要求电码的长度为6且后四个字符是"7e1p"
8. 其余所有内容均为无意义的运算,对于解密并不重要
根据4、5、7三点要求可知,输入的电码,其明文的后4位是"7e1p",而前2位哈希值固定,可以枚举。
Java的字符串hashCode()的计算,对于两个字符"xy"而言,值为(31x+y),其中xy均为ASCII码,编写脚本计算可得前两位只可能为“s5”或“qs”。带入验证,只有“s57e1p”可行。使用e类的转换表逆推,得到答案“... ____ ___. . ..___ .__.”。
本题的逆向结果将附在跟帖中。
4. 第四题
...没搞定,已经能做到动态库注入、dump、hook,时间不够没能完全干掉反调试。
调试:在系统开发选项里选择调试程序“crackme.4”,以及等待调试器附加,在程序运行后可以附加一个jdb。jdb中下断System.loadLibrary,断下后可以用gdb附加到程序,这个时候可以进一步破解。
注入:两种方法,第一种是任何时刻,可以直接在jdb中调用System.load(sopath)来注入一个动态库,另一种是在gdb里调用dlopen来注入。
hook:注入之后可以用libsubstrate.so挂钩子。可以hook掉ptrace和inotify_add_watcher之类的函数破坏反调试。理论可行,不过时间不够,最终没能完成。
经过字符串分析,怀疑第四题的加密部分是用JNI实现在native层的,所以重点大概还是dump一份libmobisec.so。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图
赞赏
雪币:
留言: