23-30

知识点:

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

1627315281528

找入口main函数

1627318463657

1627318492662

双击进入就是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