一种简单的app_process 全局注入方案
偶然在看雪看到的一篇文章,最近还看了一些elf相关的东西,所以结合一下记点儿东西.
elf文件相关资料
https://paper.seebug.org/papers/Archive/refs/elf/Understanding_ELF.pdf
app_process其实是一个elf文件,这里对它进行一些修改来达到自己的目的.
我的调试机是Nexus5 lineageOS 14,这里我们把它的app_process32 拷贝到本地,使用readelf看一下它的动态段
其中有个DEBUG项,是用于调试的,没有明确定义格式,修改点就在这里.
由于需要对system分区进行读写操作,所以这里就先adb remount一下.
把app_process32 pull到本地,用010editor打开,因为DEBUG项的上一项标记为0x6ffffffa,所以这里在010editor中搜索faffff6f(小端序)
其中标红部分即为需要修改的部分.
DT_DEBUG的标识为21,即0x15,值为0,这里将它改成DT_NEEDED,并将它的值改为一个so的名称(其实是索引),这里就不对字符串表做修改了,看看下面的DT_NEEDED项的字符串索引,然后改改写到目标位置.
这里额外说一下关于elf字符串索引的东西,elf中字符串以00(null)结尾,然后在文件中都是根据字符串表的索引来获取对应字符串的内容,索引本身可以不从字符串的开头开始,假设存在android字符串且它是字符串表的第一个,则索引为0的时候,取到的字符串就是android,当索引为2的时候,获取到的字符串就是droid,以此类推.
修改以后文件内容如下:
现在再用readelf打开文件,可以看到,对应的项已经变成一个NEEDED,而且对应一个叫ibc.so的共享库.
由于在app_process中JNI_onLoad不会执行,但是.init_array这个节会有一些初始化操作,其中包括了静态变量的初始化,所以这里写一个ibc.so且它的代码如下:1
2
3
4
5
6
7
8
9
10
class staticClass{
public:
staticClass(){
LOGE("just a hook test");
}
};
static staticClass s;
编译完成后,将它置于system/lib下,并将修改后的app_process32 push到system/bin下,重启手机,即可看到对应的log输出.
整个过程其实挺简单的,但是我比较菜所以再稍微记一下其中的知识点.
1.DT_NEEDED的作用
DT_NEEDED
此元素指明了一个所需的库的名字。不过此元素本身并不是一个字符串,它是一个指向由”DT_STRTAB”所标记的字符串表中的索引,在表中,此索引处是一个以’null’结尾的字符串,这个字符串就是库的名字。在动态数组中可以包含若干个此类型的项,这些项出现的相对顺序是不能随意调换的。
这里还涉及到一些动态链接的知识,当动态连接器为一个目标文件创建内存段的时候,动态结构中的DT_NEEDED项会指明所依赖的库,动态连接器会连接被引用的符号和它们所依赖的库,这个过程会反复地执行,直到一个完整的进程镜像被构建好。当解析一个符号引用的时候,动态连接器以一种“广度优先”的算法来查找符号表。就是说,动态连接器首先查找可执行程序自己的符号表,然后是DT_NEEDED项所指明的库的符号表,再接下来是下一层依赖库的符号表,依次下去。共享目标文件必须是可读的,其它权限没有要求。
2. .init_array 的作用
这里涉及到so的加载和启动过程
https://wps2015.org/drops/drops/Android%20Linker%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.html
该节中包含指针,这些指针指向了一些初始化代码。这些初始化代码一般是在main函数之前执行的。在C++程序中,这些代码用来运行静态构造函数。另外一个用途就是有时候用来初始化C库中的一些IO系统。