C++反汇编学习笔记(二)
Chinese:
1、地址 指针 引用
C++中地址标号用16进制表示,取一个变量地址使用&操作符,只有变量才存在内存地址,常量没有地址(不包括const定义的伪常量)
指针是一种数据类型,用于保存各种数据类型在内存中的地址。指针变量也可以取出地址,所以会出现多级指针。
C++中引用不可以单独定义,定义的时候必须初始化。引用表示一个变量的别名,对它的任何操作,本质都是在操作它所表示的变量。
2、指针和地址的区别
指针是变量,用于保存变量地址;地址是常量,是内存标号。
指针可修改,可以再次保存其他的变量地址;地址不可修改。
指针可以对其执行取地址操作得到地址;地址不可执行取地址操作。
指针包含对保存地址的解释信息;地址无法解释数据。
3、各类型指针的工作方式
通过C++的反汇编指令进行描述
// C++ Code: int nVar = 0x12345678; ;为地址赋值4字节数据12345678h mov dword ptr [ebp-10h], 12345678h // C++ Code: int *pnVar = &nVar; lea ecx, [ebp-10h] mov dword ptr [ebp-14h], ecx // C++ Code: char *pcVar = (char*)&nVar; lea edx, [ebp-10h] mov dword ptr [ebp-18h], edx // C++ Code: short *psnVar = (short*)&nVar; lea eax, [ebp-10h] mov dword ptr [ebp-1Ch], eax // C++ Code: printf("%08x", *pnVar); ;取出pnVar中保存的地址值并放入ecx中 mov ecx, dword ptr [ebp-14h] mov edx, dword ptr [ecx] ;printf函数调用部分略 // C++ Code: printf("%08x", *pcVar); ;取出pcVar中保存的地址值并放入eax中 mov eax, dword ptr [ebp-18h] ;从eax保存的地址中,以1字节方式读取数据,存入ecx中 movsx ecx, byte ptr [eax] // C++ Code: printf(“%08x", *psnVar); ;取出psnVar中保存的地址并放入edx中 mov edx, dword ptr [ebp-1Ch] ;从edx保存的地址中,以2字节的方式读取数据,存入eax中 movsx eax, word ptr [edx]
可见指针类型会按照指针类型对地址数据进行解释。去内容操作一般分为两个步骤,先取出指针中保存的地址信息,然后针对这个地址取内容,也就是一个间接寻址的过程,这也是识别指针的重要依据。
4、了解引用的内部工作原理
实际上引用类型就是指针类型,只不过它用于存放地址的内存空间对使用者而言是隐藏的。
// C++ Code int nVar = 0x12345678; mov dword ptr [ebp-4], 12345678h // C++ Code int &nVarType = nVar; ;取出变量nVar的地址放入eax中 lea eax, [ebp-4] ;将变量nVar的地址存入地址ebp-8处,这个ebp-8处便是引用类型nVarType的地址 ;从这条汇编语句中可以得出结论,引用类型在内存中是占有一席之地的 mov dword ptr [ebp-8] eax; //调用函数Add,Add的参数为int引用类型,将变量nVar作为参数传递 Add(nVar); ;取出变量nVar的地址放入ecx lea ecx, [ebp-4] ;将ecx作为参数入栈,也就是传递变量nVar的地址作为参数 push ecx; ;函数调用的指令略 call @ILT+15 (Add) (00401014) add esp, 4
引用类型的存储方式和指针是一样的,都是使用内存空间存放地址。引用只是通过编译器实现寻址,而指针需要手动寻址。
引用类型也可以作为函数的参数类型和返回类型使用。因为引用实际上就是指针,所以它同样会在参数传递时产生一份拷贝。
// C++ Code void Add(int &nVar) { nVar++; } ;取出参数nVar中的内容放入eax中 mov eax, dword ptr [ebp+8] ;对eax执行取内容操作 mov ecx, dword ptr [eax] add ecx, 1 mov edx, dword ptr [ebp+8] mov dword ptr [edx], ecx ret
从汇编代码中可以看出,引用类型的参数也占内存空间,其中保存的数据是一个地址值。取出这个地址中的数据并加1,再将+1后的结果放回。因此,在反汇编下,没有引用这种数据类型。