我试图弄清楚跳转表(将子程序名称与其地址配对的数据表)在可执行文件中的位置,以及它是否基于语言、编译器,或者是否有标准放置可能在 PE 的标头中/ELF 二进制文件。它是哪一个?我怎样才能找到这些表格或找到有关它们放置位置的文档?
到目前为止我尝试了什么:
首先,我阅读了 PE / ELF 标头的每个部分,并不确定哪一个是跳转表。
因为我发现学习编译器如何工作的前景非常令人生畏,所以我想到的最直接的解决方法是使用子例程反汇编二进制文件并找到引用该跳转目标和其他的二进制文件的一部分。在编译为 ELF 格式的C 程序开始时,我发现了以下部分:
0000000000001020 <.plt>:
1020: ff 35 1a 2f 00 00 pushq 0x2f1a(%rip) # 3f40 <_GLOBAL_OFFSET_TABLE_+0x8>
1026: f2 ff 25 1b 2f 00 00 bnd jmpq *0x2f1b(%rip) # 3f48 <_GLOBAL_OFFSET_TABLE_+0x10>
102d: 0f 1f 00 nopl (%rax)
1030: f3 0f 1e fa endbr64
1034: 68 00 00 00 00 pushq $0x0
1039: f2 e9 e1 ff ff ff bnd jmpq 1020 <.plt>
103f: 90 nop
1040: f3 0f 1e fa endbr64
1044: 68 01 00 00 00 pushq $0x1
1049: f2 e9 d1 ff ff ff bnd jmpq 1020 <.plt>
...
我认为这可能是跳转表的样子,这些地址是各种动态链接库的偏移量。我之前曾看到一个带有 .plt 的 ELF 标头部分的引用,但最初并不清楚它是否是一个跳转表。进一步研究表明:
PLT代表Procedure Linkage Table,简单地说,用于调用在链接时地址未知的外部过程/函数,并在运行时由动态链接器解析。
GOT 代表 Global Offsets Table,同样用于解析地址。PLT 和 GOT 以及其他重定位信息都在本文中详细解释。
我仍在努力寻找本节中的哪个跳转(如果有)指向我程序中的子例程。也许那个 GOT 是我接下来需要看的地方。
如果需要更多上下文,这就是我要问的原因:
我一直在研究二进制补丁,尤其是用于跟踪恶意软件行为的挂钩技术,以及恶意软件如何阻止这种跟踪。钩子(只是将控制流重定向到中间函数,然后重定向到最初预期的目标的指令)可以去很多地方,例如修补到内存中的共享二进制文件(libs)中,甚至修补到内核子例程中,但如果我理解正确地,它们有时也被直接注入到可执行二进制文件中的子例程中。
我正在研究的是攻击者阻止这些钩子放置在二进制文件中的可能性。假设攻击者从恶意软件的执行开始就使用了一个不确定的(从受害者的角度来看)跳转目的地。现在假设分析师或自动启发式分析工具试图在沙盒环境中反汇编程序以确定程序的行为,但程序为该跳转目标地址访问的 Web 服务器将仅返回一个入口点对程序在未来某个日期执行时的恶意控制流。在此之前,它会返回一个地址,使程序以良性方式运行。这是教科书式的规避,由于 x86/-64 架构的可变长度特性而成为可能。我最近发表了一篇根据我的理解将问题集可视化的图表。
但是如果编译器在程序中建立了跳转表,分析人员或威胁检测系统仍然可以知道入口点的位置以跳转到并分析这些子程序。一旦这些子例程在目标条件下在运行时执行,还可以分析寄存器以找到执行例程的地址(x86 调用约定包括此信息,以便子例程知道返回到哪里),并从分析人员还可以知道其他有效的指令边界以开始反汇编。
我对编译器的工作原理几乎一无所知,并且已经阅读了 PE / ELF 文件头的规范,但也许我错过了一些东西。我真的很感激一个指向正确方向的指针。