libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
relocate.cpp
Go to the documentation of this file.
1#include "peconv/relocate.h"
2
4#include <stdio.h>
5#include <iostream>
6
7using namespace peconv;
8
9#define RELOC_32BIT_FIELD 3
10#define RELOC_64BIT_FIELD 0xA
11
13{
14public:
15 ApplyRelocCallback(bool _is64bit, ULONGLONG _oldBase, ULONGLONG _newBase)
16 : RelocBlockCallback(_is64bit), oldBase(_oldBase), newBase(_newBase)
17 {
18 }
19
20 virtual bool processRelocField(ULONG_PTR relocField)
21 {
22 if (is64bit) {
23 ULONGLONG* relocateAddr = (ULONGLONG*)((ULONG_PTR)relocField);
24 ULONGLONG rva = (*relocateAddr) - oldBase;
25 (*relocateAddr) = rva + newBase;
26 }
27 else {
28 DWORD* relocateAddr = (DWORD*)((ULONG_PTR)relocField);
29 ULONGLONG rva = ULONGLONG(*relocateAddr) - oldBase;
30 (*relocateAddr) = static_cast<DWORD>(rva + newBase);
31 }
32 return true;
33 }
34
35protected:
36 ULONGLONG oldBase;
37 ULONGLONG newBase;
38};
39
40bool is_empty_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize)
41{
42 if (entriesNum == 0) {
43 return true; // nothing to process
44 }
45 BASE_RELOCATION_ENTRY* entry = block;
46 for (SIZE_T i = 0; i < entriesNum; i++) {
47 if (!validate_ptr(modulePtr, moduleSize, entry, sizeof(BASE_RELOCATION_ENTRY))) {
48 return false;
49 }
50 DWORD type = entry->Type;
51 if (type != 0) {
52 //non empty block found
53 return false;
54 }
55 entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)entry + sizeof(WORD));
56 }
57 return true;
58}
59
60bool process_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize, bool is64bit, RelocBlockCallback *callback)
61{
62 if (entriesNum == 0) {
63 return true; // nothing to process
64 }
65 BASE_RELOCATION_ENTRY* entry = block;
66 SIZE_T i = 0;
67 for (i = 0; i < entriesNum; i++) {
68 if (!validate_ptr(modulePtr, moduleSize, entry, sizeof(BASE_RELOCATION_ENTRY))) {
69 break;
70 }
71 DWORD offset = entry->Offset;
72 DWORD type = entry->Type;
73 if (type == 0) {
74 break;
75 }
76 if (type != RELOC_32BIT_FIELD && type != RELOC_64BIT_FIELD) {
77 if (callback) { //print debug messages only if the callback function was set
78 printf("[-] Not supported relocations format at %d: %d\n", (int)i, (int)type);
79 }
80 return false;
81 }
82 DWORD reloc_field = page + offset;
83 if (reloc_field >= moduleSize) {
84 if (callback) { //print debug messages only if the callback function was set
85 printf("[-] Malformed field: %lx\n", reloc_field);
86 }
87 return false;
88 }
89 if (callback) {
90 bool isOk = callback->processRelocField(((ULONG_PTR)modulePtr + reloc_field));
91 if (!isOk) {
92 std::cout << "[-] Failed processing reloc field at: " << std::hex << reloc_field << "\n";
93 return false;
94 }
95 }
96 entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)entry + sizeof(WORD));
97 }
98 return (i != 0);
99}
100
101bool peconv::process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback)
102{
103 IMAGE_DATA_DIRECTORY* relocDir = peconv::get_directory_entry((const BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC);
104 if (relocDir == NULL) {
105#ifdef _DEBUG
106 std::cout << "[!] WARNING: no relocation table found!\n";
107#endif
108 return false;
109 }
110 if (!validate_ptr(modulePtr, moduleSize, relocDir, sizeof(IMAGE_DATA_DIRECTORY))) {
111 std::cerr << "[!] Invalid relocDir pointer\n";
112 return false;
113 }
114 DWORD maxSize = relocDir->Size;
115 DWORD relocAddr = relocDir->VirtualAddress;
116 bool is64b = is64bit((BYTE*)modulePtr);
117
118 IMAGE_BASE_RELOCATION* reloc = NULL;
119
120 DWORD parsedSize = 0;
121 while (parsedSize < maxSize) {
122 reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR)modulePtr);
123 if (!validate_ptr(modulePtr, moduleSize, reloc, sizeof(IMAGE_BASE_RELOCATION))) {
124#ifdef _DEBUG
125 std::cerr << "[-] Invalid address of relocations\n";
126#endif
127 return false;
128 }
129 if (reloc->SizeOfBlock == 0) {
130 break;
131 }
132 size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(DWORD)) / sizeof(WORD);
133 DWORD page = reloc->VirtualAddress;
134
135 BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)reloc + sizeof(DWORD) + sizeof(DWORD));
136 if (!validate_ptr(modulePtr, moduleSize, block, sizeof(BASE_RELOCATION_ENTRY))) {
137 std::cerr << "[-] Invalid address of relocations block\n";
138 return false;
139 }
140 if (!is_empty_reloc_block(block, entriesNum, page, modulePtr, moduleSize)) {
141 if (!process_reloc_block(block, entriesNum, page, modulePtr, moduleSize, is64b, callback)) {
142 // the block was malformed
143 return false;
144 }
145 }
146 parsedSize += reloc->SizeOfBlock;
147 }
148 return true;
149}
150
151bool apply_relocations(PVOID modulePtr, SIZE_T moduleSize, ULONGLONG newBase, ULONGLONG oldBase)
152{
153 const bool is64b = is64bit((BYTE*)modulePtr);
154 ApplyRelocCallback callback(is64b, oldBase, newBase);
155 return process_relocation_table(modulePtr, moduleSize, &callback);
156}
157
158bool peconv::relocate_module(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase)
159{
160 if (modulePtr == NULL) {
161 return false;
162 }
163 if (oldBase == 0) {
164 oldBase = get_image_base(modulePtr);
165 }
166#ifdef _DEBUG
167 printf("New Base: %llx\n", newBase);
168 printf("Old Base: %llx\n", oldBase);
169#endif
170 if (newBase == oldBase) {
171#ifdef _DEBUG
172 printf("Nothing to relocate! oldBase is the same as the newBase!\n");
173#endif
174 return true; //nothing to relocate
175 }
176 if (apply_relocations(modulePtr, moduleSize, newBase, oldBase)) {
177 return true;
178 }
179#ifdef _DEBUG
180 printf("Could not relocate the module!\n");
181#endif
182 return false;
183}
184
185bool peconv::has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize)
186{
187 return process_relocation_table(modulePtr, moduleSize, nullptr);
188}
189
virtual bool processRelocField(ULONG_PTR relocField)
Definition relocate.cpp:20
ApplyRelocCallback(bool _is64bit, ULONGLONG _oldBase, ULONGLONG _newBase)
Definition relocate.cpp:15
ULONGLONG oldBase
Definition relocate.cpp:36
ULONGLONG newBase
Definition relocate.cpp:37
virtual bool processRelocField(ULONG_PTR relocField)=0
ULONGLONG get_image_base(IN const BYTE *pe_buffer)
bool validate_ptr(IN const void *buffer_bgn, IN size_t buffer_size, IN const void *field_bgn, IN size_t field_size)
bool process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback)
Definition relocate.cpp:101
bool is64bit(IN const BYTE *pe_buffer)
bool relocate_module(IN BYTE *modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase=0)
Definition relocate.cpp:158
IMAGE_DATA_DIRECTORY * get_directory_entry(IN const BYTE *pe_buffer, IN DWORD dir_id, IN bool allow_empty=false)
bool has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize)
Definition relocate.cpp:185
Wrappers over various fields in the PE header. Read, write, parse PE headers.
bool process_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize, bool is64bit, RelocBlockCallback *callback)
Definition relocate.cpp:60
#define RELOC_64BIT_FIELD
Definition relocate.cpp:10
bool apply_relocations(PVOID modulePtr, SIZE_T moduleSize, ULONGLONG newBase, ULONGLONG oldBase)
Definition relocate.cpp:151
bool is_empty_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize)
Definition relocate.cpp:40
#define RELOC_32BIT_FIELD
Definition relocate.cpp:9
Operating on PE file's relocations table.