驅動開發:內核中實現Dump進程轉儲

多數ARK反內核工具中都存在驅動級別的內存轉存功能,該功能可以將應用層中運行進程的內存鏡像轉存到特定目錄下,內存轉存功能在應對加殼程序的分析尤為重要,當進程在內存中解碼后,我們可以很容易的將內存鏡像導出 , 從而更好的對樣本進行分析,當然某些加密殼可能無效但絕大多數情況下是可以被轉存的 。

驅動開發:內核中實現Dump進程轉儲

文章插圖
在上一篇文章《驅動開發:內核R3與R0內存映射拷貝》介紹了一種方式SafeCopyMemory_R3_to_R0可以將應用層進程的內存空間映射到內核中 , 要實現內存轉儲功能我們還是需要使用這個映射函數 , 只是需要在此函數上增加一些功能而已 。
在實現轉存之前,需要得到兩個東西 , 進程內模塊基地址以及模塊長度這兩個參數是必不可少的,至于內核中如何得到指定進程的模塊數據,在很早之前的文章《驅動開發:內核中枚舉進線程與模塊》中有詳細的參考方法,這里就在此基礎之上實現一個簡單的進程模塊遍歷功能 。
如下代碼中使用的就是枚舉進程PEB結構得到更多參數的具體實現,如果不懂得可以研讀《驅動開發:內核通過PEB得到進程參數》這篇文章此處不再贅述 。
#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; PVOIDDllBase; PVOIDEntryPoint; ULONGSizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRINGBaseDllName; ULONGFlags; USHORTLoadCount; USHORTTlsIndex; PVOIDSectionPointer; ULONGCheckSum; PVOIDLoadedImports; PVOIDEntryPointActivationContext; PVOIDPatchInformation; LIST_ENTRY64 ForwarderLinks; LIST_ENTRY64 ServiceTagLinks; LIST_ENTRY64 StaticLinks; PVOIDContextInformation; ULONG64OriginalBase; LARGE_INTEGER LoadTime;} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;// 偏移地址ULONG64 LdrInPebOffset = 0x018;//peb.ldrULONG64 ModListInPebOffset = 0x010; //peb.ldr.InLoadOrderModuleList// 聲明APINTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);NTKERNELAPI PPEB PsGetProcessPeb(PEPROCESS Process);NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);// 根據進程ID返回進程EPROCESS,失敗返回NULLPEPROCESS LookupProcess(HANDLE Pid){ PEPROCESS eprocess = NULL; if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)))return eprocess; elsereturn NULL;}// 枚舉指定進程的模塊// By: LyShark.comVOID 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; // EPROCESS地址無效則退出 if (!MmIsAddressValid(Process))return; // 獲取PEB地址 Peb = (SIZE_T)PsGetProcessPeb(Process); // PEB地址無效則退出 if (!Peb)return; // 依附進程 KeStackAttachProcess(Process, &ks); __try {// 獲得LDR地址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){//打印信息:基址、大小、DLL路徑DbgPrint("模塊基址 = %p | 大小 = %ld | 模塊名 = %wZ | 完整路徑= %wZ \n",(PVOID)(((PLDR_DATA_TABLE_ENTRY)Module)->DllBase),(ULONG)(((PLDR_DATA_TABLE_ENTRY)Module)->SizeOfImage),&(((PLDR_DATA_TABLE_ENTRY)Module)->BaseDllName),&(((PLDR_DATA_TABLE_ENTRY)Module)->FullDllName));Module = Module->Flink;// 測試下一個模塊信息的可讀性ProbeForRead((CONST PVOID)Module, 80, 8);} } __except (EXCEPTION_EXECUTE_HANDLER){ ; } // 取消依附進程 KeUnstackDetachProcess(&ks);}VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){}NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ DbgPrint("hello lyshark.com \n"); 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), "lyshark.exe") != NULL){EnumModule(eproc);}} } DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS;}如上我們指定獲取應用層lyshark.exe進程的模塊信息 , 并可得到以下輸出效果:
驅動開發:內核中實現Dump進程轉儲

推薦閱讀