iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

市面上的App,做过防护的只有那些出名的,大企业的App;通常的App除了登录进行了普通的加密,是一点防护都没有的,今天我们就学习一下最基本的防护。

我们知道,iOS中hook的基本原理是两个:

  1. OC的动态性,利用 Method Swizzling 进行hook;
  2. C语言在iOS中的动态性,利用符号重绑定进行hook。

我们这里只介绍第一种,防护OC的方法。这一层只能防护住一些简单的逆向工程师,但是这是也是明白防护的第一步,后面会逐步增加防护的知识。

我们这里进行防护都是利用fishHook完成。

直接防护 method_exchangeImplementations 方法

可能进行防护,我们上来就是想到防护method swizzling 的几个方法,这里通过 
method_exchangeImplementations 进行举例。

一、首先书写防护代码:

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

二、将这个工程打包,新建工程进行破解:

(此种涉及到重签名和代码注入的知识,不明白的新手可以查看我的文章:iOS开发|Framework注入,让别人的软件执行我们的代码

因为我们知道原来工程的代码,这里我们就不分析了,直接使用 
method_exchangeImplementations 进行hook ViewController 中的 test 方法。

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

天啦!我们明明在防护代码中把 
method_exchangeImplementations 方法已经进行了防护,这里注入Framework什么还是hook到了呢?

难道是我们自己写的防护代码出错了?小白一般都那么不自信,我也会这样怀疑自己,来,我们自测一下。

测试:来到防护代码,我们直接在本工程中进行进行hook:

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

很明显,打印了“我防护了,你别乱来!”,说明我们这里的防hook没有问题。

但是当我们使用Framework注入的方式进行hook的时候,又不起作用了,这是为什么?

在 Framework 进行防护

其实标题已经告诉了我们,应该在Framework中进行hook。原因是什么?

执行顺序

从我们之前分析hook的文章中知道,如果想要更改代码执行的顺序,肯定要在执行之前拿到这个方法。我们这里是通过fishHook进行的hook防护,它其实也是在执行之前,将我们的
method_exchangeImplementations 函数进行了交换,换成了 
my_method_exchangeImplementations。

这里实验结果说明:
method_exchangeImplementations 没有被交换成 
my_method_exchangeImplementations,至少在破解代码之前没有进行交换。

为了证明这个结论,那么我们来调试一下:在防护代码中创建也创建一个Framework,看执行顺序。

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

果然,Framework是先执行的。

这样就能够解释了,因为Framework中的代码已经执行了,所以他的hook已经生效了;当执行到防护代码ViewController中的时候,早已经hook完毕了,所以,防护没有起到作用。

这里的原因,其实在DYLD的加载流程中已经解释过了(可以去看我关于DYLD的分析)。DYLD会先加载插入的Framework,然后才是慢慢进入主程序,执行我们所写的代码。

DYLD的加载过程:配置环境——加载共享缓存——初始化MechO——加载插入动态库——初始化主程序——objc_init给DYLD一个回调——load_images——load。

完全防护

上面一步一步我们进行了防护工作,发现插入Framework的执行是在我们代码之前,于是我们想要进行安全防护,肯定是需要将防护代码写在别人恶意执行之前才行。

怎么做呢?

将防护写在Framework中。

一、再次来到防护代码中,将代码转移到Framework中去。

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

我同样在本工程中进行了检测,发现是可以起到作用的,成功的拦截到了hook。

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

二、第二步我们将这个App包交给破解代码,然后进行破解。

  1. 眼镜都不要眨一下,看上面这个图。InjectCode中是我的hook代码,也是在Framework中做的,而且执行了,说明hook的代码走了。
  2. 那么看下面的log,是“我防护了,你别乱来!”。

说明什么,我们成功了!

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

没错,hook防护的代码需要写在Framework中。

补充

我们知道,除了方法 
method_exchangeImplementations 可以进行hook,还有 class_replaceMethod ,method_setImplementation 和 method_getImplementation 需要进行防护。

首先测试一下,除了 
method_exchangeImplementations,其它方式是否可以越过防护。

直接在防护代码中进行测试:

1、class_replaceMethod 方法越过了防护。

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

2、method_setImplementation 也同样越过了防护。

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

那么我们将代码完善一下:

+ (void)load {
 struct rebinding exchange;
 exchange.name = "method_exchangeImplementations";
 exchange.replacement = my_method_exchangeImplementations;
 exchange.replaced = (void *)&old_method_exchangeImplementations;
 
 struct rebinding replace;
 replace.name = "class_replaceMethod";
 replace.replacement = my_class_replaceMethod;
 replace.replaced = (void *)&old_class_replaceMethod;
 
 struct rebinding set;
 set.name = "method_setImplementation";
 set.replacement = my_method_setImplementation;
 set.replaced = (void *)&old_method_setImplementation;
 
 struct rebinding get;
 get.name = "method_getImplementation";
 get.replacement = my_method_getImplementation;
 get.replaced = (void *)&old_method_getImplementation;
 
 struct rebinding rebinds[4] = {exchange, replace, set, get};
 rebind_symbols(rebinds, 4);
 NSLog(@"%s", __func__);
}
// 定义一个函数指针,用来保留系统的exchange函数
void (*old_method_exchangeImplementations)(Method _Nonnull m1, Method _Nonnull m2);
// 定义一个函数指针,用来保留系统的replace函数
IMP _Nullable (*old_class_replaceMethod)(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types);
// 定义一个函数指针,用来保留系统的set函数
IMP _Nonnull (*old_method_setImplementation)(Method _Nonnull m, IMP _Nonnull imp);
// 定义一个函数指针,用来保留系统的get函数
IMP _Nonnull (*old_method_getImplementation)(Method _Nonnull m);
// 我自定义的exchange方法
void my_method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2) {
 NSLog(@"我防护了,你别乱来!");
}
// 我自定义的replace方法
IMP _Nullable
my_class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
 const char * _Nullable types) {
 NSLog(@"我防护了,你别乱来!");
 return nil;
}
// 我自定义的set方法
IMP _Nonnull
my_method_setImplementation(Method _Nonnull m, IMP _Nonnull imp) {
 NSLog(@"我防护了,你别乱来!");
 return nil;
}
// 我自定义的get方法
IMP _Nonnull
my_method_getImplementation(Method _Nonnull m) {
 NSLog(@"我防护了,你别乱来!");
 return nil;
}

 

完善过后,我们将防护App的包装到hook的当中进行测试。

这是hook App中的代码:

+ (void)load {
 Method oldM = class_getInstanceMethod(NSClassFromString(@"ViewController"), @selector(test));
 method_exchangeImplementations(oldM, class_getInstanceMethod([self class], @selector(hookExchange)));
 class_replaceMethod(NSClassFromString(@"ViewController"), @selector(test), class_getMethodImplementation(self.class, @selector(hookReplace)), "v@:");
 method_getImplementation(oldM);
 method_setImplementation(oldM, class_getMethodImplementation(self.class, @selector(myTest)));
}
- (void)hookExchange {
 NSLog(@"hookExchange 到了 test");
}
- (void)hookReplace {
 NSLog(@"hookReplace 到了 test");
}
- (void)hookSet {
 NSLog(@"hookSet 到了 test");
}

 

运行后的效果:每一个方法都hook住了。

 

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

 

以上就是我们利用fishHook完成的防护hook方案。

总结:

  1. 防护应该写在注入的Framework中,因为DYLD是先加载的插入动态库,只有在修改之前限制才有作用;
  2. 防护应该多种方案都想到,这样才会周全,四种OC的 Method Swizzling 都应该考虑到。

面试题持续更新记得关注我哦!

不同的圈子就有不同的学习方式 ;

(qq群搜索):651612063 群密码:111 进群文件可以直接获取大厂面试题

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

点击进群

iOS逆向|基本防护,iOS逆向的必要所求 没防护就像一个没穿衣服的人

上一篇:iOS Safari浏览器上overflow: scroll元素无法滑动bug解决方法整理


下一篇:原生js手动实现apply和call