Created
February 7, 2024 20:14
-
-
Save MurylloEx/480e980e7b45518ccd5261ff54229906 to your computer and use it in GitHub Desktop.
This snippet allow enumerate all modules of a process in Win32 using Process Environment Block (PEB) from remote process. Works with x86 and x64.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <TlHelp32.h> | |
#include <string> | |
#include <codecvt> | |
#ifndef NT_SUCCESS | |
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) | |
#endif | |
typedef struct _PROCESS_BASIC_INFORMATION { | |
PVOID Reserved1; | |
PVOID PebBaseAddress; | |
PVOID Reserved2[2]; | |
ULONG_PTR UniqueProcessId; | |
PVOID Reserved3; | |
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; | |
typedef enum _PROCESSINFOCLASS { | |
ProcessBasicInformation = 0, | |
ProcessDebugPort = 7, | |
ProcessWow64Information = 26, | |
ProcessImageFileName = 27, | |
ProcessBreakOnTermination = 29 | |
} PROCESSINFOCLASS; | |
typedef NTSTATUS(NTAPI* PNtQueryInformationProcess)( | |
IN HANDLE ProcessHandle, | |
IN PROCESSINFOCLASS ProcessInformationClass, | |
OUT PVOID ProcessInformation, | |
IN ULONG ProcessInformationLength, | |
OUT PULONG ReturnLength); | |
typedef struct _UNICODE_STRING32 { | |
USHORT Length; | |
USHORT MaximumLength; | |
DWORD32 Buffer; | |
} UNICODE_STRING32; | |
typedef struct _UNICODE_STRING64 { | |
USHORT Length; | |
USHORT MaximumLength; | |
DWORD64 Buffer; | |
} UNICODE_STRING64; | |
typedef struct _PEB_LIST_ENTRY32 { | |
DWORD32 Flink; | |
DWORD32 Blink; | |
} PEB_LIST_ENTRY32, * PPEB_LIST_ENTRY32; | |
typedef struct _PEB_LIST_ENTRY64 { | |
DWORD64 Flink; | |
DWORD64 Blink; | |
} PEB_LIST_ENTRY64, * PPEB_LIST_ENTRY64; | |
typedef struct _PEB_LDR_DATA32 { | |
ULONG Length; | |
BOOLEAN Initialized; | |
DWORD32 SsHandle; | |
PEB_LIST_ENTRY32 InLoadOrderModuleList; | |
PEB_LIST_ENTRY32 InMemoryOrderModuleList; | |
PEB_LIST_ENTRY32 InInitializationOrderModuleList; | |
} PEB_LDR_DATA32, *PPEB_LDR_DATA32; | |
typedef struct _PEB_LDR_DATA64 { | |
ULONG Length; | |
BOOLEAN Initialized; | |
DWORD64 SsHandle; | |
PEB_LIST_ENTRY64 InLoadOrderModuleList; | |
PEB_LIST_ENTRY64 InMemoryOrderModuleList; | |
PEB_LIST_ENTRY64 InInitializationOrderModuleList; | |
} PEB_LDR_DATA64, *PPEB_LDR_DATA64; | |
typedef struct _LDR_DATA_TABLE_ENTRY64 { | |
LIST_ENTRY64 InLoadOrderLinks; | |
LIST_ENTRY64 InMemoryOrderLinks; | |
LIST_ENTRY64 InInitializationOrderLinks; | |
DWORD64 DllBase; | |
DWORD64 EntryPoint; | |
ULONG SizeOfImage; | |
UNICODE_STRING64 FullDllName; | |
UNICODE_STRING64 BaseDllName; | |
} LDR_DATA_TABLE_ENTRY64, * PLDR_DATA_TABLE_ENTRY64; | |
typedef struct _LDR_DATA_TABLE_ENTRY32 { | |
LIST_ENTRY32 InLoadOrderLinks; | |
LIST_ENTRY32 InMemoryOrderLinks; | |
LIST_ENTRY32 InInitializationOrderLinks; | |
DWORD32 DllBase; | |
DWORD32 EntryPoint; | |
ULONG SizeOfImage; | |
UNICODE_STRING32 FullDllName; | |
UNICODE_STRING32 BaseDllName; | |
} LDR_DATA_TABLE_ENTRY32, * PLDR_DATA_TABLE_ENTRY32; | |
typedef struct _PEB32 { | |
BYTE Reserved1[2]; | |
BYTE BeingDebugged; | |
BYTE Reserved2[1]; | |
BYTE Reserved3[8]; //PVOID[2] | |
DWORD32 Ldr; | |
BYTE ProcessParameters[4]; //PVOID | |
BYTE Reserved4[12]; //PVOID[3] | |
BYTE AtlThunkSListPtr[4]; //PVOID | |
BYTE Reserved5[4]; //PVOID | |
BYTE Reserved6[4]; | |
BYTE Reserved7[4]; //PVOID | |
BYTE Reserved8[4]; | |
BYTE AtlThunkSListPtr32[4]; | |
BYTE Reserved9[180]; //PVOID[45] | |
BYTE Reserved10[96]; | |
BYTE PostProcessInitRoutine[4]; //PVOID | |
BYTE Reserved11[128]; | |
BYTE Reserved12[4]; //PVOID[1] | |
BYTE SessionId[4]; | |
} PEB32, * PPEB32; | |
typedef struct _PEB64 { | |
BYTE Reserved1[2]; | |
BYTE BeingDebugged; | |
BYTE Reserved2[21]; | |
DWORD64 Ldr; //PVOID | |
DWORD64 ProcessParameters; //PVOID | |
BYTE Reserved3[520]; | |
BYTE PostProcessInitRoutine[8]; //PVOID | |
BYTE Reserved4[136]; | |
BYTE SessionId[4]; | |
} PEB64, * PPEB64; | |
#pragma region System Info | |
BOOL IsX64System() { | |
UNREFERENCED_PARAMETER(GetSystemWow64DirectoryW(NULL, 0)); | |
return (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) ? FALSE : TRUE; | |
} | |
BOOL IsX86System() { | |
return (IsX64System() == FALSE) ? TRUE : FALSE; | |
} | |
BOOL IsX86Process(HANDLE ProcessHandle) { | |
if (IsX86System() == TRUE) { | |
return TRUE; | |
} | |
BOOL IsX86Process = FALSE; | |
UNREFERENCED_PARAMETER(IsWow64Process(ProcessHandle, &IsX86Process)); | |
return IsX86Process; | |
} | |
BOOL IsX64Process(HANDLE ProcessHandle) { | |
return (IsX86Process(ProcessHandle) == FALSE) ? TRUE : FALSE; | |
} | |
#pragma endregion | |
LPVOID NtGetPeb(IN HANDLE ProcessHandle) { | |
HMODULE NTDLL = GetModuleHandleW(L"NTDLL.DLL"); | |
if (NTDLL == NULL) { | |
return NULL; | |
} | |
PNtQueryInformationProcess NtQueryInformationProcess = | |
(PNtQueryInformationProcess)GetProcAddress(NTDLL, "NtQueryInformationProcess"); | |
if (!NtQueryInformationProcess) { | |
return NULL; | |
} | |
ULONG BufferLength = 0; | |
if ((IsX64System() == TRUE) && (IsX86Process(ProcessHandle) == TRUE)) { | |
// Is x64 environment and the target process is x86 | |
DWORD64 Ppeb = 0; | |
ULONG Status = NtQueryInformationProcess( | |
ProcessHandle, | |
ProcessWow64Information, | |
&Ppeb, | |
sizeof(void*), | |
&BufferLength | |
); | |
if (NT_SUCCESS(Status)) { | |
return (LPVOID)Ppeb; | |
} | |
} | |
else { | |
// Dont care if is x64 or x86. It just not is x64 environment and x86 process, then its fine. | |
PROCESS_BASIC_INFORMATION ProcessInformation = { 0 }; | |
ULONG Status = NtQueryInformationProcess( | |
ProcessHandle, | |
ProcessBasicInformation, | |
&ProcessInformation, | |
sizeof(PROCESS_BASIC_INFORMATION), | |
&BufferLength | |
); | |
if (NT_SUCCESS(Status)) { | |
return (LPVOID)ProcessInformation.PebBaseAddress; | |
} | |
} | |
return NULL; | |
} | |
int main(int argc, char** argv) | |
{ | |
HANDLE hProcess = GetCurrentProcess(); | |
LPVOID Addr = NtGetPeb(hProcess); | |
PEB64 Peb64 = { 0 }; | |
ReadProcessMemory(hProcess, Addr, &Peb64, sizeof(PEB64), NULL); | |
PEB_LDR_DATA64 Ldr64 = { 0 }; | |
ReadProcessMemory(hProcess, (LPVOID)Peb64.Ldr, &Ldr64, sizeof(PEB_LDR_DATA64), NULL); | |
DWORD64 HeadAddress = Peb64.Ldr + FIELD_OFFSET(PEB_LDR_DATA64, InLoadOrderModuleList); | |
LPVOID EntryAddress = (LPVOID)CONTAINING_RECORD(Ldr64.InLoadOrderModuleList.Flink, LDR_DATA_TABLE_ENTRY64, InLoadOrderLinks); | |
while (true) { | |
LDR_DATA_TABLE_ENTRY64 Module = { 0 }; | |
ReadProcessMemory(hProcess, EntryAddress, &Module, sizeof(Module), NULL); | |
SIZE_T nameLength = Module.FullDllName.Length * sizeof(wchar_t); | |
PWSTR name = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nameLength); | |
ReadProcessMemory(hProcess, (LPVOID)Module.FullDllName.Buffer, name, nameLength, NULL); | |
std::wcout << L"Module Name: " << name << std::endl; | |
std::cout << "Module Base Address: " << (LPVOID)Module.DllBase << std::endl; | |
PPEB_LIST_ENTRY64 Entry = (PPEB_LIST_ENTRY64)(&Module); | |
if (Entry->Flink == HeadAddress) { | |
break; | |
} | |
EntryAddress = (LPVOID)CONTAINING_RECORD(Entry->Flink, LDR_DATA_TABLE_ENTRY64, InLoadOrderLinks); | |
} | |
return EXIT_SUCCESS; | |
} | |
//int main(int argc, char** argv) | |
//{ | |
// PPEB64 Peb64 = (PPEB64)NtGetPeb(GetCurrentProcess()); // work only for local process as the pointer is valid only here | |
// | |
// PPEB_LDR_DATA64 Ldr64 = (PPEB_LDR_DATA64)Peb64->Ldr; | |
// | |
// PPEB_LIST_ENTRY64 pHead = (PPEB_LIST_ENTRY64)(&Ldr64->InLoadOrderModuleList); | |
// PPEB_LIST_ENTRY64 pEntry = (PPEB_LIST_ENTRY64)(Ldr64->InLoadOrderModuleList.Flink); | |
// | |
// while (pEntry != pHead) { | |
// PLDR_DATA_TABLE_ENTRY64 Module = CONTAINING_RECORD(pEntry, LDR_DATA_TABLE_ENTRY64, InLoadOrderLinks); | |
// | |
// std::wcout << L"Module Name: " << (wchar_t*)(Module->FullDllName.Buffer) << std::endl; | |
// std::cout << "Module Base Address: " << (LPVOID)Module->DllBase << std::endl << std::endl; | |
// | |
// pEntry = (PPEB_LIST_ENTRY64)pEntry->Flink; | |
// } | |
// | |
// return EXIT_SUCCESS; | |
//} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment