x86 反汇编/循环示例
这个函数的功能是什么?它接受什么类型的参数,并且它返回什么类型的结果(如果有)?
push ebp
mov ebp, esp
mov esi, [ebp + 8]
mov ebx, 0
mov eax, 0
mov ecx, 0
_Label_1:
mov ecx, [esi + ebx * 4]
add eax, ecx
inc ebx
cmp ebx, 100
jne _Label_1
mov esp, ebp
pop ebp
ret 4
该函数循环遍历一个由 esi 指向的 4 字节整数数组,并将每个条目相加。它在 eax 中返回总和。唯一的参数(位于 [ebp + 8] 中)是指向整数数组的指针。ebx 和 100 之间的比较表明输入数组包含 100 个条目。指针偏移量 [esi + ebx * 4] 表明数组中的每个条目都是 4 字节宽的。
这个函数的 C 原型是什么?确保包含参数、返回值和调用约定。
push ebp
mov ebp, esp
mov esi, [ebp + 8]
mov ebx, 0
mov eax, 0
mov ecx, 0
_Label_1:
mov ecx, [esi + ebx * 4]
add eax, ecx
inc ebx
cmp ebx, 100
jne _Label_1
mov esp, ebp
pop ebp
ret 4
请注意 **ret** 函数如何从堆栈中清除其参数?这意味着该函数是一个 STDCALL 函数。我们知道该函数以指向整数数组的指针作为其唯一参数。然而,我们不知道这些整数是有符号的还是无符号的,因为 **je** 命令用于两种类型的值。我们可以假设其中一个,为了简单起见,我们可以假设无符号值(在这个函数中,无符号值和有符号值实际上将以相同的方式工作)。我们还知道返回值是一个 4 字节整数,与参数数组中找到的类型相同。由于该函数没有名称,我们可以将其简单地称为 “MyFunction”,并且我们可以将参数称为 “array”,因为它是一个数组。从这些信息中,我们可以确定 C 中的以下原型
unsigned int STDCALL MyFunction(unsigned int *array);
将此代码反编译成等效的 C 源代码。
push ebp
mov ebp, esp
mov esi, [ebp + 8]
mov ebx, 0
mov eax, 0
mov ecx, 0
_Label_1:
mov ecx, [esi + ebx * 4]
add eax, ecx
inc ebx
cmp ebx, 100
jne _Label_1
mov esp, ebp
pop ebp
ret 4
从上面的函数原型和对该函数功能的描述开始,我们可以开始为该函数编写 C 代码。我们知道该函数在循环之前初始化了 eax、ebx 和 ecx。但是,我们可以看到 ecx 只是用作中间存储位置,从数组中接收连续的值,然后将其添加到 eax。
我们将创建两个无符号整数,a(用于 eax)和 b(用于 ebx)。我们将在 **register** 限定符的帮助下定义 a 和 b,这样我们就可以指示编译器不要在堆栈上为它们创建空间。对于每个循环迭代,我们都将数组在位置 ebx*4 处的值添加到运行总和 eax。将此转换为我们的 a 和 b 变量,并使用 C 语法,我们看到
a = a + array[b];
循环可以是 **for** 循环或 **while** 循环。我们看到循环控制变量 b 在循环之前初始化为 0,并且在每次循环迭代中递增 1。循环在 *递增后* 对 b 进行 100 的测试,因此我们知道 b 在循环主体内部从不等于 100。利用这些简单的事实,我们将以 3 种不同的方式编写循环
首先,使用 **while** 循环。
unsigned int STDCALL MyFunction(unsigned int *array)
{
register unsigned int b = 0;
register unsigned int a = 0;
while(b != 100)
{
a = a + array[b];
b++;
}
return a;
}
或者,使用 **for** 循环
unsigned int STDCALL MyFunction(unsigned int *array)
{
register unsigned int b;
register unsigned int a = 0;
for(b = 0; b != 100; b++)
{
a = a + array[b];
}
return a;
}
最后,使用 **do-while** 循环
unsigned int STDCALL MyFunction(unsigned int *array)
{
register unsigned int b = 0;
register unsigned int a = 0;
do
{
a = a + array[b];
b++;
}while(b != 100);
return a;
}