通过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 系统)

[cpp]  view plain copy
  1. //EnumInLoadModule.c  
  2. //compile:cl EnumInLoadModule.c  
  3. #include   
  4.   
  5. #define CONTAINING_RECORD(address, type, field) ((type *)( /  
  6.              (PCHAR)(address) - /  
  7.              (ULONG_PTR)(&((type *)0)->field)))  
  8.   
  9. typedef struct _UNICODE_STRING {  
  10.   USHORT  Length;  
  11.   USHORT  MaximumLength;  
  12.   PWSTR  Buffer;  
  13. } UNICODE_STRING, *PUNICODE_STRING;  
  14.   
  15. typedef struct _PEB_LDR_DATA  
  16. {  
  17.    DWORD Length;  
  18.    UCHAR Initialized;  
  19.    PVOID SsHandle;  
  20.    LIST_ENTRY InLoadOrderModuleList;  
  21.    LIST_ENTRY InMemoryOrderModuleList;  
  22.    LIST_ENTRY InInitializationOrderModuleList;  
  23.    PVOID EntryInProgress;  
  24. }PEB_LDR_DATA,*PPEB_LDR_DATA;  
  25.   
  26. typedef struct _LDR_DATA_TABLE_ENTRY  
  27. {  
  28.    LIST_ENTRY InLoadOrderLinks;  
  29.    LIST_ENTRY InMemoryOrderLinks;  
  30.    LIST_ENTRY InInitializationOrderLinks;  
  31.    PVOID DllBase;  
  32.    PVOID EntryPoint;  
  33.    DWORD SizeOfImage;  
  34.    UNICODE_STRING FullDllName;  
  35.    UNICODE_STRING BaseDllName;  
  36.    DWORD Flags;  
  37.    WORD LoadCount;  
  38.    WORD TlsIndex;  
  39.    LIST_ENTRY HashLinks;  
  40.    PVOID SectionPointer;  
  41.    DWORD CheckSum;  
  42.    DWORD TimeDateStamp;  
  43.    PVOID LoadedImports;  
  44.    PVOID EntryPointActivationContext;  
  45.    PVOID PatchInformation;  
  46. }LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;  
  47.   
  48. typedef struct _PEB  
  49. {  
  50.    UCHAR InheritedAddressSpace;  
  51.    UCHAR ReadImageFileExecOptions;  
  52.    UCHAR BeingDebugged;  
  53.    UCHAR SpareBool;  
  54.    PVOID Mutant;  
  55.    PVOID ImageBaseAddress;  
  56.    PPEB_LDR_DATA Ldr;  
  57. }PEB,*PPEB;  
  58.   
  59. int main(void)  
  60. {  
  61.     PLDR_DATA_TABLE_ENTRY pLdrDataEntry = NULL;  
  62.     PLIST_ENTRY pListEntryStart = NULL,pListEntryEnd = NULL;  
  63.     PPEB_LDR_DATA pPebLdrData = NULL;  
  64.     PPEB pPeb = NULL;  
  65.       
  66.     //故意加载一些DLL,以便测试!  
  67.     LoadLibrary("ResLibDemo");  
  68.     __asm  
  69.     {  
  70.         //1、通过fs:[30h]获取当前进程的_PEB结构  
  71.         mov eax,dword ptr fs:[30h];  
  72.         mov pPeb,eax  
  73.     }  
  74.       
  75.     //2、通过_PEB的Ldr成员获取_PEB_LDR_DATA结构  
  76.     pPebLdrData = pPeb->Ldr;  
  77.       
  78.     //3、通过_PEB_LDR_DATA的InMemoryOrderModuleList成员获取_LIST_ENTRY结构  
  79.     pListEntryStart = pListEntryEnd = pPebLdrData->InMemoryOrderModuleList.Flink;  
  80.       
  81.     //查找所有已载入到内存中的模块  
  82.     do  
  83.     {  
  84.         //4、通过_LIST_ENTRY的Flink成员获取_LDR_DATA_TABLE_ENTRY结构  
  85.         pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(pListEntryStart,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks);  
  86.           
  87.         //5、输出_LDR_DATA_TABLE_ENTRY的BaseDllName或FullDllName成员信息  
  88.         printf("%S/n",pLdrDataEntry->BaseDllName.Buffer);  
  89.           
  90.         pListEntryStart = pListEntryStart->Flink;  
  91.           
  92.     }while(pListEntryStart != pListEntryEnd);  
  93. }  
  94.   
  95. /* 
  96. output: 
  97.   EnumInLoadModule.exe 
  98.   ntdll.dll 
  99.   kernel32.dll 
  100.   ResLibDemo.dll 
  101.   ... 
  102. */  
  

 

四、总结

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


你可能感兴趣的:(通过PEB的Ldr枚举进程内所有已加载的模块)