前言
近期把研究dex的脱壳,顺便又是再次熟悉了一下dex的标准格式以及dex被解析后在内存中所存在的格式。自己上官网加了一个壳子,发现跑不起来。于是求助几个基友,最后样本是海总给的apk,非常全面,带有Activity、Application、BroadcastReceiver、ContentProvider、以及Service。
0x1 加壳前后对照
加固后的文件列表变化:
新增一个so文件以及一个jar包:
libbaiduprotect.so
baiduprotect.jar
改动:
META-INF目录
AndroidManifest.xml
Classes.dex
0x2 IDA尝试
用IDA来远程调试,直接跑挂了。看来有反调试。
从壳入口Java层找到例如以下语句:
static {
if(!Debug.isDebuggerConnected()) {
String v0 = Build.CPU_ABI;
if(v0 != null && (v0.startsWith("x86"))) {
StubApplication.loadX86Library();
return;
}
System.loadLibrary("baiduprotect");
}
}
把第一个if删掉之后,程序顺利的载入了baiduprotect.so。顺利的进入了壳的领空。只是不知道是程序在so里面做了完整性校验还是再次检測了debuggerconnected,每次跑都是进入了一个死循环后,然后程序就跑挂了。跑了非常多次都是难以逃出那个trap。这个时候就比較纠结了。既然反调试过不去,想起360的壳子用DD也能够脱的非常完美。那就换个方式试试。
0x3 DD大法
dd if=/proc/PID/mem of=XX skip=0 ibs=1 count=LENGTH
skip改成偏移地址
偏移地址
cat /proc/pid/maps
1.这里首先要感谢下wbyang博士猛男,这个DD大法也是上次挑战赛之后向他学来的。程序跑起来,把内存都dump出来,大概是100多mb的东西。找几个字符串,然后向上翻。找到dex文件的头。发现是被抹掉的。如图:
前面红色框的8字节是odex的magic头。后面的0x70字节是dex的头。除了一些size和编码标志没有被抹掉。其它的已经是面目全非,修复后例如以下:
这下把dex文件抠出来了。
2.把dex反编译成smali文件
出现例如以下错误:
重复检查后发现了例如以下是CodeItems以下的offset错误:
Dex的文件大小才0xA30DC。而offset指向了外面的东西。
当然是无法解析的。这里我是有一个问题的,第三个偏移,这个0x0220E8E8,指向的是前面的内存。这是怎样做到的?我个人觉得是百度是在载入完毕之后有益改成这个数字的。若有错误。还望前辈不吝指正。
把这三个offset 都改成0就能够达到反编译成功,当然是在缺三个DataItem的前提下编译成功的。找到被抹掉的DataItem地址:
以上三处为0的区域就是加固前的dex代码所存放的位置。
因此,如果我们能从dex的结构逆推出该三处的数据而且用应该的数据填充这块。静态就能把这个壳子搞定了。
3.怎样修复
360壳子要修复的数据为DataclassDef中的offset就可以。而百度的更为麻烦一些,不仅它的偏移须要修复一下,更为麻烦的是DataItem的数据也要修复。这个难度就更大了。
总的修复原则是导出函数表,然后按顺序来修复dex中被抹掉的数据,例如以下:
逆计算出函数的uleb128的索引值、常见函数的一些accessflags、以及指向函数内容的offset。
修复后例如以下:
修复的过程比較繁琐。有时候还须要自己尝试几次才知道size是多少。所以叫它人肉修复好了。
修复好了反编译如图
:
发现onCreate函数没有代码,检查了一下,又有新发现!
原来是oncreate中的insns[]也被抹掉了。
这个算是最主要的单位了。功力太弱。无法逆推。
最后总结下。百度的壳子须要修复dex头中的magic、签名值、校验值以及各个offset。还须要修复Dataclassoffset,以及Dataclass和opcodes。前两者是能够静态修复的,最后的仅仅能动态调试寻找了。百度壳子新增了一个oncreate001的函数,调用的壳中的d方法以及e方法,推測是d方法填充了insns[]解密数据,然后e方法为清洁工,抹去正确的数据或者是改成一些非法数据。此时就泪奔了。。
(心里暗想:百度好猥琐啊。。
。)
因为过去几天了,再次写文章又又一次做了一遍,把各种东西找好。写完花了将近三个小时,累觉不爱了。
。。
T T
因为水平有限,难免有错误。还望各位看官不吝指正。
2015.3.24 By Ericky