Refactor mach0 loading of imports ##bin

This commit is contained in:
Luc Tielen 2023-04-03 17:18:41 +02:00 committed by pancake
parent b0c267e827
commit 89d29a7b52
3 changed files with 115 additions and 83 deletions

View File

@ -2179,6 +2179,9 @@ void *MACH0_(mach0_free)(struct MACH0_(obj_t) *mo) {
free (mo->compiler);
r_list_free (mo->symbols_cache);
r_list_free (mo->sections_cache);
if (mo->imports_loaded) {
r_pvector_fini (&mo->imports_cache);
}
if (mo->chained_starts) {
for (i = 0; i < mo->nsegs && i < mo->segs_count; i++) {
if (mo->chained_starts[i]) {
@ -2593,7 +2596,7 @@ static bool parse_import_stub(struct MACH0_(obj_t) *bin, struct symbol_t *symbol
return false;
}
static int inSymtab(HtPP *hash, const char *name, ut64 addr) {
static int hash_find_or_insert(HtPP *hash, const char *name, ut64 addr) {
bool found = false;
char *key = r_str_newf ("%"PFMT64x".%s", addr, name);
ht_pp_find (hash, key, &found);
@ -2827,7 +2830,7 @@ const RList *MACH0_(get_symbols_list)(struct MACH0_(obj_t) *bin) {
RListIter *it;
RBinSymbol *s;
r_list_foreach (list, it, s) {
inSymtab (hash, s->name, s->vaddr);
hash_find_or_insert (hash, s->name, s->vaddr);
}
}
@ -2925,7 +2928,7 @@ const RList *MACH0_(get_symbols_list)(struct MACH0_(obj_t) *bin) {
} else {
sym->name = r_str_newf ("unk%u", (ut32)i);
}
if (!inSymtab (hash, sym->name, sym->vaddr)) {
if (!hash_find_or_insert (hash, sym->name, sym->vaddr)) {
r_list_append (list, sym);
} else {
r_bin_symbol_free (sym);
@ -2976,7 +2979,7 @@ const RList *MACH0_(get_symbols_list)(struct MACH0_(obj_t) *bin) {
char *sym_name = get_name (bin, st->n_strx, false);
if (sym_name) {
sym->name = sym_name;
if (inSymtab (hash, sym->name, sym->vaddr)) {
if (hash_find_or_insert (hash, sym->name, sym->vaddr)) {
r_bin_symbol_free (sym);
continue;
}
@ -3009,7 +3012,7 @@ static void assign_export_symbol_t(struct MACH0_(obj_t) *bin, const char *name,
if (j < sym_ctx->symbols_count) {
sym_ctx->symbols[j].offset = offset;
sym_ctx->symbols[j].addr = offset_to_vaddr (bin, offset);
if (inSymtab (sym_ctx->hash, name, sym_ctx->symbols[j].addr)) {
if (hash_find_or_insert (sym_ctx->hash, name, sym_ctx->symbols[j].addr)) {
return;
}
sym_ctx->symbols[j].size = 0;
@ -3126,7 +3129,7 @@ const struct symbol_t *MACH0_(get_symbols)(struct MACH0_(obj_t) *bin) {
bin->main_addr = symbols[j].addr;
}
}
if (inSymtab (hash, symbols[j].name, symbols[j].addr)) {
if (hash_find_or_insert (hash, symbols[j].name, symbols[j].addr)) {
free (symbols[j].name);
symbols[j].name = NULL;
j--;
@ -3169,7 +3172,7 @@ const struct symbol_t *MACH0_(get_symbols)(struct MACH0_(obj_t) *bin) {
symbols[j].name = r_str_newf ("entry%d", i);
}
symbols[j].last = 0;
if (inSymtab (hash, symbols[j].name, symbols[j].addr)) {
if (hash_find_or_insert (hash, symbols[j].name, symbols[j].addr)) {
R_FREE (symbols[j].name);
} else {
j++;
@ -3263,10 +3266,45 @@ static int parse_import_ptr(struct MACH0_(obj_t) *bin, struct reloc_t *reloc, in
return false;
}
struct import_t *MACH0_(get_imports)(struct MACH0_(obj_t) *bin) {
r_return_val_if_fail (bin, NULL);
static RBinImport *import_from_name(RBin *rbin, const char *orig_name) {
RBinImport *ptr = R_NEW0 (RBinImport);
if (!ptr) {
return NULL;
}
char *name = (char*) orig_name;
const char *_objc_class = "_OBJC_CLASS_$";
const char *_objc_metaclass = "_OBJC_METACLASS_$";
const char * type = "FUNC";
if (r_str_startswith (name, _objc_class)) {
name += strlen (_objc_class);
type = "OBJC_CLASS";
} else if (r_str_startswith (name, _objc_metaclass)) {
name += strlen (_objc_metaclass);
type = "OBJC_METACLASS";
}
// Remove the extra underscore that every import seems to have in Mach-O.
if (*name == '_') {
name++;
}
ptr->name = r_str_ndup (name, R_BIN_MACH0_STRING_LENGTH - 1);
ptr->bind = "NONE";
ptr->type = r_str_constpool_get (&rbin->constpool, type);
return ptr;
}
const RPVector *MACH0_(load_imports)(RBinFile *bf, struct MACH0_(obj_t) *bin) {
r_return_val_if_fail (bin, NULL);
if (bin->imports_loaded) {
return &bin->imports_cache;
}
bin->imports_loaded = true;
r_pvector_init (&bin->imports_cache, (RPVectorFree) r_bin_import_free);
r_pvector_reserve (&bin->imports_cache, bin->dysymtab.nundefsym);
int i, j, idx, stridx;
if (!bin->sects || !bin->symtab || !bin->symstr || !bin->indirectsyms) {
return NULL;
}
@ -3275,42 +3313,68 @@ struct import_t *MACH0_(get_imports)(struct MACH0_(obj_t) *bin) {
return NULL;
}
struct import_t *imports = calloc (bin->dysymtab.nundefsym + 1, sizeof (struct import_t));
if (!imports) {
return NULL;
}
for (i = j = 0; i < bin->dysymtab.nundefsym; i++) {
idx = bin->dysymtab.iundefsym + i;
int i, num_imports;
for (i = num_imports = 0; i < bin->dysymtab.nundefsym; i++) {
int idx = bin->dysymtab.iundefsym + i;
if (idx < 0 || idx >= bin->nsymtab) {
R_LOG_WARN ("Imports index out of bounds. Ignoring relocs");
free (imports);
return NULL;
}
stridx = bin->symtab[idx].n_strx;
int stridx = bin->symtab[idx].n_strx;
char *imp_name = get_name (bin, stridx, false);
if (imp_name) {
r_str_ncpy (imports[j].name, imp_name, R_BIN_MACH0_STRING_LENGTH - 1);
free (imp_name);
} else {
//imports[j].name[0] = 0;
if (!imp_name) {
continue;
}
imports[j].ord = i;
imports[j++].last = 0;
}
imports[j].last = 1;
if (!bin->imports_by_ord_size) {
if (j > 0) {
bin->imports_by_ord_size = j;
bin->imports_by_ord = (RBinImport**)calloc (j, sizeof (RBinImport*));
} else {
bin->imports_by_ord_size = 0;
bin->imports_by_ord = NULL;
RBinImport *import = import_from_name (bf->rbin, imp_name);
if (!import) {
free (imp_name);
break; // TODO change into continue?
}
import->ordinal = i;
r_pvector_push (&bin->imports_cache, import);
num_imports++;
if (!strcmp (import->name, "__stack_chk_fail") ) {
bin->has_canary = true;
}
if (!strcmp (import->name, "__asan_init") || !strcmp (import->name, "__tsan_init")) {
bin->has_sanitizers = true;
}
if (!strcmp (import->name, "_NSConcreteGlobalBlock")) {
bin->has_blocks_ext = true;
}
free (imp_name);
}
return imports;
bin->has_canary = false;
bin->has_retguard = -1;
bin->has_sanitizers = false;
bin->has_blocks_ext = false;
if (num_imports > 0) {
bin->imports_by_ord_size = num_imports;
bin->imports_by_ord = (RBinImport**)calloc (num_imports, sizeof (RBinImport*));
if (!bin->imports_by_ord) {
return NULL;
}
void **it;
r_pvector_foreach (&bin->imports_cache, it) {
RBinImport *import = (RBinImport*) *it;
if (import->ordinal < bin->imports_by_ord_size) {
bin->imports_by_ord[import->ordinal] = import;
}
}
} else {
bin->imports_by_ord_size = 0;
bin->imports_by_ord = NULL;
}
return &bin->imports_cache;
}
static int reloc_comparator(struct reloc_t *a, struct reloc_t *b) {

View File

@ -71,12 +71,6 @@ struct symbol_t {
bool last;
};
struct import_t {
char name[R_BIN_MACH0_STRING_LENGTH];
int ord;
int last;
};
struct reloc_t {
ut64 offset;
ut64 addr;
@ -200,6 +194,8 @@ struct MACH0_(obj_t) {
bool rebasing_buffer;
RList *symbols_cache;
RList *sections_cache;
bool imports_loaded;
RPVector imports_cache;
RList *reloc_fixups;
ut8 *internal_buffer;
int internal_buffer_size;
@ -267,7 +263,7 @@ RList *MACH0_(get_segments)(RBinFile *bf);
const struct symbol_t *MACH0_(get_symbols)(struct MACH0_(obj_t) *bin);
const RList *MACH0_(get_symbols_list)(struct MACH0_(obj_t) *bin);
void MACH0_(pull_symbols)(struct MACH0_(obj_t) *mo, RBinSymbolCallback cb, void *user);
struct import_t *MACH0_(get_imports)(struct MACH0_(obj_t) *bin);
const RPVector *MACH0_(load_imports)(RBinFile* bf, struct MACH0_(obj_t) *bin);
RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin);
struct addr_t *MACH0_(get_entrypoint)(struct MACH0_(obj_t) *bin);
struct lib_t *MACH0_(get_libs)(struct MACH0_(obj_t) *bin);

View File

@ -385,49 +385,21 @@ static RBinImport *import_from_name(RBin *rbin, const char *orig_name, HtPP *imp
}
static RList *imports(RBinFile *bf) {
RBinObject *obj = bf ? bf->o : NULL;
struct MACH0_(obj_t) *bin = bf ? bf->o->bin_obj : NULL;
const char *name;
RBinImport *ptr = NULL;
int i;
RBinObject *obj = bf? bf->o: NULL;
const RPVector *imports = MACH0_(load_imports) (bf, obj->bin_obj);
if (!imports) {
return NULL;
}
if (!obj || !bin || !obj->bin_obj) {
return NULL;
RList *list = r_list_newf ((RListFree) r_bin_import_free);
void **it;
r_pvector_foreach (imports, it) {
// need to clone here, in bobj.c the list free function is forced to `r_bin_import_free`
// otherwise, a list with no free function could be returned here..
RBinImport *import = r_bin_import_clone (*it);
r_list_append (list, import);
}
RList *ret = r_list_newf((RListFree)r_bin_import_free);
struct import_t *imports = MACH0_(get_imports)(bf->o->bin_obj);
if (!ret || !imports) {
r_list_free (ret);
free (imports);
return NULL;
}
bin->has_canary = false;
bin->has_retguard = -1;
bin->has_sanitizers = false;
bin->has_blocks_ext = false;
for (i = 0; !imports[i].last; i++) {
if (!(ptr = import_from_name (bf->rbin, imports[i].name, NULL))) {
break;
}
name = ptr->name;
ptr->ordinal = imports[i].ord;
if (bin->imports_by_ord && ptr->ordinal < bin->imports_by_ord_size) {
bin->imports_by_ord[ptr->ordinal] = ptr;
}
if (!strcmp (name, "__stack_chk_fail") ) {
bin->has_canary = true;
}
if (!strcmp (name, "__asan_init")
|| !strcmp (name, "__tsan_init")) {
bin->has_sanitizers = true;
}
if (!strcmp (name, "_NSConcreteGlobalBlock")) {
bin->has_blocks_ext = true;
}
r_list_append (ret, ptr);
}
free (imports);
return ret;
return list;
}
static RList *relocs(RBinFile *bf) {