第七章——Windows內核基礎-內核數據結構(內核對象,SSDT,TEB,PEB)


一,內核對象
內核對象的結構圖
一個內核對象分為對象頭和對象體兩個部分,在對象頭中至少有一個object_header和其他信息。對象體緊挨着對象頭中的object_header。
這里注意對象指針指向的並不是對象頭,如果要訪問對象頭,需要拿對象體減去一個特定的偏移值,獲取到對象頭,在通過對象頭獲取其他字段
Windows內核對象可以分為三類:
⑴.Dispatcher對象
        之所以叫Dispatcher對象,是因為這種對象在對象體的開始位置存放了一個特定的公共數據結構DISPATCHER_HEADER。
        包含DISPATCHER_HEADER結構的內核對象的名字都是以字母K開頭,表示這是一個內核對象,例如:KPROCESS,KTHREAD,KEVENT等等,但是反過來說,以K開頭的內        核對象不一定就是Dispatcher對象。 是不是Dispatcher對象還是取決於是否有DISPATCHER_HEADER結構體。
        此對象都是可以等待的內核對象,這些對象可以作為參數傳給內核KeWaitForSingleObject函數,以及常見的應用層函數WaitForSingleObject
 
⑵.I/O對象
        I/O對象在對象體開始位置並沒有放置DISPATCHER_HEADER結構體,但通常會放置一個type和size有關的整形成員,其中的type表示該內核對象的類型(例如文件的內核對象類型為26),size則表示為大小。常見的I/O對象有:DEVICE_OBJECT,FILE_OBJECT,IRP,DRIVER_OBJECT
 
⑶.其他對象
        除了以上兩類對象之外的都為其他內核對象,這里只說進程對象(EPROCESS)和線程對象(ETHREAD)
        進程對象EPROCESS:每個進程都有一個EPROCESS結構,記錄了各種數據,所有的EPROCESS都被存放在一個雙向鏈表中,我們在枚舉進程的時候,通過遍歷鏈表就可以查看到所有的進程。當然自己也可以將自己的進程從這個雙向鏈表中摘除,從而隱藏自身。
        有兩個內核函數可以虎丘到EPROCESS結構
        ①PsLookupProcessByProcessID(
                IN         HANDLE processID,
                OUT     PEPROCESS * process );
        ②PsGetCurrentProcess();直接獲取當前進程的EPOCESS
 
EPROCESS結構的常見數據
    
    ETHREAD結構是管理線程的內核對象,每個線程都有對象的EHREAD結構,第一個成員就是線程對象KTHREAD成員,所有的ETHREAD結構也被放在一個雙向鏈表中
    ETHREAD重要成員:KTHREAD Tcb       線程內核對象。
                                    CLIENT_ID Cid       進程ID    
 
    KPROCESS,EPROCESS,ETHREAD,KTHREAD之間的關系圖:
可以看出,EPROCESS和ETHREAD都是雙向鏈表組織管理,一個EPROCESS中包含一個KPROCESS,這個KPROCESS中指向一個ETHREAD結構,在ETHREAD中又包含一個KTHREAD結構
 
 
二,SSDT
SSDT全稱系統服務描述符表,通過ntoskrnl.exe導出。一個函數的調用,在應用層會先在kernel32.dll中調用,在通過ntdll中檢查參數,之后通過調用中斷進入0環,將調用函數的服務號存放到eax中,之后根據eax的值(索引)在SSDT中找到指定的函數
結構如下:
typedef struct ServiceDescriptorEntry {
     unsigned int *ServiceTableBase;                   //表的基地址
     unsigned int *ServiceCounterTableBase;                        
     unsigned int NumberOfServices;                //表中服務函數的個數       
     unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
 
SSDT表最重要的兩個成員一個為表的基地址,一個為函數個數
SSDT其實就是一個存放函數指針的數值,既然是函數指針,那尋址查找函數的方式就是:ServiceTableBase+index*4 (32位機器)
在64位上的尋址方式是基地址+索引*16。也可以用左移4位表示= [基地址+index*4]>>4+基地址
 
Shadow SSDT:它與SSDT類似,只是它包含的事ntoskrnel.exe和win32k.sys服務函數,主要處理user32.dll和GDI32.dll的系統調用
截屏保護,按鍵保護,搜索窗口保護,防止窗口關閉保護都可以從Shadow SSDT中的函數HOOK而實現
 
 
三,TEB(線程環境塊)
    一個進程的所有的TEB都存放在從0X7FFDE000開始的線性內存中,每4KB為一個完整的TEB
    在fs:[0]的地址執行TEB結構,這個結構開頭是一個NT_TIB結構
 TEB結構:   
TEB at fs:7FFDF000
+0x000 NtTib // _NT_TIB
+0x01c EnvironmentPointer // Ptr32 Void
+0x020 ClientId // _CLIENT_ID
+0x028 ActiveRpcHandle // Ptr32 Void
+0x02c ThreadLocalStoragePointer // Ptr32 Void
+0x030 ProcessEnvironmentBlock // Ptr32 _PEB 這里指向 PEB 表,即進程環境塊
 
NT_TIB結構:
typedef struct _NT_TIB //sizeof 1ch
{
00h struct _EXCEPTION_REGISTRATION *ExceptionList; //SEH鏈入口
04h PVOID StackBase; //堆棧基址
08h PVOID StackLimit; //堆棧大小
0ch PVOID SubSystemTib;
union {
PVOID FiberData;
10h DWORD Version;
};
14h PVOID ArbitraryUserPointer;
18h struct _NT_TIB *Self; //本NT_TIB結構自身的線性地址
}NT_TIB;
 
如何訪問TEB? 可以通過NtCurrentTeb函數和FS段寄存器訪問這兩種方法訪問TEB
FS段寄存器訪問:mov eax,dword ptr fs:[0x18];   //指向自身的TEB結構
這里如果是FS:[0]則表示為NT_TIB結構體
 
 
四,PEB
PEB在TEB的0x30偏移處查找,獲取PEB的方法:
mov eax,dword ptr fs:[0x18];        //查找TEB
mov eax,dword ptr [eax+0x30];       //查找PEB
PEB+0X2地方為BeingDebugged.如果被調試該字段為1,反之為0
PEB結構的字段非常多,這里不一一贅述
總結下PEB,TEB和EPROCESS,ETHREAD關系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM