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

語言: CN / TW / HK

“我正在參加「掘金·啟航計劃」”

前言

動手實踐:寫一個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

  • 決定請求是否需要當前協議物件處理的方法

```objectivec /** 決定請求是否需要當前協議物件處理

/ +(BOOL)canInitWithRequest:(NSURLRequest )request{

if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) {
    return NO;
}
NSString * url = request.URL.absoluteString;
return [self isUrl:url];

}

```

  • 對當前的請求物件需要進行哪些處理

```objectivec + (NSURLRequest )canonicalRequestForRequest:(NSURLRequest )request;

```

修改NSURLRequest 物件:在CanonicalRequestForRequest 方法中,可以修改 request headers

  • NSURLProtocol 如何例項化?

```objectivec - (instancetype)initWithRequest:(NSURLRequest )request cachedResponse:(nullable NSCachedURLResponse )cachedResponse client:(nullable id )client NS_DESIGNATED_INITIALIZER;

- app啟動的時候進行注入objectivec

/! 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

```objectivec %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設定代理和埠

```objectivec + (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 測試

  • 檢視請求頭資訊 ```objectivec %hook NSURLProtocol

  • (void)setProperty:(id)value forKey:(NSString )key inRequest:(NSMutableURLRequest )request{

    %log(); %orig; }

%end

```

see also

// 2/ AFHTTPSessionManager 建立NSURLSessionDataTask AFHTTPSessionManager *mgr = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:configuration];

```