数组的访问
源程序
// test1020.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#define ARRAY_SIZE 10 ///< 数组的元素个数
/// @fn ArrayInit
/// @brief 给定一个数组的首地址, 对数组初始化. 数组size = ARRAY_SIZE
void ArrayInit(char * pcArray);
/// @fn ArrayShow
/// @brief 给定一个数组的首地址, 显示数组内容
void ArrayShow(char * pcArray);
int _tmain(int argc, _TCHAR* argv[])
{
char cBuf[ARRAY_SIZE];
ArrayInit(cBuf);
ArrayShow(cBuf);
getwchar();
return 0;
}
void ArrayInit(char * pcArray)
{
size_t nIndex = 0;
for (nIndex = 0; nIndex < ARRAY_SIZE; nIndex++)
*(pcArray + nIndex) = nIndex + 1;
}
void ArrayShow(char * pcArray)
{
size_t nIndex = 0;
for (nIndex = 0; nIndex < ARRAY_SIZE; nIndex++)
_tprintf(L"*(pcArray + %d) = %d\r\n", nIndex, *(pcArray + nIndex));
}
OD反汇编
00821000 >/$ 83EC 10 sub esp, 10 ; 开辟16个字节的栈空间, 小地址前10个为数据, 大地址最后是一个栈溢出检查值
00821003 |. A1 00308200 mov eax, dword ptr [__security_cookie] ; dword ptr [__security_cookie]每次的栈溢出检查初始值值都不同
00821008 |. 33C4 xor eax, esp
0082100A |. 894424 0C mov dword ptr [esp+C], eax ; 压入栈溢出检查的参数
0082100E |. 33C0 xor eax, eax
00821010 |> 8AC8 /mov cl, al ; 对数组进行初始化
00821012 |. FEC1 |inc cl ; 每个元素初始值 = 当前位置索引 + 1
00821014 |. 880C04 |mov byte ptr [esp+eax], cl ; 基址 + 变址, 可以看成是对数组的操作.
00821017 |. 40 |inc eax ; 指向数组中下一个元素的索引
00821018 |. 83F8 0A |cmp eax, 0A ; 数组的元素个数是10
0082101B |.^ 72 F3 \jb short 00821010
0082101D |. 56 push esi
0082101E |. 57 push edi ; 经过2个push后, 执行后, 数组首地址变为了 [esp + 8]
0082101F |. 8B3D 9C208200 mov edi, dword ptr [<&MSVCR90.wprintf>] ; MSVCR90.wprintf
00821025 |. 33F6 xor esi, esi ; 变址指针清零, 用来遍历数组
00821027 |> 0FBE5434 08 /movsx edx, byte ptr [esp+esi+8] ; [esp + 8] 为数组首地址, esi 为变址指针
0082102C |. 52 |push edx
0082102D |. 56 |push esi
0082102E |. 68 F4208200 |push 008220F4 ; UNICODE "*(pcArray + %d) = %d",CR,LF
00821033 |. FFD7 |call edi ; 调用wprintf 打印数组元素
00821035 |. 46 |inc esi ; 指向下一个元素索引
00821036 |. 83C4 0C |add esp, 0C ; call edi(msvcr90.wprintf)之后的堆栈平衡
00821039 |. 83FE 0A |cmp esi, 0A ; 总共要打印10次, 数组的元素个数为10
0082103C |.^ 72 E9 \jb short 00821027 ; JB命令只判断 C标志, 判断是否有进位
0082103E |. FF15 A4208200 call dword ptr [<&MSVCR90.getwchar>] ; [getwchar
00821044 |. 8B4C24 14 mov ecx, dword ptr [esp+14]
00821048 |. 5F pop edi ; 堆栈平衡, 对应于 012a101d
00821049 |. 5E pop esi
0082104A |. 33CC xor ecx, esp
0082104C |. 33C0 xor eax, eax
0082104E |. E8 04000000 call __security_check_cookie ; 栈溢出检查, 用的参数是 012a100a 压入栈的参数
00821053 |. 83C4 10 add esp, 10 ; 堆栈平衡, 对应于012a1000
00821056 \. C3 retn
可以看出: 在汇编中对数组访问, 采用的是[基址 + 变址]的方式.
结构的访问
源程序
// test1020.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#define ARRAY_SIZE 10 ///< 数组的元素个数
typedef struct _tagInfo
{
char cType; ///< 物品类型
size_t nCounter; ///< 物品数量
wchar_t cNote[_MAX_PATH]; ///< 备注
}TAGINFO, *PTAGINFO;
int _tmain(int argc, _TCHAR* argv[])
{
TAGINFO tagInfo;
::ZeroMemory(&tagInfo, sizeof(TAGINFO));
tagInfo.cType = 1;
tagInfo.nCounter = 100;
_tcscpy_s(tagInfo.cNote, sizeof(tagInfo.cNote) / sizeof(wchar_t), L"note\r\n");
getwchar();
return 0;
}
OD反汇编
00E61000 >/$ 55 push ebp
00E61001 |. 8BEC mov ebp, esp ; esp = 0x003FF78C
00E61003 |. 83E4 F8 and esp, FFFFFFF8 ; 栈空间字节对齐, esp = 0x003FF788, 对齐后, 更靠近小地址.
00E61006 |. 81EC 18020000 sub esp, 218 ; esp = 0x003FF570, 分配218个字节栈空间, 前面是结构空间, 后面是栈溢出检查初始值
00E6100C |. A1 0030E600 mov eax, dword ptr [__security_cookie]
00E61011 |. 33C4 xor eax, esp
00E61013 |. 898424 140200>mov dword ptr [esp+214], eax ; 给栈溢出检查变量赋值
00E6101A |. 68 10020000 push 210 ; /结构长度为210
00E6101F |. 8D4424 04 lea eax, dword ptr [esp+4] ; |此时, esp + 4 为结构首地址, 因为前面有push 210
00E61023 |. 6A 00 push 0 ; |每个Bits要设置的值为0x0
00E61025 |. 50 push eax ; |结构首地址
00E61026 |. E8 33080000 call memset ; \memset
00E6102B |. 68 F420E600 push 00E620F4 ; UNICODE "note",CR,LF
00E61030 |. 8D4C24 18 lea ecx, dword ptr [esp+18] ; esp + 18 = 0x3ff578, 结构中的note部分起始地址。
00E61034 |. 68 04010000 push 104 ; 长度为0x104(260)个宽字符
00E61039 |. 51 push ecx
00E6103A |. C64424 18 01 mov byte ptr [esp+18], 1 ; esp + 0x18 = 0x3ff570, 可以看出是结构首地址. 结构.byte值 = 1
00E6103F |. C74424 1C 640>mov dword ptr [esp+1C], 64 ; esp + 1c = 0x3ff574, 结构.DWORD值 = 0x64
00E61047 |. FF15 A420E600 call dword ptr [<&MSVCR90.wcscpy_s>] ; MSVCR90.wcscpy_s
00E6104D |. 83C4 18 add esp, 18 ; 堆栈平衡, 执行后, esp = 0x3ff570, 又指向结构首地址.
00E61050 |. FF15 9C20E600 call dword ptr [<&MSVCR90.getwchar>] ; [getwchar
00E61056 |. 8B8C24 140200>mov ecx, dword ptr [esp+214] ; 栈溢出检查
00E6105D |. 33CC xor ecx, esp
00E6105F |. 33C0 xor eax, eax
00E61061 |. E8 04000000 call __security_check_cookie
00E61066 |. 8BE5 mov esp, ebp
00E61068 |. 5D pop ebp
00E61069 \. C3 retn
可以看出, 结构的访问 是 基地址 + 偏移偏移(结构的成员地址偏移, 固定的).
结构数组的访问
源程序
// test1020.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#define ARRAY_SIZE 10 ///< 数组的元素个数
typedef struct _tagInfo
{
char cType; ///< 物品类型
size_t nCounter; ///< 物品数量
wchar_t cNote[_MAX_PATH]; ///< 备注
}TAGINFO, *PTAGINFO;
int _tmain(int argc, _TCHAR* argv[])
{
size_t nIndex = 0;
TAGINFO tagInfo[ARRAY_SIZE];
::ZeroMemory(&tagInfo[0], sizeof(TAGINFO) * ARRAY_SIZE);
for (nIndex = 0; nIndex < ARRAY_SIZE; nIndex++)
{
tagInfo[nIndex].cType = 1;
tagInfo[nIndex].nCounter = rand();
wsprintf(tagInfo[nIndex].cNote, L"%s%d\r\n", L"note", nIndex);
}
getwchar();
return 0;
}
OD反汇编
012F1000 >/$ B8 A4140000 mov eax, 14A4
012F1005 |. E8 76080000 call _chkstk
012F100A |. A1 00302F01 mov eax, dword ptr [__security_cookie]
012F100F |. 33C4 xor eax, esp
012F1011 |. 898424 A01400>mov dword ptr [esp+14A0], eax
012F1018 |. 53 push ebx
012F1019 |. 55 push ebp
012F101A |. 56 push esi
012F101B |. 57 push edi
012F101C |. 68 A0140000 push 14A0 ; /结构数组总size = 0x14a0
012F1021 |. 8D4424 14 lea eax, dword ptr [esp+14] ; |结构数组首地址为 [esp + 14] = 0x0035e550
012F1025 |. 6A 00 push 0 ; |c = 00
012F1027 |. 50 push eax ; |s
012F1028 |. E8 7F080000 call memset ; \清空结构数组
012F102D |. 8B2D A4202F01 mov ebp, dword ptr [<&MSVCR90.rand>] ; MSVCR90.rand
012F1033 |. 8B1D B0202F01 mov ebx, dword ptr [<&USER32.wsprintfW>] ; USER32.wsprintfW
012F1039 |. 83C4 0C add esp, 0C ; 堆栈平衡
012F103C |. 33FF xor edi, edi ; 结构数组中的当前结构索引值清零.
012F103E |. 8D7424 14 lea esi, dword ptr [esp+14] ; esi = 结构数组第一个结构的地址
012F1042 |> C646 FC 01 /mov byte ptr [esi-4], 1 ; 结构[n].byteVal = 1
012F1046 |. FFD5 |call ebp ; 产生随机数, 随机数在eax中
012F1048 |. 57 |push edi
012F1049 |. 68 04212F01 |push 012F2104 ; UNICODE "note"
012F104E |. 8D4E 04 |lea ecx, dword ptr [esi+4] ; esi + 4 = 结构.cValueW, size = 0x210 - 0x4 - 0x4
012F1051 |. 68 10212F01 |push 012F2110 ; UNICODE "%s%d",CR,LF
012F1056 |. 51 |push ecx
012F1057 |. 8906 |mov dword ptr [esi], eax ; 当前结构.dwValue = rand(); 可以看出当前结构指针指到了结构.dwValue地址上
012F1059 |. FFD3 |call ebx ; USER32.wsprintfW
012F105B |. 47 |inc edi ; 结构数组当前结构的位置索引, base0
012F105C |. 83C4 10 |add esp, 10 ; 堆栈平衡, 对应于wsprintfW
012F105F |. 81C6 10020000 |add esi, 210 ; 指向结构数组中的下一个结构, 当前 esi = 0x0035e974
012F1065 |. 83FF 0A |cmp edi, 0A ; 结构数组元素个数 = 0xA
012F1068 |.^ 72 D8 \jb short 012F1042
012F106A |. FF15 A0202F01 call dword ptr [<&MSVCR90.getwchar>] ; [getwchar
012F1070 |. 8B8C24 B01400>mov ecx, dword ptr [esp+14B0]
012F1077 |. 5F pop edi
012F1078 |. 5E pop esi
012F1079 |. 5D pop ebp
012F107A |. 5B pop ebx
012F107B |. 33CC xor ecx, esp
012F107D |. 33C0 xor eax, eax
012F107F |. E8 07000000 call __security_check_cookie
012F1084 |. 81C4 A4140000 add esp, 14A4
012F108A \. C3 retn
可以看出, 对结构数组成员的访问, 采用的是 变址 + 结构成员地址偏移的方法