因此,基本上,我正在研究一些脱扣的动态链接的ELF二进制文件(32位Linux x86),使用objdump对其进行反汇编,修改并尝试重新组装它们。基于符号表的主要功能的地址,但是,在剥离的二进制文件上,我们只是不知道主要功能的位置。

当然我可以调整整个文本部分,从ELF的原始入口点开始。

但是问题是:
如果我从重新组装的ELF的入口点开始,那我将不得不拆开该部分。可能会双重初始化一些东西,因为在我重新组装的asm代码中,我的代码为_start__do_global_dtors_aux; __libc_csu_fini,而链接器还将这些功能附加到新的ELF中。 />现在我在这个问题上还没有策略,有人可以给我一些帮助吗?

#1 楼

关键在于确定所讨论的映像是否使用“标准” C运行时库类型(glibc,musl,uclibc)。如果是这样,则可以获取入口点地址,并将该地址与这些库中的启动例程集合进行匹配,并精确定位main()位置,因为您知道哪个call是将控制权转移到main()的那个。

然后,该映像可能不会与任何众所周知的C运行时链接,例如,如果它是直接调用内核syscall的代码段,还是设法鞭打了自己的CRT库。 >
另一个好处是,如果该程序根本不是用C编写的,并且使用了其他花哨的语言,但这似乎超出了问题的范围,因为main()与这些语言无关。猜猜。

#2 楼

我开始在《反向ELF 64位LSB可执行文件x86-64,gdb》中回答这个问题,但这只是针对AMD64。并将其第一个参数作为指向__libc_start_main函数条目的指针。以下是该功能的完整说明(从其手册页开始):


main

名称

__libc_start_main-初始化例程

简介

int __libc_start_main(int (*main) (int, char**, char**), int argc, char** ubp_av,
                      void (*init) (void), void (*fini) (void), 
                      void (*rtld_fini) (void), void (* stack_end));


描述

__libc_start_main函数应执行执行环境的任何必要的初始化,调用带有适当参数的main函数,并处理__libc_start_main()的返回值。如果main()函数返回,则应将返回值传递给main()函数。

注意:尽管本规范旨在独立于实现,但进程和库的初始化可能包括: />
如果有效用户ID与真实用户ID不相同,请执行任何必要的安全检查。
初始化线程子系统。
注册exit()以在此动态共享库释放资源退出(或已卸载)。
注册rtld_fini处理程序以在程序出口运行。
调用初始化函数fini
用适当的参数调用(*init)()

此列表仅作为示例。

main()不在源标准中;请参见参考。它仅在二进制标准中。

另请参见

ISO / IEC 23360的每个体系结构特定部分中的过程初始化部分。 />
因此,exit()不仅为您提供了main()过程的地址,还为您提供了__libc_start_main()__libc_start_mainmain()的访问权限。然后,重点是从汇编代码中提取每个自变量,这些自变量可能会因所使用的ABI(应用程序二进制接口)而有所不同(功能自变量可能会推入堆栈或特定寄存器中)。

#3 楼

objdump -f exe_name

exe_name:     file format elf32-little
architecture: UNKNOWN!, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00306990


上面提到的起始地址是可执行文件的主要入口点。您也可以使用gdb

(gdb) break *0x00306990


进行验证。通常,起始地址已映射到符号_start,因此也可以执行br />
如果我没记错的话,_start会调用__libc_start_main,而__libc_csu_init会依次调用<43 />

#4 楼

因此,我认为,在从objdump反汇编的asm代码中,我们应该始终找到以下内容:上面的代码是addr函数的开始地址。

对吗?有什么例外吗?

评论


实际上,这取决于您使用的ABI。例如,在SystemV AMD64中,您将在寄存器%rdi中找到第一个参数。

–恐怖
2014年6月26日19:54