通过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 ... */  

 

四、总结

枚举模块有多种方式,随着深入的学习,希望能总结越来越来的方法。在这里感谢sai 的文章:http://www.debugman.com/read.php?tid=4255,虽然他的文章还没细看,但他里面的_LDR_DATA_TABLE_ENTRY结构促发了我编写测试的想法并总结了本文。


 

你可能感兴趣的:(数据结构,struct,String,list,测试,table)