iOS逆向学习笔记11(HOOK原理下)

1.Fishhook hook原理

  在一节笔记中我们已经掌握了fishhook的基本使用,也详细探讨了dyld在加载应用程序的过程中绑定外部符号的流程,那么现在我们再来研究一下fishhook是如何通过符号的字符串来找到其在懒加载符号表中的指针的。

1.1 查找String table

  首先通过传入的符号字符串去string table查找这个字符串所在的位置,例如:如果要查找NSLog函数的符号,那么就回去字符串表(函数名的符号就是在函数名前加上一个下划线,并且每个符号之间都用.隔开)中查找_NSLog这个符号,找到之后计算其在字符串表中的偏移值为0xE8(0x11458 - 0x11370),如下图所示:


1.2 查找Symbol Table

  通过查找String table得到的偏移值0xE8查找这个符号在符号表中的索引值,如下图所示:


1.3 查找indrect symbols

  在Symbol table中获取到这个符号在Symbol table中的索引值后,就去indrect symbols中查找这个符号在indrect symbols中的编号,如下图所示:


1.4 查找Lazy Symbol Pointers

  外部符号在懒加载符号表中的位置与其在间接符号表中的位置是一一对应的,上一步查找到符号在间接符号表中的位置后,就可以在懒加载符号表中获取到指向这个符号的指针了,如下图所示:


2.应用程序脱符号以及恢复符号

2.1 脱符号

  给应用程序脱符号的主要目的是为了减少MachO文件的体积,如果你想要为APP瘦身,可以在你的项目工程中设置如下的选项:


image.png

  将Deployment Postprocessing设置为YES,脱去符号之后我们再来看看MachO文件中的符号,如下图所示:



  首先,工程编译完成之后多了一个bc文件,这个文件是用来在线上崩溃的时候恢复符号用的。

  间接符号表中的符号是没有任何变化的。



  而应用程序中的本地符号以及全局符号都被脱去了,我们再在viewDidLoad函数中打上断点编译运行一下,结果发下根本就没有来到断点,如下图所示:

虽然我们添加的普通断点是不能执行的,那么我们就设置一个NSLog函数的符号断点试一下,如下图所示:
添加符号断点

设置符号断点名

调试运行,来到断点之后,我们使用bt指令查看一下函数调用栈,如下图所示:

2.2 动态调试查看脱去符号之后的MachO运行时某个类所调用方法名

经过上面脱符号的操作,我们发现原本的本地符号都被替换成了___lldb_unnamed_symbolX的字符串,在APP上架的时候,是都会脱去所有的符号的,这样我们在调试的时候就无从得知到底是哪个类调用了哪个方法呢?但是我们还是可以动态调试获取到这个方法的信息的,具体操作如下所示:
我们现在viewController中编写如下代码

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self my_test];
    
}

- (void)my_test {
    NSLog(@"调用了my_test方法");
}

运行到断点的时候,我们看一下函数调用汇编代码,如下图所示:


i

假设我们现在想要知道红框位置所调用的objc_msgSend是那个类的哪个方法,该怎么动态调试出来呢?
我们可以尝试计算出这个bl跳转的地址在MachO中的偏移量并在下次运行的时候获取到主应用程序的ASLR下一个符号断点,跳到这个objc_msgSend中的汇编代码中,打印一下x0以及x1寄存器的值,流程如下:
首先获取bl 0x104d8e4d8这行汇编代码在MachO中的偏移量,为(0x104d8ddb0 - 0x0000000104d88000)0x5db0,然后设置一个objc_msgSendSuper2函数符号断点,获取到刚刚那个方法还没执行之前的主程序的首地址,如下图所示:



然后计算出刚刚那行汇编代码在本次运行中的地址为(0x102e08000 + 0x5db0)0x102e0ddb0,然后设置一个地址断点,如下图所示:

紧接着跳到这个断点查看一下寄存器x0以及x1的值,如下图所示:



然后就可以查看到调用的地址了。
以上的操作步骤很复杂,因此就有人提出了为什么不直接打objc_msgSend这个符号断点,而是要通过获取对应bl指令地址去下断点查看方法信息呢?这是因为objc_msgSend这个函数其实在项目中调用次数非常的多,如果下这个断点,我们根本无从得知当前objc_msgSend中x0与x1寄存器上的值是不是我们想要查找的类和方法。

2.2 使用restore-symbol工具恢复machO文件中的符号(不能恢复静态函数符号)

我们知道OC语言中有很多库函数(例如:NSStringFromClass、NSClassFromString、NSSelectorFromString、NSStringFromSelector等),这些函数都是对类的方法或者类名字符串进行的一些操作,试想一下,脱符号有可能把这些类名符号以及类方法符号都完全脱去吗?如果脱去了,以上的这些函数调用就会出现问题了,所以这些符号一定还在其他MachO段中存在着,而脱符号仅仅是对Symbol Table、String Table中的本地以及全局符号进行了脱离,而这些必要的类名符号以及类方法符号其实还有所保留,如下图所示:


因此我们就可以根据这三个表中的信息对(除了函数之外的符号进行恢复)
使用restore-symbol工具对MachO文件的符号进行恢复
restore-symbol工具链接 密码:9xk6
打开终端,输入如下命令:

查看恢复之后的MachO文件的符号,如下图所示:

如果恢复完之后想要再次运行到真机上,就需要重新签名,重新安装。

3.使用fishhook做防护

可以使用fishhook做防护的原因:是因为在hook别的应用程序的时候我们使用最多的方式就是Method Swizzle,而Method Swizzle的方式使用的就是系统的函数,因此我们就可以使用fishhook去hook这些系统的函数以达到防护自己的APP目的。


3.1 防护代码示例

3.1.1 创建一个项目,在项目中创建一个framework,拖入fishhook两个代码文件,创建文件并暴露其头文件

3.1.2 在AntiHookCode.m文件中编写如下代码

#import "AntiHookCode.h"
#import "fishhook.h"

//在framework中做防护的原因,因为framework中load方法的调用要早于主程序以及后插入的其他动态库的load方法,在这里面做防护才能有效的防止别人在hook你的APP的时候,使用的objc方法是已经被你所改变了的。
@implementation AntiHookCode

+ (void)load {
    
    //exchange
    struct rebinding exchange;
    exchange.name = "method_exchangeImplementations";
    exchange.replacement = my_method_exchangeImps;
    exchange.replaced = (void *)&exchangeP;
    NSLog(@"来到了Load方法!!");
    
    struct rebinding rebindings[] = {exchange};
    
    rebind_symbols(rebindings, 1);
}

void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);

void my_method_exchangeImps(Method _Nonnull m1, Method _Nonnull m2) {
    NSLog(@"检测到了Hook!");
}

@end

在AntiHookCode.h文件中编写如下代码

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

NS_ASSUME_NONNULL_BEGIN

//暴露给本工程使用的method_exchangeImps指针
CF_EXPORT void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);

@interface AntiHookCode : NSObject

@end

NS_ASSUME_NONNULL_END

3.1.3 在Main.storyboard中拖入两个按钮,如下图所示:

image.png

在ViewController.m中编写如下代码:

#import "ViewController.h"
#import <AntiHookLib/AntiHookLib.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Method originMethod = class_getInstanceMethod([self class], @selector(button2Click));
    Method myHookMethod = class_getInstanceMethod([self class], @selector(myHookBtn2Click));
    Method myHookMethod2 = class_getInstanceMethod([self class], @selector(myHookBtn2Click2));
    
    method_exchangeImplementations(originMethod, myHookMethod);
    
    if (exchangeP != NULL) {
        exchangeP(originMethod, myHookMethod2);
    }
}

- (void)myHookBtn2Click2 {
    NSLog(@"自己的hook成功了2");
}

- (void)myHookBtn2Click {
    NSLog(@"自己的hook成功了");
}

- (IBAction)button1Click {
    NSLog(@"点击了按钮1");
}
- (IBAction)button2Click {
    NSLog(@"点击了按钮2");
}

@end

运行程序,就会发现系统函数method_exchangeImplementations以及被hook了,但是可以使用exchangeP指针进行与method_exchangeImplementations一样的操作。
运行结果如下:


3.2 防护应用程序AntiHookDemo hook测试

3.2.1 新建一个HookDemo

首先新建一个HooDemo工程,主要创建完毕后一定先要在真机中运行一次。然后在应用程序根目录创建APP文件夹,拖入写好的应用重签名脚本文件以及yololib工具,压缩应用程序



image.png


inject.m文件中编写的注入代码

#import "inject.h"
#import <objc/runtime.h>

@implementation inject

+ (void)load {
    Method originMethod = class_getInstanceMethod(NSClassFromString(@"ViewController"), @selector(button1Click));
    
    Method hookMethod = class_getInstanceMethod([self class], @selector(myButton1Click));
    
    method_exchangeImplementations(originMethod, hookMethod);
}

- (void)myButton1Click {
    NSLog(@"hook成功!");
}

@end

修改appSign.sh中的第三方库名



最后运行程序,分别点击两个按钮,就可以看到如下的打印结果:



注意:遇到下面这个崩溃别慌,重新运行就好了
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容