iOS口试题 怎样防止函数被hook

分享
源代码 2024-9-13 16:39:16 99 0 来自 中国
被问到一个标题:假如你做SDK给外部使用,怎样包管提供的函数不被外部hook?
我们知道,iOS中的hook根本原理有两个:
1.OC的动态性,使用 Method Swizzling 举行hook;2.C语言在iOS中的动态性,使用符号重绑定举行hook。以是,我们可以使用OC的Method Swizzling来hook方法,有以下三种方法:
1、方法互换OBJC_EXPORT voidmethod_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)     OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);    2、更换方法OBJC_EXPORT IMP _Nullableclass_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,                     const char * _Nullable types)     OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);    3、setIMP & getIMPOBJC_EXPORT IMP _Nonnullmethod_setImplementation(Method _Nonnull m, IMP _Nonnull imp)     OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);    OBJC_EXPORT IMP _Nullableclass_getMethodImplementation(Class _Nullable cls, SEL _Nonnull name)     OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);创建工程,在StoryBord中画两个按钮,然后在ViewController中实现对应的方法:
#import "ViewController.h"@interface ViewController ()@end@implementation ViewController+(void)load{    NSLog(@"ViewController--Load");}- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view. }- (IBAction)method1id)sender {       NSLog(@"这是方法一"); }- (IBAction)method2id)sender {      NSLog(@"这是方法二");}@end接着新创建HookClass类,先实现hook,以class_getInstanceMethod为例:
+ (void)load {  //互换方法一    Method old1 = class_getInstanceMethod(objc_getClass("ViewController"), @selector(method1);    Method new1 = class_getInstanceMethod(self, @selector(click1Hook1);    method_exchangeImplementations(old1, new1);  //互换方法二    Method old2 = class_getInstanceMethod(objc_getClass("ViewController"), @selector(method2);    Method new2 = class_getInstanceMethod(self, @selector(click1Hook2);    method_exchangeImplementations(old2, new2);}实现必要的互换的两个方法
- (void)click1Hook1id)sender {       NSLog(@"点击了hook1");}- (void)click1Hook2id)sender {      NSLog(@"点击了hook2");}运行代码,点击两个按钮,发现其实现了方法互换:
2022-12-09 18:30:08.954801+0800 HookTest[80560:759752] 点击了hook12022-12-09 18:30:09.892046+0800 HookTest[80560:759752] 点击了hook2那么标题来了,假如我们向外部提供的方法被hook了,造成预期外的效果,那么该怎样防止呢?由于dyld加载步调时候,对于外部符号(比方体系函数)是lazybind加载的,编译的时候并不是绑定真实的地点,而是在运行时动态绑定的,以是可以使用finishhook来hook体系方法。如我们可以先把method_exchangeImplementations先换成我们本身的函数,外部再使用method_exchangeImplementations来互换方法时就失效啦。同理,class_replaceMethod及method_setImplementation & class_getMethodImplementation也是一样。必要留意的是,dyld在加载步调的时候,会先加载动态库,而且是按照MachO文件存储的顺序加载(也就是Xcode链接库的顺序),以是我们要把hook代码放到动态库最前面。完备代码如下:
#import "HookClass.h"#import <objc/runtime.h>#import "fishhook.h"@implementation HookClass//生存原来的互换函数void (* exchangeProtect)(Method _Nonnull m1, Method _Nonnull m2);IMP _Nonnull (* setIMP)(Method _Nonnull m, IMP _Nonnull imp);IMP _Nonnull (* getIMP)(Method _Nonnull m);//新的函数void protectExchange(Method _Nonnull m1, Method _Nonnull m2){    NSLog(@"检测到了hook");}+ (void)load {        Method old1 = class_getInstanceMethod(objc_getClass("ViewController"), @selector(method1);        Method new1 = class_getInstanceMethod(self, @selector(click1Hook1);        method_exchangeImplementations(old1, new1);        Method old2 = class_getInstanceMethod(objc_getClass("ViewController"), @selector(method2);        Method new2 = class_getInstanceMethod(self, @selector(click1Hook2);        method_exchangeImplementations(old2, new2);    //在互换代码之前,把全部的runtime代码写完      //防护    struct rebinding bd;    bd.name = "method_exchangeImplementations";    bd.replacement=protectExchange;    bd.replaced=(void *)&exchangeProtect;        struct rebinding bd1;    bd1.name = "class_replaceMethod";    bd1.replacement=protectExchange;    bd1.replaced=(void *)&exchangeProtect;        struct rebinding bd2;    bd2.name = "method_setImplementation";    bd2.replacement=protectExchange;    bd2.replaced=(void *)&setIMP;        struct rebinding bd3;    bd3.name = "method_getImplementation";    bd3.replacement=protectExchange;    bd3.replaced=(void *)&getIMP;        struct rebinding rebindings[]={bd,bd1,bd2,bd3};    rebind_symbols(rebindings, 4);  }- (void)click1Hook1id)sender {     NSLog(@"点击了hook1");   }- (void)click1Hook2id)sender {        NSLog(@"点击了hook2"); }@end再建个HookClass+protect分类来验证,假如外部想hook我们的方法,就会有检测到了hook的提示,代码如下:
#import "HookClass+protect.h"#import <objc/runtime.h>@implementation HookClass (protect)+ (void)load {     Method oldM = class_getInstanceMethod([self class], @selector(test)); method_exchangeImplementations(oldM, class_getInstanceMethod([self class], @selector(hookExchange))); class_replaceMethod([self class], @selector(test), class_getMethodImplementation(self.class, @selector(hookReplace)), "v@:"); method_getImplementation(oldM); method_setImplementation(oldM, class_getMethodImplementation(self.class, @selector(myTest)));}- (void)test {    NSLog(@"test方法");}- (void)hookExchange { NSLog(@"hookExchange 到了 test");}- (void)hookReplace { NSLog(@"hookReplace 到了 test");}- (void)hookSet { NSLog(@"hookSet 到了 test");}@end运行代码,可以看到,我们的hook防护起到了作用:
2022-12-09 18:29:59.395944+0800 HookTest[80560:759752] 检测到了hook2022-12-09 18:29:59.396107+0800 HookTest[80560:759752] 检测到了hook2022-12-09 18:29:59.396201+0800 HookTest[80560:759752] 检测到了hook2022-12-09 18:29:59.396279+0800 HookTest[80560:759752] 检测到了hook相关资料

iOS安全防护
fishhook 使用及其 hook 原理
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 06:16, Processed in 0.142064 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表