runtime添加屬性&方法,hook小結(jié)

前端時(shí)間看了一些逆向工程誉尖,掃了一眼'小黃書'辛掠,不得不感嘆runtime的強(qiáng)大之處。在不越獄情況下注入一些dylib來hook定位释牺,步數(shù)等系統(tǒng)函數(shù)后萝衩,發(fā)現(xiàn)用到的工具都是高度封裝好的,就回頭寫了一個(gè)runtime的小例子;

①動(dòng)態(tài)添加屬性

建立公開類的Category没咙,此處以UIWebView為例子猩谊;
引如objc/runtime.h,聲明屬性:

#import "UIWebView+Swizzling.h"
#import <objc/runtime.h>
@interface UIWebView ()
@property(nonatomic,copy)NSString* associatedProp;
@end

runtimeobjc_setAssociatedObject實(shí)現(xiàn)setter祭刚,objc_getAssociatedObject實(shí)現(xiàn)getter

-(void)setAssociatedProp:(NSString *)associatedProp{
    objc_setAssociatedObject(self, &associatedPropKey, associatedProp, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString*)associatedProp{
    return objc_getAssociatedObject(self, &associatedPropKey);
}

使用:

[self.webView setValue:@"associatedPropSuccess" forKey:@"associatedProp"];
NSLog(@"\nassociatedProp:%@",[self.webView valueForKey:@"associatedProp"]);

打优平荨:

image.png

②hook公開類的public||private方法

建立公開類的Category,此處以UIWebViewloadRequest:webView:didFinishLoadForFrame:為例子涡驮;
使用class-dump可以查看很多私有方法暗甥;
+(void)load方法中如下(為什么在load中?可以想一下):

@implementation UIWebView (Swizzling)
+ (void)load
{
    //hook公開類的public方法
    Method loadRequest = class_getInstanceMethod([self class], NSSelectorFromString(@"loadRequest:"));
    Method swizzling_loadRequest = class_getInstanceMethod([self class], @selector(swizzling_loadRequest:));
    method_exchangeImplementations(loadRequest, swizzling_loadRequest);
    //hook公開類&private方法
    Method didFinishLoadForFrame = class_getInstanceMethod([self class], NSSelectorFromString(@"webView:didFinishLoadForFrame:"));
    Method swizzling_didFinishLoadForFrame = class_getInstanceMethod([self class], @selector(swizzling_webView:didFinishLoadForFrame:));
    method_exchangeImplementations(didFinishLoadForFrame, swizzling_didFinishLoadForFrame);
}

可以看到這個(gè)方法獲取了UIWebView中兩個(gè)方法的入口imp并且交換了捉捅,效果從A->a B->b變成了A->b B->a;
下面只需要實(shí)現(xiàn)我們自己的方法:

- (void)swizzling_loadRequest:(id)request;
{
    NSLog(@"\nswizzling_loadRequest\narg1:%@\n",request);
    [self swizzling_loadRequest:request];
}
-(void)swizzling_webView:(id)webView didFinishLoadForFrame:(id)frame{
    NSLog(@"\nswizzling_didFinishLoadForFrame\narg1:%@\narg2:%@\n",webView,frame);
    [self swizzling_webView:webView didFinishLoadForFrame:frame];
}

由于imp互換撤防,當(dāng)UIWebView調(diào)用loadRequest時(shí)會(huì)進(jìn)入我們的swizzling_loadRequest:(id)request,而我們調(diào)用時(shí)候也是如此棒口,不會(huì)產(chǎn)生遞歸寄月;
打庸枷ァ:

image.png

image.png

③hook未知類的方法,如代理

如果我們想要hook一個(gè)代理方法漾肮,甚至一個(gè)未知viewControllerviewDidLoad厂抖,又要怎么做呢?
這里我們以UIWebViewwebViewDidStartLoad:舉例克懊;

(webView:??????)

步驟如上忱辅,不過要先考慮一下實(shí)現(xiàn)代理方法前提是一定遵循了代理,那我們可以從setDelegate:入手:

+ (void)load{
    Method setDegelagte = class_getInstanceMethod([self class], NSSelectorFromString(@"setDelegate:"));
    Method swizzling_setDelegate = class_getInstanceMethod([self class], @selector(swizzling_setDelegate:));
    method_exchangeImplementations(setDegelagte, swizzling_setDelegate);
}
const char *type = "v@:@@";
//v==void,@==object,:=selector 詳查Type Encoding
-(void)swizzling_setDelegate:(id)delegate{
    [self swizzling_setDelegate:delegate];
    Class vc = [delegate class];
    NSLog(@"\nswizzling_delegateClass\nclass:%@\n",vc);

    if ([vc isSubclassOfClass:[UIViewController class]]) {
        //不同于load方法谭溉,設(shè)置單例保證交換1次
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            //生命周期不同 所以先加入目標(biāo)類中 再在目標(biāo)類中進(jìn)行exchange
            class_addMethod(vc, @selector(swizzling_webViewDidStartLoad:), class_getMethodImplementation([self class], @selector(swizzling_webViewDidStartLoad:)), type);
            Method webViewDidStartLoad = class_getInstanceMethod(vc, NSSelectorFromString(@"webViewDidStartLoad:"));
            Method swizzling_webViewDidStartLoad = class_getInstanceMethod(vc, @selector(swizzling_webViewDidStartLoad:));
            method_exchangeImplementations(webViewDidStartLoad, swizzling_webViewDidStartLoad);
            NSLog(@"addMethodOK?:%d",class_addMethod(vc, @selector(addMethod), class_getMethodImplementation([self class], @selector(addMethod)), type));;
        });
    }
}

我們首先讓方法順利執(zhí)行耕蝉,然后就可以獲取到delegate的class,但是此時(shí)機(jī)不唯一夜只,所以要在單例中進(jìn)行exchange垒在;
由于exchange方法的類不是UIWebView,所以要先把方法add到delegate class扔亥,然后再進(jìn)行exchange场躯;
同時(shí)在目標(biāo)類中加入了一個(gè)方法;
接下來實(shí)現(xiàn):

-(void)swizzling_webViewDidStartLoad:(id)webView{
    NSLog(@"\nswizzling_webViewDidStartLoad\n");
    //執(zhí)行添加的方法 此處已進(jìn)入目標(biāo)類 直接執(zhí)行self addMethod
    [self addMethod];
    [self swizzling_webViewDidStartLoad:webView];
}
-(void)addMethod{
    NSLog(@"addMethodRunSuccess");
    [self performSelector:NSSelectorFromString(@"back:") withObject:nil afterDelay:1];
}

再看看打勇眉贰:

image.png

至此我們已經(jīng)利用UIWebViewdelegate成功獲取到目標(biāo)class并hook代理方法踢关,添加了自定義方法并調(diào)用;

小結(jié)

可以猜測(cè)逆向工程正是利用runtime粘茄,先編譯Category到dylib签舞,再把動(dòng)態(tài)的dylib壓到二進(jìn)制文件讀取列表中,再進(jìn)行重簽名柒瓣,在app運(yùn)行時(shí)會(huì)加載我們的Category儒搭,從而完成hook等操作;
runtime和Category了解的還是不夠多芙贫,有時(shí)間真的要把runtime中的api研究一下搂鲫。。磺平。
一點(diǎn)小的見解魂仍,還望各位多多交流和教導(dǎo)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拣挪,一起剝皮案震驚了整個(gè)濱河市擦酌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌菠劝,老刑警劉巖赊舶,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡锯岖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門甫何,熙熙樓的掌柜王于貴愁眉苦臉地迎上來出吹,“玉大人,你說我怎么就攤上這事辙喂〈防危” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵巍耗,是天一觀的道長秋麸。 經(jīng)常有香客問我,道長炬太,這世上最難降的妖魔是什么灸蟆? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮亲族,結(jié)果婚禮上炒考,老公的妹妹穿的比我還像新娘。我一直安慰自己霎迫,他們只是感情好斋枢,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著知给,像睡著了一般瓤帚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涩赢,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天戈次,我揣著相機(jī)與錄音,去河邊找鬼筒扒。 笑死朝扼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的霎肯。 我是一名探鬼主播擎颖,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼观游!你這毒婦竟也來了搂捧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤懂缕,失蹤者是張志新(化名)和其女友劉穎允跑,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡聋丝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年扣蜻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膘盖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖翎迁,靈堂內(nèi)的尸體忽然破棺而出巡蘸,到底是詐尸還是另有隱情咐蚯,我是刑警寧澤健无,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站火惊,受9級(jí)特大地震影響求类,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屹耐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一尸疆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惶岭,春花似錦仓技、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兆衅,卻和暖如春地沮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背羡亩。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工摩疑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畏铆。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓雷袋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辞居。 傳聞我的和親對(duì)象是個(gè)殘疾皇子楷怒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,686評(píng)論 0 9
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫瓦灶、插件鸠删、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,058評(píng)論 4 62
  • objc_getAssociatedObject返回與給定鍵的特定對(duì)象關(guān)聯(lián)的值。ID objc_getAssoci...
    有一種再見叫青春閱讀 1,567評(píng)論 0 7
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 729評(píng)論 0 2
  • iOS操作多線程的四種方法 Pthreads(C語言框架贼陶,基本不用***主要是不會(huì)??) NSThread(Appl...
    家丁三鍋閱讀 129評(píng)論 0 0