跳转到内容

x86 反汇编/变量示例

来自维基教科书,开放世界中的开放书籍

示例:识别 C++ 代码

[编辑 | 编辑源代码]

你能说出以下访问器方法的原始 C++ 源代码大致是什么样的吗?

 push ebp
 mov ebp, esp
 mov eax, [ecx + 8] ;THISCALL function, passes "this" pointer in ecx
 mov esp, ebp
 pop ebp
 ret

我们不知道类名,因此我们将使用一个通用的名称 MyClass(或者您想称呼它为任何名称)。我们将列出一个简单的类定义,它在偏移量 +8 处包含一个数据值。偏移量 +8 是唯一被访问的数据值,因此我们不知道前 8 个字节的数据是什么样的,但我们将假设(为了我们的目的)我们的类看起来像这样

 class MyClass
 {
   int value1;
   int value2;
   int value3; //offset +8
   ...
 }

然后我们将创建我们的函数,我将它命名为“GetValue3()”。我们知道被访问的数据值位于 [ecx+8] 处(我们在上面定义为“value3”)。此外,我们知道数据正在被读入一个 4 字节寄存器 (eax) 中,并且没有被截断。因此,我们可以假设 value3 是一个 4 字节的数据值。我们可以使用 **this** 指针作为存储在 ecx 中的指针值,并且我们可以从该指针(value3)获取位于偏移量 +8 处的元素。

 MyClass::GetValue3()
 {
   return this->value3;
 }

**this** 指针在这里不是必需的,但我仍然使用它来说明变量是如何作为 **this** 指针的偏移量被访问的。

**注意**:请记住,我们不知道类中前 8 个字节实际上是什么样的,我们只有一个访问器方法,它只访问偏移量 +8 处的单个数据值。该类也可以看起来像这样

 class MyClass /*Alternate Definition*/
 {
    byte byte1;
    byte byte2;
    short short1;
    long value2;
    long value3;
  ...
 }

或者,任何其他 8 字节的组合。

示例:识别 C++ 代码

[编辑 | 编辑源代码]

你能说出以下设置器方法的原始 C++ 源代码大致是什么样的吗?

 push ebp
 mov ebp, esp
 cmp [ebp + 8], 0
 je error
 mov eax, [ebp + 8]
 mov [ecx + 0], eax
 mov eax, 1
 jmp end
 :error
 mov eax, 0
 :end
 mov esp, ebp
 pop ebp
 ret

这段代码看起来有点复杂,但不要惊慌!我们将慢慢地一步一步地进行。前两行代码设置了堆栈帧。

 push ebp
 mov ebp, esp

接下来的两行代码将 [ebp + 8](我们知道它是第一个参数)的值与零进行比较。如果 [ebp+8] 为零,函数跳转到标签“error”。我们看到标签“error”将 eax 设置为 0,并返回。我们以前没有见过它,但这看起来很像一个 **if** 语句。“如果参数为零,则返回零”。

另一方面,如果参数不为零,我们将值移入 eax,然后将值移入 [ecx + 0],我们知道它是 MyClass 中的第一个数据字段。我们还从这段代码中看到,这个第一个数据字段必须是 4 个字节长(因为我们使用的是 eax)。在我们将 eax 移入 [ecx + 0] 之后,我们将 eax 设置为 1,并跳转到函数的结尾。

如果我们使用与上面问题 1 中相同的 MyClass 定义,我们可以为我们的函数“SetValue1(int val)”获得以下代码。

 int MyClass::SetValue1(int val)
 {
   if(val == 0) return 0;
   this->value1 = val;
   return 1;
 }

请注意,由于我们在失败时返回 0,在成功时返回 1,因此该函数看起来像具有 **bool** 返回值。但是,返回值是 4 个字节宽(使用的是 eax),但 **bool** 的大小是特定于实现的,因此我们不能确定。**bool** 通常被定义为具有 1 个字节的大小,但它通常以与 **int** 相同的方式存储。

华夏公益教科书