IOS - 抓包通杀篇

IOS中大多数情况,开发者都会使用OC提供的api函数,CFNetworkCopySystemProxySettings来进行代理检测;

CFNetworkCopySystemProxySettings

在这里插入图片描述

在这里插入图片描述

检测函数直接会检测这些ip和端口等:
在这里插入图片描述

采用直接附加页面进程:

frida -UF -l 通杀代理抓包.js

上通杀脚本:

var _imports = Process.findModuleByName("XXX").enumerateImports();
var _CFNetworkCopySystemProxySettings = null;
for (var i = 0; i < _imports.length; i++) {
    
    
    //查找CFNetworkCopySystemProxySettings系统代理函数
    if (_imports[i].name.indexOf("CFNetworkCopySystemProxySettings") !== -1) {
    
    
        console.log(_imports[i].name, _imports[i].address);
        _CFNetworkCopySystemProxySettings = _imports[i].address;
    }
}


if (_CFNetworkCopySystemProxySettings) {
    
    
    Interceptor.attach(_CFNetworkCopySystemProxySettings, {
    
    
        onEnter: function (agrgs) {
    
    

        }, onLeave: function (retval) {
    
    
            console.log("retval: ", ObjC.Object(retval));
            //将返回值全部nop
            retval.replace(0);
        }
    })
}

NSURL URLWithString:

> frida-trace -U -f 包名 -m "+[NSURL URLWithString:]"

更改url得传入得参数,及堆栈打印,也叫url定位

/*
 * Auto-generated by Frida. Please modify to match the signature of +[NSURL URLWithString:].
 * This stub is currently auto-generated from manpages when available.
 *
 * For full API reference, see: https://frida.re/docs/javascript-api/
 */

{
    
    
  /**
   * Called synchronously when about to call +[NSURL URLWithString:].
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
   * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
   * @param {object} state - Object allowing you to keep state across function calls.
   * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
   * However, do not use this to store function arguments across onEnter/onLeave, but instead
   * use "this" which is an object for keeping state local to an invocation.
   */
  onEnter(log, args, state) {
    
    
	console.log('CCCryptorCreate called from:\n' +
        Thread.backtrace(this.context, Backtracer.ACCURATE)
        .map(DebugSymbol.fromAddress).join('\n') + '\n');
	log(`+[NSURL URLWithString:]` + ObjC.Object(args[2]));
  },

  /**
   * Called synchronously when about to return from +[NSURL URLWithString:].
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave(log, retval, state) {
    
    
  }
}

双向证书:

资源路径操作,可以入手关键函数;

> frida-trace  -UF  -m "-[NSBundle pathForResource*]"
/*
 * Auto-generated by Frida. Please modify to match the signature of -[NSBundle pathForResource:ofType:].
 * This stub is currently auto-generated from manpages when available.
 *
 * For full API reference, see: https://frida.re/docs/javascript-api/
 */

{
    
    
  /**
   * Called synchronously when about to call -[NSBundle pathForResource:ofType:].
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
   * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
   * @param {object} state - Object allowing you to keep state across function calls.
   * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
   * However, do not use this to store function arguments across onEnter/onLeave, but instead
   * use "this" which is an object for keeping state local to an invocation.
   */
  onEnter(log, args, state) {
    
    
	console.log('NSBundle pathForResource called from:\n' +
        Thread.backtrace(this.context, Backtracer.ACCURATE)
        .map(DebugSymbol.fromAddress).join('\n') + '\n');
    log(`-[NSBundle pathForResource:${
      
      ObjC.Object(args[2])} ofType:${
      
      ObjC.Object(args[3])}]`);
  },

  /**
   * Called synchronously when about to return from -[NSBundle pathForResource:ofType:].
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave(log, retval, state) {
    
    
  }
}

HOOK抓包

基于底层ssl库来实现:

//请求
var ssl_write = Module.findExportByName("libboringssl.dylib", "SSL_write");
console.log("ssl_write", ssl_write);   //ssl input len
Interceptor.attach(ssl_write, {
    
    
    onEnter: function (args) {
    
    
        console.log("=================================================");
        console.log("CurrentThreadId: ", Process.getCurrentThreadId(), ", ssl_write onEnter args[1]: ", hexdump(args[1], {
    
    length: args[2].toInt32()}));
    }, onLeave: function (retval) {
    
    

    }
});

//返回响应
var ssl_read = Module.findExportByName("libboringssl.dylib", "SSL_read");
console.log("ssl_read", ssl_read);  //ssl output len
Interceptor.attach(ssl_read, {
    
    
    onEnter: function (args) {
    
    
        this.args1 = args[1];
        this.args2 = args[2];
    }, onLeave: function (retval) {
    
    
        console.log("=================================================");
        console.log("CurrentThreadId: ", Process.getCurrentThreadId(), ", ssl_read onLeave args[1]: ",
            this.args1.readByteArray(this.args2.toInt32())
        );
    }
});

r0Capture 肉师傅的安卓应用层抓包通杀脚本

这个在之前安卓也说过,ios和安卓都通用的;
详见:https://codeooo.blog.csdn.net/article/details/127123371

function initializeGlobals() {
    
    
  var resolver = new ApiResolver("module");
  var exps = [
    [Process.platform == "darwin" ? "*libboringssl*" : "*libssl*", ["SSL_read", "SSL_write", "SSL_get_fd", "SSL_get_session", "SSL_SESSION_get_id"]], // for ios and Android
    [Process.platform == "darwin" ? "*libsystem*" : "*libc*", ["getpeername", "getsockname", "ntohs", "ntohl"]]
  ];

源码里三目运算符,也说明了,ios用 libboringssl 动态库 , 安卓 libssl库;

同时还hook了,”SSL_read", “SSL_write” ,等等~

Interceptor.attach(addresses["SSL_read"],
  {
    
    
    onEnter: function (args) {
    
    
      var message = getPortsAndAddresses(SSL_get_fd(args[0]), true);
      message["ssl_session_id"] = getSslSessionId(args[0]);
      message["function"] = "SSL_read";
      message["stack"] = SSLstackread;
      this.message = message;
      this.buf = args[1];
    },
    onLeave: function (retval) {
    
    
      retval |= 0; // Cast retval to 32-bit integer.
      if (retval <= 0) {
    
    
        return;
      }
      send(this.message, Memory.readByteArray(this.buf, retval));
    }
  });

Interceptor.attach(addresses["SSL_write"],
  {
    
    
    onEnter: function (args) {
    
    
      var message = getPortsAndAddresses(SSL_get_fd(args[0]), false);
      message["ssl_session_id"] = getSslSessionId(args[0]);
      message["function"] = "SSL_write";
      message["stack"] = SSLstackwrite;
      send(message, Memory.readByteArray(args[1], parseInt(args[2])));
    },
    onLeave: function (retval) {
    
    
    }
  });

猜你喜欢

转载自blog.csdn.net/weixin_38927522/article/details/129129544
今日推荐