反彙編分析--hello,world

程序很簡單,就一個printf函數,通過分析我們主要明白大致的反彙編流程,感性認識一下棧的空間佈局。

#include<stdio.h>
int main()
{
	printf("hello,world");
	return 0;
}

在這裏插入圖片描述

cl hello.c /Fa hello.asm

/Fa表示生成彙編列表文件

	TITLE	C:\moddemod\demo\c\re\hello.cpp
	.686P
	.XMM
	include listing.inc
	.model	flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
CONST	SEGMENT
$SG5543	DB	'hello,world', 00H
CONST	ENDS
PUBLIC	___local_stdio_printf_options
PUBLIC	__vfprintf_l
PUBLIC	_printf
PUBLIC	_main
PUBLIC	?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA ; `__local_stdio_printf_options'::`2'::_OptionsStorage
EXTRN	___acrt_iob_func:PROC
EXTRN	___stdio_common_vfprintf:PROC
_BSS	SEGMENT
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA DQ 01H DUP (?) ; `__local_stdio_printf_options'::`2'::_OptionsStorage
_BSS	ENDS
_TEXT	SEGMENT
_main	PROC
	push	ebp
	mov	ebp, esp
	push	OFFSET $SG5543
	call	_printf
	add	esp, 4
	xor	eax, eax
	pop	ebp
	ret	0
_main	ENDP
_TEXT	ENDS
_TEXT	SEGMENT
__Result$ = -8						; size = 4
__ArgList$ = -4						; size = 4
__Format$ = 8						; size = 4
_printf	PROC						; COMDAT
	push	ebp
	mov	ebp, esp
	sub	esp, 8
	lea	eax, DWORD PTR __Format$[ebp+4]
	mov	DWORD PTR __ArgList$[ebp], eax
	mov	ecx, DWORD PTR __ArgList$[ebp]
	push	ecx
	push	0
	mov	edx, DWORD PTR __Format$[ebp]
	push	edx
	push	1
	call	___acrt_iob_func
	add	esp, 4
	push	eax
	call	__vfprintf_l
	add	esp, 16					; 00000010H
	mov	DWORD PTR __Result$[ebp], eax
	mov	DWORD PTR __ArgList$[ebp], 0
	mov	eax, DWORD PTR __Result$[ebp]
	mov	esp, ebp
	pop	ebp
	ret	0
_printf	ENDP
_TEXT	ENDS
_TEXT	SEGMENT
__Stream$ = 8						; size = 4
__Format$ = 12						; size = 4
__Locale$ = 16						; size = 4
__ArgList$ = 20						; size = 4
__vfprintf_l PROC					; COMDAT
	push	ebp
	mov	ebp, esp
	mov	eax, DWORD PTR __ArgList$[ebp]
	push	eax
	mov	ecx, DWORD PTR __Locale$[ebp]
	push	ecx
	mov	edx, DWORD PTR __Format$[ebp]
	push	edx
	mov	eax, DWORD PTR __Stream$[ebp]
	push	eax
	call	___local_stdio_printf_options
	mov	ecx, DWORD PTR [eax+4]
	push	ecx
	mov	edx, DWORD PTR [eax]
	push	edx
	call	___stdio_common_vfprintf
	add	esp, 24					; 00000018H
	pop	ebp
	ret	0
__vfprintf_l ENDP
_TEXT	ENDS
_TEXT	SEGMENT
___local_stdio_printf_options PROC			; COMDAT
	push	ebp
	mov	ebp, esp
	mov	eax, OFFSET ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA ; `__local_stdio_printf_options'::`2'::_OptionsStorage
	pop	ebp
	ret	0
___local_stdio_printf_options ENDP
_TEXT	ENDS
END

我們主要看一下main函數

_main	PROC
	push	ebp
	mov	ebp, esp
	push	OFFSET $SG5543
	call	_printf
	add	esp, 4
	xor	eax, eax
	pop	ebp
	ret	0
_main	ENDP

在這裏插入圖片描述

假設初始的時候esp指向9,也即9是棧頂,當

push ebp

執行push ebp的時候,(esp先減4字節(32位),如果是64位減8字節),
在我們這裏減後指向8這個地址,此時esp寄存器的值變爲8,隨後將ebp的值壓在8-9這塊空間裏

mov ebp, esp

隨後更新ebp寄存器的值,即將esp寄存器的值賦值給ebp寄存器

push	OFFSET $SG5543

OFFSET $SG5543這塊內存地址指向hello,world,也即是將這塊內存的偏移量存放在棧上,便於尋址hello,world的位置,
當push的時候,首先esp先減4指向7,然後把offset取到的偏移量存放在7-8這塊內存地址

call _printf

call指令在執行的時候首先將call指令的下一條語句的地址壓棧後再跳到_printf去執行,想一下這是爲什麼?

因爲當_printf執行完後,還要回來繼續執行,所以必須把回來的地址先存起來,這起始也就是對應高級語言裏的函數調用然後返回,底層就是這樣實現的。

剛纔說了先將add esp, 4的地址壓棧,同樣,先將esp的值減4指向6,將該地址存放到6-7這段空間
隨後將eip寄存器的值修改爲_printf函數入口地址

下面到了_printf函數

push ebp
mov ebp, esp

同樣的操作,將在main函數裏面的ebp壓棧,此時esp指向5,同時更新ebp的值

sub esp, 8

將esp的值減8,即指向3的位置

後面的我們就暫時先不分析了…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章