初探反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