Windows内核驱动EPROCESS遍历进程模块
- 2019 年 11 月 15 日
- 筆記
包含的头文件 #include <ntifs.h> #include <ntstrsafe.h> 声明的API函数 NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process); NTKERNELAPI PPEB_EX PsGetProcessPeb(PEPROCESS Process); NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE Id, PEPROCESS *Process); NTKERNELAPI NTSTATUS PsLookupThreadByThreadId(HANDLE Id, PETHREAD *Thread); NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread); //NTKERNELAPI VOID NTAPI KeAttachProcess(PEPROCESS Process); //NTKERNELAPI VOID NTAPI KeDetachProcess(); //NTKERNELAPI VOID NTAPI KeStackAttachProcess(PEPROCESS Process, PKAPC_STATE ApcState); //NTKERNELAPI VOID NTAPI KeUnstackDetachProcess(PKAPC_STATE ApcState); 因为要通过PEPROCESS 来获取进程和模块,所以还要用到几个结构体要,在WinDbg 可看到。 这里新建一个头文件,包含了PEB等信息 #include "peb.h" 如下: #pragma once #include <ntifs.h> typedef struct _PEB_LDR_DATA_EX { ULONG Length; // +0x00 BOOLEAN Initialized; // +0x04 PVOID SsHandle; // +0x08 LIST_ENTRY InLoadOrderModuleList; // +0x0c LIST_ENTRY InMemoryOrderModuleList; // +0x14 LIST_ENTRY InInitializationOrderModuleList;// +0x1c }PEB_LDR_DATA_EX, *PPEB_LDR_DATA_EX; typedef struct _LDR_DATA_TABLE_ENTRY_EX { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { ULONG TimeDateStamp; PVOID LoadedImports; }; PVOID EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY ForwarderLinks; LIST_ENTRY ServiceTagLinks; LIST_ENTRY StaticLinks; PVOID ContextInformation; PVOID OriginalBase; LARGE_INTEGER LoadTime; } LDR_DATA_TABLE_ENTRY_EX, *PLDR_DATA_TABLE_ENTRY_EX; typedef struct _CURDIR { UNICODE_STRING DosPath; PVOID Handle; }CURDIR, *PCURDIR; typedef struct _RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; STRING DosPath; }RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; //进程参数 typedef struct _RTL_USER_PROCESS_PARAMETERS{ ULONG MaximumLength; ULONG Length; ULONG Flags; ULONG DebugFlags; PVOID ConsoleHandle; ULONG ConsoleFlags; PVOID StandardInput; PVOID StandardOutput; PVOID StandardError; CURDIR CurrentDirectory; UNICODE_STRING DllPath; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; PVOID Environment; ULONG StartingX; ULONG StartingY; ULONG CountX; ULONG CountY; ULONG CountCharsX; ULONG CountCharsY; ULONG FillAttribute; ULONG WindowFlags; ULONG ShowWindowFlags; UNICODE_STRING WindowTitle; UNICODE_STRING DesktopInfo; UNICODE_STRING ShellInfo; UNICODE_STRING RuntimeData; RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32]; }RTL_USER_PROCESS_PARAMETERS,*PRTL_USER_PROCESS_PARAMETERS; //进程环境块(因为Windows内核有一个机构PEB,为了不重定义,所以就另起一个名字) typedef struct _PEB_EX { UCHAR InheritedAddressSpace; UCHAR ReadImageFileExecOptions; UCHAR BeingDebugged; UCHAR SpareBool; PVOID Mutant; PVOID ImageBaseAddress; PPEB_LDR_DATA_EX Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; UCHAR Reserved4[104]; PVOID Reserved5[52]; PVOID PostProcessInitRoutine; PVOID Reserved7; UCHAR Reserved6[128]; ULONG SessionId; } PEB_EX, *PPEB_EX; 用于遍历进程函数 void EnumProcess(PEPROCESS eprocess) { KAPC_STATE ks; if (!MmIsAddressValid(eprocess)) return; //获取 PEB信息 PPEB_EX peb = PsGetProcessPeb(eprocess); if (!peb) return; //依附进程!!!!!!!!!!!!!! KeStackAttachProcess(eprocess, &ks); __try { if (PsGetProcessId(eprocess)!=0) { //获取 进程参数 PRTL_USER_PROCESS_PARAMETERS rtl_user_process_param = (PRTL_USER_PROCESS_PARAMETERS)peb->ProcessParameters; DbgPrint("CommandLine:%wZn", &rtl_user_process_param->CommandLine); DbgPrint("ImagePath=%wZn", &rtl_user_process_param->ImagePathName); //DbgPrint("Window Title=%wZn", &rtl_user_process_param->WindowTitle); DbgPrint("——————————————————————————————"); } } __except (EXCEPTION_EXECUTE_HANDLER) { //DbgPrint("Can not Process..."); } //取消依附进程 KeUnstackDetachProcess(&ks); } //遍历模块,大体上和遍历进程一样,但也要注意 void EnumModules(PEPROCESS eprocess) { KAPC_STATE ks; if (!MmIsAddressValid(eprocess)) return; //获取 PEB信息 PPEB_EX peb = PsGetProcessPeb(eprocess); if (!peb) return; //依附进程!!!!!!!!!!!!!! KeStackAttachProcess(eprocess, &ks); __try { PPEB_LDR_DATA_EX peb_LDR_data = (PPEB_LDR_DATA_EX)peb->Ldr; PLIST_ENTRY list_entry = &peb_LDR_data->InLoadOrderModuleList; //先获取第一个 PLIST_ENTRY currentList = list_entry->Flink; while (currentList!=list_entry) { PLDR_DATA_TABLE_ENTRY_EX ldr_data_table_entry = (PLDR_DATA_TABLE_ENTRY_EX)currentList; DbgPrint("Module Base=%p DllPath=%wZn", ldr_data_table_entry->DllBase, &ldr_data_table_entry->FullDllName); //指向下一个 currentList = currentList->Flink; } } __except (EXCEPTION_EXECUTE_HANDLER) { //DbgPrint("Can not Modules..."); } //取消依附进程 KeUnstackDetachProcess(&ks); } //这个函数把上面两个函数整合在一起了 VOID EnumProcessModuleInformations() { //第一个进程环境块 PEPROCESS eprocess=PsGetCurrentProcess(); PEPROCESS eprocess_first = eprocess; while (1) { //获取进程 EnumProcess(eprocess); //下一个进程,我获取的是WinXP的 EPROCESS ! eprocess = (PEPROCESS)(*(ULONG*)((ULONG)eprocess + 0x88) - 0x88); if (eprocess == eprocess_first) { break; } } eprocess= eprocess_first; while (1) { //获取模块 EnumModules(eprocess); //下一个进程 eprocess = (PEPROCESS)(*(ULONG*)((ULONG)eprocess + 0x88) - 0x88); if (eprocess == eprocess_first) { break; } } } 7 //卸载函数很简单 VOID unload(PDRIVER_OBJECT p) { DbgPrint("UnloadDriver..."); } 8 //驱动入口函数 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver_Obj, PUNICODE_STRING pRegisterPath) { DbgPrint("DriverEntry..."); pDriver_Obj->DriverUnload = unload; DbgPrint("DriverName:%wZ RegisterPath:%wZ n ", &pDriver_Obj->DriverName, pRegisterPath); //这里调用 EnumProcessModuleInformations(); return STATUS_SUCCESS; } 9
最后,基本上OK了,附上一张测试图:

Windows内核驱动EPROCESS遍历进程模块 END