首页
社区
课程
招聘
[原创] 从 Android 源码看 SO 的加载
发表于: 2017-5-16 11:34 11506

[原创] 从 Android 源码看 SO 的加载

2017-5-16 11:34
11506

做安卓逆向的时候常常会碰到写在 Shared Object(即 [*.so] 文件,下文 SO)的加固逻辑,碰到 SO 的时候惯性分析方法是:静态找 JNI_Onload / .init / .init_array 这些在加载之初会被调用的代码段或者是指向被调用代码段的指针段。


然而现在的加固基本上都会用各种方式抹掉函数关系、SHT 等导致直接静态分析 SO 时既不能从函数表里找到 JNI_Onload 也不能从 SECTION 里找到 .init,部分逆向人员在这种情况下走了弯路。


Android 作为开源的系统,既然可以拿到源码,那么就可以尝试分析加载 SO 时的流程,进而找到对应正确的下断位置来确定 JNI_Onload / .init 的偏移量。下文中所有源码均为 android-4.4.2_r1 版本,各个版本在细节上的实现可能存在差异。


以 [java.lang.Runtime -> load()] 为例子来说明(loadLiabrary() 最后和 load() 殊途同归,有兴趣的可以自行分析),对应的 Android 源码在 [java/lang/Runtime.java],从 320 行开始。


可以看到 load(String pathName) 实际上是调用了 load(String pathName, ClassLoader loader),而后者又调用了 doLoad(pathName, loader),这里的函数调用没有什么实际的意义(仅指对逆向者没有实质的意义,下同)一直在传值。


下面是 doLoad(pathName, loader) 的定义,源码还是在上面的 Runtime.java 里。


主要是检测 loader 的正确性,并带上 LD_LIBRARY_PATH 一起进入 nativeLoad(name, loader, ldLibraryPath),这里开始进入 native 层,nativeLoad 的定义在 vm/native/java_lang_Runtime.cpp # 64 行,如下。


还是传值 + 检查,然后执行 [bool success = dvmLoadNativeCode(fileName, classLoader, &reason);] ,看下 dvmLoadNativeCode(...) 的代码,位于 vm/Native.cpp # 301 行


做了一些常规的检查,不赘述了,可以看到 [version = (*func)(gDvmJni.jniVm, NULL);] 这里调用了 JNI_OnLoad,上一行是 [ALOGI("[Calling JNI_OnLoad for \"%s\"]", pathName);],记录一下方便逆向时确定位置。


根据逆向经验 .init(_array) 段定义的内容是在 JNI_OnLoad 之前执行的,而 dlopen 是加载 SO 的函数可能会在这里执行 .init,看一下 dlopen 函数,它的定义在 linker/dlfcn.cpp # 63 行


其实还是调用了 do_dlopen,do_dlopen 的定义在 linker/linker.cpp # 823 行,代码如下。


做了一些检查,*是否符合调用 dlopen 的格式、*是否属于已经加在过的 SO,如果属于之前没有加在过的 SO 就执行 [si->CallConstructors();],看一下 CallConstructors() 的定义。


重点是最后这的 [CallFunction("DT_INIT", init_func);] 和 [CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);],很明显是执行 .init(_array) 定义的内容,这里不贴 CallArray 的代码了,其实还是循环调用了 CallFunction,下面看看 CallFunction 的代码,linker/linker.cpp # 1172 行


看到这行代码 [function();],所以可以确定 .init(_array) 定义的内容最终在这执行。同样记录一下 [TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, name);] 方便逆向时确定位置。



[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 1
支持
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  CCkicker   +1.00 2017/06/19
最新回复 (14)
雪    币: 1039
活跃值: (355)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习了,蟹蟹分享
2017-5-16 11:57
0
雪    币: 4522
活跃值: (5679)
能力值: ( LV13,RANK:437 )
在线值:
发帖
回帖
粉丝
3
火钳留
2017-5-16 12:44
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
  vonLoad  =  dlsym(handle,  "JNI_OnLoad");
自己写个测试程序  ,dlsym一些位置  应该可以吧
感觉那样太废劲
2017-5-16 14:21
0
雪    币: 360
活跃值: (84)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
5
elianmeng vonLoad = dlsym(handle, "JNI_OnLoad"); 自己写个测试程序 ,dlsym一些位置 应该可以吧 感觉那样太废劲
dlsym对JNI_Onload是没问题的  .init这些呢
2017-5-16 14:42
0
雪    币: 1039
活跃值: (1825)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
大佬留个联系方式交流下呗  @Caln
2017-5-16 15:42
0
雪    币: 7795
活跃值: (5212)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2017-5-16 18:25
0
雪    币: 360
活跃值: (84)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
8
wooyunking 大佬留个联系方式交流下呗 @Caln
w.uyc.cc+r0@gmail.com
2017-5-18 12:14
0
雪    币: 234
活跃值: (927)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
9
分析的非常清晰
2017-5-31 00:35
0
雪    币: 339
活跃值: (1051)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
10
感谢分享~
2017-6-1 08:58
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
有个安卓软件是SO加密,有偿帮我分析下,8000+可谈,扣扣9-7-3-5-3-8-2-6,谢谢
2017-6-1 22:15
0
雪    币: 3757
活跃值: (1757)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
12
感谢分享。。。
前段时间研究过安卓逆向,但网上的教程都是好几年之前的了。。。
这篇文章正是我需要的
2017-6-3 08:51
0
雪    币: 0
活跃值: (418)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
您好,我是gslab游戏安全实验室的,想转载您的文章到官网,会注上作者和来源
2017-8-21 11:30
0
雪    币: 360
活跃值: (84)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
14
gslab实验室 您好,我是gslab游戏安全实验室的,想转载您的文章到官网,会注上作者和来源
好的  没有问题
2017-8-21 17:03
0
雪    币: 53
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
分析的挺好
2017-11-8 13:07
0
游客
登录 | 注册 方可回帖
返回