亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS開發中實現hook消息機制的方法探究

2020-07-26 03:33:25
字體:
來源:轉載
供稿:網友

Method Swizzling 原理

在Objective-C中調用一個方法,其實是向一個對象發送消息,查找消息的唯一依據是selector的名字。利用Objective-C的動態特性,可以實現在運行時偷換selector對應的方法實現,達到給方法掛鉤的目的。
每個類都有一個方法列表,存放著selector的名字和方法實現的映射關系。IMP有點類似函數指針,指向具體的Method實現。

我們可以利用 method_exchangeImplementations 來交換2個方法中的IMP,
我們可以利用 class_replaceMethod 來修改類,
我們可以利用 method_setImplementation 來直接設置某個方法的IMP,
……
歸根結底,都是偷換了selector的IMP,如下圖所示:

Method Swizzling 實踐


舉個例子好了,我想鉤一下NSArray的lastObject 方法,只需兩個步驟。
第一步:給NSArray加一個我自己的lastObject

復制代碼 代碼如下:

#import "NSArray+Swizzle.h" 
 
 
@implementation NSArray (Swizzle) 
 
 
- (id)myLastObject 

    id ret = [self myLastObject]; 
    NSLog(@"**********  myLastObject *********** "); 
    return ret; 

@end 

乍一看,這不遞歸了么?別忘記這是我們準備調換IMP的selector,[self myLastObject] 將會執行真的 [self lastObject] 。

第二步:調換IMP

復制代碼 代碼如下:

#import  
#import "NSArray+Swizzle.h" 
 
 
int main(int argc, char *argv[]) 

    @autoreleasepool { 
         
        Method ori_Method =  class_getInstanceMethod([NSArray class], @selector(lastObject)); 
        Method my_Method = class_getInstanceMethod([NSArray class], @selector(myLastObject)); 
        method_exchangeImplementations(ori_Method, my_Method); 
         
        NSArray *array = @[@"0",@"1",@"2",@"3"]; 
        NSString *string = [array lastObject]; 
        NSLog(@"TEST RESULT : %@",string);  
          
        return 0; 
    } 


控制臺輸出Log:

復制代碼 代碼如下:

2013-07-18 16:26:12.585 Hook[1740:c07] **********  myLastObject ***********  
2013-07-18 16:26:12.589 Hook[1740:c07] TEST RESULT : 3 


結果很讓人欣喜,是不是忍不住想給UIWebView的loadRequest: 加 TODO 了呢?

示例

有了這個原理,接下來讓我們來看一個實例:
下面先直接上源碼:
 

復制代碼 代碼如下:

//
//  TestHookObject.m
//  TestHookMessage
//
//  Created by mapleCao on 13-2-28.
//  Copyright (c) 2013年 mapleCao. All rights reserved.
//

#import "TestHookObject.h"
#import <objc/objc.h>
#import <objc/runtime.h>

@implementation TestHookObject

// this method will just excute once
+ (void)initialize
{
    // 獲取到UIWindow中sendEvent對應的method
    Method sendEvent = class_getInstanceMethod([UIWindow class], @selector(sendEvent:));
    Method sendEventMySelf = class_getInstanceMethod([self class], @selector(sendEventHooked:));
   
    // 將目標函數的原實現綁定到sendEventOriginalImplemention方法上
    IMP sendEventImp = method_getImplementation(sendEvent);
    class_addMethod([UIWindow class], @selector(sendEventOriginal:), sendEventImp, method_getTypeEncoding(sendEvent));
   
    // 然后用我們自己的函數的實現,替換目標函數對應的實現
    IMP sendEventMySelfImp = method_getImplementation(sendEventMySelf);
    class_replaceMethod([UIWindow class], @selector(sendEvent:), sendEventMySelfImp, method_getTypeEncoding(sendEvent));
}

/*
 * 截獲到window的sendEvent
 * 我們可以先處理完以后,再繼續調用正常處理流程
 */
- (void)sendEventHooked:(UIEvent *)event
{
    // do something what ever you want
    NSLog(@"haha, this is my self sendEventMethod!!!!!!!");
   
    // invoke original implemention
    [self performSelector:@selector(sendEventOriginal:) withObject:event];
}

@end



  下面我們來逐行分析一下上面的代碼:
 
  首先我們來看19行,這一行主要目的是獲取到UIWindow原生的sendEvent的Method(一個結構體,用來對方法進行描述),接著第20行是獲取到我們自己定義的類中的sendEvent的Method(這兩個方法的簽名必須一樣,否則運行時報錯)。第23行我們通過UIWindow原生的sendEvent的Method獲取到對應的IMP(一個函數指針),第24行使用運行時API Class_addMethod給UIWindow類添加了一個叫sendEventOriginal的方法,該方法使用UIWindow原生的sendEvent的實現,并且有著相同的方法簽名(必須相同,否則運行時報錯)。27行是獲取我們自定義類中的sendEventMySelf的IMP,28行是關鍵的一行,這一行的主要目的是為UIWindow原生的sendEvent指定一個新的實現,我們看到我們將該實現指定到了我們自己定義的sendEventMySelf上。到了這兒我們就完成了偷梁換柱,大功告成。
 
  執行上面這些行以后,我們就成功的將UIWindow的sendEvent重定向到了我們自己的寫的sendEventMySelf的實現,然后將其原本的實現重定向到了我們給它新添加的方法sendEventOriginal中。而sendEventMySelf中,我們首先可以對這個消息進行我們想要的處理,然后再通過41行調用sendEventOriginal方法轉到正常的執行流程。
 
  這塊兒你可能有個困惑 “我們自定義類中明明是沒有sendEventOriginal方法的???”
 
  為什么執行起來不報錯,而且還會正常執行?因為sendEventMySelf是UIWindow的sendEvent重定向過來的,所以在運行時該方法中的self代表的就是UIWindow的實例,而不再是TestHookObject的實例了。加上sendEventOriginal是我們通過運行時添加到UIWindow的實例方法,所以可以正常調用。當然如果直接通過下面這種方式調用也是可以的,只不過編譯器會提示警告(編譯器沒那么智能),因此我們采用了performSelector的調用方式。
 

復制代碼 代碼如下:

[self sendEventOriginal:event];

  以上就是Hook的實現,使用時我們只需要讓TestHookObject類執行一次初始話操作就可以了,執行完以后。UIWindow的sendEvent消息就會會hook到我們的sendEventMySelf中了。
 
  下面是調用代碼:
 
 
 

復制代碼 代碼如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.viewController = [[[TestHookViewController alloc] initWithNibName:@"TestHookViewController" bundle:nil] autorelease];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
   
   
    //hook UIWindow‘s SendEvent method
    TestHookObject *hookSendEvent = [[TestHookObject alloc] init];
    [hookSendEvent release];
   
    UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    btn.center = CGPointMake(160, 240);
    btn.backgroundColor = [UIColor redColor];
    [btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventAllEvents];
    [self.window addSubview:btn];
    [btn release];
   
    return YES;
}


代碼中我們還專門添加了一個button來驗證,hook完以后消息是否正常傳遞。經驗證消息流轉完全正常。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美一级在线亚洲天堂| 精品亚洲精品福利线在观看| 国产综合福利在线| 4438全国成人免费| 欧美激情精品久久久| 欧美高清videos高潮hd| 国产精品欧美亚洲777777| 91久久精品久久国产性色也91| 国产精品视频免费在线| 97视频在线观看播放| 日韩va亚洲va欧洲va国产| 91av在线免费观看视频| 美日韩精品视频免费看| 亚洲第一福利网站| 一区二区三区回区在观看免费视频| 成人精品一区二区三区电影免费| 九九久久综合网站| 欧美日韩中文字幕综合视频| 精品国产鲁一鲁一区二区张丽| 亚洲毛茸茸少妇高潮呻吟| 亚洲欧美国产精品久久久久久久| 亚洲毛片一区二区| 欧美日韩在线一区| 欧美激情一区二区三级高清视频| 成人久久一区二区| 92国产精品视频| 亚洲国产成人精品久久久国产成人一区| 亚洲第一页中文字幕| 日韩成人在线网站| 国内精品免费午夜毛片| 91精品久久久久久久久不口人| 欧美亚洲第一页| 国产精品久久久久久久久久久久久| 精品国产一区二区三区在线观看| 国产精品自在线| 久久久久久国产精品三级玉女聊斋| 日韩中文字幕av| 亚洲精品一区二区网址| 久久久在线视频| 亚洲精品久久久久久下一站| 成人福利视频网| 少妇精69xxtheporn| 国产精品高清网站| 国产精国产精品| 岛国视频午夜一区免费在线观看| 日韩av综合中文字幕| 亚洲已满18点击进入在线看片| 久久99热精品这里久久精品| 韩国日本不卡在线| 久久99久久99精品中文字幕| 97在线观看免费| 成人黄色av网| 亚洲精品国产精品国产自| 精品久久久免费| 欧美国产精品人人做人人爱| 午夜精品一区二区三区在线视| 2019中文字幕在线| 亚洲成人a级网| 亚洲精品欧美日韩| 91亚洲国产成人精品性色| 国产日韩欧美电影在线观看| 91久久精品国产91久久性色| 国产在线观看一区二区三区| 欧美另类第一页| 爽爽爽爽爽爽爽成人免费观看| 欧美精品18videosex性欧美| 成人性生交大片免费观看嘿嘿视频| 亚洲天堂男人天堂女人天堂| 欧美激情aaaa| 欧美性感美女h网站在线观看免费| 热久久美女精品天天吊色| 国产精品美乳一区二区免费| 久热精品在线视频| 这里只有视频精品| 最近2019中文免费高清视频观看www99| 狠狠色香婷婷久久亚洲精品| 亚洲女人被黑人巨大进入| 欧美成人黄色小视频| 欧美激情精品久久久久久久变态| 亚洲美女免费精品视频在线观看| 欧美激情精品久久久久久免费印度| 日日狠狠久久偷偷四色综合免费| 国产欧美日韩免费看aⅴ视频| 国产精品久久久久999| 国产福利精品视频| 亚洲欧美日韩在线一区| 日日摸夜夜添一区| 国产精品视频一区国模私拍| 午夜精品理论片| 亚洲人成人99网站| 日韩欧美精品网站| 亚洲欧美国产制服动漫| 亚洲精品网址在线观看| 欧美福利视频在线观看| 国产精品免费一区| 福利精品视频在线| 不卡伊人av在线播放| 欧美一区二粉嫩精品国产一线天| 国产精品香蕉国产| 在线不卡国产精品| 欧美精品一区二区免费| 国产成人精品久久| 欧美精品videosex极品1| 亚洲精品网站在线播放gif| 国产主播欧美精品| 欧美精品videossex88| 国产91网红主播在线观看| 91av在线免费观看视频| 91精品国产九九九久久久亚洲| 这里只有精品视频在线| 亚洲精品欧美日韩专区| 日韩禁在线播放| 91欧美视频网站| 国产精品久久久久久久久免费看| 欧美成人三级视频网站| 日韩av有码在线| 欧美性猛交xxxx富婆| 精品欧美激情精品一区| 亚洲乱码av中文一区二区| 青青草原一区二区| 亚洲人成绝费网站色www| 国产精品成人v| 久久高清视频免费| 欧美精品久久久久久久久| 亚洲欧美日韩中文视频| 精品久久香蕉国产线看观看亚洲| 国产精品三级久久久久久电影| 中文字幕亚洲色图| 国产手机视频精品| 日本亚洲精品在线观看| 日韩免费在线电影| 日本国产高清不卡| 日韩av免费看| 精品美女国产在线| 欧美精品成人91久久久久久久| 国产精品美女主播| 欧美精品videossex88| 国产高清在线不卡| 久久久久久com| 日本成熟性欧美| 欧美华人在线视频| 国产成人亚洲综合青青| 国产美女久久精品香蕉69| 欧美在线欧美在线| 亚洲qvod图片区电影| 大胆人体色综合| 中文精品99久久国产香蕉| 欧美性xxxxhd| 欧美性猛交xxxx乱大交极品| 激情久久av一区av二区av三区| 国语自产偷拍精品视频偷| 欧美夜福利tv在线| 国外成人在线视频| 不卡av在线播放| 欧美激情a∨在线视频播放| 日韩久久精品成人| 欧美成人免费大片| 欧美精品videosex性欧美| 尤物精品国产第一福利三区| 亚洲老司机av| 亚洲女人天堂色在线7777| 国产欧美日韩中文字幕在线| 日韩成人网免费视频| 91免费高清视频|