1、代码示例
#include "stdafx.h"
int main(int argc, char* argv[])
{
int i=0, a[4]={1,2,3,4},j=5;
for(i=4; i>=0; i--)
printf("%d",a[i]);
printf("\n end!");
return 0;
}
2、反汇编
我们反汇编赋值语句时,首先可以发现在定义时元素是按照先后顺序入栈的(即自左向右入栈),在这里我们先将 i 压入栈中,然后将数组 a[4] 压入栈中,最后将 j=5 压入栈中;然后观察 数组 a[4] 元素的入栈,发现 【ebp-14h】数组的首地址,且入栈顺序是 4,3,2,1;因此我么可以判断,数组入栈顺序是从右至左。
上面我们反汇编的是int数组,发现这个每个元素占 4个字节。下图,我们反汇编的是字符数组的,通过堆栈我们可以知道字符数组每个元素占 1个字节。
3、数组示例
参考链接:常见指针和数组的反汇编(x86)
一维数组的定义和赋值
8: int i=0, a[4]={1,2,3,4},temp;
0040D778 C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
0040D77F C7 45 EC 01 00 00 00 mov dword ptr [ebp-14h],1//a[1]
0040D786 C7 45 F0 02 00 00 00 mov dword ptr [ebp-10h],2//a[2]
0040D78D C7 45 F4 03 00 00 00 mov dword ptr [ebp-0Ch],3//a[3]
0040D794 C7 45 F8 04 00 00 00 mov dword ptr [ebp-8],4 //a[4]
二维数组:
8: int i, a[2][3]={1,2,3,4},temp;
0040D778 C7 45 E4 01 00 00 00 mov dword ptr [ebp-1Ch],1
0040D77F C7 45 E8 02 00 00 00 mov dword ptr [ebp-18h],2
0040D786 C7 45 EC 03 00 00 00 mov dword ptr [ebp-14h],3
0040D78D C7 45 F0 04 00 00 00 mov dword ptr [ebp-10h],4
0040D794 33 C0 xor eax,eax
0040D796 89 45 F4 mov dword ptr [ebp-0Ch],eax //a[1][1]
0040D799 89 45 F8 mov dword ptr [ebp-8],eax //a[1][2]
一维数组的元的赋值、取值、自增
10: a[0] = 6; //数组元素的赋值
0040D79B C7 45 EC 06 00 00 00 mov dword ptr [ebp-14h],6
11: temp = a[1]; //数组元素的取值
0040D7A2 8B 45 F0 mov eax,dword ptr [ebp-10h]
0040D7A5 89 45 E8 mov dword ptr [ebp-18h],eax
12: a[2]++; //自增
0040D7A8 8B 4D F4 mov ecx,dword ptr [ebp-0Ch]
0040D7AB 83 C1 01 add ecx,1
0040D7AE 89 4D F4 mov dword ptr [ebp-0Ch],ecx
二维数组:可以发现表示二维数组的元素和一维数组相差不大,都是直接定位内存单元地址寻找元素的,和下标无关。
10: a[0][0] = 6;
0040D79C C7 45 E4 06 00 00 00 mov dword ptr [ebp-1Ch],6
11: temp = a[0][1];
0040D7A3 8B 4D E8 mov ecx,dword ptr [ebp-18h]
0040D7A6 89 4D E0 mov dword ptr [ebp-20h],ecx
12: a[0][2]++;
0040D7A9 8B 55 EC mov edx,dword ptr [ebp-14h]
0040D7AC 83 C2 01 add edx,1
0040D7AF 89 55 EC mov dword ptr [ebp-14h],edx
一维数组中元素的动态赋值与被赋值
//eax = i
14: a[i] = i+2; //被变量动态赋值
0040D7C9 8B 45 FC mov eax,dword ptr [ebp-4]
0040D7CC 83 C0 02 add eax,2
0040D7CF 8B 4D FC mov ecx,dword ptr [ebp-4]
0040D7D2 89 44 8D EC mov dword ptr [ebp+ecx*4-14h],eax
16: a[i] = 10; //被常量动态赋值
0040D7F0 8B 45 FC mov eax,dword ptr [ebp-4]
0040D7F3 C7 44 85 EC 0A 00 00 mov dword ptr [ebp+eax*4-14h],0Ah
14: temp = a[i]; //赋值给变量
0040D7C9 8B 45 FC mov eax,dword ptr [ebp-4]
0040D7CC 8B 4C 85 EC mov ecx,dword ptr [ebp+eax*4-14h]
二维数组:
11: a[0][i] = i+2; //被变量动态赋值
0040D7BB 8B 55 FC mov edx,dword ptr [ebp-4]
0040D7BE 83 C2 02 add edx,2
0040D7C1 8B 45 FC mov eax,dword ptr [ebp-4]
0040D7C4 89 54 85 E4 mov dword ptr [ebp+eax*4-1Ch],edx
16: a[0][i] = 10; //被常量动态赋值
0040D7EE 8B 4D FC mov ecx,dword ptr [ebp-4]
0040D7F1 C7 44 8D E4 0A 00 00 mov dword ptr [ebp+ecx*4-1Ch],0Ah
14: temp = a[0][i]; //动态赋值给变量
0040D7CA 8B 4D FC mov ecx,dword ptr [ebp-4]
0040D7CD 8B 54 8D E4 mov edx,dword ptr [ebp+ecx*4-1Ch]
0040D7D1 89 55 E0 mov dword ptr [ebp-20h],edx
4、溢出函数
关于溢出的函数,之前详细的讲解过了 strcpy 和 memcpy 两个函数,所以这里就不细讲了,详情请移步:哦!
1、连接函数 strcat(str1, str2)
如下图,为此函数的溢出原理:str2长度 > str1 的长度,然后导致溢出,当 str2 足够长时,溢出的字符串把 函数执行结束后 ret 的返回地址覆盖了,然后就可以实现地址跳转了。