HookZz & HookZzModules Release

前言

花了有些时间写这个 hookzz 框架. 白话文说下, 单指令的 hook, 无惧短函数和不定参数函数, 可以 hook 指令地址, 可以 RuntimeCodePatch, 还有很多其他玩法. Move to HookZz

下面直接复制粘贴 README.md 了.

HookZzModules 是基于 HookZz 搞得一些模块. 可以在更方便的在 反调试 / hook_objc_msgSend / hook_MGCopyAnswer 做一些工作.

如果希望了解原理请 Move to HookFrameworkDesign

What is HookZz ?

a cute hook framwork.

still developing, for arm64/IOS now!

ref to: frida-gum and minhook and substrate.

special thanks to frida-gum's perfect code and modular architecture, frida is aircraft carrier, HookZz is boat.

Features

  • HookZz-Modules help you to hook.

  • the power to access registers directly

  • hook function with replace_call

  • hook function with pre_call and post_call

  • hook address(a piece of code) with pre_call and half_call

  • (almost)only one instruction to hook(i.e.hook short funciton, even only one instruction)

  • runtime code patch, without codesign limit

  • it’s cute

Getting Started

Move to HookZz Getting Started

How it works ?

Move to HookFrameworkDesign.md

Docs

Move to HookZz docs

Example

Move to HookZz example

Modules

Move to HookZzModules

Quick Example No.1

Read It Carefully!

#include "hookzz.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

int (*orig_printf)(const char * restrict format, ...);
int fake_printf(const char * restrict format, ...) {
    puts("call printf");

    char *stack[16];
    va_list args;
    va_start(args, format);
    memcpy(stack, args, 8 * 16);
    va_end(args);

    // how to hook variadic function? fake a original copy stack.
    // [move to detail-1](http://jmpews.github.io/2017/08/29/pwn/%E7%9F%AD%E5%87%BD%E6%95%B0%E5%92%8C%E4%B8%8D%E5%AE%9A%E5%8F%82%E6%95%B0%E7%9A%84hook/)
    // [move to detail-2](https://github.com/jmpews/HookZzModules/tree/master/AntiDebugBypass)
    int x = orig_printf(format, stack[0], stack[1], stack[2], stack[3], stack[4], stack[5], stack[6], stack[7], stack[8], stack[9], stack[10], stack[11], stack[12], stack[13], stack[14], stack[15]);
    return x;
}

void printf_pre_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
    puts((char *)rs->general.regs.x0);
    STACK_SET(callstack, "format", rs->general.regs.x0, char *);
    puts("printf-pre-call");
}

void printf_post_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
    if(STACK_CHECK_KEY(callstack, "format")) {
        char *format = STACK_GET(callstack, "format", char *);
        puts(format);
    }
    puts("printf-post-call");
}

__attribute__((constructor)) void test_hook_printf()
{
    void *printf_ptr = (void *)printf;

    ZzBuildHook((void *)printf_ptr, (void *)fake_printf, (void **)&orig_printf, printf_pre_call, printf_post_call);
    ZzEnableHook((void *)printf_ptr);
    printf("HookZzzzzzz, %d, %p, %d, %d, %d, %d, %d, %d, %d\n",1, (void *)2, 3, (char)4, (char)5, (char)6 , 7, 8 , 9);
}

breakpoint with lldb. Read It Carefully!

(lldb) disass -s 0x1815f61d8 -c 3
libsystem_c.dylib`printf:
    0x1815f61d8 <+0>: sub    sp, sp, #0x30             ; =0x30 
    0x1815f61dc <+4>: stp    x20, x19, [sp, #0x10]
    0x1815f61e0 <+8>: stp    x29, x30, [sp, #0x20]
(lldb) c
Process 41408 resuming
HookZzzzzzz, %d, %p, %d, %d, %d, %d, %d, %d, %d

printf-pre-call
call printf
HookZzzzzzz, 1, 0x2, 3, 4, 5, 6, 7, 8, 9
HookZzzzzzz, %d, %p, %d, %d, %d, %d, %d, %d, %d

printf-post-call
(lldb) disass -s 0x1815f61d8 -c 3
libsystem_c.dylib`printf:
    0x1815f61d8 <+0>: b      0x1795f61d8
    0x1815f61dc <+4>: stp    x20, x19, [sp, #0x10]
    0x1815f61e0 <+8>: stp    x29, x30, [sp, #0x20]

Quick Example No.2

Read It Carefully!

#include "hookzz.h"
#include <stdio.h>
#include <unistd.h>

static void hack_this_function()
{
#ifdef __arm64__
    __asm__("mov X0, #0\n"
            "mov w16, #20\n"
            "svc #0x80");
#endif
}

static void sorry_to_exit()
{
#ifdef __arm64__
    __asm__("mov X0, #0\n"
            "mov w16, #1\n"
            "svc #0x80");
#endif
}

void getpid_pre_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
    unsigned long request = *(unsigned long *)(&rs->general.regs.x16);
    printf("request(x16) is: %ld\n", request);
    printf("x0 is: %ld\n", (long)rs->general.regs.x0);
}

void getpid_half_call(RegState *rs, ThreadStack *threadstack, CallStack *callstack) {
    pid_t x0 = (pid_t)(rs->general.regs.x0);
    printf("getpid() return at x0 is: %d\n", x0);
}

__attribute__((constructor)) void test_hook_address()
{
    void *hack_this_function_ptr = (void *)hack_this_function;
    ZzBuildHookAddress(hack_this_function_ptr + 8, hack_this_function_ptr + 12, getpid_pre_call, getpid_half_call);
    ZzEnableHook((void *)hack_this_function_ptr + 8);

    void *sorry_to_exit_ptr = (void *)sorry_to_exit;
    unsigned long nop_bytes = 0xD503201F;
    ZzRuntimeCodePatch((unsigned long)sorry_to_exit_ptr + 8, (zpointer)&nop_bytes, 4);

    hack_this_function();
    sorry_to_exit();

    printf("hack success -.0\n");
}

breakpoint with lldb. Read It Carefully!

(lldb) disass -n hack_this_function
test_hook_address.dylib`hack_this_function:
    0x1000b0280 <+0>:  mov    x0, #0x0
    0x1000b0284 <+4>:  mov    w16, #0x14
    0x1000b0288 <+8>:  svc    #0x80
    0x1000b028c <+12>: ret    

(lldb) disass -n sorry_to_exit
test_hook_address.dylib`sorry_to_exit:
    0x1000b0290 <+0>:  mov    x0, #0x0
    0x1000b0294 <+4>:  mov    w16, #0x1
    0x1000b0298 <+8>:  svc    #0x80
    0x1000b029c <+12>: ret    

(lldb) c
Process 41414 resuming
request(x16) is: 20
x0 is: 0
getpid() return at x0 is: 41414
hack success -.0
(lldb) disass -n hack_this_function
test_hook_address.dylib`hack_this_function:
    0x1000b0280 <+0>:  mov    x0, #0x0
    0x1000b0284 <+4>:  mov    w16, #0x14
    0x1000b0288 <+8>:  b      0x1001202cc
    0x1000b028c <+12>: ret    

(lldb) disass -n sorry_to_exit
test_hook_address.dylib`sorry_to_exit:
    0x1000b0290 <+0>:  mov    x0, #0x0
    0x1000b0294 <+4>:  mov    w16, #0x1
    0x1000b0298 <+8>:  nop    
    0x1000b029c <+12>: ret  
3 个赞

膜膜膜

你这个HookZz,我理解是不是就是类似于Substrate和CaptainHook的一个东西?

原理是 inlinehook, 这个毫无疑问, 在底层做一些优化, 比如说我的 inlinehook 只需要修改一条指令, 换言之可以 hook 短函数, 即使只有一条指令, 并且允许你可以定义一些函数, 做一些 pre_call 和 post_call 的工作, 不像 substrate 只能 replace, 那其实可以在 pre_call 和 post_call 做很多有趣的事情, 不用担心不定参数函数还是其他, 你只要处理好寄存器就行, 因为我暴露给你此时所有的寄存器的值, 并且你可以修改.

也就是说,粒度比substrate更细了?能修改寄存器的值是比substrate要牛比,但是这样一个场景能不能满足呢:

一个函数,中间有一条比较指令。能否改变这条比较指令的条件,从而达到只修改一条汇编指令来改变整个函数逻辑的目的呢?

这种情况有两种处理方法, 第一种, 使用 ZzRuntimeCodePatch, 免去手动修改文件, 重打包的操作, 指定好指令位置, 写入指令数据即可. 类似于 Frida 的 Memory.patchCode, 另一种方法, 找到指令地址, 使用 ZzBuildHookAddress 对该地址进行 hook, 那么可以在比较指令前, 修改寄存器的值, 从而绕过.

还请狗神多多提提疑问和指教.

又出现了一只大牛

我给他加了个L1的管理权限。
Because why not

最近读了下 hook智障框架的几篇文章,确实非常不错,感谢分享了。

资磁

hook智障 大佬, 你这解释我无言以对啊

1 个赞

感谢张总和狗神.

膜,HookFrameworkDesign.md写的很用心详细,学习

/Users/jmpews/Desktop/SpiderZz/Pwntools/Darwin/bin/optool install -c load -p “@executable_path/test_hook_oc.dylib” -t ${EXECUTABLE_NAME}

請教 @jmpews 大神!安裝教學在run script裡面有這一行指令。請問SpiderZz, Pwntools Darwin bin這些關鍵字是該如何去理解和解決,看完您的Docs還是無頭緒,求解了,感謝~

我邮件给你回复了.

跪谢大神的指引,我针对问题2, 3点 努力尝试去!

@jmpews 大神下午好,了解好optool后,在试着编译HookZzModules/hook_objc_msgSend/makefile裡面遇到一个错误,我是採用以下指令去跑:

make -f makefile 

跑完的错误是:

`xcrun --sdk iphoneos --find clang` -isysroot `xcrun --sdk iphoneos --show-sdk-path`  -I/Users/wz/Projects/HookZz/include -O0 -g -L/Users/wz/Projects/HookZz -lhookzz.static -arch arm64 -framework Foundation -dynamiclib -Wl,-undefined,dynamic_lookup hook_objc_msgSend.o -o hook_objc_msgSend.dylib
ld: library not found for -lhookzz.static
clang: error: linker command failed with exit code 1 (use -v to see invocation)

但我查过HookZz整个资料夹,没有这份档桉名hookzz.static。唯一类似的可能就是位于/HookZz/build/libhookzz.static.a,但实际複製一份到项目当前目录下,依然显示
ld: library not found for -llibhookzz.static.a

不甘心下,透过教学文档的实作,我可以发现tests资料夹底下譬如有一个test_hook_address.c,透过make -f darwin.ios.mk test
可以成功编译出dylib,可是darwin.ios.mk有这个-lhookzz.static指令却不会出错。

我尝试把makefile 跟hook_objc_msgSend.m搬到HookZz当前目录下,让makefile与darwin.ios.mk路径相同。
但执行时,依然显示找不到-lhookzz.static。

请问大大这该如何解惑呢?

我終於找到問題了,不刪除我原先問題,希望使用這個神器HookZz新手也能避坑,你想先玩看看大神提供的HookZzModule裡的範例的話,在build就會跟我出現一樣的問題ld: library not found for -lhookzz.static
後來我一行一行與darwin.ios.mk比對終於發現在這裡他是寫成-L$(HOOKZZ_DIR)/build -lhookzz.static
可是module的demo範例makefile是寫成HOOKZZ_LIB_DIR = $(abspath …/HookZz) 這樣而已,所以找不到hookzz.static,我在路徑變數加上/build這個錯誤就消失了,成功編譯了,雖然出現以下警告:
ld: warning: -undefined dynamic_lookup is deprecated on iOS

不過至少現階段的錯誤已解決…小弟繼續努力安裝中

大神你好,在用你写的HookZz框架,我用iOSOpenDev 写了一个动态库,放在越狱机中正常hook一个app,打印出了x0寄存器的值。但是动态库和app打包成ipa放到免越狱机器上, 开启APP就闪退。
我看打印日志是提示“ exited due to an invalid code signature.”。不知道你是否遇到过这个问题??
我想问一下 ZzBuildHookAddress 方法 能否用在免越狱的 hook中?

闪退日志如下:

源代码如下:

%ctor

{

NSLog(@"测试---替换成功--1");

unsigned long _sub_100009774 = (_dyld_get_image_vmaddr_slide(0) + 0x100009774);

void *hack_this_function_ptr = (void *)_sub_100009774;

ZzBuildHookAddress((void *)((unsigned long)hack_this_function_ptr + 0xB4), (void *)((unsigned long)hack_this_function_ptr + 0xB8), getpid_pre_call, getpid_half_call,TRUE);

ZzEnableHook((void *)((unsigned long)hack_this_function_ptr + 0xB4));

NSLog(@"测试---替换成功--1-1");

NSLog(@"测试---替换成功--2");

NSLog(@"测试---替换成功--3");

NSLog(@"测试---替换成功--4");

}

两个设备都是64位的,越狱设备是8.1系统,免越狱设备是10.3系统。

我想问一下 ZzBuildHookAddress 方法 能否用在免越狱的 hook中?

1 个赞

不能。。。。