標籤:
Method Swizzling(方法調配)
怎麼說呢,先瞭解什麼是鉤子為什麼用鉤子,學過C++的朋友應該清楚,hook就是用來獲得(截斷/改變)底層調用的方法。這樣我們可以自由的修改或者讀取一些想要的東西。(個人理解)
下面是百度百科的解釋:鉤子(Hook),是Windows訊息處理機制的一個平台,應用程式可以在上面設定子程以監視指定視窗的某種訊息,而且所監視的視窗可以是其他進程所建立的。當訊息到達後,在目標視窗處理函數之前處理它。鉤子機制允許應用程式截獲處理window訊息或特定事件
那ios中我們就用Method Swizzling來實現,為什麼說是內部鉤子呢,因為需要在工程裡實現,我改天會分享外部的。
----------------------------------------------淩亂的分割線------------------------------------------
先瞭解一下SEL和IMP的概念,
SEL可以理解為函數名的意思,我們常用的@selector()就是通過字串獲得SEL
IMP可以理解成函數指標的意思,是能正確讀取到函數的內容
一般是這樣的:盜個圖
我們要做的就是把連結線解開,然後連到我們自訂的函數IMP上,如果有需要的話,我們再連回原來的IMP上
就是這樣的:
如果在執行完IMPn後還想繼續調用IMPc的話,只需要在IMPn中調用selectorN就行了。
---------------------------------------------淩亂的分割線----------------------------------------
具體怎麼做呢:
Method origMethod = class_getInstanceMethod(class, origSelector); //擷取SEL的Method
Method是一個結構體,我們想要的IMP就在裡面,看看結構
struct objc_method { SEL method_name OBJC2_UNAVAILABLE; char *method_types OBJC2_UNAVAILABLE; IMP method_imp OBJC2_UNAVAILABLE;}
IMP origIMP = method_getImplementation(origMethod); //擷取Method中的IMP
ok,IMP擷取到了,串連SEL到別的IMP呢
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types); //先增加新方法名SEL+原來的IMPIMP method_setImplementation(Method m, IMP imp); //然後將原來的method(SEL)重新分配新的IMP
void method_exchangeImplementations(Method m1, Method m2) //或者可以使用method的交換方法
---------------------------------------------淩亂的分割線-------------------------------------
實戰,假設我們想知道app跳轉都傳送了什麼值(如應用調用QQ分享什麼的),那麼我們可以勾取UIApplication的OpenUrl方法
#import "KHookObjectWrapper.h"#import "UIKit/UIKit.h"#import <objc/objc.h>#import <objc/runtime.h>@implementation KHookObjectWrapper+ (void)setup{ //openURL Method m = class_getInstanceMethod([UIApplication class], @selector(openURL:)); class_addMethod([UIApplication class], @selector(hook_openURL:), method_getImplementation(m), method_getTypeEncoding(m)); method_setImplementation(m, class_getMethodImplementation([self class], @selector(hook_openURL:)));}- (BOOL)hook_openURL:(NSURL *)url{ NSLog(@"hook_openURL:%@", [url absoluteString]); return [self hook_openURL:url];}
使用method的交換方法實現:
#import "KHookObjectWrapper.h"#import "UIKit/UIKit.h"#import <objc/objc.h>#import <objc/runtime.h>@implementation KHookObjectWrapper+ (void)setup{ //openURL Method m = class_getInstanceMethod([UIApplication class], @selector(openURL:)); Method m2 = class_getInstanceMethod([self class], @selector(hook_openURL:)); class_addMethod([UIApplication class], @selector(hook_openURL:), method_getImplementation(m), method_getTypeEncoding(m)); //為什麼要有這句的,因為UIApplication沒有hook_openURL方法會奔潰,大家覺得可以講self的hook_openURL改名成openURL,大家可以試試,也是不行的 method_exchangeImplementations(m, m2);}- (BOOL)hook_openURL:(NSURL *)url{ NSLog(@"hook_openURL:%@", [url absoluteString]); return [self hook_openURL:url];}@end
--------------------------------------------------------------------
另外再加一點,假如你只是想重寫類的某些方法,分類也是不錯的選擇,分類一旦加入工程,不需要包含標頭檔有會生效,所以請謹慎使用
@implementation UIApplication (test)- (BOOL)openURL:(NSURL*)url { NSLog(@"!!!!!%@", [url absoluteString]); return YES;}@end
當然你沒辦法重新在掉回原來的IMP了!
ios逆向工程-內部鉤子(Method Swizzling)