一、HOOK概述

HOOK,中文为“钩子”或“挂钩”,在ios逆向中是指改变程序的运行流程的一种技术,通过hook可以让别人的程序执行自己的代码逻辑,在逆向中经常使用。所以就来看看HOOK的原理吧!

上图很常见的微信抢红包,hook原理就相当于程序本来收到红包消息用户应该点击红包之后点击“抢”,才能领红包,而通过HOOK既可以执行自己的代码,用户不需要点击自动执行抢红包代码,这就是HOOK常见的应用。

1.ios中HOOK技术的几种方式

1、Method Swizzle

利用OC的Runtime特性,动态改变SEL(方法编号)和IMP(方法的实现)的对应关系,达到OC方法调用流程改变的目的,主要用在OC方法中。

2、fishhook

他是facebook提供的一个动态修改链接mach-o文件的工具。利用MachO文件加载原理,通过修改懒加载和非懒加载两个表指针达到C函数HOOK的目的。

3、Cydia Substrate

Cydia Substrate 原名为 Mobile Substrate,主要针对OC方法、C函数以及函数地址进行hook操作,他可以用于iOS,也可用于android 。官网:www.cydiasubstrate.com

Method Swizzle :

在OC中,SEL和IMP的关系好比标题和页码、接口和实现之间的关系,一个是标题,一个是对应的实现。Runtime提供了交换两个SEL和IMP对应关系的函数:method_exchangeImplememtations(Method m1,Method m2) 这个函数交换两个SEL和IMP之间的关系的技术,叫Method Swizzle(方法欺骗)。

例子:

//
//  ViewController.m
//  Demo
//
//  Created by yrl on 2019/7/26.
//  Copyright © 2019 apple. All rights reserved.
//#import "ViewController.h"
#import <objc/runtime.h>@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];NSURL *url = [NSURL URLWithString:@"https://study.163.com/courses-search?keyword=逻辑教育"];//出现中文应进行编码转换,否则会为空NSLog(@"%@",url);}@end

运行结果:

我们可以用stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]转码

利用OC的Runtime进行方法交换,例子:

//
//  NSURL+HK_URL.m
//  Demo
//
//  Created by yrl on 2019/7/26.
//  Copyright © 2019 apple. All rights reserved.
//#import "NSURL+HK_URL.h"
#import <objc/runtime.h>@implementation NSURL (HK_URL)
+(void)load{//类方法Method URLWithStr = class_getClassMethod(self, @selector(URLWithString:));//系统的Method HK_URLWithStr = class_getClassMethod(self, @selector(HK_URLWithString:));//自己的//changemethod_exchangeImplementations(URLWithStr, HK_URLWithStr);
}+(nullable instancetype)HK_URLWithString:(NSString *)URLString{NSURL * url = [NSURL HK_URLWithString:URLString];//应用HK_URLWithString系,URLWithString已经交换了,会造成死递归统if(url == nil){//如果为空则进行编码转换URLString = [URLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];}url = [NSURL HK_URLWithString:URLString];//将URLString赋值给UK_URLWithStringreturn url;
}@end

实现了HOOK 了NSURL类的URLWithString方法,在类方法load中交换了系统的URLWithString和自己定义的HK_URLWithString,在调用URLWithString时会调用HK_URLWithString,实现HOOK,将中文编码,再运行程序:

可看到中文已经被编码了,说明我们已经改变了程序的执行流程。

Cydia Substrate

很强大的一个框架

1.MoblieHooker

他有一系列的宏和函数,底层调用的objc的runtime和fishhook来替换系统或者目标应用,其中有两个函数:

MSHookMessageEx 主要用于Objective-C方法 void MSHookMessageEx(Class class ,SEL selector ,IMP replacement ,IMP result)第一个参数是哪个类,第二个参数是哪个编号(方法),第三个新方法的实现,第四个参数旧方法的实现

MSHookFunction 主要用于C/C++函数 void MSHookFunction(voidfunction, void * replacement, void ** p_original) Logos语法的%HOOK就是对这个函数做了一层封装。

2.MobileLoader

用于加载第三方dylib在运行的应用程序中。启动MobileLoader会根据规则把指定的第三方动态库加载进去,第三方动态库也就是我们写的破解程序。

3.Safe Mode

破解程序本质是dylib,寄生在别人的进程里,系统进程一旦出错,可能导致整个系统崩溃,Cydia Substrate提供安全模式,在安全模式下,所有的第三方dylib都会被禁止,便查错与修复。

FishHook

不是一个框架,是一个工具,工具代码可以在github上下载:https:/github.com/facebook/fishhook.git,勾不住自己定义的函数,只能勾系统函数。

其中只有一个.c和.h文件,代码不长,有兴趣可以看看源码,代码有很多关于MachO文件的东西,先了解一下MachO的API

fishhook.h就俩函数一个结构体:

例子:点击屏幕触发NSLog函数转到myNSLog

将fishhook.c   fishhokk.h拖进项目

//
//  ViewController.m
//  fishhook
//
//  Created by yrl on 2019/7/26.
//  Copyright © 2019 apple. All rights reserved.
//#import "ViewController.h"
#import "fishhook.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];NSLog(@"123");//NSLog属于懒加载,调用才能看到//实现交换//定义rebinding结构体struct rebinding nslog;nslog.name = "NSLog";nslog.replacement = myNSLog;nslog.replaced = (void **)&sys_nslog;//定义结构体数组struct rebinding rebs[1] = {nslog};/* 用来重新绑定符号* arg1 存放rebinding结构体的数组* arg2 数组长度*/rebind_symbols(rebs, 1);//两个参数 结构体数组、数组长度printf("修改完毕!!");
}
//-------------更改系统NSLOG函数-------------
//函数指针,用来保存原来的函数地址
static void(*sys_nslog)(NSString *format,...);
//定义一个新的函数
void myNSLog(NSString *format, ...){format = [format stringByAppendingString:@"\n勾上了!!"];sys_nslog(format);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{//屏幕触发事件NSLog(@"点击屏幕!!");
}@end

运行函数,点击屏幕:

二、FishHook的原理探究

仿照上面的工程再写一个代码,这回我们用来勾自己定义的newFunc()函数,当点击屏幕时,func(str)应该被newFunc HOOK,转而执行newFunc函数逻辑:

//
//  ViewController.m
//  fishhook2
//
//  Created by yrl on 2019/7/26.
//  Copyright © 2019 apple. All rights reserved.
//#import "ViewController.h"
#import "fishhook.h"
@interface ViewController ()@end@implementation ViewControllervoid func(const char *str){NSLog(@"%s",str);
}- (void)viewDidLoad {[super viewDidLoad];//交换rebind_symbols((struct rebinding[1]){{"func",newRunc,(void **)&funcP}}, 1);}
//原始指针
static void (*funcP)(const char * str);
//新方法
void newRunc(const char * str){NSLog(@"勾住了");funcP(str);
}-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{func("hello");
}@end

运行后发现并没有按照预想的来:

FishHook原理:

git上有介绍(英文):

dyld binds lazy and non-lazy symbols by updating pointers in particular sections of the __DATA segment of a Mach-O binary. fishhook re-binds these symbols by determining the locations to update for each of the symbol names passed to rebind_symbols and then writing out the corresponding replacements.

For a given image, the __DATA segment may contain two sections that are relevant for dynamic symbol bindings: __nl_symbol_ptr and __la_symbol_ptr__nl_symbol_ptr is an array of pointers to non-lazily bound data (these are bound at the time a library is loaded) and __la_symbol_ptr is an array of pointers to imported functions that is generally filled by a routine called dyld_stub_binder during the first call to that symbol (it's also possible to tell dyld to bind these at launch). In order to find the name of the symbol that corresponds to a particular location in one of these sections, we have to jump through several layers of indirection. For the two relevant sections, the section headers (struct sections from <mach-o/loader.h>) provide an offset (in the reserved1 field) into what is known as the indirect symbol table. The indirect symbol table, which is located in the __LINKEDIT segment of the binary, is just an array of indexes into the symbol table (also in __LINKEDIT) whose order is identical to that of the pointers in the non-lazy and lazy symbol sections. So, given struct section nl_symbol_ptr, the corresponding index in the symbol table of the first address in that section is indirect_symbol_table[nl_symbol_ptr->reserved1]. The symbol table itself is an array of struct nlists (see <mach-o/nlist.h>), and each nlist contains an index into the string table in __LINKEDITwhich where the actual symbol names are stored. So, for each pointer __nl_symbol_ptr and __la_symbol_ptr, we are able to find the corresponding symbol and then the corresponding string to compare against the requested symbol names, and if there is a match, we replace the pointer in the section with the replacement.

可执行文件MachO怎么进入内存的?是通过DYLD(动态链接器)加载进内存的,通过lldb(调试工具)的image list可以看到加载MachO文件的同时还加载了哪些库,期间涉及到了ASLR(地址空间布局随机化),每次加载的内存地址的偏移都不一样。

拿上面的例子说,自己定义的func函数和NSLog函数在内存中的地址不一样,位置也不一样,func在MachO文件中,NSLog在系统动态库(dylib共享的动态链接库)中,那么func里面调用NSLog要找到NSLog的地址,MachO文件怎么找?怎么知道的?在程序启动之前都不知道,不同手机的NSLog地址也是不一样的,这就是DYLD的工作了,如图:

所有的可执行文件都是由它加载的,dyld加载了MachO,一旦加载了MachO文件,苹果采用了一种技术叫PIC(位置独立代码),当程序MachO调用其外部的函数的时候,比如说NSLog,他就会在DATA段创建一个指针,八个字节,用来放外部函数的地址,在调用之前这里是什么是不知道的,当func调用系统动态库中NSLog时就通过dyld链接dylib找到NSLog函数的真实地址,写入到DATA段,dyld就会绑定一个MachO里面的函数(符号),也就是写到data段里的符号,所以这就是为什么fishhook的交换函数叫rebind_sybomls(绑定符号),也就是说这个函数只适用于系统的动态连接库中的函数(系统C级别函数),因为只有系统函数在MachO调用的时候会有符号写入data段,所以这就是为什么去HOOK自己定义的函数不起作用,因为自己定义的函数MachO运行的时候不需要去通过dyld获取函数地址,自然就HOOK不到。

具体验证:上一个fishhook例子

将例子build一下,提取fishhook.app里面的可执行文件,用MachOview打开,看看其二进制文件格式:我们就看DATA段

可以看到NSLog的地址0x100003028(现在这个值没用,运行的时候dyld才给它赋值) 偏移0x3028,运行时保存NSLog的真实地址,而这个地址在MachO文件偏移的0x3028处,我们找一下,调试在此处下断点:

通过lldb查看 输入image list

我们查看NSLog文件地址(MachO文件地址记得后面加偏移才是NSLog地址):x 0x10b729000+0x3028

这个是NSLog地址(小端序)0x010bac20de,查看此处的汇编代码:dis -s 0x010bac20de

往下走一步ni 再查看原来NSLog的地址:

此处变为myNSLog了,可见,hook成功。

通过符号找字符

在MachO文件找字符,在Lazy Symbol Pointers表中NSLog在第一位,与之对应的有一个表Dynamic Symbol Table下的Indirect Symbols表

对比一下两个表一一对应,Indirect Symbols指向了下一个Symbols表的第0x79个表项:

他中的数据指向了String Table 的index下标:

位置在0x4f1c+0x9b =0x4fb7,找到这个位置:

对应的就是NSLog的字符,每一个字符都是以“_”以“.”结束。

这个过程就是开头那段英文所说的意思,官方给的图:

Lazy Symbol和Indirect Symbol Table对应,Lazy Symbol的0x1061处的表项指向了 Indirect Symbol Table的对应0x1061处的表项,而Indirect Symbol Table0x1061处指向的是Symbol Table的16343处,Symbol Table的16343处指向的是String Table的70026处的字符,可以看到字符为"_close.",他用的是close()函数,而我们用的是NSLog函数。

后记:

MachO文件很重要,在做防护,检测app是否被修改,被注入,是否在越狱环境中,都需要不断检测MachO文件的字段是否被修改,如果MachO被修改说明app被修改了,那么app就会做出相应的防护措施,比如微信扫脸支付等功能禁用等,所以我们要了解MachO文件。

IOS 之FishHook原理及例子相关推荐

  1. iOS程序启动原理(上)

    为什么80%的码农都做不了架构师?>>>    iOS程序启动原理 Info.plist 常见设置 建立一个工程后,会在Supporting files文件夹下看到一个"工 ...

  2. iOS应⽤签名原理浅析

    目录 1. 前文 2. 数字签名 3. 简单代码签名 4. 双层代码签名 5. 描述文件 6. 结束语 1. 前文 还记得刚开始开发iOS APP的时候,总是在真机调试这块弄的云里雾里的,什么证书,什 ...

  3. iOS程序启动原理---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...

  4. IOS SEL (@selector) 原理及使用总结(一)

    SEL 类成员方法的指针 可以理解 @selector()就是取类方法的编号,他的行为基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应 ...

  5. iOS应用签名原理--数字签名?代码签名?双层代码签名?

    数字签名 数字签名(又称公钥数字签名.电子签章等)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法.一套数字签名通常定义两种互补的运算,一个用于签名,另一个 ...

  6. 如何理解苹果iOS版PhoneGap原理分析

    PhoneGap,著名的跨平台Hybrid框架,旨在让开发者使用HTML.Javascript.CSS开发跨平台的App. 最近的工作,就是做Hybrid方面的,很自然,方案就从PhoneGap入手. ...

  7. iOS 覆盖率检测原理与增量代码测试覆盖率工具实现

    背景 对苹果开发者而言,由于平台审核周期较长,客户端代码导致的线上问题影响时间往往比较久.如果在开发.测试阶段能够提前暴露问题,就有助于避免线上事故的发生.代码覆盖率检测正是帮助开发.测试同学提前发现 ...

  8. iOS开发·runtime原理与实践: 基本知识篇

    点击上方"iOS开发",选择"置顶公众号" 关键时刻,第一时间送达! 摘要:这篇文章首先介绍runtime原理,包括类,超类,元类,super_class,is ...

  9. iOS证书签名原理分析

    在iOS真机调试和发布上线的时候,我们可能已经习惯了配置各种证书.描述文件,等这一繁琐的步骤.但是对于背后我们为什么要配置这些东西,以及其背后的原理之前一直没有做过分析研究,最近有空就简单的研究了一下 ...

最新文章

  1. docke跨主机通信之gre隧道
  2. boost::gregorian模块实现自出生以来的天数的测试程序
  3. spring和springboot区别
  4. react leaflet_如何使用Leaflet在React中轻松构建地图应用
  5. 怎么让模糊的数字变清楚_一键模糊图像变清晰,好家伙!这款神器插件你值得拥有...
  6. 使用TensorFlow.js的AI聊天机器人三:改进了文本中的情感检测
  7. 学python要什么基础-学Python首先要学什么?
  8. MyCat分片规则之取模范围分片
  9. 中国物联网行业发展现状及竞争前景分析报告2022-2028年
  10. MES系统生产派工提高注塑行业生产效率
  11. HTPP的请求方式有哪些?
  12. 『软件推荐』PanDownload出安卓版了
  13. [运放滤波器]3_反相同相比例放大电路_Multisim电路仿真
  14. WordPress底部添加备案信息小技巧
  15. secureCRT及secureFX配置
  16. 电商运营的要点有哪些
  17. 西北乱跑娃 --- python opencv图像祛噪
  18. Xiaojie雷达之路再回首---TI文档总结
  19. MySql8安装错误信息:The service already exists!
  20. 画一条连接两点的线,由两点坐标确定一条直线

热门文章

  1. python多元线性回归实例_利用Python进行数据分析之多元线性回归案例
  2. 根据入栈顺序判断出栈顺序的合法性
  3. 同步电复律英文_同步电复律与非同步电复律有什么区别?
  4. 犹如“笼中困兽”的中国半导体,正在冒着敌人的炮火“匍匐前进”
  5. Ubuntu 笔记本 麦克风无声音解决方法
  6. 一汽启明的PDM解决方案
  7. egret新手引导反向遮罩
  8. 36.DAC工作原理与配置
  9. python calu()_python使用配置文件过程详解
  10. 成都 java_成都Java开发程序员薪资多少?