获取内核进程DLL基地址 与 获取某进程内部DLL地址
一、驱动编写的基本写法
DriverEntry :相当main函数
DriverUnload : 卸载函数
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("已卸载驱动!\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
DbgPrint("安装驱动成功!\n");
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
二、了解内核PEB结构体
Windbg使用命令:dt _PEB [进程EPROCESS] 随便查看一个进程的 EPROCESS ,图中结构体0x18偏移处有一个Ldr指向了 _PEB_LDR_DATA
点击Ldr 之后查看了 _PEB_LDR_DATA 的结构是这样子的,其中 InLoadOrderModuleList 指向了另一个结构体的地址 _LDR_DATA_TABLE_ENTRY 这里面就有内核进程DLL的地址
下图可以看到双向链表中保存了当前进程的基地址
编写代码的思路就有了,获取 PEB->Ldr->InLoadOrderModuleList->Blink
代码中使用了一个微软提供的宏 CONTAINING_RECORD : 它的功能为已知结构体或类的某一成员、对象中该成员的地址以及这一结构体名或类名,从而得到该对象的基地址。
#include<ntddk.h>
typedef struct _LDR_DATA_TABLE_ENTRY {
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 {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
}LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("已卸载驱动!\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
PLDR_DATA_TABLE_ENTRY pLdr = NULL;
PLIST_ENTRY pListEntry = NULL;
PLIST_ENTRY pCurrentListEntry = NULL;
PLDR_DATA_TABLE_ENTRY pCurrentModule = NULL;
DbgPrint("安装驱动成功!\n");
pDriverObject->DriverUnload = DriverUnload;
// UNICODE_STRING UnicodeString2;
//RtlInitUnicodeString(&UnicodeString2, L"ntoskrnl.exe");
pLdr = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
pListEntry = pLdr->InLoadOrderLinks.Flink;
pCurrentListEntry = pListEntry->Flink;
while (pCurrentListEntry != pListEntry)
{
pCurrentModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (pCurrentModule->BaseDllName.Buffer != 0)
{
DbgPrint("ModuleName = %wZ ModuleBase = %p \r\n",
pCurrentModule->BaseDllName,
pCurrentModule->DllBase);
}
pCurrentListEntry = pCurrentListEntry->Flink;
}
return STATUS_SUCCESS;
}
可以看到已经获取到了内核全部模块的基地址

如果需要获取某个进程的某个DLL的基地址,可以先封装成一个函数 传入eprocess 和需要获取模块的名称,根据函数名判断一下。
NTSTATUS GetModeaddr(PEPROCESS Eprocess, PUNICODE_STRING ModeName)
{
KAPC_STATE ks;
PUNICODE_STRING UnicodeString2;
DbgPrint("%wZ", ModeName);
DbgPrint("%wZ", &ModeName);
RtlInitUnicodeString(&UnicodeString2, ModeName);
PEPROCESS Eprocess2 = Eprocess;
if (Eprocess2 == NULL)
{
DbgPrint("Eprocess 获取失败");
return;
}
__try {
ULONG64 peb = *(PULONG64)((ULONG64)Eprocess2 + PEB_OFFSET_IN_EPROCESS);
KeStackAttachProcess(Eprocess2, &ks);
ULONG64 idr = *(PULONG64)(peb + LDR_OFFSET_IN_PEB);
PLIST_ENTRY pListHead = (idr + InLoadOrderModuleList_OFFSET);
PLIST_ENTRY pMod = pListHead->Flink; //下一个链表
while (pMod != pListHead)
{
PCUNICODE_STRING name = &(((PLDR_DATA_TABLE_ENTRY)pMod)->ModuleName);
//DbgPrint("name = %wZ\n Base= %p", name, (PVOID)(((PLDR_DATA_TABLE_ENTRY)pMod)->ModuleBaseAddress));
if (RtlCompareUnicodeString(name, &UnicodeString2, TRUE))
{
DbgPrint("name = %wZ\n Base= %p", name, (PVOID)(((PLDR_DATA_TABLE_ENTRY)pMod)->ModuleBaseAddress));
base = (PVOID)(((PLDR_DATA_TABLE_ENTRY)pMod)->ModuleBaseAddress);
}
pMod = pMod->Flink;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("EXCEPTION_EXECUTE_HANDLER is occure...\n");
}
KeUnstackDetachProcess(&ks);
}

浙公网安备 33010602011771号