iTracer V1.2 版本 如何才能打印出原函数的返回数据呢?

在iTracer V1.2 版本 中的it_chook_method_done_for_class函数里获取函数列表,用运行时函数method_setImplementation(method, (IMP)mmapfunc)替换原函数,增加了打印回显信息的函数it_chook_method_trace,我的问题是如何能实现打印原函数返回数据呢? 像是用mobilesubstrate的MSHookMessageEx函数替换原函数,在替换函数里可以调用原函数,获取到原函数的返回数据。
MSHookMessageEx Hook 的函数如下:
static IMP SpringBoard_isMenuDoubleTapAllowed_orig;
BOOL SpringBoard_isMenuDoubleTapAllowed_mod(id self,SEL sel)
{
BOOL res = SpringBoard_isMenuDoubleTapAllowed_orig(self, sel);
NSLog(@“res:%d”,res); return res;
}

MSHookMessageEx(NSClassFromString(@“SpringBoard”),
@selector(isMenuDoubleTapAllowed),
(IMP)SpringBoard_isMenuDoubleTapAllowed_mod,
&SpringBoard_isMenuDoubleTapAllowed_orig);

iTracer V1.2 ARMV7 的代码如下:
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;

希望论坛里的大佬们多多指教我这个菜鸟啊

没有用过iTracer,用这个怎么执行原函数?如果知道怎么执行原函数,那获取其返回值就是

id 返回值 = 原函数();

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;
}*

你这个问题应该算是对工具使用的疑问了,我建议你给作者发个邮件问问。另外,既然是自动追踪执行流程,会不会压根就没有提供调用原函数的功能?

在 mobilesubstrate hook了以后一样可以trace嘛

#define GLogStack() NSLog(@"%s: L%d :%@", func, LINE, [NSThread callStackSymbols])

是这样吗