获取汇编代码中的特定偏移量

逆向工程 拆卸
2021-06-12 09:31:59

我尝试对应用程序进行逆向工程,但遇到了我不明白的问题。我有以下反汇编代码gdb

   │0x7ffff76f7e4b <_ZN16CRRegistratorImp8RegisterEbPv+587> je     0x7ffff76f7ce6 <_ZN16CRRegistratorImp8RegisterEbPv+230>                                                              │
   │0x7ffff76f7e51 <_ZN16CRRegistratorImp8RegisterEbPv+593> mov    rdi,QWORD PTR [rbp+0x10]                                                                                             │
   │0x7ffff76f7e55 <_ZN16CRRegistratorImp8RegisterEbPv+597> mov    rax,QWORD PTR [rdi]                                                                                                  │
   │0x7ffff76f7e58 <_ZN16CRRegistratorImp8RegisterEbPv+600> call   QWORD PTR [rax+0x30]                                                                                                 │
   │0x7ffff76f7e5b <_ZN16CRRegistratorImp8RegisterEbPv+603> test   al,al                                                                                                                │
   │0x7ffff76f7e5d <_ZN16CRRegistratorImp8RegisterEbPv+605> je     0x7ffff76f7ce6 <_ZN16CRRegistratorImp8RegisterEbPv+230>                                                              │
   │0x7ffff76f7e63 <_ZN16CRRegistratorImp8RegisterEbPv+611> jmp    0x7ffff76f7d29 <_ZN16CRRegistratorImp8RegisterEbPv+297>      
   │0x7ffff76f7e68 <_ZN16CRRegistratorImp8RegisterEbPv+616> xor    edx,edx                                                                                                              │
   │0x7ffff76f7e6a <_ZN16CRRegistratorImp8RegisterEbPv+618> mov    rsi,r12                                                                                                              │
   │0x7ffff76f7e6d <_ZN16CRRegistratorImp8RegisterEbPv+621> mov    rdi,rbp                                                                                                              │
   │0x7ffff76f7e70 <_ZN16CRRegistratorImp8RegisterEbPv+624> call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>                                         │
   │0x7ffff76f7e75 <_ZN16CRRegistratorImp8RegisterEbPv+629> jmp    0x7ffff76f7e41 <_ZN16CRRegistratorImp8RegisterEbPv+577>                                                              │
   │0x7ffff76f7e77 <_ZN16CRRegistratorImp8RegisterEbPv+631> mov    edx,0x4                                                                                                              │
   │0x7ffff76f7e7c <_ZN16CRRegistratorImp8RegisterEbPv+636> mov    rsi,r12                                                                                                              │
   │0x7ffff76f7e7f <_ZN16CRRegistratorImp8RegisterEbPv+639> mov    rdi,rbp                                                                                                              │
   │0x7ffff76f7e82 <_ZN16CRRegistratorImp8RegisterEbPv+642> call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>    

这不是整个过程,但我认为没有必要。我想知道的是,如何到达地址0x7ffff76f7e68+616)。我在想,在这个过程中的某个地方,我会找到类似这样的指令:

jmp 0x7ffff76f7e68 <_ZN16CRRegistratorImp8RegisterEbPv+616>

但是在这个过程中没有这样的指令,它不可能到达那里,因为在地址上+611jmp指令。所以我有以下问题:

  1. 是死代码吗?
  2. 是否可以+616从其他程序直接跳转到这个特定地址()?

  3. 还有其他方法可以到达这个地址吗?

1个回答

有几种可能性。至少它看起来不像垃圾,所以 GDB 内置的反汇编引擎可能对操作码是正确的。

GDB 在显示那些对更大目标进行逆向工程时很重要的细节方面有些受限。实际上可能是死代码,因为名称表明这是 C++ 代码。因此,总是有可能某些虚函数从未被引用,但仍保留在二进制文件中。本质上,有些极端情况会导致死代码。但是,如果不了解有关目标的更多信息,就很难从这个小窗口中看出您提供的目标。

首先,我将首先对名称进行整理,因为您似乎有应用程序的调试符号:

CRRegistratorImp::Register(bool, void*)
CallRegGuiCallback(CRRegistrator*, void*, ERegGUIAction)

根据此列表,您可以看到 Linux ABI(System V AMD64 ABI)在 x86-64 上使用以下寄存器(按顺序):RDI、RSI、RDX、RCX、R8、R9、XMM0–7。

根据这些知识,我推断这可能是两个非常小的包装函数来完成类似的工作:

; first function
xor    edx,edx
mov    rsi,r12
mov    rdi,rbp
call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>
jmp    0x7ffff76f7e41 <_ZN16CRRegistratorImp8RegisterEbPv+577>
; second function below
mov    edx,0x4
mov    rsi,r12
mov    rdi,rbp
call   0x7ffff7596518 <_Z18CallRegGuiCallbackP13CRRegistratorPv13ERegGUIAction@plt>

大致(分别为:

CallRegGuiCallback($RDI, $RSI, 0);
CallRegGuiCallback($RDI, $RSI, 0x4);

如果没有适当的反汇编程序,您将无法判断该代码是否已失效(== 未引用)。GDB 对于这项工作来说太粗糙了。即使使用适当的反汇编程序,您也不能 100% 确定它是死代码,即使反汇编程序“推理”它是死代码。

也就是说,尝试radare2(免费,开源)、Hopper(商业,但负担得起)或IDA Pro(商业,但相对昂贵,但非常强大)。这些应该让您更好地了解代码的哪些部分被代码的其他部分引用。

回答您的问题:

  1. 是死代码吗?

    可能,但没有办法确定(即排除假阴性!)。

  2. 是否可以从其他程序直接跳转到这个特定地址(+616)?

    当然,在jmp语义上,a实际上甚至可能就足够了,因为这些小函数似乎将参数传递给了call它们自己。

  3. 还有其他方法可以到达这个地址吗?

    是的,从我的头脑中我可以想出大约六个左右,而且可能还有更多偷偷摸摸的。然而,那个(子)问题有点开放。无论如何,您可以jmp或使用任何类型的条件跳转。您可以call或者您可以将地址加载到寄存器中并执行间接操作,call或者您可以混淆地址,将其加载到寄存器中,然后进行任何类型的位处理和算术以及间接调用,或者您可以拥有一个 vtable最终会调用这个特定的代码块。

在这种情况下,更大的反汇编可能会有所帮助。