前段时间看到看雪有篇文章讲百度壳的分析,讲的是native创建虚拟机来自主加载so,代码是基于dvm的。但是我直接改成art,在8.0上并没有成功,当时想着写art的脱壳机的时候再去研究一下原因,结果一拖再拖就没有下文了。最近又看到一个创建虚拟机来加载so的,看了一下代码,是基于art的,并且可以跑成功。于是就打算看看为啥之前的不行。
相比于dvm的,art的那个代码多了如下部分:
1 | //1 |
//2
registerNatives_t registerNatives;
registerNatives = (registerNatives_t) dlsym(libandroid_runtime_dso, “Java_com_android_internal_util_WithFramework_registerNatives”);
if (!registerNatives) {
// Attempt non-legacy version
registerNatives = (registerNatives_t) dlsym(libandroid_runtime_dso, “registerFrameworkNatives”);
if(!registerNatives) {
return -3;
}
}
1 |
//3
JNIEXPORT void InitializeSignalChain() {
}
JNIEXPORT void ClaimSignalChain() {
}
JNIEXPORT void UnclaimSignalChain() {
}
JNIEXPORT void InvokeUserSignalHandler() {
}
JNIEXPORT void EnsureFrontOfChain() {
}
JNIEXPORT void AddSpecialSignalHandlerFn() {
}
JNIEXPORT void RemoveSpecialSignalHandlerFn() {
}
```
第一部分主要是加载虚拟机的一些选项,对整个流程影响不大。
第二部分跟注册native函数有关,这里没有仔细分析。
第三部分较为关键,这里直接到导出了这些函数 。也是2个代码区别最大的地方。
如果直接在art下运行之前dvm的代码(需要把libdvm.so改为art)去加载,就会报一个错 > “E/libsigchain(3476): InitializeSignalChain is not exported by the main executable.”
表示主程序没有导出这个函数。 直接查看源码可以看到art确实会用到这些导出函数,另外源码中也在libsigchain中定义了这些函数,但是这些函数是直接调用abort的。
看到这里就有一个疑问,为啥我导出函数的时候会走我的函数,但是我不导出的时候直接调用libsigchain中的dummy函数。我想到的一点可能是函数名称重复导致的问题(其实也不能算问题)。由于我的主程序导出了这个函数,linker在找地址的时候就直接到找了我定义的函数。
https://bbs.pediy.com/thread-216701.htm
https://github.com/rednaga/native-shim