libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
pe_raw_to_virtual.cpp
Go to the documentation of this file.
2
3#include "peconv/util.h"
5
6#include "peconv/logger.h"
7
8using namespace peconv;
9
10// Map raw PE into virtual memory of local process:
11bool sections_raw_to_virtual(IN const BYTE* payload, IN SIZE_T payloadSize, OUT BYTE* destBuffer, IN SIZE_T destBufferSize)
12{
13 if (!payload || !destBuffer) return false;
14
15 BYTE* payload_nt_hdr = get_nt_hdrs(payload, payloadSize);
16 if (!payload_nt_hdr) {
17 LOG_ERROR("Invalid PE at 0x%llx.", (unsigned long long)payload);
18 return false;
19 }
20
21 const bool is64b = is64bit(payload);
22
23 IMAGE_FILE_HEADER *fileHdr = nullptr;
24 DWORD hdrsSize = 0;
25 void* secptr = nullptr;
26 if (is64b) {
27 IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
28 fileHdr = &(payload_nt_hdr64->FileHeader);
29 hdrsSize = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
30 secptr = (void*)((ULONG_PTR)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
31 }
32 else {
33 IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
34 fileHdr = &(payload_nt_hdr32->FileHeader);
35 hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
36 secptr = (void*)((ULONG_PTR)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
37 }
38 DWORD first_raw = 0;
39 //copy all the sections, one by one:
40 for (WORD i = 0; i < fileHdr->NumberOfSections; i++) {
41 PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONG_PTR)secptr + ((ULONG_PTR)IMAGE_SIZEOF_SECTION_HEADER * i));
42 if (!validate_ptr(static_cast<const void*>(payload), payloadSize, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) { // check if fits in the source size
43 return false;
44 }
45 const BYTE* next_sec_dest = destBuffer + (reinterpret_cast<const BYTE*>(next_sec) - payload);
46 if (!validate_ptr(static_cast<const void*>(destBuffer), destBufferSize, next_sec_dest, IMAGE_SIZEOF_SECTION_HEADER)) { // check if fits in the destination size
47 return false;
48 }
49 if (next_sec->PointerToRawData == 0 || next_sec->SizeOfRawData == 0) {
50 continue; //skipping empty
51 }
52 void* section_mapped = destBuffer + next_sec->VirtualAddress;
53 void* section_raw_ptr = (BYTE*)payload + next_sec->PointerToRawData;
54 size_t sec_size = next_sec->SizeOfRawData;
55
56 if ((next_sec->VirtualAddress + sec_size) > destBufferSize) {
57 sec_size = (destBufferSize > next_sec->VirtualAddress) ? SIZE_T(destBufferSize - next_sec->VirtualAddress) : 0;
58 LOG_WARNING("Section %u: virtual size exceeds buffer, truncating to 0x%zx (buffer: 0x%zx).", i, sec_size, destBufferSize);
59 }
60 if (next_sec->VirtualAddress >= destBufferSize && sec_size != 0) {
61 LOG_ERROR("Section %u: VirtualAddress 0x%lx is out of bounds.", i, next_sec->VirtualAddress);
62 return false;
63 }
64 if (next_sec->PointerToRawData + sec_size > destBufferSize) {
65 LOG_ERROR("Section %u: raw data exceeds buffer (size: 0x%zx).", i, sec_size);
66 return false;
67 }
68
69 // validate source:
70 if (!validate_ptr(static_cast<const void*>(payload), payloadSize, section_raw_ptr, sec_size)) {
71 if (next_sec->PointerToRawData > payloadSize) {
72 LOG_WARNING("Section %u: PointerToRawData out of bounds, skipping.", i);
73 continue;
74 }
75 // trim section
76 sec_size = payloadSize - (next_sec->PointerToRawData);
77 }
78 // validate destination:
79 if (!peconv::validate_ptr(destBuffer, destBufferSize, section_mapped, sec_size)) {
80 LOG_WARNING("Section %u: destination out of bounds, skipping.", i);
81 continue;
82 }
83 memcpy(section_mapped, section_raw_ptr, sec_size);
84 if (first_raw == 0 || (next_sec->PointerToRawData < first_raw)) {
85 first_raw = next_sec->PointerToRawData;
86 }
87 }
88
89 //copy payload's headers:
90 if (hdrsSize == 0) {
91 hdrsSize= first_raw;
92 LOG_INFO("SizeOfHeaders not set, using first section raw offset as fallback: 0x%lx.", hdrsSize);
93 }
94 if (!validate_ptr((const LPVOID)payload, destBufferSize, (const LPVOID)payload, hdrsSize)) {
95 return false;
96 }
97 memcpy(destBuffer, payload, hdrsSize);
98 return true;
99}
100
102 IN const BYTE* payload,
103 IN size_t in_size,
104 OUT size_t &out_size,
105 IN OPTIONAL bool executable,
106 IN OPTIONAL ULONG_PTR desired_base
107)
108{
109 //check payload:
110 BYTE* nt_hdr = get_nt_hdrs(payload);
111 if (!nt_hdr) {
112 LOG_ERROR("Invalid PE at 0x%llx.", (unsigned long long)(ULONG_PTR)payload);
113 return nullptr;
114 }
115 DWORD payloadImageSize = 0;
116
117 const bool is64 = is64bit(payload);
118 if (is64) {
119 IMAGE_NT_HEADERS64* payload_nt_hdr = (IMAGE_NT_HEADERS64*)nt_hdr;
120 payloadImageSize = payload_nt_hdr->OptionalHeader.SizeOfImage;
121 }
122 else {
123 IMAGE_NT_HEADERS32* payload_nt_hdr = (IMAGE_NT_HEADERS32*)nt_hdr;
124 payloadImageSize = payload_nt_hdr->OptionalHeader.SizeOfImage;
125 }
126 payloadImageSize = peconv::round_up_to_unit(payloadImageSize, (DWORD)PAGE_SIZE);
127
128 DWORD protect = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
129 //first we will prepare the payload image in the local memory, so that it will be easier to edit it, apply relocations etc.
130 //when it will be ready, we will copy it into the space reserved in the target process
131 BYTE* localCopyAddress = alloc_pe_buffer(payloadImageSize, protect, reinterpret_cast<void*>(desired_base));
132 if (!localCopyAddress) {
133 LOG_ERROR("Could not allocate memory in the current process.");
134 return nullptr;
135 }
136 LOG_DEBUG("Allocated local memory: %p size: %x", localCopyAddress, payloadImageSize);
137 if (!sections_raw_to_virtual(payload, in_size, localCopyAddress, payloadImageSize)) {
138 LOG_ERROR("Could not copy PE file into virtual buffer.");
139 peconv::free_pe_buffer(localCopyAddress);
140 return nullptr;
141 }
142 out_size = payloadImageSize;
143 return localCopyAddress;
144}
#define LOG_DEBUG(fmt,...)
Definition logger.h:56
#define LOG_INFO(fmt,...)
Definition logger.h:50
#define LOG_ERROR(fmt,...)
Definition logger.h:36
#define LOG_WARNING(fmt,...)
Definition logger.h:44
ALIGNED_BUF alloc_pe_buffer(size_t buffer_size, DWORD protect, void *desired_base=nullptr)
bool validate_ptr(IN const void *buffer_bgn, IN size_t buffer_size, IN const void *field_bgn, IN size_t field_size)
bool free_pe_buffer(ALIGNED_BUF buffer, size_t buffer_size=0)
INT_TYPE round_up_to_unit(const INT_TYPE size, const INT_TYPE unit)
bool is64bit(IN const BYTE *pe_buffer)
BYTE * pe_raw_to_virtual(IN const BYTE *rawPeBuffer, IN size_t rawPeSize, OUT size_t &outputSize, IN OPTIONAL bool executable=true, IN OPTIONAL ULONG_PTR desired_base=0)
BYTE * get_nt_hdrs(IN const BYTE *pe_buffer, IN OPTIONAL size_t buffer_size=0)
Wrappers over various fields in the PE header. Read, write, parse PE headers.
#define PAGE_SIZE
bool sections_raw_to_virtual(IN const BYTE *payload, IN SIZE_T payloadSize, OUT BYTE *destBuffer, IN SIZE_T destBufferSize)
Converting PE from raw to virtual format.
Miscellaneous utility functions.