内核枚举进程使用PspCidTable
这个未公开的函数,它能最大的好处是能得到进程的EPROCESS地址,由于是未公开的函数,所以我们需要变相的调用这个函数,通过PsLookupProcessByProcessId
函数查到进程的EPROCESS,如果PsLookupProcessByProcessId
返回失败,则证明此进程不存在,如果返回成功则把EPROCESS、PID、PPID、进程名等通过DbgPrint打印到屏幕上。
内核枚举进程: 进程就是活动起来的程序,每一个进程在内核里,都有一个名为 EPROCESS
的结构记录它的详细信息,其中就包括进程名,PID,PPID,进程路径等,通常在应用层枚举进程只列出所有进程的编号即可,不过在内核层需要把它的 EPROCESS 地址给列举出来。
内核枚举进程使用PspCidTable
这个未公开的函数,它能最大的好处是能得到进程的EPROCESS地址,由于是未公开的函数,所以我们需要变相的调用这个函数,通过PsLookupProcessByProcessId
函数查到进程的EPROCESS,如果PsLookupProcessByProcessId
返回失败,则证明此进程不存在,如果返回成功则把EPROCESS、PID、PPID、进程名等通过DbgPrint打印到屏幕上。
#include <ntifs.h>
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);
PEPROCESS LookupProcess(HANDLE Pid) { PEPROCESS eprocess = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; Status = PsLookupProcessByProcessId(Pid, &eprocess); if (NT_SUCCESS(Status)) return eprocess; return NULL; }
VOID EnumProcess() { PEPROCESS eproc = NULL; for (int temp = 0; temp < 100000; temp += 4) { eproc = LookupProcess((HANDLE)temp); if (eproc != NULL) { DbgPrint("进程名: %s --> 进程PID = %d --> 父进程PPID = %d\r\n",PsGetProcessImageFileName(eproc),PsGetProcessId(eproc), PsGetProcessInheritedFromUniqueProcessId(eproc)); ObDereferenceObject(eproc); } } }
VOID UnDriver(PDRIVER_OBJECT driver) { DbgPrint(("Uninstall Driver Is OK \n")); }
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { EnumProcess(); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|

内核枚举线程: 内核线程的枚举与进程相似,线程中也存在一个ETHREAD结构,但在枚举线程之前需要先来枚举到指定进程的eprocess结构,然后在根据eprocess结构对指定线程进行枚举。
#include <ntddk.h> #include <windef.h>
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE Id, PEPROCESS *Process); NTKERNELAPI NTSTATUS PsLookupThreadByThreadId(HANDLE Id, PETHREAD *Thread); NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
PEPROCESS LookupProcess(HANDLE Pid) { PEPROCESS eprocess = NULL; if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess))) return eprocess; else return NULL; }
PETHREAD LookupThread(HANDLE Tid) { PETHREAD ethread; if (NT_SUCCESS(PsLookupThreadByThreadId(Tid, ðread))) return ethread; else return NULL; }
VOID EnumThread(PEPROCESS Process) { ULONG i = 0, c = 0; PETHREAD ethrd = NULL; PEPROCESS eproc = NULL; for (i = 4; i<262144; i = i + 4) { ethrd = LookupThread((HANDLE)i); if (ethrd != NULL) { eproc = IoThreadToProcess(ethrd); if (eproc == Process) { DbgPrint("线程: ETHREAD=%p TID=%ld\n",ethrd,(ULONG)PsGetThreadId(ethrd)); } ObDereferenceObject(ethrd); } } }
VOID MyEnumThread(char *ProcessName) { ULONG i = 0; PEPROCESS eproc = NULL; for (i = 4; i<100000000; i = i + 4) { eproc = LookupProcess((HANDLE)i); if (eproc != NULL) { ObDereferenceObject(eproc); if (strstr(PsGetProcessImageFileName(eproc), ProcessName) != NULL) { EnumThread(eproc); } } } }
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { MyEnumThread("calc.exe"); DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
|

内核枚举进程模块: 枚举进程中的所有模块信息,DLL模块记录在 PEB 的 LDR 链表里,LDR 是一个双向链表,枚举链表即可,相应的卸载可使用MmUnmapViewOfSection
函数,分别传入进程的EPROCESS,DLL模块基址即可。
#include <ntddk.h> #include <windef.h>
typedef struct _KAPC_STATE { LIST_ENTRY ApcListHead[2]; PKPROCESS Process; UCHAR KernelApcInProgress; UCHAR KernelApcPending; UCHAR UserApcPending; } KAPC_STATE, *PKAPC_STATE;
typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY64 InLoadOrderLinks; LIST_ENTRY64 InMemoryOrderLinks; LIST_ENTRY64 InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; PVOID SectionPointer; ULONG CheckSum; PVOID LoadedImports; PVOID EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY64 ForwarderLinks; LIST_ENTRY64 ServiceTagLinks; LIST_ENTRY64 StaticLinks; PVOID ContextInformation; ULONG64 OriginalBase; LARGE_INTEGER LoadTime; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
ULONG64 LdrInPebOffset = 0x018; ULONG64 ModListInPebOffset = 0x010;
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); NTKERNELAPI PPEB PsGetProcessPeb(PEPROCESS Process); NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);
PEPROCESS LookupProcess(HANDLE Pid) { PEPROCESS eprocess = NULL; if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess))) return eprocess; else return NULL; }
VOID EnumModule(PEPROCESS Process) { SIZE_T Peb = 0; SIZE_T Ldr = 0; PLIST_ENTRY ModListHead = 0; PLIST_ENTRY Module = 0; ANSI_STRING AnsiString; KAPC_STATE ks; if (!MmIsAddressValid(Process)) return; Peb = (SIZE_T)PsGetProcessPeb(Process); if (!Peb) return; KeStackAttachProcess(Process, &ks); __try { Ldr = Peb + (SIZE_T)LdrInPebOffset; ProbeForRead((CONST PVOID)Ldr, 8, 8); ModListHead = (PLIST_ENTRY)(*(PULONG64)Ldr + ModListInPebOffset); ProbeForRead((CONST PVOID)ModListHead, 8, 8); Module = ModListHead->Flink; while (ModListHead != Module) { DbgPrint("模块基址=%p 大小=%ld 路径=%wZ\n",(PVOID)(((PLDR_DATA_TABLE_ENTRY)Module)->DllBase), (ULONG)(((PLDR_DATA_TABLE_ENTRY)Module)->SizeOfImage),&(((PLDR_DATA_TABLE_ENTRY)Module)->FullDllName)); Module = Module->Flink; ProbeForRead((CONST PVOID)Module, 80, 8); } } __except (EXCEPTION_EXECUTE_HANDLER){;} KeUnstackDetachProcess(&ks); }
VOID MyEnumModule(char *ProcessName) { ULONG i = 0; PEPROCESS eproc = NULL; for (i = 4; i<100000000; i = i + 4) { eproc = LookupProcess((HANDLE)i); if (eproc != NULL) { ObDereferenceObject(eproc); if (strstr(PsGetProcessImageFileName(eproc), ProcessName) != NULL) { EnumModule(eproc); } } } }
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { MyEnumModule("calc.exe"); DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
|

内核枚举加载SYS文件: 内核中的SYS文件也是通过双向链表的方式相连接的,我们可以通过遍历LDR_DATA_TABLE_ENTRY
结构(遍历自身DriverSection成员),就能够得到全部的模块信息。
#include <ntddk.h> #include <wdm.h>
typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImages; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { struct { ULONG TimeDateStamp; }; struct { PVOID LoadedImports; }; }; }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { ULONG count = 0; NTSTATUS Status; DriverObject->DriverUnload = DriverUnload; PLDR_DATA_TABLE_ENTRY pLdr = NULL; PLIST_ENTRY pListEntry = NULL; PLDR_DATA_TABLE_ENTRY pModule = NULL; PLIST_ENTRY pCurrentListEntry = NULL;
pLdr = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; pListEntry = pLdr->InLoadOrderLinks.Flink; pCurrentListEntry = pListEntry->Flink;
while (pCurrentListEntry != pListEntry) { pModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (pModule->BaseDllName.Buffer != 0) { DbgPrint("基址:%p ---> 偏移:%p ---> 结束地址:%p---> 模块名:%wZ \r\n", pModule->DllBase, pModule->SizeOfImages - (LONGLONG)pModule->DllBase, (LONGLONG)pModule->DllBase + pModule->SizeOfImages,pModule->BaseDllName); } pCurrentListEntry = pCurrentListEntry->Flink; } DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
|
