利用Objective-C运行时hook函数的三种方法
来源:互联网 发布:图像算法笔试题 编辑:程序博客网 时间:2024/06/15 22:52
方法一,hook已有公开头文件的类:
首先写一个Utility函数:
#import <objc/runtime.h>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([UIWebView class], @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:");}在程序启动的时候调用一下 [UIWebView hook] 即可。使用一个UIWebView打开一个网页,即会打印NSLog。
方法二,hook没有公开头文件的类,需要另建一个类作为新函数载体,然后先为被hook的类增加函数,再替换。
UIWebView体系中有一个类叫UIWebBrowserView,它是真正显示网页的UIView,并有部分函数是作为WebCore向外发送回调信息的接收者。
现我们去hook UIWebBrowserView的这个函数:
- (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2;嗯,是的,这个函数和UIWebView的一样,实际上就是UIWebBrowserView会再调用通知到UIWebView的同名函数。
创建一个类,不要与被hook的类同名,例如加了个Hook前缀:
@interface UIWebBrowserViewHook : NSObject+ (void)hook;- (void)hook_webView:(id)arg1 didFinishLoadForFrame:(id)arg2;@end其中以hook_为前缀的新增函数的实现与方法一中相同,差别在类函数中:
@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);}在程序启动的时候调用一下 [UIWebBrowserViewHook hook] 即可。使用一个UIWebView打开一个网页,即会打印NSLog。
方法三,hook没有公开头文件的类,另建一个类作为新函数载体,用新函数替换旧函数,并把旧函数保存到静态变量里:
继续以UIWebBrowserView为例子。注意新函数可以与被hook的函数同名
@interface UIWebBrowserViewHook : NSObject+ (void)hook;- (void)webView:(id)arg1 didFinishLoadForFrame:(id)arg2;@end需要用到另一个Utility函数:
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 UIWebBrowserViewHookstatic 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在程序启动的时候调用一下 [UIWebBrowserViewHook hook] 即可。使用一个UIWebView打开一个网页,即会打印NSLog。
三种方法的比较:
最方便的当然是第一种,但需要是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 运行时之三:方法与消息
- Error
- WindowManager.LayoutParams(下)
- 未来音乐的格式——Opus格式
- Mac OS X编译最新webkit(2013-03-15)
- 在windows和mac上以特定ua启动chrome的脚本
- 利用Objective-C运行时hook函数的三种方法
- Xcode3创建和使用iOS的dylib动态库
- 二进制/十六进制转浮点数的编程(互转类似)
- Python的一些环境配置
- iOS私有API(一) -[UIApplication _cancelAllTouches]
- iOS私有API(二) UIGestureRecognizerDelegate的两个函数
- asp.net 超时问题
- WebKit的ManualTests & PerformanceTests
- Mac上命令行获取iPhone/iPad的Identifier(UUID) 的方法