android-tcp-tracev2

by
4 views 5c37a197...

Description

android-tcp-tracev2

How to Use

Download the script and run it with Frida CLI:

Download Script

Then run with Frida:

frida -U -f YOUR_PACKAGE_NAME -l android-tcp-tracev2.js

Replace YOUR_PACKAGE_NAME with the target app's package name.

Source Code

JavaScript
/*
 * Frida script to trace TCP connections of Android apps by MaMe82
 * - based on libc.so!connect()
 * - adds Java backtrace if calling thread is attached to JVM (omitted otherwise)
 * - results could be used to correlate data to inbound connections on TLS interception proxies
 * - credz to "Ole André V. Ravnås" for the online discussion (ref: https://twitter.com/mame82/status/1324654507117187072)
 *
 * Note: the code is a modified excerpt of an agent written in TypeScript. This version is pure JS but may require
 * some "performance rework" on the generated message objects
 *
 * Usage:
 *    frida -U --no-pause --codeshare mame82/android-tcp-trace -f <app/process>
 */

// frida -U android-tcp-trace.js -f org.megapari.client
// frida -U --codeshare mame82/android-tcp-trace -f org.megapari.client
// frida -U --codeshare KhanhPham2411/android-tcp-trace -f org.megapari.client

function hookNativeSocket() {
    const tcpSocketFDs = new Map()
  
    const fSocketConnect = Module.getExportByName("libc.so", "connect")
    Interceptor.attach(fSocketConnect, {
      onEnter(args) {
        this.sockFd = args[0].toInt32()
      },
      onLeave(res) {
        const sockFd = this.sockFd
        const sockType = Socket.type(sockFd)
        if (!(sockType === "tcp6" || sockType === "tcp")) return
  
        const sockLocal = Socket.localAddress(sockFd)
        const tcpEpLocal = sockLocal && sockLocal.ip ? sockLocal : undefined
        const sockRemote = Socket.peerAddress(sockFd)
        const tcpEpRemote = sockRemote && sockRemote.ip ? sockRemote : undefined
  
        if (!tcpEpLocal) return
        // ToDo: if socket FD already exists in the set, a faked 'close' message shall be sent first (currently handled by receiving logic)
        tcpSocketFDs.set(sockFd, tcpEpLocal)
        let msg = {
          socketFd: sockFd,
          pid: Process.id,
          threadId: this.threadId,
          socketEventType: "connect",
          type: "socketCall",
          result: res
        }
  
        if (tcpEpLocal) {
          msg.hostip = tcpEpLocal.ip
          msg.port = tcpEpLocal.port
        }
        if (tcpEpRemote) {
          msg.dstIp = tcpEpRemote.ip
          msg.dstPort = tcpEpRemote.port
        }
  
        //if (Java.available) {     // checks presence of Java runtime in process
        if (Java.vm !== null && Java.vm.tryGetEnv() !== null) {
          // checks if Thread is JVM attached (JNI env available)
          let java_lang_Exception = Java.use("java.lang.Exception")
          var exception = java_lang_Exception.$new()
          const trace = exception.getStackTrace()
          msg.stack = trace.map(traceEl => {
            return {
              class: traceEl.getClassName(),
              file: traceEl.getFileName(),
              line: traceEl.getLineNumber(),
              method: traceEl.getMethodName(),
              isNative: traceEl.isNativeMethod(),
              str: traceEl.toString()
            }
          })
        }
  
        //send(msg)
        console.log(JSON.stringify(msg, null, 4))
      }
    })
  
    const libcEx = Process.getModuleByName("libc.so").enumerateExports()
    const socketExports = libcEx.filter(
      expDetails =>
        expDetails.type === "function" &&
        ["shutdown", "close"].some(serachStr => serachStr === expDetails.name)
    )
    socketExports.forEach(exp => {
      Interceptor.attach(exp.address, {
        onEnter(args) {
          const sockFd = args[0].toInt32()
          if (!tcpSocketFDs.has(sockFd)) return
          const sockType = Socket.type(sockFd)
          if (tcpSocketFDs.has(sockFd)) {
            const tcpEP = tcpSocketFDs.get(sockFd)
            const msg = {
              socketFd: sockFd,
              pid: Process.id,
              threadId: this.threadId,
              socketEventType: exp.name,
              hostip: tcpEP.ip,
              port: tcpEP.port,
              type: "socketCall"
            }
            tcpSocketFDs.delete(sockFd)
            //send(msg)
            if(msg.socketEventType == "close") {return}
            
            console.log(JSON.stringify(msg, null, 4))
          }
        }
      })
    })
  }
  
  hookNativeSocket()
  
Share this script:
Twitter LinkedIn

Comments

Login or Sign up to leave a comment.
Loading comments...