【iOS逆向】4种常用Hook的原理分析及示例

1,486 阅读3分钟

前沿

Hook是逆向研发的常用技能,Hook能够快速验证猜想,更改原有逻辑。在iOS端,常用Hook分为4类:OC runtime交换方法,captainhook, Fishhook, Dobbyx。

操作流程

  • OC runtime原理&示例
  • CaptainHook原理&示例
  • FishHook原理&示例
  • Dobbyx原理&示例

OC runtime原理&示例

1.原理

1.1.runtime是iOS端的运行机制,在这种机制下,苹果给开发者提供了相关API,供开发者实现方法交换,通过这个方法method_exchangeImplementations即可实现方法交换。

这种能力的使用场景很多:全埋点,对于老代码中某个方法的全局修改。

2.示例

  • 封装一个方法交换方法
+ (BOOL)swizzleOriginMethod:(SEL)originalSEL withAlternateMethod:(SEL)alternateSEL {
    //获取原始的方法
    Method originalMethod = class_getInstanceMethod(self, originalSEL);
    if (!originalMethod) {
        return NO;
    }
    //获取将要交换的方法
    Method alternateMethod = class_getInstanceMethod(self, alternateSEL);
    if (!alternateMethod) {
        return NO;
    }
    //交互两个方法的实现
    method_exchangeImplementations(originalMethod, alternateMethod);
    //返回yes,方法交换成功
    return YES;
}
  • +(void)load{}方法中实现方法交换
+ (void)load {
    [self swizzleOriginMethod:@selector(hook1:) withAlternateMethod:@selector(hook1_:)];    
}

CaptainHook原理&示例

1.原理

Captainhook是一个头文件,由很多宏定义构成,是越狱机上的一个hook方案,配合MonkeyDev项目可以快速编写Hook。

mobilesubstrate分为MobileHookerMobileLoader以及Safe mode MobileHooker,是CydiaSubstrate的一个组件,对CObjective-C均有效, MobileHooker组件主要提供了MSHookMessageExMSHookFunction两个函数针对不同语言的inline hook功能,其中MSHookMessageEx负责用来hook Objective-C函数,MSHookFunction负责用来hook C/C++函数

MSHookMessageEx本质还是利用runtime去获取某个类的一些信息,然后class_replaceMethod

static inline Class CHLoadClass_(CHClassDeclaration_ *declaration, Class value)
{
    declaration->class_ = value;//自己本身
    declaration->metaClass_ = object_getClass(value);//他的isa地址
    declaration->superClass_ = class_getSuperclass(value);//从父类开始查找value(也可以说是symbol)
    return value;
}

2.示例

//声明要操作的类
CHDeclareClass(ViewController)

//要操作的方法
CHOptimizedMethod1(self, void, ViewController, testFunc, NSString*, arg1) {
    arg1 = @"new testFun";
    CHSuper1(ViewController, testFunc, arg1);
}

//在main之前加载进去
CHConstructor{

    CHLoadLateClass(ViewController);
    CHHook1(ViewController, testFunc);
}

FishHook原理&示例

1.原理

C语言是静态的,调用某个函数跳转到某个地址,这是在编译链接时就决定了。

如果调用的C函数是动态库中的,那么在启动前是不知道这个函数的地址的,这个地址是运行时算出来的,既然是运行时算的,那么就有机会操作。

在macho文件DATA段中__la_symbol_ptr懒加载指针表,表中的指针一开始都指向__stub_helper,第一次调用才绑定值。

fishhook通过遍历__la_symbol_ptr,找到第i个元素对应的名字,就可以将__la_symbol_ptr中第i个元素改掉,完成hook。

2.示例

static int (*open_origin)(const char *, int, ...);

int new_open(const char *path, int oflag, ...) {
    printf("我就是不打开文件\n");
    return 0;

}

- (void)fishHookAction {
    
//        struct rebinding {
//          const char *name; //需要hook的函数名称,C字符串
//          void *replacement;//新函数地址
//          void **replaced;//原始函数地址的指针(二级指针)
//        };
        
        //rebind_symbols rebinding结构体的数组,包含重新绑定的信息
        //rebindings_nel 绑定的个数
        //int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);

        //初始化rebinding结构体
        struct rebinding open_rebinding = { "open", new_open, (void *)&open_origin };

        //将结构体包装数组,传入数组大小,对原符号重新绑定
        rebind_symbols((struct rebinding[1]){open_rebinding}, 1);

        //调用open函数
        int fd = open("~/DeskTop/1.txt", O_RDWR);
}

Dobbyx原理&示例

1.原理

2.示例

- (void)dobbyxAction {
    
    NSLog(@"最新的结果是: %d",sum(3,2));
}

int sum(int a,int b){
    return  a + b;
}

//函数指针用于保留原来的执行流程
static int(*sum_p)(int a,int b);

//新函数
int mySum(int a,int b){
    NSLog(@"原有的结果是:%d",sum_p(a,b));
    return a - b;
}

总结: 正向开发用swizzle,逆向OC方法Captainhook,逆向系统C函数Fishhook,逆向自定义C函数Dobbyx。

只做技术分享

5.附件

请联系作者索取