设为首页 加入收藏

TOP

驱动开发:内核中实现Dump进程转储(一)
2023-07-23 13:31:51 】 浏览:61
Tags:Dump 程转储

多数ARK反内核工具中都存在驱动级别的内存转存功能,该功能可以将应用层中运行进程的内存镜像转存到特定目录下,内存转存功能在应对加壳程序的分析尤为重要,当进程在内存中解码后,我们可以很容易的将内存镜像导出,从而更好的对样本进行分析,当然某些加密壳可能无效但绝大多数情况下是可以被转存的。

在上一篇文章《驱动开发:内核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;
	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;		//peb.ldr
ULONG64 ModListInPebOffset = 0x010;	//peb.ldr.InLoadOrderModuleList

// 声明API
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
NTKERNELAPI PPEB PsGetProcessPeb(PEPROCESS Process);
NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);

// 根据进程ID返回进程EPROCESS,失败返回NULL
PEPROCESS LookupProcess(HANDLE Pid)
{
	PEPROCESS eprocess = NULL;
	if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)))
		return eprocess;
	else
		return NULL;
}

// 枚举指定进程的模块
// By: LyShark.com
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;
	
	// 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);
	
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇驱动开发:内核通过PEB得到进程参.. 下一篇驱动开发:内核R3与R0内存映射拷贝

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目