利用Objective-C运行时hook函数的三种方法
版权声明:转载请注明出处:http://blog.csdn.net/hursing
方法一,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 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
在程序启动的时候调用一下 [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函数的三种方法的更多相关文章
- 微信小程序使用函数的三种方法
使用来自不同页面的函数 函数写在util.js页面 function formatTime(date) { var year = date.getFullYear() var month = date ...
- javascript函数 (二 定义函数的三种方法)
javascript定义函数(声明函数)可以有三种方法:正常方法.构造函数.函数直接量 <html><head></head><body> <sc ...
- matlab拟合函数的三种方法
方法一:多项式拟合polyfit 1 x=[1 2 3 4 5 6 7 8 9]; 2 3 y=[9 7 6 3 -1 2 5 7 20]; 4 P= polyfit(x, y, 3) %三阶多项式拟 ...
- jQuery添加自定义函数的三种方法
原文链接:http://caibaojian.com/284.html 方法一: jQuery.fn.setApDiv=function () { //apDiv浮动层显示位置居中控制 var whe ...
- 利用matlab求图像均值和方差的几种方法
一.求均值 % 求一副灰度图像的均值 close all; clear; clc; i=imread('d:/lena.jpg'); %载入真彩色图像 i=rgb2gray(i); %转换为灰度图 i ...
- Objective C运行时(runtime)
#import <objc/runtime.h> void setBeingRemoved(id __self, SEL _cmd) { NSLog(@"------------ ...
- js字符串转换为数字的三种方法。(转换函数)(强制类型转换)(利用js变量弱类型转换)
js字符串转换为数字的三种方法.(转换函数)(强制类型转换)(利用js变量弱类型转换) 一.总结 js字符串转换为数字的三种方法(parseInt("1234blue"))(Num ...
- 痞子衡嵌入式:在IAR开发环境下将关键函数重定向到RAM中执行的三种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下将关键函数重定向到RAM中执行的三种方法. 嵌入式项目里应用程序代码正常是放在 Flash 中执行的,但有时候也需要将 ...
- (转)在网页中JS函数自动执行常用三种方法
原文:http://blog.sina.com.cn/s/blog_6f6b4c3c0100nxx8.html 在网页中JS函数自动执行常用三种方法 在网页中JS函数自动执行常用三种方法 在HTML中 ...
随机推荐
- VC维含义
VC维含义的个人理解 有关于VC维可以在很多机器学习的理论中见到,它是一个重要的概念.在读<神经网络原理>的时候对一个实例不是很明白,通过这段时间观看斯坦福的机器学习公开课及相关补充材料, ...
- JavaScript的理解记录(3)
---接上篇 一.函数: 1. 函数定义后直接执行:var f = (function(x){ return x*10}(10)); 2. 函数的调用有四种方式: 作为函数:作为方法:作为构造函 ...
- springMVC学习--RESTful支持
简介 RESTful架构,就是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方便,所以正得到越来越多网站的采用.RESTful(即Representational State T ...
- Eclipse+Maven创建webapp项目<一>
Eclipse+Maven创建webapp项目<一> 1.开启eclipse,右键new——>other,如下图找到maven project 2.选择maven project,显 ...
- javascript 学习一(概述+基本语法)
http://js.do/ 概述 JavaScript :脚本语言 诞生于1995年. javascript 1.0,发布于Netscape Navigator 2 @1996年3月 布兰登·艾奇( ...
- java基础语法要点<二>(基于1.8)
注解(元数据) 从jdk5 开始,java支持在源文件中嵌入补充信息,称为注释(annotation).注释不会改变程序的动作,也就不会改变程序的语义.但在开发和部署期间,各种工具可以使用这类信息.元 ...
- DOCTYPE是什么鬼?文档模式又是什么鬼?
!DOCTYPE !DOCTYPE是什么: 在所有 HTML 文档中规定 DOCTYPE 是非常重要的,这样浏览器就能了解预期的文档类型, 告诉浏览器要通过哪一种规范(文档类型定义 DTD)解析文档( ...
- 【VS2013】设定Nuget代理
@tags "visual studio 2013" nuget vs2013中用nuget想必是一件很爽的事情,就像java里面用maven来安装各种包一样.有时候网络不好,nu ...
- 修改ftp端口为50021
1. 配置 2. 增加防火墙规则 netsh firewall set portopening tcp 50021 ftp-50021 enable 3. 重启服务 net stop FileZill ...
- springMVC配置步骤
所用的工具为eclipse for javaEE,tomcat 8.0 1.导入jar包 把以上的jar包全部复制到项目的WebContent/WEB-INF/lib目录中 2.在webContent ...