初探反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
打开
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
> 在`App`中,打开`ViewController.m`文件,写入以下代码:>
import “ViewController.h”
import
@implementation ViewController
(void)viewDidLoad { [super viewDidLoad]; }
(IBAction)btnClick1:(id)sender { NSLog(@”按钮1调用!”); }
(IBAction)btnClick2:(id)sender { NSLog(@”按钮2调用了!”); }
@end
> 创建`Payload`目录> 编译项目,将编译后的`AntiHook.app`拷贝到`Payload`目录下<br />> 使用`zip`命令,将`Payload`打包为`AntiHook.ipa`>
zip -ry AntiHook.ipa Payload
> > 案例2:> 测试`AntiHook`项目的反`HOOK`防护是否有效> 搭建`App`项目,命名为`HookDemo`,作为重签名`App`> 添加`target`,创建`Framework`,命名为`Hook`,设置为动态库> 在`Framework`中,创建`Inject`文件<br />> 打开`Inject.h`文件,写入以下代码:>
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
> 将`appSign.sh`文件、`yololib`文件,拷贝到项目根目录。然后在项目根目录,创建`App`目录<br />> 将`案例1`中,最后打包的`AntiHook.ipa`文件,拷贝到`App`目录<br />> 在`HookDemo`中,选择`Build Phases`,在`Run Script`中输入:`./appSign.sh`<br />> 真机运行项目,检测到`HOOK`代码<br />> 点击`按钮1`,输出的还是原始内容<br />> `AntiHook`项目中的防护代码生效,当注入的动态库,使用`method_exchangeImplementations`函数时,可以被检测出来,并让攻击方的`HOOK`失效> 案例3:> 在本工程中使用方法交换> 来到`AntiHook`项目> 在`HookMgr`中,打开`AntiHookCode.h`文件,写入以下代码:>
import
import
CF_EXPORT void (*sys_exchange)(Method _Nonnull m1, Method _Nonnull m2);
@interface AntiHookCode : NSObject
@end
> 打开`HookMgr.h`文件,写入以下代码:>
import
import
> 在`AntiHook`中,打开`ViewController.m`文件,写入以下代码:>
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
> 真机运行项目,点击`按钮2`<br />> 在本工程中,使用`sys_exchange`函数`HOOK`成功。但对于攻击方,在不知道函数名称的情况下,则很难进行`HOOK`> 上述防护方式,过于简单。它会在`MachO`的字符串表中,存储`method_exchangeImplementations`的字符串> 使用`Hopper`,打开`HookMgr`动态库的`MachO`文件<br />> 攻击方通过字符串,很容易定位到防护代码,然后对其破解。例如,在更早的执行时机,对防护的关键函数`HOOK`,让防护代码失效> 所以上述方式,不建议使用。高明的防护代码,应该让攻击方很难发现,尽量不留下痕迹。在程序运行过程中,不知不觉的将其干掉#####MokeyDev> `MokeyDev`:作者`刘培庆`,原`iOSOpenDev`的升级版,一款非越狱插件开发集成神器> 主要包括四个模块:> - `Logos Tweak`:使用`theos`提供的`logify.pl`工具,将`*.xm`文件转成`*.mm`文件参与执行。集成了`CydiaSubstrate`,可以使用`MSHookMessageEx`和`MSHookFunction`来`Hook`指定地址和`OC`函数> - `CaptainHook Tweak`:使用`CaptainHook`提供的头文件,进行`OC`函数的`Hook`以及属性的获取> - `Command-line Tool`:可以直接创建运行于越狱设备的命令行工具> - `MonkeyApp`:这是自动给第三方应用集成`Reveal`、`Cycript`和注入`dylib`的模块。支持调试`dylib`和第三方应用,支持`Pod`给第三放应用集成`SDK`,只需要准备一个砸壳后的`ipa`或`app`文件即可> 安装`MokeyDev`,需要先安装`theos`。详情可参见:[官方文档](https://github.com/AloneMonkey/MonkeyDev) & [安装说明](https://github.com/AloneMonkey/MonkeyDev/wiki/%E5%AE%89%E8%A3%85)> 安装中,遇到`xcode 12 Types.xcspec not found`错误,可执行以下命令:>
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
> - 详情可查看:[原文地址](https://github.com/AloneMonkey/MonkeyDev/issues/266)> 案例1> 搭建`MokeyApp`项目> 安装`MokeyDev`成功后,打开`Xcode`,创建新项目> 选择`MokeyApp`<br />> 创建成功,默认包含`App`和注入的动态库<br />> 案例2> 使用`MokeyApp`实现应用重签名> `MokeyApp`支持`.ipa`和`.app`格式> 将`ipa`包,拷贝到`MokeyDemo`下的`TargetApp`目录中<br />> 运行`MokeyDemo`项目,即可安装成功<br />> 案例3> 使用`MokeyApp`实现代码注入> 在`MokeyDemoDylib`中,点击`MokeyDemoDylib.xm`文件,选择`Objective-C++ Source`<br />> 打开`MokeyDemoDylib.xm`文件,写入以下代码:>
import
%hook ViewController
- (void)btnClick1:(id)sender { NSLog(@”🍺🍺🍺🍺🍺”); }
%end
> - 使用`Logos`语法,详情可查看:[官方文档](https://iphonedev.wiki/index.php/Logos)> 真机运行项目,检测到`HOOK`代码<br />> 点击`按钮1`,输出的是交换后的内容<br />> `HOOK`成功后,调用原始函数>
- (void)btnClick1:(id)sender { NSLog(@”🍺🍺🍺🍺🍺”); %orig; } ```
只需要
%orig一句代码,即可调用
使用
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代码
点击
按钮1,输出的还是原始内容
当
method_setImplementation函数被交换,MokeyDev的HOOK代码同样失效在
MokeyDev中,使用的是Substrate框架
在
MokeyDemoDylib.xm中写入的Logos语法,也是被libsubstrate.dylib库进行解析
将
.xm中的代码,解析到MokeyDemoDylib.mm文件
在
MSHookMessageEx函数内部,也是通过get/set方法,对OC方法进行HOOK
总结:
反
HOOK防护
- 利用
fishHook,修改Method Swizzle相关函数- 不推荐使用,防护痕迹过于明显。会导致其他三方库无法使用
Method Swizzle- 防护代码需要最先被执行,否则先被
HOOK,防护代码失效- 原始工程编写的
Framework库,优先于注入库的加载,适合写防护代码
MokeyDev
- 原
iOSOpenDev的升级版,一款非越狱插件开发集成神器- 使用
Substrate框架- 底层通过
get/set方法,对OC方法进行HOOK







