Note:
The address of the next instruction to be executed in the EIP register;
MoV eax and EBX move the eax content of the register to EBX. The machine instruction is 2 bytes.
The operation performed by the Leave command is equivalent to mov EBP, ESP, and pop EBP. The machine command is 1 byte.
The operation performed by the RET command is equivalent to pop EIP, and the machine command is 1 byte.
The operation performed by the call ADDR command is equivalent to pushing eip and then jmp addr; the machine command is 4 bytes.
The operations performed by jmp addr are equivalent to mov ADDR and EIP. The machine command is 2 bytes.
Note: what we call "equivalent" is equivalent in terms of functionality, and is not equivalent to actual machine commands.
1. Compile the test program as follows:
// File name: CC. c
# Include
Int Foo (INT Fi, int fj)
{
Int FK;
FK = 3;
Return (0 );
}
Int main ()
{
Int Mi;
Int mj;
Mi = 1;
Mj = 2;
Foo (MI, MJ );
Return (0 );
}
2. Compile the Code:
Gcc-g-o CC cc. c
3. Debug: gdb cc with GDB
(1) view the source program:
(GDB) List
4 {
5 Int FK;
6 FK = 3;
7 Return (0 );
8}
9 int main ()
10 {
11 int Mi;
12 INT mj;
13 MI = 1;
(GDB)
14 mj = 2;
15 Foo (MI, MJ );
16
17 return (0 );
18}
(2) view the assembly code:
(GDB) disass main
Dump of worker er code for function main:
0x8048444: Push % EBP
0x8048445: mov % ESP, % EBP
0x8048447: Sub $0x8, % ESP
0x804844a: movl $0x1, 0 xfffffffc (% EBP)
0x8048451: movl $0x2, 0xfffffff8 (% EBP)
0x8048458: Sub $0x8, % ESP
0x804845b: pushl 0xfffffff8 (% EBP)
0x804845e: pushl 0 xfffffffc (% EBP)
0x8048461: Call 0x8048430
0x8048466: add $0x10, % ESP
0x8048469: mov $0x0, % eax
0x804846e: Leave
0x804846f: Ret
End of worker er dump.
(GDB) disass foo
Dump of worker er code for function FOO:
0x8048430: Push % EBP
0x8048431: mov % ESP, % EBP
0x8048433: Sub $0x4, % ESP
0x8048436: movl $0x3, 0 xfffffffc (% EBP)
0x804843d: mov $0x0, % eax
Zero X 8048442: Leave
0x8048443: Ret
End of worker er dump.
(3) set breakpoints in the main function and execute the program so that the program is paused at the beginning of the main function:
(GDB) Break 9
Breakpoint 1 at 0x8048444: file c1.c, line 9.
(GDB) Run
Starting program:/home/Syf/P/CC
Breakpoint 1, main () at c1.c: 10
10 {
(4) view the key register content:
(GDB) I reg ESP
ESP 0 xbffffaec 0 xbffffaec
(GDB) I reg EBP
EBP 0xbffffb28 0xbffb28
(GDB) I reg EIP
EIP 0x8048444 0x8048444
(5) view stack space content:
(GDB) x/32xw 0xbffffae0
0xbffffae0: 0x080494e8 0x080495e4 0xbffaf8 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1
0xbffffb10: 0x00000000 0xbffffb5c 0x4015ec3c 0x40016300
0xbffffb20: 0x00000001 0x08048330 0x00000000 0x08048351
0xbffffb30: 0x08048444 0x00000001 0xbffffb54 0x080482bc
0xbffffb40: 0x080484b0 0x4000dc14 0xbffffb4c 0x40016944
0xbffffb50: 0x00000001 0xbffffc53 0x00000000 0xbffffc62
Note: The EBP content is 0xbffffb28. The content of this address is 0x00000000;
(6) execute a machine command (0x8048444: Push % EBP) to load the stack:
(GDB) Si
0x08048445 10 {
(GDB) I reg ESP
ESP 0xbffffae8 0xbffffae8
(GDB) I reg EBP
EBP 0xbffffb28 0xbffb28
(GDB) I reg EIP
EIP 0x8048445 0x8048445
(GDB) x/12xw 0xbffffae0
0xbffffae0: 0x080494e8 0x080495e4 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1
We can see that the EBP (content is 0xbffffb28) is compressed to 0xbffffae8.
(7) execute a machine command (0x8048445: mov % ESP, % EBP), that is, ESP-> EBP, to view the register content and heap content:
(GDB) Si
0x08048447 in main () at c1.c: 10
10 {
(GDB) I reg EBP
EBP 0xbffffae8 0xbffffae8
(GDB) I reg ESP
ESP 0xbffffae8 0xbffffae8
(GDB) I reg EIP
EIP 0x8048447 0x8048447
(GDB) x/12xw 0xbffffae0
0xbffffae0: 0x080494e8 0x080495e4 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1
As you can see, the stack space content has not changed, but the register EBP has changed to the ESP value.
(8) execute three machine commands and assign values to MI and MJ.
The three commands are:
0x8048447: Sub $0x8, % ESP
0x804844a: movl $0x1, 0 xfffffffc (% EBP)
0x8048451: movl $0x2, 0xfffffff8 (% EBP)
These three commands assign values to MI and MI.
(GDB) Si
13 MI = 1;
(GDB) Si
14 mj = 2;
(GDB) Si
15 Foo (MI, MJ );
(GDB) I reg ESP
ESP 0xbffffae0 0xbffffae0
(GDB) I reg EBP
EBP 0xbffffae8 0xbffffae8
(GDB) I reg EIP
EIP 0x8048458 0x8048458
(GDB) x/12xw 0xbffffae0
0xbffffae0: 0x00000002 0x00000001 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1
As you can see, the system is Mi, MJ allocates space in the stack (corresponding addresses are 0xbffffae4, 0xbffffae0), and assigned values (respectively: 0x00000002 ).
(9) execute the next command (0x8048458: Sub $0x8, % ESP) and add the stack space to 8 bytes. It is meaningless and can be omitted, code optimization is skipped.
Note: The method to optimize the code is gcc-o CC cc. C.
(GDB) Si
0x0804845b 15 Foo (MI, MJ );
(10) execute the following two commands. The heap will call the parameter pressure stack of the function Foo (INT, INT. The two commands are:
0x804845b: pushl 0xfffffff8 (% EBP)
0x804845e: pushl 0 xfffffffc (% EBP)
These two commands apply to the parameter pressure stack of the called function Foo (INT Fi, int fj.
(GDB) Si
0x0804845e 15 Foo (MI, MJ );
(GDB) Si
0x08048461 15 Foo (MI, MJ );
(GDB) I reg ESP
ESP 0xbffffad0 0xbffffad0
(GDB) I reg EBP
EBP 0xbffffae8 0xbffffae8
(GDB) I reg EIP
EIP 0x8048461 0x8048461
(GDB) x/12xw 0xbffffad0
0xbffffad0: 0x00000001 0x00000002 0xbffffaf8 0x08048411
0xbffffae0: 0x00000002 0x00000001 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffb5c 0x080482d2
(11) run the following command: 0x8048461: Call 0x8048430.
This call command can be divided into two Commands: Push eip and JMP 0x8048430.
The function is to save the address of the next instruction after calling the main function Foo (INT, INT) (0x8048466), so that Foo (INT, INT) after the function is returned, continue the command in the main () function, and jump to the address of Foo (INT, INT) (0x8048430) to execute the function Foo (INT, INT );
Note: At this time, the EIP is 0x8048466, and the corresponding command is: 0x8048466: add $0x10, % ESP
(GDB) Si
Foo (FI = 1, Fj =-1073743020) at c1.c: 4
4 {
(GDB) I reg ESP
ESP 0 xbffffacc 0 xbffffacc
(GDB) I reg EBP
EBP 0xbffffae8 0xbffffae8
(GDB) I reg EIP
EIP 0x8048430 0x8048430
(GDB) x/12xw 0 xbffffacc
0 xbffffacc: 0x08048466 0x00000001 0x00000002 0xbffffaf8
0 xbffffadc: 0x08048411 0x00000002 0x00000001 0xbffffb28
0 xbffffaec: 0x40046507 0x00000001 0xbffffb54 0xbffffb5c
(12) execute the following two commands and view the register and heap content:
The two commands are:
0x8048430: Push % EBP
0x8048431: mov % ESP, % EBP
The two commands are used to store the EBP in the main function, so that it can be used for return (corresponding to step 1), and assign the ESP value to EBP (EBP-> ESP ), generally, this function is returned (corresponding to step 1 ).
(GDB) Si
0x08048431 4 {
(GDB) Si
0x08048433 in Foo (FI = 1, Fj = 2) at c1.c: 4
4 {
(GDB) I reg ESP
ESP 0xbffffac8 0xbffac8
(GDB) I reg EBP
EBP 0xbffffac8 0xbffac8
(GDB) I reg EIP
EIP 0x8048433 0x8048433
(GDB) x/12xw 0xbffffac8
0xbffffac8: 0xbffffae8 0x08048466 0x00000001 0x00000002
0xbffffad8: 0xbffffaf8 0x08048411 0x00000002 0x00000001
0xbffffae8: 0xbffffb28 0x40046507 0x00000001 0xbffffb54
We can see that the content of the EBP is pushed to the stack, which is at address 0xbffffac8.
(13) execute the following two commands and view the register and heap content:
The two commands are:
0x8048433: Sub $0x4, % ESP
0x8048436: movl $0x3, 0 xfffffffc (% EBP)
The function is to assign values to fk.
(GDB) Si
7 Return (0 );
(GDB) I reg ESP
ESP 0xbffffac4 0xbffac4
(GDB) I reg EBP
EBP 0xbffffac8 0xbffac8
(GDB) I reg EIP
EIP 0x804843d 0x804843d
(GDB) x/12xw 0xbffffac4
0xbffffac4: 0x00000003 0xbffffae8 0x08048466 0x00000001
0xbffffad4: 0x00000002 0xbffaf8 0x08048411 0x00000002
0xbffffae4: 0x00000001 0xbffffb28 0x40046507 0x00000001
We can see that the system allocates space (0xbffffac4) for FK In the heap and assigns a value (0x00000003 ).
(14) execute the next command (0x8048469: mov $0x0, % eax) to clear eax, even if the return value is 0.
(GDB) I reg ESP
ESP 0xbffffac4 0xbffac4
(GDB) I reg EBP
EBP 0xbffffac8 0xbffac8
(GDB) I reg EIP
EIP 0x8048442 0x8048442
(GDB) x/12xw 0xbffffac4
0xbffffac4: 0x00000003 0xbffffae8 0x08048466 0x00000001
0xbffffad4: 0x00000002 0xbffaf8 0x08048411 0x00000002
0xbffffae4: 0x00000001 0xbffffb28 0x40046507 0x00000001
(15) execute the next command (0x8048442: Leave). This command can be divided into mov ebp esp and pop EBP, so that the EBP in the main function saved in step 12 is displayed, prepare for the return.
(GDB) Si
0x08048443 in Foo (FI = 1, Fj =-1073743020) at c1.c: 8
8}
(GDB) I reg ESP
ESP 0 xbffffacc 0 xbffffacc
(GDB) I reg EBP
EBP 0xbffffae8 0xbffffae8
(GDB) I reg EIP
EIP 0x8048443 0x8048443
(GDB) x/12xw 0 xbffffacc
0 xbffffacc: 0x08048466 0x00000001 0x00000002 0xbffffaf8
0 xbffffadc: 0x08048411 0x00000002 0x00000001 0xbffffb28
0 xbffffaec: 0x40046507 0x00000001 0xbffffb54 0xbffffb5c
(16) execute the next command (0x8048443: Ret), that is, pop EIP. Return the return address saved in Step 11: 0x8048466: add $0x10, % ESP.
(GDB) Si
0x08048466 in main () at c1.c: 15
15 Foo (MI, MJ );
(GDB) I reg ESP
ESP 0xbffffad0 0xbffffad0
(GDB) I reg EBP
EBP 0xbffffae8 0xbffffae8
(GDB) I reg EIP
EIP 0x8048466 0x8048466
(GDB) x/12xw 0xbffffad0
0xbffffad0: 0x00000001 0x00000002 0xbffffaf8 0x08048411
0xbffffae0: 0x00000002 0x00000001 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffb5c 0x080482d2
(17) at this time, the EIP is: 0x8048466: add $0x10, % ESP,
The subsequent Commands include:
0x8048466: add $0x10, % ESP
0x8048469: mov $0x0, % eax
0x804846e: Leave
0x804846f: Ret
So far, the function call is complete. We will not analyze the following content.