Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Implement PE & MDMP base relocations. DO NOT MERGE YET! #4711

Draft
wants to merge 13 commits into
base: dev
Choose a base branch
from
21 changes: 1 addition & 20 deletions librz/bin/format/mdmp/mdmp_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,22 +93,17 @@ RzPVector /*<RzBinImport *>*/ *PE_(rz_bin_mdmp_pe_get_imports)(struct PE_(rz_bin
ut64 offset;
struct rz_bin_pe_import_t *imports = NULL;
RzBinImport *ptr = NULL;
RzBinReloc *rel;
RzPVector *ret;
RzPVector *relocs;

imports = PE_(rz_bin_pe_get_imports)(pe_bin->bin);
ret = rz_pvector_new(NULL);
relocs = rz_pvector_new(free);

if (!imports || !ret || !relocs) {
if (!imports || !ret) {
free(imports);
free(ret);
free(relocs);
return NULL;
}

pe_bin->bin->relocs = relocs;
for (i = 0; !imports[i].last; i++) {
if (!(ptr = RZ_NEW0(RzBinImport))) {
break;
Expand All @@ -121,24 +116,10 @@ RzPVector /*<RzBinImport *>*/ *PE_(rz_bin_mdmp_pe_get_imports)(struct PE_(rz_bin
ptr->ordinal = imports[i].ordinal;
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
offset = imports[i].vaddr;
if (offset > pe_bin->vaddr) {
offset -= pe_bin->vaddr;
}
rel->additive = 0;
rel->import = ptr;
rel->addend = 0;
rel->vaddr = offset + pe_bin->vaddr;
rel->paddr = imports[i].paddr + pe_bin->paddr;
rz_pvector_push(relocs, rel);
}
free(imports);

Expand Down
3 changes: 2 additions & 1 deletion librz/bin/format/pe/pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -81,7 +83,6 @@ static int bin_pe_init(RzBinPEObj *bin) {
(bin);
PE_(bin_pe_parse_resource)
(bin);
bin->relocs = NULL;
return true;
}

Expand Down
30 changes: 25 additions & 5 deletions librz/bin/format/pe/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@

#define PE_SCN_ALIGN_MASK 0x00F00000

typedef struct rz_bin_pe_reloc_block_t {
ut32 page_rva;
ut32 block_size;
} RzBinPeRelocBlock;

// encoding is 12 bits for type and 4 bits for offset.
// See: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-reloc-section-image-only
#define PE_RELOC_ENT_TYPE(val) ((val) >> 12)
#define PE_RELOC_ENT_OFFSET(val) ((val)&0xfff)

typedef struct rz_bin_pe_reloc_ent_t {
wargio marked this conversation as resolved.
Show resolved Hide resolved
ut16 raw_val;
ut32 page_rva;
} RzBinPeRelocEnt;

struct rz_bin_pe_addr_t {
ut64 vaddr;
ut64 paddr;
Expand Down Expand Up @@ -165,14 +180,14 @@ struct PE_(rz_bin_pe_obj_t) {
int import_directory_size;
ut64 size;
int num_sections;
int endian;
bool verbose;
int big_endian;
RzList /*<Pe_image_rich_entry *>*/ *rich_entries;
RzPVector /*<RzBinReloc *>*/ *relocs;
RzList /*<rz_pe_resource *>*/ *resources;
RzVector /*<RzBinPeRelocEnt>*/ *relocs;
wargio marked this conversation as resolved.
Show resolved Hide resolved
const char *file;
RzBuffer *b;
RzBuffer *buf_patched; // overlay over the original file with relocs patched
Sdb *kv;
RzCMS *cms;
RzSpcIndirectDataContent *spcinfo;
Expand All @@ -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 /*<RzBinSymbol *>*/ *PE_(rz_bin_pe_get_clr_symbols)(RzBinPEObj *bin);
Expand All @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions librz/bin/format/pe/pe64_relocs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-FileCopyrightText: 2024 Roee Toledano <roeetoledano10@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only

#define RZ_BIN_PE64 1
XVilka marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

#include "pe_relocs.c"
4 changes: 2 additions & 2 deletions librz/bin/format/pe/pe_exports.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
67 changes: 67 additions & 0 deletions librz/bin/format/pe/pe_relocs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2024 Roee Toledano <roeetoledano10@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only

#include "pe.h"
XVilka marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave 1 empty line between SPDX headers and first #include


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 /*<RzBinPeRelocEnt>*/ *relocs, RzBuffer *b, RzBinPeRelocBlock *block, ut64 *offset, const int big_endian) {
const ut32 reloc_block_end = *offset + block->block_size - 8; // block size includes the size of the next blocks entry, which is 8 bytes long
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 /*<RzBinPeRelocEnt>*/ *relocs) {
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->nt_headers->optional_header.DataDirectory[PE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
const ut64 relocs_end_offset = offset + bin->nt_headers->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);
bin->relocs = ret;
if (!ret) {
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;
}

return true;
}
87 changes: 51 additions & 36 deletions librz/bin/format/pe/pe_specs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions librz/bin/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
28 changes: 0 additions & 28 deletions librz/bin/p/bin_mdmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,33 +376,6 @@ static RzPVector /*<RzBinMem *>*/ *mdmp_mem(RzBinFile *bf) {
return ret;
}

static RzPVector /*<RzBinReloc *>*/ *mdmp_relocs(RzBinFile *bf) {
MiniDmpObj *obj;
struct Pe32_rz_bin_mdmp_pe_bin *pe32_bin;
struct Pe64_rz_bin_mdmp_pe_bin *pe64_bin;
RzListIter *it;

RzPVector *ret = rz_pvector_new(free);
if (!ret) {
return NULL;
}

obj = (MiniDmpObj *)bf->o->bin_obj;

rz_list_foreach (obj->pe32_bins, it, pe32_bin) {
if (pe32_bin->bin && pe32_bin->bin->relocs) {
rz_pvector_join(ret, pe32_bin->bin->relocs);
}
}
rz_list_foreach (obj->pe64_bins, it, pe64_bin) {
if (pe64_bin->bin && pe64_bin->bin->relocs) {
rz_pvector_join(ret, pe64_bin->bin->relocs);
}
}

return ret;
}

static RzPVector /*<RzBinImport *>*/ *mdmp_imports(RzBinFile *bf) {
MiniDmpObj *obj;
struct Pe32_rz_bin_mdmp_pe_bin *pe32_bin;
Expand Down Expand Up @@ -491,7 +464,6 @@ RzBinPlugin rz_bin_plugin_mdmp = {
.load_buffer = &mdmp_load_buffer,
.check_buffer = &mdmp_check_buffer,
.mem = &mdmp_mem,
.relocs = &mdmp_relocs,
.maps = &mdmp_maps,
.sections = &mdmp_sections,
.symbols = &mdmp_symbols,
Expand Down
Loading
Loading