前言
这一次我们要通过逆向分析的视角分析一下普通局部变量,静态局部变量,全局变量,静态全局变量,const全局变量的差异
一只Demo
int g_global_int = 0x01;
static int g_static_global_int = 0x02;
const int g_const_global_int = 0x03;
void local_variable_demo()
{
int local_int = 0x04;
static int static_local_int = 0x05;
const int const_local_int = 0x06;
printf("%d, %d, %d\n", local_int, static_local_int, const_local_int);
}
void global_variable_demo()
{
printf("%d, %d, %d\n", g_global_int, g_static_global_int, g_const_global_int);
}
int main()
{
local_variable_demo();
global_variable_demo();
return 0;
}
我们需要将上面的代码编译为可执行程序,然后我们使用x64dbg对上面的程序进行分析
局部变量
局部变量我们需要关注 local_variable_demo 接口,下面的图为这个接口反汇编内容

普通局部变量

在上面的返回编结果中我们需要关注三个位置,第一个位置 sub esp, 0xD8,这条指令的含义是对 esp 寄存器中的内容减 0xD8,esp寄存器使我们的栈顶指针,栈又是向下增长的,所以对esp做减法相当于开辟了一段栈空间,而我们的局部变量就是要保存在这里开辟的栈空间上的
第二个位置 mov dword ptr ss:[ebp-0x8], 0x4,对栈上 ebp-0x8 处的位置上写入 0x04,ebp-0x8就是我们的局部变量,而0x04也就是我们的初始值了
第三个位置 mov edx, dword ptr ss:[ebp-0x8],是从栈 ebp-0x8 位置上,也就是我们的局部变量上读取数据并存储到寄存器 edx 中。那么为什么要将局部变量上的值存储到 edx 寄存器中呢?我们可以看到下一条指令是 push edx,这条指令的作用是将edx中的值作为printf的参数压到栈上,因为push指令的操作数不能是内存,所以需要先将值保存到 edx 寄存器中,再通过 edx 压入到栈上
静态局部变量

我们可以发现静态局部变量就只有一个使用的语句,将静态变量中的值复制到了 ecx 寄存器中,那静态变量初始化的过程哪去了呢?
这是因为静态变量在程序编译的时候就已经完成了初始化的工作,如果静态变量初始化的值不为0,那么静态变量的地址会指向数据段,在编译时就将值直接写入到了数据段中,我们可以看到我们反汇编的结果中也确实指向了数据段,如果初始值为0,就会被分配到.bss段
const 局部变量

我们可以看到const局部变量和普通的局部变量是一样的,那是如何做到const变量的值不可修改的呢?答案是const 变量不能修改是编译器做的检查,当发现修改const变量时就会提示编译错误
全局变量
全局变量我们要看 global_variable_demo 接口

从上图中我们可以看出三种全局变量都在数据段,看起来是一样的,但是我们看一下变量的地址,g_global_init 的地址为 0xBAA020,g_static_global_int 的地址为 0xBAA024,g_const_global_int 的地址为 0xBA7B40,我们可以发现普通全局变量和静态全局变量的存储空间是挨着的,而const全局变量的地址就远了很多这是为什么呢?
我们来看一下内存布局

我们可以发现 g_global_init 和 g_static_global_int 在.data 段,该数据段是可写的,而const全局变量由于不可写入,所以被放在了只读数据段 .rdata 中
安全问题
接下来要简单的说一下安全性问题,我们通过上面已经可以看到,程序的数据就保存在栈上和数据段中,我们可以很轻易的就行查找和篡改,那么我们如何防范我们的程序被人恶意分析数据和篡改呢?
我们可以使用 Virbox protector 工具对我们的程序进行保护,保护后的程序其他人就没有办法进行调试了,同时也可以让我们的程序变得无法分析,还有内存校验等等功能,让我们的程序和数据变的安全