攔截所有app的網(wǎng)絡(luò)請(qǐng)求

前提 : 有時(shí)會(huì)遇到這樣的需求:將一些別人app上比較優(yōu)質(zhì)的內(nèi)容,用到自己產(chǎn)品中.由于別人的app做了大量的參數(shù)加密, 我們獲取不到加密規(guī)則,所以使用接口直接調(diào)用的方法就走不通.

本文就是要介紹使用逆向技術(shù)攔截目標(biāo)app的所有網(wǎng)絡(luò)請(qǐng)求.對(duì)于我們需要的接口數(shù)據(jù)上傳到我們自己的服務(wù)器中

工具:
monkeyDev
PPSNetworkMonitor開源庫中的代碼

代碼如下:

PPSURLSessionConfiguration.h

@interface PPSURLSessionConfiguration : NSObject

@property (nonatomic,assign) BOOL isSwizzle;

+ (PPSURLSessionConfiguration *)defaultConfiguration;

/**
 *  swizzle NSURLSessionConfiguration's protocolClasses method
 */
- (void)load;

/**
 *  make NSURLSessionConfiguration's protocolClasses method is normal
 */
- (void)unload;

@end

PPSURLSessionConfiguration.m

#import "PPSURLSessionConfiguration.h"
#import <objc/runtime.h>
#import "PPSURLProtocol.h"

@implementation PPSURLSessionConfiguration


+ (PPSURLSessionConfiguration *)defaultConfiguration {
    
    static PPSURLSessionConfiguration *staticConfiguration;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        staticConfiguration=[[PPSURLSessionConfiguration alloc] init];
    });
    return staticConfiguration;
    
}
- (instancetype)init {
    self = [super init];
    if (self) {
        self.isSwizzle=NO;
    }
    return self;
}

- (void)load {
    
    self.isSwizzle=YES;
    Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
    [self swizzleSelector:@selector(protocolClasses) fromClass:cls toClass:[self class]];
    
}

- (void)unload {
    
    self.isSwizzle=NO;
    Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
    [self swizzleSelector:@selector(protocolClasses) fromClass:cls toClass:[self class]];
    
}

- (void)swizzleSelector:(SEL)selector fromClass:(Class)original toClass:(Class)stub {
    
    Method originalMethod = class_getInstanceMethod(original, selector);
    Method stubMethod = class_getInstanceMethod(stub, selector);
    if (!originalMethod || !stubMethod) {
        [NSException raise:NSInternalInconsistencyException format:@"Couldn't load NEURLSessionConfiguration."];
    }
    method_exchangeImplementations(originalMethod, stubMethod);
}

- (NSArray *)protocolClasses {
    
    return @[[PPSURLProtocol class]];
    //如果還有其他的監(jiān)控protocol,也可以在這里加進(jìn)去
}

@end

PPSURLProtocol.h

@interface PPSURLProtocol : NSURLProtocol

+ (void)start;

+ (void)end;

@end

PPSURLProtocol.m

#import "PPSURLSessionConfiguration.h"

static NSString *const PPSHTTP = @"PPSHTTP";//為了避免canInitWithRequest和canonicalRequestForRequest的死循環(huán)

@interface PPSURLProtocol()<NSURLConnectionDelegate,NSURLConnectionDataDelegate>

@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) NSURLRequest *pps_request;
@property (nonatomic, strong) NSURLResponse *pps_response;
@property (nonatomic, strong) NSMutableData *pps_data;


@end

@implementation PPSURLProtocol

#pragma mark - init
- (instancetype)init {
    self = [super init];
    if (self) {
    }
    return self;
}

+ (void)load {
    
}

+ (void)start {
    PPSURLSessionConfiguration *sessionConfiguration = [PPSURLSessionConfiguration defaultConfiguration];
    [NSURLProtocol registerClass:[PPSURLProtocol class]];
    if (![sessionConfiguration isSwizzle]) {
        [sessionConfiguration load];
    }
}

+ (void)end {
    PPSURLSessionConfiguration *sessionConfiguration = [PPSURLSessionConfiguration defaultConfiguration];
    [NSURLProtocol unregisterClass:[PPSURLProtocol class]];
    if ([sessionConfiguration isSwizzle]) {
        [sessionConfiguration unload];
    }
}


/**
 需要控制的請(qǐng)求

 @param request 此次請(qǐng)求
 @return 是否需要監(jiān)控
 */
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    
    if (![request.URL.scheme isEqualToString:@"http"] &&
        ![request.URL.scheme isEqualToString:@"https"]) {
        return NO;
    }
    //如果是已經(jīng)攔截過的  就放行
    if ([NSURLProtocol propertyForKey:PPSHTTP inRequest:request] ) {
        return NO;
    }
    return YES;
}

/**
 設(shè)置我們自己的自定義請(qǐng)求
 可以在這里統(tǒng)一加上頭之類的
 
 @param request 應(yīng)用的此次請(qǐng)求
 @return 我們自定義的請(qǐng)求
 */
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
    [NSURLProtocol setProperty:@YES
                        forKey:PPSHTTP
                     inRequest:mutableReqeust];
    return [mutableReqeust copy];
}

- (void)startLoading {
    NSURLRequest *request = [[self class] canonicalRequestForRequest:self.request];
    self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
    self.pps_request = self.request;
}

- (void)stopLoading {
    [self.connection cancel];

    //獲取請(qǐng)求方法
    NSString *requestMethod = self.pps_request.HTTPMethod;
    NSLog(@"請(qǐng)求方法:%@\n",requestMethod);
    
    //獲取請(qǐng)求頭
    NSDictionary *headers = self.pps_request.allHTTPHeaderFields;
    NSLog(@"請(qǐng)求頭:\n");
    for (NSString *key in headers.allKeys) {
        NSLog(@"%@ : %@",key,headers[key]);
    }

    //獲取請(qǐng)求結(jié)果
   // 上傳攔截結(jié)果到我們自己服務(wù)器上
    NSString *string = [self responseJSONFromData:self.pps_data];
    NSLog(@"請(qǐng)求結(jié)果:%@",string);
    if ([[self.request.URL absoluteString] containsString:@"liked"]) {
        NSURLSession *session = [NSURLSession sharedSession];
        NSURL *url = [NSURL URLWithString:@"xxxx"];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        request.HTTPMethod = @"POST";
        request.HTTPBody = [[NSString stringWithFormat:@"json_data=%@", string] dataUsingEncoding:NSUTF8StringEncoding];
        
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        }];
        [dataTask resume];
    }
    
}

#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    [self.client URLProtocol:self didFailWithError:error];
}

- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection{
    return YES;
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
    [self.client URLProtocol:self didReceiveAuthenticationChallenge:challenge];
}

- (void)connection:(NSURLConnection *)connection
didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [self.client URLProtocol:self didCancelAuthenticationChallenge:challenge];
}

#pragma mark - NSURLConnectionDataDelegate
-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response{
    
    if (response != nil) {
        self.pps_response = response;
        [self.client URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
    }
    return request;
}

- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
    self.pps_response = response;
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
    [self.pps_data appendData:data];
    NSLog(@"receiveData");
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse {
    return cachedResponse;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [[self client] URLProtocolDidFinishLoading:self];
}

//轉(zhuǎn)換json
-(id)responseJSONFromData:(NSData *)data {
    if(data == nil) return nil;
    NSError *error = nil;
    id returnValue = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
    if(error) {
        NSLog(@"JSON Parsing Error: %@", error);
        //https://github.com/coderyi/NetworkEye/issues/3
        return nil;
    }
    //https://github.com/coderyi/NetworkEye/issues/1
    if (!returnValue || returnValue == [NSNull null]) {
        return nil;
    }
    
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:returnValue options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    return jsonString;
}

- (NSMutableData *)pps_data {
    if (!_pps_data) {
        _pps_data = [NSMutableData data];
    }
    return _pps_data;
}

@end

如上兩個(gè)文件導(dǎo)入MonkeyDev中 就會(huì)在如下方法中

- (void)stopLoading {...}

攔截你所導(dǎo)入的目標(biāo)ipa的所有網(wǎng)絡(luò)請(qǐng)求 .

根據(jù)抓包地址確定你需要的接口數(shù)據(jù)進(jìn)行過濾

// 例如我需要的接口xxx
 if ([[self.request.URL absoluteString] containsString:@"xxxx"]){}

好了 到此為止攔擊所有app的網(wǎng)絡(luò)請(qǐng)求就完成了, 如果有不明白或者工具不會(huì)使用的留言,看到就會(huì)回答. 感謝大家!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,145評(píng)論 1 32
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 11,185評(píng)論 6 13
  • AFHTTPRequestOperationManager 網(wǎng)絡(luò)傳輸協(xié)議UDP、TCP、Http、Socket、X...
    Carden閱讀 4,403評(píng)論 0 12
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中。。。 其實(shí)如果沒有APIManager這一層是沒法使用delegate的,畢竟多個(gè)單...
    yhtang閱讀 5,259評(píng)論 1 23
  • 記憶中的他們都是日常的樣子 神態(tài)自若,平淡安詳 直到有一天突然意識(shí)到他們老了 是的… 直到他們老的躺在醫(yī)院病床上再...
    舊城xu閱讀 328評(píng)論 0 0