libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
remote_pe_reader.cpp
Go to the documentation of this file.
2
3#include <iostream>
4
5#include "peconv/util.h"
7
8using namespace peconv;
9
11{
13 SIZE_T out = VirtualQueryEx(processHandle, moduleBase, &page_info, sizeof(page_info));
14 if (out != sizeof(page_info)) {
15 return false;
16 }
17 return true;
18}
19
21{
22 if (page_info.Type == 0) {
23 return false; //invalid type, skip it
24 }
25 if ((BYTE*)page_info.BaseAddress > moduleBase) {
26 return 0; //should never happen
27 }
28 const size_t offset = (ULONG_PTR)moduleBase - (ULONG_PTR)page_info.BaseAddress;
29 const size_t area_size = page_info.RegionSize - offset;
30 return area_size;
31}
32
34{
37 return 0;
38 }
39 const size_t area_size = _fetch_region_size(page_info, moduleBase);
40 return area_size;
41}
42
44{
47 return 0;
48 }
49 if (page_info.Type == 0) {
50 return 0; //invalid type, skip it
51 }
52 return (ULONGLONG) page_info.AllocationBase;
53}
54
55namespace peconv {
62 {
63 if (!buffer || buffer_size == 0) {
64 return 0;
65 }
66 if ((buffer_size < minimal_size) || minimal_size == 0) {
67 return 0;
68 }
71
74 //cannot read even the minimal size, quit trying
75 return test_read_size;
76 }
78
79 SIZE_T read_size = 0;
81
83 {
84 read_size = 0;
87 }
88 else {
90 }
91 const size_t delta = (last_failed_size - last_success_size) / 2;
92 if (delta == 0) break;
94 }
96 read_size = 0;
97 memset(buffer, 0, buffer_size);
99 return read_size;
100 }
101 }
102 return 0;
103 }
104};
105
107{
108 if (!buffer || buffer_size == 0) {
109 return 0;
110 }
111 memset(buffer, 0, buffer_size);
112
113 SIZE_T read_size = 0;
115
116 while (buffer_size > 0)
117 {
119 break;
120 }
122 if (last_error != ERROR_SUCCESS) {
123 if (read_size == 0 && (last_error != ERROR_PARTIAL_COPY)) {
124 break; // break
125 }
126 }
129#ifdef _DEBUG
130 std::cout << "peconv::search_readable_size res: " << std::hex << read_size << std::endl;
131#endif
132 }
133 break;
134 }
135
136#ifdef _DEBUG
137 if (read_size == 0) {
138 std::cerr << "[WARNING] Cannot read memory. Last Error : " << last_error << std::endl;
139 }
140 else if (read_size < buffer_size) {
141 std::cerr << "[WARNING] Read size: " << std::hex << read_size
142 << " is smaller than the requested size: " << std::hex << buffer_size
143 << ". Last Error: " << last_error << std::endl;
144
145 }
146#endif
147 return static_cast<size_t>(read_size);
148}
149
151{
152 if (!buffer || buffer_size == 0) {
153 return 0;
154 }
157 return 0;
158 }
159 if ((page_info.State & MEM_COMMIT) == 0) {
160 return 0;
161 }
163 if (region_size == 0) {
164 return 0;
165 }
166
168
169 const bool is_accessible = (page_info.Protect & PAGE_NOACCESS) == 0;
171 DWORD oldProtect = 0;
172
173 // check the access right and eventually try to change it
174 if (force_access && !is_accessible) {
176#ifdef _DEBUG
177 if (!access_changed) {
179 if (err != ERROR_ACCESS_DENIED) {
180 std::cerr << "[!] " << std::hex << start_addr << " : " << region_size << " inaccessible area, changing page access failed: " << std::dec << err << "\n";
181 }
182 }
183#endif
184 }
185
186 size_t size_read = 0;
189 if ((size_read == 0) && (page_info.Protect & PAGE_GUARD)) {
190#ifdef _DEBUG
191 std::cout << "Warning: guarded page, trying to read again..." << std::endl;
192#endif
194 }
195 }
196 // if the access rights were changed, change it back:
197 if (access_changed) {
199 }
200 return size_read;
201}
202
204{
205 if (!buffer || !start_addr || buffer_size == 0) {
206 return 0;
207 }
208 memset(buffer, 0, buffer_size);
209
210 size_t real_read = 0; // how many bytes has been realy read (not counting the skipped areas)
211 size_t last_valid = 0; // the last chunk that was really read (don't count the last skipped ones)
212
213 size_t buf_index = 0;
214 for (buf_index = 0; buf_index < buffer_size; ) {
216
219 break;
220 }
222 if (region_size == 0) {
223 break;
224 }
225
226 // read the memory:
227 const size_t read_chunk = read_remote_region(
230 (BYTE*)((ULONG_PTR)buffer + buf_index),
234 );
235 if (read_chunk == 0) {
236 //skip the region that could not be read, and proceed to the next:
238 continue;
239 }
241 real_read += read_chunk; // total sum of the read content
242 last_valid = buf_index; // the last chunk that was really read
243 }
244 if (real_read == 0) {
245 return 0;
246 }
247 return last_valid;
248}
249
251{
252 if (buffer == nullptr) {
253 return false;
254 }
256 if (read_size == 0) {
257 return false;
258 }
260 if (nt_ptr == nullptr) {
261 return false;
262 }
263 const size_t nt_offset = nt_ptr - buffer;
264 const size_t nt_size = peconv::is64bit(buffer) ? sizeof(IMAGE_NT_HEADERS64) : sizeof(IMAGE_NT_HEADERS32);
265 const size_t min_size = nt_offset + nt_size;
266
267 if (read_size < min_size) {
268 std::cerr << "[-] [" << std::dec << get_process_id(processHandle)
269 << " ][" << std::hex << (ULONGLONG) start_addr
270 << "] Read size: " << std::hex << read_size
271 << " is smaller that the minimal size:" << get_hdrs_size(buffer)
272 << std::endl;
273 return false;
274 }
275 //reading succeeded and the header passed the checks:
276 return true;
277}
278
279namespace peconv {
280 inline size_t roundup_to_unit(size_t size, size_t unit)
281 {
282 if (unit == 0) {
283 return size;
284 }
285 size_t parts = size / unit;
286 if (size % unit) parts++;
287 return parts * unit;
288 }
289};
290
292{
294
296 return NULL;
297 }
299 if (section_hdr == NULL || section_hdr->Misc.VirtualSize == 0) {
300 return NULL;
301 }
302 size_t buffer_size = section_hdr->Misc.VirtualSize;
303 if (roundup) {
305 if (va == 0) va = PAGE_SIZE;
306 buffer_size = roundup_to_unit(section_hdr->Misc.VirtualSize, va);
307 }
309 if (module_code == NULL) {
310 return NULL;
311 }
313 if (read_size == 0) {
314 // this function is slower, so use it only if the normal read has failed:
316 }
317 if (read_size == 0) {
319 return NULL;
320 }
322 return module_code;
323}
324
325size_t peconv::read_remote_pe(const HANDLE processHandle, LPVOID start_addr, const size_t mod_size, OUT BYTE* buffer, const size_t bufferSize)
326{
327 if (buffer == nullptr) {
328 std::cerr << "[-] Invalid output buffer: NULL pointer" << std::endl;
329 return 0;
330 }
331 if (bufferSize < mod_size || bufferSize < MAX_HEADER_SIZE ) {
332 std::cerr << "[-] Invalid output buffer: too small size!" << std::endl;
333 return 0;
334 }
335 // read PE section by section
336 PBYTE hdr_buffer = buffer;
337 //try to read headers:
339 std::cerr << "[-] Failed to read the module header" << std::endl;
340 return 0;
341 }
343 std::cerr << "[-] Sections headers are invalid or atypically aligned" << std::endl;
344 return 0;
345 }
347#ifdef _DEBUG
348 std::cout << "Sections: " << sections_count << std::endl;
349#endif
350 size_t read_size = MAX_HEADER_SIZE;
351
352 for (size_t i = 0; i < sections_count; i++) {
354 if (!hdr) {
355 std::cerr << "[-] Failed to read the header of section: " << i << std::endl;
356 break;
357 }
358 const DWORD sec_va = hdr->VirtualAddress;
360 if (sec_va + sec_vsize > bufferSize) {
361 std::cerr << "[-] No more space in the buffer!" << std::endl;
362 break;
363 }
365#ifdef _DEBUG
366 std::cerr << "[-] [" << std::hex << start_addr << "] Failed to read the module section " << i <<" : at: " << std::hex << (ULONG_PTR)start_addr + sec_va << std::endl;
367#endif
368 }
369 // update the end of the read area:
370 size_t new_end = sec_va + sec_vsize;
372 }
373#ifdef _DEBUG
374 std::cout << "Total read size: " << read_size << std::endl;
375#endif
376 return read_size;
377}
378
387
390 IN const HANDLE processHandle,
394{
396#ifdef _DEBUG
397 std::cout << "Module Size: " << mod_size << std::endl;
398#endif
399 if (mod_size == 0) {
400 return false;
401 }
403 if (buffer == nullptr) {
404 std::cerr << "[-] Failed allocating buffer. Error: " << GetLastError() << std::endl;
405 return false;
406 }
407 //read the module that it mapped in the remote process:
409 if (read_size == 0) {
410 std::cerr << "[-] Failed reading module. Error: " << GetLastError() << std::endl;
412 buffer = nullptr;
413 return false;
414 }
415
417 buffer, mod_size,
418 reinterpret_cast<ULONGLONG>(start_addr),
419 dump_mode, exportsMap);
420
422 buffer = nullptr;
423 return is_dumped;
424}
425
bool parse_delayed_desc(BYTE *modulePtr, const size_t moduleSize, const ULONGLONG img_base, LPSTR lib_name, const T_FIELD ordinal_flag, IMAGE_DELAYLOAD_DESCRIPTOR *desc, peconv::t_function_resolver *func_resolver)
Functions and classes responsible for fixing Import Table. A definition of ImportedDllCoverage class.
DWORD get_process_id(HANDLE hProcess)
Definition util.cpp:76
peconv::UNALIGNED_BUF get_remote_pe_section(HANDLE processHandle, LPVOID moduleBase, const size_t sectionNum, OUT size_t &sectionSize, bool roundup, bool force_access=false)
DWORD get_virtual_sec_size(IN const BYTE *pe_hdr, IN const PIMAGE_SECTION_HEADER sec_hdr, IN bool rounded)
bool dump_remote_pe(IN LPCTSTR outputFilePath, IN const HANDLE processHandle, IN LPVOID moduleBase, IN OUT t_pe_dump_mode &dump_mode, IN OPTIONAL peconv::ExportsMapper *exportsMap=nullptr)
bool is_valid_sections_hdr_offset(IN const BYTE *buffer, IN const size_t buffer_size)
UNALIGNED_BUF alloc_unaligned(size_t buf_size)
size_t read_remote_region(HANDLE processHandle, LPVOID start_addr, OUT BYTE *buffer, const size_t buffer_size, const bool force_access, const SIZE_T minimal_size=0x100)
PIMAGE_SECTION_HEADER get_section_hdr(IN const BYTE *pe_buffer, IN const size_t buffer_size, IN size_t section_num)
size_t read_remote_memory(HANDLE processHandle, LPVOID start_addr, OUT BYTE *buffer, const size_t buffer_size, const SIZE_T minimal_size=0x100)
bool fetch_region_info(HANDLE processHandle, LPVOID start_addr, MEMORY_BASIC_INFORMATION &page_info)
DWORD get_image_size(IN const BYTE *payload)
t_pe_dump_mode
Definition pe_dumper.h:16
size_t read_remote_area(HANDLE processHandle, LPVOID start_addr, OUT BYTE *buffer, const size_t buffer_size, const bool force_access, const SIZE_T minimal_size=0x100)
bool free_pe_buffer(ALIGNED_BUF buffer, size_t buffer_size=0)
ALIGNED_BUF alloc_pe_buffer(size_t buffer_size, DWORD protect, ULONGLONG desired_base=NULL)
size_t roundup_to_unit(size_t size, size_t unit)
DWORD get_sec_alignment(IN const BYTE *modulePtr, IN bool is_raw)
bool is64bit(IN const BYTE *pe_buffer)
size_t get_sections_count(IN const BYTE *buffer, IN const size_t buffer_size)
SIZE_T _search_readable_size(HANDLE processHandle, LPVOID start_addr, OUT BYTE *buffer, const size_t buffer_size, const SIZE_T minimal_size)
const ULONGLONG MAX_HEADER_SIZE
bool read_remote_pe_header(HANDLE processHandle, LPVOID moduleBase, OUT BYTE *buffer, const size_t bufferSize, bool force_access=false)
bool dump_pe(IN LPCTSTR outputFilePath, IN OUT BYTE *buffer, IN size_t buffer_size, IN const ULONGLONG module_base, IN OUT t_pe_dump_mode &dump_mode, IN OPTIONAL const peconv::ExportsMapper *exportsMap=nullptr)
Definition pe_dumper.cpp:26
DWORD get_hdrs_size(IN const BYTE *pe_buffer)
PBYTE UNALIGNED_BUF
Definition buffer_util.h:41
BYTE * get_nt_hdrs(IN const BYTE *pe_buffer, IN OPTIONAL size_t buffer_size=0)
size_t read_remote_pe(const HANDLE processHandle, LPVOID moduleBase, const size_t moduleSize, OUT BYTE *buffer, const size_t bufferSize)
size_t fetch_region_size(HANDLE processHandle, LPVOID start_addr)
ULONGLONG fetch_alloc_base(HANDLE processHandle, LPVOID start_addr)
void free_unaligned(UNALIGNED_BUF section_buffer)
DWORD get_remote_image_size(IN const HANDLE processHandle, IN LPVOID start_addr)
#define PAGE_SIZE
size_t _fetch_region_size(MEMORY_BASIC_INFORMATION &page_info, LPVOID moduleBase)
Reading from a PE module that is loaded within a remote process.
Miscellaneous utility functions.