上一篇文章: "心旷神怡:挖掘LLDB调试的无限可能性"
前篇文章介绍了如何运用LLDB进行动态调试。在本篇中,我们将深入探讨HOOK的原理。
回顾之前的内容,我们已经了解了一些关于HOOK的知识,包括如何通过砸壳、使用class-dump工具来获取目标应用的信息,并且实现了在tweak工程中进行类的hook等一系列操作,从而实现我们想要的功能。
因此,我们不仅需要掌握如何熟练地使用HOOK技术,还需要理解其背后的原理。
1.HOOK本质
-
HOOK
,中文称之为“钩子”,意味着在程序执行过程中插入的一种机制,可以用来监视、修改或者拦截程序的行为。
注意
HOOK技术实质上是一种改变程序执行流程的技术。在软件工程中,程序的执行流程是按照一定的逻辑和顺序进行的,而HOOK技术可以介入这个流程,改变其正常执行的路径,从而实现特定的功能或修改程序的行为。
举例来说,我们可以考虑视频广告的情况。在某些应用中,如果用户不是会员,就需要观看一定时长的广告才能继续使用。通过使用HOOK技术,我们可以修改应用的代码,以拦截广告播放的部分,从而实现跳过广告的效果。这个例子只是一个示范,实际上,HOOK技术可以应用于各种场景,包括增加功能、修改行为、调试应用等等。
当然,拦截广告只是HOOK技术的一个应用案例,实际上,它的应用远不止于此。在以后的技术分享中,我们可以进一步探讨不同的应用场景和具体实现方法。
2.HOOK原理
-
1.
HOOK原理第一种方式,通过Method Swizzle进行实现.
首先,Method Swizzle离不开Objective-C的运行时(Runtime)特性,因为它需要在运行时动态地交换方法的实现。其次,这项技术在越狱平台和非越狱平台都可以使用。
另外,提到了通过交换两个selector来实现方法交换调用,这是Method Swizzle的核心原理之一。通过交换两个方法的实现,可以改变原本的方法调用顺序或行为,从而实现一些特定的功能或修复bug。
2.1
方法的实现保存在IMP(Implementation)中,这是一种函数指针,指向了具体的方法实现代码。
2.2
Runtime提供了修改IMP和交换两个IMP实现的方法。
案例
ViewController.m
#import "ViewController.h"
#import <Objc/Runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self originalMehtod];
[self newMethod];
}
+ (void)load{
Class class = [self class];
SEL originalSelector = @selector(originalMehtod);
SEL newSelector = @selector(newMethod);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method newMethod = class_getInstanceMethod(class, newSelector);
method_exchangeImplementations(originalMethod,newMethod);
}
-(void)originalMehtod{
NSLog(@"原方法");
}
-(void)newMethod{
NSLog(@"新方法");
}
@end
结果
2020-02-27 15:50:24.226036+0800 SwizzleMethod[4372:221449] 新方法
2020-02-27 15:50:24.226125+0800 SwizzleMethod[4372:221449] 原方法
我们通过方法的交换实现,修改了方法的调用.
-
3.
如果我们在新创建的方法调用自己,会不会循环调用?
我们看一下调用结果
-(void)newMethod{
NSLog(@"新方法");
[self newMethod];
}
打印结果
2020-02-27 15:54:47.515105+0800 SwizzleMethod[4475:226449] 新方法
2020-02-27 15:54:47.515193+0800 SwizzleMethod[4475:226449] 原方法
2020-02-27 15:54:47.515261+0800 SwizzleMethod[4475:226449] 原方法
通过结果可见,我们成功地利用方法交换技术修改了方法的调用,避免了循环调用的问题。
Method Swizzling技术,我们可以在用户无感知的情况下拦截某个方法并进行统计处理。
3. Cydia Substrate
Cydia Substrate地址: Cydia Substrate
To install Substrate, you will need to "jailbreak" your device, as making
changes to other software is not something that Apple normally allows.
要安装Substrate,你需要“jailbreak”你的设备,因为修改其他软件不是苹果通常允许的。
Depending on your iOS version and device, you will need to use one of a
few different jailbreaking tools such as redsn0w or evasi0n.
根据你的iOS版本和设备,你需要使用一些不同的越狱工具,如redsn0w或evasi0n。
The various jailbreaking tools install Cydia Installer, which you can then
use to install Substrate and any of thousands of Substrate extensions.
各种越狱工具安装Cydia安装程序,然后您可以使用它们来安装Substrate和数千个Substrate扩展中的任何一个。
- Cydia Substrate
针对OC方法
,C函数
以及函数地址进行HOOK操作.从上图可以看到,Android和iOS都可以使用.
1.
MobileHooker
MobileHooker 替换系统函数
void MSHookMessageEx(Class _class, SEL message, IMP hook, IMP *old);
void MSHookFunction(void *symbol, void *hook, void **old);
MSHookMessageEx 主要作用于OC函数,Logos语法主要是对MSHookFunction函数进行了封装.
关于
Logos语法
的文章在这里: iOS逆向之Logos语法介绍,大家可以了解一下.MSHookFunction 主要作用于C和C++函数
2.
MSHookMessageEx的使用
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
MSHookMessageEx([NSObject class], @selector(description), &newDescription, &oldDescription);
}
NSString * (* oldDescription)(id self , SEL _cmd);
NSString *newDescription(id self, SEL _cmd){
NSString * description = (*oldDescription)(self,_cmd);
description = [description stringByAppendingString:@"!"];
return description;
}
我们首先创建oldDescription
用于保存原来的NSString类description方法的地址,通过实现新的newDescription
.
最后通过MSHookMessageEX函数替换原来的description方法,实现Hook.
刚才有提到,其实Logos语法是对MSHookMessageEx函数的封装.
3.
MSHookFunction
MSHookFunction函数的作用对象是C,C++函数,然后C,C++并不提供runtime这种高级的API
,所以我们想HOOK更加困难.
void MSHookFunction(void *symbol, void *hook, void **old);
- MSHookFunction 三个参数分别是 替换的原函数,替换函数,MobileHooker保存的原函数.
void (*oldFunction)(void);
void newFunction(void){
MSImageRef image = MSGetImageByName("");
void * symbol = MSFindSymbol(image, "symbol");
if (symbol) {
MSHookFunction((void *)symbol, (void *)&newFunction,(void **)&oldFunction);
}else{
NSLog(@"没有symbol");
}
}
我们通过定义原方法用户保存要HOOK函数被替换的指令,
接着实现新的newFunction方法,使用MSHookFunction
来对修改的函数进行Hook.
4.
MobileLoader
MobileLoader 加载第三方dylib在运行的应用程序中.
4.1
MobileLoader主要是系统启动时由Launchd进程将Mobileloader加载进内存
4.2
Moblieloader会通过环境变量(DYLD_INSERT_LIBRARIES
)将自己加载进设备各个进程
4.3
并遍历 /Library/MobileSubstrate/DynamicLibraries/目录下的文件,如下图
4.4
每个dylib及plist文件来确定dylib的作用范围.如果当前进程满足该作用范围,则会使用dlopen函数加载对应的dylib.
5.
SafeMode
注入应用进程,修改应用的逻辑存在一定风险.因为寄生在应用进程中,系统进程很容易造成崩溃.如果崩溃的是SpringBoard等系统进程,则会造成系统瘫痪.
我们可以在安全模式下进行第三方插件的禁用,卸载,从而帮助系统修复.
4.Fishhook
注意
本篇文章不会过多介绍Fishhook的内容,下一篇文章将会专门针对Fishhook进行详细介绍。
总结
1.
本篇文章主要介绍了HOOK的原理。2.
我们探讨了三种通过HOOK实现的方式:Method Swizzle(利用runtime机制进行hook)、Cydia Substrate和FishHook。