数组的访问

源程序

// 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



可以看出, 对结构数组成员的访问, 采用的是 变址 + 结构成员地址偏移的方法