反汇编:指针数组和数组指针
前言:作为指针数组和数组指针的学习
指针数组
第一种写法
代码如下:
#include<stdio.h>
int main(){
//指针数组
char arr[3][10] = {
"aaaaa",
"bbbbb",
"ccccc"
};
printf("%s",arr[1]);
}
反汇编如下:
0040D440 >/> \55 PUSH EBP
0040D441 |. 8BEC MOV EBP,ESP
0040D443 |. 83EC 60 SUB ESP,60
0040D446 |. 53 PUSH EBX
0040D447 |. 56 PUSH ESI
0040D448 |. 57 PUSH EDI
0040D449 |. 8D7D A0 LEA EDI,DWORD PTR SS:[EBP-60]
0040D44C |. B9 18000000 MOV ECX,18
0040D451 |. B8 CCCCCCCC MOV EAX,CCCCCCCC
0040D456 |. F3:AB REP STOS DWORD PTR ES:[EDI]
0040D458 |. A1 2C204200 MOV EAX,DWORD PTR DS:[??_C@_05NHMN@aaaaa?$AA@] ; 将保存字符串的地址四个字节赋值给eax
0040D45D |. 8945 E0 MOV DWORD PTR SS:[EBP-20],EAX ; 将eax赋值给ebp-20
0040D460 |. 66:8B0D 30204>MOV CX,WORD PTR DS:[422030] ; 除了那四个字节之后存储字符串的地址中的双字节赋值给cx
0040D467 |. 66:894D E4 MOV WORD PTR SS:[EBP-1C],CX ; 也就是把aaaaa最后一个a的值赋值给ebp-1c,以0结尾
0040D46B |. 33D2 XOR EDX,EDX ; 清空edx
0040D46D |. 8955 E6 MOV DWORD PTR SS:[EBP-1A],EDX
0040D470 |. A1 24204200 MOV EAX,DWORD PTR DS:[??_C@_05GKCJ@bbbbb?$AA@]
0040D475 |. 8945 EA MOV DWORD PTR SS:[EBP-16],EAX
0040D478 |. 66:8B0D 28204>MOV CX,WORD PTR DS:[422028]
0040D47F |. 66:894D EE MOV WORD PTR SS:[EBP-12],CX
0040D483 |. 33D2 XOR EDX,EDX
0040D485 |. 8955 F0 MOV DWORD PTR SS:[EBP-10],EDX
0040D488 |. A1 1C204200 MOV EAX,DWORD PTR DS:[??_C@_05BHF@ccccc?$AA@]
0040D48D |. 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX
0040D490 |. 66:8B0D 20204>MOV CX,WORD PTR DS:[422020]
0040D497 |. 66:894D F8 MOV WORD PTR SS:[EBP-8],CX
0040D49B |. 33D2 XOR EDX,EDX
0040D49D |. 8955 FA MOV DWORD PTR SS:[EBP-6],EDX ; 清空ebp-6的高位两字节
0040D4A0 |. 8D45 EA LEA EAX,DWORD PTR SS:[EBP-16] ; 取bbbbb的字符串赋值给eax
0040D4A3 |. 50 PUSH EAX ; /<%s>
0040D4A4 |. 68 0C244200 PUSH OFFSET my.??_C@_02DILL@?$CFs?$AA@ ; |format = "%s"
0040D4A9 |. E8 82020000 CALL my.printf ; \printf
第二种写法
代码如下:
#include<stdio.h>
int main(){
//指针数组
//还可以这样表示
//相当于定义为arr[][10]
char* arr[10] = {
"aaaaa",
"bbbbb",
"ccccc"
};
printf("%s",arr[1]);
}
反汇编如下:
0040D440 >/> \55 PUSH EBP
0040D441 |. 8BEC MOV EBP,ESP
0040D443 |. 83EC 68 SUB ESP,68
0040D446 |. 53 PUSH EBX
0040D447 |. 56 PUSH ESI
0040D448 |. 57 PUSH EDI
0040D449 |. 8D7D 98 LEA EDI,DWORD PTR SS:[EBP-68]
0040D44C |. B9 1A000000 MOV ECX,1A
0040D451 |. B8 CCCCCCCC MOV EAX,CCCCCCCC
0040D456 |. F3:AB REP STOS DWORD PTR ES:[EDI]
0040D458 |. C745 D8 2C204>MOV DWORD PTR SS:[EBP-28],OFFSET my.??_C@_05NHMN@aaaaa?$AA@ ; 将保存字符串的地址赋值给ebp-28中
0040D45F |. C745 DC 24204>MOV DWORD PTR SS:[EBP-24],OFFSET my.??_C@_05GKCJ@bbbbb?$AA@ ; 将保存字符串的地址赋值给ebp-24中
0040D466 |. C745 E0 1C204>MOV DWORD PTR SS:[EBP-20],OFFSET my.??_C@_05BHF@ccccc?$AA@ ; 将保存字符串的地址赋值给ebp-20中
0040D46D |. B9 07000000 MOV ECX,7 ; ecx赋值为7
0040D472 |. 33C0 XOR EAX,EAX ; 清空eax
0040D474 |. 8D7D E4 LEA EDI,DWORD PTR SS:[EBP-1C] ; ebp-1c的地址赋值给edi
0040D477 |. F3:AB REP STOS DWORD PTR ES:[EDI] ; 初始化00000000
0040D479 |. 8B45 DC MOV EAX,DWORD PTR SS:[EBP-24] ; 将存储bbbbb的地址赋值给eax
0040D47C |. 50 PUSH EAX ; /<%s>
0040D47D |. 68 0C244200 PUSH OFFSET my.??_C@_02DILL@?$CFs?$AA@ ; |format = "%s"
0040D482 |. E8 A9020000 CALL my.printf ; \printf
0040D487 |. 83C4 08 ADD ESP,8
0040D48A |. 5F POP EDI
0040D48B |. 5E POP ESI
0040D48C |. 5B POP EBX
0040D48D |. 83C4 68 ADD ESP,68
0040D490 |. 3BEC CMP EBP,ESP
0040D492 |. E8 59020000 CALL my.__chkesp
0040D497 |. 8BE5 MOV ESP,EBP
0040D499 |. 5D POP EBP
0040D49A \. C3 RETN
总结:
1、第一种方式:赋值的是字符串的字符数据
2、第二种方式:赋值的是字符串的地址
数组指针
代码如下:
#include<stdio.h>
int main(){
int arr[] = {1,2,3,4,5,6,7,8,9,0}; //一维数组
int(*px)[2][2] = (int (*)[2][2])arr;
printf("%d\n",(*px)[1][1]);
px++;
printf("%d\n",(*px)[1][1]);
return 0;
}
反汇编如下:
0040D756 |. F3:AB REP STOS DWORD PTR ES:[EDI]
0040D758 |. C745 D8 01000>MOV DWORD PTR SS:[EBP-28],1 ; 1
0040D75F |. C745 DC 02000>MOV DWORD PTR SS:[EBP-24],2 ; 2
0040D766 |. C745 E0 03000>MOV DWORD PTR SS:[EBP-20],3 ; 3
0040D76D |. C745 E4 04000>MOV DWORD PTR SS:[EBP-1C],4 ; 4
0040D774 |. C745 E8 05000>MOV DWORD PTR SS:[EBP-18],5 ; 5
0040D77B |. C745 EC 06000>MOV DWORD PTR SS:[EBP-14],6 ; 6
0040D782 |. C745 F0 07000>MOV DWORD PTR SS:[EBP-10],7 ; 7
0040D789 |. C745 F4 08000>MOV DWORD PTR SS:[EBP-C],8 ; 8
0040D790 |. C745 F8 09000>MOV DWORD PTR SS:[EBP-8],9 ; 9
0040D797 |. C745 FC 00000>MOV DWORD PTR SS:[EBP-4],0 ; 0
0040D79E |. 8D45 D8 LEA EAX,DWORD PTR SS:[EBP-28] ; 数组的首地址赋值给eax,eax就为0012FF58
0040D7A1 |. 8945 D4 MOV DWORD PTR SS:[EBP-2C],EAX ; 将存储数组的首地址赋值给ebp-2c指向的值
0040D7A4 |. 8B4D D4 MOV ECX,DWORD PTR SS:[EBP-2C] ; 将 当前数组首地址 赋值给ecx
0040D7A7 |. 8B51 0C MOV EDX,DWORD PTR DS:[ECX+C] ; ecx+C 相当于当前的地址加上0xC,可以理解为跳过两个int字节取下一组的第一个,也就是(*px)[1][1]
0040D7AA |. 52 PUSH EDX ; /<%d>
0040D7AB |. 68 1C204200 PUSH OFFSET my.??_C@_03HMFC@?$CFd?6?$AA@ ; |format = "%d
"
0040D7B0 |. E8 FB38FFFF CALL my.printf ; \printf
0040D7B5 |. 83C4 08 ADD ESP,8 ; 堆栈平衡,下面就是准备输出代码中第二个printf了
0040D7B8 |. 8B45 D4 MOV EAX,DWORD PTR SS:[EBP-2C] ; 当前的数组的首地址赋值给eax
0040D7BB |. 83C0 10 ADD EAX,10 ; 现在是eax+10,相当于跳过两段,每段2个数,8字节,那就是跳过16字节
0040D7BE |. 8945 D4 MOV DWORD PTR SS:[EBP-2C],EAX ; 当前的eax地址赋值给ebp-2c指向的值
0040D7C1 |. 8B4D D4 MOV ECX,DWORD PTR SS:[EBP-2C] ; 取其中的值给ecx
0040D7C4 |. 8B51 0C MOV EDX,DWORD PTR DS:[ECX+C] ; ecx+C指向的值赋值给edx
0040D7C7 |. 52 PUSH EDX ; /<%d>
0040D7C8 |. 68 1C204200 PUSH OFFSET my.??_C@_03HMFC@?$CFd?6?$AA@ ; |format = "%d
"
0040D7CD |. E8 DE38FFFF CALL my.printf ; \printf
0040D7D2 |. 83C4 08 ADD ESP,8
0040D7D5 |. 33C0 XOR EAX,EAX
0040D7D7 |. 5F POP EDI
0040D7D8 |. 5E POP ESI
0040D7D9 |. 5B POP EBX
0040D7DA |. 83C4 6C ADD ESP,6C
0040D7DD |. 3BEC CMP EBP,ESP
0040D7DF |. E8 4C39FFFF CALL my.__chkesp
0040D7E4 |. 8BE5 MOV ESP,EBP
0040D7E6 |. 5D POP EBP
0040D7E7 \. C3 RETN