Devirtualize message dispatch in ObjectiveC (#5328)
This commit is contained in:
parent
ae4ce0dd5d
commit
5cbab45fd8
8 changed files with 896 additions and 8 deletions
|
|
@ -159,7 +159,7 @@ RZ_API RzAnalysis *rz_analysis_new(RZ_NULLABLE const char *sdb_types_path) {
|
|||
analysis->debug_info = rz_analysis_debug_info_new();
|
||||
analysis->cmpval = UT64_MAX;
|
||||
analysis->lea_jmptbl_ip = UT64_MAX;
|
||||
analysis->ht_cpp_virtual_xrefs = ht_sp_new(HT_STR_DUP, NULL, (HtSPFreeValue)rz_set_u_free);
|
||||
analysis->ht_virtual_xrefs = ht_sp_new(HT_STR_DUP, NULL, (HtSPFreeValue)rz_set_u_free);
|
||||
return analysis;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6117,7 +6117,23 @@ RZ_IPI RzCmdStatus rz_delete_global_imports_handler(RzCore *core, int argc, cons
|
|||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_analysis_devirtualize_handler(RzCore *core, int argc, const char **argv) {
|
||||
rz_analysis_devirtualize_methods(core->analysis);
|
||||
RzBinObject *obj = rz_bin_cur_object(core->bin);
|
||||
if (!obj) {
|
||||
RZ_LOG_ERROR("Cannot get current bin object\n");
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
switch (obj->lang) {
|
||||
case RZ_BIN_LANGUAGE_CXX:
|
||||
rz_analysis_devirtualize_cxx_methods(core->analysis);
|
||||
break;
|
||||
case RZ_BIN_LANGUAGE_OBJC:
|
||||
case RZ_BIN_LANGUAGE_SWIFT:
|
||||
rz_analysis_devirtualize_objc_methods(core);
|
||||
break;
|
||||
default:
|
||||
RZ_LOG_ERROR("Devirtualization is only supported for C++ and Objective-C binaries.\n");
|
||||
break;
|
||||
}
|
||||
return RZ_CMD_STATUS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -861,7 +861,7 @@ static bool free_virt_calls(void *user, const ut64 key, const void *v) {
|
|||
}
|
||||
|
||||
static bool add_virtual_xref(RzAnalysis *analysis, const ut64 key, RzSetS *vfunc_set) {
|
||||
HtSP *virtual_xref = analysis->ht_cpp_virtual_xrefs;
|
||||
HtSP *virtual_xref = analysis->ht_virtual_xrefs;
|
||||
RzPVector *pvect = rz_set_s_to_vector(vfunc_set);
|
||||
void **it;
|
||||
rz_pvector_foreach (pvect, it) {
|
||||
|
|
@ -928,7 +928,7 @@ static void free_variable_book(RzCppVariableBook *var_book) {
|
|||
/**
|
||||
* \brief devirtualize virtual calls in cpp
|
||||
*/
|
||||
RZ_API void rz_analysis_devirtualize_methods(RzAnalysis *analysis) {
|
||||
RZ_API void rz_analysis_devirtualize_cxx_methods(RzAnalysis *analysis) {
|
||||
// TODO : Generalize for classes
|
||||
RzCppVariableBook *var_book = rz_analysis_mark_classes(analysis);
|
||||
if (!var_book) {
|
||||
|
|
@ -953,7 +953,7 @@ static bool print_virtual_xrefs(RzCore *core, ut64 key, void *val) {
|
|||
*/
|
||||
RZ_API void rz_analysis_virtual_xrefs_print(RzAnalysis *analysis, const char *vfunc) {
|
||||
RzCore *core = analysis->core;
|
||||
HtSP *ht_virtual_xrefs = analysis->ht_cpp_virtual_xrefs;
|
||||
HtSP *ht_virtual_xrefs = analysis->ht_virtual_xrefs;
|
||||
bool found = false;
|
||||
RzSetU *set = ht_sp_find(ht_virtual_xrefs, vfunc, &found);
|
||||
if (!found) {
|
||||
|
|
@ -973,7 +973,7 @@ static bool add_virtual_xref_row(RzTable *table, const ut64 addr, void *val) {
|
|||
* \brief print xrefs of virtual functions as table
|
||||
*/
|
||||
RZ_API void rz_analysis_virtual_xrefs_print_table(RzAnalysis *analysis, const char *vfunc, RzTable *table) {
|
||||
HtSP *ht_virtual_xrefs = analysis->ht_cpp_virtual_xrefs;
|
||||
HtSP *ht_virtual_xrefs = analysis->ht_virtual_xrefs;
|
||||
bool found = false;
|
||||
RzSetU *set = ht_sp_find(ht_virtual_xrefs, vfunc, &found);
|
||||
if (!found) {
|
||||
|
|
|
|||
332
librz/core/devirtualize_objc.c
Normal file
332
librz/core/devirtualize_objc.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
// SPDX-FileCopyrightText: 2025 tushar3q34 <tushar3q34@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_util.h>
|
||||
#include <rz_analysis.h>
|
||||
#include <rz_core.h>
|
||||
#include "core_private.h"
|
||||
|
||||
/**
|
||||
* \file devirtualize_objc.c
|
||||
* Devirtualization for Objective-C methods
|
||||
*
|
||||
* This file implements the devirtualization of Objective-C methods
|
||||
* by analyzing the class and method structure.
|
||||
*/
|
||||
|
||||
static bool is_branch_type_to_method(RzAnalysisOp *op) {
|
||||
switch (op->type) {
|
||||
case RZ_ANALYSIS_OP_TYPE_JMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_RET:
|
||||
case RZ_ANALYSIS_OP_TYPE_CALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_RCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_ICALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_IRCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_CCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCCALL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief initialises stack and registers for tainting
|
||||
*/
|
||||
static void rz_track_init(RzAnalysis *analysis, RzCore *core) {
|
||||
// Random Memory allocation representing function stack
|
||||
rz_core_analysis_esil_init_mem(core, NULL, 0x1000, 0x1050);
|
||||
rz_core_analysis_il_reinit(core); // initializing VM
|
||||
// TODO : Make general for other archs
|
||||
if (!rz_str_cmp(analysis->arch_target->arch, "x86", -1)) {
|
||||
rz_core_analysis_il_vm_set(core, "rbp", 0x1fff);
|
||||
rz_core_analysis_il_vm_set(core, "rsp", 0x1fff);
|
||||
} else if (!rz_str_cmp(analysis->arch_target->arch, "arm", -1)) {
|
||||
rz_core_analysis_il_vm_set(core, "fp", 0x1fff);
|
||||
rz_core_analysis_il_vm_set(core, "sp", 0x1fff);
|
||||
} else {
|
||||
RZ_LOG_WARN("arch %s not supported", analysis->arch_target->arch);
|
||||
}
|
||||
}
|
||||
|
||||
static ut64 get_reg_value(RzAnalysis *analysis, const char *reg_name) {
|
||||
RzAnalysisILVM *vm = analysis->il_vm;
|
||||
RzILVal *il_c_reg = rz_il_vm_get_var_value(vm->vm, RZ_IL_VAR_KIND_GLOBAL, reg_name);
|
||||
if (!il_c_reg) {
|
||||
return UT64_MAX;
|
||||
}
|
||||
RzBitVector *bv = rz_il_value_to_bv(il_c_reg);
|
||||
if (!bv) {
|
||||
return UT64_MAX;
|
||||
}
|
||||
ut64 val = rz_bv_to_ut64(bv);
|
||||
rz_bv_free(bv);
|
||||
return val;
|
||||
}
|
||||
|
||||
static RZ_OWN char *get_message_dispatch_method(RzCore *core, ut64 meta_class_addr, ut64 meth_str_addr) {
|
||||
RzBinFile *bf = rz_bin_cur(core->bin);
|
||||
void **it;
|
||||
|
||||
const RzPVector *vec = rz_bin_object_get_strings(bf->o);
|
||||
char *methname = NULL;
|
||||
rz_pvector_foreach (vec, it) {
|
||||
RzBinString *bin_str = *it;
|
||||
if (bin_str->vaddr == meth_str_addr) {
|
||||
methname = rz_str_dup(bin_str->string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const RzPVector *symbols = rz_bin_object_get_symbols(bf->o);
|
||||
char *classname = NULL;
|
||||
rz_pvector_foreach (symbols, it) {
|
||||
RzBinSymbol *symbol = *it;
|
||||
if (symbol->vaddr == meta_class_addr) {
|
||||
classname = rz_str_dup(strstr(symbol->name, "CLASS_$_") + strlen("CLASS_$_"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!classname || !methname) {
|
||||
RZ_FREE(methname);
|
||||
RZ_FREE(classname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Modifying method name to include method_class_(name)
|
||||
char *oldname = methname;
|
||||
methname = rz_str_newf("method_%s_%s", classname, methname);
|
||||
RZ_FREE(oldname);
|
||||
|
||||
RzVector *methods = rz_analysis_class_method_get_all(core->analysis, classname);
|
||||
bool found = false;
|
||||
if (methods) {
|
||||
RzAnalysisMethod *method;
|
||||
rz_vector_foreach (methods, method) {
|
||||
if (!rz_str_cmp(method->name, methname, -1)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rz_vector_free(methods);
|
||||
RZ_FREE(classname);
|
||||
if (found) {
|
||||
return methname;
|
||||
}
|
||||
RZ_FREE(methname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RzSetU *allocator_xrefs(RzAnalysis *analysis) {
|
||||
RzList *list = rz_analysis_function_list(analysis);
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
RzListIter *it;
|
||||
RzAnalysisFunction *fcn;
|
||||
RzSetU *xref_addrs = rz_set_u_new();
|
||||
rz_list_foreach (list, it, fcn) {
|
||||
char *res = strstr(fcn->name, "sym.imp.objc_alloc_init");
|
||||
if (res != NULL) {
|
||||
RzList *xref_list = rz_analysis_xrefs_get_to(analysis, fcn->addr);
|
||||
RzListIter *itt;
|
||||
RzAnalysisXRef *xref;
|
||||
rz_list_foreach (xref_list, itt, xref) {
|
||||
rz_set_u_add(xref_addrs, xref->from);
|
||||
}
|
||||
}
|
||||
}
|
||||
return xref_addrs;
|
||||
}
|
||||
|
||||
static void add_virtual_xrefs(RzAnalysis *analysis, const char *method_name, ut64 addr) {
|
||||
bool found = false;
|
||||
HtSP *virtual_xrefs = analysis->ht_virtual_xrefs;
|
||||
RzSetU *set = ht_sp_find(virtual_xrefs, method_name, &found);
|
||||
if (!found) {
|
||||
set = rz_set_u_new();
|
||||
ht_sp_insert(virtual_xrefs, method_name, set);
|
||||
}
|
||||
rz_set_u_add(set, addr);
|
||||
}
|
||||
|
||||
static void devirtualize_msg_dispatch(RzCore *core, RzSetU *msg_dispatch_addr) {
|
||||
|
||||
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, RZ_ANALYSIS_FCN_TYPE_ROOT);
|
||||
if (!function) {
|
||||
function = rz_analysis_get_fcn_in(core->analysis, core->offset, RZ_ANALYSIS_FCN_TYPE_NULL);
|
||||
}
|
||||
if (!function) {
|
||||
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
||||
return;
|
||||
}
|
||||
|
||||
// The first argument is usually the register holding class meta info
|
||||
const char *cl_reg = rz_analysis_cc_arg(core->analysis, function->cc, 0);
|
||||
|
||||
// The second argument is usually the register holding message selector
|
||||
const char *m_reg = rz_analysis_cc_arg(core->analysis, function->cc, 1);
|
||||
|
||||
// The return argument stores the value of instance after call to allocator
|
||||
const char *ret_reg = rz_analysis_cc_ret(core->analysis, function->cc);
|
||||
|
||||
RzSetU *xref_addrs = allocator_xrefs(core->analysis);
|
||||
|
||||
ut64 start = function->addr; // start of the function
|
||||
ut64 end = rz_analysis_function_max_addr(function);
|
||||
RzAnalysisOp *op = rz_analysis_op_new();
|
||||
rz_track_init(core->analysis, core);
|
||||
|
||||
ut8 *bytes = malloc(end - start);
|
||||
if (!rz_io_read_at(core->io, start, bytes, end - start)) {
|
||||
RZ_LOG_ERROR("Cannot read at offset 0x%08" PFMT64x "\n", start);
|
||||
}
|
||||
ut64 offset = 0;
|
||||
|
||||
bool refresh_vm = false;
|
||||
while (start < end) {
|
||||
rz_analysis_op(core->analysis, op, start, bytes + offset, end - start, RZ_ANALYSIS_OP_MASK_ALL);
|
||||
if (refresh_vm) {
|
||||
rz_core_analysis_il_reinit(core);
|
||||
refresh_vm = false;
|
||||
}
|
||||
refresh_vm = is_branch_type_to_method(op);
|
||||
|
||||
rz_core_il_step(core, 1);
|
||||
|
||||
if (rz_set_u_contains(xref_addrs, start)) {
|
||||
// continue track past allocator call
|
||||
ut64 val = get_reg_value(core->analysis, cl_reg);
|
||||
rz_core_analysis_il_vm_set(core, ret_reg, val);
|
||||
}
|
||||
|
||||
if (rz_set_u_contains(msg_dispatch_addr, op->addr)) {
|
||||
// Devirtualize the message dispatch
|
||||
ut64 vf_addr = get_reg_value(core->analysis, m_reg);
|
||||
ut64 cmeta_addr = get_reg_value(core->analysis, cl_reg);
|
||||
|
||||
// Get function name called by message dispatch
|
||||
char *vmethod_name = get_message_dispatch_method(core, cmeta_addr, vf_addr);
|
||||
if (vmethod_name) {
|
||||
RzStrBuf *comment = rz_strbuf_new(NULL);
|
||||
rz_strbuf_setf(comment, "Message dispatch to %s", vmethod_name);
|
||||
const char *str_comment = rz_strbuf_drain(comment);
|
||||
rz_core_meta_comment_add(core, str_comment, start);
|
||||
RZ_FREE(str_comment);
|
||||
add_virtual_xrefs(core->analysis, vmethod_name, op->addr);
|
||||
}
|
||||
}
|
||||
start += op->size;
|
||||
offset += op->size;
|
||||
core->offset = start;
|
||||
rz_analysis_op_fini(op);
|
||||
}
|
||||
rz_set_u_free(xref_addrs);
|
||||
rz_analysis_op_free(op);
|
||||
free(bytes);
|
||||
}
|
||||
|
||||
static char *construct_reloc_name(RZ_NONNULL RzBinReloc *reloc, RZ_NULLABLE const char *name, bool demangle) {
|
||||
RzStrBuf *buf = rz_strbuf_new("");
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// (optional) libname_
|
||||
if (reloc->import && reloc->import->libname) {
|
||||
rz_strbuf_appendf(buf, "%s_", reloc->import->libname);
|
||||
} else if (reloc->symbol && reloc->symbol->libname) {
|
||||
rz_strbuf_appendf(buf, "%s_", reloc->symbol->libname);
|
||||
}
|
||||
|
||||
// actual name
|
||||
if (name) {
|
||||
rz_strbuf_append(buf, name);
|
||||
} else if (demangle && reloc->import && RZ_STR_ISNOTEMPTY(reloc->import->dname)) {
|
||||
rz_strbuf_append(buf, reloc->import->dname);
|
||||
} else if (reloc->import && RZ_STR_ISNOTEMPTY(reloc->import->name)) {
|
||||
rz_strbuf_append(buf, reloc->import->name);
|
||||
} else if (demangle && reloc->symbol && RZ_STR_ISNOTEMPTY(reloc->symbol->dname)) {
|
||||
rz_strbuf_appendf(buf, "%s", reloc->symbol->dname);
|
||||
} else if (reloc->symbol && RZ_STR_ISNOTEMPTY(reloc->symbol->name)) {
|
||||
rz_strbuf_appendf(buf, "%s", reloc->symbol->name);
|
||||
} else if (reloc->is_ifunc) {
|
||||
// addend is the function pointer for the resolving ifunc
|
||||
rz_strbuf_appendf(buf, "ifunc_%" PFMT64x, reloc->addend);
|
||||
} else {
|
||||
rz_strbuf_set(buf, "");
|
||||
}
|
||||
|
||||
return rz_strbuf_drain(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief devirtualize Objective-C message dispatch methods
|
||||
*
|
||||
* \param core The RzCore instance to work with.
|
||||
*/
|
||||
RZ_API void rz_analysis_devirtualize_objc_methods(RZ_NULLABLE RzCore *core) {
|
||||
if (!core) {
|
||||
RZ_LOG_ERROR("devirtualization analysis failed");
|
||||
return;
|
||||
}
|
||||
RzBinFile *bf = rz_bin_cur(core->bin);
|
||||
RzBinObject *obj = rz_bin_cur_object(core->bin);
|
||||
|
||||
if (!bf || !obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the binary file has message dispatch methods
|
||||
// First find in symbols, then in relocs
|
||||
bool msg_dispatch = false;
|
||||
RzVector *msg_dispatch_addrs = rz_vector_new(sizeof(ut64), NULL, NULL);
|
||||
|
||||
const RzPVector *symbols = rz_bin_object_get_symbols(bf->o);
|
||||
void **iter;
|
||||
rz_pvector_foreach (symbols, iter) {
|
||||
RzBinSymbol *symbol = *iter;
|
||||
if (!rz_str_cmp(symbol->name, "objc_msgSend", -1)) {
|
||||
msg_dispatch = true;
|
||||
rz_vector_push(msg_dispatch_addrs, &(symbol->vaddr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RzBinRelocStorage *relocs = rz_bin_object_patch_relocs(bf, obj);
|
||||
for (size_t i = 0; i < relocs->relocs_count; i++) {
|
||||
RzBinReloc *reloc = relocs->relocs[i];
|
||||
bool demangle = rz_config_get_b(core->config, "bin.demangle");
|
||||
char *name = construct_reloc_name(reloc, NULL, demangle);
|
||||
if (!rz_str_cmp(name, "objc_msgSend", -1)) {
|
||||
msg_dispatch = true;
|
||||
rz_vector_push(msg_dispatch_addrs, &(reloc->vaddr));
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
|
||||
RzSetU *msg_dispatch_xref_addr = rz_set_u_new();
|
||||
|
||||
// Note all xrefs to message dispatch
|
||||
ut64 *itt;
|
||||
rz_vector_foreach (msg_dispatch_addrs, itt) {
|
||||
ut64 addr = *itt;
|
||||
RzList *xref_list = rz_analysis_xrefs_get_to(core->analysis, addr);
|
||||
RzListIter *it;
|
||||
RzAnalysisXRef *xref;
|
||||
rz_list_foreach (xref_list, it, xref) {
|
||||
rz_set_u_add(msg_dispatch_xref_addr, xref->from);
|
||||
}
|
||||
rz_list_free(xref_list);
|
||||
}
|
||||
rz_vector_free(msg_dispatch_addrs);
|
||||
|
||||
if (msg_dispatch) {
|
||||
devirtualize_msg_dispatch(core, msg_dispatch_xref_addr);
|
||||
}
|
||||
rz_set_u_free(msg_dispatch_xref_addr);
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ rz_core_sources = [
|
|||
'cvfile.c',
|
||||
'csyscall.c',
|
||||
'devirtualize_cxx.c',
|
||||
'devirtualize_objc.c',
|
||||
'disasm.c',
|
||||
'fortune.c',
|
||||
'golang.c',
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@ typedef struct rz_analysis_t {
|
|||
char *sdb_types_path; ///< system path prefix, whether created in initialization or passed by RzCore.
|
||||
ut64 cmpval; ///< last compare value for jump table.
|
||||
ut64 lea_jmptbl_ip; ///< jump table x86 lea ip
|
||||
HtSP /*<const char *, RzSetU *>*/ *ht_cpp_virtual_xrefs; ///< addresses of cpp virtual function calls
|
||||
HtSP /*<const char *, RzSetU *>*/ *ht_virtual_xrefs; ///< addresses of virtual function calls
|
||||
} RzAnalysis;
|
||||
|
||||
typedef enum rz_analysis_addr_hint_type_t {
|
||||
|
|
@ -2304,7 +2304,8 @@ typedef struct rz_variable_book_t {
|
|||
} RzCppVariableBook;
|
||||
|
||||
RZ_API RzCppVariableBook *rz_analysis_mark_classes(RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_devirtualize_methods(RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_devirtualize_cxx_methods(RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_devirtualize_objc_methods(RZ_NULLABLE RzCore *core);
|
||||
RZ_API void rz_analysis_devirtualize(RzAnalysis *analysis, RzCppVariableBook *var_book);
|
||||
RZ_API void rz_analysis_virtual_xrefs_print(RzAnalysis *analysis, const char *vfunc);
|
||||
RZ_API void rz_analysis_virtual_xrefs_print_table(RzAnalysis *analysis, const char *vfunc, RzTable *table);
|
||||
|
|
|
|||
|
|
@ -724,4 +724,501 @@ EXPECT=<<EOF
|
|||
| 0x100002cf0 add sp, sp, 0x40
|
||||
\ 0x100002cf4 ret
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=objc msg dispatch (amd64)
|
||||
FILE=bins/mach0/objc-employee
|
||||
CMDS=<<EOF
|
||||
aaaa
|
||||
avD @ main
|
||||
pdf @ main
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
;-- main:
|
||||
;-- section.0.__TEXT.__text:
|
||||
;-- _main:
|
||||
;-- func.1000018c0:
|
||||
/ entry0(int64_t arg1, int64_t arg2);
|
||||
| ; arg int64_t arg1 @ rdi
|
||||
| ; arg int64_t arg2 @ rsi
|
||||
| ; var int var_a8h @ stack - 0xa8
|
||||
| ; var int var_a4h @ stack - 0xa4
|
||||
| ; var int var_a0h @ stack - 0xa0
|
||||
| ; var int var_9ch @ stack - 0x9c
|
||||
| ; var void *var_98h @ stack - 0x98
|
||||
| ; var int var_8ch @ stack - 0x8c
|
||||
| ; var void *var_88h @ stack - 0x88
|
||||
| ; var int var_7ch @ stack - 0x7c
|
||||
| ; var void *var_78h @ stack - 0x78
|
||||
| ; var int var_6ch @ stack - 0x6c
|
||||
| ; var void *var_68h @ stack - 0x68
|
||||
| ; var int64_t var_60h @ stack - 0x60
|
||||
| ; var int64_t var_58h @ stack - 0x58
|
||||
| ; var void *var_50h @ stack - 0x50
|
||||
| ; var int64_t var_48h @ stack - 0x48
|
||||
| ; var const char *var_40h @ stack - 0x40
|
||||
| ; var int64_t var_34h @ stack - 0x34
|
||||
| ; var int64_t var_30h @ stack - 0x30
|
||||
| ; var void *var_28h @ stack - 0x28
|
||||
| ; var const char **format @ stack - 0x20
|
||||
| ; var int64_t var_18h @ stack - 0x18
|
||||
| ; var int64_t var_10h @ stack - 0x10
|
||||
| ; var int64_t var_ch @ stack - 0xc
|
||||
| 0x1000018c0 push rbp ; [00] -r-x section size 1126 named 0.__TEXT.__text
|
||||
| 0x1000018c1 mov rbp, rsp
|
||||
| 0x1000018c4 sub rsp, 0xb0
|
||||
| 0x1000018cb mov dword [var_ch], 0x00
|
||||
| 0x1000018d2 mov dword [var_10h], edi ; arg1
|
||||
| 0x1000018d5 mov qword [var_18h], rsi ; arg2
|
||||
| 0x1000018d9 call sym.imp.objc_autoreleasePoolPush
|
||||
| 0x1000018de lea rsi, qword reloc.__CFConstantStringClassReference ; str.cstr.Hello_World_Object
|
||||
| ; 0x100002010
|
||||
| 0x1000018e5 mov rdi, rsi
|
||||
| 0x1000018e8 mov qword [var_48h], rax
|
||||
| 0x1000018ec mov al, 0x00
|
||||
| 0x1000018ee call sym.imp.NSLog
|
||||
| 0x1000018f3 mov rsi, qword [section.15.__DATA.__objc_classrefs] ; [0x100003320:8]=0x100003370 sym.class_Employee ; "p3"
|
||||
| 0x1000018fa mov rdi, rsi
|
||||
| 0x1000018fd call sym.imp.objc_alloc_init
|
||||
| 0x100001902 mov qword [format], rax
|
||||
| 0x100001906 mov rax, qword [format]
|
||||
| 0x10000190a mov rsi, qword [section.14.__DATA.__objc_selrefs] ; [0x1000032f8:8]=0x100001ecf section.4.__TEXT.__objc_methname
|
||||
| 0x100001911 mov rdi, rax
|
||||
| 0x100001914 call qword [reloc.objc_msgSend] ; [0x100002000:8]=0 ; Message dispatch to method_Employee_sayHello
|
||||
| 0x10000191a mov rsi, qword [section.15.__DATA.__objc_classrefs] ; [0x100003320:8]=0x100003370 sym.class_Employee ; "p3"
|
||||
| 0x100001921 mov rdi, qword [section.14.__DATA.__objc_selrefs] ; [0x1000032f8:8]=0x100001ecf section.4.__TEXT.__objc_methname
|
||||
| 0x100001928 mov qword [var_50h], rdi
|
||||
| 0x10000192c mov rdi, rsi
|
||||
| 0x10000192f mov rsi, qword [var_50h]
|
||||
| 0x100001933 mov qword [var_58h], rax
|
||||
| 0x100001937 call qword [reloc.objc_msgSend] ; [0x100002000:8]=0 ; Message dispatch to method_Employee_sayHello
|
||||
| 0x10000193d mov rsi, qword [format]
|
||||
| 0x100001941 lea rdi, qword str.base__p ; 0x100001dbe ; "base %p\n" ; const char *format
|
||||
| 0x100001948 mov qword [var_60h], rax
|
||||
| 0x10000194c mov al, 0x00
|
||||
| 0x10000194e call sym.imp.printf ; int printf(const char *format)
|
||||
| 0x100001953 mov rsi, qword [format]
|
||||
| 0x100001957 mov qword [var_28h], rsi
|
||||
| 0x10000195b mov rsi, qword [format]
|
||||
| 0x10000195f mov rdi, qword [data.100003300] ; [0x100003300:8]=0x100001ed8 "p0"
|
||||
| 0x100001966 mov qword [var_68h], rdi
|
||||
| 0x10000196a mov rdi, rsi
|
||||
| 0x10000196d mov rsi, qword [var_68h]
|
||||
| 0x100001971 mov dword [var_6ch], eax
|
||||
| 0x100001974 call qword [reloc.objc_msgSend] ; [0x100002000:8]=0
|
||||
| 0x10000197a mov rsi, qword [var_28h]
|
||||
| 0x10000197e sub rax, rsi
|
||||
| 0x100001981 lea rdi, qword str.iii__p__username ; 0x100001dc7 ; "iii %p _username\n" ; const char *format
|
||||
| 0x100001988 mov rsi, rax
|
||||
| 0x10000198b mov al, 0x00
|
||||
| 0x10000198d call sym.imp.printf ; int printf(const char *format)
|
||||
| 0x100001992 mov rsi, qword [format]
|
||||
| 0x100001996 mov rdi, qword [data.100003308] ; [0x100003308:8]=0x100001edb "p1"
|
||||
| 0x10000199d mov qword [var_78h], rdi
|
||||
| 0x1000019a1 mov rdi, rsi
|
||||
| 0x1000019a4 mov rsi, qword [var_78h]
|
||||
| 0x1000019a8 mov dword [var_7ch], eax
|
||||
| 0x1000019ab call qword [reloc.objc_msgSend] ; [0x100002000:8]=0
|
||||
| 0x1000019b1 mov rsi, qword [var_28h]
|
||||
| 0x1000019b5 sub rax, rsi
|
||||
| 0x1000019b8 lea rdi, qword str.iii__p__firstName ; 0x100001dd9 ; "iii %p _firstName\n" ; const char *format
|
||||
| 0x1000019bf mov rsi, rax
|
||||
| 0x1000019c2 mov al, 0x00
|
||||
| 0x1000019c4 call sym.imp.printf ; int printf(const char *format)
|
||||
| 0x1000019c9 mov rsi, qword [format]
|
||||
| 0x1000019cd mov rdi, qword [data.100003310] ; [0x100003310:8]=0x100001ede "p2"
|
||||
| 0x1000019d4 mov qword [var_88h], rdi
|
||||
| 0x1000019d8 mov rdi, rsi
|
||||
| 0x1000019db mov rsi, qword [var_88h]
|
||||
| 0x1000019df mov dword [var_8ch], eax
|
||||
| 0x1000019e5 call qword [reloc.objc_msgSend] ; [0x100002000:8]=0
|
||||
| 0x1000019eb mov rsi, qword [var_28h]
|
||||
| 0x1000019ef sub rax, rsi
|
||||
| 0x1000019f2 lea rdi, qword str.iii__p__shortWord ; 0x100001dec ; "iii %p _shortWord\n" ; const char *format
|
||||
| 0x1000019f9 mov rsi, rax
|
||||
| 0x1000019fc mov al, 0x00
|
||||
| 0x1000019fe call sym.imp.printf ; int printf(const char *format)
|
||||
| 0x100001a03 mov rsi, qword [format]
|
||||
| 0x100001a07 mov rdi, qword [data.100003318] ; [0x100003318:8]=0x100001ee1 "p3"
|
||||
| 0x100001a0e mov qword [var_98h], rdi
|
||||
| 0x100001a15 mov rdi, rsi
|
||||
| 0x100001a18 mov rsi, qword [var_98h]
|
||||
| 0x100001a1f mov dword [var_9ch], eax
|
||||
| 0x100001a25 call qword [reloc.objc_msgSend] ; [0x100002000:8]=0
|
||||
| 0x100001a2b mov rsi, qword [var_28h]
|
||||
| 0x100001a2f sub rax, rsi
|
||||
| 0x100001a32 lea rdi, qword str.iii__p__wideWord ; 0x100001dff ; "iii %p _wideWord\n" ; const char *format
|
||||
| 0x100001a39 mov rsi, rax
|
||||
| 0x100001a3c mov al, 0x00
|
||||
| 0x100001a3e call sym.imp.printf ; int printf(const char *format)
|
||||
| 0x100001a43 mov rsi, qword [format]
|
||||
| 0x100001a47 mov qword [var_30h], rsi
|
||||
| 0x100001a4b mov dword [var_34h], 0x00
|
||||
| 0x100001a52 mov dword [var_a0h], eax
|
||||
| ; CODE XREF from entry0 @ 0x100001a8b
|
||||
| .-> 0x100001a58 cmp dword [var_34h], 0x20
|
||||
| ,==< 0x100001a5c jnl 0x100001a90
|
||||
| |: 0x100001a62 mov rax, qword [var_30h]
|
||||
| |: 0x100001a66 movsxd rcx, dword [var_34h]
|
||||
| |: 0x100001a6a movzx esi, byte [rax+rcx*1]
|
||||
| |: 0x100001a6e lea rdi, qword str.02x ; 0x100001e11 ; "%02x " ; const char *format
|
||||
| |: 0x100001a75 mov al, 0x00
|
||||
| |: 0x100001a77 call sym.imp.printf ; int printf(const char *format)
|
||||
| |: 0x100001a7c mov dword [var_a4h], eax
|
||||
| |: 0x100001a82 mov eax, dword [var_34h]
|
||||
| |: 0x100001a85 add eax, 0x01
|
||||
| |: 0x100001a88 mov dword [var_34h], eax
|
||||
| |`=< 0x100001a8b jmp 0x100001a58
|
||||
| `--> 0x100001a90 lea rdi, qword data.100001e17 ; 0x100001e17 ; "\n" ; const char *format
|
||||
| 0x100001a97 mov al, 0x00
|
||||
| 0x100001a99 call sym.imp.printf ; int printf(const char *format)
|
||||
| 0x100001a9e lea rdi, qword reloc.__CFConstantStringClassReference.100002030 ; rsi
|
||||
| ; 0x100002030
|
||||
| 0x100001aa5 mov qword [var_40h], rdi
|
||||
| 0x100001aa9 mov rsi, qword [var_40h]
|
||||
| 0x100001aad lea rdi, qword data.100001e28 ; 0x100001e28 ; "%p\n" ; const char *format
|
||||
| 0x100001ab4 mov dword [var_a8h], eax
|
||||
| 0x100001aba mov al, 0x00
|
||||
| 0x100001abc call sym.imp.printf ; int printf(const char *format)
|
||||
\ 0x100001ac1 int3
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=objc msg dispatch (arm64)
|
||||
FILE=bins/mach0/objc-employee-ios14-arm64
|
||||
CMDS=<<EOF
|
||||
aaaa
|
||||
avD @ main
|
||||
pdf @ main
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
; UNKNOWN XREF from segment.TEXT @ +0xd0
|
||||
;-- main:
|
||||
;-- section.0.__TEXT.__text:
|
||||
;-- _main:
|
||||
;-- func.100007714:
|
||||
/ entry0(int64_t arg1, int64_t arg2);
|
||||
| ; arg int64_t arg1 @ x0
|
||||
| ; arg int64_t arg2 @ x1
|
||||
| ; var int64_t var_80h @ stack - 0x80
|
||||
| ; var int64_t var_68h @ stack - 0x68
|
||||
| ; var int64_t var_60h @ stack - 0x60
|
||||
| ; var int64_t var_58h @ stack - 0x58
|
||||
| ; var int64_t var_50h @ stack - 0x50
|
||||
| ; var int64_t var_48h @ stack - 0x48
|
||||
| ; var int64_t var_3ch @ stack - 0x3c
|
||||
| ; var int64_t var_38h @ stack - 0x38
|
||||
| ; var int64_t var_30h @ stack - 0x30
|
||||
| ; var int64_t var_28h @ stack - 0x28
|
||||
| ; var int64_t var_20h @ stack - 0x20
|
||||
| ; var int64_t var_18h @ stack - 0x18
|
||||
| ; var int64_t var_14h @ stack - 0x14
|
||||
| ; var int64_t var_10h @ stack - 0x10
|
||||
| ; var int64_t var_8h @ stack - 0x8
|
||||
| 0x100007714 sub sp, sp, 0x80 ; [00] -r-x section size 1180 named 0.__TEXT.__text
|
||||
| 0x100007718 stp fp, lr, [var_10h]
|
||||
| 0x10000771c add fp, sp, 0x70
|
||||
| 0x100007720 stur wzr, [var_14h] ; arg1
|
||||
| 0x100007724 stur w0, [var_18h] ; arg1
|
||||
| 0x100007728 stur x1, [var_20h] ; arg2
|
||||
| 0x10000772c bl fcn.100007bd4
|
||||
| 0x100007730 adrp x8, reloc.dyld_stub_binder ; 0x100008000
|
||||
| 0x100007734 add x8, x8, 8 ; 0x100008008
|
||||
| ; reloc.__CFConstantStringClassReference
|
||||
| 0x100007738 str x0, [var_50h]
|
||||
| 0x10000773c mov x0, x8
|
||||
| 0x100007740 bl section.1.__TEXT.__stubs ; section.1.__TEXT.__stubs(void)
|
||||
| 0x100007744 adrp x8, reloc.NSLog ; 0x10000c000
|
||||
| 0x100007748 add x8, x8, 0x220 ; 0x10000c220 ; "`\xc2"
|
||||
| 0x10000774c ldr x0, [x8] ; [0x10000c220:4]=0xc260 ; "`\xc2"
|
||||
| 0x100007750 str x8, [var_58h]
|
||||
| 0x100007754 bl fcn.100007bbc
|
||||
| 0x100007758 stur x0, [var_28h]
|
||||
| 0x10000775c ldur x0, [var_28h]
|
||||
| 0x100007760 adrp x8, reloc.NSLog ; 0x10000c000
|
||||
| 0x100007764 add x8, x8, 0x1f0
|
||||
| 0x100007768 ldr x1, [x8] ; [0x100007ea9:4]=0x48796173 ; "sayHello"
|
||||
| 0x10000776c str x8, [var_60h]
|
||||
| 0x100007770 bl fcn.100007bec ; Message dispatch to method_Employee_sayHello
|
||||
| 0x100007774 ldr x8, [var_58h] ; [0x28:4]=-1 ; 40
|
||||
| 0x100007778 ldr x0, [x8]
|
||||
| 0x10000777c ldr x9, [var_60h] ; [0x20:4]=-1 ; 32
|
||||
| 0x100007780 ldr x1, [x9]
|
||||
| 0x100007784 bl fcn.100007bec ; Message dispatch to method_Employee_sayHello
|
||||
| 0x100007788 ldur x8, [var_28h]
|
||||
| 0x10000778c adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007790 add x0, x0, 0xd98 ; 0x100007d98 ; "base %p\n"
|
||||
| 0x100007794 mov x9, sp
|
||||
| 0x100007798 str x8, [x9]
|
||||
| 0x10000779c bl fcn.100007c1c
|
||||
| 0x1000077a0 ldur x8, [var_28h]
|
||||
| 0x1000077a4 adrp x9, reloc.NSLog ; 0x10000c000
|
||||
| 0x1000077a8 add x9, x9, 0x1f8
|
||||
| 0x1000077ac ldr x1, [x9] ; [0x100007eb2:4]=0x65736162 ; "base"
|
||||
| 0x1000077b0 mov x0, x8
|
||||
| 0x1000077b4 bl fcn.100007bec ; Message dispatch to method_Employee_base
|
||||
| 0x1000077b8 stur x0, [var_30h]
|
||||
| 0x1000077bc ldur x0, [var_28h]
|
||||
| 0x1000077c0 adrp x8, reloc.NSLog ; 0x10000c000
|
||||
| 0x1000077c4 add x8, x8, 0x200
|
||||
| 0x1000077c8 ldr x1, [x8]
|
||||
| 0x1000077cc bl fcn.100007bec
|
||||
| 0x1000077d0 ldur x8, [var_30h]
|
||||
| 0x1000077d4 subs x8, x0, x8
|
||||
| 0x1000077d8 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x1000077dc add x0, x0, 0xda1 ; 0x100007da1 ; "iii %p _username\n"
|
||||
| 0x1000077e0 mov x9, sp
|
||||
| 0x1000077e4 str x8, [x9]
|
||||
| 0x1000077e8 bl fcn.100007c1c
|
||||
| 0x1000077ec ldur x8, [var_28h]
|
||||
| 0x1000077f0 adrp x9, reloc.NSLog ; 0x10000c000
|
||||
| 0x1000077f4 add x9, x9, 0x208
|
||||
| 0x1000077f8 ldr x1, [x9]
|
||||
| 0x1000077fc mov x0, x8
|
||||
| 0x100007800 bl fcn.100007bec
|
||||
| 0x100007804 ldur x8, [var_30h]
|
||||
| 0x100007808 subs x8, x0, x8
|
||||
| 0x10000780c adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007810 add x0, x0, 0xdb3 ; 0x100007db3 ; "iii %p _firstName\n"
|
||||
| 0x100007814 mov x9, sp
|
||||
| 0x100007818 str x8, [x9]
|
||||
| 0x10000781c bl fcn.100007c1c
|
||||
| 0x100007820 ldur x8, [var_28h]
|
||||
| 0x100007824 adrp x9, reloc.NSLog ; 0x10000c000
|
||||
| 0x100007828 add x9, x9, 0x210
|
||||
| 0x10000782c ldr x1, [x9]
|
||||
| 0x100007830 mov x0, x8
|
||||
| 0x100007834 bl fcn.100007bec
|
||||
| 0x100007838 ldur x8, [var_30h]
|
||||
| 0x10000783c subs x8, x0, x8
|
||||
| 0x100007840 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007844 add x0, x0, 0xdc6 ; 0x100007dc6 ; "iii %p _shortWord\n"
|
||||
| 0x100007848 mov x9, sp
|
||||
| 0x10000784c str x8, [x9]
|
||||
| 0x100007850 bl fcn.100007c1c
|
||||
| 0x100007854 ldur x8, [var_28h]
|
||||
| 0x100007858 adrp x9, reloc.NSLog ; 0x10000c000
|
||||
| 0x10000785c add x9, x9, 0x218
|
||||
| 0x100007860 ldr x1, [x9]
|
||||
| 0x100007864 mov x0, x8
|
||||
| 0x100007868 bl fcn.100007bec
|
||||
| 0x10000786c ldur x8, [var_30h]
|
||||
| 0x100007870 subs x8, x0, x8
|
||||
| 0x100007874 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007878 add x0, x0, 0xdd9 ; 0x100007dd9 ; "iii %p _wideWord\n"
|
||||
| 0x10000787c mov x9, sp
|
||||
| 0x100007880 str x8, [x9]
|
||||
| 0x100007884 bl fcn.100007c1c
|
||||
| 0x100007888 ldur x8, [var_28h]
|
||||
| 0x10000788c stur x8, [var_38h]
|
||||
| 0x100007890 stur wzr, [var_3ch]
|
||||
| ; CODE XREF from entry0 @ 0x1000078d0
|
||||
| .-> 0x100007894 ldur w8, [var_3ch]
|
||||
| : 0x100007898 cmp w8, 0x20
|
||||
| ,==< 0x10000789c b.ge 0x1000078d4
|
||||
| |: 0x1000078a0 ldur x8, [var_38h]
|
||||
| |: 0x1000078a4 ldursw x9, [var_3ch]
|
||||
| |: 0x1000078a8 ldrb w10, [x8, x9]
|
||||
| |: 0x1000078ac adrp x0, data.100007000 ; 0x100007000
|
||||
| |: 0x1000078b0 add x0, x0, 0xdeb ; 0x100007deb ; "%02x "
|
||||
| |: 0x1000078b4 mov x8, sp
|
||||
| |: 0x1000078b8 mov x1, x10
|
||||
| |: 0x1000078bc str x1, [x8]
|
||||
| |: 0x1000078c0 bl fcn.100007c1c
|
||||
| |: 0x1000078c4 ldur w8, [var_3ch]
|
||||
| |: 0x1000078c8 add w8, w8, 1
|
||||
| |: 0x1000078cc stur w8, [var_3ch]
|
||||
| |`=< 0x1000078d0 b 0x100007894
|
||||
| `--> 0x1000078d4 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x1000078d8 add x0, x0, 0xdf1
|
||||
| 0x1000078dc bl fcn.100007c1c
|
||||
| 0x1000078e0 adrp x8, reloc.dyld_stub_binder ; 0x100008000
|
||||
| 0x1000078e4 add x8, x8, 0x28 ; 0x100008028
|
||||
| ; x9
|
||||
| 0x1000078e8 mov x0, x8
|
||||
| 0x1000078ec bl fcn.100007bf8
|
||||
| 0x1000078f0 add x8, var_48h
|
||||
| 0x1000078f4 str x0, [var_48h]
|
||||
| 0x1000078f8 ldr x9, [var_48h] ; x1
|
||||
| ; [0x38:4]=-1
|
||||
| 0x1000078fc adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007900 add x0, x0, 0xe02 ; 0x100007e02 ; "%p\n"
|
||||
| 0x100007904 mov x10, sp
|
||||
| 0x100007908 str x9, [x10]
|
||||
| 0x10000790c str x8, [var_68h]
|
||||
| 0x100007910 bl fcn.100007c1c
|
||||
| ;-- x30:
|
||||
| ;-- lr:
|
||||
| ;-- pc:
|
||||
\ 0x100007914 brk 1
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=objc msg dispatch (arm64)
|
||||
FILE=bins/mach0/objc-employee-ios14-arm64e
|
||||
CMDS=<<EOF
|
||||
aaaa
|
||||
avD @ main
|
||||
pdf @ main
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
; UNKNOWN XREF from segment.TEXT @ +0xd0
|
||||
;-- main:
|
||||
;-- section.0.__TEXT.__text:
|
||||
;-- _main:
|
||||
;-- func.100007760:
|
||||
/ entry0(int64_t arg1, int64_t arg2);
|
||||
| ; arg int64_t arg1 @ x0
|
||||
| ; arg int64_t arg2 @ x1
|
||||
| ; var int64_t var_80h @ stack - 0x80
|
||||
| ; var int64_t var_68h @ stack - 0x68
|
||||
| ; var int64_t var_60h @ stack - 0x60
|
||||
| ; var int64_t var_58h @ stack - 0x58
|
||||
| ; var int64_t var_50h @ stack - 0x50
|
||||
| ; var int64_t var_48h @ stack - 0x48
|
||||
| ; var int64_t var_3ch @ stack - 0x3c
|
||||
| ; var int64_t var_38h @ stack - 0x38
|
||||
| ; var int64_t var_30h @ stack - 0x30
|
||||
| ; var void *instance @ stack - 0x28
|
||||
| ; var int64_t var_20h @ stack - 0x20
|
||||
| ; var int64_t var_18h @ stack - 0x18
|
||||
| ; var int64_t var_14h @ stack - 0x14
|
||||
| ; var int64_t var_10h @ stack - 0x10
|
||||
| ; var int64_t var_8h @ stack - 0x8
|
||||
| 0x100007760 pacibsp ; [00] -r-x section size 1208 named 0.__TEXT.__text
|
||||
| 0x100007764 sub sp, sp, 0x80
|
||||
| 0x100007768 stp fp, lr, [var_10h]
|
||||
| 0x10000776c add fp, sp, 0x70
|
||||
| 0x100007770 stur wzr, [var_14h] ; arg1
|
||||
| 0x100007774 stur w0, [var_18h] ; arg1
|
||||
| 0x100007778 stur x1, [var_20h] ; arg2
|
||||
| 0x10000777c bl sym.imp.objc_autoreleasePoolPush
|
||||
| 0x100007780 adrp x8, reloc.NSLog ; 0x100008000
|
||||
| 0x100007784 add x8, x8, 0x50 ; 0x100008050 ; "X\x80\U00000001"
|
||||
| 0x100007788 str x0, [var_50h]
|
||||
| 0x10000778c mov x0, x8
|
||||
| 0x100007790 bl sym.imp.NSLog
|
||||
| 0x100007794 adrp x8, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|
||||
| 0x100007798 add x8, x8, 0x1d0 ; 0x10000c1d0
|
||||
| ; section.14.__DATA.__objc_classrefs
|
||||
| 0x10000779c ldr x0, [x8] ; [0x10000c1d0:4]=0xc210 ; section.14.__DATA.__objc_classrefs
|
||||
| 0x1000077a0 str x8, [var_58h]
|
||||
| 0x1000077a4 bl sym.imp.objc_alloc_init
|
||||
| 0x1000077a8 stur x0, [instance]
|
||||
| 0x1000077ac ldur x0, [instance] ; void *instance
|
||||
| 0x1000077b0 adrp x8, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|
||||
| 0x1000077b4 add x8, x8, 0x1a0
|
||||
| 0x1000077b8 ldr x1, [x8] ; [0x100007ea9:4]=0x48796173 ; "sayHello" ; char *selector
|
||||
| 0x1000077bc str x8, [var_60h]
|
||||
| 0x1000077c0 bl sym.imp.objc_msgSend ; Message dispatch to method_Employee_sayHello ; void *objc_msgSend(void *instance, char *selector)
|
||||
| 0x1000077c4 ldr x8, [var_58h] ; [0x28:4]=-1 ; 40
|
||||
| 0x1000077c8 ldr x0, [x8] ; void *instance
|
||||
| 0x1000077cc ldr x9, [var_60h] ; [0x20:4]=-1 ; 32
|
||||
| 0x1000077d0 ldr x1, [x9] ; char *selector
|
||||
| 0x1000077d4 bl sym.imp.objc_msgSend ; Message dispatch to method_Employee_sayHello ; void *objc_msgSend(void *instance, char *selector)
|
||||
| 0x1000077d8 ldur x8, [instance]
|
||||
| 0x1000077dc adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x1000077e0 add x0, x0, 0xd98 ; 0x100007d98 ; "base %p\n" ; const char *format
|
||||
| 0x1000077e4 mov x9, sp
|
||||
| 0x1000077e8 str x8, [x9]
|
||||
| 0x1000077ec bl sym.imp.printf ; int printf(const char *format)
|
||||
| 0x1000077f0 ldur x8, [instance]
|
||||
| 0x1000077f4 adrp x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|
||||
| 0x1000077f8 add x9, x9, 0x1a8
|
||||
| 0x1000077fc ldr x1, [x9] ; [0x100007eb2:4]=0x65736162 ; "base" ; char *selector
|
||||
| 0x100007800 mov x0, x8 ; void *instance
|
||||
| 0x100007804 bl sym.imp.objc_msgSend ; Message dispatch to method_Employee_base ; void *objc_msgSend(void *instance, char *selector)
|
||||
| 0x100007808 stur x0, [var_30h]
|
||||
| 0x10000780c ldur x0, [instance] ; void *instance
|
||||
| 0x100007810 adrp x8, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|
||||
| 0x100007814 add x8, x8, 0x1b0
|
||||
| 0x100007818 ldr x1, [x8] ; char *selector
|
||||
| 0x10000781c bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
|
||||
| 0x100007820 ldur x8, [var_30h]
|
||||
| 0x100007824 subs x8, x0, x8
|
||||
| 0x100007828 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x10000782c add x0, x0, 0xda1 ; 0x100007da1 ; "iii %p _username\n" ; const char *format
|
||||
| 0x100007830 mov x9, sp
|
||||
| 0x100007834 str x8, [x9]
|
||||
| 0x100007838 bl sym.imp.printf ; int printf(const char *format)
|
||||
| 0x10000783c ldur x8, [instance]
|
||||
| 0x100007840 adrp x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|
||||
| 0x100007844 add x9, x9, 0x1b8
|
||||
| 0x100007848 ldr x1, [x9] ; char *selector
|
||||
| 0x10000784c mov x0, x8 ; void *instance
|
||||
| 0x100007850 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
|
||||
| 0x100007854 ldur x8, [var_30h]
|
||||
| 0x100007858 subs x8, x0, x8
|
||||
| 0x10000785c adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007860 add x0, x0, 0xdb3 ; 0x100007db3 ; "iii %p _firstName\n" ; const char *format
|
||||
| 0x100007864 mov x9, sp
|
||||
| 0x100007868 str x8, [x9]
|
||||
| 0x10000786c bl sym.imp.printf ; int printf(const char *format)
|
||||
| 0x100007870 ldur x8, [instance]
|
||||
| 0x100007874 adrp x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|
||||
| 0x100007878 add x9, x9, 0x1c0
|
||||
| 0x10000787c ldr x1, [x9] ; char *selector
|
||||
| 0x100007880 mov x0, x8 ; void *instance
|
||||
| 0x100007884 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
|
||||
| 0x100007888 ldur x8, [var_30h]
|
||||
| 0x10000788c subs x8, x0, x8
|
||||
| 0x100007890 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007894 add x0, x0, 0xdc6 ; 0x100007dc6 ; "iii %p _shortWord\n" ; const char *format
|
||||
| 0x100007898 mov x9, sp
|
||||
| 0x10000789c str x8, [x9]
|
||||
| 0x1000078a0 bl sym.imp.printf ; int printf(const char *format)
|
||||
| 0x1000078a4 ldur x8, [instance]
|
||||
| 0x1000078a8 adrp x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|
||||
| 0x1000078ac add x9, x9, 0x1c8
|
||||
| 0x1000078b0 ldr x1, [x9] ; char *selector
|
||||
| 0x1000078b4 mov x0, x8 ; void *instance
|
||||
| 0x1000078b8 bl sym.imp.objc_msgSend ; void *objc_msgSend(void *instance, char *selector)
|
||||
| 0x1000078bc ldur x8, [var_30h]
|
||||
| 0x1000078c0 subs x8, x0, x8
|
||||
| 0x1000078c4 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x1000078c8 add x0, x0, 0xdd9 ; 0x100007dd9 ; "iii %p _wideWord\n" ; const char *format
|
||||
| 0x1000078cc mov x9, sp
|
||||
| 0x1000078d0 str x8, [x9]
|
||||
| 0x1000078d4 bl sym.imp.printf ; int printf(const char *format)
|
||||
| 0x1000078d8 ldur x8, [instance]
|
||||
| 0x1000078dc stur x8, [var_38h]
|
||||
| 0x1000078e0 stur wzr, [var_3ch]
|
||||
| ; CODE XREF from entry0 @ 0x100007920
|
||||
| .-> 0x1000078e4 ldur w8, [var_3ch]
|
||||
| : 0x1000078e8 cmp w8, 0x20
|
||||
| ,==< 0x1000078ec b.ge 0x100007924
|
||||
| |: 0x1000078f0 ldur x8, [var_38h]
|
||||
| |: 0x1000078f4 ldursw x9, [var_3ch]
|
||||
| |: 0x1000078f8 ldrb w10, [x8, x9]
|
||||
| |: 0x1000078fc adrp x0, data.100007000 ; 0x100007000
|
||||
| |: 0x100007900 add x0, x0, 0xdeb ; 0x100007deb ; "%02x " ; const char *format
|
||||
| |: 0x100007904 mov x8, sp
|
||||
| |: 0x100007908 mov x1, x10
|
||||
| |: 0x10000790c str x1, [x8]
|
||||
| |: 0x100007910 bl sym.imp.printf ; int printf(const char *format)
|
||||
| |: 0x100007914 ldur w8, [var_3ch]
|
||||
| |: 0x100007918 add w8, w8, 1
|
||||
| |: 0x10000791c stur w8, [var_3ch]
|
||||
| |`=< 0x100007920 b 0x1000078e4
|
||||
| `--> 0x100007924 adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007928 add x0, x0, 0xdf1 ; const char *format
|
||||
| 0x10000792c bl sym.imp.printf ; int printf(const char *format)
|
||||
| 0x100007930 adrp x8, reloc.NSLog ; 0x100008000
|
||||
| 0x100007934 add x8, x8, 0x70 ; 0x100008070 ; "X\x80\U00000001"
|
||||
| 0x100007938 mov x0, x8 ; void *instance
|
||||
| 0x10000793c bl sym.imp.objc_retain ; void objc_retain(void *instance)
|
||||
| 0x100007940 add x8, var_48h
|
||||
| 0x100007944 str x0, [var_48h]
|
||||
| 0x100007948 ldr x9, [var_48h] ; [0x38:4]=-1 ; 56
|
||||
| 0x10000794c adrp x0, data.100007000 ; 0x100007000
|
||||
| 0x100007950 add x0, x0, 0xe02 ; 0x100007e02 ; "%p\n" ; const char *format
|
||||
| 0x100007954 mov x10, sp
|
||||
| 0x100007958 str x9, [x10]
|
||||
| 0x10000795c str x8, [var_68h]
|
||||
| 0x100007960 bl sym.imp.printf ; int printf(const char *format)
|
||||
| ;-- x30:
|
||||
| ;-- lr:
|
||||
| ;-- pc:
|
||||
\ 0x100007964 brk 1
|
||||
EOF
|
||||
RUN
|
||||
|
|
@ -41,4 +41,45 @@ EXPECT=<<EOF
|
|||
0x10000289c
|
||||
0x10000290c
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=objc message dispatch (amd64)
|
||||
FILE=bins/mach0/objc-employee
|
||||
CMDS=<<EOF
|
||||
aaaa
|
||||
avD @ main
|
||||
avx method_Employee_sayHello
|
||||
avxt method_Employee_sayHello
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
Virtual xrefs to method_Employee_sayHello
|
||||
C 0x100001914 call qword [reloc.objc_msgSend]
|
||||
C 0x100001937 call qword [reloc.objc_msgSend]
|
||||
from
|
||||
------------
|
||||
0x100001914
|
||||
0x100001937
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=objc msg dispatch (arm64)
|
||||
FILE=bins/mach0/objc-employee-ios14-arm64e
|
||||
CMDS=<<EOF
|
||||
aaaa
|
||||
avD @ main
|
||||
avx method_Employee_base
|
||||
avx method_Employee_sayHello
|
||||
avxt method_Employee_sayHello
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
Virtual xrefs to method_Employee_base
|
||||
C 0x100007804 bl sym.imp.objc_msgSend
|
||||
Virtual xrefs to method_Employee_sayHello
|
||||
C 0x1000077d4 bl sym.imp.objc_msgSend
|
||||
C 0x1000077c0 bl sym.imp.objc_msgSend
|
||||
from
|
||||
------------
|
||||
0x1000077d4
|
||||
0x1000077c0
|
||||
EOF
|
||||
RUN
|
||||
Loading…
Reference in a new issue