libPeConv
A library to load, manipulate, dump PE files.
pe_virtual_to_raw.cpp
Go to the documentation of this file.
2
3#include "peconv/util.h"
5#include "peconv/relocate.h"
6
7#include <iostream>
8
9using namespace peconv;
10
11bool sections_virtual_to_raw(BYTE* payload, SIZE_T payload_size, OUT BYTE* destAddress, OUT SIZE_T *raw_size_ptr)
12{
13 if (!payload || !destAddress) return false;
14
15 BYTE* payload_nt_hdr = get_nt_hdrs(payload, payload_size);
16 if (payload_nt_hdr == NULL) {
17 std::cerr << "Invalid payload: " << std::hex << (ULONGLONG) payload << std::endl;
18 return false;
19 }
20
21 const bool is64b = is64bit(payload);
22
23 IMAGE_FILE_HEADER *fileHdr = NULL;
24 DWORD hdrsSize = 0;
25 LPVOID secptr = NULL;
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 = (LPVOID)((ULONGLONG)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
31 } else {
32 IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*) payload_nt_hdr;
33 fileHdr = &(payload_nt_hdr32->FileHeader);
34 hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
35 secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
36 }
37
38 //copy all the sections, one by one:
39#ifdef _DEBUG
40 std::cout << "Coping sections:" << std::endl;
41#endif
42 DWORD first_raw = 0;
43 SIZE_T raw_end = hdrsSize;
44 for (WORD i = 0; i < fileHdr->NumberOfSections; i++) {
45 PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i));
46 if (!validate_ptr(payload, payload_size, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) {
47 return false;
48 }
49
50 LPVOID section_mapped = (BYTE*) payload + next_sec->VirtualAddress;
51 LPVOID section_raw_ptr = destAddress + next_sec->PointerToRawData;
52 SIZE_T sec_size = next_sec->SizeOfRawData;
53
54 size_t new_end = sec_size + next_sec->PointerToRawData;
55 if (new_end > raw_end) raw_end = new_end;
56
57 if ((next_sec->VirtualAddress + sec_size) > payload_size) {
58 std::cerr << "[!] Virtual section size is out ouf bounds: " << std::hex << sec_size << std::endl;
59 sec_size = (payload_size > next_sec->VirtualAddress) ? SIZE_T(payload_size - next_sec->VirtualAddress) : 0;
60 std::cerr << "[!] Truncated to maximal size: " << std::hex << sec_size << ", buffer size: " << payload_size << std::endl;
61 }
62 if (next_sec->VirtualAddress > payload_size && sec_size != 0) {
63 std::cerr << "[-] VirtualAddress of section is out ouf bounds: " << std::hex << next_sec->VirtualAddress << std::endl;
64 return false;
65 }
66 if (next_sec->PointerToRawData + sec_size > payload_size) {
67 std::cerr << "[-] Raw section size is out ouf bounds: " << std::hex << sec_size << std::endl;
68 return false;
69 }
70#ifdef _DEBUG
71 std::cout << "[+] " << next_sec->Name << " to: " << std::hex << section_raw_ptr << std::endl;
72#endif
73 //validate source:
74 if (!peconv::validate_ptr(payload, payload_size, section_mapped, sec_size)) {
75 std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
76 continue;
77 }
78 //validate destination:
79 if (!peconv::validate_ptr(destAddress, payload_size, section_raw_ptr, sec_size)) {
80 std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
81 continue;
82 }
83 memcpy(section_raw_ptr, section_mapped, sec_size);
84 if (first_raw == 0 || (next_sec->PointerToRawData < first_raw)) {
85 first_raw = next_sec->PointerToRawData;
86 }
87 }
88 if (raw_end > payload_size) raw_end = payload_size;
89 if (raw_size_ptr != NULL) {
90 (*raw_size_ptr) = raw_end;
91 }
92
93 //copy payload's headers:
94 if (hdrsSize == 0) {
95 hdrsSize = first_raw;
96#ifdef _DEBUG
97 std::cout << "hdrsSize not filled, using calculated size: " << std::hex << hdrsSize << "\n";
98#endif
99 }
100 if (!validate_ptr(payload, payload_size, payload, hdrsSize)) {
101 return false;
102 }
103 memcpy(destAddress, payload, hdrsSize);
104 return true;
105}
106
108 IN BYTE* payload,
109 IN size_t in_size,
110 IN ULONGLONG loadBase,
111 OUT size_t &out_size,
112 IN OPTIONAL bool rebuffer
113)
114{
115 BYTE* out_buf = (BYTE*)alloc_pe_buffer(in_size, PAGE_READWRITE);
116 if (out_buf == NULL) return NULL; //could not allocate output buffer
117
118 BYTE* in_buf = payload;
119 if (rebuffer) {
120 in_buf = (BYTE*) alloc_pe_buffer(in_size, PAGE_READWRITE);
121 if (in_buf == NULL) {
122 free_pe_buffer(out_buf, in_size);
123 return NULL;
124 }
125 memcpy(in_buf, payload, in_size);
126 }
127
128 ULONGLONG oldBase = get_image_base(in_buf);
129 bool isOk = true;
130 // from the loadBase go back to the original base
131 if (!relocate_module(in_buf, in_size, oldBase, loadBase)) {
132 //Failed relocating the module! Changing image base instead...
133 if (!update_image_base(in_buf, (ULONGLONG)loadBase)) {
134 std::cerr << "[-] Failed relocating the module!" << std::endl;
135 isOk = false;
136 } else {
137#ifdef _DEBUG
138 std::cerr << "[!] WARNING: The module could not be relocated, so the ImageBase has been changed instead!" << std::endl;
139#endif
140 }
141 }
142 SIZE_T raw_size = 0;
143 if (isOk) {
144 if (!sections_virtual_to_raw(in_buf, in_size, out_buf, &raw_size)) {
145 isOk = false;
146 }
147 }
148 if (rebuffer && in_buf != NULL) {
149 free_pe_buffer(in_buf, in_size);
150 in_buf = NULL;
151 }
152 if (!isOk) {
153 free_pe_buffer(out_buf, in_size);
154 out_buf = NULL;
155 raw_size = 0;
156 }
157 out_size = raw_size;
158 return out_buf;
159}
160
162 IN const BYTE* payload,
163 IN size_t in_size,
164 IN ULONGLONG loadBase,
165 OUT size_t &out_size
166)
167{
168 out_size = in_size;
169 BYTE* out_buf = (BYTE*)alloc_pe_buffer(out_size, PAGE_READWRITE);
170 if (!out_buf) {
171 out_size = 0;
172 return nullptr;
173 }
174 memcpy(out_buf, payload, in_size);
175
176 ULONGLONG oldBase = get_image_base(out_buf);
177 bool isOk = true;
178 // from the loadBase go back to the original base
179 if (!relocate_module(out_buf, out_size, oldBase, loadBase)) {
180 //Failed relocating the module! Changing image base instead...
181 if (!update_image_base(out_buf, (ULONGLONG)loadBase)) {
182 std::cerr << "[-] Failed relocating the module!" << std::endl;
183 isOk = false;
184 } else {
185#ifdef _DEBUG
186 std::cerr << "[!] WARNING: The module could not be relocated, so the ImageBase has been changed instead!" << std::endl;
187#endif
188 }
189 }
190 //---
191 //set raw alignment the same as virtual
192 DWORD v_alignment = peconv::get_sec_alignment((const PBYTE)payload, false);
193 if (!peconv::set_sec_alignment(out_buf, true, v_alignment)) {
194 isOk = false;
195 }
196 //set Raw pointers and sizes of the sections same as Virtual
197 size_t sections_count = peconv::get_sections_count(out_buf, out_size);
198 for (size_t i = 0; i < sections_count; i++) {
199 PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(out_buf, out_size, i);
200 if (!sec) break;
201
202 sec->Misc.VirtualSize = peconv::get_virtual_sec_size(out_buf, sec, true);
203 sec->SizeOfRawData = sec->Misc.VirtualSize;
204 sec->PointerToRawData = sec->VirtualAddress;
205 }
207 if (!isOk) {
208 free_pe_buffer(out_buf);
209 out_buf = nullptr;
210 out_size = 0;
211 }
212 return out_buf;
213}
bool set_sec_alignment(IN OUT BYTE *pe_buffer, IN bool is_raw, IN DWORD new_alignment)
bool validate_ptr(IN const void *buffer_bgn, IN SIZE_T buffer_size, IN const void *field_bgn, IN SIZE_T field_size)
Definition: buffer_util.cpp:9
DWORD get_virtual_sec_size(IN const BYTE *pe_hdr, IN const PIMAGE_SECTION_HEADER sec_hdr, IN bool rounded)
bool update_image_base(IN OUT BYTE *payload, IN ULONGLONG destImageBase)
ULONGLONG get_image_base(IN const BYTE *pe_buffer)
PIMAGE_SECTION_HEADER get_section_hdr(IN const BYTE *pe_buffer, IN const size_t buffer_size, IN size_t section_num)
BYTE * pe_virtual_to_raw(IN BYTE *payload, IN size_t in_size, IN ULONGLONG loadBase, OUT size_t &outputSize, IN OPTIONAL bool rebuffer=true)
bool free_pe_buffer(ALIGNED_BUF buffer, size_t buffer_size=0)
Definition: buffer_util.cpp:84
ALIGNED_BUF alloc_pe_buffer(size_t buffer_size, DWORD protect, ULONGLONG desired_base=NULL)
Definition: buffer_util.cpp:78
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)
bool relocate_module(IN BYTE *modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase=0)
Definition: relocate.cpp:162
BYTE * pe_realign_raw_to_virtual(IN const BYTE *payload, IN size_t in_size, IN ULONGLONG loadBase, OUT size_t &outputSize)
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.
bool sections_virtual_to_raw(BYTE *payload, SIZE_T payload_size, OUT BYTE *destAddress, OUT SIZE_T *raw_size_ptr)
Converting PE from virtual to raw format.
Operating on PE file's relocations table.
Miscellaneous utility functions.