9#define RELOC_32BIT_FIELD 3
10#define RELOC_64BIT_FIELD 0xA
23 ULONGLONG* relocateAddr = (ULONGLONG*)((ULONG_PTR)relocField);
24 ULONGLONG rva = (*relocateAddr) -
oldBase;
25 (*relocateAddr) = rva +
newBase;
28 DWORD* relocateAddr = (DWORD*)((ULONG_PTR)relocField);
29 ULONGLONG rva = ULONGLONG(*relocateAddr) -
oldBase;
30 (*relocateAddr) =
static_cast<DWORD
>(rva +
newBase);
42 if (entriesNum == 0) {
46 for (SIZE_T i = 0; i < entriesNum; i++) {
50 DWORD type = entry->
Type;
61 bool validate_reloc_field(PVOID modulePtr, SIZE_T moduleSize,
bool is64bit,
const DWORD reloc_field)
63 const size_t field_width =
is64bit ?
sizeof(ULONGLONG) :
sizeof(DWORD);
64 const ULONG_PTR reloc_ptr = (ULONG_PTR)modulePtr + reloc_field;
71 if (entriesNum == 0) {
76 for (i = 0; i < entriesNum; i++) {
80 DWORD offset = entry->
Offset;
81 DWORD type = entry->
Type;
88 LOG_ERROR(
"Not supported relocation format at %d: %d.", (
int)i, (
int)type);
92 const DWORD reloc_field = page + offset;
93 if (!validate_reloc_field(modulePtr, moduleSize,
is64bit, reloc_field)) {
95 LOG_ERROR(
"Malformed reloc field: 0x%lx.", reloc_field);
102 LOG_ERROR(
"Failed processing reloc field at: 0x%lx.", reloc_field);
114 if (relocDir == NULL) {
118 if (!
validate_ptr(modulePtr, moduleSize, relocDir,
sizeof(IMAGE_DATA_DIRECTORY))) {
122 const DWORD maxSize = relocDir->Size;
123 const DWORD relocAddr = relocDir->VirtualAddress;
124 const bool is64b =
is64bit((BYTE*)modulePtr);
126 IMAGE_BASE_RELOCATION* reloc = NULL;
128 DWORD parsedSize = 0;
129 while (parsedSize < maxSize) {
130 const ULONGLONG curr_reloc_addr = relocAddr + parsedSize;
131 reloc = (IMAGE_BASE_RELOCATION*)(curr_reloc_addr + (ULONG_PTR)modulePtr);
132 if (!
validate_ptr(modulePtr, moduleSize, reloc,
sizeof(IMAGE_BASE_RELOCATION))) {
133 LOG_WARNING(
"Invalid address of relocations, RVA: 0x%llx when moduleSize is: 0x%llx", curr_reloc_addr, (ULONGLONG)moduleSize);
136 if (reloc->SizeOfBlock < (2 *
sizeof(DWORD))) {
137 LOG_WARNING(
"Malformed relocation block: SizeOfBlock too small.");
140 const size_t entriesNum = (reloc->SizeOfBlock - 2 *
sizeof(DWORD)) /
sizeof(WORD);
141 const DWORD page = reloc->VirtualAddress;
145 LOG_WARNING(
"Invalid address of relocations block.");
149 if (!
process_reloc_block(block, entriesNum, page, modulePtr, moduleSize, is64b, callback)) {
155 const DWORD _newParsedSize = parsedSize + reloc->SizeOfBlock;
156 if (_newParsedSize < parsedSize) {
157 LOG_ERROR(
"Invalid SizeOfBlock: DWORD overflow.");
160 parsedSize = _newParsedSize;
167 const bool is64b =
is64bit((BYTE*)modulePtr);
174 if (!modulePtr || !moduleSize) {
180 LOG_DEBUG(
"New Base: 0x%llx Old Base: 0x%llx.", (
unsigned long long)newBase, (
unsigned long long)oldBase);
181 if (newBase == oldBase) {
182 LOG_DEBUG(
"Nothing to relocate: oldBase equals newBase.");
188 LOG_ERROR(
"Could not relocate the module.");
198 bool virtual_addr_to_rva_no_relocs(IN
const BYTE* modulePtr, IN
const size_t module_size, IN ULONGLONG callback_addr, OUT DWORD& callback_rva)
200 const ULONGLONG img_base = (ULONGLONG)modulePtr;
202 if (callback_addr >= img_base && callback_addr < (img_base + module_size)) {
206 if (callback_addr < (ULONGLONG)module_size) {
215bool peconv::virtual_addr_to_rva(IN
const PBYTE modulePtr, IN
const size_t module_size, IN ULONGLONG callback_addr, OUT DWORD& callback_rva, IN std::unordered_set<ULONGLONG>* _relocs)
217 if (!module_size || !callback_addr)
return false;
219 const ULONGLONG img_base = (ULONGLONG)modulePtr;
221 std::unordered_set<ULONGLONG> local_relocs;
222 std::unordered_set<ULONGLONG>& reloc_values = _relocs ? (*_relocs) : local_relocs;
230 if (reloc_values.empty()) {
231 return virtual_addr_to_rva_no_relocs(modulePtr, module_size, callback_addr, callback_rva);
234 auto _convert_va_to_rva = [&](ULONGLONG& addr, DWORD &rva) ->
bool
236 if (reloc_values.find(addr) != reloc_values.end()) {
238 if (addr < img_base) {
239 LOG_ERROR(
"Invalid VA: 0x%llx cannot convert safely", addr);
242 rva =
static_cast<DWORD
>(addr - img_base);
246 if (addr > module_size) {
249 rva =
static_cast<DWORD
>(addr);
253 return _convert_va_to_rva(callback_addr, callback_rva);
#define MASK_TO_DWORD(val)
virtual bool processRelocField(ULONG_PTR relocField)
ApplyRelocCallback(bool _is64bit, ULONGLONG _oldBase, ULONGLONG _newBase)
virtual bool processRelocField(ULONG_PTR relocField)=0
Compile-time configurable logging macros for peconv.
#define LOG_DEBUG(fmt,...)
#define LOG_ERROR(fmt,...)
#define LOG_WARNING(fmt,...)
bool has_relocations(IN const BYTE *pe_buffer)
ULONGLONG get_image_base(IN const BYTE *pe_buffer)
bool virtual_addr_to_rva(IN const PBYTE imgBase, IN const size_t imgSize, IN ULONGLONG virtualAddr, OUT DWORD &outRVA, IN std::unordered_set< ULONGLONG > *relocs=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 process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback)
bool is64bit(IN const BYTE *pe_buffer)
IMAGE_DATA_DIRECTORY * get_directory_entry(IN const BYTE *pe_buffer, IN DWORD dir_id, IN bool allow_empty=false)
bool relocate_module(IN PBYTE modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase=0)
bool has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize)
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)
#define RELOC_64BIT_FIELD
bool apply_relocations(PVOID modulePtr, SIZE_T moduleSize, ULONGLONG newBase, ULONGLONG oldBase)
bool is_empty_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize)
#define RELOC_32BIT_FIELD
Operating on PE file's relocations table.