原文发表于百度空间,2008-7-25
==========================================================================
PEB中的Ldr部分包含有当前进程所加载的模块信息.
lkd> dt _peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
.....
其结构定义如下:
typedef struct _PEB_LDR_DATA { ULONG Length; BOOLEAN Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; //按加载顺序 LIST_ENTRY InMemoryOrderModuleList; //按内存顺序 LIST_ENTRY InInitializationOrderModuleList; //按初始化顺序 } PEB_LDR_DATA,*PPEB_LDR_DATA;
另一个重要结构就是存储每个模块信息的LDR_MODULE部分,其定义如下:
typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; void* BaseAddress; void* EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; HANDLE SectionHandle; ULONG CheckSum; ULONG TimeDateStamp; } LDR_MODULE, *PLDR_MODULE;
这两者的关系呢,引用别人的两张图来说明一下吧,看了图应该一目了然.
第二张图太大了,放个缩略图吧.
结构搞清楚之后,要遍历就很简单了,主要就是遍历一个双向环状链表.
PEB_LDR_DATA *pPEBLDR; LDR_MODULE *pLdrMod; LIST_ENTRY *pListEntry,*pStart; void *p,*BaseAddress,*FullDllName; _asm { mov eax,fs:[0x30] //TEB->PEB mov eax,[eax+0xC] //PEB->Ldr mov pPEBLDR,eax } printf("PEB_LDR_DATA:0x%08x ",pPEBLDR); printf("LDR->Length:0x%08x ",pPEBLDR->Length); printf("LDR->InLoadOrderModuleList: 0x%08x ",pPEBLDR->InLoadOrderModuleList); printf("LDR->InMemoryOrderModuleList: 0x%08x ",pPEBLDR->InMemoryOrderModuleList); printf("LDR->InInitializationOrderModuleList: 0x%08x ",pPEBLDR->InInitializationOrderModuleList); //遍历双链表 pListEntry=(LIST_ENTRY*)(PUCHAR)&(pPEBLDR->InLoadOrderModuleList); pStart=pListEntry; printf("BaseAddress FullDllName ==================================== "); do { pListEntry=pListEntry->Flink; pLdrMod=(LDR_MODULE*)pListEntry; printf("0x%08x ",pLdrMod->BaseAddress); wprintf(L"%s ",pLdrMod->FullDllName.Buffer); } while(pListEntry!=pStart);
效果图: