通过PEB遍历当前进程中的模块(C语言实现)
0x00 相关说明:
Windows应用层如果要遍历当前进程所加载的模块可以使用WIN32API通过进程快照来实现
通过PEB来遍历进程模块没有WIN32API的使用痕迹,在某些场合更加好用
其中32位应用程序的 PEB 的地址可以通过 fs:[0x30]获取,fs:[0]为TEB结构的地址
0x01 相关数据结构:
下面的数据结构可以在windbg中使用命令查看(使用 dt <数据结构名称>)
typedef struct _TEB { //fs:[0]
NT_TIB Tib;
PVOID EnvironmentPointer;
CLIENT_ID Cid;
PVOID ActiveRpcInfo;
PVOID ThreadLocalStoragePointer;
PPEB Peb;
//......
} TEB, * PTEB;
typedef struct _PEB { //fs:[0x30]
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
BYTE BitField;
PVOID Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
//......
} PEB, * PPEB;
typedef struct _PEB_LDR_DATA {
UINT Length;
BYTE Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
//......
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
//......
} _LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _CLIENT_ID {
PVOID UniqueProcess;
PVOID UniqueThread;
} CLIENT_ID, * PCLIENT_ID;
0x02 实现原理:
结构索引流程如下:
其中各个_LDR_DATA_TABLE_ENTRY结构的关系如下:(以3个模块为例)
其中 InLoadOrderLinks、InMemoryOrderLinks、InInitializationOrderLinks 均为:LIST_ENTRY
0x03 代码实现:
代码实现如下:(记得自行添加前面介绍的相关结构定义):
int main(int argc, char* argv[])
{
PPEB pPEB = (PPEB)__readfsdword(0x30);
PPEB_LDR_DATA pLdr = pPEB->Ldr;DWORD dwFixOffset=0;
PLDR_DATA_TABLE_ENTRY pBase, pNext;printf("Enum InLoadOrderModuleList:\r\n");
dwFixOffset = 0;
pBase = (PLDR_DATA_TABLE_ENTRY)((DWORD)(pLdr->InLoadOrderModuleList.Flink) - dwFixOffset);
pNext = pBase;
do {
wprintf_s(L"%s\r\n", pNext->FullDllName.Buffer);
pNext = (PLDR_DATA_TABLE_ENTRY)((DWORD)(pNext->InLoadOrderLinks.Flink) - dwFixOffset);
} while (pBase != pNext);
printf("Enum InLoadOrderModuleList End!\r\n\r\n");printf("Enum InMemoryOrderModuleList:\r\n");
dwFixOffset = (DWORD) & (pBase->InMemoryOrderLinks) - (DWORD)pBase;
pBase = (PLDR_DATA_TABLE_ENTRY)((DWORD)(pLdr->InMemoryOrderModuleList.Flink) - dwFixOffset);
pNext = pBase;
do {
wprintf_s(L"%s\r\n", pNext->FullDllName.Buffer);
pNext = (PLDR_DATA_TABLE_ENTRY)((DWORD)(pNext->InMemoryOrderLinks.Flink) - dwFixOffset);
} while (pBase != pNext);
printf("Enum InMemoryOrderModuleList End!\r\n\r\n");printf("Enum InInitializationOrderModuleList:\r\n");
dwFixOffset = (DWORD) & (pBase->InInitializationOrderLinks) - (DWORD)pBase;
pBase = (PLDR_DATA_TABLE_ENTRY)((DWORD)(pLdr->InInitializationOrderModuleList.Flink) - dwFixOffset);
pNext = pBase;
do {
wprintf_s(L"%s\r\n", pNext->FullDllName.Buffer);
pNext = (PLDR_DATA_TABLE_ENTRY)((DWORD)(pNext->InInitializationOrderLinks.Flink) - dwFixOffset);
} while (pBase != pNext);
printf("Enum InInitializationOrderModuleList End!\r\n\r\n");
system("pause");
return 0;
}
代码执行结果: