iOS hook delegate (一)

本文介绍了一种利用MethodSwizzling技术hook未知调用类的方法,通过重写UIWebView的setDelegate方法来捕获代理对象,并进一步交换指定代理方法的实现。

利用method Swizzling黑魔法可以轻松的 hook 系统的已知类的方法, 但是对于系统的delegate方法, 其实际调用类存在多种, 如何针对未知调用类的 hook 呢?

我们结合webView进行探讨, 并且假定调用webView的类已经实现了其所有的代理方法, 在不改变原类调用的请求下, 如何 hook 它呢?

首先,如果我们设置webView的代理方法, 一定会调用:

webView.delegate = xxx;

这样一定会调用webView的setDelegate方法, 因此我们想到可不可以hook webView的setDelegate拿到实际调用其代理的类, 然后对其进行方法交换.

- (void)hook_setDelegate:(id<UIWebViewDelegate>)delegate{
    [self hook_setDelegate:delegate];
    // 获得delegate的实际调用类
    Class aClass = [delegate class];
    // 传递给HookWebViewDelegateMonitor来交互方法
    [HookWebViewDelegateMonitor exchangeUIWebViewDelegateMethod:aClass];
}
// 在load中交换系统的setDelegate 和我们要hook的代理方法
+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method originalMethod = class_getInstanceMethod([UIWebView class], @selector(setDelegate:));
        Method swizzledMethod = class_getInstanceMethod([UIWebView class], @selector(hook_setDelegate:));
        method_exchangeImplementations(originalMethod, swizzledMethod);
    });
}

首先我们新建一个类(HookWebViewDelegateMonitor), 用于交互方法并实现:

#import "HookWebViewDelegateMonitor.h"
#import <objc/runtime.h>
#import <objc/message.h>

static void hook_exchangeMethod(Class originalClass, SEL originalSel, Class replacedClass, SEL replacedSel){
    Method originalMethod = class_getInstanceMethod(originalClass, originalSel);
    Method replacedMethod = class_getInstanceMethod(replacedClass, replacedSel);
    IMP replacedMethodIMP = method_getImplementation(replacedMethod);
    // 将样替换的方法往代理类中添加, (一般都能添加成功, 因为代理类中不会有我们自定义的函数)
    BOOL didAddMethod =
    class_addMethod(originalClass,
                    replacedSel,
                    replacedMethodIMP,
                    method_getTypeEncoding(replacedMethod));

    if (didAddMethod) {// 添加成功
        NSLog(@"class_addMethod succeed --> (%@)", NSStringFromSelector(replacedSel));
        // 获取新方法在代理类中的地址
        Method newMethod = class_getInstanceMethod(originalClass, replacedSel);
        // 交互原方法和自定义方法
        method_exchangeImplementations(originalMethod, newMethod);
    }else{// 如果失败, 则证明自定义方法在代理方法中, 直接交互就可以
        method_exchangeImplementations(originalMethod, replacedMethod);
    }
}

@implementation HookWebViewDelegateMonitor

+ (void)exchangeUIWebViewDelegateMethod:(Class)aClass{
    hook_exchangeMethod(aClass, @selector(webViewDidStartLoad:), [self class], @selector(replaced_webViewDidStartLoad:));
    hook_exchangeMethod(aClass, @selector(webViewDidFinishLoad:), [self class], @selector(replaced_webViewDidFinishLoad:));
    hook_exchangeMethod(aClass, @selector(webView:didFailLoadWithError:), [self class], @selector(replaced_webView:didFailLoadWithError:));
    hook_exchangeMethod(aClass, @selector(webView:shouldStartLoadWithRequest:navigationType:), [self class], @selector(replaced_webView:shouldStartLoadWithRequest:navigationType:));

}

- (BOOL)replaced_webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSLog(@"-------replaced_webView-shouldStartLoadWithRequest---------");
    return [self replaced_webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
}

- (void)replaced_webViewDidStartLoad:(UIWebView *)webView
{
    NSLog(@"-------replaced_webViewDidStartLoad--------");
    [self replaced_webViewDidStartLoad:webView];
}

- (void)replaced_webViewDidFinishLoad:(UIWebView *)webView
{
    NSLog(@"-------replaced_webViewDidFinishLoad--------");
    [self replaced_webViewDidFinishLoad:webView];
}

- (void)replaced_webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
    NSLog(@"--------replaced_webView-didFailLoadWithError--------");
    [self replaced_webView:webView didFailLoadWithError:error];
}

@end

当我们在ViewController中实现了WebView的调用打印日志如下:
这里写图片描述
这个方法还有一个弊端就是只能hook 原类中已经调用了的方法 , 如果原类中没有实现shouldStartLoadWithRequest这个方法的话, replace_shouldStartLoadWithRequest这个方法也不会调用.
这里写图片描述

Demo 地址如下
Demo

本人还在进一步的探索中, 如有问题, 欢迎指正, 非常感谢. 如果大佬们有更好的hook方案, 也希望可以告知小弟.

参考资料:
通过Method Swizzling实现Hook中的深坑
小白笔记(“动态”hook某class的delegate方法”)
Objective-C的hook方案(一): Method Swizzling
利用Objective-C运行时hook函数的三种方法

<think>好的,我现在需要回答用户关于如何使用Frida Hook iOS设备上的所有网络请求并获取运行命令的问题。首先,我得回忆下Frida的基本工作原理和iOS网络请求相关的API。 用户提到了iOS设备,所以需要明确iOS上的网络请求通常使用哪些框架。常见的应该是NSURLConnection、NSURLSession以及可能的三方库如Alamofire。不过基础的系统级请求大多还是通过NSURLSession处理的。所以,我需要Hook这些类的方法。 接下来,用户需要具体的命令和示例代码。首先,用户需要确保iOS设备上安装了frida-server,并且电脑可以通过USB连接设备。启动frida-server的命令应该是在设备上运行,但用户可能已经知道这部分,所以可能不需要详细说明,但最好还是提下。 然后,Hook的关键点在于找到需要拦截的方法。例如,NSURLSession的dataTaskWithRequest:completionHandler:方法,或者NSURLConnection的sendAsynchronousRequest:queue:completionHandler:方法。此外,可能需要Hook像NSURLProtocol这样的底层类,但可能比较复杂。 接下来,编写Frida的JavaScript代码。需要使用ObjC模块来访问Objective-C的类和方法。例如,使用ObjC.classes.NSURLSession获取类,然后Hook相关方法。在实现中,需要打印出请求的URL、方法、头部等信息,可能还需要获取请求体。 需要注意的是,iOS上的某些网络请求可能使用SSL,此时数据可能已经被加密,直接Hook应用层的API可能无法获取明文数据,这时候可能需要更底层的Hook,比如SSL相关的函数,但这可能比较复杂,而且需要越狱环境。 另外,用户提到要获取运行命令,可能是指执行系统命令?这部分可能需要额外的权限,或者通过其他方式实现,但用户的问题主要是关于网络请求的Hook,可能这里需要澄清,但根据上下文,可能用户是想在执行网络请求时运行某些命令,或者获取网络请求的数据。 现在,根据引用中的资料,特别是引用[3]提到的步骤:附加到目标应用,找到目标函数,Hook并修改行为。因此,示例代码应该包括这些步骤。例如,使用Interceptor.attach来Hook方法,或者在Objective-C中使用方法交换。 另外,引用[5]提到了Hook已存在的实例,但网络请求可能更多的是Hook类方法而不是实例方法,因此可能需要直接Hook类的方法。 综合这些,我需要编写个JavaScript脚本,使用Frida的ObjC API来Hook NSURLSession或NSURLConnection的相关方法,并在回调中打印请求信息。同时,给出运行该脚本的Frida命令,比如frida -U -l script.js -f com.apple.Safari(假设Hook Safari,但用户可能需要指定具体的应用)。 需要注意,iOS上的应用可能使用更高级的API,比如URLSession的delegate方法,这时候可能需要Hook对应的delegate方法,例如URLSession:dataTask:didReceiveData:等。不过对于通用的请求捕获,Hook创建任务的方法可能更直接。 最后,要确保示例代码正确使用Frida的语法,比如ObjC.choose()或者直接替换方法实现。同时,提醒用户可能需要处理不同的iOS版本和应用的差异性,以及可能的SSL Pinning问题。</think>### 使用 Frida Hook iOS 网络请求的步骤及示例代码 #### 1. 核心思路 iOS 应用网络请求主要通过 `NSURLSession` 或 `NSURLConnection` 实现,通过 Hook 相关类的方法即可拦截请求数据。以下是具体步骤: 1. **附加到目标进程**:通过 Frida 附加到 iOS 应用进程。 2. **Hook 网络请求方法**:针对 `NSURLSession` 的 `dataTaskWithRequest:completionHandler:` 方法进行 Hook。 3. **提取请求信息**:从请求对象中获取 URL、请求头、请求体等关键信息[^3][^5]。 --- #### 2. 具体命令与代码示例 ##### 步骤 1:启动 Frida 并附加到目标应用 ```bash # 附加到前台运行的 App(如 Safari) frida -U -F -l hook_network.js # 附加到指定 Bundle ID 的应用(如微信) frida -U -l hook_network.js -f com.tencent.xin ``` ##### 步骤 2:编写 JavaScript Hook 脚本 (`hook_network.js`) ```javascript Java.perform(function () { // iOS 使用 Objective-C 类,需通过 ObjC API 操作 const NSURLSession = ObjC.classes.NSURLSession; // Hook NSURLSession 的 dataTaskWithRequest:completionHandler: 方法 Interceptor.attach(NSURLSession['- dataTaskWithRequest:completionHandler:'].implementation, { onEnter: function (args) { // 解析参数:request 对象和 completionHandler const request = new ObjC.Object(args[2]); const completionHandler = new ObjC.Object(args[3]); // 提取请求 URL、HTTP 方法、请求头 const url = request.URL().absoluteString().toString(); const method = request.HTTPMethod().toString(); const headers = request.allHTTPHeaderFields().toString(); // 打印请求信息 console.log(`[+] 拦截到网络请求: URL: ${url} Method: ${method} Headers: ${headers}`); // 提取请求体(需异步读取) const bodyData = request.HTTPBody(); if (bodyData) { const body = ObjC.classes.NSString.alloc().initWithData_encoding_(bodyData, 4).toString(); console.log(`Body: ${body}`); } } }); }); ``` --- #### 3. 关键点说明 1. **Hook 目标方法**:选择 `dataTaskWithRequest:completionHandler:` 因其在创建任务时触发,覆盖大部分请求场景[^3]。 2. **请求体处理**:iOS 的 `HTTPBody` 可能为 `NSData` 类型,需转换为字符串(如 UTF-8)。 3. **SSL 加密限制**:若应用启用 SSL Pinning,需额外 Hook 安全相关类(如 `NSURLSessionDelegate` 的 `didReceiveChallenge` 方法)[^4]。 --- #### 4. 扩展应用:执行系统命令 若需在拦截请求时执行系统命令(需越狱环境),可添加以下代码: ```javascript // 调用 iOS 的 system 函数执行命令 const system = new NativeFunction(Module.findExportByName(null, 'system'), 'int', ['pointer']); system(Memory.allocUtf8String('ls /var/mobile/Containers/Data/Application/')); ``` --- #### 5. 注意事项 - **越狱环境**:部分操作需越狱权限(如访问沙盒目录)。 - **应用签名**:未签名的脚本可能被 iOS 拒绝执行。 - **性能影响**:高频 Hook 可能降低应用性能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值