#include <windows.h>
int func002(char *str, int len)
{
strcpy(str, "hello");
return len;
}
int func001(int x, char y, char *z)
{
char buff[10];
int aa;
func002(z, aa);
return 0x100;
}
void main_call()
{
int a;
char b;
char c[100];
func001(a, b, c);
func002(c, a);
}
void main()
{
main_call();
}
对应的反汇编代码:cl /Fac1.asm cat.c
; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.21022.08
TITLE E:\code\ctoasm\cat.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
_DATA SEGMENT
$SG76990 DB 'hello', 00H
_DATA ENDS
PUBLIC _func002
EXTRN _strcpy:PROC
; Function compile flags: /Odtp
_TEXT SEGMENT
_str$ = 8 ; size = 4
_len$ = 12 ; size = 4
_func002 PROC
; File e:\code\ctoasm\cat.c
; Line 5
push ebp
mov ebp, esp
; Line 6
push OFFSET $SG76990
mov eax, DWORD PTR _str$[ebp]
push eax
call _strcpy
add esp, 8
; Line 8
mov eax, DWORD PTR _len$[ebp] //eax才是函数返回值,len实际未赋值
; Line 9
pop ebp
ret 0
_func002 ENDP
_TEXT ENDS
PUBLIC _func001
; Function compile flags: /Odtp
_TEXT SEGMENT
_aa$ = -4 ; size = 4
_x$ = 8 ; size = 4 //0的前面压栈了pc和ebp。
_y$ = 12 ; size = 1
_z$ = 16 ; size = 4
_func001 PROC
; Line 12
push ebp
mov ebp, esp
sub esp, 20 ; 00000014H
; Line 16
mov eax, DWORD PTR _aa$[ebp]
push eax
mov ecx, DWORD PTR _z$[ebp]
push ecx
call _func002
add esp, 8
; Line 18
mov eax, 256 ; 00000100H //返回值
; Line 19
mov esp, ebp
pop ebp
ret 0
_func001 ENDP
_TEXT ENDS
PUBLIC __$ArrayPad$
PUBLIC _main_call
EXTRN ___security_cookie:DWORD
EXTRN @__security_check_cookie@4:PROC
; Function compile flags: /Odtp
_TEXT SEGMENT
_c$ = -120 ; size = 100 //字节对齐108,并填充12字节,所以分配的局部变量空间是120B
__$ArrayPad$ = -12 ; size = 4
_b$ = -5 ; size = 1
_a$ = -4 ; size = 4
_main_call PROC
; Line 22
push ebp // 每一级的ebp指向上一级的esp起始地址。
mov ebp, esp
sub esp, 120 ; 00000078H
mov eax, DWORD PTR ___security_cookie
xor eax, ebp
mov DWORD PTR __$ArrayPad$[ebp], eax //&*%*&%
; Line 27
lea eax, DWORD PTR _c$[ebp] //为什么不都用eax?
push eax
movzx ecx, BYTE PTR _b$[ebp] //赋值并清零。
push ecx
mov edx, DWORD PTR _a$[ebp]
push edx
call _func001
add esp, 12 ; 0000000cH // 调用者将压栈参数弹出堆栈。
; Line 29
mov eax, DWORD PTR _a$[ebp]
push eax
lea ecx, DWORD PTR _c$[ebp]
push ecx
call _func002
add esp, 8
; Line 30
mov ecx, DWORD PTR __$ArrayPad$[ebp]
xor ecx, ebp
call @__security_check_cookie@4 // 大概是堆栈检查的调试功能。
mov esp, ebp // 前面将esp保存到ebp中,这里恢复esp的取值,相当于丢弃了局部变量空间。
pop ebp
ret 0
_main_call ENDP
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 33
push ebp
mov ebp, esp
; Line 34
call _main_call
; Line 35
xor eax, eax //eax存放函数返回值
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
汇编代码的核心是ESP、EBP的设计。
ESP是函数堆栈指针,每次PUSH减4,每次pop加4.
EBP是每个函数的基址指针,表示该函数的“起始堆栈”,可用户函数返回后恢复堆栈,类似盗梦空间的kick处理。