Hook函数内部地址

在没有能力自己写cydia hook 框架的情况下,想实现在某个函数任意地址(目标12字节+)hook,怎么办呢。
下面分享个小玩具,可以实现在函数中部hook。

步骤1:
首先找到你要hook那条语句地址,比如0x493B12

步骤2:
创建2个函数
其中$warp函数是构造好的函数。

static  void $wap(){
    asm volatile(
                 "stmfd sp!,{r0}\n"                 // 多压入一个空位,存放old_fun
                 "stmfd sp!,{r0-r12,r14}\n"  		// 保存现场
                 "bl %0\n"                          // 调用函数,返回值r0是old fun地址
                 "str r0,[sp,#0x38]\n"              // 直接将r0放入上面的空位
                 "ldmfd sp!,{r0-r12,r14}\n"   		// 恢复现场
                 "ldmfd sp!,{pc}\n"                 // 将old_fun弹到pc
                 :
                 :"g"(realFun)                //g 使用任何可用的寄存器和内存位置
                 :
                 );
}

realFun是hook业务函数,funRet为函数返回地址。
realFun的参数根据自己需要设置。
如果hook目标地址的有效数据不是r0-r3,比如r6, 那么可以在
“bl %0\n” 这句之前加一句

"mov r0, r6\n"

也可以访问栈变量 偏移自己估算。

"ldr r1, [sp,#0x48] \n"

然后是实际的hook业务代码。

static int funRet;

static int realFun(int r0, int r1, const char* r2, int r3) {
    @autoreleasepool {
        /* your code */
        
        return funRet;
    }
}

最后用MSHookFunction hook该地址,并将返回地址保存在funRet里。

void* addr = (void*)((dyldget_image_vmaddr_slide(0) + 0x493B12)|1); 
MSHookFunction((void *)addr, (void *)$wrap, (void **)& funRet);

注意标志位寄存器未保存,你可以自己加上,64位代码同理。

另外的实例:
有很多人想hook stringWithFormat: 其实上面方法就可以


static int funRet;

static int realFun(id self, SEL _cmd, NSString* fmt, va_list argp) {
    void* pre =  __builtin_return_address(1);   /* 第0层为warp地址 */
    void* base = (void*)_dyld_get_image_header(0);
    Dl_info info = {0};
    if (dladdr(pre, &info) && info.dli_fbase == base) {
        NSString* res = [[NSString alloc] initWithFormat:fmt locale:nil arguments:argp];
        //printf("call_addr:%p\n \t fmt:%s\n \t res:%s\n", pre, [fmt UTF8String], [res UTF8String]);
        //fflush(stdout);
        NSLog(@"\n \t call_addr:%p\n \t fmt:%@ \n \t res:%@", pre, fmt, res);
        [res release];
    }
    return funRet;
}

static  void $warp(){
    asm volatile(
                 "stmfd sp!, {r3} \n"
                 "stmfd sp!, {r0-r12, r14} \n"
                 "add r3, sp, #0x38 \n"
                 "bl %0 \n"
                 "str r0, [sp, #0x38] \n"
                 "ldmfd sp!, {r0-r12, r14} \n"
                 "ldmfd sp!, {pc} \n"
                 :
                 :"g"(realFun)                //g 使用任何可用的寄存器和内存位置
                 :
                 );
}

MSHookMessageEx(objc_getMetaClass("NSString"), @selector(stringWithFormat:), (IMP)&$warp, (IMP*)&funRet);

注释的地方有点小问题需要花点时间修改一下,我没需求,懒得改了 :)。

理论上也可以hook objc_msgSend, 但是一定要注意循环调用。

3 个赞

你这wrap函数有问题哦~

wrap 到跳转真正的hook函数(realFun)之间有stmfd操作,会使得realFun接收到的参数与真实调用的参数不一样。

因为参数传递4个以上的时候,剩下的参数在栈顶上,调用realFun之前你进行过压栈操作,会使得realFun认为你压入栈的这些数据才是参数。

我估计你所谓的“注释的地方有点小问题”,有的就是这个问题哦

擦,这点忘了,下面那段临时写出来的,回去我再改一改。

改好了 :slight_smile:

楼主warp中的保存现场及恢复现场的汇编在arm64位中该怎么写呢,急求

1 个赞

看完我哭了

书的内容怎么样,好想下手

群里有人放了盗版。还没看

大兄弟,advanced-apple-debugging-and-reverse-engineering这本书的盗版能否发个链接么?感谢

不用看我我不支持盗版