全局变量和局部变量
在提及全局变量和局部变量之前,需要先谈谈程序运行时在内存中的状态
任何一个程序在运行时都会把内存分成如下几块区域:
全局变量
- 全局变量在程序编译完成后地址就已经确定下来了,只要程序启动,全局变量就已经存在了,启动后里面是否有值取决于声明时是否给定了初始值,如果没有,默认为0
- 全局变量的值可以被所有函数所修改,里面存储的是最后一次修改的值.
- 全局变量所占内存会一直存在,直到整个进程结束.
- 全局变量的反汇编识别:
MOV 寄存器,byte/word/dword ptr ds:[0x12345678]
上面的0x12345678是固定的地址,每次程序启动都不变
通过寄存器的宽度,或者byte/word/dword 来判断全局变量的宽度
- 全局变量就是所谓的基址
局部变量
- 局部变量在程序编译完成后并没有分配固定的地址
- 在所属的方法没有被调用时,局部变量并不会分配内存地址,只有当所属的程序被调用了,才会在堆栈中分配内存
- 当局部变量所属的方法执行完毕后,局部变量所占用的内存将变成垃圾数据.局部变量消失
- 局部变量只能在方法内部使用,函数A无法使用函数B的局部变量
- 局部变量的反汇编识别
[ebp-4]
[ebp-8]
[ebp-0xC]
例子
#include "stdafx.h"
//全局变量
int global=0x610;
int main(int argc, char* argv[])
{
//局部变量
int temp=0x160;
global=global+temp;
return 0;
}
4: #include "stdafx.h"
5: //全局变量
6: int global=0x610;
7: int main(int argc, char* argv[])
8: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,44h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-44h]
0040101C mov ecx,11h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
9: //局部变量
10: int temp=0x160;
00401028 mov dword ptr [ebp-4],160h
11:
12: global=global+temp;
0040102F mov eax,[global (00428a64)]
00401034 add eax,dword ptr [ebp-4]
00401037 mov [global (00428a64)],eax
13:
14: return 0;
0040103C xor eax,eax
15: }
0040103E pop edi
0040103F pop esi
00401040 pop ebx
00401041 mov esp,ebp
00401043 pop ebp
00401044 ret
我们可以看到相关代码在这里:
9: //局部变量
10: int temp=0x160;
00401028 mov dword ptr [ebp-4],160h
11:
12: global=global+temp;
0040102F mov eax,[global (00428a64)]
00401034 add eax,dword ptr [ebp-4]
00401037 mov [global (00428a64)],eax
我们可以很清楚地看到局部变量是直接保存在[ebp-4]也就是堆栈中的
而全局变量则是保存在一个固定的内存地址00428a64里
同时在断点刚断下的时候,就是还没运行上面的代码时,观察[global (00428a64)]也就是全局变量地址里存储的内容时,可以看到
我们全局变量已经初始化并被赋值了,观察整个main函数的反汇编代码,我们并没有看到全局变量赋值相关的语句,但这并不能说明程序在运行前就已经赋值了,别忘了也有可能是在mainCRTStartup中将这里初始化的,为了印证这一点,我们直接将程序用OD打开,然后会在mainCRTStartup函数执行前断下,以此来验证是否是一打开程序全局变量就已经初始化了
输入之前全局变量的地址,然后查看
可以观察到左下角数据窗口里,我们的全局变量已经初始化了,验证完毕