我试图查看是否可以在仍然保持原始ELF的执行流程的同时在ELF的.text部分中附加功能代码。理想情况下,我想调用新函数,但这就是它自己要爬的山。我更关心只添加代码。这是现实的吗?还是我头顶过头?我已经能够通过简单地覆盖字节来添加代码。但是,我想扩展.text部分并插入它。如果有更好的方法将新功能插入到ELF中,我将不知所措。但是任何指导都是有帮助的。

评论

有众所周知的技术可用于将代码添加到ELF二进制文件中。你的目标是什么?二进制文件是静态链接的吗?节头表存在于二进制文件中吗?

嗨,欢迎来到RE.SE。添加到@julian写道:python与它有什么关系?

它确实具有标准的动态链接库,但是我想向ELF添加用户定义的函数。节标题表存在

#1 楼

可以做您想做的。您可能会遇到一些困难。我将向您简要说明如何在几种不同的情况下完成该操作。由组成以及它们在运行时在过程映像中的位置。即使存在可以自动为您执行工作的工具,也最好知道在“底层”必须完成的工作。
编写并编译要添加的代码。当然,您可以稍后再做,但是通过这种方式,您将知道需要添加多少空间。
有了1.中获得的知识之后,现在就可以解释readelf -S executableToPatch命令的输出了。它将列出可执行文件中存在的部分以及信息,例如文件中的偏移量。
如果幸运的话,您要更新的部分的偏移量+它的基本大小+您要添加的代码的大小小于下一部分的偏移量。在这种情况下,您只想创建一个文件,其中包含本节的新内容(即,修改前的全部内容和您附加的额外代码)。然后,您可以简单地运行:
objcopy --update-section .text=fileWithTheNewContent nameOfExe nameOfExePatched,您就可以完成。仅仅意味着objcopy: nameOfExe: section .text offset adjusted to newOffset向前移动了一些后续部分,使得它们彼此不重叠(从objcopy开始,这是ELF规范的要求之一)。但是,与上一点相反,您不能仅在此处完成,因为某些情况下包含数据的部分也可能更改了其偏移量。
检查哪些部分已重定位。如果它们都不包含数据,则现在可以测试该程序的行为是否与修改之前相同。如果是这样,则您的工作已完成-您的代码已成功更新。
如果它的行为不同或某些包含数据的部分已更改其偏移量,则有必要将数据引用固定到该部分,即修补代码,以便它引用新数据节位置中的偏移量。例如,当1.向前移动了.rodata个字节时,您将必须通过在每个地址中添加4096来更改对.rodata的所有引用,即,如果您具有4096,则要将其更改为mov rax, [rip+0x20],但是这样做并不容易,尽管仍然可以。


评论


谢谢!我最近尝试了obj复制-现在,我发现.text部分中有.rodata引用,这在很大程度上进行了解释。现在经历并更新这些内容无疑将是下一个挑战。我很感激!

–住宿
19年8月19日在23:08

#2 楼


我想扩展.text部分并插入[code]。如果有更好的方法将新功能插入ELF,我将不胜枚举。


Linux病毒编写者在1990年代就率先提出了向ELF文件添加任意代码的技术。与他们开发的方法以及更现代的技术相比,采用objcopy路线似乎相当粗糙。从那时起,就不需要重新发明轮子了。

从那时起,出现了更多现代的方法来操纵ELF二进制运行时行为,包括各种注入技术和仪器框架。

出于这个问题的目的,我们可以将修改二进制功能的方法分为两种方法:
到程序运行时)
通过注入(运行时修改)诱导新行为。

静态修改技术

文本段填充感染

经典的ELF text段(非节)填充感染方法似乎与您当前正在尝试的方法最紧密相关。 />寄生码,只要它的大小是可以的。此空间不会干扰原始段,无需重新定位。遵循给出偏爱文本段的准则
,我们可以看到在文本段
端的填充是一种可行的解决方案。 1


实现此目的的算法如下:



在ELF标头中将p_shoff增加PAGE_SIZE
修补插入代码(寄生)以跳转到入口点
(原始)
找到文本段程序头文件


修改ELF头文件的入口点指向新的
代码(p_vaddr + p_filesz
为每个新的代码(寄生虫)增加p_filesz的数量
为每个新代码(寄生虫)增加p_memsz的数量


每个phdr插入后是谁的段(文本段)段


p_offset的寄生虫长度增加


对于插入后的每个PAGE_SIZE,其节段都居住


/>将PAGE_SIZE增加shdr


物理上将新代码(寄生物)插入并填充到sh_len到文件中-文本段shdr + sh_offset(原始)1 />



除了对该技术的解释以及实现该技术的病毒的源代码(包括在1998年的文章[1]中)之外,还有2016年(在所有这些年之后,它仍然有效)关于ELF段填充感染的教程可在0x00sec获得,称为ELFun File Injector。除了文本段感染方法外,还存在数据段感染,这非常相似。如果愿意的话,还可以添加一个额外的细分。


PLT / GOT感染

首先在2000年的Phrack文章2中对此进行了详细介绍。修补PLT / GOT以指向二进制文件中的代码,该二进制文件已通过感染方法插入,而不是指向动态链接到二进制文件的共享库中的代码:


它可以注意,我们可以更改[GOT中的函数名称]指向我们自己的代码,从而替换库调用。如果在替换之前保存了GOT的状态,则可以调用旧的库例程,从而重定向任何库调用。 2


实现此方法的最简单方法似乎是使用LIEF工具框架。 LIEF文档中标题为Infecting the plt / got的感染提供了一个教程。请注意,在本教程中,修补了GOT而不是PLT,并且通过创建新的段(上述感染技术之一)将代码添加到了文件中。


除此以外,还有其他一些技术可以直接修改文件,但是段填充感染和PLT / GOT感染似乎是最简单的。技术

由于DLL注入和运行时进程操作与您当前的任务不太直接相关,因此我不再赘述。


通过PAGE_SIZE进行DLL注入非常强大和有用。我发现有用的2个教程是



LD_PRELOAD技巧-用于从C源代码编译的二进制文件

关于C ++中的函数插入的注释从C ++源代码编译的二进制文件


DLL挂钩也可以通过LIEF来完成:请参阅ELF挂钩

使用p_offset的过程代码注入
>
有些方法更加晦涩难懂,例如Cerberus ELF界面中详细介绍的p_filesz感染和欺诈ELF中所述的“颠覆性动态链接”


参考文献


Unix病毒。 Silvio Cesare
通过ELF PLT感染重新共享图书馆的电话,Silvio Cesare


评论


在考虑该路线时-我不希望我的代码先执行。我想在main中修改原始函数调用以调用我的代码。当我将入口点更改为我的代码时,会不会立即执行我的代码?

–住宿
19年8月21日在15:08



@stayge,您已经看到许多路线。我想在main中修改原始函数调用以调用我的代码。 <-是否正在调用共享库函数?修补CALL地址以跳转到您插入的代码是否足够?您为什么要在这种约束下运作?请清楚地描述问题。

– julian♦
19年8月21日在15:23



正在调用用户定义的函数。我尝试将代码放入.so并使用LD_PRELOAD,但它仅覆盖库函数。我想修补该调用,以便它可以跳转到我的函数,然后返回到main并继续执行。这只是在哪里放置代码而无需重新整理整个ELF的问题

–住宿
19年8月21日在17:10



@stayge是的,这种使用DLL注入的方法将行不通,因为您希望插入驻留在二进制文件本身而不是DLL中的代码。据我所知,您可以在不修补入口点的情况下使用文本段感染方法。该函数的CALL地址可以打补丁,而不是指向文本段中的代码。如果通过这种绕道(与objcopy路由相同)调用函数,则堆栈对齐可能是个问题。

– julian♦
19年8月22日在6:32



#3 楼

我在高中时写了一个小实用程序来做类似的事情:
https://github.com/jdefrancesco/elfy

您向.note部分注入有效载荷,它将修改ELF条目指向.note节。之后,它将跳回到原始入口点。