Using Frida
Frida is a dynamic instrumentation toolkit that lets you inject code into running applications. It’s useful for monitoring applications written in any language, including binaries without source code.
Installation
Section titled “Installation”Install Frida tools:
pip install frida-toolsFor specific platforms, see the Frida documentation.
Basic approach
Section titled “Basic approach”The workflow for Frida-based monitoring:
- Write a Frida script that hooks target functions and emits events
- Run the target application with Frida attached
- Pipe events to SpecMon for monitoring
Event emission
Section titled “Event emission”Your Frida script should emit events in SpecMon’s JSON format:
function emitEvent(name, args, result) { const event = { time: Math.floor(Date.now() * 1e6), event: { name: "pair", type: "function", args: [ { name: name, type: "function", args: args.map(arg => ({ value: arg, type: "constant" })) }, { value: result, type: "constant" } ] } }; console.log(JSON.stringify(event));}See Event Format for details on the expected structure.
Date.now() has millisecond resolution; multiplying by 1e6 yields nanoseconds with millisecond granularity.
Hooking example: OpenSSL
Section titled “Hooking example: OpenSSL”Frida script
Section titled “Frida script”Here’s an example Frida script that hooks OpenSSL’s SHA256 and HMAC functions to emit events:
// Helper to convert bytes to hex stringfunction toHex(buffer) { if (buffer === null) return "0x"; const bytes = new Uint8Array(buffer); return "0x" + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');}
// Emit SpecMon eventfunction emitEvent(name, args, result) { const event = { time: Math.floor(Date.now() * 1e6), event: { name: "pair", type: "function", args: [ { name: name, type: "function", args: args.map(arg => ({value: arg, type: "constant"})) }, {value: result, type: "constant"} ] } }; console.log(JSON.stringify(event));}
// Hook OpenSSL SHA256const SHA256 = Module.findExportByName("libcrypto.so", "SHA256");if (SHA256) { Interceptor.attach(SHA256, { onEnter: function(args) { this.data = args[0].readByteArray(parseInt(args[1])); }, onLeave: function(retval) { const result = retval.readByteArray(32); emitEvent("sha256", [toHex(this.data)], toHex(result)); } });}
// Hook OpenSSL HMACconst HMAC = Module.findExportByName("libcrypto.so", "HMAC");if (HMAC) { Interceptor.attach(HMAC, { onEnter: function(args) { // args: evp_md, key, key_len, data, data_len, md, md_len this.key = args[1].readByteArray(parseInt(args[2])); this.data = args[3].readByteArray(parseInt(args[4])); }, onLeave: function(retval) { const result = retval.readByteArray(32); emitEvent("hmac", [toHex(this.key), toHex(this.data)], toHex(result)); } });}
console.log("Hooks installed");Running with SpecMon
Section titled “Running with SpecMon”Here’s how to run your target application with Frida and pipe events to SpecMon:
# Run application with Frida and pipe to SpecMonfrida -l hook_crypto.js -f ./target_app 2>/dev/null | \ specmon monitor protocol.spthy --in -Integration with SpecMon
Section titled “Integration with SpecMon”Direct piping
Section titled “Direct piping”frida -l script.js -f ./app 2>/dev/null | specmon monitor spec.spthy --in -Via file
Section titled “Via file”# Collect eventsfrida -l script.js -f ./app > events.json 2>/dev/null
# Monitor offlinespecmon monitor spec.spthy --in events.jsonVia socket
Section titled “Via socket”For long-running applications:
// In Frida script: send to socket instead of stdoutconst socket = new Socket("localhost", 8080);
function emitEvent(name, args, result) { const event = { /* ... */ }; socket.write(JSON.stringify(event) + "\n");}# Terminal 1: SpecMon listensspecmon monitor spec.spthy --in localhost:8080
# Terminal 2: Run with Fridafrida -l script.js -f ./appDebugging
Section titled “Debugging”List available exports
Section titled “List available exports”// Find functions in a libraryModule.enumerateExports("libcrypto.so").forEach(function(exp) { if (exp.name.includes("SHA")) { console.log(exp.name + " @ " + exp.address); }});Log function calls
Section titled “Log function calls”Interceptor.attach(target, { onEnter: function(args) { console.log("Called with: " + args[0] + ", " + args[1]); }});Check event format
Section titled “Check event format”# Pretty-print eventsfrida -l script.js -f ./app 2>/dev/null | head -5 | jq .Best practices
Section titled “Best practices”- Handle null pointers: Check before reading memory
- Use correct lengths: Read the actual data length, not buffer capacity
- Test incrementally: Verify each hook before adding more
- Match specification names: Use function names that match your triggers
Next steps
Section titled “Next steps”- Event Format — Event structure reference
- SpecMon Annotations — Configure triggers