android-tcp-tracev2
4 views
5c37a197...
Description
android-tcp-tracev2
How to Use
Download the script and run it with Frida CLI:
Download ScriptThen 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()
Comments