HOOK概述
HOOK(鉤子) 其實就是改變程序執行流程的一種技術的統稱!
iOS中HOOK技術的幾種方式
1、Method Swizzle
利用OC的Runtime特性,動態改變SEL(方法編號)和IMP(方法實現)的對應關系,達到OC方法調用流程改變的目的。主要用于OC方法。
2、fishhook
它是Facebook提供的一個動態修改鏈接mach-O文件的工具。利用MachO文件加載原理,通過修改懶加載和非懶加載兩個表的指針達到C函數HOOK的目的。
https://github.com/facebook/fishhook
==fishhook在OC中的使用:==
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"123");
//定義rebinding結構體
struct rebinding nslogBind;
//函數的名稱
nslogBind.name = "NSLog";
//新的函數地址
nslogBind.replacement = myLog;
//保存原始函數地址的變量的指針
nslogBind.replaced = (void *)&old_mylog;
//定義數組
struct rebinding rebindings[] = {nslogBind};
/*
arg1 : 存放rebinding結構體的數組
arg2 : 數組的長度
*/
rebind_symbols(rebindings, 1);
}
//函數指針,用來保存原始的函數地址
static void (*old_mylog)(NSString *format, ...);
//新的NSLog
void myLog(NSString *format, ...) {
format = [format stringByAppendingString:@"\n勾上了!"];
//再調用原來的
old_mylog(format);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"點擊了屏幕!!!");
}
@end
==NSLog的綁定過程:==
在MachO文件中查看NSLog的內存地址
(lldb) image list
[ 0] D92A4EC1-406D-3C26-9F39-C3D4A46A2948 0x00000001049f4000 /Users/yaoqi/Library/Developer/Xcode/DerivedData/001-fishHookDemo-cwtlojyvecrawmdgeiokwkgwddql/Build/Products/Debug-iphoneos/001-fishHookDemo.app/001-fishHookDemo
[ 1] 477A8A1F-098B-3A80-860D-656A3F4918EA 0x0000000104d38000 /Users/yaoqi/Library/Developer/Xcode/iOS DeviceSupport/11.2.1 (15C153)/Symbols/usr/lib/dyld
[ 2] B0F8DF97-77EC-3600-8A9F-35035B889EFD 0x0000000184dd9000 /Users/yaoqi/Library/Developer/Xcode/iOS DeviceSupport/11.2.1 (15C153)/Symbols/System/Library/Frameworks/Foundation.framework/Foundation
(lldb) x 0x00000001049f4000+0x8018
0x1049fc018: 24 af de 84 01 00 00 00 34 b9 dd 84 01 00 00 00 $.......4.......
0x1049fc028: 90 f5 a2 8d 01 00 00 00 58 ab 9f 04 01 00 00 00 ........X.......
(lldb) dis -s 0x0184deaf24
Foundation`NSLog:
0x184deaf24 <+0>: sub sp, sp, #0x20 ; =0x20
0x184deaf28 <+4>: stp x29, x30, [sp, #0x10]
0x184deaf2c <+8>: add x29, sp, #0x10 ; =0x10
0x184deaf30 <+12>: add x8, x29, #0x10 ; =0x10
0x184deaf34 <+16>: str x8, [sp, #0x8]
0x184deaf38 <+20>: add x1, x29, #0x10 ; =0x10
0x184deaf3c <+24>: mov x2, x30
0x184deaf40 <+28>: bl 0x184ec6d38 ; _NSLogv
(lldb) ni
(lldb) ni
(lldb) ni
(lldb) ni
(lldb) ni
(lldb) ni
(lldb) x 0x00000001049f4000+0x8018
0x1049fc018: bc 9d 9f 04 01 00 00 00 34 b9 dd 84 01 00 00 00 ........4.......
0x1049fc028: 90 f5 a2 8d 01 00 00 00 3c ee f7 83 01 00 00 00 ........<.......
(lldb) dis -s 0x01049f9dbc
001-fishHookDemo`myLog:
0x1049f9dbc <+0>: sub sp, sp, #0x30 ; =0x30
0x1049f9dc0 <+4>: stp x29, x30, [sp, #0x20]
0x1049f9dc4 <+8>: add x29, sp, #0x20 ; =0x20
0x1049f9dc8 <+12>: mov x8, #0x0
0x1049f9dcc <+16>: stur x8, [x29, #-0x8]
0x1049f9dd0 <+20>: sub x9, x29, #0x8 ; =0x8
0x1049f9dd4 <+24>: str x0, [sp, #0x10]
0x1049f9dd8 <+28>: mov x0, x9
(lldb)
==NSLog在MachO文件中的反向查找過程:==
3、Cydia Substrate
Cydia Substrate 原名為 Mobile Substrate ,它的主要作用是針對OC方法、C函數以及函數地址進行HOOK操作。當然它并不是僅僅針對iOS而設計的,安卓一樣可以用。官方地址:
http://www.cydiasubstrate.com/
?
Cydia Substrate主要由3部分組成:
- MobileHooker
MobileHooker顧名思義用于HOOK。它定義一系列的宏和函數,底層調用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 就是對此函數做了一層封裝
- MobileLoader
MobileLoader用于加載第三方dylib在運行的應用程序中。啟動時MobileLoader會根據規則把指定目錄的第三方的動態庫加載進去,第三方的動態庫也就是我們寫的破解程序.
- safe mode
因為APP程序質量參差不齊崩潰再所難免,破解程序本質是dylib,寄生在別人進程里。 系統進程一旦出錯,可能導致整個進程崩潰,崩潰后就會造成iOS癱瘓。所以CydiaSubstrate引入了安全模式,在安全模 式下所有基于CydiaSubstratede 的三方dylib都會被禁用,便于查錯與修復。
代碼的基本防護
==注入的Framework庫中的Hook代碼:==
#import "hookMgr.h"
#import "fishhook.h"
#import <objc/message.h>
@implementation hookMgr
//專門HOOK
+(void)load
{
NSLog(@"hookMgr--Load");
//內部用到的交換代碼!
Method old = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick1:));
Method new = class_getInstanceMethod(self, @selector(click1Hook:));
method_exchangeImplementations(old, new);
//基本防護
struct rebinding bd;
bd.name = "method_exchangeImplementations";
bd.replacement = myExchang;
bd.replaced = (void *)&exchangeP;
struct rebinding bd1;
bd1.name = "method_getImplementation";
bd1.replacement = myExchang;
bd1.replaced = (void *)&getIMP;
struct rebinding bd2;
bd2.name = "method_setImplementation";
bd2.replacement = myExchang;
bd2.replaced = (void *)&setIMP;
// method_getImplementation
// method_setImplementation
struct rebinding rebindings[] = {bd,bd1,bd2};
rebind_symbols(rebindings, 3);
}
//保留原來的交換函數
IMP _Nonnull (*setIMP)(Method _Nonnull m, IMP _Nonnull imp);
IMP _Nonnull (*getIMP)(Method _Nonnull m);
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
//新的函數
void myExchang(Method _Nonnull m1, Method _Nonnull m2){
NSLog(@"檢測到了HOOK!!!");
//強制退出!
exit(1);
}
-(void)click1Hook:(id)sendr{
NSLog(@"原來APP的HOOK保留!!");
}
@end
==使用Monkey創建的工程去Hook App中的代碼:==
如果別人要Hook自己寫的App中的代碼,就會閃退。
// 修改 MachO
#import <UIKit/UIKit.h>
%hook ViewController
- (void)btnClick2:(id)org
{
NSLog(@"??????????????????????????????");
exit(0);
}
%end
HOOK原理總結
- MachO文件是被誰加載?DYLD(負責加載系統動態庫)加載
- ASLR技術 MachO文件加載的時候是隨機地址
- PIC位置代碼獨立
如果MachO內部需要調用系統的庫函數
現在_DATA段(可讀可寫)中建立一個指針,指向外部函數
DYLD會動態的進行綁定,將MachO中的_DATA中的指針,指向外部函數
_DATA中的指針就是一個symbols