ios逆向工程-內部鉤子(Method Swizzling)

Method Swizzling(方法調配)ios

怎麼說呢,先了解什麼是鉤子爲何用鉤子,學過C++的朋友應該清楚,hook就是用來得到(截斷/改變)底層調用的方法。這樣咱們能夠自由的修改或者讀取一些想要的東西。(我的理解)app

下面是百度百科的解釋:鉤子(Hook),是Windows消息處理機制的一個平臺,應用程序能夠在上面設置子程以監視指定窗口的某種消息,並且所監視的窗口能夠是其餘進程所建立的。當消息到達後,在目標窗口處理函數以前處理它。鉤子機制容許應用程序截獲處理window消息或特定事件函數

那ios中咱們就用Method Swizzling來實現,爲何說是內部鉤子呢,由於須要在工程裏實現,我改天會分享外部的。url

----------------------------------------------凌亂的分割線------------------------------------------spa

先了解一下SEL和IMP的概念,指針

SEL能夠理解爲函數名的意思,咱們經常使用的@selector()就是經過字符串得到SELcode

IMP能夠理解成函數指針的意思,是能正確讀取到函數的內容htm

通常是這樣的:盜個圖進程

咱們要作的就是把連接線解開,而後連到咱們自定義的函數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+原來的IMP
IMP 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了!

相關文章
相關標籤/搜索