通过PEB遍历当前进程中的模块(C语言实现)

Posted darkbright

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过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;
}

代码执行结果:

技术图片

以上是关于通过PEB遍历当前进程中的模块(C语言实现)的主要内容,如果未能解决你的问题,请参考以下文章

二叉树先序遍历C语言实现

C内存共享进程通信范例

二叉树层次遍历(包含C语言实现代码)

远程监控的原理和实现如何用c语言实现

C语言如何终止线程

用c语言写二叉树,源代码。