前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hook原理

Hook原理

原创
作者头像
ruochen
发布2021-12-05 23:03:08
2.1K0
发布2021-12-05 23:03:08
举报

1.1 创建主工程 AntiHookDemo

创建一个工程AntiHookDemo,页面中有两个按钮btn1btn2:

image.png

对应两个事件:

代码语言:txt
复制
- (IBAction)btn1Click:(id)sender {
    NSLog(@"click btn1");
}
代码语言:txt
复制
- (IBAction)btn2Click:(id)sender {
    NSLog(@"click btn2");
}

1.2 创建防护 HookManager (FrameWork 动态库)

这个时候要使用fishhook防护,在FrameWork中写防护代码。基于两点:

  1. Framework在主工程+ load执行之前执行+ load
  2. 别人注入的Framework也在防护代码之后。

创建一个HookManager Framework,文件结构下:

image.png

AntiHookManager.h

代码语言:txt
复制
#import <Foundation/Foundation.h>
代码语言:txt
复制
#import <objc/message.h>
代码语言:txt
复制
//暴露给外界使用
代码语言:txt
复制
CF_EXPORT void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
代码语言:txt
复制
@interface AntiHookManager : NSObject
代码语言:txt
复制
@end

AntiHookManager.m:

代码语言:txt
复制
#import "AntiHookManager.h"
代码语言:txt
复制
#import "fishhook.h"
代码语言:txt
复制
@implementation AntiHookManager
代码语言:txt
复制
+ (void)load {
代码语言:txt
复制
    //基本防护
代码语言:txt
复制
    struct rebinding exchange;
代码语言:txt
复制
    exchange.name = "method_exchangeImplementations";
代码语言:txt
复制
    exchange.replacement = hp_exchange;
代码语言:txt
复制
    exchange.replaced = (void *)&exchange_p;
代码语言:txt
复制
    struct rebinding bds[] = {exchange};
代码语言:txt
复制
    rebind_symbols(bds, 1);
代码语言:txt
复制
}
代码语言:txt
复制
//指回原方法
代码语言:txt
复制
void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
代码语言:txt
复制
void hp_exchange(Method _Nonnull m1, Method _Nonnull m2) {
代码语言:txt
复制
    //可以在这里进行上报后端等操作
代码语言:txt
复制
    NSLog(@"find  Hook");
代码语言:txt
复制
}
代码语言:txt
复制
@end

HookManager.h中导出头文件:

代码语言:txt
复制
#import <HookManager/AntiHookManager.h>

然后将AntiHookManager.h放入public Headers

image.png

修改主工程的ViewController.m如下:

代码语言:txt
复制
#import <HookManager/HookManager.h>
代码语言:txt
复制
@interface ViewController ()
代码语言:txt
复制
@end
代码语言:txt
复制
@implementation ViewController
代码语言:txt
复制
- (void)viewDidLoad {
    [super viewDidLoad];
    exchange_p(class_getInstanceMethod(self.class, @selector(btn2Click:)),class_getInstanceMethod(self.class, @selector(test)));
}
代码语言:txt
复制
- (void)test {
    NSLog(@"self Hook Success");
}
代码语言:txt
复制
- (IBAction)btn1Click:(id)sender {
    NSLog(@"click btn1");
}
代码语言:txt
复制
- (IBAction)btn2Click:(id)sender {
    NSLog(@"click btn2");
}
代码语言:txt
复制
@end

在工程中Hook自己的方法,这个时候运行主工程:

代码语言:txt
复制
AntiHookDemo[1432:149145] click btn1
代码语言:txt
复制
AntiHookDemo[1432:149145] self Hook Success

btn2能够被自己正常Hook

1.3 创建注入工程 HookDemo

  1. 在根目录创建APP文件夹以及Payload文件夹,拷贝AntiHookDemo.appAPP/Payload目录,压缩zip -ry AntiHookDemo.ipa Payload/生成.ipa文件
  2. 拷贝appResign.sh重签名脚本以及yololib注入工具到根目录。
  3. 创建HPHook注入Framework

HPHook代码如下:

代码语言:txt
复制
#import "HPInject.h"
代码语言:txt
复制
#import <objc/message.h>
代码语言:txt
复制
@implementation HPInject
代码语言:txt
复制
+ (void)load {
代码语言:txt
复制
    method_exchangeImplementations(class_getInstanceMethod(objc_getClass("ViewController"), @selector(btn1Click:)), class_getInstanceMethod(self, @selector(my_click)));
代码语言:txt
复制
}
代码语言:txt
复制
- (void)my_click {
    NSLog(@"inject Success");
}
代码语言:txt
复制
@end

编译运行:

代码语言:txt
复制
AntiHookDemo[1437:149999] find  Hook
代码语言:txt
复制
AntiHookDemo[1437:149999] click btn1
代码语言:txt
复制
AntiHookDemo[1437:149999] self Hook Success

首先是检测到了Hook,其次自己内部btn2 hook成功了,`btn1

hook没有注入成功。到这里暴露给自己用和防止别人Hook都已经成功了。对于三方库中正常使用到的Hook可以在防护代码中做逻辑判断可以加白名单等调用回原来的方法。如果自己的库在image

list最后一个那么三方库其实已经Hook`完了。

当然只Hook method_exchangeImplementations不能完全防护,还需要Hook

class_replaceMethod以及method_setImplementation

这种防护方式破解很容易,一般不这么处理:

1.在Hopper中可以找到method_exchangeImplementations,直接在MachO中修改这个字符串HookManager中就Hook不到了(这里会直接crash,因为viewDidLoad中调用了exchange_p,对于有保护逻辑的就可以绕过了,并且method_exchangeImplementations没法做混淆)

image.png

2.可以很容易定位到防护代码,直接在防护代码之前Hook,或者将fishhook中的一些系统函数Hook也能破解。本质上是不执行防护代码。

二、MonkeyDev

MonkeyDev是逆向开发中一个常用的工具

MonkeyDev。能够帮助我们进行重签名和代码注入。

2.1 安装 MonkeyDev

theos安装 (Cydia Substrate就是 theos中的工具)

代码语言:txt
复制
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos

配置环境变量

代码语言:txt
复制
#逆向相关配置
代码语言:txt
复制
#export THEOS=/opt/theos
代码语言:txt
复制
#写入环境变量
代码语言:txt
复制
#export PATH=$THEOS/bin:$PATH

运行nic.pl查看theos信息。

image.png

`error Cowardly refusing to make a project inside $THEOS

(/opt/theos/)出现这个错误则是export`配置有问题。

指定Xcode

代码语言:txt
复制
sudo xcode-select -s /Applications/Xcode.app

安装命令

代码语言:txt
复制
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)"

这里是安装Xcode插件。安装完成后重启XcodeXcode中会出现MonkeyDev对应的功能:

image.png

  • MonkeyApp:自动给第三方应用集成RevealCycript和注入dylib的模块,支持调试dylib和第三方应用,支持Pod给第三放应用集成SDK,只需要准备一个砸壳后的ipa或者app文件即可。
  • MonkeyPod:提供了创建Pod的项目。
  • CaptainHook Tweak:使用CaptainHook提供的头文件进行OC函数的Hook以及属性的获取。
  • Command-line Tool:可以直接创建运行于越狱设备的命令行工具。
  • Logos Tweak:使用theos提供的logify.pl工具将.xm文件转成.mm文件进行编译,集成了CydiaSubstrate,可以使用MSHookMessageExMSHookFunctionHook OC函数和指定地址。

卸载命令

代码语言:txt
复制
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-uninstall)"

更新命令

代码语言:txt
复制
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-update)"

错误处理

1.MonkeyDev 安装出现:Types.xcspec not found

添加一个软连接:

代码语言:txt
复制
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

2.2 重签名

创建一个MonkeyDemo工程:

image.png

工程目录如下:

image.png

在工程目录下有一个TargetApp目录,直接将微信8.0.2版本拖进去:

image.png

编译运行工程:

image.png

这个时候就重签名成功了。相比用脚本自己跑方便很多,也能避免很多异常。

2.3 MonkeyDev 代码注入

工程配置

MonkeyDemo注入一下AntiHookDemo,将AntiHookDemo编译生成的App加入MonkeyDemoTargetApp中:

image.png

代码注入

MonkeyDemo工程MonkeyDemoDylib->Logos目录,.xm文件可以写OCC++C

image.png

MonkeyDemoDylib.xmtype改为Objective-C++ Preprocessed Source

image.png

这里面的默认代码就是Logos语法:

image.png

.xm默认打开方式修改为Xcode后重启Xcode就能识别代码了,否则就还是默认文本文件。将默认的代码删除,写Hook

btn1Click的代码:

代码语言:txt
复制
#import <UIKit/UIKit.h>
代码语言:txt
复制
//要hook的类
代码语言:txt
复制
%hook ViewController
代码语言:txt
复制
//要hook的方法
代码语言:txt
复制
- (void)btn1Click:(id)sender {
    NSLog(@"Monkey Hook Success");
    //调用原来的方法
    %orig;
}
代码语言:txt
复制
%end

直接运行工程后点击btn1

代码语言:txt
复制
AntiHookDemo[9306:5972601] find  Hook
代码语言:txt
复制
AntiHookDemo[9306:5972601] find  Hook
代码语言:txt
复制
AntiHookDemo[9309:5973617] Monkey Hook Success
代码语言:txt
复制
AntiHookDemo[9350:5987306] click btn1

image.png

这个时候就Hook成功了,并且检测到了Hook。这里没有防护住是因为Monkey中用的是getImpsetImp

AntiHookManager做下改进:

AntiHookManager .h:

代码语言:txt
复制
#import <Foundation/Foundation.h>
代码语言:txt
复制
#import <objc/message.h>
代码语言:txt
复制
//暴露给外界使用
代码语言:txt
复制
CF_EXPORT void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
代码语言:txt
复制
CF_EXPORT IMP _Nonnull (*getImp_p)(Method _Nonnull m);
代码语言:txt
复制
CF_EXPORT IMP _Nonnull(*setImp_p)(Method _Nonnull m, IMP _Nonnull imp);
代码语言:txt
复制
@interface AntiHookManager : NSObject
代码语言:txt
复制
@end

AntiHookManager .m:

代码语言:txt
复制
#import "AntiHookManager.h"
代码语言:txt
复制
#import "fishhook.h"
代码语言:txt
复制
@implementation AntiHookManager
代码语言:txt
复制
+ (void)load {
代码语言:txt
复制
    //基本防护
代码语言:txt
复制
    struct rebinding exchange;
代码语言:txt
复制
    exchange.name = "method_exchangeImplementations";
代码语言:txt
复制
    exchange.replacement = hp_exchange;
代码语言:txt
复制
    exchange.replaced = (void *)&exchange_p;
代码语言:txt
复制
    struct rebinding setIMP;
代码语言:txt
复制
    setIMP.name = "method_setImplementation";
代码语言:txt
复制
    setIMP.replacement = hp_setImp;
代码语言:txt
复制
    setIMP.replaced = (void *)&setImp_p;
代码语言:txt
复制
    struct rebinding getIMP;
代码语言:txt
复制
    getIMP.name = "method_getImplementation";
代码语言:txt
复制
    getIMP.replacement = hp_getImp;
代码语言:txt
复制
    getIMP.replaced = (void *)&getImp_p;
代码语言:txt
复制
    struct rebinding bds[] = {exchange,setIMP,getIMP};
代码语言:txt
复制
    rebind_symbols(bds, 3);
代码语言:txt
复制
}
代码语言:txt
复制
//指回原方法
代码语言:txt
复制
void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
代码语言:txt
复制
IMP _Nonnull (*getImp_p)(Method _Nonnull m);
代码语言:txt
复制
IMP _Nonnull(*setImp_p)(Method _Nonnull m, IMP _Nonnull imp);
代码语言:txt
复制
void hp_exchange(Method _Nonnull m1, Method _Nonnull m2) {
代码语言:txt
复制
    //可以在这里进行上报后端等操作
代码语言:txt
复制
    NSLog(@"find  Hook");
代码语言:txt
复制
}
代码语言:txt
复制
void (hp_getImp)(Method _Nonnull m) {
代码语言:txt
复制
    NSLog(@"find  Hook getImp");
代码语言:txt
复制
}
代码语言:txt
复制
void (hp_setImp)(Method _Nonnull m, IMP _Nonnull imp) {
代码语言:txt
复制
    NSLog(@"find  Hook setImp");
代码语言:txt
复制
}
代码语言:txt
复制
@end

这个时候控制台输出:

代码语言:txt
复制
AntiHookDemo[1488:207119] find  Hook getImp
代码语言:txt
复制
AntiHookDemo[1488:207119] find  Hook
代码语言:txt
复制
AntiHookDemo[1488:207119] find  Hook getImp
代码语言:txt
复制
AntiHookDemo[1488:207119] find  Hook
代码语言:txt
复制
AntiHookDemo[1488:207119] click btn1

点击btn1也没有Hook到了。在这里运行时有可能CrashJSEvaluateScript的时候,直接删除App重新跑一次就可以了。

libsubstrate.dylib解析的,

其实这里.xm文件是被libsubstrate.dylib解析成MonkeyDemoDylib.mm中的内容(.xm代码是不参与编译的):

image.png

MSHookMessageEx底层用的是setImpgetImpOC进行Hook的。

错误问题

1.`Signing for "MonkeyDemoDylib" requires a development team. Select a

development team in the Signing & Capabilities editor.`

直接在该targetbuild settings 中添加CODE_SIGNING_ALLOWED=NO

image.png

https://iosre.com/t/xcode11-monkeydev/17021

2.`Failed to locate Logos Processor. Is Theos installed? If not, see

https://github.com/theos/theos/wiki/Inst allation.`

出现这个错误一般是theos没有安装好。或者路径配置的有问题。

3.library not found for -libstdc++

需要下载对应的库到XCode目录中。参考:[https://github.com/longyoung/libstdc.6.0.9-if-help-

you-give-a-

star](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Flongyoung%2Flibstdc.6.0.9-if-

help-you-give-a-star)

4.`The WatchKit app’s Info.plist must have a WKCompanionAppBundleIdentifier

key set to the bundle identifier of the companion app.`

删除DerivedData重新运行。

5.`This application or a bundle it contains has the same bundle identifier as

this application or another bundle that it contains. Bundle identifiers must

be unique.`

这种情况大概率是手机上之前安装过相同bundleIdApp安装不同版本导致,需要删除重新安装。还有问题的话删除DerivedDatabundleId

6.`This app contains a WatchKit app with one or more Siri Intents app

extensions that declare IntentsSupported that are not declared in any of the

companion app's Siri Intents app extensions. WatchKit Siri Intents extensions'

IntentsSupported values must be a subset of the companion app's Siri Intents

extensions' IntentsSupported values.`

需要删除com.apple.WatchPlaceholder(在/opt/MonkeyDev/Tools目录中修改pack.sh):

代码语言:txt
复制
rm -rf "${TARGET_APP_PATH}/com.apple.WatchPlaceholder" || true

然后删除DerivedData重新运行。

  1. LLVM Profile Error: Failed to write file "default.profraw": Operation not permittedundefined这个说明App内部做了反调试防护。直接在Monkey中开启sysctl
代码语言:txt
复制
rebind_symbols((struct rebinding[1]){{"sysctl", my_sysctl, (void*)&orig_sysctl}},1);

8.`Attempted to load Reveal Library twice. Are you trying to load dynamic

library with Reveal Framework already linked?`

直接删除dylibOther Linker Flags的设置即可(可能的原因是手机端已经导入了这个库):

⚠️遇见莫名其妙的错误建议删除DerivedData重启Xcode重新运行。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.1 创建主工程 AntiHookDemo
  • 1.2 创建防护 HookManager (FrameWork 动态库)
  • 1.3 创建注入工程 HookDemo
  • 二、MonkeyDev
    • 2.1 安装 MonkeyDev
      • 2.2 重签名
        • 2.3 MonkeyDev 代码注入
          • 工程配置
          • 代码注入
      相关产品与服务
      命令行工具
      腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档