Skip to content

Commit 9da1cba

Browse files
authored
Merge pull request #135 from namazso/master
Almost only-RPM module enumeration (closes #131)
2 parents b89bbfd + d7dfd3e commit 9da1cba

File tree

1 file changed

+142
-47
lines changed

1 file changed

+142
-47
lines changed

NativeCore/Windows/EnumerateRemoteSectionsAndModules.cpp

Lines changed: 142 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,120 @@
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+
8118
void 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), [&sections](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), [&sections](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(&section);
138-
}
233+
callbackSection(&section);
139234
}
140235
}
141236
}

0 commit comments

Comments
 (0)