iOS逆向工程 - 基本防护

知道了 HOOK 的原理,接下来我们就可以做一些代码的基本防护了。我们今天基本防护要达到的目的是:自己的 Method Swizzle 保留! 外面注入的 HOOK 失效!

我们的需求:

我要在内部 HOOK btnClick1:,在外部 HOOK btnClick2:。我要保证内部的 HOOK 生效,外部的 HOOK 不生效。

创建基本防护类

首先,创建一个工程,假设该工程名叫“基本防护”,我们可以在 ViewController类里添加两个按钮点击方法:

-(IBAction)btnClick1:(id)sender{
    NSLog(@"按钮1调用了!!");
}
-(IBAction)btnClick2:(id)sender{
    NSLog(@"按钮2调用了!!");
}

接下来,我们要专门建一个 HOOK 管理的类 HookMgr,导入"fishhook.h"

#import "hookMgr.h"
#import "fishhook.h"
#import 

@implementation hookMgr
//专门HOOK
+(void)load
{
    NSLog(@"hookMgr---load");
    //内部用到的交换代码! 
    #我们可以把项目中所有用 runtime 去修改的代码都写到这个地方。
    Method old = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick1:));
    Method new = class_getInstanceMethod(self, @selector(click1Hook:));
    method_exchangeImplementations(old, new);
    
    //基本防护
    # runtime 用于交换的方法有两个:
    # 1. method_exchangeImplementations 
    # 2. method_getImplementation、method_setImplementation
    # 为了反 HOOK,我们会对这两个方法都进行防护
    struct rebinding bd;
    bd.name = "method_exchangeImplementations";
    bd.replacement = myExchang;
    bd.replaced = (void *)&exchangeP;
    
//    method_getImplementation
//    method_setImplementation

    struct rebinding bd1;
    bd1.name = "method_getImplementation";
    bd1.replacement = myExchang;
    bd1.replaced = (void *)&getIMP;
    
    struct rebinding bd2;
    bd2.name = "method_setImplementation";
    bd2.replacement = myExchang;
    bd2.replaced = (void *)&setIMP;
    
    struct rebinding rebindings[] = {bd,bd1,bd2};
    rebind_symbols(rebindings, 3);
}

//保留原来的交换函数
IMP _Nonnull (*setIMP)(Method _Nonnull m, IMP _Nonnull imp);
IMP _Nonnull (*getIMP)(Method _Nonnull m);
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);

//新的函数
void myExchang(Method _Nonnull m1, Method _Nonnull m2){
    NSLog(@"检测到了HOOK!!!");
    //强制退出!
    exit(1);
}

-(void)click1Hook:(id)sendr{
    NSLog(@"原来APP的HOOK保留!!");
}

@end

上面代码,当点击btnClick1:的时候,会执行交换后的click1Hook:的方法。点击btnClick2:的时候,执行的还是btnClick2:的方法。

iOS逆向工程 - 基本防护_第1张图片
类结构.png

生成ipa包

上面就是所有基本防护的代码,我们把编译后的 app 包拿出来,新建一个Payload文件夹,把 app 包放入该文件夹里。在终端执行zip -ry Hook.ipa Payload命令,生成一个 ipa 包。

现在,我们自己的基本防护的项目已经写完了,假设上面的 ipa 包是别人在某个平台下载下来的。他现在要通过逆向来 HOOK 我们项目里的方法了。

创建一个类来HOOK我们的基本防护类

新建一个工程或MonkeyDev工程,假设该工程名叫“HOOK基本防护”,按照文章 iOS逆向工程 - 代码注入 实现 Framework 注入。在 Framework 类"Hook.m"里写上如下 HOOK 代码:

#import "Hook.h"
#import 

@implementation Hook

+(void)load
{
    NSLog(@"hook---load");
    //内部用到的交换代码!
    Method old = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick2:));
    Method new = class_getInstanceMethod(self, @selector(click2Hook:));
    method_exchangeImplementations(old, new);
}

-(void)click2Hook:(id)send{
    NSLog(@"交换成功!!");
}

@end

由于,我们的防护代码里已经把系统 runtime 的用于交换的方法都交换成了我们自己的方法myExchang,所以别人如果用 runtime 用于交换的方法来 HOOK 我们的方法,就会执行myExchang方法。程序就会强制退出!

遇到的问题

想法不错,但是如果此时别人 HOOK 我们的方法时,你会发现我们的方法被悲剧的 HOOK 住了。原因在于代码的执行顺序。程序会依次执行:

  1. “HOOK基本防护”工程的 Framework 类 Hook
  2. “基本防护”工程的 ViewController 类 ViewController
  3. “基本防护”工程的 AppDelegate 类 AppDelegate
  4. “基本防护”工程的 HookMgr 类 HookMgr

问题解决

可以看到,别人的 HOOK 都已经成功了,我们才做防护,这样还有何意义呢。所以,我们要做的就是改变代码的执行顺序。我们可以自己搞一个动态库antiHook,这个动态库专门用来做防护。然后把fishhookHookMgr两个类都拖到antiHook文件夹底下。再次重复【生成ipa包】步骤。

iOS逆向工程 - 基本防护_第2张图片
image.png

此时,程序的执行顺序会变为:

  1. “基本防护”工程的 HookMgr 类 HookMgr
  2. “HOOK基本防护”工程的 Framework 类 Hook
  3. “基本防护”工程的 ViewController 类 ViewController
  4. “基本防护”工程的 AppDelegate 类 AppDelegate

可以看到,程序会先加载我们的防护代码,然后再加载三方注入的动态库,这样就做到了代码防护。

如果我们还想要在自己的基本防护的工程里 HOOK 该怎么办呢?

把整个工程里所有用到

1. method_exchangeImplementations 
2. method_getImplementation、method_setImplementationexchangeP

方法的地方全部改为 exchangeP 方法就可以了。

最后,如果还想 HOOK 做过基本防护的工程该怎么办呢?

有一个思路,就是改变加载顺序。在你的防护动态库antiHook调用之前先调用三方注入的动态库。也就是修改 Mach-O 文件。

你可能感兴趣的:(iOS逆向工程 - 基本防护)