今天讓我們來看Win32ASM里面的高級一點(diǎn)的技術(shù)——SMC(當(dāng)當(dāng)當(dāng)當(dāng)……)!!!
SMC是什么意思?它的英文名叫“Self Modifying Code”,顧名思義,就是“代碼自修改”(?)(不好意思,小弟的英語六級還沒過,只能翻譯成這樣啦……)
“代碼自修改”?哇,好高深啊!其實(shí)不然……
我們知道,Win32應(yīng)用程序是運(yùn)行在保護(hù)模式下的,每個(gè)Win32應(yīng)用程序都有相互獨(dú)立的4GB地址空間,并且已經(jīng)摒棄了16位時(shí)代的把代碼分為Data、Code等段的內(nèi)存模式的做法;現(xiàn)在它們只有一種內(nèi)存模式,即FLAT模式,意思是“平坦”的內(nèi)存模式——再也沒有煩人的64KB的段大小限制啦。如此一來,所有的Win32應(yīng)用程序都能各自運(yùn)行在一個(gè)連續(xù)、平坦、巨大的4GB空間中,作為程序員,也不用再跟段寄存器打交道,您可以用任意的段寄存器尋址任意的地址空間,是不是很方便呢?
不過且慢,Win32時(shí)代的編程雖然比之Win16時(shí)代已經(jīng)方便了不止一個(gè)數(shù)量級,但是畢竟還有一些規(guī)則是需要遵守的。最明顯的之一就是不能在程序運(yùn)行的過程中隨便更改代碼段!
(咦?剛剛不是說了Win32里面沒有段的概念了嗎?怎么這里又來了一個(gè)“代碼段”了?別急,請聽我細(xì)細(xì)道來……)
雖然Win32下已經(jīng)沒有了“段”,但是您還是可以給自己的程序分成不同的“段”,一個(gè)“分段”的開始即是上一個(gè)“分段”的結(jié)束。Win32只有兩種性質(zhì)的分段:Data和Code。
實(shí)際上,在Win32里面的分段并不是像DOS下一樣,為不同的段分別指出不同的段寄存器,因?yàn)閃indows下只有一個(gè)4GB的段,Windows程序中的分段表現(xiàn)在當(dāng)程序裝載時(shí),賦予不同的段不同的屬性,比如說當(dāng)你的程序加載時(shí),對于Ring3程序來說,.code段是不可寫的,而.data段是可寫的,如果你嘗試像在DOS下一樣寫自己的代碼部分,你將會(huì)得到一個(gè)“很cool”的藍(lán)屏錯(cuò)誤。
怎么樣?頭暈了嗎?如果沒有的話,讓我們繼續(xù)!^_^
上面已經(jīng)提到代碼段是不能在程序運(yùn)行途中更改的了,那么怎么又來了一個(gè)“SMC”技術(shù)呢?它是如何實(shí)現(xiàn)的?
其實(shí)關(guān)鍵就在于鏈接時(shí)的參數(shù),只要指定了代碼段的屬性是可寫的,那么就OK啦!(默認(rèn)的參數(shù)是不可寫的)。也就是說,我們在編譯、鏈接帶有SMC的Win32ASM時(shí)應(yīng)該這樣做:
ml /c /coff %1.asm link /subsystem:windows /section:.text,RWE %1.obj
|
怎么樣?明白了嗎? /section:.text,RWE 這句指定了代碼段(.text)的屬性是RWE,含義是:R(ReadAble),W(WriteAble),E(ExecuteAble),也就是“可讀可寫可執(zhí)行”。這樣我們的程序就可以在運(yùn)行途中自己改寫自己的代碼段啦,怎么樣?是不是很爽呢?
下面給出了一個(gè)完整的帶有SMC技術(shù)的Win32ASM例子,很容易理解的,記得要用上面的方法來編譯和鏈接哦!
;*********************************************** ;程序名稱:演示SMC原理 ;作者:羅聰 ;日期:2002-10-2 ;出處:http://laoluoc.yeah.net(老羅的繽紛天地) ;注意事項(xiàng):如欲轉(zhuǎn)載,請保持本程序的完整,并注明: ;轉(zhuǎn)載自“老羅的繽紛天地”(http://laoluoc.yeah.net) ;***********************************************
.386 .model flat, stdcall option casemap:none
include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib
ShowMessage proto ReplaceMent proto
.data szMsg1 db "這是未執(zhí)行SMC之前的代碼!", 0 szMsg2 db "SMC已經(jīng)執(zhí)行!", 0 szCaption db "SMC demo by LC, 2002", 0 Replace_Len dd 0
.code main: ;第一次執(zhí)行子程序ShowMessage,此時(shí)還沒執(zhí)行SMC操作 invoke ShowMessage
lea eax, ReplaceMentEnd ;標(biāo)號ReplaceMent的結(jié)束 lea edx, ReplaceMentStart ;標(biāo)號ReplaceMent的開始 sub eax, edx ;標(biāo)號ReplaceMent的長度 mov Replace_Len, eax ;把長度儲存起來
;關(guān)鍵代碼!!!!!!!!! lea esi, ReplaceMentStart ;標(biāo)號ReplaceMent的開始 lea edi, ShowMessageStart ;原程序ShowMessage的標(biāo)號的開始 mov ecx, Replace_Len ;標(biāo)號ReplaceMent的長度 rep movsb ;這里是最關(guān)鍵的語句!!!執(zhí)行SMC操作!
;第二次執(zhí)行子程序ShowMessage,此時(shí)已經(jīng)執(zhí)行了SMC操作。 ;換句話說,ShowMessage的內(nèi)容已經(jīng)不是第一次運(yùn)行時(shí)的內(nèi)容了: invoke ShowMessage
invoke ExitProcess, 0
ShowMessage proc ;這里用“::”的話,就能夠使標(biāo)號成為全局性的 ShowMessageStart:: invoke MessageBox, NULL, addr szMsg1, addr szCaption, MB_OK ShowMessageEnd::
;用nop來預(yù)留空間,以便后面的SMC能夠成功執(zhí)行; ;否則如果空間不夠,將有可能產(chǎn)生不可預(yù)測的錯(cuò)誤: nop nop nop nop nop nop nop nop
ret ShowMessage endp
ReplaceMent proc ;將要用來SMC的代碼: ReplaceMentStart:: ;invoke MessageBox, NULL, addr szMsg2, addr szCaption, MB_OK or MB_ICONINFORMATION push MB_OK or MB_ICONINFORMATION lea eax, szCaption push eax lea eax, szMsg2 push eax push NULL lea eax, MessageBox call eax ReplaceMentEnd::
ret ReplaceMent endp
end main
|