Windows核心新手上路1——掛鈎SSDT
這個系列記錄學習我學習windows核心的點點滴滴,高手請直接無視。
文章核心內容:掛鈎SSDT中函數列NtOpenProcess,NtDuplicateObject,NtCreateThread,NtOpenThread,NtWriteVirtualMemory,過濾進程操作來保護目標進程空間。
SSDT的全稱是System Services Descriptor Table,系統服務描述符表。這個表把ring3的Win32 API和ring0的核心API聯絡起來。SSDT並不僅僅只包含一個龐大的地址索引表,它還包含著一些其它有用的資訊,諸如地址索引的基地址、服務函數個數等。
SSDT管的是與系統相關的函數(kernel32.dll、ntdll.dll)。通過修改此表的函數地址可以對常用windows函數及API進行hook,從而實現對一些關心的系統動作進行過濾、監控的目的。一些HIPS、防毒軟體、系統監控、註冊表監視軟體往往會採用此介面來實現自己的監控模組。
SSDT在Win32子系統的核心實現是NTOSKRNL.EXE,匯出表名是 KeServiceDescriptorTable,對應系統進程一般有System
SSDT結構:
typedef struct tagSSDT {
PULONG pSSDTBase; //SSDT在記憶體中的基址
PVOID pServiceCounterTable;
ULONG uNumberOfServices; //SSDT項個數
PUCHAR pParamTableBase;
} SSDT, *PSSDT; //SSDT
1 如何掛鈎SSDT
首先關閉CR0防寫保護(通過改變CR0寄存器的WP位),然後用新的函數地址替換原來SSDT中的函數地址,最後恢複CR0防寫保護。
掛鈎SSDT中函數列NtOpenProcess,NtDuplicateObject,NtCreateThread,NtOpenThread,NtWriteVirtualMemory,過濾進程操作來保護目標進程空間。
1.1NtOpenProcess
在Windows作業系統中,kernel32!OpenProcess通過調用ntdll!NtOpenProcess最終轉到核心態的nt!NtOpenProcess,通過掛鈎NtOpenProcess,可以過濾和攔截進程開啟其他進程的操作。
在自訂的NtOpenProcess函數中,首先擷取要開啟的進程PID,判斷該PID是否是被保護的進程,如果是被保護的進程,則去掉開啟許可權中的相應許可權,如果是開啟本系統R3進程,還要去掉結束進程的許可權,最終,再調用真實的NtOpenProcess函數,最後返回給R3的進程控制代碼就無法讀寫操作受保護的進程,惡意程式也無法結束目標進程。
通過進程控制代碼擷取PID 判斷是否受保護的PID 如果是 做一些許可權的處理…. 調用真實NtOpenProcess 如果否 調用真實的NtCreateThread |
代碼1.1 MyNtOpenProcess
1.2NtDuplicateObject
Windows系統提供了一個函數DuplicateHandle,用於從其他進程複製一個控制代碼到當前進程,而且csrss.exe進程會儲存所有進程的控制代碼,通過調用DuplicateHandle從csrss中複製控制代碼,可以間接的達到調用OpenProcess擷取目標進程控制代碼的目的。
在定義的NtDuplcateObject函數中,首先調用真實的NtDuplicateObject,如果調用成功,判斷最後返回的控制代碼是不是受保護進程的控制代碼,如果是受保護的進程控制代碼,則關閉之。通過這樣的過濾,惡意程式無法通過調用DuplicateHandle來開啟受保護的進程。
1.3NtCreateThread
R3中在進程中和其他進程中建立線程(分別調用CreateThread和CreateRemoteThread)最終通過ntdll!NtCreateThread轉到核心態的nt!CreateThread,通過過濾nt!CreateThread可以防止惡意程式在受保護的進程中建立遠程線程(即調用CreateRemoteThread)。實現的MyNtCreateThread處理流程如代碼1.2所示:
通過進程控制代碼擷取PID 判斷是否受保護的PID 如果是 返回STATUS_ACCESS_DENIED 如果否 調用真實的NtCreateThread |
代碼1.2 MyNtCreateThread
1.4NtOpenThread
在windows作業系統中,通過調用OpenThread可以擷取目標線程的控制代碼,進一步通過此控制代碼操作目標線程。防密碼竊取系統掛鈎了NtOpenThread來防止惡意程式操作受保護進程的線程。
在自訂的NtOpenThread函數中,首先擷取線程所在進程的PID,然後判斷該PID是否被保護,如果是被保護的PID,則直接返回STATUS_ACCESS_DENIED,否則調用真實的NtOpenThread。
1.5NtWriteVirtualMemory
在windows作業系統中,進程可以調用kernel32!WriteProcessMemory來寫其他進程記憶體,kernel32!WriteProcessMemory通過ntdll!NtWriteVirtualMemory轉到核心態的nt!NtWriteVirtualMemory。通過掛鈎nt!NtWriteVirtualMemory來防目惡意程式寫受保護的進程記憶體。虛擬碼如代碼1.3所示。
通過進程控制代碼擷取PID 判斷是否受保護的PID 如果是 返回STATUS_ACCESS_DENIED 如果否 調用真實的NtWriteVirtualMemory |
代碼1.3 MyNtWriteVirtualMemory
Windows核心新手上路1——掛鈎SSDT
這個系列記錄學習我學習windows核心的點點滴滴,高手請直接無視。
文章核心內容:掛鈎SSDT中函數列NtOpenProcess,NtDuplicateObject,NtCreateThread,NtOpenThread,NtWriteVirtualMemory,過濾進程操作來保護目標進程空間。
SSDT的全稱是System Services Descriptor Table,系統服務描述符表。這個表把ring3的Win32 API和ring0的核心API聯絡起來。SSDT並不僅僅只包含一個龐大的地址索引表,它還包含著一些其它有用的資訊,諸如地址索引的基地址、服務函數個數等。
SSDT管的是與系統相關的函數(kernel32.dll、ntdll.dll)。通過修改此表的函數地址可以對常用windows函數及API進行hook,從而實現對一些關心的系統動作進行過濾、監控的目的。一些HIPS、防毒軟體、系統監控、註冊表監視軟體往往會採用此介面來實現自己的監控模組。
SSDT在Win32子系統的核心實現是NTOSKRNL.EXE,匯出表名是 KeServiceDescriptorTable,對應系統進程一般有System
SSDT結構:
typedef struct tagSSDT {
PULONG pSSDTBase; //SSDT在記憶體中的基址
PVOID pServiceCounterTable;
ULONG uNumberOfServices; //SSDT項個數
PUCHAR pParamTableBase;
} SSDT, *PSSDT; //SSDT
1 如何掛鈎SSDT
首先關閉CR0防寫保護(通過改變CR0寄存器的WP位),然後用新的函數地址替換原來SSDT中的函數地址,最後恢複CR0防寫保護。
掛鈎SSDT中函數列NtOpenProcess,NtDuplicateObject,NtCreateThread,NtOpenThread,NtWriteVirtualMemory,過濾進程操作來保護目標進程空間。
1.1NtOpenProcess
在Windows作業系統中,kernel32!OpenProcess通過調用ntdll!NtOpenProcess最終轉到核心態的nt!NtOpenProcess,通過掛鈎NtOpenProcess,可以過濾和攔截進程開啟其他進程的操作。
在自訂的NtOpenProcess函數中,首先擷取要開啟的進程PID,判斷該PID是否是被保護的進程,如果是被保護的進程,則去掉開啟許可權中的相應許可權,如果是開啟本系統R3進程,還要去掉結束進程的許可權,最終,再調用真實的NtOpenProcess函數,最後返回給R3的進程控制代碼就無法讀寫操作受保護的進程,惡意程式也無法結束目標進程。
通過進程控制代碼擷取PID 判斷是否受保護的PID 如果是 做一些許可權的處理…. 調用真實NtOpenProcess 如果否 調用真實的NtCreateThread |
代碼1.1 MyNtOpenProcess
1.2NtDuplicateObject
Windows系統提供了一個函數DuplicateHandle,用於從其他進程複製一個控制代碼到當前進程,而且csrss.exe進程會儲存所有進程的控制代碼,通過調用DuplicateHandle從csrss中複製控制代碼,可以間接的達到調用OpenProcess擷取目標進程控制代碼的目的。
在定義的NtDuplcateObject函數中,首先調用真實的NtDuplicateObject,如果調用成功,判斷最後返回的控制代碼是不是受保護進程的控制代碼,如果是受保護的進程控制代碼,則關閉之。通過這樣的過濾,惡意程式無法通過調用DuplicateHandle來開啟受保護的進程。
1.3NtCreateThread
R3中在進程中和其他進程中建立線程(分別調用CreateThread和CreateRemoteThread)最終通過ntdll!NtCreateThread轉到核心態的nt!CreateThread,通過過濾nt!CreateThread可以防止惡意程式在受保護的進程中建立遠程線程(即調用CreateRemoteThread)。實現的MyNtCreateThread處理流程如代碼1.2所示:
通過進程控制代碼擷取PID 判斷是否受保護的PID 如果是 返回STATUS_ACCESS_DENIED 如果否 調用真實的NtCreateThread |
代碼1.2 MyNtCreateThread
1.4NtOpenThread
在windows作業系統中,通過調用OpenThread可以擷取目標線程的控制代碼,進一步通過此控制代碼操作目標線程。防密碼竊取系統掛鈎了NtOpenThread來防止惡意程式操作受保護進程的線程。
在自訂的NtOpenThread函數中,首先擷取線程所在進程的PID,然後判斷該PID是否被保護,如果是被保護的PID,則直接返回STATUS_ACCESS_DENIED,否則調用真實的NtOpenThread。
1.5NtWriteVirtualMemory
在windows作業系統中,進程可以調用kernel32!WriteProcessMemory來寫其他進程記憶體,kernel32!WriteProcessMemory通過ntdll!NtWriteVirtualMemory轉到核心態的nt!NtWriteVirtualMemory。通過掛鈎nt!NtWriteVirtualMemory來防目惡意程式寫受保護的進程記憶體。虛擬碼如代碼1.3所示。
通過進程控制代碼擷取PID 判斷是否受保護的PID 如果是 返回STATUS_ACCESS_DENIED 如果否 調用真實的NtWriteVirtualMemory |
代碼1.3 MyNtWriteVirtualMemory