360早期整体加固classes.dex后的apk的特点:1、在apk的assets文件的路径下新增两个文件libjiagu.so和libjiagu_x86.so。2、在apk的AndroidManifest.xml文件的application标签中新增两个元素(这会导致程序修改后的回编译失败)。


标签中的android:name="com.qihoo.util.StubApplication"就是壳程序的入口点。标签中的"qihoo"是因为360公司的全称为"北京奇虎科技有限公司"。
静态分析Java层的壳程序入口点StubApplication类。
StubApplication开始定义了静态遍历和字符串以及大量的native 方法。如下图,strEntryApplication 指向真实的 Application 类名(被加固隐藏);soName 是加固的库名,最终会加载 libjiagu.so。所有以 n 开头的方法(如 n0110、n0111 等)以及 interface7/8 都是 native 方法,在 libjiagu.so 中实现。

attachBaseContext 方法是壳的启动入口。如下图,根据 CPU 架构(x86 或 ARM)从 Assets 中复制对应的 SO 文件到应用私有目录(/data/data/<包名>/files/)。若为 64 位 ARM,则额外复制 libjiagu_64.so 并优先加载它,否则加载 libjiagu.so。

如下图,完成Application 的创建与替换。getNewAppInstance 通过类加载器加载 strEntryApplication 指定的类并实例化。通过反射调用 Application.attach(Context) 方法,将真实 Application 与壳上下文绑定。调用 interface8(native 方法)可能用于通知加固层完成替换。

onCreate的调用如下图,ChangeTopApplication 内部调用 interface7,随后调用 Application 的 onCreate,进入业务代码。

IDA静态分析libjiagu.so。
虽然可以正常解析一些符号和字符串,但是so文件中出现了大量未解析的数据,如下图所示。


010查看so文件的ELF结构。如下图,对so文件的节区做了处理,如节名、节偏移等。但是对节的数据未做处理。虽然这会影响IDA的部分反编译,但在IDA高版本中还是可以识别到大部分的符号信息,但是还是会有大部分的数据未能正常识别。

观察导入导出函数表,可以找到fopen、fclose、JNI_OnLoad等函数信息,但是未找到init_array、init_proc等函数信息。


静态分析JNI_OnLoad,如下图,没有得到太多的有用信息,又因为ELF文件被处理过,所以反编译结果不太准确。

IDA动态调试libjiagu.so。
启动IDA服务端文件,注意修改服务端文件和IDA的默认调试端口,绕过可能存在的反调试。

动态调试启动程序之后无法直接点击so库进入,这是因为so库被加密处理了,IDA找不到这个so的真实路径和名称

但是我们静态分析已经知道了JNI_OnLoad的地址。

加上动态调试so库的加载基址就可以得到JNI_OnLoad动态调试的绝对地址。

跳转到地址后观察是否和静态分析的指令一致,然后观察是ARM指令还是thumb指令,最后P键识别为函数,下断点后F9运行到此处。

一路F8、F7调试,因为函数是混淆过的,所以会经过很多无意义的跳转。
观察运行到了mmap函数,下断点观察内存和寄存器。查看此时内存都是00000。

观察寄存的值,判断mmap复制的哪块区域。

运行完后观察程序段的分布,发现多出了一些区域。

一直调试到memcpy拷贝函数,运行后观察内存发现多出了数据。

把R1的数据拷贝到R0。

运行至756635D0函数,进入后发现逻辑很多。

计算偏移地址,跳转回静态文件进行分析。
整体观察函数,进行了严混淆,很少的对其他函数进行调用,多进行了一些对数据加减移位等操作,判断函数可能与解密有关。

不需要步入认分析,直接F8步过查看内存数据的变化。

遇到SVC 0记得跳过,可能会导致程序崩溃。

F7进入75663C2C。

遇到mprotect_0函数,这个涉及到了对内存属性的修改。

运行至BLX LR。

运行至debug078区域,75614000就是上面申请的空间处。

出现了BLX LR,点击跳转的目的地址在so的空间中,计算偏移地址回到静态文件进行分析。

BLX loc75661454是反调试函数,如下图,也使用到了open函数和strtol函数(将数据转换为长整型)。


判断指令为ARM指令,始终让R0返回0,因为是比较R0是否为0根据结果是否调用反调试函数。


四字节修改内存数据。

LR保存返回地址。

修改内存。


修改后的指令。


反调试过掉后,就是要拿到dex文件。
在mmap函数处的开头和结尾下断点。


不断的F9、F8,观察寄存器和栈空间是否出现dex的字符。
运行出现了errno。


段中也出现了zero段

但是当前区域还没有数据
。

一路F8,F9运行直到栈空间和内存空间出现dex字符就要一步一步跟踪了,避免错过加载dex文件的时机。
BLX R12 加载加密的dex文件到内存中,759F8100时内存中出现dex.035,那759F8100就是解密dex文件。



观察起始地址和大小dump出dex文件即可。


参考文章:Android逆向与安全——360 dex加固与脱壳 - 知乎
[招生]科锐逆向工程师培训(2026年7月3日实地,远程教学同时开班, 第56期)!
最后于 10小时前
被ODcat编辑
,原因: