局部变量
-
利用栈存放局部变量
局部变量在栈中进行分配,函数执行后会释放这些栈。
用sub esp, X 来为局部变量分配空间
用[ebp - X]寻址调用这些变量
用[ebp + X]参数调用相对于ebp偏移量是正的编译器在优化模式时,通过esp寄存器直接对局部变量和参数进行寻址
函数退出时,用add esp, 8指令平衡栈,释放局部变量释放的内存
(Delphi编译器)通过esp加一个负数来进行内存的分配。
编译器可能会用push reg 取代sub esp, 4指令节省空间
// 局部变量分配与清楚栈的形式
1.
sub esp, n
...
add esp, n
2.
add esp, -n
...
sub esp, -n
3.
push reg
...
pop reg
//利用push reg指令取代sub esp, 4
//C
int add(int x, int y)
int main()
{
int a=5;
int b=6;
add(a,b);
return 0;
}
int add(int x, int y)
{
int z;
z=x+y;
return z;
}
//汇编代码如下(不进行优化)
//main 主函数
push ebp
mov ebp, esp
sub esp, 00000008
mov [ebp-04], 00000005 ;存放参数a
mov [ebp-08], 00000006 ;存放参数b
mov eax, dword ptr [ebp-08] ;参数b存放到eax中
push eax
mov ecx, dword ptr [ebp-04]
push ecx
call 0040102A
add esp, 00000008
xor eax, eax
mov esp, ebp
pop ebp
ret
//add(int x, int y)
push ebp
mov ebp, esp
push ecx ;为局部变量分配内存(sub esp, 4)(开辟一块栈)
mov eax, dword ptr[ebp+08] ;取两个参数
add eax, dword ptr[ebp+0C]
mov dword ptr[ebp-04], eax ;把和储存在局部变量[ebp-04]
mov eax, dword ptr[ebp-04]
mov esp, ebp
pop ebp
ret
局部变量的起始值时随机的,是其他函数执行后留在栈中的垃圾数据,因此需要对其初始化。
初始化局部变量有两种方法:
1.通过mov指令为变量赋值,例如mov [ebp-04], 5;
2.使用push指令直接将值压入栈,例如push 5.
- 利用寄存器存放局部变量
除了栈占用2个寄存器,编译器会利用剩下的6个通用寄存器尽可能有效地存放局部变量。这样可以少产生代码,提高程序的效率。如果寄存器不够用,编译就会将变量放到栈中。在进行逆向分析时,局部变量的生存周期比较短,必须及时确定寄存器的变量时那个变量。
全局变量
全局变量作用于整个程序,他一直存在,放在全局变量的内存区中。局部变量则存在于函数的栈中,函数调用结束后便会消失。在大多数程序中,常数一般放在全局变量中。(注册版标记,测试版标记)
大多数情况下,在汇编代码中识别全局变量比在其他结构中要容易得多。全局变量通常位于数据区块(.data)的一个固定地址处,,当程序需要访问全局变量时,一般用一个固定的硬编码地址直接等对内存寻址。
mov eax, dword ptr [4084C0h]