雖然我以往的文章中都有穿插此內容,但沒有專門來說明(x86和x64專門來匯編說明)。雖然此篇老外文很基礎,但卻講得頗為詳細。
在 shellcode 能夠定位或使用任何 Windows api 之前,必須定位 kernel32.dll 的基地址。該方法使用 Win32線程信息塊(TIB)定位程序環(huán)境塊(PEB)來定位 InInitializationOrderModuleList,它包含 kernel32.dll 的基地址作為它的第二個列表條目。
32位版本
此方法適用于所有版本的 Windows。
以下代碼將定位 Kernel32 的基地址:
1234567891011
mov eax,[fs:0x30] ; Get the memory address of the PEB; structure and store it in EAXmov eax,[eax+0x0C] ; Get the memory address of the PEB_LDR_DATA; structure and store it in EAXmov esi,[eax+0x1C] ; Get the memory address of the first; LIST_ENTRY structure stored in the; InInitializationOrderModuleList and store; it in ESIlodsd ; Loads the memory address of the cond ; LIST_ENTRY structuremov ebx,[eax+0x08] ; Save the ba address of kernel32.dll in EBX
1、第一條MOV指令將PEB結構的地址保存在EAX 中。Windows 使用FS寄存器來存儲TIB結構的地址,PEB結構的地址位于偏移量0x30字節(jié)處。該FS包含地址0x7FFDE000:
B.如果我們查看內存轉儲中的那個位置,我們可以看到PEB的地址位于偏移量0x30(48 字節(jié))處,在此示例中其值為0x7FFDF000:
圖2: PEB 地址0x30
2、第二條MOV指令將PEB_LDR_DATA結構的地址保存在EAX 中。該PEB_LDR_DATA結構位于一個偏移0x0C字節(jié)的PEB結構,它的值是0x00341EA0在這個例子中:
圖 3:偏移 0x0C 處的 PEB_LDR_DATA 結構地址
3、第三條MOV指令將InInitializationOrderModuleList列表的地址保存在ESI 中。此列表包含已加載模塊的列表。第一個條目是ntdll.dll,第二個是kernel32.dll,這就是我們所追求的。第一個列表條目地址位于0x1C(28 字節(jié))的偏移量處,在本例中它的值為0x00341F58:
圖 4:偏移 0xC1 處的 InInitializationOrderModuleList 列表地址
4、該LODSD指令增量ESI,其中包含第一模塊的地址,一個讓現(xiàn)在指向kernel32.dll中錄入并保存在地址EAX,它的值是0x00342020在這個例子:
圖 5:LOSD 指令遞增 ESI 以指向下一個列表條目
5、最后的MOV指令將kernel32.dll的基地址保存在EBX 中。距該位置0x08(8 個字節(jié))的偏移量是kernel32.dll的基地址所在的位置,在此示例中其值為0x7C800000:
圖 6:位于偏移 0x08 處的 Kernel32.dll 的基地址
64 位版本現(xiàn)在,在 64 位系統(tǒng)上嘗試同樣的事情。我將嘗試 32 位代碼,看看它是否有效。馬上,問題來了:
圖 7:fs:[0x30] 無效
在FS:[0x30]值指向未知的記憶,這是不會幫助我們。在參考維基百科上的Win32 線程信息塊(TIB,又名線程環(huán)境塊( TEB ))信息后,似乎在 64 位系統(tǒng)上,進程環(huán)境塊( PEB ) 位于gs:[0x60] 處。在我們繼續(xù)之前,讓我們看看還有什么變化。我決定切換到WinDBG進行更多探索。
檢查 TIB(TEB) 結構在WinDBG 中,讓我們使用!teb命令獲取TEB的基地址:
圖 8:查找 TEB 的基地址
接下來,使用基地址,我們可以使用以下命令檢查TEB結構:
dt _TEB 000007fffffde000
我們可以確認PEB結構位于偏移量0x60 處。
圖 9:PEB 結構位于 TEB 的偏移 0x60
檢查 PEB 結構在WinDBG 中,可以使用以下命令轉儲PEB結構:
dt _PEB 000007fffffd9000
從結果中我們看到,LDR結構是在一個偏移量為0x18的的PEB結構的基址。
圖 10:LDR 結構位于 PEB 的偏移量 0x18
檢查 PEB_LDR_DATA 列表結構我們知道在 32 位工作時,PEB_LDR_DATA結構的第一個列表項應該包含有關正在運行的程序的信息,ntdll作為第二個列表項,第三個應該包含有關kernel32 的信息。我們現(xiàn)在將嘗試驗證它對于 64 位系統(tǒng)是否相同。首先,要查看列表,以下命令:
dt _PEB_LDR_DATA 000000007723d640
迭代 LDR 數(shù)據(jù)表以查找 Kernel32我們對偏移量0x20處的InMemoryOrderModuleList感興趣。我們將首先看看那里有什么。
圖 11:檢查 PEB_LDR_DATA 結構
要查看列表中的第一個條目指向什么,我們將通過發(fā)出以下命令來檢查LDR_DATA_TABLE_ENTRY結構內容:
dt _LDR_DATA_TABLE_ENTRY poi(000000007723d640+0x20)
正如我們在圖 12 中看到的,第一個條目是當前進程。在這個例子中恰好是notepad.exe。
圖 12:查看第一個 LDR 數(shù)據(jù)表條目
我們需要查看000000007723d640+0x20指向的內容。由于我們正在查看一個雙向鏈表,這應該將我們帶到下一個條目。以下命令將查看該值:
? poi(000000007723d640+0x20)
圖 13:查看下一個 LDR 數(shù)據(jù)表條目的指針
使用計算值,我們現(xiàn)在可以通過以下命令查看下一個LDR_DATA_TABLE_ENTRY:
dt _LDR_DATA_TABLE_ENTRY poi(00000000003c34e0)
下一個入口指向ntdll.dll。這可能很有用。不需要知道最終 shellcode 的這個地址,但是,我們可以注意到它在列表中的位置。
圖 14:第二個 LDR 數(shù)據(jù)表條目指向 ntdll.dll
要查看列表中的下一個條目,我們需要計算下一個條目的地址。LDR_DATA_TABLE_ENTRY結構的第一個元素是一個雙向鏈表。要找到FLink,我們只需要找到計算指針,然后我們就可以查看下一個條目。執(zhí)行此操作的命令是:
? poi(00000000003c34e0)dt _LDR_DATA_TABLE_ENTRY poi(00000000003c35f0)
太好了,我們找到了kernel32.dll的條目。
圖 15:第三個 LDR 數(shù)據(jù)表條目指向 kernel32.dll
把它放在一起現(xiàn)在我們知道如何找到包含kernel32.dll模塊詳細信息的 LDR 數(shù)據(jù)表條目,是時候編寫一些程序集來復制我們在上一節(jié)中所做的工作,以便我們可以定位和存儲基地址的KERNEL32,以便它可以被用來定位的Win32 API。
我們首先列出我們在WinDBG 中執(zhí)行的查找kernel32基地址的步驟。
找到PEB結構的地址。
找到PEB_LDR_DATA結構的地址。
找到InMemoryOrderModuleList列表的地址。
迭代到第三個InMemoryOrderModuleList條目。
存儲kernel32.dll的基地址。
1:找到PEB結構的地址根據(jù)維基百科文章,線程信息塊存儲在gs寄存器中,PEB位于偏移量0x60 處。有了這些信息,下面的匯編指令應該將PEB的地址存儲在RAX寄存器中:
mov rax, [gs:0x60]
2:找到PEB_LDR_DATA結構的地址該PEB_LDR_DATA結構位于一個偏移為0x18從基地址PEB。下面的指令應該將PEB_LDR_DATA結構的地址存儲在RAX寄存器中。
mov rax, [rax+0x18]
3:找到InMemoryOrderModuleList列表的地址所述InMemoryOrderModuleList是在的偏移為0x20的的PEB_LDR_DATA結構。以下程序集將地址存儲在RAX寄存器中:
mov rax, [rax+0x20]
4:迭代到第三個 InMemoryOrderModuleList 條目該InMemoryOrderModuleList是一個雙向鏈表。每個列表的第一個元素是FLink,因此我們可以使用它通過加載第一個指針兩次來快速迭代到列表中的第三個條目。以下代碼將在RAX寄存器中保留第三個條目的地址:
mov rax, [rax]mov rax, [rax]
5:保存Kernel32的基地址最后一步是將kernel32.dll的基地址保存在某處,以便我們以后可以使用它來檢索其他 Win32 函數(shù)。根據(jù)Microsoft 的 x64 調用約定,R12-R15寄存器是調用者/被調用者保存的寄存器。這意味著我們應該能夠保留這些寄存器之一來為我們的 shellcode 的其余部分存儲kernel32.dll的基地址。基地址位于距列表條目開頭0x20的偏移量處。將基地址存儲在R12寄存器中的代碼是:
mov r12, [rax+0x20]
完整的組裝綜上所述,查找kernel32.dll基地址并存入R12寄存器的匯編程序如下:
12345678910111213
[SECTION .text]BITS 64global _start_start:mov rax, [gs:0x60]mov rax, [rax+0x18]mov rax, [rax+0x20]mov rax, [rax]mov rax, [rax]mov r12, [rax+0x20]
正如您在圖 16 中看到的,kernel32.dll的基地址已成功存儲在R12 中。
圖 16:Kernel32.dll 的基地址存儲在 R12 中
或者,如果您還需要保存ntdll.dll的基地址,您可以使用一個輕微的變體,這個變體會將ntdll.dll的基址存儲在R13寄存器中:
1234567891011121314
[SECTION .text]BITS 64global _start_start:mov rax, [gs:0x60]mov rax, [rax+0x18]mov rax, [rax+0x20]mov rax, [rax]mov r13, [rax+0x20]mov rax, [rax]mov r12, [rax+0x20]
結論學習了如何使用 x86 和 x64 匯編代碼查找kernel32.dll的基地址。找到kernel32.dll基地址的能力很重要,因為它可以用來調用LoadLibrary Win32 函數(shù)來定位其他有趣的 Win32 函數(shù)的地址,甚至加載其他 DLL 以添加附加功能。就像添加ws2_32.dll以提供對以下函數(shù)的訪問:accept、bind、socket、WSASocket 和 WSAStartup。
本文發(fā)布于:2023-02-28 20:01:00,感謝您對本站的認可!
本文鏈接:http://www.newhan.cn/zhishi/a/167764964976579.html
版權聲明:本站內容均來自互聯(lián)網(wǎng),僅供演示用,請勿用于商業(yè)和其他非法用途。如果侵犯了您的權益請與我們聯(lián)系,我們將在24小時內刪除。
本文word下載地址:kernel32(kernel32.dll動態(tài)鏈接庫報錯解決方法).doc
本文 PDF 下載地址:kernel32(kernel32.dll動態(tài)鏈接庫報錯解決方法).pdf
| 留言與評論(共有 0 條評論) |