Skip to content

Commit

Permalink
Update COFF relocations
Browse files Browse the repository at this point in the history
* Break down `relocs_foreach` to sub functions for readability
* Migrate to using `RzBinReloc.print_name` for reloc name printing
  • Loading branch information
Roeegg2 committed Nov 5, 2024
1 parent 8b90795 commit 7d5eac5
Showing 1 changed file with 114 additions and 69 deletions.
183 changes: 114 additions & 69 deletions librz/bin/format/coff/coff_reloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,112 @@ RZ_API ut64 rz_coff_import_index_addr(struct rz_bin_coff_obj *obj, ut64 imp_inde

typedef void (*RelocsForeachCb)(RZ_BORROW RzBinReloc *reloc, ut8 *patch_buf, size_t patch_buf_sz, void *user);

static size_t reloc_general_arch_rel32_common(struct rz_bin_coff_obj *bin, RzBinReloc *reloc, ut64 sym_vaddr, ut8 *patch_buf, const char *print_name) {
reloc->print_name = print_name;
reloc->type = RZ_BIN_RELOC_32;
reloc->additive = 1;
ut32 data;
if (!rz_buf_read_le32_at(bin->b, reloc->paddr, &data)) {
return 0;
}
reloc->addend = data;
data += sym_vaddr - reloc->vaddr - 4;
rz_write_le32(patch_buf, (st32)data);

return 4;
}

static size_t reloc_arm_branches_common(struct rz_bin_coff_obj *bin, RzBinReloc *reloc, ut64 sym_vaddr, ut8 *patch_buf, const char *print_name) {
reloc->print_name = print_name;
reloc->type = RZ_BIN_RELOC_32;
ut16 hiword;
if (!rz_buf_read_le16_at(bin->b, reloc->paddr, &hiword)) {
return 0;
}
ut16 loword;
if (!rz_buf_read_le16_at(bin->b, reloc->paddr + 2, &loword)) {
return 0;
}
ut64 dst = sym_vaddr - reloc->vaddr - 4;
if (dst & 1) {
return 0;
}
loword |= (ut16)(dst >> 1) & 0x7ff;
hiword |= (ut16)(dst >> 12) & 0x7ff;
rz_write_le16(patch_buf, hiword);
rz_write_le16(patch_buf + 2, loword);

return 4;
}

static ut8 handle_i386_relocs(struct rz_bin_coff_obj *bin, RzBinReloc *reloc, ut64 sym_vaddr, ut8 *patch_buf, ut16 reloc_type) {
switch (reloc_type) {
case COFF_REL_I386_DIR32:
reloc->type = RZ_BIN_RELOC_32;
rz_write_le32(patch_buf, (ut32)sym_vaddr);
reloc->print_name = "IMAGE_REL_I386_32";
return 4;
case COFF_REL_I386_REL32:
return reloc_general_arch_rel32_common(bin, reloc, sym_vaddr, patch_buf, "IMAGE_REL_I386_REL32");
// TODO: Missing handling of other relocation types
default:
RZ_LOG_WARN("Unimplemented/unknown COFF i386 relocation type: %d\n", reloc_type);
break;
}

return 0;
}

static ut8 handle_amd64_relocs(struct rz_bin_coff_obj *bin, RzBinReloc *reloc, ut64 sym_vaddr, ut8 *patch_buf, ut16 reloc_type) {
switch (reloc_type) {
case COFF_REL_AMD64_REL32:
return reloc_general_arch_rel32_common(bin, reloc, sym_vaddr, patch_buf, "IMAGE_REL_AMD64_REL32");
// TODO: Missing handling of other relocation types
default:
RZ_LOG_WARN("Unimplemented/unknown COFF AMD64 relocation type: %d\n", reloc_type);
break;
}

return 0;
}

static ut8 handle_arm_relocs(struct rz_bin_coff_obj *bin, RzBinReloc *reloc, ut64 sym_vaddr, ut8 *patch_buf, ut16 reloc_type) {
switch (reloc_type) {
case COFF_REL_ARM_BRANCH24T:
return reloc_arm_branches_common(bin, reloc, sym_vaddr, patch_buf, "IMAGE_REL_ARM_BRANCH24T");
case COFF_REL_ARM_BLX23T:
return reloc_arm_branches_common(bin, reloc, sym_vaddr, patch_buf, "IMAGE_REL_ARM_BLX23T");
// TODO: Missing handling of other relocation types
default:
RZ_LOG_WARN("Unimplemented/unknown COFF ARM relocation type: %d\n", reloc_type);
break;
}

return 0;
}

static ut8 handle_arm64_relocs(struct rz_bin_coff_obj *bin, RzBinReloc *reloc, ut64 sym_vaddr, ut8 *patch_buf, ut16 reloc_type) {
switch (reloc_type) {
case COFF_REL_ARM64_BRANCH26:
reloc->type = RZ_BIN_RELOC_32;
ut32 data;
if (!rz_buf_read_le32_at(bin->b, reloc->paddr, &data)) {
break;
}
ut64 dst = sym_vaddr - reloc->vaddr;
data |= (ut32)((dst >> 2) & 0x3ffffffULL);
rz_write_le32(patch_buf, data);
reloc->print_name = "IMAGE_REL_ARM64_BRANCH26";
return 4;
// TODO: Missing handling of other relocation types
default:
RZ_LOG_WARN("Unimplemented/unknown COFF ARM64 relocation type: %d\n", reloc_type);
break;
}

return 0;
}

static void relocs_foreach(struct rz_bin_coff_obj *bin, RelocsForeachCb cb, void *user) {
if (!bin->scn_hdrs) {
return;
Expand Down Expand Up @@ -97,82 +203,21 @@ static void relocs_foreach(struct rz_bin_coff_obj *bin, RelocsForeachCb cb, void
ut8 patch_buf[8];
if (sym_vaddr) {
switch (bin->hdr.f_magic) {
// TODO: Missing handling of MIPS architecture
case COFF_FILE_MACHINE_I386:
switch (rel[j].rz_type) {
case COFF_REL_I386_DIR32:
reloc.type = RZ_BIN_RELOC_32;
rz_write_le32(patch_buf, (ut32)sym_vaddr);
plen = 4;
break;
case COFF_REL_I386_REL32:
reloc.type = RZ_BIN_RELOC_32;
reloc.additive = 1;
ut32 data;
if (!rz_buf_read_le32_at(bin->b, reloc.paddr, &data)) {
break;
}
reloc.addend = data;
data += sym_vaddr - reloc.vaddr - 4;
rz_write_le32(patch_buf, (st32)data);
plen = 4;
break;
}
plen = handle_i386_relocs(bin, &reloc, sym_vaddr, patch_buf, rel[j].rz_type);
break;
case COFF_FILE_MACHINE_AMD64:
switch (rel[j].rz_type) {
case COFF_REL_AMD64_REL32:
reloc.type = RZ_BIN_RELOC_32;
reloc.additive = 1;
ut32 data;
if (!rz_buf_read_le32_at(bin->b, reloc.paddr, &data)) {
break;
}
reloc.addend = data;
data += sym_vaddr - reloc.vaddr - 4;
rz_write_le32(patch_buf, (st32)data);
plen = 4;
break;
}
plen = handle_amd64_relocs(bin, &reloc, sym_vaddr, patch_buf, rel[j].rz_type);
break;
case COFF_FILE_MACHINE_ARMNT:
switch (rel[j].rz_type) {
case COFF_REL_ARM_BRANCH24T:
case COFF_REL_ARM_BLX23T:
reloc.type = RZ_BIN_RELOC_32;
ut16 hiword;
if (!rz_buf_read_le16_at(bin->b, reloc.paddr, &hiword)) {
break;
}
ut16 loword;
if (!rz_buf_read_le16_at(bin->b, reloc.paddr + 2, &loword)) {
break;
}
ut64 dst = sym_vaddr - reloc.vaddr - 4;
if (dst & 1) {
break;
}
loword |= (ut16)(dst >> 1) & 0x7ff;
hiword |= (ut16)(dst >> 12) & 0x7ff;
rz_write_le16(patch_buf, hiword);
rz_write_le16(patch_buf + 2, loword);
plen = 4;
break;
}
plen = handle_arm_relocs(bin, &reloc, sym_vaddr, patch_buf, rel[j].rz_type);
break;
case COFF_FILE_MACHINE_ARM64:
switch (rel[j].rz_type) {
case COFF_REL_ARM64_BRANCH26:
reloc.type = RZ_BIN_RELOC_32;
ut32 data;
if (!rz_buf_read_le32_at(bin->b, reloc.paddr, &data)) {
break;
}
ut64 dst = sym_vaddr - reloc.vaddr;
data |= (ut32)((dst >> 2) & 0x3ffffffULL);
rz_write_le32(patch_buf, data);
plen = 4;
break;
}
plen = handle_arm64_relocs(bin, &reloc, sym_vaddr, patch_buf, rel[j].rz_type);
break;
default:
RZ_LOG_WARN("Unimplemented/unknown COFF architecture type: %d\n", bin->hdr.f_magic);
break;
}
}
Expand Down

0 comments on commit 7d5eac5

Please sign in to comment.