知识点:
CALL框架
EBP寄存器 栈底指针
ESP寄存器 栈顶指针
一、EBP栈底指针
EBP是一个特殊的寄存器,通过EBP+偏移量 可以访问CALL里边的局部变量。它的低16位叫BP。//EAX和AX的关系
二、ESP栈顶指针
ESP栈顶指针与EBP构成的一段空间大小,一般就是本CALL局部变量的空间大小总和。ESP指针配合EBP使用。//SP
三、代码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| void fun1(void)
{ //0401000 /$ 55 PUSH EBP //保存栈环境或者叫保存EBP指针
//0401001 |. 8BEC MOV EBP,ESP
//0401003 |. 5D POP EBP //恢复EBP指针
//0401004 \. C3 RETN
}
void fun2(void)
{
int a;
int b=5;
}
void fun3(void)
{
fun2();
}
|
总结:
1、每个CALL会分配一个独立的栈段空间,供局部变量使用.
栈段空间大小一般要大于局部变量所需空间大小之和 ebp-esp=栈段空间大小。
2、CALL栈平衡。进CALL前与出CALL后 EBP和ESP的值不变。
知识点:
PUSH
POP
CALL堆栈平衡
RETN指令
一、PUSH入栈指令 (压栈指令):
格式: PUSH 操作数
//sub esp,4 ;mov [esp],EBP
操作数可以是寄存器,存储器,或者立即数
二、POP出栈指令 (弹栈指令)
格式:POP 操作数
//mov EBP,[esp] ;add esp,4
操作数是寄存器,或者存储器,不能是立即数
三、代码分析
1、测试PUSH和POP 与ESP栈顶指针的关系
2、CALL与ESP的关系
3、总结栈的特点(后进先出)
[EBP-??] // 局部变量
[ EBP+??] //上一个CALL 局部变量,上一个CALL传入参数
CALL PUSH EIP
RETN POP EIP
知识点:
cdecl 函数调用约定
stdcall 函数调用约定
CALL堆栈平衡
配置属性–> c/c++ -->高级–>调用约定
一、cdecl调用约定
VC++默认约定__cdecl
1、源代码
1 2 3 4 5 6 7
| int __cdecl add1(int a,int b)
{
return a+b;
}
|
2、生成汇编代码
1 2 3 4 5 6 7 8 9 10 11
| 00401000 /$ 55 PUSH EBP
00401001 |. 8BEC MOV EBP,ESP
00401003 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
00401006 |. 0345 0C ADD EAX,DWORD PTR SS:[EBP+C]
00401009 |. 5D POP EBP
0040100A \. C3 RETN ; POP EIP
|
3、调用代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| push b
push a
call add1
add esp,8
00401031 |. 6A 02 PUSH 2 ; 0012FF7C
00401033 |. 6A 01 PUSH 1
00401035 |. E8 C6FFFFFF CALL stdcall_.00401000 ; __cdecl add1
0040103A |. 83C4 08 ADD ESP,8 ; RETN 8
|
二、stdcall调用约定
API函数约定 __stdcall
1、源代码
1 2 3 4 5 6 7
| int __stdcall add2(int a,int b)
{
return a+b;
}
|
2、生成汇编代码
1 2 3 4 5 6 7 8 9 10 11
| 00401010 /$ 55 PUSH EBP
00401011 |. 8BEC MOV EBP,ESP
00401013 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
00401016 |. 0345 0C ADD EAX,DWORD PTR SS:[EBP+C]
00401019 |. 5D POP EBP
0040101A \. C2 0800 RETN 8 ; RETN 8 //ADD ESP,8
|
3、调用代码
1 2 3 4 5 6 7 8 9 10 11
| push b
push a
call add2
0040103D |. 6A 04 PUSH 4 ; 0012FF7C
0040103F |. 6A 03 PUSH 3
00401041 |. E8 CAFFFFFF CALL stdcall_.00401010 ; __stdcall add2 PUSH 下一个EIP
|
知识点:
fastcall 函数调用约定
CALL堆栈平衡
三、__fastcall 函数调用约定
直接用寄存器传递参数,由于寄存器相对于栈(存储器)速度要快上许多,所以这类的调用约定叫fastcall
1、源代码
1 2 3 4 5 6 7
| int __fastcall add2(int a,int b)
{
return a+b;
}
|
2、汇编代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 00401020 /$ 55 PUSH EBP
00401021 |. 8BEC MOV EBP,ESP
00401023 |. 83EC 08 SUB ESP,8 ; int a,b;
00401026 |. 8955 F8 MOV DWORD PTR SS:[EBP-8],EDX ; b=edx
00401029 |. 894D FC MOV DWORD PTR SS:[EBP-4],ECX ; a=ecx
0040102C |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0040102F |. 0345 F8 ADD EAX,DWORD PTR SS:[EBP-8]
00401032 |. 8BE5 MOV ESP,EBP ; add esp,8
00401034 |. 5D POP EBP
00401035 \. C3 RETN
|
3、调用代码
1 2 3 4 5
| 00401096 |. BA 02000000 MOV EDX,2
0040109B |. B9 01000000 MOV ECX,1
004010A0 |. E8 7BFFFFFF CALL fastcall.00401020 ; 3
|
一般超过两个参数,就会使用栈来存储其他参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| int __fastcall add4(int a, int b,int c,int d,int e) {
return a + b + c + d + e; }
00F4112B . 6A 05 push 0x5 ; 002FF838 00F4112D . 6A 04 push 0x4 00F4112F . 6A 03 push 0x3 00F41131 . BA 02000000 mov edx,0x2 00F41136 B9 db B9 00F41137 01 db 01 00F41138 00 db 00 00F41139 00 db 00 00F4113A > 00 db 00 ; 002FF838 00F4113B . E8 80FFFFFF call ConsoleA.00F410C0
00F410C0 /$ 55 push ebp 00F410C1 |. 8BEC mov ebp,esp 00F410C3 |. 83EC 08 sub esp,0x8 00F410C6 |. 8955 F8 mov [local.2],edx 00F410C9 |. 894D FC mov [local.1],ecx 00F410CC |. 8B45 FC mov eax,[local.1] 00F410CF |. 0345 F8 add eax,[local.2] 00F410D2 |. 0345 08 add eax,[arg.1] 00F410D5 |. 0345 0C add eax,[arg.2] 00F410D8 |. 0345 10 add eax,[arg.3] 00F410DB |. 8BE5 mov esp,ebp 00F410DD |. 5D pop ebp 00F410DE \. C2 0C00 retn 0xC
|
知识点:
if else
逆向还原代码
一、了解if else结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| sub esp,8
00401029 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0040102C |. 3B45 F8 CMP EAX,DWORD PTR SS:[EBP-8]
0040102F |. 7E 10 JLE SHORT ifelse01.00401041 //表示 else部分的开始
00401031 |. 68 FC204000 PUSH ifelse01.004020FC ; /format = "a>b"
00401036 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
0040103C |. 83C4 04 ADD ESP,4
0040103F |. EB 0E JMP SHORT ifelse01.0040104F //结合前边的 jle 401041 判断是否有else部分
00401041 |> 68 00214000 PUSH ifelse01.00402100 ; /format = "b>=a"
00401046 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
0040104C |. 83C4 04 ADD ESP,4
|
二、逆向还原代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| int a,b,c; //00401006 |. 68 F4204000 PUSH ifelse01.004020F4 ; /format = "begin" //0040100B |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf //00401011 |. 83C4 04 ADD ESP,4 printf("begin"); //00401014 |. C745 FC 01000>MOV DWORD PTR SS:[EBP-4],1 //0040101B |. C745 F8 02000>MOV DWORD PTR SS:[EBP-8],2 //00401022 |. C745 F4 03000>MOV DWORD PTR SS:[EBP-C],3 a=1,b=2,c=3; //00401029 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] //0040102C |. 3B45 F8 CMP EAX,DWORD PTR SS:[EBP-8] //0040102F |. 7E 10 JLE SHORT ifelse01.00401041 if (a>b) { //00401031 |. 68 FC204000 PUSH ifelse01.004020FC ; /format = "a>b" //00401036 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf //0040103C |. 83C4 04 ADD ESP,4 //0040103F |. EB 0E JMP SHORT ifelse01.0040104F printf("a>b"); }else { //00401041 |> 68 00214000 PUSH ifelse01.00402100 ; /format = "b>=a" //00401046 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf //0040104C |. 83C4 04 ADD ESP,4 printf("b>=a"); } //0040104F |> \8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C] ; c //00401052 |. 3B4D F8 CMP ECX,DWORD PTR SS:[EBP-8] ; b //00401055 |. 7E 46 JLE SHORT ifelse01.0040109D ; if (c>b) if (c>b) { //00401057 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C] c //0040105A |. 3B55 FC CMP EDX,DWORD PTR SS:[EBP-4] a //0040105D |. 7E 20 JLE SHORT ifelse01.0040107F if (c>a) { //0040105F |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] //00401062 |. 50 PUSH EAX ; /<%d> //00401063 |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C] ; | //00401066 |. 51 PUSH ECX ; |<%d> //00401067 |. 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8] ; | //0040106A |. 52 PUSH EDX ; |<%d> //0040106B |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] ; | //0040106E |. 50 PUSH EAX ; |<%d> //0040106F |. 68 08214000 PUSH ifelse01.00402108 ; |format = "%d>%d,%d>%d" //00401074 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf //0040107A |. 83C4 14 ADD ESP,14 printf("%d>%d,%d>%d",c,b,c,a); //0040107D |. EB 1E JMP SHORT ifelse01.0040109D }else { //0040107F |> 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] //00401082 |. 51 PUSH ECX ; /<%d> //00401083 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C] ; | //00401086 |. 52 PUSH EDX ; |<%d> //00401087 |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8] ; | //0040108A |. 50 PUSH EAX ; |<%d> //0040108B |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C] ; | //0040108E |. 51 PUSH ECX ; |<%d> //0040108F |. 68 14214000 PUSH ifelse01.00402114 ; |format = "%d>%d,%d<=%d" //00401094 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf //0040109A |. 83C4 14 ADD ESP,14 printf("%d>%d,%d<=%d",c,b,c,a); } } //0040109D |> 33C0 XOR EAX,EAX
|
知识点:
switch case生成的汇编框架
逆向汇编代码还原成C++代码
一、了解switch case结构
1、普通情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 00401011 |. 83C4 04 ADD ESP,4
00401014 |. C745 FC 20000>MOV DWORD PTR SS:[EBP-4],20 ; a=20;
0040101B |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0040101E |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX ; switch (a)
00401021 |. 837D F8 03 CMP DWORD PTR SS:[EBP-8],3 ; case 3:
00401025 |. 74 0E JE SHORT switchCa.00401035
00401027 |. 837D F8 04 CMP DWORD PTR SS:[EBP-8],4 ; case 4:
0040102B |. 74 28 JE SHORT switchCa.00401055
0040102D |. 837D F8 05 CMP DWORD PTR SS:[EBP-8],5 ; case 5:
00401031 |. 74 12 JE SHORT switchCa.00401045
00401033 |. EB 30 JMP SHORT switchCa.00401065 ; default:
|
2、跳转表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
00401014 |. C745 FC 20000>MOV DWORD PTR SS:[EBP-4],20 ; a=20;
0040101B |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0040101E |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX ; b=a
00401021 |. 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8] ; b==1
00401024 |. 83E9 03 SUB ECX,3 ; a-0x3=跳转表数组大小 ecx = a - 最小case值
00401027 |. 894D F8 MOV DWORD PTR SS:[EBP-8],ECX
0040102A |. 837D F8 0E CMP DWORD PTR SS:[EBP-8],0E ; 0E=case最大常量-case最小常量
0040102E |. 77 61 JA SHORT switchCa.00401091 ; default:
00401030 |. 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8] ;edx == local.1 == ecx == a - case最小值
00401033 |. 0FB682 CC1040>MOVZX EAX,BYTE PTR DS:[EDX+4010CC] ; 跳转表的索引数组
0040103A |> FF2485 B41040>JMP DWORD PTR DS:[EAX*4+4010B4] ; /跳转表
|
二、逆向还原代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| //00401003 |. 83EC 08 SUB ESP,8 ; int a,b
//00401006 |. 68 F4204000 PUSH switchCa.004020F4 ; /format = "begin\n"
//0040100B |. FF15 A4204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
//00401011 |. 83C4 04 ADD ESP,4 ; a=20
//00401014 |. C745 FC 20000>MOV DWORD PTR SS:[EBP-4],20 ; switch (a)
//0040101B |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
//0040101E |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
//00401021 |. 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
//00401024 |. 83E9 09 SUB ECX,9 ; 23
//00401027 |. 894D F8 MOV DWORD PTR SS:[EBP-8],ECX
//0040102A |. 837D F8 08 CMP DWORD PTR SS:[EBP-8],8 ; 9..17
//0040102E |. 77 4A JA SHORT switchCa.0040107A ; 9,11,15,16,17
//00401030 |. 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
//00401033 |. FF2495 9C1040>JMP DWORD PTR DS:[EDX*4+40109C] ; 跳转表
//0040103A |> 68 FC204000 PUSH switchCa.004020FC ; /format = "aaa"
//0040103F |. FF15 A4204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
//00401045 |. 83C4 04 ADD ESP,4
//00401048 |. EB 3E JMP SHORT switchCa.00401088
//0040104A |> 68 00214000 PUSH switchCa.00402100 ; /format = "aaaa"
//0040104F |. FF15 A4204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
//00401055 |. 83C4 04 ADD ESP,4
//00401058 |. EB 2E JMP SHORT switchCa.00401088
//0040105A |> 68 08214000 PUSH switchCa.00402108 ; /format = "bbbb"
//0040105F |. FF15 A4204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
//00401065 |. 83C4 04 ADD ESP,4
//00401068 |. EB 1E JMP SHORT switchCa.00401088
//0040106A |> 68 10214000 PUSH switchCa.00402110 ; /format = "xxxx"
//0040106F |. FF15 A4204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
//00401075 |. 83C4 04 ADD ESP,4
//00401078 |. EB 0E JMP SHORT switchCa.00401088
//0040107A |> 68 18214000 PUSH switchCa.00402118 ; /format = "3333"
//0040107F |. FF15 A4204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf //Default
//00401085 |. 83C4 04 ADD ESP,4
//00401088 |> 68 20214000 PUSH switchCa.00402120 ; /command = "pause"
//0040108D |. FF15 9C204000 CALL DWORD PTR DS:[<&MSVCR90.system>] ; \system
//00401093 |. 83C4 04 ADD ESP,4
printf("begin");
int a=0x20;
switch(a)
{
case 11:
printf("aaa");
break;
case 15:
printf("aaaa");
break;
case 17:
printf("bbbb");
break;
case 9:
printf("xxxx");
break;
default:
printf("3333");
break;
}
|
## 知识点:
入口函数main的定位
逆向汇编代码还原成C++代码
索引表数组
跳转表
设置程序的入口基址
最少要大于等于0x10000

找入口main函数


双击进入就是main函数的入口位置了
一、索引表及跳转表分析
1、确定case常量
18,20,28,32
2、确定case常量顺序 (可以根据 跳转表 调整也可以)
000210AC 00021063 30.00021063 18
000210B0 00021053 30.00021053 20
000210B4 00021048 30.00021048 28
000210B8 00021089 30.00021089 32
**// 调整后实际上就是按地址大小排序 **
000210B4 00021048 30.00021048 28
000210B0 00021053 30.00021053 20
000210AC 00021063 30.00021063 18
000210B8 00021089 30.00021089 32
二、还原代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| printf("begin");
int a,b; a=0x16; b=3;
switch(a)
{
case 28:
b=b+a;
break;
case 20:
printf("123");
break;
//18,20,28,32
case 18:
if (b>9)
{
printf("3333");
}else
{
printf("2222");
}
break;
case 32:
printf("321");
//break;
default:
printf("00end");
break;
}
//end
|