ios objc 方法调用记录插件itracer v1.2如果你想逆向 某些app的调用流程 或者 系统app的一些功能的 私有 framework class api 调用流程,只需要 配置需要挂接的 类名和app名, 就可以实时追踪 相关功能的 调用流程。
问题是原函数是hook过来的,是由hook的进程执行的。
/* //////////////////////////////////////////////////////////////////////////////////////
- macros for arm64
/
// str xt, [xn, #im]!
#define A64$str_xt_$xn_im$(xt, xn, im) (0xf8000c00 | (((im) & 0x1ff) << 12) | (((xn) & 0x1f) << 5) | ((xt) & 0x1f))
// ldr xt, [xn], #im
#define A64$ldr_xt_$xn$im(xt, xn, im) (0xf8400400 | (((im) & 0x1ff) << 12) | (((xn) & 0x1f) << 5) | ((xt) & 0x1f))
// stp xt1, xt2, [xn, #im]!
#define A64$stp_xt1_xt2$xn_im$(xt1, xt2, xn, im) (0xa9800000 | ((((im) >> 3) & 0x7f) << 15) | (((xt2) & 0x1f) << 10) | (((xn) & 0x1f) << 5) | ((xt1) & 0x1f))
// ldp xt1, xt2, [xn], #im
#define A64$ldp_xt1_xt2_$xn$_im(xt1, xt2, xn, im) (0xa8c00000 | ((((im) >> 3) & 0x7f) << 15) | (((xt2) & 0x1f) << 10) | (((xn) & 0x1f) << 5) | ((xt1) & 0x1f))
// movz xd, #im, lsl #shift
#define A64$movz_xd_im(xd, im, shift) (0xd2800000 | (((shift) >> 4) << 21) | (((im) & 0xffff) << 5) | ((xd) & 0x1f))
// movk xd, #im, lsl #shift
#define A64$movk_xd_im(xd, im, shift) (0xf2800000 | (((shift) >> 4) << 21) | (((im) & 0xffff) << 5) | ((xd) & 0x1f))
// br xn
#define A64$br(xn) (0xd61f0000 | (((xn) & 0x1f) << 5))
// blr xn
#define A64$blr(xn) (0xd63f0000 | (((xn) & 0x1f) << 5))
// ret xn
#define A64$ret(xn) (0xd65f0000 | (((xn) & 0x1f) << 5))
// ldr xt, #im
#define A64$ldr_xt_im(xt, im) (0x58000000 | ((((im) >> 2) & 0xfffff) << 5) | ((xt) & 0x1f))
/ //////////////////////////////////////////////////////////////////////////////////////
- macros for arm
/
// ldr rd, [rn, #im]
#define A$ldr_rd_$rn_im$(rd, rn, im) (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im))
// movw rd, #im
#define A$movw_rd_im(rd, im) (0xe3000000 | (((im) & 0xf000) << 4) | ((rd) << 12) | ((im) & 0x0fff))
// movt rd, #im
#define A$movt_rd_im(rd, im) (0xe3400000 | (((im) & 0xf000) << 4) | ((rd) << 12) | ((im) & 0x0fff))
// push {r0-r9, lr}
#define A$push$r0_r9_lr$ (0xe92d43ff)
// pop {r0-r9, lr}
#define A$pop$r0_r9_lr$ (0xe8bd43ff)
// blx rm
#define A$blx(rm) (0xe12fff30 | ((rm) & 0x0000000f))
// nop
#define A$nop (0xe1a00000)
static tb_inline tb_pointer_t it_chook_method_done_for_class(tb_xml_node_t const node, tb_pointer_t mmapfunc, tb_cpointer_t mmaptail)
{
// check
tb_assert_and_check_return_val(node && mmapfunc && mmaptail, mmapfunc);
// the class name
tb_char_t const* class_name = tb_string_cstr(&node->name);
tb_assert_and_check_return_val(class_name, mmapfunc);
// init method list
tb_uint_t method_n = 0;
Method* method_s = class_copyMethodList(objc_getClass(class_name), &method_n);
tb_trace_d(“class: %s, method: %u”, class_name, method_n);
tb_check_return_val(method_n && method_s, mmapfunc);
// walk methods
tb_size_t i = 0;
for (i = 0; i < method_n; i++)
{
Method method = method_s*;
if (method)
{
// the selector
// SEL sel = method_getName(method);
// the imp
IMP imp = method_getImplementation(method);
// trace
// tb_trace_d("%s %s]: %p", class_name, sel_getName(sel), imp);
// ok?
if (imp)
{
// hook
#if defined(TB_ARCH_ARM)
ifdef TB_ARCH_ARM64
tb_uint32_t* p = (tb_uint32_t*)mmapfunc;
tb_assert_and_check_break(p + (48 + 1) <= (tb_uint32_t*)mmaptail);
// push
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x0, A64$x1, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x2, A64$x3, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x4, A64$x5, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x6, A64$x7, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x8, A64$x9, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x10, A64$x11, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x12, A64$x13, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x14, A64$x15, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x16, A64$x17, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x18, A64$x19, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x20, A64$x21, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x22, A64$x23, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x24, A64$x25, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x26, A64$x27, A64$sp, -16);
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x28, A64$x29, A64$sp, -16);
// *p++ = A64$str_xt_$xn_im$(A64$x30, A64$sp, -8); // FIXME: oops! why?
*p++ = A64$stp_xt1_xt2_$xn_im$(A64$x30, A64$x29, A64$sp, -16);
// trace
*p++ = A64$movz_xd_im(A64$x0, ((tb_uint64_t)node), 0);
*p++ = A64$movk_xd_im(A64$x0, ((tb_uint64_t)node) >> 16, 16);
*p++ = A64$movk_xd_im(A64$x0, ((tb_uint64_t)node) >> 32, 32);
*p++ = A64$movk_xd_im(A64$x0, ((tb_uint64_t)node) >> 48, 48);
*p++ = A64$movz_xd_im(A64$x1, ((tb_uint64_t)method), 0);
*p++ = A64$movk_xd_im(A64$x1, ((tb_uint64_t)method) >> 16, 16);
*p++ = A64$movk_xd_im(A64$x1, ((tb_uint64_t)method) >> 32, 32);
*p++ = A64$movk_xd_im(A64$x1, ((tb_uint64_t)method) >> 48, 48);
*p++ = A64$ldr_xt_im(A64$x16, 88);
*p++ = A64$blr(A64$x16);
// pop
*p++ = A64$ldp_xt1_xt2_$xn$im(A64$x30, A64$x29, A64$sp, 16);
// *p++ = A64$ldr_xt$xn$im(A64$x30, A64$sp, 8);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x28, A64$x29, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x26, A64$x27, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x24, A64$x25, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x22, A64$x23, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x20, A64$x21, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x18, A64$x19, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x16, A64$x17, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x14, A64$x15, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x12, A64$x13, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x10, A64$x11, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x8, A64$x9, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x6, A64$x7, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x4, A64$x5, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$im(A64$x2, A64$x3, A64$sp, 16);
*p++ = A64$ldp_xt1_xt2$xn$_im(A64$x0, A64$x1, A64$sp, 16);
// goto native function
*p++ = A64$ldr_xt_im(A64$x16, 8);
*p++ = A64$br(A64$x16);
*p++ = ((tb_uint32_t)imp);
*p++ = (tb_uint32_t)((tb_uint64_t)imp >> 32);
*p++ = ((tb_uint32_t)&it_chook_method_trace);
p++ = (tb_uint32_t)((tb_uint64_t)&it_chook_method_trace >> 32);
// trace
// tb_trace_d(“bytes: %lu x4”, p - (tb_uint32_t const)mmapfunc);
// hook
method_setImplementation(method, (IMP)mmapfunc);
mmapfunc = p;
else
tb_uint32_t* p = (tb_uint32_t*)mmapfunc;
tb_assert_and_check_break(p + 11 <= (tb_uint32_t*)mmaptail);
*p++ = A$push$r0_r9_lr$;
*p++ = A$movw_rd_im(A$r0, ((tb_uint32_t)node) & 0xffff);
*p++ = A$movt_rd_im(A$r0, ((tb_uint32_t)node) >> 16);
*p++ = A$movw_rd_im(A$r1, ((tb_uint32_t)method) & 0xffff);
*p++ = A$movt_rd_im(A$r1, ((tb_uint32_t)method) >> 16);
*p++ = A$movw_rd_im(A$r9, ((tb_uint32_t)&it_chook_method_trace) & 0xffff);
*p++ = A$movt_rd_im(A$r9, ((tb_uint32_t)&it_chook_method_trace) >> 16);
*p++ = A$blx(A$r9);
*p++ = A$pop$r0_r9_lr$;
*p++ = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);
*p++ = (tb_uint32_t)imp;
method_setImplementation(method, (IMP)mmapfunc);
mmapfunc = p;
endif
}
}
}
// free it
if (method_s) free(method_s);
method_s = tb_null;
// ok
return mmapfunc;
}
static tb_inline tb_pointer_t it_chook_method_done(tb_pointer_t mmapfunc, tb_cpointer_t mmaptail)
{
// check
tb_assert_and_check_return_val(g_cfg, tb_null);
// walk
tb_xml_node_t* root = tb_xml_node_goto(g_cfg, “/itrace/class”);
tb_xml_node_t* node = tb_xml_node_chead(root);
while (node)
{
if (node->type == TB_XML_NODE_TYPE_ELEMENT)
mmapfunc = it_chook_method_done_for_class(node, mmapfunc, mmaptail);
node = node->next;
}
// ok
return mmapfunc;
}
static tb_inline tb_bool_t it_chook_init()
{
// check
tb_assert_and_check_return_val(g_cfg, tb_false);
// the method size
tb_size_t method_size = it_chook_method_size();
tb_assert_and_check_return_val(method_size, tb_false);
// trace
tb_trace_i(“chook: method_size: %lu”, method_size);
// init mmap base
#if defined(TB_ARCH_ARM)
ifdef TB_ARCH_ARM64
tb_size_t mmapmaxn = method_size * (48 + 1);
tb_size_t mmapsize = mmapmaxn * sizeof(tb_uint32_t);
else
tb_size_t mmapmaxn = method_size * 11;
tb_size_t mmapsize = mmapmaxn * sizeof(tb_uint32_t);
endif
#elif defined(TB_ARCH_x86)
tb_size_t mmapmaxn = method_size * 32;
tb_size_t mmapsize = mmapmaxn;
#elif defined(TB_ARCH_x64)
tb_size_t mmapmaxn = method_size * 96;
tb_size_t mmapsize = mmapmaxn;
#endif
tb_byte_t* mmapbase = (tb_byte_t*)mmap(tb_null, mmapsize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
tb_assert_and_check_return_val(mmapbase != MAP_FAILED && mmapbase, tb_false);
// trace
tb_trace_i(“mmapmaxn: %lu, mmapbase: %p”, mmapmaxn, mmapbase);
// hook
tb_pointer_t mmaptail = it_chook_method_done(mmapbase, mmapbase + mmapsize);
// clear cache
if (mmapbase != mmaptail) it_clear_cache(mmapbase, mmaptail);
// protect: rx
tb_long_t ok = mprotect(mmapbase, mmapsize, PROT_READ | PROT_EXEC);
tb_assert_and_check_return_val(!ok, tb_false);
// ok
return tb_true;
}*