利用Objective-C运行时hook函数的三种方法
来源:互联网 发布:任我行定位软件 编辑:程序博客网 时间:2024/06/01 08:19
原文地址:http://blog.csdn.net/hursing/article/details/8688860
方法一,hook已有公开头文件的类:
首先写一个Utility函数:
- #import <objc/runtime.h>
- inline void exchangeMethod(Class aClass, SEL oldSEL, SEL newSEL)
- {
- Method oldMethod = class_getInstanceMethod(aClass, oldSEL);
- assert(oldMethod);
- Method newMethod = class_getInstanceMethod(aClass, newSEL);
- assert(newMethod);
- method_exchangeImplementations(oldMethod, newMethod);
- }
现在,目标是hook UIWebView没公开的函数
- - (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2;
因为已知类的声明,所以可以使用category:
- @interface UIWebView (Hook)
- + (void)hook;
- - (void)hook_webView:(id)arg1 didFinishLoadForFrame:(id)arg2;
- @end
- @implementation UIWebView (Hook)
- + (void)hook
- {
- // hook UIWebView中表示一个HTML的frame加载完毕的函数
- exchangeMethod([UIWebViewclass],
- @selector(webView:didFinishLoadForFrame:),
- @selector(hook_webView:didFinishLoadForFrame:));
- }
- - (void)hook_webView:(id)arg1 didFinishLoadForFrame:(id)arg2
- {
- // 因为交换了selector和implementation的映射,原样调一下本函数实际会调用被hook的函数。
- [self hook_webView:arg1 didFinishLoadForFrame:arg2];
- NSLog(@"webView:didFinishLoadForFrame:");
- }
方法二,hook没有公开头文件的类,需要另建一个类作为新函数载体,然后先为被hook的类增加函数,再替换:
UIWebView体系中有一个类叫UIWebBrowserView,它是真正显示网页的UIView,并有部分函数是作为WebCore向外发送回调信息的接收者。
现我们去hook UIWebBrowserView的这个函数:
- - (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2;
创建一个类,不要与被hook的类同名,例如加了个Hook后缀:
- @interface UIWebBrowserViewHook : NSObject
- + (void)hook;
- - (void)hook_webView:(id)arg1 didFinishLoadForFrame:(id)arg2;
- @end
- @implementation UIWebBrowserViewHook
- + (void)hook
- {
- Class aClass = objc_getClass("UIWebBrowserView");
- SEL sel = @selector(hook_webView:didFinishLoadForFrame:);
- // 为UIWebBrowserView增加函数
- class_addMethod(aClass, sel, class_getMethodImplementation([self class], sel), "v@:@@");
- // 交换实现
- exchangeMethod(aClass, @selector(webView:didFinishLoadForFrame:), sel);
- }
方法三,hook没有公开头文件的类,另建一个类作为新函数载体,用新函数替换旧函数,并把旧函数保存到静态变量里:
继续以UIWebBrowserView为例子。注意新函数可以与被hook的函数同名
- @interface UIWebBrowserViewHook : NSObject
- + (void)hook;
- - (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2;
- @end
- inline void replaceImplementation(Class newClass, Class hookedClass, SEL sel, IMP& oldImp)
- {
- Method old = class_getInstanceMethod(hookedClass, sel);
- IMP newImp = class_getMethodImplementation(newClass, sel);
- oldImp = method_setImplementation(old, newImp);
- }
当两个selector不同名时,以上函数再增加一个参数即可。
下面是实现:
- @implementation UIWebBrowserViewHook
- static IMP webView_didFinishLoadForFrame = NULL;
- + (void)hook
- {
- Class hookedClass = objc_getClass("UIWebBrowserView");
- SEL sel = @selector(webView:didFinishLoadForFrame:);
- replaceImplementation([self class], hookedClass, sel, webView_didFinishLoadForFrame);
- }
- - (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2
- {
- // 需要这样来调用被替换掉的原实现
- webView_didFinishLoadForFrame(self, @selector(webView:didFinishLoadForFrame:), arg1, arg2);
- NSLog(@"webView:didFinishLoadForFrame:");
- }
- @end
三种方法的比较:
最方便的当然是第一种,但需要是hook有公开头文件的类。
方法二和方法三都新建了一个类,方法二需要描述selector的types,这个比较麻烦,如例子中的"v@:@@"表示返回值为void,第一和第二个参数都是id。方法三不用types,但要增加全局变量。
Objective-C的runtime参考资料:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008048
- 利用Objective-C运行时hook函数的三种方法
- 利用Objective-C运行时hook函数的三种方法
- 利用Objective-C运行时hook函数的三种方法
- Hook Objective-C 的方法
- Objective-C运行时Hook函数避免Crash以及无码埋点的思路
- 三、Objective-c-运行时的理解
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- Objective-C Runtime 运行时之三:方法与消息
- WO+开放平台:API调用开发手记(关于签名字段)
- 嵌套div(块级元素)的静态定位
- Xcode6的新特性、iPhone6和iPhone6Plus的适配,xcode6iphone6
- 解决VS系列按ALT+G不能跳转问题
- 算法系列-----矩阵(七)-------------矩阵的除法
- 利用Objective-C运行时hook函数的三种方法
- C++ auto_ptr智能指针的用法
- flexslider 使用方式
- IE 8兼容:X-UA-Compatible的解释
- <cstdlib>头文件
- iReport5.6.0 linechart 制作方法
- HDU 2932 Extraordinarily Tired Students (暴力+取模还是很强大的)
- 【DB.PL/SQL】程序流程控制 —— GOTO语句
- 源码安装nginx,mysql模块(drizzle模块), memcache模块, redis模块