这是不雅观的,所以我会对更好的想法感兴趣,但这里总结了我基本能够完成的工作。
这是一个插入原始精灵填充的小引导负载的双叉方法,然后mmap()是一个任意大的二进制blob来完成实际的工作。
第I部分:引导净荷
基本上我插入在.ARM.exidx部分(这在代码段的顶部加载)和.preinit_array部之间一些填充的代码量小。这段代码只是将另一个二进制blob和mmap()作为只读文件打开,并且在我希望安全的硬编码虚拟地址中可执行。
为了让我插入的代码作为主要可执行文件的一部分加载,我必须修改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字节。保留修正我objcopy链接精灵的内容到一个二进制blob,dd自己128字节从/ dev /零,和猫到开始......
正如我所说...这是不雅的,所以我打开更好的想法
不一定为我想要做的一切,我想要一个相当一般的方法。但是我可能有足够的空间来编码系统调用mmap()从外部文件中编译一个可执行页面,并编辑启动代码以跳转到该页面。 – 2011-04-22 18:37:26
为什么地球上你不重新编译内核......? – 2011-04-22 22:19:30
@Turbo J这不是内核代码。监控用户代码的内核对于无法从备用闪存位置引导内核的设备来说是非常激烈的,而且当精确内核的源还没有被释放时(如在设备开始之前应该已经完成的)销售)。 – 2011-04-22 22:57:30