From 82b119d253585b5f60baf5822c08f39da6a7cd0a Mon Sep 17 00:00:00 2001 From: Roee Toledano Date: Wed, 13 Nov 2024 17:26:39 +0200 Subject: [PATCH] Implement PE base relocations 1. Everything is based off of Microsoft's PE format documentation [found here](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format) 2. Up until now, imports were used for relocations in the PE & MDMP format, which is wrong. PE uses base relocations. 3. PE relocations do not have symbols associated with them, and thus have no name. In order to still have flags in relocs flagspace, dummy symbols were allocated with generic names composed of the relocation's virtual address space. * Remove old code of setting import entries to PE relocations * Parse PE base relocations * Implement converting from the specific RzBinPeRelocEnt type to the general RzBinReloc type * Implement corrent type naming of PE relocations * Add missing `PE_IMAGE_FILE_MACHINE` types * Add PE base relocation types * Fix PE format 'has_canary' function * Remove 'RzBinPEObj.endian' and use 'RzBinPEObj.big_endian' instead * Removed a.exe and b.exe tests, as they don't contain base relocations and swapped them with correct tests * Corrected old PE relocation tests * Add new PE base relocation tests --- librz/bin/format/pe/pe.c | 3 +- librz/bin/format/pe/pe.h | 30 +- librz/bin/format/pe/pe64_relocs.c | 5 + librz/bin/format/pe/pe_exports.c | 4 +- librz/bin/format/pe/pe_relocs.c | 72 ++ librz/bin/format/pe/pe_specs.h | 87 +- librz/bin/meson.build | 2 + librz/bin/p/bin_pe.inc | 191 ++-- test/db/abi/compilers/pelles_c | 4 +- test/db/abi/compilers/visual_studio | 8 +- test/db/analysis/x86_32 | 2 +- test/db/analysis/x86_64 | 2 +- test/db/cmd/cmd_pd | 8 +- test/db/formats/pe/imports_tinyW7 | 18 - test/db/formats/pe/pe | 1540 +++++++++++++++++++++++---- test/db/tools/rz_bin | 8 - 16 files changed, 1659 insertions(+), 325 deletions(-) create mode 100644 librz/bin/format/pe/pe64_relocs.c create mode 100644 librz/bin/format/pe/pe_relocs.c diff --git a/librz/bin/format/pe/pe.c b/librz/bin/format/pe/pe.c index 882f78b04df..9488ac4f8ff 100644 --- a/librz/bin/format/pe/pe.c +++ b/librz/bin/format/pe/pe.c @@ -68,6 +68,8 @@ static int bin_pe_init(RzBinPEObj *bin) { (bin); PE_(bin_pe_init_security) (bin); + PE_(bin_pe_init_relocs) + (bin); bin->big_endian = PE_(rz_bin_pe_is_big_endian)(bin); @@ -81,7 +83,6 @@ static int bin_pe_init(RzBinPEObj *bin) { (bin); PE_(bin_pe_parse_resource) (bin); - bin->relocs = NULL; return true; } diff --git a/librz/bin/format/pe/pe.h b/librz/bin/format/pe/pe.h index 247f0dc45e6..3e8830664e2 100644 --- a/librz/bin/format/pe/pe.h +++ b/librz/bin/format/pe/pe.h @@ -69,6 +69,22 @@ #define PE_SCN_ALIGN_MASK 0x00F00000 +// For the following relocation structs, +// See: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-reloc-section-image-only +typedef struct rz_bin_pe_reloc_block_t { + ut32 page_rva; ///< RVA of the block + ut32 block_size; ///< Size of the block +} RzBinPeRelocBlock; + +// encoding is 12 bits for type and 4 bits for offset. +#define PE_RELOC_ENT_TYPE(val) ((val) >> 12) +#define PE_RELOC_ENT_OFFSET(val) ((val)&0xfff) + +typedef struct rz_bin_pe_reloc_ent_t { + ut16 raw_val; ///< Type + Offset of the relocation entry + ut32 page_rva; ///< RVA of the block to which the relocation entry belongs +} RzBinPeRelocEnt; + struct rz_bin_pe_addr_t { ut64 vaddr; ut64 paddr; @@ -165,12 +181,11 @@ struct PE_(rz_bin_pe_obj_t) { int import_directory_size; ut64 size; int num_sections; - int endian; bool verbose; int big_endian; RzList /**/ *rich_entries; - RzPVector /**/ *relocs; RzList /**/ *resources; + RzVector /**/ *relocs; const char *file; RzBuffer *b; Sdb *kv; @@ -182,9 +197,10 @@ struct PE_(rz_bin_pe_obj_t) { RzHash *hash; }; -#define MAX_METADATA_STRING_LENGTH 256 -#define COFF_SYMBOL_SIZE 18 -#define PE_READ_STRUCT_FIELD(var, struct_type, field, size) var->field = rz_read_le##size(buf + offsetof(struct_type, field)) +#define MAX_METADATA_STRING_LENGTH 256 +#define COFF_SYMBOL_SIZE 18 +#define PE_READ_STRUCT_FIELD(var, struct_type, field, size) var->field = rz_read_le##size(buf + offsetof(struct_type, field)) +#define PE_READ_STRUCT_FIELD_L(buf, var, struct_type, field, size) var.field = rz_read_le##size(buf + offsetof(struct_type, field)) // pe_clr.c RZ_OWN RzList /**/ *PE_(rz_bin_pe_get_clr_symbols)(RzBinPEObj *bin); @@ -207,6 +223,10 @@ int PE_(read_image_import_directory)(RzBuffer *b, ut64 addr, PE_(image_import_di int PE_(read_image_delay_import_directory)(RzBuffer *b, ut64 addr, PE_(image_delay_import_directory) * directory); struct rz_bin_pe_import_t *PE_(rz_bin_pe_get_imports)(RzBinPEObj *bin); +// pe_relocs.c +int PE_(bin_pe_init_relocs)(RZ_NONNULL RzBinPEObj *bin); +bool PE_(bin_pe_has_base_relocs)(RZ_NONNULL RzBinPEObj *bin); + // pe_info.c char *PE_(rz_bin_pe_get_arch)(RzBinPEObj *bin); char *PE_(rz_bin_pe_get_cc)(RzBinPEObj *bin); diff --git a/librz/bin/format/pe/pe64_relocs.c b/librz/bin/format/pe/pe64_relocs.c new file mode 100644 index 00000000000..d55d438ec7a --- /dev/null +++ b/librz/bin/format/pe/pe64_relocs.c @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: 2024 Roee Toledano +// SPDX-License-Identifier: LGPL-3.0-only + +#define RZ_BIN_PE64 1 +#include "pe_relocs.c" diff --git a/librz/bin/format/pe/pe_exports.c b/librz/bin/format/pe/pe_exports.c index 2ea054155c6..af8b28aff97 100644 --- a/librz/bin/format/pe/pe_exports.c +++ b/librz/bin/format/pe/pe_exports.c @@ -234,13 +234,13 @@ struct rz_bin_pe_export_t *PE_(rz_bin_pe_get_exports)(RzBinPEObj *bin) { } for (i = 0; i < bin->export_directory->NumberOfFunctions; i++) { // get vaddr from AddressOfFunctions array - function_rva = rz_read_at_ble32((ut8 *)func_rvas, i * sizeof(PE_VWord), bin->endian); + function_rva = rz_read_at_ble32((ut8 *)func_rvas, i * sizeof(PE_VWord), bin->big_endian); // have exports by name? if (bin->export_directory->NumberOfNames > 0) { // search for value of i into AddressOfOrdinals name_vaddr = 0; for (n = 0; n < bin->export_directory->NumberOfNames; n++) { - PE_Word fo = rz_read_at_ble16((ut8 *)ordinals, n * sizeof(PE_Word), bin->endian); + PE_Word fo = rz_read_at_ble16((ut8 *)ordinals, n * sizeof(PE_Word), bin->big_endian); // if exist this index into AddressOfOrdinals if (i == fo) { function_ordinal = fo; diff --git a/librz/bin/format/pe/pe_relocs.c b/librz/bin/format/pe/pe_relocs.c new file mode 100644 index 00000000000..7112427b24b --- /dev/null +++ b/librz/bin/format/pe/pe_relocs.c @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2024 Roee Toledano +// SPDX-License-Identifier: LGPL-3.0-only + +#include "pe.h" + +bool PE_(bin_pe_has_base_relocs)(RZ_NONNULL RzBinPEObj *bin) { + rz_return_val_if_fail(bin, false); + + return bin->relocs && (rz_vector_len(bin->relocs) > 0); +} + +static bool read_reloc_ent_from_block(RZ_NONNULL RzVector /**/ *relocs, + RzBuffer *b, RzBinPeRelocBlock *block, ut64 *offset, const int big_endian) { + // block size includes the size of the next blocks entry, which is 8 bytes long + const ut32 reloc_block_end = *offset + block->block_size - 8; + do { + RzBinPeRelocEnt reloc = { 0 }; + if (!rz_buf_read_ble16_offset(b, offset, &reloc.raw_val, big_endian)) { + return false; + } + reloc.page_rva = block->page_rva; + + rz_vector_push(relocs, &reloc); + + } while (*offset < reloc_block_end); + + return true; +} + +static bool get_relocs_from_data_dir(RZ_NONNULL RzBinPEObj *bin, RZ_BORROW RZ_NONNULL RzVector /**/ *relocs) { + rz_return_val_if_fail(bin->b && bin->nt_headers && bin->optional_header, false); + RzBuffer *b = bin->b; + const st64 o_addr = rz_buf_tell(b); + + // get offset in file of first reloc block + ut64 offset = PE_(bin_pe_rva_to_paddr)(bin, bin->optional_header->DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); + const ut64 relocs_end_offset = offset + bin->optional_header->DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + + do { + RzBinPeRelocBlock block = { 0 }; + if (!rz_buf_read_ble32_offset(b, &offset, &block.page_rva, bin->big_endian) || + !rz_buf_read_ble32_offset(b, &offset, &block.block_size, bin->big_endian) || + !read_reloc_ent_from_block(relocs, b, &block, &offset, bin->big_endian)) { + return false; + } + + } while (offset < relocs_end_offset); + + rz_buf_seek(b, o_addr, RZ_BUF_SET); + + return true; +} + +int PE_(bin_pe_init_relocs)(RZ_NONNULL RzBinPEObj *bin) { + rz_return_val_if_fail(bin, false); + + RzVector *ret = rz_vector_new(sizeof(RzBinPeRelocEnt), NULL, NULL); + if (!ret) { + bin->relocs = NULL; + return false; + } + + if (PE_(rz_bin_pe_is_stripped_relocs)(bin) || !get_relocs_from_data_dir(bin, ret)) { + rz_vector_free(bin->relocs); + bin->relocs = NULL; + return false; + } + + bin->relocs = ret; + + return true; +} diff --git a/librz/bin/format/pe/pe_specs.h b/librz/bin/format/pe/pe_specs.h index 446e4399c48..e3939fdc9b6 100644 --- a/librz/bin/format/pe/pe_specs.h +++ b/librz/bin/format/pe/pe_specs.h @@ -61,42 +61,44 @@ typedef struct { #define PE_IMAGE_FILE_TYPE_PE32 0x10b #define PE_IMAGE_FILE_TYPE_PE32PLUS 0x20b -#define PE_IMAGE_FILE_MACHINE_UNKNOWN 0x0000 -#define PE_IMAGE_FILE_MACHINE_ALPHA 0x0184 -#define PE_IMAGE_FILE_MACHINE_ALPHA64 0x0284 -#define PE_IMAGE_FILE_MACHINE_AM33 0x01d3 -#define PE_IMAGE_FILE_MACHINE_AMD64 0x8664 -#define PE_IMAGE_FILE_MACHINE_ARM 0x01c0 -#define PE_IMAGE_FILE_MACHINE_ARMNT 0x01c4 -#define PE_IMAGE_FILE_MACHINE_ARM64 0xaa64 -#define PE_IMAGE_FILE_MACHINE_AXP64 PE_IMAGE_FILE_MACHINE_ALPHA64 -#define PE_IMAGE_FILE_MACHINE_CEE 0xc0ee -#define PE_IMAGE_FILE_MACHINE_CEF 0x0cef -#define PE_IMAGE_FILE_MACHINE_EBC 0x0ebc -#define PE_IMAGE_FILE_MACHINE_I386 0x014c -#define PE_IMAGE_FILE_MACHINE_IA64 0x0200 -#define PE_IMAGE_FILE_MACHINE_M32R 0x9041 -#define PE_IMAGE_FILE_MACHINE_M68K 0x0268 -#define PE_IMAGE_FILE_MACHINE_MIPS16 0x0266 -#define PE_IMAGE_FILE_MACHINE_MIPSFPU 0x0366 -#define PE_IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 -#define PE_IMAGE_FILE_MACHINE_POWERPC 0x01f0 -#define PE_IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 -#define PE_IMAGE_FILE_MACHINE_POWERPCBE 0x01f2 -#define PE_IMAGE_FILE_MACHINE_R10000 0x0168 -#define PE_IMAGE_FILE_MACHINE_R3000 0x0162 -#define PE_IMAGE_FILE_MACHINE_R4000 0x0166 -#define PE_IMAGE_FILE_MACHINE_SH3 0x01a2 -#define PE_IMAGE_FILE_MACHINE_SH3DSP 0x01a3 -#define PE_IMAGE_FILE_MACHINE_SH3E 0x01a4 -#define PE_IMAGE_FILE_MACHINE_SH4 0x01a6 -#define PE_IMAGE_FILE_MACHINE_SH5 0x01a8 -#define PE_IMAGE_FILE_MACHINE_THUMB 0x01c2 -#define PE_IMAGE_FILE_MACHINE_TRICORE 0x0520 -#define PE_IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 -#define PE_IMAGE_FILE_MACHINE_RISCV32 0x5032 -#define PE_IMAGE_FILE_MACHINE_RISCV64 0x5064 -#define PE_IMAGE_FILE_MACHINE_RISCV128 0x5128 +#define PE_IMAGE_FILE_MACHINE_UNKNOWN 0x0000 +#define PE_IMAGE_FILE_MACHINE_ALPHA 0x0184 +#define PE_IMAGE_FILE_MACHINE_ALPHA64 0x0284 +#define PE_IMAGE_FILE_MACHINE_AM33 0x01d3 +#define PE_IMAGE_FILE_MACHINE_AMD64 0x8664 +#define PE_IMAGE_FILE_MACHINE_ARM 0x01c0 +#define PE_IMAGE_FILE_MACHINE_ARMNT 0x01c4 +#define PE_IMAGE_FILE_MACHINE_ARM64 0xaa64 +#define PE_IMAGE_FILE_MACHINE_AXP64 PE_IMAGE_FILE_MACHINE_ALPHA64 +#define PE_IMAGE_FILE_MACHINE_CEE 0xc0ee +#define PE_IMAGE_FILE_MACHINE_CEF 0x0cef +#define PE_IMAGE_FILE_MACHINE_EBC 0x0ebc +#define PE_IMAGE_FILE_MACHINE_I386 0x014c +#define PE_IMAGE_FILE_MACHINE_IA64 0x0200 +#define PE_IMAGE_FILE_MACHINE_LOONGARCH32 0x6232 +#define PE_IMAGE_FILE_MACHINE_LOONGARCH64 0x6234 +#define PE_IMAGE_FILE_MACHINE_M32R 0x9041 +#define PE_IMAGE_FILE_MACHINE_M68K 0x0268 +#define PE_IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define PE_IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define PE_IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define PE_IMAGE_FILE_MACHINE_POWERPC 0x01f0 +#define PE_IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define PE_IMAGE_FILE_MACHINE_POWERPCBE 0x01f2 +#define PE_IMAGE_FILE_MACHINE_R10000 0x0168 +#define PE_IMAGE_FILE_MACHINE_R3000 0x0162 +#define PE_IMAGE_FILE_MACHINE_R4000 0x0166 +#define PE_IMAGE_FILE_MACHINE_SH3 0x01a2 +#define PE_IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define PE_IMAGE_FILE_MACHINE_SH3E 0x01a4 +#define PE_IMAGE_FILE_MACHINE_SH4 0x01a6 +#define PE_IMAGE_FILE_MACHINE_SH5 0x01a8 +#define PE_IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define PE_IMAGE_FILE_MACHINE_TRICORE 0x0520 +#define PE_IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define PE_IMAGE_FILE_MACHINE_RISCV32 0x5032 +#define PE_IMAGE_FILE_MACHINE_RISCV64 0x5064 +#define PE_IMAGE_FILE_MACHINE_RISCV128 0x5128 #define PE_IMAGE_FILE_RELOCS_STRIPPED 0x0001 #define PE_IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 @@ -530,6 +532,19 @@ typedef struct { #define PE_RESOURCE_ENTRY_HTML 23 #define PE_RESOURCE_ENTRY_MANIFEST 24 +// relocation types +#define PE_IMAGE_REL_BASED_ABSOLUTE 0 +#define PE_IMAGE_REL_BASED_HIGH 1 +#define PE_IMAGE_REL_BASED_LOW 2 +#define PE_IMAGE_REL_BASED_HIGHLOW 3 +#define PE_IMAGE_REL_BASED_HIGHADJ 4 +#define PE_IMAGE_REL_BASED_MIPS_JMPADDR_ARM_MOV32_RISCV_HIGH20 5 +// ... 6 is reserved +#define PE_IMAGE_REL_BASED_THUMB_MOV32_RISCV_LOW12I 7 +#define PE_IMAGE_REL_BASED_RISCV_LOW12S_LOONGARCH32_MARK_LA 8 +#define PE_IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define PE_IMAGE_REL_BASED_DIR64 10 + #define STRINGFILEINFO_TEXT "StringFileInfo" #define TRANSLATION_TEXT "Translation" #define VARFILEINFO_TEXT "VarFileInfo" diff --git a/librz/bin/meson.build b/librz/bin/meson.build index c911dfeec3a..a8ba822cae3 100644 --- a/librz/bin/meson.build +++ b/librz/bin/meson.build @@ -236,6 +236,8 @@ rz_bin_sources = [ 'format/pe/pe64_hdr.c', 'format/pe/pe_imports.c', 'format/pe/pe64_imports.c', + 'format/pe/pe_relocs.c', + 'format/pe/pe64_relocs.c', 'format/pe/pe_exports.c', 'format/pe/pe64_exports.c', 'format/pe/pe_rsrc.c', diff --git a/librz/bin/p/bin_pe.inc b/librz/bin/p/bin_pe.inc index e5259f15ea2..a9a28464ddd 100644 --- a/librz/bin/p/bin_pe.inc +++ b/librz/bin/p/bin_pe.inc @@ -422,9 +422,7 @@ static void filter_import(ut8 *n) { } static RzPVector /**/ *imports(RzBinFile *bf) { - RzPVector *relocs = NULL; RzBinImport *ptr = NULL; - RzBinReloc *rel = NULL; struct rz_bin_pe_import_t *imports = NULL; int i; @@ -436,17 +434,6 @@ static RzPVector /**/ *imports(RzBinFile *bf) { return NULL; } - // XXX: has_canary is causing problems! thus we need to check and clean here until it is fixed! - if (((struct PE_(rz_bin_pe_obj_t) *)bf->o->bin_obj)->relocs) { - rz_pvector_free(((struct PE_(rz_bin_pe_obj_t) *)bf->o->bin_obj)->relocs); - } - - if (!(relocs = rz_pvector_new(free))) { - rz_pvector_free(ret); - return NULL; - } - ((struct PE_(rz_bin_pe_obj_t) *)bf->o->bin_obj)->relocs = relocs; - if (!(imports = PE_(rz_bin_pe_get_imports)(bf->o->bin_obj))) { return ret; } @@ -464,37 +451,134 @@ static RzPVector /**/ *imports(RzBinFile *bf) { // index for the import. There is no point in exposing it. // ptr->hint = imports[i].hint; rz_pvector_push(ret, ptr); - - if (!(rel = RZ_NEW0(RzBinReloc))) { - break; - } -#ifdef RZ_BIN_PE64 - rel->type = RZ_BIN_RELOC_64; -#else - rel->type = RZ_BIN_RELOC_32; -#endif - rel->additive = 0; - rel->import = ptr; - rel->addend = 0; - { - ut8 addr[4]; - rz_buf_read_at(bf->buf, imports[i].paddr, addr, 4); - ut64 newaddr = (ut64)rz_read_le32(&addr); - rel->vaddr = newaddr; - } - rel->paddr = imports[i].paddr; - rz_pvector_push(relocs, rel); } free(imports); return ret; } +static const char *get_reloc_type_name(const ut8 reloc_type, const ut32 machine_type) { + switch (reloc_type) { + case PE_IMAGE_REL_BASED_ABSOLUTE: + return "IMAGE_REL_BASED_ABSOLUTE"; + case PE_IMAGE_REL_BASED_HIGH: + return "IMAGE_REL_BASED_HIGH"; + case PE_IMAGE_REL_BASED_LOW: + return "IMAGE_REL_BASED_LOW"; + case PE_IMAGE_REL_BASED_HIGHLOW: + return "IMAGE_REL_BASED_HIGHLOW"; + case PE_IMAGE_REL_BASED_HIGHADJ: + return "IMAGE_REL_BASED_HIGHADJ"; + case PE_IMAGE_REL_BASED_MIPS_JMPADDR_ARM_MOV32_RISCV_HIGH20: + switch (machine_type) { + case PE_IMAGE_FILE_MACHINE_MIPS16: + case PE_IMAGE_FILE_MACHINE_MIPSFPU: + case PE_IMAGE_FILE_MACHINE_MIPSFPU16: + case PE_IMAGE_FILE_MACHINE_R4000: + case PE_IMAGE_FILE_MACHINE_WCEMIPSV2: + return "IMAGE_REL_BASED_MIPS_JMPADDR"; + case PE_IMAGE_FILE_MACHINE_ARM: + case PE_IMAGE_FILE_MACHINE_ARM64: + case PE_IMAGE_FILE_MACHINE_ARMNT: + case PE_IMAGE_FILE_MACHINE_THUMB: + return "IMAGE_REL_BASED_ARM_MOV32"; + case PE_IMAGE_FILE_MACHINE_RISCV32: + case PE_IMAGE_FILE_MACHINE_RISCV64: + case PE_IMAGE_FILE_MACHINE_RISCV128: + return "IMAGE_REL_BASED_RISCV_HIGH20"; + default: + RZ_LOG_WARN("Unknown machine type for PE relocation type number: %d\n", reloc_type); + return "IMAGE_REL_BASED_UNKNOWN"; + } + + case PE_IMAGE_REL_BASED_THUMB_MOV32_RISCV_LOW12I: + switch (machine_type) { + case PE_IMAGE_FILE_MACHINE_THUMB: + return "IMAGE_REL_BASED_THUMB_MOV32"; + case PE_IMAGE_FILE_MACHINE_RISCV32: + case PE_IMAGE_FILE_MACHINE_RISCV64: + case PE_IMAGE_FILE_MACHINE_RISCV128: + return "IMAGE_REL_BASED_RISCV_LOW12I"; + default: + RZ_LOG_WARN("Unknown machine type for PE relocation type number: %d\n", reloc_type); + return "IMAGE_REL_BASED_UNKNOWN"; + } + case PE_IMAGE_REL_BASED_RISCV_LOW12S_LOONGARCH32_MARK_LA: + switch (machine_type) { + case PE_IMAGE_FILE_MACHINE_RISCV32: + case PE_IMAGE_FILE_MACHINE_RISCV64: + case PE_IMAGE_FILE_MACHINE_RISCV128: + return "IMAGE_REL_BASED_RISCV_LOW12S"; + case PE_IMAGE_FILE_MACHINE_LOONGARCH32: + case PE_IMAGE_FILE_MACHINE_LOONGARCH64: + return "IMAGE_REL_BASED_LOONGARCH32_MARK_LA"; + default: + RZ_LOG_WARN("Unknown machine type for PE relocation type number: %d\n", reloc_type); + return "IMAGE_REL_BASED_UNKNOWN"; + } + case PE_IMAGE_REL_BASED_MIPS_JMPADDR16: + switch (machine_type) { + case PE_IMAGE_FILE_MACHINE_MIPS16: + case PE_IMAGE_FILE_MACHINE_MIPSFPU: + case PE_IMAGE_FILE_MACHINE_MIPSFPU16: + case PE_IMAGE_FILE_MACHINE_R4000: + case PE_IMAGE_FILE_MACHINE_WCEMIPSV2: + return "IMAGE_REL_BASED_MIPS_JMPADDR16"; + default: + RZ_LOG_WARN("Unknown machine type for PE relocation type number: %d\n", reloc_type); + return "IMAGE_REL_BASED_UNKNOWN"; + } + case PE_IMAGE_REL_BASED_DIR64: + return "IMAGE_REL_BASED_DIR64"; + default: + RZ_LOG_WARN("Unknown PE relocation type number: %d\n", reloc_type); + return "IMAGE_REL_BASED_UNKNOWN"; + } +} + +// NOTE: No patching is needed because base relocations (as their name suggests) patch relocations based off the delta +// between the executable expected load address, and the actual load address. And since Rizin always loads +// the binaries at their preferred base address, the delta is always 0 and so no patching is needed. static RzPVector /**/ *relocs(RzBinFile *bf) { - struct PE_(rz_bin_pe_obj_t) *obj = bf->o->bin_obj; - if (obj) { - return obj->relocs; + rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, NULL); + RzBinPEObj *bin = bf->o->bin_obj; + + if (!bin->relocs) { + return NULL; } - return NULL; + + RzPVector *ret = NULL; + if (!(ret = rz_pvector_new((RzPVectorFree)rz_bin_reloc_free))) { + return NULL; + } + + if (!PE_(bin_pe_has_base_relocs)(bin)) { + rz_pvector_free(ret); + return NULL; + } + + RzBinPeRelocEnt *pe_reloc; + rz_vector_foreach (bin->relocs, pe_reloc) { + RzBinReloc *general_reloc = RZ_NEW0(RzBinReloc); + if (!general_reloc) { + RZ_LOG_ERROR("Failed to allocate PE RzBinReloc\n"); + return ret; + } + + general_reloc->vaddr = PE_RELOC_ENT_OFFSET(pe_reloc->raw_val) + pe_reloc->page_rva; + general_reloc->paddr = PE_(bin_pe_rva_to_paddr(bin, general_reloc->vaddr)); + general_reloc->type = PE_RELOC_ENT_TYPE(pe_reloc->raw_val); + general_reloc->print_name = get_reloc_type_name(PE_RELOC_ENT_TYPE(pe_reloc->raw_val), bin->nt_headers->file_header.Machine); + + // Allocating symbol just so we can have a name for the reloc + general_reloc->symbol = RZ_NEW0(RzBinSymbol); + general_reloc->symbol->name = rz_str_newf("pe_%08" PFMT64x, general_reloc->vaddr); + + rz_pvector_push(ret, general_reloc); + } + + rz_vector_free(bin->relocs); + + return ret; } static RzPVector /**/ *libs(RzBinFile *bf) { @@ -554,30 +638,17 @@ err: } static int has_canary(RzBinFile *bf) { - // XXX: We only need imports here but this causes leaks, we need to wait for the below. This is a horrible solution! - // TODO: use O(1) when imports sdbized - struct PE_(rz_bin_pe_obj_t) *bin = bf->o->bin_obj; void **it; - if (bin) { - const RzPVector *relocs_vec = bin->relocs; - RzBinReloc *rel; - if (relocs_vec) { - rz_pvector_foreach (relocs_vec, it) { - rel = *it; - if (!strcmp(rel->import->name, "__security_init_cookie")) { - return true; - } - } - } - } else { // rz_bin needs this as it will not initialise bin - const RzPVector *imports_vec = imports(bf); - RzBinImport *imp; - if (imports_vec) { - rz_pvector_foreach (imports_vec, it) { - imp = *it; - if (!strcmp(imp->name, "__security_init_cookie")) { - return true; - } + const RzPVector *imports_vec = imports(bf); + RzBinImport *imp; + if (imports_vec) { + rz_pvector_foreach (imports_vec, it) { + imp = *it; + // __security_init_cookie is a function imported from msvcrt.dll (libc) that when called + // initiliazes the stack canary. So if the function is imported, we can + // assume the binary uses stack canary. + if (!strcmp(imp->name, "__security_init_cookie")) { + return true; } } } diff --git a/test/db/abi/compilers/pelles_c b/test/db/abi/compilers/pelles_c index 11da8cb8529..1298a0df276 100644 --- a/test/db/abi/compilers/pelles_c +++ b/test/db/abi/compilers/pelles_c @@ -24,7 +24,7 @@ EXPECT=<