通过PEB的Ldr枚举进程内所有已加载的模块
一、几个重要的数据结构,可以通过windbg的dt命令查看其详细信息
_PEB、_PEB_LDR_DATA、_LDR_DATA_TABLE_ENTRY
二、技术原理
1、通过fs:[30h]获取当前进程的_PEB结构
2、通过_PEB的Ldr成员获取_PEB_LDR_DATA结构
3、通过_PEB_LDR_DATA的InMemoryOrderModuleList成员获取_LIST_ENTRY结构
4、通过_LIST_ENTRY的Flink成员获取_LDR_DATA_TABLE_ENTRY结构,注意:这里的Flink指向的是_LDR_DATA_TABLE_ENTRY结构中的InMemoryOrderLinks成员,因此需要计算真正的_LDR_DATA_TABLE_ENTRY起始地址,我们可以用CONTAINING_RECORD来计算。
5、输出_LDR_DATA_TABLE_ENTRY的BaseDllName或FullDllName成员信息。
三、代码实现(基于XP sp2 系统)
//EnumInLoadModule.c
//compile:cl EnumInLoadModule.c
#include <windows.h>
#define CONTAINING_RECORD(address, type, field) ((type *)( /
(PCHAR)(address) - /
(ULONG_PTR)(&((type *)0)->field)))
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PEB_LDR_DATA
{
DWORD Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
}PEB_LDR_DATA,*PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
DWORD SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
DWORD Flags;
WORD LoadCount;
WORD TlsIndex;
LIST_ENTRY HashLinks;
PVOID SectionPointer;
DWORD CheckSum;
DWORD TimeDateStamp;
PVOID LoadedImports;
PVOID EntryPointActivationContext;
PVOID PatchInformation;
}LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR SpareBool;
PVOID Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
}PEB,*PPEB;
int main(void)
{
PLDR_DATA_TABLE_ENTRY pLdrDataEntry = NULL;
PLIST_ENTRY pListEntryStart = NULL,pListEntryEnd = NULL;
PPEB_LDR_DATA pPebLdrData = NULL;
PPEB pPeb = NULL;
//故意加载一些DLL,以便测试!
LoadLibrary("ResLibDemo");
__asm
{
//1、通过fs:[30h]获取当前进程的_PEB结构
mov eax,dword ptr fs:[30h];
mov pPeb,eax
}
//2、通过_PEB的Ldr成员获取_PEB_LDR_DATA结构
pPebLdrData = pPeb->Ldr;
//3、通过_PEB_LDR_DATA的InMemoryOrderModuleList成员获取_LIST_ENTRY结构
pListEntryStart = pListEntryEnd = pPebLdrData->InMemoryOrderModuleList.Flink;
//查找所有已载入到内存中的模块
do
{
//4、通过_LIST_ENTRY的Flink成员获取_LDR_DATA_TABLE_ENTRY结构
pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(pListEntryStart,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks);
//5、输出_LDR_DATA_TABLE_ENTRY的BaseDllName或FullDllName成员信息
printf("%S/n",pLdrDataEntry->BaseDllName.Buffer);
pListEntryStart = pListEntryStart->Flink;
}while(pListEntryStart != pListEntryEnd);
}
/*
output:
EnumInLoadModule.exe
ntdll.dll
kernel32.dll
ResLibDemo.dll
...
*/