From 628aa5c6f5627998b686d16562983ec517f6bd6a Mon Sep 17 00:00:00 2001 From: "Koh M. Nakagawa" Date: Wed, 15 Feb 2023 18:13:52 +0100 Subject: [PATCH] Add support for the XTAC file format ##bin --- dist/plugins-cfg/plugins.def.cfg | 1 + libr/bin/format/xtac/xtac.h | 81 +++++ libr/bin/meson.build | 1 + libr/bin/p/Makefile | 1 + libr/bin/p/bin_xtac.c | 593 +++++++++++++++++++++++++++++++ libr/bin/p/xtac.mk | 10 + libr/include/r_bin.h | 1 + libr/meson.build | 3 +- test/db/anal/v850 | 1 + test/db/formats/xtac | 122 +++++++ 10 files changed, 813 insertions(+), 1 deletion(-) create mode 100644 libr/bin/format/xtac/xtac.h create mode 100644 libr/bin/p/bin_xtac.c create mode 100644 libr/bin/p/xtac.mk create mode 100644 test/db/formats/xtac diff --git a/dist/plugins-cfg/plugins.def.cfg b/dist/plugins-cfg/plugins.def.cfg index ba1ab7683e91d..633d51490ac61 100644 --- a/dist/plugins-cfg/plugins.def.cfg +++ b/dist/plugins-cfg/plugins.def.cfg @@ -138,6 +138,7 @@ bin.xcoff64 bin.xnu_kernelcache bin.z64 bin.zimg +bin.xtac bin_ldr.ldr_linux bin_xtr.xtr_dyldcache bin_xtr.xtr_fatmach0 diff --git a/libr/bin/format/xtac/xtac.h b/libr/bin/format/xtac/xtac.h new file mode 100644 index 0000000000000..24f2208122544 --- /dev/null +++ b/libr/bin/format/xtac/xtac.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) FFRI Security, Inc., 2023 / Author: FFRI Security, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _INCLUDE_XTAC_H_ +#define _INCLUDE_XTAC_H_ + +#include + +#define XTAC_MAGIC "XTAC" + +typedef struct x86_arm_addr_pair_t { + ut32 x86_rva; + ut32 arm64_rva; +} X86ArmAddrPair; + +// NOTE: Here "pointer" means RVA from the image base of the cache file +typedef struct r_bin_xtac_header_t { + ut32 magic; // signature (always "XTAC") + ut32 version; // version of XTAC + ut32 is_updated; // cache file is updated (1) or not (0) + ut32 ptr_to_addr_pairs; // pointer to x86 to arm address pairs + ut32 num_of_addr_pairs; // number of address pairs + ut32 ptr_to_mod_name; // pointer to module name + ut32 size_of_mod_name; // size of module name (in bytes) + ut32 ptr_to_nt_pname; // pointer to NT path name + ut32 size_of_nt_pname; // size of NT path name (in bytes) + ut32 ptr_to_head_blck_stub; // pointer to head BLCK stub + ut32 ptr_to_tail_blck_stub; // pointer to tail BLCK stub + ut32 size_of_blck_stub_code; // size of BLCK stub code (not including BLCK stub header) + ut32 ptr_to_xtac_linked_list_head; // pointer to the head of linked list for updating + // xtac.exe uses this for accessing the location to be corrected + ut32 ptr_to_xtac_linked_list_tail; // pointer to the tail of linked list for updating +} RBinXtacHeader; + +typedef struct r_bin_blck_stub_header_t { + ut32 magic; // signature (always "BLCK") + ut32 offset_to_next_entry; // offset to the next entry from the current BLCK stub code + ut32 ptr_to_next_entry; // pointer to the next BLCK stub + ut32 padding; // padding (always 0) + + ut32 ptr_to_entry; // pointer to this entry +} RBinBlckStubHeader; + +typedef struct r_bin_xtac_linked_list_entry_t { + ut32 meta_and_offset; // metadata (upper 8bits) and quarter of offset to next entry (lower 24bits) + ut32 forward_edge_addr; // x86 RVA of forward edge address + ut32 backward_edge_addr; // x86 RVA of backward edge address + + ut32 ptr_to_entry; // pointer to this entry +} RBinXtacLinkedListEntry; + +typedef struct r_bin_xtac_obj_t { + RBinXtacHeader *header; + X86ArmAddrPair *address_pairs; + ut16 *mod_name_u16; + char *mod_name_u8; + ut16 *nt_path_name_u16; + char *nt_path_name_u8; + + RBuffer *b; + RList *blck_stubs; // RList of r_bin_bock_stub_header_t + RList *xtac_linked_list; // RList of r_bin_xtac_linked_list_entry_t + Sdb *kv; + bool verbose; + int size; +} RBinXtacObj; + +#endif diff --git a/libr/bin/meson.build b/libr/bin/meson.build index 7a7b6988128e0..7fc100f961605 100644 --- a/libr/bin/meson.build +++ b/libr/bin/meson.build @@ -85,6 +85,7 @@ r_bin_sources = [ 'p/bin_xtr_xalz.c', 'p/bin_z64.c', 'p/bin_zimg.c', + 'p/bin_xtac.c', # implementation 'format/bflt/bflt.c', 'format/coff/coff.c', diff --git a/libr/bin/p/Makefile b/libr/bin/p/Makefile index c867d2070815f..307d34f6909f7 100644 --- a/libr/bin/p/Makefile +++ b/libr/bin/p/Makefile @@ -23,6 +23,7 @@ FORMATS+=dex.mk fs.mk ningb.mk coff.mk xcoff64.mk ningba.mk xbe.mk zimg.mk FORMATS+=omf.mk cgc.mk dol.mk rel.mk nes.mk mbn.mk psxexe.mk FORMATS+=vsf.mk nin3ds.mk bflt.mk wasm.mk sfc.mk FORMATS+=mdmp.mk z64.mk qnx.mk prg.mk dmp64.mk +FORMATS+=xtac.mk FORMATS+=xtr_dyldcache.mk FORMATS+=xtr_fatmach0.mk diff --git a/libr/bin/p/bin_xtac.c b/libr/bin/p/bin_xtac.c new file mode 100644 index 0000000000000..aa9db56742b2d --- /dev/null +++ b/libr/bin/p/bin_xtac.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) FFRI Security, Inc., 2023 / Author: FFRI Security, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define R_LOG_ORIGIN "xtac" + +#include +#include "../format/xtac/xtac.h" + +#define GET_META_DATA(v) (((v)&0xF0000000) >> 28) +#define GET_OFFSET(v) ((v)&0x0FFFFFFF) + +static inline bool has_forward_edge_addr(ut8 meta) { + return (meta & 0x1) == 0x1; +} + +static inline bool has_backward_edge_addr(ut8 meta) { + return (meta & 0x2) == 0x2; +} + +static RList *sections(RBinFile *bf) { + RBinXtacObj *bin = bf->o->bin_obj; + + RList *ret = NULL; + if (!(ret = r_list_newf ((RListFree)r_bin_section_free))) { + return NULL; + } + + RBinSection *ptr_sect_header = NULL, *ptr_sect_blck = NULL, *ptr_sect_trans_code = NULL; + + if (!(ptr_sect_header = R_NEW0 (RBinSection))) { + r_list_free (ret); + return NULL; + } + ptr_sect_header->name = strdup ("header"); + ptr_sect_header->vsize = bin->header->ptr_to_head_blck_stub; + ptr_sect_header->paddr = ptr_sect_header->vaddr = 0; + ptr_sect_header->perm = R_PERM_R; + r_list_append (ret, ptr_sect_header); + + ut32 blck_stub_code_size = bin->header->size_of_blck_stub_code + 8; // NOTE: always 8 bytes data is padded. + ut32 ptr_addr = bin->header->ptr_to_head_blck_stub + sizeof (RBinBlckStubHeader) - 4; + int i; + for (i = 0; i < bin->blck_stubs->length; i++) { + RBinBlckStubHeader *blck_stub_header = (RBinBlckStubHeader *)r_list_get_n (bin->blck_stubs, i); + + if (!(ptr_sect_blck = R_NEW0 (RBinSection))) { + r_list_free (ret); + return NULL; + } + + ptr_sect_blck->name = r_str_newf ("blck_code_%d", i); + ptr_sect_blck->vsize = blck_stub_code_size; + ptr_sect_blck->paddr = ptr_addr; + ptr_sect_blck->vaddr = ptr_addr; + ptr_sect_blck->perm = R_PERM_RX; + ptr_addr += blck_stub_code_size; + r_list_append (ret, ptr_sect_blck); + + if (!(ptr_sect_trans_code = R_NEW0 (RBinSection))) { + r_list_free (ret); + return NULL; + } + + const ut32 size_of_trans_code = blck_stub_header->offset_to_next_entry - blck_stub_code_size; + + ptr_sect_trans_code->name = r_str_newf ("trans_code_%d", i); + ptr_sect_trans_code->vsize = size_of_trans_code; + ptr_sect_trans_code->paddr = ptr_addr; + ptr_sect_trans_code->vaddr = ptr_addr; + ptr_sect_trans_code->perm = R_PERM_RX; + ptr_addr += size_of_trans_code; + r_list_append (ret, ptr_sect_trans_code); + + ptr_addr += sizeof (RBinBlckStubHeader) - 4; + } + + return ret; +} + +static RList *fields(RBinFile *bf) { + RList *ret = r_list_new (); + if (!ret) { + return NULL; + } + + r_strf_buffer (128); +#define ROWL(nam, siz, val, fmt) \ + r_list_append (ret, r_bin_field_new (addr, addr, siz, nam, r_strf ("0x%08x", val), fmt, false)); + RBinXtacObj *bin = bf->o->bin_obj; + + ut64 addr = 0; + ROWL ("magic", 4, bin->header->magic, "x"); + addr += 4; + ROWL ("version", 4, bin->header->version, "x"); + addr += 4; + ROWL ("is_updated", 4, bin->header->is_updated, "x"); + addr += 4; + ROWL ("ptr_to_addr_pairs", 4, bin->header->ptr_to_addr_pairs, "x"); + addr += 4; + ROWL ("num_of_addr_pairs", 4, bin->header->num_of_addr_pairs, "x"); + addr += 4; + + r_list_append (ret, r_bin_field_new (bin->header->ptr_to_mod_name, bin->header->ptr_to_mod_name, 0, "mod_name", strdup (bin->mod_name_u8), "s", false)); + ROWL ("ptr_to_mod_name", 4, bin->header->ptr_to_mod_name, "x"); + addr += 4; + ROWL ("size_of_mod_name", 4, bin->header->size_of_mod_name, "x"); + addr += 4; + + r_list_append (ret, r_bin_field_new (bin->header->ptr_to_nt_pname, bin->header->ptr_to_nt_pname, 0, "nt_pname", strdup (bin->nt_path_name_u8), "s", false)); + ROWL ("ptr_to_nt_pname", 4, bin->header->ptr_to_nt_pname, "x"); + addr += 4; + ROWL ("size_of_nt_pname", 4, bin->header->size_of_nt_pname, "x"); + addr += 4; + + ROWL ("ptr_to_head_blck_stub", 4, bin->header->ptr_to_head_blck_stub, "x"); + addr += 4; + ROWL ("ptr_to_tail_blck_stub", 4, bin->header->ptr_to_tail_blck_stub, "x"); + addr += 4; + ROWL ("size_of_blck_stub_code", 4, bin->header->size_of_blck_stub_code, "x"); + addr += 4; + ROWL ("ptr_to_xtac_linked_list_head", 4, bin->header->ptr_to_xtac_linked_list_head, "x"); + addr += 4; + ROWL ("ptr_to_xtac_linked_list_tail", 4, bin->header->ptr_to_xtac_linked_list_tail, "x"); + addr += 4; + + addr = bin->header->ptr_to_addr_pairs; + int i; + for (i = 0; i < bin->header->num_of_addr_pairs; i++) { + char *x86_rva_key_name = r_str_newf ("address_pairs[%d].x86_rva", i); + char *arm64_rva_key_name = r_str_newf ("address_pairs[%d].arm64_rva", i); + + ROWL (x86_rva_key_name, 4, bin->address_pairs[i].x86_rva, "x"); + addr += 4; + ROWL (arm64_rva_key_name, 4, bin->address_pairs[i].arm64_rva, "x"); + addr += 4; + + R_FREE (x86_rva_key_name); + R_FREE (arm64_rva_key_name); + } + + for (i = 0; i < bin->blck_stubs->length; i++) { + char *blck_key_name = r_str_newf ("blck_stub[%d]", i); + RBinBlckStubHeader *blck_stub = (RBinBlckStubHeader *)r_list_get_n (bin->blck_stubs, i); + + addr = blck_stub->ptr_to_entry; + + char *key_blck_magic = r_str_newf ("%s.magic", blck_key_name); + ROWL (key_blck_magic, 4, blck_stub->magic, "x"); + addr += 4; + R_FREE (key_blck_magic); + + char *key_blck_offset_to_next_entry = r_str_newf ("%s.offset_to_next_entry", blck_key_name); + ROWL (key_blck_offset_to_next_entry, 4, blck_stub->offset_to_next_entry, "x"); + addr += 4; + R_FREE (key_blck_offset_to_next_entry); + + char *key_blck_ptr_to_next_entry = r_str_newf ("%s.ptr_to_next_entry", blck_key_name); + ROWL (key_blck_ptr_to_next_entry, 4, blck_stub->ptr_to_next_entry, "x"); + addr += 4; + R_FREE (key_blck_ptr_to_next_entry); + + char *key_blck_padding = r_str_newf ("%s.padding", blck_key_name); + ROWL (key_blck_padding, 4, blck_stub->padding, "x"); + addr += 4; + R_FREE (key_blck_padding); + + R_FREE (blck_key_name); + } + + for (i = 0; i < bin->xtac_linked_list->length; i++) { + char *entry_key_name = r_str_newf ("xtac_linked_list[%d]", i); + RBinXtacLinkedListEntry *entry = (RBinXtacLinkedListEntry *)r_list_get_n (bin->xtac_linked_list, i); + + addr = entry->ptr_to_entry; + + char *key_meta_and_offset = r_str_newf ("%s.meta_and_offset", entry_key_name); + ROWL (key_meta_and_offset, 4, entry->meta_and_offset, "x"); + addr += 4; + R_FREE (key_meta_and_offset); + + const ut8 meta = GET_META_DATA (entry->meta_and_offset); + if (has_forward_edge_addr (meta)) { + char *key_forward_edge_addr = r_str_newf ("%s.forward_edge_addr", entry_key_name); + ROWL (key_forward_edge_addr, 4, entry->forward_edge_addr, "x"); + addr += 4; + R_FREE (key_forward_edge_addr); + } + + if (has_backward_edge_addr (meta)) { + char *key_backward_edge_addr = r_str_newf ("%s.backward_edge_addr", entry_key_name); + ROWL (key_backward_edge_addr, 4, entry->backward_edge_addr, "x"); + addr += 4; + R_FREE (key_backward_edge_addr); + } + + R_FREE (entry_key_name); + } + + return ret; + +#undef ROWL +} + +static void header(RBinFile *bf) { + RBinXtacObj *bin = bf->o->bin_obj; + struct r_bin_t *rbin = bf->rbin; + rbin->cb_printf ("XTAC file header:\n"); + rbin->cb_printf (" magic : 0x%x\n", bin->header->magic); + rbin->cb_printf (" version : 0x%x\n", bin->header->version); + rbin->cb_printf (" is_updated : 0x%x\n", bin->header->is_updated); + rbin->cb_printf (" ptr_to_addr_pairs : 0x%x\n", bin->header->ptr_to_addr_pairs); + rbin->cb_printf (" num_of_addr_pairs : 0x%x\n", bin->header->num_of_addr_pairs); + + rbin->cb_printf (" ptr_to_mod_name : 0x%x\n", bin->header->ptr_to_mod_name); + rbin->cb_printf (" size_of_mod_name : 0x%x\n", bin->header->size_of_mod_name); + rbin->cb_printf (" module name : %s\n", bin->mod_name_u8); + + rbin->cb_printf (" ptr_to_nt_pname : 0x%x\n", bin->header->ptr_to_nt_pname); + rbin->cb_printf (" size_of_nt_pname : 0x%x\n", bin->header->size_of_nt_pname); + rbin->cb_printf (" module name : %s\n", bin->nt_path_name_u8); + + rbin->cb_printf (" ptr_to_head_blck_stub : 0x%x\n", bin->header->ptr_to_head_blck_stub); + rbin->cb_printf (" ptr_to_tail_blck_stub : 0x%x\n", bin->header->ptr_to_tail_blck_stub); + rbin->cb_printf (" size_of_blck_stub_code : 0x%x\n", bin->header->size_of_blck_stub_code); + rbin->cb_printf (" ptr_to_xtac_linked_list_head : 0x%x\n", bin->header->ptr_to_xtac_linked_list_head); + rbin->cb_printf (" ptr_to_xtac_linked_list_tail : 0x%x\n", bin->header->ptr_to_xtac_linked_list_tail); + + rbin->cb_printf ("address pairs (x86, arm64):\n"); + const ut32 n_addr_pairs = bin->header->num_of_addr_pairs; + ut32 i; + for (i = 0; i < n_addr_pairs; i++) { + rbin->cb_printf (" 0x%x, 0x%x\n", bin->address_pairs[i].x86_rva, bin->address_pairs[i].arm64_rva); + } + + rbin->cb_printf ("blck stubs:\n"); + RBinBlckStubHeader *blck_stub = NULL; + RListIter *iter = NULL; + r_list_foreach (bin->blck_stubs, iter, blck_stub) { + rbin->cb_printf (" blck stub entry\n"); + rbin->cb_printf (" ptr_to_entry : 0x%x\n", blck_stub->ptr_to_entry); + rbin->cb_printf (" magic : 0x%x\n", blck_stub->magic); + rbin->cb_printf (" offset_to_next_entry : 0x%x\n", blck_stub->offset_to_next_entry); + rbin->cb_printf (" ptr_to_next_entry : 0x%x\n", blck_stub->ptr_to_next_entry); + rbin->cb_printf (" padding : 0x%x\n", blck_stub->padding); + } + + rbin->cb_printf ("xtac linked list:\n"); + RBinXtacLinkedListEntry *entry = NULL; + r_list_foreach (bin->xtac_linked_list, iter, entry) { + rbin->cb_printf (" xtac linked list entry\n"); + rbin->cb_printf (" ptr_to_entry : 0x%x\n", entry->ptr_to_entry); + rbin->cb_printf (" meta_data : 0x%x\n", GET_META_DATA (entry->meta_and_offset)); + rbin->cb_printf (" offset_to_next_entry : 0x%x\n", GET_OFFSET (entry->meta_and_offset) * 4); + rbin->cb_printf (" forward_edge_addr : 0x%x\n", entry->forward_edge_addr); + rbin->cb_printf (" backward_edge_addr : 0x%x\n", entry->backward_edge_addr); + } +} + +static bool r_bin_xtac_read_header(RBinXtacObj *bin) { + if (!(bin->header = R_NEW0 (RBinXtacHeader))) { + return false; + } + if (r_buf_read_at (bin->b, 0, (ut8 *)bin->header, sizeof (RBinXtacHeader)) < 0) { + R_LOG_WARN ("Read (xtac header)"); + R_FREE (bin->header); + return false; + } + return true; +} + +static bool r_bin_xtac_read_address_pairs(RBinXtacObj *bin) { + const ut32 n_addr_pairs = bin->header->num_of_addr_pairs; + const ut32 addr_pair_size = n_addr_pairs * sizeof (X86ArmAddrPair); + const ut32 p_addr_pair = bin->header->ptr_to_addr_pairs; + if (!(bin->address_pairs = R_NEWS0 (X86ArmAddrPair, n_addr_pairs))) { + return false; + } + if (r_buf_read_at (bin->b, p_addr_pair, (ut8 *)bin->address_pairs, addr_pair_size) < 0) { + R_LOG_WARN ("Read (xtac address pairs)"); + R_FREE (bin->address_pairs); + return false; + } + return true; +} + +static bool r_bin_xtac_read_module_name(RBinXtacObj *bin) { + const ut32 len_of_mod_name = bin->header->size_of_mod_name / sizeof (ut16) + 1; + const ut32 p_mod_name = bin->header->ptr_to_mod_name; + if (!(bin->mod_name_u16 = R_NEWS0 (ut16, len_of_mod_name))) { + return false; + } + if (r_buf_read_at (bin->b, p_mod_name, (ut8 *)bin->mod_name_u16, bin->header->size_of_mod_name) < 0) { + R_LOG_WARN ("Read (xtac module name)"); + R_FREE (bin->mod_name_u16); + return false; + } + if (!(bin->mod_name_u8 = r_str_utf16_decode ((ut8 *)bin->mod_name_u16, bin->header->size_of_mod_name))) { + R_FREE (bin->mod_name_u16); + return false; + } + return true; +} + +static bool r_bin_xtac_read_nt_native_pathname(RBinXtacObj *bin) { + const ut32 len_of_nt_pname = (bin->header->size_of_nt_pname / sizeof (ut16)) + 1; + const ut32 p_nt_name = bin->header->ptr_to_nt_pname; + if (!(bin->nt_path_name_u16 = R_NEWS0 (ut16, len_of_nt_pname))) { + return false; + } + const ut32 size_read = r_buf_read_at (bin->b, p_nt_name, (ut8 *)bin->nt_path_name_u16, bin->header->size_of_nt_pname); + if (size_read != bin->header->size_of_nt_pname) { + R_LOG_WARN ("Read (xtac nt path)"); + R_FREE (bin->nt_path_name_u16); + return false; + } + + char *nt_path_name_u8_raw; + if (!(nt_path_name_u8_raw = r_str_utf16_decode ((ut8 *)bin->nt_path_name_u16, bin->header->size_of_nt_pname))) { + R_FREE (bin->nt_path_name_u16); + return false; + } + + if (!(bin->nt_path_name_u8 = r_str_escape_utf8_for_json (nt_path_name_u8_raw, -1))) { + R_FREE (bin->nt_path_name_u16); + R_FREE (nt_path_name_u8_raw); + return false; + } + + R_FREE (nt_path_name_u8_raw); + + return true; +} + +static bool r_bin_xtac_read_blck_stubs(RBinXtacObj *bin) { + if (!(bin->blck_stubs = r_list_newf (free))) { + return false; + } + const ut32 max_depth = 20; + ut32 i = 0; + ut32 p_blck_stub = bin->header->ptr_to_head_blck_stub; + do { + RBinBlckStubHeader *blck_stub = NULL; + if (!(blck_stub = R_NEW0 (RBinBlckStubHeader))) { + return false; + } + if (r_buf_read_at (bin->b, p_blck_stub, (ut8 *)blck_stub, sizeof (RBinBlckStubHeader) - sizeof (ut32)) < 0) { + R_LOG_WARN ("Read (xtac BLCK stub)"); + R_FREE (blck_stub); + return false; + } + blck_stub->ptr_to_entry = p_blck_stub; + r_list_append (bin->blck_stubs, blck_stub); + if (p_blck_stub == blck_stub->ptr_to_next_entry) { + R_LOG_WARN ("An infinite loop is detected. Some header members of BOCK Stub might be broken"); + break; + } + p_blck_stub = blck_stub->ptr_to_next_entry; + i++; + if (i >= max_depth) { + R_LOG_WARN ("Too many BLCK Stubs. Some header members of BLCK Stub might be broken"); + break; + } + } while (p_blck_stub); + return true; +} + +static bool r_bin_xtac_read_xtac_linked_list(RBinXtacObj *bin) { + if (!(bin->xtac_linked_list = r_list_newf (free))) { + return false; + } + RBinXtacLinkedListEntry *entry = NULL; + ut32 p_xtac_linked_list_entry = bin->header->ptr_to_xtac_linked_list_head; + do { + ut32 p_buffer = p_xtac_linked_list_entry; + + if (!(entry = R_NEW0 (RBinXtacLinkedListEntry))) { + return false; + } + entry->ptr_to_entry = p_buffer; + + if (r_buf_read_at (bin->b, p_buffer, (ut8 *)entry, sizeof (ut32)) < 0) { + R_LOG_WARN ("Read (xtac linked list metadata)"); + R_FREE (entry); + return false; + } + + const ut32 meta = GET_META_DATA (entry->meta_and_offset); + if (has_forward_edge_addr (meta)) { + p_buffer += sizeof (ut32); + if (r_buf_read_at (bin->b, p_buffer, (ut8 *)&entry->forward_edge_addr, sizeof (ut32)) < 0) { + R_LOG_WARN ("Read (xtac linked list forward edge address)"); + R_FREE (entry); + return false; + } + } + if (has_backward_edge_addr (meta)) { + p_buffer += sizeof (ut32); + if (r_buf_read_at (bin->b, p_buffer, (ut8 *)&entry->backward_edge_addr, sizeof (ut32)) < 0) { + R_LOG_WARN ("Read (xtac linked list backward edge address)"); + R_FREE (entry); + return false; + } + } + + r_list_append (bin->xtac_linked_list, entry); + p_xtac_linked_list_entry += GET_OFFSET (entry->meta_and_offset) * 4; + } while (p_xtac_linked_list_entry < bin->header->ptr_to_addr_pairs); + + if (GET_OFFSET (entry->meta_and_offset) != 0x0FFFFFFF) { + R_LOG_WARN ("xtac linked list is not properly terminated"); + R_LOG_WARN ("Some entry of xtac linked list might be broken"); + } + + return true; +} + +static bool r_bin_xtac_init(RBinXtacObj *bin) { + // NOTE: not tested on big-endian processor + if (!r_bin_xtac_read_header (bin)) { + return false; + } + + if (!r_bin_xtac_read_address_pairs (bin)) { + return false; + } + + if (!r_bin_xtac_read_module_name (bin)) { + return false; + } + + if (!r_bin_xtac_read_nt_native_pathname (bin)) { + return false; + } + + if (!r_bin_xtac_read_blck_stubs (bin)) { + return false; + } + + if (!r_bin_xtac_read_xtac_linked_list (bin)) { + return false; + } + + return true; +} + +static void r_bin_xtac_free(RBinXtacObj *bin) { + if (!bin) { + return; + } + R_FREE (bin->header); + R_FREE (bin->address_pairs); + R_FREE (bin->mod_name_u16); + R_FREE (bin->mod_name_u8); + R_FREE (bin->nt_path_name_u16); + R_FREE (bin->nt_path_name_u8); + + r_buf_free (bin->b); + bin->b = NULL; + + r_list_free (bin->blck_stubs); + r_list_free (bin->xtac_linked_list); + bin->blck_stubs = NULL; + bin->xtac_linked_list = NULL; + + R_FREE (bin); + return; +} + +static RBinXtacObj *r_bin_xtac_new_buf(RBuffer *buf, bool verbose) { + RBinXtacObj *bin = R_NEW0 (RBinXtacObj); + if (R_LIKELY (bin)) { + bin->b = r_buf_ref (buf); + bin->size = r_buf_size (buf); + bin->verbose = verbose; + if (!r_bin_xtac_init (bin)) { + r_bin_xtac_free (bin); + } + } + return bin; +} + +static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadaddr, Sdb *sdb) { + r_return_val_if_fail (bf && bin_obj && buf, false); + RBinXtacObj *res = r_bin_xtac_new_buf (buf, bf->rbin->verbose); + if (res) { + *bin_obj = res; + return true; + } + return false; +} + +static void destroy(RBinFile *bf) { + r_bin_xtac_free ((RBinXtacObj *)bf->o->bin_obj); +} + +static ut64 baddr(RBinFile *bf) { + return bf->o->baddr; +} + +static RBinInfo *info(RBinFile *bf) { + RBinInfo *ret = R_NEW0 (RBinInfo); + if (!ret) { + return NULL; + } + ret->lang = NULL; + ret->arch = strdup ("arm"); + ret->cpu = strdup ("v8"); + ret->bits = 64; + ret->big_endian = 0; + ret->file = bf->file? strdup (bf->file): NULL; + ret->type = strdup ("XTAC"); + ret->has_pi = 0; + ret->has_canary = 0; + ret->has_retguard = -1; + ret->big_endian = 0; + ret->has_va = 0; + ret->has_nx = 0; + ret->dbg_info = 0; + ret->dbg_info = 0; + ret->dbg_info = 0; + return ret; +} + +static bool check_buffer(RBinFile *file, RBuffer *b) { + ut64 length = r_buf_size (b); + if (length <= sizeof (RBinXtacHeader)) { + return false; + } + + ut8 buf[sizeof (XTAC_MAGIC) - 1]; + r_buf_read_at (b, 0, buf, sizeof (buf)); + return memcmp (buf, XTAC_MAGIC, sizeof (buf)) == 0; +} + +static RList *symbols(RBinFile *bf) { + RBinXtacObj *bin = bf->o->bin_obj; + + ut64 x86_baddr = baddr (bf), arm_baddr = 0x0; + + RList *ret = NULL; + if (!(ret = r_list_newf (free))) { + return NULL; + } + + RBinSymbol *ptr = NULL; + const ut32 num_pairs = bin->header->num_of_addr_pairs; + int i; + for (i = 0; i < num_pairs; i++) { + if (!(ptr = R_NEW0 (RBinSymbol))) { + break; + } + const ut32 x86_vaddr = bin->address_pairs[i].x86_rva + x86_baddr; + const ut32 arm_vaddr = bin->address_pairs[i].arm64_rva + arm_baddr; + ptr->name = r_str_newf ("x86.%08x", x86_vaddr); + ptr->bind = "NONE"; + ptr->type = R_BIN_TYPE_FUNC_STR; + ptr->size = 0; + ptr->vaddr = ptr->paddr = arm_vaddr; + ptr->ordinal = i; + r_list_append (ret, ptr); + } + + return ret; +} + +RBinPlugin r_bin_plugin_xtac = { + .name = "xtac", + .desc = "XTAC format r2 plugin", + .license = "Apache License 2.0", + .load_buffer = &load_buffer, + .destroy = &destroy, + .check_buffer = &check_buffer, + .baddr = &baddr, + .minstrlen = 6, + .info = &info, + .fields = &fields, + .header = &header, + .symbols = &symbols, + .sections = §ions, +}; diff --git a/libr/bin/p/xtac.mk b/libr/bin/p/xtac.mk new file mode 100644 index 0000000000000..af91358c05a15 --- /dev/null +++ b/libr/bin/p/xtac.mk @@ -0,0 +1,10 @@ +OBJ_XTAC=bin_xtac.o + +STATIC_OBJ+=${OBJ_XTAC} +TARGET_XTAC=bin_xtac.${EXT_SO} + +ALL_TARGETS+=${TARGET_XTAC} + +${TARGET_XTAC}: ${OBJ_XTAC} + ${CC} $(call libname,bin_xtac) -shared ${CFLAGS} \ + -o ${TARGET_XTAC} ${OBJ_XTAC} ${LINK} ${LDFLAGS} diff --git a/libr/include/r_bin.h b/libr/include/r_bin.h index adcfb9d5a7714..0c57f0e9be17f 100644 --- a/libr/include/r_bin.h +++ b/libr/include/r_bin.h @@ -906,6 +906,7 @@ extern RBinPlugin r_bin_plugin_lua; extern RBinPlugin r_bin_plugin_hunk; extern RBinPlugin r_bin_plugin_xalz; extern RBinPlugin r_bin_plugin_lua; +extern RBinPlugin r_bin_plugin_xtac; #ifdef __cplusplus } diff --git a/libr/meson.build b/libr/meson.build index 82708fe4d7d0e..2c4771d00de01 100644 --- a/libr/meson.build +++ b/libr/meson.build @@ -255,7 +255,8 @@ bin_plugins += [ 'xcoff64', 'xnu_kernelcache', 'z64', - 'zimg' + 'zimg', + 'xtac' ] bin_ldr_plugins += [ diff --git a/test/db/anal/v850 b/test/db/anal/v850 index f621ff07c3055..53e2547cede41 100644 --- a/test/db/anal/v850 +++ b/test/db/anal/v850 @@ -327,6 +327,7 @@ EXPECT=<