11#include < windows.h>
2+ #include < winternl.h>
23#include < tlhelp32.h>
34#include < vector>
45#include < algorithm>
56
67#include " NativeCore.hpp"
78
9+ static DWORD GetRemotePeb (HANDLE process, PPEB* ppeb)
10+ {
11+ const auto ntdll = GetModuleHandle (TEXT (" ntdll" ));
12+ if (!ntdll)
13+ return ERROR_MOD_NOT_FOUND;
14+
15+ using tRtlNtStatusToDosError = ULONG (NTAPI *)(
16+ _In_ NTSTATUS Status
17+ );
18+ const auto pRtlNtStatusToDosError = tRtlNtStatusToDosError (GetProcAddress (ntdll, " RtlNtStatusToDosError" ));
19+ if (!pRtlNtStatusToDosError)
20+ return ERROR_NOT_FOUND;
21+
22+ using tNtQueryInformationProcess = NTSTATUS (NTAPI *)(
23+ _In_ HANDLE ProcessHandle,
24+ _In_ PROCESSINFOCLASS ProcessInformationClass,
25+ _Out_writes_bytes_ (ProcessInformationLength) PVOID ProcessInformation,
26+ _In_ ULONG ProcessInformationLength,
27+ _Out_opt_ PULONG ReturnLength
28+ );
29+
30+ const auto pNtQueryInformationProcess = tNtQueryInformationProcess (GetProcAddress (ntdll, " NtQueryInformationProcess" ));
31+ if (!pNtQueryInformationProcess)
32+ return ERROR_NOT_FOUND;
33+
34+ PROCESS_BASIC_INFORMATION pbi;
35+ const auto status = pNtQueryInformationProcess (process, ProcessBasicInformation, &pbi, sizeof (pbi), nullptr );
36+ if (!NT_SUCCESS (status))
37+ return pRtlNtStatusToDosError (status);
38+
39+ *ppeb = pbi.PebBaseAddress ;
40+
41+ return ERROR_SUCCESS;
42+ }
43+
44+ template <typename Proc>
45+ static DWORD EnumerateRemoteModulesNative (HANDLE process, Proc proc)
46+ {
47+ PPEB ppeb;
48+ const auto error = GetRemotePeb (process, &ppeb);
49+ if (error != ERROR_SUCCESS)
50+ return error;
51+
52+ PPEB_LDR_DATA ldr;
53+ auto success = ReadRemoteMemory (process, &ppeb->Ldr , &ldr, 0 , sizeof (ldr));
54+ if (!success)
55+ return ERROR_READ_FAULT; // we seem to swallow the error anyways, might aswell give a distinctive one back
56+
57+ const auto list_head = &ldr->InMemoryOrderModuleList ; // remote address
58+ PLIST_ENTRY list_current; // remote address
59+ success = ReadRemoteMemory (process, &list_head->Flink , &list_current, 0 , sizeof (list_current));
60+ if (!success)
61+ return ERROR_READ_FAULT;
62+
63+ while (list_current != list_head)
64+ {
65+ // TODO: error handling - what do we do if module list changed? We can't un-call the callback
66+
67+ LDR_DATA_TABLE_ENTRY mod;
68+ success = ReadRemoteMemory (process, CONTAINING_RECORD (list_current, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks), &mod, 0 , sizeof (mod));
69+ if (!success)
70+ return ERROR_SUCCESS; // return success here to prevent running the other one
71+
72+ EnumerateRemoteModuleData data = {};
73+ data.BaseAddress = mod.DllBase ;
74+ data.Size = *(ULONG*)&mod.Reserved2 [1 ]; // instead of undocced member could read ImageSize from headers
75+ const auto path_len = std::min (sizeof (RC_UnicodeChar) * (PATH_MAXIMUM_LENGTH - 1 ), size_t (mod.FullDllName .Length ));
76+ success = ReadRemoteMemory (process, mod.FullDllName .Buffer , data.Path , 0 , int (path_len));
77+ if (!success)
78+ return ERROR_SUCCESS; // return success here to prevent running the other one
79+
80+ // UNICODE_STRING is not guaranteed to be null terminated
81+ data.Path [path_len / 2 ] = 0 ;
82+
83+ proc (&data);
84+
85+ list_current = mod.InMemoryOrderLinks .Flink ;
86+ }
87+
88+ return ERROR_SUCCESS;
89+ }
90+
91+ template <typename Proc>
92+ static DWORD EnumerateRemoteModulesWinapi (HANDLE process, Proc proc)
93+ {
94+ const auto handle = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, GetProcessId (process));
95+ if (handle == INVALID_HANDLE_VALUE)
96+ return GetLastError ();
97+
98+ MODULEENTRY32W me32 = {};
99+ me32.dwSize = sizeof (MODULEENTRY32W);
100+ if (Module32FirstW (handle, &me32))
101+ {
102+ do
103+ {
104+ EnumerateRemoteModuleData data = {};
105+ data.BaseAddress = me32.modBaseAddr ;
106+ data.Size = me32.modBaseSize ;
107+ std::memcpy (data.Path , me32.szExePath , std::min (MAX_PATH, PATH_MAXIMUM_LENGTH));
108+
109+ proc (&data);
110+ } while (Module32NextW (handle, &me32));
111+ }
112+
113+ CloseHandle (handle);
114+
115+ return ERROR_SUCCESS;
116+ }
117+
8118void RC_CallConv EnumerateRemoteSectionsAndModules (RC_Pointer process, EnumerateRemoteSectionsCallback callbackSection, EnumerateRemoteModulesCallback callbackModule)
9119{
10120 if (callbackSection == nullptr && callbackModule == nullptr )
@@ -55,48 +165,34 @@ void RC_CallConv EnumerateRemoteSectionsAndModules(RC_Pointer process, Enumerate
55165 address = reinterpret_cast <size_t >(memInfo.BaseAddress ) + memInfo.RegionSize ;
56166 }
57167
58- const auto handle = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, GetProcessId (process));
59- if (handle != INVALID_HANDLE_VALUE)
168+ const auto moduleEnumerator = [&](EnumerateRemoteModuleData* data)
60169 {
61- MODULEENTRY32W me32 = {};
62- me32.dwSize = sizeof (MODULEENTRY32W);
63- if (Module32FirstW (handle, &me32))
170+ if (callbackModule != nullptr )
171+ callbackModule (data);
172+
173+ if (callbackSection != nullptr )
64174 {
65- do
66- {
67- if (callbackModule != nullptr )
175+ auto it = std::lower_bound (std::begin (sections), std::end (sections), static_cast <LPVOID>(data->BaseAddress ), [§ions](const auto & lhs, const LPVOID& rhs)
68176 {
69- EnumerateRemoteModuleData data = {};
70- data.BaseAddress = me32.modBaseAddr ;
71- data.Size = me32.modBaseSize ;
72- std::memcpy (data.Path , me32.szExePath , std::min (MAX_PATH, PATH_MAXIMUM_LENGTH));
177+ return lhs.BaseAddress < rhs;
178+ });
73179
74- callbackModule (&data);
75- }
180+ IMAGE_DOS_HEADER DosHdr = {};
181+ IMAGE_NT_HEADERS NtHdr = {};
182+
183+ ReadRemoteMemory (process, data->BaseAddress , &DosHdr, 0 , sizeof (IMAGE_DOS_HEADER));
184+ ReadRemoteMemory (process, PUCHAR (data->BaseAddress ) + DosHdr.e_lfanew , &NtHdr, 0 , sizeof (IMAGE_NT_HEADERS));
185+
186+ std::vector<IMAGE_SECTION_HEADER> sectionHeaders (NtHdr.FileHeader .NumberOfSections );
187+ ReadRemoteMemory (process, PUCHAR (data->BaseAddress ) + DosHdr.e_lfanew + sizeof (IMAGE_NT_HEADERS), sectionHeaders.data (), 0 , NtHdr.FileHeader .NumberOfSections * sizeof (IMAGE_SECTION_HEADER));
188+ for (auto i = 0 ; i < NtHdr.FileHeader .NumberOfSections ; ++i)
189+ {
190+ auto && sectionHeader = sectionHeaders[i];
76191
77- if (callbackSection != nullptr )
192+ const auto sectionAddress = reinterpret_cast <size_t >(data->BaseAddress ) + sectionHeader.VirtualAddress ;
193+ for (auto j = it; j != std::end (sections); ++j)
78194 {
79- auto it = std::lower_bound (std::begin (sections), std::end (sections), static_cast <LPVOID>(me32.modBaseAddr ), [§ions](const auto & lhs, const LPVOID& rhs)
80- {
81- return lhs.BaseAddress < rhs;
82- });
83-
84- IMAGE_DOS_HEADER DosHdr = {};
85- IMAGE_NT_HEADERS NtHdr = {};
86-
87- ReadRemoteMemory (process, me32.modBaseAddr , &DosHdr, 0 , sizeof (IMAGE_DOS_HEADER));
88- ReadRemoteMemory (process, me32.modBaseAddr + DosHdr.e_lfanew , &NtHdr, 0 , sizeof (IMAGE_NT_HEADERS));
89-
90- std::vector<IMAGE_SECTION_HEADER> sectionHeaders (NtHdr.FileHeader .NumberOfSections );
91- ReadRemoteMemory (process, me32.modBaseAddr + DosHdr.e_lfanew + sizeof (IMAGE_NT_HEADERS), sectionHeaders.data (), 0 , NtHdr.FileHeader .NumberOfSections * sizeof (IMAGE_SECTION_HEADER));
92- for (auto i = 0 ; i < NtHdr.FileHeader .NumberOfSections ; ++i)
93- {
94- auto && sectionHeader = sectionHeaders[i];
95-
96- const auto sectionAddress = reinterpret_cast <size_t >(me32.modBaseAddr ) + sectionHeader.VirtualAddress ;
97- for (auto j = it; j != std::end (sections); ++j)
98- {
99- if (sectionAddress >= reinterpret_cast <size_t >(j->BaseAddress )
195+ if (sectionAddress >= reinterpret_cast <size_t >(j->BaseAddress )
100196 && sectionAddress < reinterpret_cast <size_t >(j->BaseAddress ) + static_cast <size_t >(j->Size )
101197 && sectionHeader.VirtualAddress + sectionHeader.Misc .VirtualSize <= me32.modBaseSize )
102198 {
@@ -121,21 +217,20 @@ void RC_CallConv EnumerateRemoteSectionsAndModules(RC_Pointer process, Enumerate
121217
122218 break ;
123219 }
124- }
125-
126- }
127220 }
128- } while (Module32NextW (handle, &me32));
129- }
130221
131- CloseHandle (handle);
222+ }
223+ }
224+ };
225+
226+ if (EnumerateRemoteModulesNative (process, moduleEnumerator) != ERROR_SUCCESS)
227+ EnumerateRemoteModulesWinapi (process, moduleEnumerator);
132228
133- if (callbackSection != nullptr )
229+ if (callbackSection != nullptr )
230+ {
231+ for (auto && section : sections)
134232 {
135- for (auto && section : sections)
136- {
137- callbackSection (§ion);
138- }
233+ callbackSection (§ion);
139234 }
140235 }
141236}
0 commit comments