R 2 Frida
R 2 Frida
R 2 Frida
Debugger Debuggee
Debugger Debuggee
bootstrapper
Debugger Debuggee
bootstrapper-thread
bootstrapper
Debugger Debuggee
bootstrapper-thread
bootstrapper
frida-agent.so
Debugger Debuggee
bootstrapper-thread
bootstrapper
bootstrapper
JavaScript
Demos
Motivation behind Frida
Existing tools often not a good fit for the task at hand
Creating a new tool usually takes too much effort
Short feedback loop: reversing is an iterative process
Use one toolkit for multi-platform instrumentation
Future remake of oSpy (see below)
What is Frida?
Dynamic instrumentation toolkit
Debug live processes
Scriptable
Execute your own debug scripts
inside another process
Multi-platform
Windows, Mac, Linux, iOS, Android, QNX
Open Source
Why would you need Frida?
For reverse-engineering
For programmable debugging
For dynamic instrumentation
But ultimately: To
enable rapid
development of new tools for the task
at hand
Architecture
Highly modular and decoupled
Instrumentation core written in C (frida-gum)
C++ and JavaScript language bindings
Easy to use high-level API: "run JS in that process"
Packages instrumentation core in a library
Injects that using a per OS injector component
Communicates with it over a per OS transport
Bindings: C, Node.js, Python, .NET, Swift, Qt
Philosophy: only bare metal building blocks,
community provides use-case-specific modules in
npm, e.g. frida-fs, frida-screenshot, frida-uikit, frida-
uiwebview, etc.
Let's explore the basics
1) Build and run the test app that we will instrument:
#include <stdio.h> $ clang hello.c -o hello
#include <unistd.h> $ ./hello
f() is at 0x106a81ec0
void Number: 0
f (int n) Number: 1
{ Number: 2
printf ("Number: %d\n", n); …
}
int
main ()
{
int i = 0;
2) Make note of the
printf ("f() is at %p\n", f);
address of f(), which is
while (1)
{
0x106a81ec0 here.
f (i++);
sleep (1);
}
}
Hooking f() from Node.js
'use strict'; $ # install Node.js 5.1
$ npm install co frida frida-load
const co = require('co'); $ node app.js
const frida = require('frida'); { type: 'send', payload: 531 }
const fs = require('mz/fs'); { type: 'send', payload: 532 }
…
let session, script;
co(function *() {
session = yield frida.attach('hello');
const source = yield fs.readFile(
require.resolve('./agent.js'), 'utf-8');
script = yield session.createScript(source);
script.events.listen('message', message => {
console.log(message);
});
yield script.load();
});
'use strict';
session = frida.attach("hello")
script = session.create_script("""
Interceptor.attach(ptr("0x106a81ec0"), {
onEnter: function(args) {
Address of f() goes here
send(args[0].toInt32());
} $ pip install frida
}); $ python app.py
""") {'type': 'send', 'payload': 531}
def on_message(message, data): {'type': 'send', 'payload': 532}
print(message) …
script.on('message', on_message)
script.load()
sys.stdin.read()
There are also language-bindings for QML, .NET, etc. The API is the same except
We will stick to the Node.js bindings for the remainder of this presentation.
Modifying function arguments
'use strict'; $ node app.js
send({
user: {
name: 'john.doe'
},
key: '1234'
});
oops;
Receiving messages
'use strict'; $ node app.js
'use strict';
Module.enumerateExports('libcommonCrypto.dylib', {
onMatch: e => {
if (e.type === 'function') {
try {
Interceptor.attach(e.address, {
onEnter: args => {
send({ event: 'call', name: e.name });
}
});
} catch (error) {
console.log('Ignoring ' + e.name + ': ' + error.message);
}
}
},
onComplete: () => {
send({ event: 'ready' });
}
});
But there's an app for that
$ sudo easy_install frida
$ frida-trace -U -f com.apple.AppStore -I libcommonCrypto.dylib
io plugin code walkthrough
Questions?
Twitter: @oleavr
Thanks!
Code is at:
https://github.com/nowsecure/r2frida
Soon also available in r2pm.