windbg查找Kernel32.dll基址
一、首先準備好一個程序,運行起來,用windbg進行附加調試,由於每個windows下的程序都會加載kernel32.dll,因此,找基址的過程是一樣的;
二、查看PEB地址;
法一、r $peb
法二、通過TEB獲取,r $teb
獲取到teb地址後,對_TEB結構體解析dt _TEB 3ca000
法三、通過fs寄存器獲取,我們知道fs:[0]就是TEB結構體的首地址,但是,在windbg裏dd fs:[0]時,地址卻做了隱藏:
那該怎麽辦呢,其實,這就要看下TEB的結構了
在TEB結構的0x18偏移處,存放的其實就是TEB的地址,和fs:[0]是一樣的;
另外,在TEB結構的0x30偏移處,存放的就是PEB的地址,我們再來看下:
和上面兩種方法,得到的結果都是一致的,這也驗證了我們的想法;
三、接下來,既然PEB的地址找到了,就對PEB進行解析:
首先找到LDR:
接下來,解析LDR:
這裏,也許有人會有疑問:那個_LIST_ENTRY後面,怎麽有兩個值,是什麽含義呢?加個-b,就看出來了:
typedef struct _LIST_ENTRY { struct _LIST_ENTRY *Flink; struct _LIST_ENTRY *Blink; } LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
其實,內核數據結構中,比較常見,使用的這個雙向鏈表;
我們就選取InLoadOrderModuleList這個鏈;對它的Flink進行解析,
通過查閱MSDN,知道,這個Flink指向的具體的數據結構類型是:_LDR_DATA_TABLE_ENTRY
繼續遍歷InLoadOrderLinks的Flink字段:
還不是Kernel32.dll,繼續走:
到此,通過遍歷InLoadOrderLinks鏈,我們找到了KERNEL32.DLL,取出基址就比較容易了,在0x18偏移處;
取出這個基址,我們就可以解析PE導出表,找到我們需要的函數的地址了;
四、代碼
int GetKernel32Base() { int nAddress = 0; _asm { push eax; mov eax, fs:[0x30]; // PEB mov eax, [eax + 0xC] // LDR mov eax, [eax + 0xC] // InLoadOrderModuleList, exe mov eax, [eax]; // nt.dll mov eax, [eax]; // kernel32.dll mov eax, dword ptr ds:[eax + 0x18]; // BaseAddr; mov nAddress, eax; pop eax; } return nAddress; }
附錄:
參考MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/aa813708%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
windbg查找Kernel32.dll基址