2

我正在尝试将一些额外的日志记录代码合并到一个静态链接的(android arm linux)可执行文件中。

(正常的跟踪方法似乎不起作用,因为它是一个守护进程,它在做任何有趣的事情之前 clone()s - 告诉 strace 跟随它只会让它崩溃)。

十六进制编辑现有代码以将跳转指令插入新代码已经过测试和工作,问题是将新代码合并到可执行文件中,这样它不会干扰现有段,并且确实被加载到一个可执行的页面。

我已经能够将所有附加代码压缩到单个目标文件部分,但无法弄清楚如何使用 objcopy(甚至 ld)以正确加载的方式合并它 - 似乎我需要调整大小并移动现有负载段,或者添加一个额外的负载段。

在共享库中添加代码可能是另一种选择,如果有办法将必要的存根添加到已链接且当前为静态的可执行文件中(然后我将在跳转指令中进行十六进制编辑到存根的已知位置,运行时然后链接器将指向添加的代码)

4

1 回答 1

0

这是不雅的,所以我会对更好的想法感兴趣,但这里是我能够使基本工作的总结。

这是一个两管齐下的方法,将一个小的引导有效负载插入到原始精灵的填充中,然后 mmap() 是一个任意更大的二进制 blob 来完成实际工作。

第一部分:引导有效载荷

基本上,我在 .ARM.exidx 部分(加载在代码段的顶部)和 .preinit_array 部分之间的一些填充中插入了少量代码。这段代码只是打开另一个二进制 blob 并将它的 mmap()s 作为只读和可执行文件在硬编码的虚拟地址上执行,我希望它是安全的。

为了让我插入的代码作为主可执行文件的一部分加载,我必须修改 elf 文件中加载段的大小,在本例中,它是从 0x54 开始的第二个 phdr 结构。0x64 (0x54+0x20) 处的 p_filesz 和 0x68 (0x54+0x24) 处的 p_memsz 都已更改。

我还更改了 elf 标头中偏移量 0x18 处的 e_entry 起始地址,以指向我插入的代码。我插入的代码在完成设置后会跳转到旧的起始地址(实际上它首先跳转到较大有效负载中的第二阶段设置,然后跳转到原始地址)。

最后,我更改了我想要捕获的函数的静态链接系统调用存根,以指向我在 mmap() 中的较大有效负载的加载地址处的替换。

第二部分:大有效载荷

这实现了正在进行的任何修改——在我的例子中,用满足某些条件时记录的函数替换系统调用。由于主可执行文件是静态链接的,因此它也必须是 - 或者更简单地说,它不能使用 C 库。相反,它使用汇编语言为基本 I/O 发出系统调用。我意识到,如果没有作为可执行文件加载,我没有持久的局部变量存储,所以在启动时我 mmap() 一个匿名页面来保存局部变量 - 主要是我正在登录的文件的 fd 和设备驱动程序 fd 的操作应该记录。

编译这部分有点不雅。我正在使用 -S 切换到 gcc 进行汇编,然后删除所有部分关键字。然后我通过 gcc 将其传回以组装并生成一个对象。我通过链接器运行它,将我的第一个函数的名称指定为入口点 (-e),并使用自定义链接器脚本删除 0x8000 起始偏移量。但是由于标头仍然存在一些偏移量,在本例中为 128 个字节。为了保留修复,我将链接精灵的内容复制到二进制 blob 中,将自己从 /dev/zero 中删除 128 个字节,然后将其添加到开头....

正如我所说......这很不雅,所以我愿意接受更好的想法

于 2011-04-23T03:29:45.667 回答