利用Objective-C运行时hook函数的三种方法

原创 2013年03月18日 20:30:39

方法一,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

版权声明:转载请注明出处:http://blog.csdn.net/hursing

Objective-C的hook方案(一): Method Swizzling

Objective-C的hook方案(一):  Method Swizzling在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有更加灵活的...

iOS 逆向-非越狱手机Hook App

引子由于对iOS逆向分析很感兴趣,所以也花了很长一段时间学习了iOS逆向相关知识,并积累了一些相关经验,在越狱设备上成功让我爽了一把,前段时间比较火的微信抢红包功能也是一步一脚印让自己给弄出来了。后来...
  • ChSaDiN
  • ChSaDiN
  • 2016年06月13日 13:52
  • 8453

IOS逆向笔记之HOOK实现(非越狱)

HOOK是越狱的最终目标,目的是给应用添加功能如插件或者是更改应用的某个功能来满足我们的需求,如微信中添加抢红包插件。本文将以最近比较火的“快看”漫画为例子去除付费漫画中的收费弹窗,实现免费看漫画的功...

iOS攻防 - (九)将iOS应用注入dylib和hook后,重新签名并打包

iOS攻防 - (八)将iOS应用hook和注入dylib后,重新签名并打包1.下载微信,并解密WeChat.ipa我的本篇博客已经讲过,此处不再赘述 ;http://blog.csdn.net/u0...

iOS安全攻防(十七):Fishhook

Fishhook众所周知,Objective-C的首选hook方案为Method Swizzle,于是大家纷纷表示核心内容应该用C写。接下来进阶说说iOS下C函数的hook方案,先介绍第一种方案———...

iOS逆向工程(手动HOOK自己编写的APP)- 学习整理

iOS逆向工程(手动HOOK自己编写的APP)- 学习整理   作者 _品味生活_ 关注 2016.05.13 14:48 字数 1920 阅读 6214评论 17喜欢 45 ...

iOS开发 - iOS的hook方案

iOS的各种hook方案比较

Method Swizzling(iOS的hook机制)

为了安全,要为NSUserDefaults加密。但是为NSUserDefaults的每个读写的地方加入加密解密方法也太麻烦。所以想重写NSUserDefaults的读写方法,把加密解密方法内嵌其中,这...

iOS运行时以及HOOK的理解:runtime和method swizzling

iOS运行时以及HOOK的理解:runtime和method swizzling

利用RunTime Hook 实现iOS防止按钮连续响应点击

虽然iOS很少出现这种问题, 而且也有很多办法可以解决. 为了更好的熟悉了解RunTime, 那我们就来看看用RunTime是这么解决的吧. 链接:https://github.c...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用Objective-C运行时hook函数的三种方法
举报原因:
原因补充:

(最多只允许输入30个字)