Skip to content

Instantly share code, notes, and snippets.

@MurylloEx
Created February 7, 2024 20:14
Show Gist options
  • Save MurylloEx/480e980e7b45518ccd5261ff54229906 to your computer and use it in GitHub Desktop.
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.
#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