1. 来自于 Linux 的 的 elf
Android 上的 so(elf)与 Linux 上的有 99%的相似,其中的知识点和结构是可以互通的。
2. Elf 的链接视图
Elf 在加载前和加载后的结构是不一样的,这就给加密提供了方便。
链接执行的时候,shdr 中的表将会被映射到 phdr 中,里面有 3 个头非常重要elf_header,program header,section header,linker 将根据这三个头信息进行 so 文件加载
3. Elf header
存储 so 文件最基本的信息,比如 so 运行 cpu 平台,program header 数量,section header数量等,重要性等同于 dex header
4. Elf Section header
存储 so 文件的链接用信息,主要是用于给外部程序提供详细的本 so 文件的信息,比如第几行对应哪个函数,什么名字,对应的源码位置等等。Ida 则是通过读取该头信息进行 so 文件分析的。
5. Elf Program header
存储 so 文件运行时需要的信息,该信息会直接被 linker 所使用,运用于 so 文件的加载过程中。因此 header 的数据是肯定可信的。
6. 从内存中 dump 出 出 so 文件
对目标程序进行安装启动和端口转发
使用 ida 打开目标程序进行挂接
定位到目标 so 文件,得到该文件的起始地址和文件大小,通过脚本程序从内存中 dump出来
dump 出来的 so 文件由于加载时候进行了内存对齐,所以可能会大一些内存中所加载的段如下图
通过分析.dynstr 的 section 表中数据可以找到想要的函数名和某些加密方法
Dynamic section 中存放着函数和所依赖的 so 文件
Relocation 中存放重定位数据
ARM 文件中特有的表,存放着一些函数的中转表
dynsym 中能够找到需要导入的所有函数的名字、起始地址、大小和访问权限等
7. Others
8. Android linker
Android 上的 elf 文件是通过 linker 加载到内存中并进行执行的。所以通过研究 linker 可以清楚地知道 Android 系统到底使用了 so 文件中的哪几个数据,linker 启动的时候会首先对自身的函数表数据等进行重定位,然后再对其他 so 文件进行定位。Linker 源代码位置:Bionic/Linker
9. Program header 和 和 Section header
Linker 加载中只会用到 Program header,而 Section header 基本上不会用到,甚至直接删除 Section header 也是可以的。
10. Program header 解析
So 加载:linker.cpp --> soinfo* do_dlopen(const char* name, int flags);
find_library(name); //加载
si --> CallConstructors(); //调用初始化函数
CallFunction(“DT_INIT”, init_func); --> so 脱壳点
CallArray(“DT_INIT_ARRAY”, init_array, init_array_count, false); --> dex 脱壳点