iOS小技能:【intercept the HTTP/HTTPS requests 】利用NSURLProtocol 拦截请求

2022-12-19 17:28:53 浏览数 (1)

前言

动手实践:写一个tweak ,修改请求的HTTPHeaderField

NSURLProtocol 只能拦截 UIURLConnection、NSURLSession 和 UIWebView 中的请求; 对于 WKWebView 中发出的网络请求也无能为力,如果真的要拦截来自 WKWebView 中的请求,还是需要实现 WKWebView 对应的 WKNavigationDelegate,并在代理方法中获取请求。

应用场景:

1、 自定义请求头的HTTPHeaderField 2、针对NSURLSessionConfiguration设置代理和端口,让一些特殊的请求走自定义的隧道IP和端口

I NSURLProtocol 拦截 HTTP 请求

1.1 NSURLProtocol 拦截 HTTP 请求的原理

An NSURLProtocol object handles the loading of protocol-specific URL data. The NSURLProtocol class itself is an abstract class that provides the infrastructure for processing URLs with a specific URL scheme. You create subclasses for any custom protocols or URL schemes that your app supports.

HTTP 请求开始时,URL 加载系统创建一个合适的 NSURLProtocol 对象处理对应的 URL 请求,因此我们只需写一个继承自 NSURLProtocol 的类,并通过 - registerClass: 方法注册我们的协议类,然后 URL 加载系统就会在请求发出时使用我们创建的协议对象对该请求进行处理。

1.2 使用 NSURLProtocol 拦截 HTTP 请求

从CSDN下载Demo:https://download.csdn.net/download/u011018979/16753164

1、文章:https://kunnan.blog.csdn.net/article/details/115690756 2、原理:利用NSURLProtocol 拦截 HTTP 请求 3、应用场景:隧道APP请求我们自己接口的都不走隧道、修改请求的HTTPHeaderField,设置代理IP和端口、防抓包(使Thor,Charles,Burp等代理抓包方式全部失效)CustomHTTPProtocol

  • 决定请求是否需要当前协议对象处理的方法
代码语言:javascript复制
/**
 决定请求是否需要当前协议对象处理
 
 */
 (BOOL)canInitWithRequest:(NSURLRequest *)request{
    
    if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) {
        return NO;
    }
    NSString * url = request.URL.absoluteString;
    return [self isUrl:url];
}

  • 对当前的请求对象需要进行哪些处理
代码语言:javascript复制
  (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;

修改NSURLRequest 对象:在CanonicalRequestForRequest 方法中,可以修改 request headers

  • NSURLProtocol 如何实例化?
代码语言:javascript复制
- (instancetype)initWithRequest:(NSURLRequest *)request cachedResponse:(nullable NSCachedURLResponse *)cachedResponse client:(nullable id <NSURLProtocolClient>)client NS_DESIGNATED_INITIALIZER;

  • app启动的时候进行注入
代码语言:javascript复制

/*! Call this to start the module.  Prior to this the module is just dormant, and 
 *  all HTTP requests proceed as normal.  After this all HTTP and HTTPS requests 
 *  go through this module.
 */
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    [CustomHTTPProtocol setDelegate:self];
    if (YES) {
        [CustomHTTPProtocol start];
    }
    

}

II 动手实践

源码获取请关注【公号:iOS逆向】:写一个tweak ,修改请求的HTTPHeaderField

2.1 hook

代码语言:javascript复制
%hook AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    %log();
    BOOL rect = %orig;
    
    
    [CustomHTTPProtocol setDelegate:self];
    if (YES) {
        [CustomHTTPProtocol start];
    }
    
    return rect;
}

%end

2.2 针对NSURLSessionConfiguration设置代理和端口

代码语言:javascript复制
  (QNSURLSessionDemux *)sharedDemux
{
    static dispatch_once_t      sOnceToken;
    static QNSURLSessionDemux * sDemux;
    dispatch_once(&sOnceToken, ^{
        NSURLSessionConfiguration *     config;
        
        config = [NSURLSessionConfiguration defaultSessionConfiguration];
        // You have to explicitly configure the session to use your own protocol subclass here 
        // otherwise you don't see redirects <rdar://problem/17384498>.
        
#pragma mark - ********  针对NSURLSessionConfiguration设置代理和端口

        NSString* proxyHost = @"socks-";
        //                NSString* proxyHost = @"192.168.2.166";
        NSNumber* proxyPort = [NSNumber numberWithInt: 8830 ];
        //                NSNumber* proxyPort = [NSNumber numberWithInt: 8888 ];
        
        // Create an NSURLSessionConfiguration that uses the proxy
        NSDictionary *proxyDict = @{
                                    @"HTTPEnable"  : @1,
                                    (NSString *)kCFStreamPropertyHTTPProxyHost  : proxyHost,
                                    (NSString *)kCFStreamPropertyHTTPProxyPort  : proxyPort,
                                    
                                    @"HTTPSEnable"  : @(1),
                                    (NSString *)kCFStreamPropertyHTTPSProxyHost  : proxyHost,
                                    (NSString *)kCFStreamPropertyHTTPSProxyPort  : proxyPort,
                                    
                                    
                                    };
        
        
        //    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
        config.connectionProxyDictionary = proxyDict;
        
        
        [config setHTTPAdditionalHeaders:@{
                                                  Authorizationkey:Authorizationvalue,
                                                  }
         ];

        config.protocolClasses = @[ self ];
        sDemux = [[QNSURLSessionDemux alloc] initWithConfiguration:config];
    });
    return sDemux;
}

2.3 测试

  • 查看请求头信息
代码语言:javascript复制
%hook NSURLProtocol


  (void)setProperty:(id)value 
forKey:(NSString *)key 
inRequest:(NSMutableURLRequest *)request{
    
    %log();
    %orig;
}

%end

see also

  • iOS APP 不走全局proxy的方案【 例如:隧道APP的请求接口,一些自己特殊接口不走隧道】(利用NSURLProtocol 进行请求的拦截)

https://kunnan.blog.csdn.net/article/details/78147628

  • 防代理 configuration.connectionProxyDictionary
代码语言:javascript复制
 
    //APP请求我们自己接口的都不走隧道
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    configuration.connectionProxyDictionary = @{};
    
    
//    2/ AFHTTPSessionManager 创建NSURLSessionDataTask
    AFHTTPSessionManager *mgr = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:configuration];
    

0 人点赞