您的位置:首页 > 编程语言 > C语言/C++

C++逆向第十课-----数组与指针的寻址

2017-03-09 10:29 323 查看
好久没写博客了,做人最难的事情就是坚持,不管怎么样,从今天开始重新捡起来,做人还是应该有始有终

0x00 逆向时候判断数组的依据

证明在内存上是连续的,中间不留空

数据类型上要有一致性

如何证明:

比例因子寻址,例如:mov reg,[ebp + esi * 4 - 8]

循环迭代

数组的优势就是循环批量的操作

0x01 数组与局部变量赋值的对比

源码:

8:        int n1 = 1;
00401028   mov         dword ptr [ebp-4],1
9:        int n2 = 2;
0040102F   mov         dword ptr [ebp-8],2
10:       int n3 = 3;
00401036   mov         dword ptr [ebp-0Ch],3
11:       int n4 = 4;
0040103D   mov         dword ptr [ebp-10h],4
12:       int n5 = 5;
00401044   mov         dword ptr [ebp-14h],5
13:
14:       int nArr[5] = {1,2,3,4,5};
0040104B   mov         dword ptr [ebp-28h],1
00401052   mov         dword ptr [ebp-24h],2
00401059   mov         dword ptr [ebp-20h],3
00401060   mov         dword ptr [ebp-1Ch],4
00401067   mov         dword ptr [ebp-18h],5


由上面的代码可以看出连续定义相同类型的局部变量和数组赋值顺序是相反的

0x02 数组与字符串

在C++中,字符串本身就是数组

字符串初始化代码Debug与Release版对比

C++源码

char szHello[] = "Hello World!!!!";
printf("%s\r\n",szHello);


Debug版反汇编

mov     eax, dword ptr ds:aHelloWorld ; "Hello World!!!!"
mov     [ebp+var_38], eax
mov     ecx, dword ptr ds:aHelloWorld+4 ; "o World!!!!"
mov     [ebp+var_34], ecx
mov     edx, dword ptr ds:aHelloWorld+8 ; "rld!!!!"
mov     [ebp+var_30], edx
mov     eax, dword ptr ds:aHelloWorld+0Ch ; "!!!"
mov     [ebp+var_2C], eax
lea     ecx, [ebp+var_38]
push    ecx
push    offset aS_0     ; "%s\r\n"
call    _printf
add     esp, 8


Release版反汇编

mov     ecx, dword_40603C
mov     eax, dword_406038
mov     edx, dword_406040
mov     [esp+10h+var_C], ecx
lea     ecx, [esp+10h+var_10]
mov     [esp+10h+var_10], eax
mov     eax, dword_406044
push    ecx
push    offset aS       ; "%s\r\n"
mov     [esp+18h+var_8], edx
mov     [esp+18h+var_4], eax
call    _printf


对比以上源码可知道,字符串赋值操作都是,将.data数据区的地址给连续的栈空间,相当于给数组赋初值

0x03数组字与字符串处理

在Debug版下,将直接调用库函数处理字符串,但是在Release版本下,会采用内联汇编进行优化。但是在高版本的编译器中这些优化又消失了如VS2013,因为这些优化都集成到了硬件当中去了

C++源码

char szHello[] = "Hello World!!!!";
printf("%d\r\n",strlen(szHello));


Debug版反汇编

mov     eax, dword ptr ds:aHelloWorld ; "Hello World!!!!"
mov     dword ptr [ebp+Str], eax
mov     ecx, dword ptr ds:aHelloWorld+4 ; "o World!!!!"
mov     [ebp+var_C], ecx
mov     edx, dword ptr ds:aHelloWorld+8 ; "rld!!!!"
mov     [ebp+var_8], edx
mov     eax, dword ptr ds:aHelloWorld+0Ch ; "!!!"
mov     [ebp+var_4], eax
lea     ecx, [ebp+Str]
push    ecx             ; Str
call    _strlen


Release版反汇编

mov     eax, dword_406038
mov     ecx, dword_40603C
mov     edx, dword_406040
mov     [esp+10h+var_10], eax
mov     eax, dword_406044
push    edi
mov     [esp+14h+var_C], ecx
mov     [esp+14h+var_4], eax
//以下为无分支求字符串长度的汇编代码
lea     edi, [esp+14h+var_10]
or      ecx, 0FFFFFFFFh
xor     eax, eax
mov     [esp+14h+var_8], edx
repne scasb
not     ecx
dec     ecx
push    ecx
push    offset aD       ; "%d\r\n"
call    _printf
add     esp, 8


0x04下标寻址和指针寻址

指针寻址方式不但没有下标寻址方式便利,而且效率也比下标寻址低。这一点我们可以用反汇编证明。

C++源码

char szHello[] = "Hello!!";
char * pChar = "Hello!!";
printf("%c\r\n",szHello[0]);
printf("%c\r\n",* pChar);


Debug版反汇编

11:       char szHello[] = "Hello!!";
0040B4B8   mov         eax,[string "Hello!!" (0041fe58)]
0040B4BD   mov         dword ptr [ebp-8],eax
0040B4C0   mov         ecx,dword ptr [string "Hello World!!!!"+4 (0041fe5c)]
0040B4C6   mov         dword ptr [ebp-4],ecx
12:       char * pChar = "Hello!!";
0040B4C9   mov         dword ptr [ebp-0Ch],offset string "Hello!!" (0041fe58)
13:       printf("%c\r\n",szHello[0]);
0040B4D0   movsx       edx,byte ptr [ebp-8]
0040B4D4   push        edx
0040B4D5   push        offset string "%d\r\n" (0041fe50)
0040B4DA   call        printf (0040b7b0)
0040B4DF   add         esp,8
14:       printf("%c\r\n",* pChar);
0040B4E2   mov         eax,dword ptr [ebp-0Ch]
0040B4E5   movsx       ecx,byte ptr [eax]
0040B4E8   push        ecx
0040B4E9   push        offset string "%d\r\n" (0041fe50)
0040B4EE   call        printf (0040b7b0)
0040B4F3   add         esp,8


由以上反汇编代码可以看出指针多了一次间接访问

0x04多维数组下标寻址

以二位下标为例子

C++源码

int ary[3][5] = {
{1,2,3,4,5},
{1,2,3,4,5},
{1,2,3,4,5}
};
printf("%d\r\n",ary[argc + 1][0]);


Debug版反汇编

17:       printf("%d\r\n",ary[argc + 1][0]);
0040B521   mov         eax,dword ptr [ebp+8]
0040B524   add         eax,1
0040B527   imul        eax,eax,14h
0040B52A   mov         ecx,dword ptr [ebp+eax-3Ch]
0040B52E   push        ecx
0040B52F   push        offset string "%d\r\n" (0041fe50)
0040B534   call        printf (0040b7b0)
0040B539   add         esp,8


可以看出数组下标寻址公式为

二维数组type nArray[M]
,使用i,j作为下标寻址

nArray + i * N * sizeof(type) + j * sizeof(type)
= nArray + i * N * sizeof(type) + j*sizeof(type)


Release版反汇编

mov     ecx, [esp+eax*4+3Ch+var_28]
push    ecx
push    offset aD       ; "%d\r\n"
call    _printf


由以上反汇编可以看出有些许优化,具体优化公式为

nArray + i * N * sizeof(type) + j * sizeof(type)
=nArray + sizeof(type)* (i * N + j)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++逆向