libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
pe_loader.cpp
Go to the documentation of this file.
1#include "peconv/pe_loader.h"
2
3#include "peconv/relocate.h"
8
9#include "peconv/logger.h"
10
11using namespace peconv;
12
13namespace {
14 BYTE* load_no_sec_pe(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable)
15 {
16 ULONG_PTR desired_base = 0;
17 size_t out_size = (r_size < PAGE_SIZE) ? PAGE_SIZE : r_size;
18 if (executable) {
19 desired_base = get_image_base(dllRawData);
20 out_size = peconv::get_image_size(dllRawData);
21 }
22 if (out_size < r_size) {
23 out_size = r_size;
24 }
25 const DWORD protect = (executable) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
26 BYTE* mappedPE = peconv::alloc_pe_buffer(out_size, protect, reinterpret_cast<void*>(desired_base));
27 if (!mappedPE) {
28 return nullptr;
29 }
30 ::memcpy(mappedPE, dllRawData, r_size);
31 v_size = out_size;
32 return mappedPE;
33 }
34};
35
36BYTE* peconv::load_pe_module(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable, bool relocate, ULONG_PTR desired_base)
37{
38 if (!peconv::get_nt_hdrs(dllRawData, r_size)) {
39 return nullptr;
40 }
41 if (peconv::get_sections_count(dllRawData, r_size) == 0) {
42 return load_no_sec_pe(dllRawData, r_size, v_size, executable);
43 }
44 // by default, allow to load the PE at the supplied base
45 // if relocating is required, but the PE has no relocation table...
46 if (relocate && !has_relocations(dllRawData)) {
47 // ...enforce loading the PE image at its default base (so that it will need no relocations)
48 desired_base = get_image_base(dllRawData);
49 }
50 // load a virtual image of the PE file at the desired_base address (random if desired_base is NULL):
51 BYTE *mappedDLL = pe_raw_to_virtual(dllRawData, r_size, v_size, executable, desired_base);
52 if (mappedDLL) {
53 //if the image was loaded at its default base, relocate_module will return always true (because relocating is already done)
54 if (relocate && !relocate_module(mappedDLL, v_size, (ULONGLONG)mappedDLL)) {
55 // relocating was required, but it failed - thus, the full PE image is useless
56 LOG_ERROR("Could not relocate the module.");
57 free_pe_buffer(mappedDLL, v_size);
58 mappedDLL = nullptr;
59 }
60 } else {
61 LOG_ERROR("Could not allocate memory at the desired base.");
62 }
63 return mappedDLL;
64}
65
66BYTE* peconv::load_pe_module(LPCTSTR filename, OUT size_t &v_size, bool executable, bool relocate, ULONG_PTR desired_base)
67{
68 size_t r_size = 0;
69 BYTE *dllRawData = load_file(filename, r_size);
70 if (!dllRawData) {
71 LOG_ERROR("Cannot load the file.");
72 return nullptr;
73 }
74 BYTE* mappedPE = load_pe_module(dllRawData, r_size, v_size, executable, relocate, desired_base);
75 free_file(dllRawData);
76 return mappedPE;
77}
78
79namespace
80{
81 bool validate_and_load_imports(BYTE* loaded_pe, const size_t v_size, t_function_resolver* import_resolver)
82 {
83 if (!has_valid_import_table(loaded_pe, v_size)) {
84 LOG_WARNING("PE does not have a valid Import Table.");
85 return true; // nothing to load, use as is
86 }
87 if (load_imports(loaded_pe, import_resolver)) {
88 return true;
89 }
90 LOG_ERROR("Loading imports failed.");
91 return false;
92 }
93};
94
95BYTE* peconv::load_pe_executable(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, t_function_resolver* import_resolver, ULONG_PTR desired_base)
96{
97 BYTE* loaded_pe = load_pe_module(dllRawData, r_size, v_size, true, true, desired_base);
98 if (!loaded_pe) {
99 LOG_ERROR("Loading failed.");
100 return nullptr;
101 }
102 LOG_DEBUG("Loaded at: %p.", loaded_pe);
103 if (!validate_and_load_imports(loaded_pe, v_size, import_resolver)) {
104 free_pe_buffer(loaded_pe, v_size);
105 return NULL;
106 }
107 return loaded_pe;
108}
109
110
111BYTE* peconv::load_pe_executable(LPCTSTR my_path, OUT size_t &v_size, t_function_resolver* import_resolver)
112{
113 BYTE* loaded_pe = load_pe_module(my_path, v_size, true, true);
114 if (!loaded_pe) {
115 LOG_ERROR("Loading failed.");
116 return NULL;
117 }
118 LOG_DEBUG("Loaded at: %p.", loaded_pe);
119 if (!validate_and_load_imports(loaded_pe, v_size, import_resolver)) {
120 free_pe_buffer(loaded_pe, v_size);
121 return NULL;
122 }
123 return loaded_pe;
124}
Definitions of the used buffer types. Functions for their allocation and deallocation.
Searching specific functions in PE's Exports Table.
Definitions of basic Imports Resolver classes. They can be used for filling imports when the PE is lo...
Parsing and filling the Import Table.
Compile-time configurable logging macros for peconv.
#define LOG_DEBUG(fmt,...)
Definition: logger.h:80
#define LOG_ERROR(fmt,...)
Definition: logger.h:60
#define LOG_WARNING(fmt,...)
Definition: logger.h:68
bool has_valid_import_table(const PBYTE modulePtr, size_t moduleSize, size_t max_count=0)
bool has_relocations(IN const BYTE *pe_buffer)
ULONGLONG get_image_base(IN const BYTE *pe_buffer)
ALIGNED_BUF alloc_pe_buffer(size_t buffer_size, DWORD protect, void *desired_base=nullptr)
Definition: buffer_util.cpp:78
peconv::UNALIGNED_BUF load_file(IN LPCTSTR filename, OUT size_t &r_size)
Definition: file_util.cpp:9
DWORD get_image_size(IN const BYTE *payload)
bool free_pe_buffer(ALIGNED_BUF buffer, size_t buffer_size=0)
Definition: buffer_util.cpp:84
BYTE * load_pe_module(BYTE *payload_raw, size_t r_size, OUT size_t &v_size, bool executable, bool relocate, ULONG_PTR desired_base=0)
Definition: pe_loader.cpp:36
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)
size_t get_sections_count(IN const BYTE *buffer, IN const size_t buffer_size)
void free_file(IN peconv::UNALIGNED_BUF buffer)
Definition: file_util.cpp:127
BYTE * get_nt_hdrs(IN const BYTE *pe_buffer, IN OPTIONAL size_t buffer_size=0, IN OPTIONAL const LONG max_pe_offset=MAX_HEADER_SIZE)
bool relocate_module(IN PBYTE modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase=0)
Definition: relocate.cpp:172
BYTE * load_pe_executable(BYTE *payload_raw, size_t r_size, OUT size_t &v_size, t_function_resolver *import_resolver=nullptr, ULONG_PTR desired_base=0)
Definition: pe_loader.cpp:95
bool load_imports(BYTE *modulePtr, t_function_resolver *func_resolver=nullptr)
#define PAGE_SIZE
Loading PE from a file with the help of the custom loader.
Operating on PE file's relocations table.