frida snippets
1.0.0
& 出力例も
Load C/C++ module
One time watchpoint
Socket activity
Intercept open
Execute shell command
List modules
Log SQLite query
Log method arguments
Intercept entire module
Dump memory segments
Memory scan
Stalker
Cpp Demangler
Early hook
Binder transactions
Get system property
Reveal manually registered native symbols
Enumerate loaded classes
Class description
Turn WiFi off
Set proxy
Get IMEI
Hook io InputStream
Android make Toast
Await for specific module to load
Webview URLS
Print all runtime strings & stacktrace
Print shared preferences updates
String comparison
Hook JNI by address
Hook constructor
Hook Java reflection
Trace class
Hooking Unity3d
Get Android ID
Change location
Bypass FLAG_SECURE
Shared Preferences update
Hook all method overloads
Register broadcast receiver
Increase step count
list classes implements interface with class loaders
$ frida --codeshare FrenchYeti/android-file-system-access-hook -f com.example.app --no-pause
implementation
プロパティにnull
を割り当てます。OS Log
iOS alert box
File access
Observe class
Find application UUID
Extract cookies
Describe class members
Class hierarchy
Hook refelaction
Device properties
Take screenshot
Log SSH commands
{
"scope": "source.js",
"completions": [
{"trigger": "fridainterceptor", "contents": "Interceptor.attach(n ptr,n {n onEnter:function(args) {nn },n onLeave: function(retval) {nn }n }n)"},
{"trigger": "fridaperform", "contents": "function main(){n console.log('main()');n}nnconsole.log('script loaded');nJava.perform(main);"},
{"trigger": "fridause", "contents": "var kls = Java.use('kls');"},
{"trigger": "fridahex", "contents": "hexdump(n ptr,n {n offset: 0,n length: ptr_sizen }n);" },
{"trigger": "fridabacktrace", "contents": "console.log('called from:\n' +n Thread.backtrace(this.context, Backtracer.ACCURATE)n .map(DebugSymbol.fromAddress).join('\n') + '\n'n);"},
{"trigger": "fridamods", "contents": "var mods = Process.enumerateModules().filter(function(mod){n return mod.name.includes("<name>");n});"},
{"trigger": "fridaexport", "contents": "Module.findExportByName(null, "<export_name>");"},
{"trigger": "fridabase", "contents": "Module.findBaseAddress(name);"},
{"trigger": "fridaoverload", "contents": "kls.method_name.overload().implementation=function(){}"}
]
}
略語をリストするには:ab
key
と<Space>
を入力して展開します
~/.vimrc
に追加 ab fridaintercept Interceptor.attach(ptr, {<CR><Tab>onEnter: function(args) {<CR><CR>},<CR>onLeave: function(retval) {<CR><CR>}<CR><BS>})
ab fridabacktrace console.warn(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('n'));<ESC>F(3;
ab fridadescribe console.log(Object.getOwnPropertyNames(Java.use('$').__proto__).join('nt'))<Esc>F$
キーボード ショートカットを使用した Java メソッド フック ジェネレーター
curl -o ~/$JEB$/scripts/FridaCodeGenerator.py https://raw.githubusercontent.com/iddoeldor/frida-snippets/master/scripts/FridaCodeGenerator.py
Ctrl+Shift+Z
を押しますxclip
を使用) var keylog_callback = new NativeCallback ( ( ssl , line ) => {
send ( Memory . readCString ( line ) ) ;
} , 'void' , [ 'pointer' , 'pointer' ] ) ;
if ( ObjC . available ) {
var CALLBACK_OFFSET = 0x2A8
if ( Memory . readDouble ( Module . findExportByName ( 'CoreFoundation' , 'kCFCoreFoundationVersionNumber' ) ) >= 1751.108 ) {
CALLBACK_OFFSET = 0x2B8
}
Interceptor . attach ( Module . findExportByName ( 'libboringssl.dylib' , 'SSL_CTX_set_info_callback' ) , {
onEnter ( args ) {
ptr ( args [ 0 ] ) . add ( CALLBACK_OFFSET ) . writePointer ( keylog_callback )
}
} )
} else if ( Java . available ) {
var set_keylog_callback = new NativeFunction ( Module . findExportByName ( 'libssl.so' , 'SSL_CTX_set_keylog_callback' ) , 'void' , [ 'pointer' , 'pointer' ] ) ;
Interceptor . attach ( Module . findExportByName ( 'libssl.so' , 'SSL_CTX_new' ) , {
onLeave ( retval ) {
set_keylog_callback ( retval , keylog_callback )
}
} )
}
⬆ トップに戻る
# include < iostream >
# include < string >
extern " C " {
void * create_stdstr ( char *data, int size) {
std::string* s = new std::string ();
(*s). assign (data, size);
return s;
}
}
$ ./android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++ a.cpp -o a -shared -static-libstdc++ && adb push a /data/local/tmp/a
[ device ] - >
function readStdString ( str ) {
if ( ( str . readU8 ( ) & 1 ) === 1 ) { // size LSB (=1) indicates if it's a long string
return str . add ( 2 * Process . pointerSize ) . readPointer ( ) . readUtf8String ( ) ;
}
return str . add ( 1 ) . readUtf8String ( ) ;
}
[ device ] - > Module . load ( '/data/local/tmp/a' ) ;
[ device ] - > var fp_create_stdstr = Module . findExportByName ( 'a' , 'create_stdstr' ) ;
[ device ] - > var createStdString = new NativeFunction ( fp_create_stdstr , 'pointer' , [ 'pointer' , 'int' ] ) ;
[ device ] - > var stdstr1 = createStdString ( Memory . allocUtf8String ( "abcd" ) , 3 ) ;
"0x07691234567"
[ device ] - > readStdString ( stdstr1 ) ;
"abc"
$ ./aarch64-linux-android21-clang /tmp/b.c -o /tmp/a -shared ../sysroot/usr/lib/aarch64-linux-android/21/liblog.so && adb push /tmp/a /data/local/tmp/a
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#define TAG "TEST1"
#define LOGI (...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGE (...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
void test ( void ) {
FILE * fp = popen ( "ls -l /sdcard 2>&1" , "r" );
if ( fp == NULL )
LOGE ( "executing cmd failed" );
char b [ 256 ];
while ( fgets ( b , sizeof ( b ), fp ) != NULL ) {
LOGI ( "%s" , b );
}
pclose ( fp );
}
$ frida -Uf com.app --no-pause --enable-jit -e " Module.load('/data/local/tmp/a') "
[ ] - > new NativeFunction(Module.findExportByName( ' a ' , ' test ' ), ' void ' , [])()
⬆ トップに戻る
funcPtr
傍受し、 mprotect
を使用してアクセス許可を削除することでx2
に読み取り/書き込みを行ったユーザーをログに記録します。
Process . setExceptionHandler ( function ( exp ) {
console . warn ( JSON . stringify ( Object . assign ( exp , { _lr : DebugSymbol . fromAddress ( exp . context . lr ) , _pc : DebugSymbol . fromAddress ( exp . context . pc ) } ) , null , 2 ) ) ;
Memory . protect ( exp . memory . address , Process . pointerSize , 'rw-' ) ;
// can also use `new NativeFunction(Module.findExportByName(null, 'mprotect'), 'int', ['pointer', 'uint', 'int'])(parseInt(this.context.x2), 2, 0)`
return true ; // goto PC
} ) ;
Interceptor . attach ( funcPtr , {
onEnter : function ( args ) {
console . log ( 'onEnter' , JSON . stringify ( {
x2 : this . context . x2 ,
mprotect_ret : Memory . protect ( this . context . x2 , 2 , '---' ) ,
errno : this . errno
} , null , 2 ) ) ;
} ,
onLeave : function ( retval ) {
console . log ( 'onLeave' ) ;
}
} ) ;
[iOS Device::com.app]-> onEnter {
"x2": "0x1c145c6e0",
"mprotect_ret": true,
"errno": 2
}
{
"type": "access-violation",
"address": "0x1853b0198",
"memory": {
"operation": "read",
"address": "0x1c145c6e0"
},
"context": {
"lr": "0x100453358",
"fp": "0x16fb2e860",
"x28": "0x0",
"x27": "0x0",
"x26": "0x104312600",
"x25": "0x0",
"x24": "0x0",
"x23": "0x0",
"x22": "0x0",
"x21": "0xb000000422bbda03",
"x20": "0x1c4a22560",
"x19": "0xb000000422bbda03",
"x18": "0x0",
"x17": "0x100d25290",
"x16": "0x1853b0190",
"x15": "0x0",
"x14": "0x5",
"x13": "0xe5a1c4119597",
"x12": "0x10e80ca30",
"x11": "0x180000003f",
"x10": "0x10e80ca00",
"x9": "0x1020ad7c3",
"x8": "0x0",
"x7": "0x0",
"x6": "0x0",
"x5": "0x0",
"x4": "0xb000000422bbda03",
"x3": "0x1c4a22560",
"x2": "0x1c145c6e0",
"x1": "0x1020ad7c3",
"x0": "0x1c145c6e0",
"sp": "0x16fb2e790",
"pc": "0x1853b0198"
},
"nativeContext": "0x16fc42b24"
}
onLeave
⬆ トップに戻る
Process
. getModuleByName ( { linux : 'libc.so' , darwin : 'libSystem.B.dylib' , windows : 'ws2_32.dll' } [ Process . platform ] )
. enumerateExports ( ) . filter ( ex => ex . type === 'function' && [ 'connect' , 'recv' , 'send' , 'read' , 'write' ] . some ( prefix => ex . name . indexOf ( prefix ) === 0 ) )
. forEach ( ex => {
Interceptor . attach ( ex . address , {
onEnter : function ( args ) {
var fd = args [ 0 ] . toInt32 ( ) ;
var socktype = Socket . type ( fd ) ;
if ( socktype !== 'tcp' && socktype !== 'tcp6' )
return ;
var address = Socket . peerAddress ( fd ) ;
if ( address === null )
return ;
console . log ( fd , ex . name , address . ip + ':' + address . port ) ;
}
} )
} )
Androidの例
# wrap the script above inside Java.perform
$ frida -Uf com.example.app -l script.js --no-pause
[Android Model-X::com.example.app]- > 117 write 5.0.2.1:5242
117 read 5.0.2.1:5242
135 write 5.0.2.1:4244
135 read 5.0.2.1:4244
135 read 5.0.2.1:4244
⬆ トップに戻る
特定のファイルが開かれた場合にlibc#open
インターセプトし、バックトレースをログに記録する例。
Interceptor . attach ( Module . findExportByName ( "/system/lib/libc.so" , "open" ) , {
onEnter : function ( args ) {
this . flag = false ;
var filename = Memory . readCString ( ptr ( args [ 0 ] ) ) ;
console . log ( 'filename =' , filename )
if ( filename . endsWith ( ".xml" ) ) {
this . flag = true ;
var backtrace = Thread . backtrace ( this . context , Backtracer . ACCURATE ) . map ( DebugSymbol . fromAddress ) . join ( "nt" ) ;
console . log ( "file name [ " + Memory . readCString ( ptr ( args [ 0 ] ) ) + " ]nBacktrace:" + backtrace ) ;
}
} ,
onLeave : function ( retval ) {
if ( this . flag ) // passed from onEnter
console . warn ( "nretval: " + retval ) ;
}
} ) ;
var fds = { } ; // for f in /proc/`pidof $APP`/fd/*; do echo $f': 'readlink $f; done
Interceptor . attach ( Module . findExportByName ( null , 'open' ) , {
onEnter : function ( args ) {
var fname = args [ 0 ] . readCString ( ) ;
if ( fname . endsWith ( '.jar' ) ) {
this . flag = true ;
this . fname = fname ;
}
} ,
onLeave : function ( retval ) {
if ( this . flag ) {
fds [ retval ] = this . fname ;
}
}
} ) ;
[ 'read' , 'pread' , 'readv' ] . forEach ( fnc => {
Interceptor . attach ( Module . findExportByName ( null , fnc ) , {
onEnter : function ( args ) {
var fd = args [ 0 ] ;
if ( fd in fds )
console . log ( ` ${ fnc } : ${ fds [ fd ] }
t ${ Thread . backtrace ( this . context , Backtracer . ACCURATE ) . map ( DebugSymbol . fromAddress ) . join ( 'nt' ) } ` ) ;
}
} ) ;
} ) ;
⬆ トップに戻る
import frida
from frida_tools . application import Reactor
import threading
import click
class Shell ( object ):
def __init__ ( self , argv , env ):
self . _stop_requested = threading . Event ()
self . _reactor = Reactor ( run_until_return = lambda reactor : self . _stop_requested . wait ())
self . _device = frida . get_usb_device ()
self . _sessions = set ()
self . _device . on ( "child-added" , lambda child : self . _reactor . schedule ( lambda : self . _on_child_added ( child )))
self . _device . on ( "child-removed" , lambda child : self . _reactor . schedule ( lambda : self . _on_child_removed ( child )))
self . _device . on ( "output" , lambda pid , fd , data : self . _reactor . schedule ( lambda : self . _on_output ( pid , fd , data )))
self . argv = argv
self . env = env
self . output = [] # stdout will pushed into array
def exec ( self ):
self . _reactor . schedule ( lambda : self . _start ())
self . _reactor . run ()
def _start ( self ):
click . secho ( "✔ spawn(argv={})" . format ( self . argv ), fg = 'green' , dim = True )
pid = self . _device . spawn ( self . argv , env = self . env , stdio = 'pipe' )
self . _instrument ( pid )
def _stop_if_idle ( self ):
if len ( self . _sessions ) == 0 :
self . _stop_requested . set ()
def _instrument ( self , pid ):
click . secho ( "✔ attach(pid={})" . format ( pid ), fg = 'green' , dim = True )
session = self . _device . attach ( pid )
session . on ( "detached" , lambda reason : self . _reactor . schedule ( lambda : self . _on_detached ( pid , session , reason )))
click . secho ( "✔ enable_child_gating()" , fg = 'green' , dim = True )
session . enable_child_gating ()
# print("✔ resume(pid={})".format(pid))
self . _device . resume ( pid )
self . _sessions . add ( session )
def _on_child_added ( self , child ):
click . secho ( "⚡ child_added: {}" . format ( child ), fg = 'green' , dim = True )
self . _instrument ( child . pid )
@ staticmethod
def _on_child_removed ( child ):
click . secho ( "⚡ child_removed: {}" . format ( child ), fg = 'green' , dim = True )
def _on_output ( self , pid , fd , data ):
# print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data)))
# fd=0 (input) fd=1(stdout) fd=2(stderr)
if fd != 2 :
self . output . append ( data )
def _on_detached ( self , pid , session , reason ):
click . secho ( "⚡ detached: pid={}, reason='{}'" . format ( pid , reason ), fg = 'green' , dim = True )
self . _sessions . remove ( session )
self . _reactor . schedule ( self . _stop_if_idle , delay = 0.5 )
@ staticmethod
def _on_message ( pid , message ):
click . secho ( "⚡ message: pid={}, payload={}" . format ( pid , message ), fg = 'green' , dim = True )
ディレクトリの内容をリストします。
def ls ( folder ):
cmd = Shell ([ '/bin/sh' , '-c' , 'ls -la ' + folder ], None )
cmd . exec ()
for chunk in cmd . output :
print ( chunk . strip (). decode ())
iOSからバイナリをプルする
cmd = Shell ([ '/bin/sh' , '-c' , 'cat /System/Library/PrivateFrameworks/Example.framework/example' ], None )
cmd . exec ()
with open ( '/tmp/example' , 'wb+' ) as f :
f . writelines ( cmd . output )
# $ file /tmp/example
# /tmp/example: Mach-O 64-bit 64-bit architecture=12 executable
⬆ トップに戻る
Process . enumerateModulesSync ( )
. filter ( function ( m ) { return m [ 'path' ] . toLowerCase ( ) . indexOf ( 'app' ) != - 1 ; } )
. forEach ( function ( m ) {
console . log ( JSON . stringify ( m , null , ' ' ) ) ;
// to list exports use Module.enumerateExportsSync(m.name)
} ) ;
モジュールとエクスポートのリストを表示する
sudo frida Process -- no - pause -- eval ' var x = { } ; Process . enumerateModulesSync ( ) . forEach ( function ( m ) { x [ m . name ] = Module . enumerateExportsSync ( m . name ) } ) ; x ' - q | less + F
{
"name" : "app_process64" ,
"base" : "0x6313a1c000" ,
"size" : 40960 ,
"path" : "/system/bin/app_process64"
}
{
"name" : "libappfuse.so" ,
"base" : "0x749ab96000" ,
"size" : 53248 ,
"path" : "/system/lib64/libappfuse.so"
}
{
"name" : "[email protected]" ,
"base" : "0x749b448000" ,
"size" : 90112 ,
"path" : "/system/lib64/[email protected]"
}
{
"name" : "[email protected]" ,
"base" : "0x749ac9e000" ,
"size" : 94208 ,
"path" : "/system/lib64/[email protected]"
}
{
"name" : "[email protected]" ,
"base" : "0x74981e0000" ,
"size" : 98304 ,
"path" : "/system/lib64/[email protected]"
}
{
"name" : "[email protected]" ,
"base" : "0x73fb4cc000" ,
"size" : 40960
拡大する