初探反HOOK防护

HOOK第三方App时,对于OC方法,一般会使用Method Swizzle。例如:使用系统提供的method_exchangeImplementations函数,将两个方法进行交换

自己开发的App,如果使用fishHook,预先将method_exchangeImplementations和自定义函数交换,攻击方在不知道函数名称的情况下,将很难进行HOOK

案例1:

使用fishHook交换method_exchangeImplementations

搭建App项目,命名为AntiHook,作为反HOOK案例

防护代码写在Framework中更适宜,因为load方法调用时机比主程序更快,并且可以在别人注入的动态库之前被执行

添加target,创建Framework,命名为HookMgr,设置为动态库

Framework中,创建AntiHookCode文件,并导入fishhook
iOS逆向实战--020:初探反HOOK防护 - 图1

打开AntiHookCode.m文件,写入以下代码:

```

import “AntiHookCode.h”

import “fishhook.h”

import

@implementation AntiHookCode

+(void)load{ struct rebinding reb; reb.name=”method_exchangeImplementations”; reb.replacement=my_exchange; reb.replaced=(void *)&sys_exchange;

struct rebinding rebs[] = { reb }; rebind_symbols(rebs, 1); }

void (*sys_exchange)(Method _Nonnull m1, Method _Nonnull m2);

void my_exchange(Method _Nonnull m1, Method _Nonnull m2){ NSLog(@”检测到HOOK”); }

@end

  1. > `App`中,打开`ViewController.m`文件,写入以下代码:
  2. >

import “ViewController.h”

import

@implementation ViewController

  • (void)viewDidLoad { [super viewDidLoad]; }

  • (IBAction)btnClick1:(id)sender { NSLog(@”按钮1调用!”); }

  • (IBAction)btnClick2:(id)sender { NSLog(@”按钮2调用了!”); }

@end

  1. > 创建`Payload`目录
  2. > 编译项目,将编译后的`AntiHook.app`拷贝到`Payload`目录下<br />
  3. ![](https://upload-images.jianshu.io/upload_images/9297953-815f8f34cfdc6139.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  4. > 使用`zip`命令,将`Payload`打包为`AntiHook.ipa`
  5. >

zip -ry AntiHook.ipa Payload

  1. > ![](https://upload-images.jianshu.io/upload_images/9297953-3a7e42b9df83243c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  2. > 案例2
  3. > 测试`AntiHook`项目的反`HOOK`防护是否有效
  4. > 搭建`App`项目,命名为`HookDemo`,作为重签名`App`
  5. > 添加`target`,创建`Framework`,命名为`Hook`,设置为动态库
  6. > `Framework`中,创建`Inject`文件<br />
  7. ![](https://upload-images.jianshu.io/upload_images/9297953-a5acd05c4ba3d4bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  8. > 打开`Inject.h`文件,写入以下代码:
  9. >

import “Inject.h”

import

@implementation Inject

+(void)load{ Method sysClick1 = class_getInstanceMethod(objc_getClass(“ViewController”), @selector(btnClick1:)); Method myClick1 = class_getInstanceMethod(self, @selector(my_btnClick1)); method_exchangeImplementations(sysClick1, myClick1); }

-(void)my_btnClick1{ NSLog(@”🍺🍺🍺🍺🍺”); }

@end

  1. > `appSign.sh`文件、`yololib`文件,拷贝到项目根目录。然后在项目根目录,创建`App`目录<br />
  2. ![](https://upload-images.jianshu.io/upload_images/9297953-d0b643e631414ddd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  3. > `案例1`中,最后打包的`AntiHook.ipa`文件,拷贝到`App`目录<br />
  4. ![](https://upload-images.jianshu.io/upload_images/9297953-52fba6ce3f46f232.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  5. > `HookDemo`中,选择`Build Phases`,在`Run Script`中输入:`./appSign.sh`<br />
  6. ![](https://upload-images.jianshu.io/upload_images/9297953-a0cf6202f4350996.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  7. > 真机运行项目,检测到`HOOK`代码<br />
  8. ![](https://upload-images.jianshu.io/upload_images/9297953-98f94ef855357685.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  9. > 点击`按钮1`,输出的还是原始内容<br />
  10. ![](https://upload-images.jianshu.io/upload_images/9297953-b30347d9bf4d597e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  11. > `AntiHook`项目中的防护代码生效,当注入的动态库,使用`method_exchangeImplementations`函数时,可以被检测出来,并让攻击方的`HOOK`失效
  12. > 案例3
  13. > 在本工程中使用方法交换
  14. > 来到`AntiHook`项目
  15. > `HookMgr`中,打开`AntiHookCode.h`文件,写入以下代码:
  16. >

import

import

CF_EXPORT void (*sys_exchange)(Method _Nonnull m1, Method _Nonnull m2);

@interface AntiHookCode : NSObject

@end

  1. > 打开`HookMgr.h`文件,写入以下代码:
  2. >

import

import

  1. > `AntiHook`中,打开`ViewController.m`文件,写入以下代码:
  2. >

import “ViewController.h”

import

@implementation ViewController

  • (void)viewDidLoad { [super viewDidLoad];

    Method sysClick2 = class_getInstanceMethod(self.class, @selector(btnClick2:)); Method myClick2 = class_getInstanceMethod(self.class, @selector(test)); sys_exchange(sysClick2, myClick2); }

-(void)test{ NSLog(@”本工程HOOK,🍺🍺🍺🍺🍺”); }

  • (IBAction)btnClick1:(id)sender { NSLog(@”按钮1调用!”); }

  • (IBAction)btnClick2:(id)sender { NSLog(@”按钮2调用了!”); }

@end

  1. > 真机运行项目,点击`按钮2`<br />
  2. ![](https://upload-images.jianshu.io/upload_images/9297953-2071d0aa658eac5e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  3. > 在本工程中,使用`sys_exchange`函数`HOOK`成功。但对于攻击方,在不知道函数名称的情况下,则很难进行`HOOK`
  4. > 上述防护方式,过于简单。它会在`MachO`的字符串表中,存储`method_exchangeImplementations`的字符串
  5. > 使用`Hopper`,打开`HookMgr`动态库的`MachO`文件<br />
  6. ![](https://upload-images.jianshu.io/upload_images/9297953-4ba78feb7c300f79.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  7. > 攻击方通过字符串,很容易定位到防护代码,然后对其破解。例如,在更早的执行时机,对防护的关键函数`HOOK`,让防护代码失效
  8. > 所以上述方式,不建议使用。高明的防护代码,应该让攻击方很难发现,尽量不留下痕迹。在程序运行过程中,不知不觉的将其干掉
  9. #####MokeyDev
  10. > `MokeyDev`:作者`刘培庆`,原`iOSOpenDev`的升级版,一款非越狱插件开发集成神器
  11. > 主要包括四个模块:
  12. > - `Logos Tweak`:使用`theos`提供的`logify.pl`工具,将`*.xm`文件转成`*.mm`文件参与执行。集成了`CydiaSubstrate`,可以使用`MSHookMessageEx``MSHookFunction``Hook`指定地址和`OC`函数
  13. > - `CaptainHook Tweak`:使用`CaptainHook`提供的头文件,进行`OC`函数的`Hook`以及属性的获取
  14. > - `Command-line Tool`:可以直接创建运行于越狱设备的命令行工具
  15. > - `MonkeyApp`:这是自动给第三方应用集成`Reveal``Cycript`和注入`dylib`的模块。支持调试`dylib`和第三方应用,支持`Pod`给第三放应用集成`SDK`,只需要准备一个砸壳后的`ipa``app`文件即可
  16. > 安装`MokeyDev`,需要先安装`theos`。详情可参见:[官方文档](https://github.com/AloneMonkey/MonkeyDev) & [安装说明](https://github.com/AloneMonkey/MonkeyDev/wiki/%E5%AE%89%E8%A3%85)
  17. > 安装中,遇到`xcode 12 Types.xcspec not found`错误,可执行以下命令:
  18. >

sudo ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/PrivatePlugIns/IDEOSXSupportCore.ideplugin/Contents/Resources /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications

  1. > - 详情可查看:[原文地址](https://github.com/AloneMonkey/MonkeyDev/issues/266)
  2. > 案例1
  3. > 搭建`MokeyApp`项目
  4. > 安装`MokeyDev`成功后,打开`Xcode`,创建新项目
  5. > 选择`MokeyApp`<br />
  6. ![](https://upload-images.jianshu.io/upload_images/9297953-37ebd5aeb5d8c570.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  7. > 创建成功,默认包含`App`和注入的动态库<br />
  8. ![](https://upload-images.jianshu.io/upload_images/9297953-459ed7fa13143646.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  9. > 案例2
  10. > 使用`MokeyApp`实现应用重签名
  11. > `MokeyApp`支持`.ipa``.app`格式
  12. > `ipa`包,拷贝到`MokeyDemo`下的`TargetApp`目录中<br />
  13. ![](https://upload-images.jianshu.io/upload_images/9297953-bf2702d6c1e21012.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  14. > 运行`MokeyDemo`项目,即可安装成功<br />
  15. ![](https://upload-images.jianshu.io/upload_images/9297953-356c8ea28c5e3af1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  16. > 案例3
  17. > 使用`MokeyApp`实现代码注入
  18. > `MokeyDemoDylib`中,点击`MokeyDemoDylib.xm`文件,选择`Objective-C++ Source`<br />
  19. ![](https://upload-images.jianshu.io/upload_images/9297953-6e177fae484b4508.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  20. > 打开`MokeyDemoDylib.xm`文件,写入以下代码:
  21. >

import

%hook ViewController

  • (void)btnClick1:(id)sender { NSLog(@”🍺🍺🍺🍺🍺”); }

%end

  1. > - 使用`Logos`语法,详情可查看:[官方文档](https://iphonedev.wiki/index.php/Logos)
  2. > 真机运行项目,检测到`HOOK`代码<br />
  3. ![](https://upload-images.jianshu.io/upload_images/9297953-a00b94463c0e6d11.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  4. > 点击`按钮1`,输出的是交换后的内容<br />
  5. ![](https://upload-images.jianshu.io/upload_images/9297953-2d934e8e6ca2e914.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240#alt=)
  6. > `HOOK`成功后,调用原始函数
  7. >
  • (void)btnClick1:(id)sender { NSLog(@”🍺🍺🍺🍺🍺”); %orig; } ```

只需要%orig一句代码,即可调用
iOS逆向实战--020:初探反HOOK防护 - 图2

使用MokeyApp,在AntiHook项目中,可以检测到method_exchangeImplementations函数的使用,说明防护代码有效。至于方法还是被交换了,可能MokeyDev使用的是get/set方法

案例4

AntiHook项目中,增加对method_setImplementation的防护

来到AntiHookCode项目

Framework中,打开AntiHookCode.m文件,修改为以下代码

```

import “AntiHookCode.h”

import “fishhook.h”

@implementation AntiHookCode

+(void)load{

struct rebinding rebExchange; rebExchange.name=”method_exchangeImplementations”; rebExchange.replacement=my_check; rebExchange.replaced=(void *)&sys_exchange;

struct rebinding rebSetImp; rebSetImp.name=”method_setImplementation”; rebSetImp.replacement=my_check; rebSetImp.replaced=(void *)&sys_setImp;

struct rebinding rebs[] = { rebExchange, rebSetImp }; rebind_symbols(rebs, 2); }

void (sys_exchange)(Method _Nonnull m1, Method _Nonnull m2); IMP _Nonnull (sys_setImp)(Method _Nonnull m, IMP _Nonnull imp);

void my_check(Method _Nonnull m1, Method _Nonnull m2){ NSLog(@”检测到HOOK”); }

@end ```

编译项目,将ipa包,覆盖到MokeyDemo下的TargetApp目录中

真机运行项目,检测到HOOK代码
iOS逆向实战--020:初探反HOOK防护 - 图3

点击按钮1,输出的还是原始内容
iOS逆向实战--020:初探反HOOK防护 - 图4

method_setImplementation函数被交换,MokeyDevHOOK代码同样失效

MokeyDev中,使用的是Substrate框架
iOS逆向实战--020:初探反HOOK防护 - 图5

MokeyDemoDylib.xm中写入的Logos语法,也是被libsubstrate.dylib库进行解析
iOS逆向实战--020:初探反HOOK防护 - 图6

.xm中的代码,解析到MokeyDemoDylib.mm文件
iOS逆向实战--020:初探反HOOK防护 - 图7

MSHookMessageEx函数内部,也是通过get/set方法,对OC方法进行HOOK

总结:

HOOK防护

  • 利用fishHook,修改Method Swizzle相关函数
  • 不推荐使用,防护痕迹过于明显。会导致其他三方库无法使用Method Swizzle
  • 防护代码需要最先被执行,否则先被HOOK,防护代码失效
  • 原始工程编写的Framework库,优先于注入库的加载,适合写防护代码

MokeyDev

  • iOSOpenDev的升级版,一款非越狱插件开发集成神器
  • 使用Substrate框架
  • 底层通过get/set方法,对OC方法进行HOOK