Last active
June 7, 2023 17:40
-
-
Save miticollo/c8303ca061304d0b0372258ad6259c6c to your computer and use it in GitHub Desktop.
A tccd tracer. It logs all INSERT queries that tccd does to store permissions for a third-party app.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import signal | |
import threading | |
import _frida | |
import frida | |
from frida.core import Device, Session, Script, ScriptMessage | |
signal_event: threading.Event = threading.Event() | |
def signal_handler(sig, frame): | |
print("Interrupted by Ctrl-C, stopping...") | |
signal_event.set() | |
signal.signal(signal.SIGINT, signal_handler) | |
compiler: frida.Compiler = frida.Compiler() | |
compiler.on("diagnostics", lambda diag: print(f"on_diagnostics: {diag}")) | |
bundle: str = compiler.build('tccd.ts', | |
project_root='tccd.ts', compression='terser') | |
def on_message(message: ScriptMessage, data): | |
if message["type"] == "send": | |
payload: dict = message["payload"] | |
mtype: str = payload["type"] | |
if mtype == "tccd": | |
if payload["pid"] != -1: | |
process: _frida.Process = device.enumerate_processes(pids=[payload["pid"]])[0] | |
print(f"""\ | |
Detect analysis permissions: | |
service: {payload["query"][0]}, | |
client: {payload["query"][1]} (PID {process.pid}), | |
auth_value: {payload["query"][3]}""") | |
else: | |
print(f'Skipping client: {payload["query"][1]}') | |
else: | |
print("Unhandled message:", message) | |
device: Device = frida.get_usb_device() | |
session: Session = device.attach('tccd') | |
script: Script = session.create_script(source=bundle) | |
script.on("message", on_message) | |
script.load() | |
print('Press Ctrl-C to exit...') | |
signal_event.wait() | |
session.detach() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* tccd is an iOS daemon that saves permissions (e.g., popups that ask "... Would | |
* Like to Access the Camera") of third-party apps. | |
* It stores the permission in an SQLCipher DB: /private/var/mobile/Library/TCC/. | |
* This agent prints all INSERT queries that tccd does. | |
* | |
* To use it run | |
* frida -U -n 'tccd' -l agent.ts | |
*/ | |
const LIBSQLITE_PATH: string = '/usr/lib/libsqlite3.dylib' | |
let stmt: NativePointer | undefined; | |
const sqlQuery: (string | number | null)[] = []; | |
const sqlite3_expanded_sql = new NativeFunction( | |
Module.getExportByName(LIBSQLITE_PATH, 'sqlite3_expanded_sql'), | |
'pointer', // pStmt | |
['pointer'] | |
); | |
Interceptor.attach(Module.getExportByName(LIBSQLITE_PATH, 'sqlite3_prepare_v2'), { | |
onEnter(args): void { | |
if (args[1].readUtf8String()?.startsWith("INSERT")) { | |
if (sqlQuery.length != 0) throw new Error("sqlQuery is not empty!"); | |
this.ppStmt = args[3]; | |
} | |
}, | |
onLeave(): void { | |
if (this.ppStmt !== undefined) { | |
stmt = this.ppStmt.readPointer() | |
if (stmt?.isNull()) throw new Error("There is an error in sqlite3_prepare_v2!"); | |
} | |
} | |
}); | |
Interceptor.attach(Module.getExportByName(LIBSQLITE_PATH, 'sqlite3_bind_text'), { | |
onEnter(args): void { | |
if (stmt?.equals(args[0])) sqlQuery[args[1].toInt32() - 1] = args[2].readUtf8String(); | |
} | |
}); | |
Interceptor.attach(Module.getExportByName(LIBSQLITE_PATH, 'sqlite3_bind_int'), { | |
onEnter(args): void { | |
if (stmt?.equals(args[0])) sqlQuery[args[1].toInt32() - 1] = args[2].toInt32(); | |
} | |
}); | |
Interceptor.attach(Module.getExportByName(LIBSQLITE_PATH, 'sqlite3_bind_int64'), { | |
onEnter(args): void { | |
if (stmt?.equals(args[0])) sqlQuery[args[1].toInt32() - 1] = int64(args[2].toString()).toNumber(); | |
} | |
}); | |
Interceptor.attach(Module.getExportByName(LIBSQLITE_PATH, 'sqlite3_bind_null'), { | |
onEnter(args): void { | |
if (stmt?.equals(args[0])) sqlQuery[args[1].toInt32() - 1] = null; | |
} | |
}); | |
Interceptor.attach(Module.getExportByName(LIBSQLITE_PATH, 'sqlite3_finalize'), { | |
onEnter(args): void { | |
if (stmt?.equals(args[0])) { | |
send({ | |
type: "tccd", | |
query: sqlQuery, | |
expandedQuery: sqlite3_expanded_sql(stmt).readUtf8String(), | |
pid: getPidForApplication(<string>sqlQuery[1]) | |
}); | |
sqlQuery.length = 0; | |
stmt = undefined; | |
} | |
} | |
}); | |
function getPidForApplication(bundleID: string): number { | |
// https://github.com/frida/frida-core/blob/53d3724dd7/src/darwin/springboard.h#L24-L46 | |
const {FBSSystemService} = ObjC.classes; | |
// https://github.com/frida/frida-core/blob/53d3724dd7/src/darwin/frida-helper-backend-glue.m#L1369-L1371 | |
const service = FBSSystemService.sharedService(); | |
return service.pidForApplication_(bundleID); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment