Intro
360加固保可以针对ELF和DEX进行保护,360某些产品的ELF文件基本都使用了自家产品进行加壳,而这些正是我们感兴趣的东西。由于文件比较多,为了能够快速的拿到Payload,最近稍微总结了一些较为通用的方法。
大体流程
壳整个流程的目的是解密核心ELF文件到内存中,关键解密的地方有3处,均使用RC4。
- INIT_ARRAY:壳填充了结构,Linker在so加载完毕后会调用这个回调。这个函数被重命名为__gnu_armfini_26。其功能是进行一些反调试,并且解密JNI_Onload的代码。
- JNI_Onload:JNI_OnLoad负责解密核心ELF并加载。此时解密的ELF文件的入口代码没有解密。
- __gnu_Unwind_0:最后的步骤,解密核心ELF的入口代码。在不同的版本中解密入口代码的地方有所不同,一般的产品中在壳调用原始JNI_OnLoad之前会进行解密,360的某些产品则会通过Hook库函数的方式,在调用库函数之前再进行解密。
关键函数
外壳大部分函数名被修改成了伪库函数的名字,如图:
通过调试得到了一些关键函数的功能,对这些函数下断点可以快速的脱壳:
__gnu_arm_message | rc4_decode |
__arm_aeabi_6 | rc4_init |
__gnu_Unwind_0 | 解密入口 |
脱壳流程
- 找到__gnu_armfini_26函数。修改入口代码为FE FF FF EA,即死循环;
- 加载so并使用调试器附加,将原始代码修改回去,一般是PatchDword(GetRegValue(“PC”), 0xe92d0001);
- 对__gnu_arm_message进行下断,然后开始跑;
- 第一次是JNI_Onload的解密,第二次是ELF文件的解密,记录下解密数据保存的地址和大小,RC4解密完之后还会有些处理,此时可以先不Dump;
- 第三次略有不同,如果是解密一个8字节的数据,则需要手工设置PC为__gnu_Unwind_0。如果大于8字节,则是在解密入口代码。解密完成后Dump出Step 4中的数据以及入口代码。
- 把入口代码写回ELF中。ELF头部magic可能被修改为lfx,这种情况把lfx替换为ELF即可。
Pingback引用通告: 360安卓壳反调试 | corner
Pingback引用通告: 加固保动态脱壳学习
Pingback引用通告: 360安卓壳反调试 - lbchs-团队
Pingback引用通告: 动态脱壳学习 - lbchs-团队
Pingback引用通告: 一周信息安全干货分享(第19期) – Guge's blog