這是從別人博客上摘的一段C嵌匯編碼
( http://www.shnenglu.com/kevinlynx/archive/2011/01/02/137886.html
)

__declspec(naked)

void caller(void* pfn,

)



{

__asm


{

pop eax;

add eax, 3;

xchg dword ptr[esp], eax;

push eax;

ret;

}

}
下面是調(diào)用方法
void print_str( const char *s )

{
printf( "%s\n", s );
}{ ...
caller( print_str, "a string" ); __asm add esp, 4
...}
原作者講了一些基礎(chǔ),這里就不提了
看了一遍,發(fā)現(xiàn) "ADD EAX, 3" 的用法有點(diǎn)奇怪(我相信搞破解的人一定比較熟悉,但正常的程序不會(huì)這么寫。)
初看 EAX 是地址,+3是很危險(xiǎn)的,但仔細(xì)一看,發(fā)現(xiàn)代碼是為了從最外層主調(diào)函數(shù)一路穿越"caller" 直達(dá) print_str,這里牽涉到一個(gè)重要問題,就是在CALL指令時(shí),會(huì)有將“CALL指令下一條地址壓棧”的操作,那么代碼思路很明了了,就是為了要造出 調(diào)用print_str時(shí),ESP(+0) 指向 caller(..)調(diào)用的下一個(gè)地址。
第一關(guān)已經(jīng)順利搞定,但又碰到個(gè)問題,由于 print_str 的入?yún)⑹强勺兊模员仨氂?cdecl調(diào)用,那RET之后 如何平棧呢? 如果直接跳到 caller下一條地址,就喪失了平棧的機(jī)會(huì),最終會(huì)在某個(gè)主調(diào)函數(shù)上被微軟的 stack cookie捕獲拋個(gè)SEH。
這里就用到文章開頭提到的 ADD EAX, 3。
必須要造一個(gè)環(huán)境,讓 caller 調(diào)用完成后,給個(gè)機(jī)會(huì)清理現(xiàn)場(chǎng)。于是乎,caller之后就有了 ADD ESP, 4。其實(shí)這里的4是與print_str的入?yún)?shù)目相關(guān)的,每個(gè)參數(shù)要多加 4字節(jié),如此一來,整個(gè)代碼就理順了。
那為什么 是 ADD EAX, 3呢? 應(yīng)該是預(yù)估出一條ADD指令占用多少長(zhǎng)度,和具體的環(huán)境有關(guān)。因?yàn)闆]看INTEL手冊(cè),這里只能認(rèn)為ADD 寄存器+WORD的長(zhǎng)度是3個(gè)字節(jié)。我用VC試驗(yàn)了一下,的確是如此,我也嘗試了ADD 寄存器+DWORD,長(zhǎng)度變?yōu)榱?個(gè)字節(jié)。