- Ⅰ. はじめに
- Ⅱ. インストール
- Ⅲ. 使い方
- iOSでFridaを利用する方法
- Androidのアプリをトレースする
- Windows上のプロセスをトレースする
- 起動中のプロセス一覧を表示する
- インストール済みのアプリ一覧を表示する(USB接続端末)
- 引数を表示する
- HEXダンプ1
- HEXダンプ2
- レジスタ(ARMの例)
- 直接アドレスを指定してメモリを読み取る
- メモリを書き換える
- アドレス(ポインタ)にオフセットを加える
- 文字列を表示する(IL2CPP用)
- ネイティブ関数アドレスを取得し、呼び出す
- Javaをhookする
- Java クラスの新規インスタンスを作成し、メソッドを呼び出す
- Fridaでjavax.crypto.spec.SecretKeySpecをhookする方法
- Fridaでjava.security.MessageDigestをhookする方法
- Frida を Node.js で利用する場合のサンプル
- onLeave の retval を書き換える方法
- onLeaveでargsを読み取る方法
- Windows で send を frida-trace する場合の例
- バックトレースを表示する
- オフセットを指定する場合
- DWARF
- dump_so, dump_dex
- Android root権限なしでFridaを利用する方法
- Android起動時にFridaを自動起動する方法
- IPアドレス指定で接続する方法
- Javaのhookを楽にする方法
- 改ざん検知を回避してfrida-gadgetをinjectする方法
- IL2Cppのhookを楽にする方法
- Anti Anti frida
- その他
- 参考
Ⅰ. はじめに
Frida (読み:ふりーだ)は JavaScriptを用いてアプリケーションをデバッグすることができる強力なツールです。
http://www.frida.re/
Ⅱ. インストール
pip install frida-tools
Ⅲ. 使い方
iOSでFridaを利用する方法
Androidのアプリをトレースする
※予めAndroidにfrida-serverを入れ、起動しておく必要があります。
frida-trace -U -i *Func* app
Windows上のプロセスをトレースする
frida-trace -i *Func* notepad.exe
起動中のプロセス一覧を表示する
frida-ps # USB接続端末 # frida-ps -Ua
インストール済みのアプリ一覧を表示する(USB接続端末)
frida-ps -Uai
引数を表示する
onEnter: function (log, args, state) { for(var i=0; i<10; i++) { log("Func args[" + i + "]" + Memory.readUtf8String(args[i])); } },
HEXダンプ1
function dump(pointer, length) { var buf = Memory.readByteArray(pointer, length); console.log(hexdump(buf, { offset: 0, length: length, header: true, ansi: true })); } dump(pointer, 16);
HEXダンプ2
function arrayBuffer2hexString (buffer) { return Array.prototype.map.call(new Uint8Array(buffer), function (x) { return ('00' + x.toString(16)).slice(-2) }).join(' '); } var src = args[0]; var srcSize = args[1]; var buffer = Memory.readByteArray(src, srcSize); var hexString = arrayBuffer2hexString(buffer); console.log(hexString); // 出力 // 68 65 6C 6C 6F 77 6F 72 6C 64
レジスタ(ARMの例)
console.log("r0: " + this.context.r0); console.log("r1: " + this.context.r1); console.log("r2: " + this.context.r2); console.log("r3: " + this.context.r3); console.log("r4: " + this.context.r4); console.log("r5: " + this.context.r5); console.log("r6: " + this.context.r6); console.log("r7: " + this.context.r7);
直接アドレスを指定してメモリを読み取る
var pointer = new NativePointer("0x7ad1a4d0"); var buf1 = Memory.readUtf8String(pointer); console.log(buf1);
メモリを書き換える
// 0x1CCA61C に 0x01を1バイト書き込む
Memory.writeS8(0x1CCA61C, 0x01);
アドレス(ポインタ)にオフセットを加える
やり方1
var pointer = new NativePointer("0x00400000"); pointer = pointer.add(1);
やり方2
var pointer = ptr("0x00400000"); pointer = pointer.add(1);
やり方3
function addOffset(pointer, offset) { var address = parseInt(pointer) + offset; var addressHex = "0x" + address.toString(16); return new NativePointer(addressHex); } addOffset(pointer, 0x10);
文字列を表示する(IL2CPP用)
function dumpString(pointer) { // length var lengthPointer = addOffset(pointer, 0x10); var length = Memory.readInt(lengthPointer); // data var dataPointer = addOffset(pointer, 0x14); var str = Memory.readUtf16String(dataPointer, length); console.log("[" + str + "]"); }
ネイティブ関数アドレスを取得し、呼び出す
function getFunctionPointer(moduleName, offset, ret, args) { var lib = Module.findBaseAddress(moduleName); var address = parseInt(lib) + offset; var functionPointer = new NativePointer("0x" + address.toString(16)); var func = new NativeFunction(functionPointer, ret, args); return func; } var func = getFunctionPointer('libil2cpp.so', 0x1CCA61C, 'pointer', ['pointer', 'pointer']); var result = func(thisPointer, arg);
Javaをhookする
// frida -U -l myscript.js tld.hoge.app function hookClassA() { classA = Java.use("tld.hoge.app.a"); classA.onClick.implementation = function(arg1, arg2) { // this.onClick(arg1, arg2); console.log("[*] onClick called"); } console.log("[*] onClick handler modified"); } function hookClassB() { classB = Java.use("tld.hoge.app.b"); classB.a.implementation = function(arg1, arg2) { retval = this.a(arg1, arg2); console.log("retval=" + retval); return retval; } console.log("[*] tld.hoge.app.b modified"); } setImmediate(function() { console.log("[*] Starting script"); Java.perform(function() { hookClassA(); hookClassB(); }) })
Java クラスの新規インスタンスを作成し、メソッドを呼び出す
// frida -U -l myscript.js tld.hoge.app // https://github.com/frida/frida-java-bridge/blob/master/test/re/frida/ClassCreationTest.java if (Java.available) { Java.perform(function () { const JavaString = Java.use('java.lang.String'); const str = JavaString.$new('Hello World'); console.log('str = ' + str); console.log('str.length() = ' + str.length()); }) } // 出力 // str = Hello World // str.length() = 11
Fridaでjavax.crypto.spec.SecretKeySpecをhookする方法
Fridaでjava.security.MessageDigestをhookする方法
Frida を Node.js で利用する場合のサンプル
onLeave の retval を書き換える方法
replace() を使うと書き換える事が出来る。
onLeave: function (log, retval, state) { retval.replace(1); // retvalを1に書き換える }
onLeaveでargsを読み取る方法
thisにオブジェクト状態を保存する事が出来るのでその機能を利用する。
{ onEnter: function (log, args, state) { this.args2 = args[2]; log('onEnter args[2]:' + this.args2); }, onLeave: function (log, retval, state) { log('onLeave args[2]:' + this.args2); } } // 出力 // onEnter args[2]:0x106 // onLeave args[2]:0x106
Windows で send を frida-trace する場合の例
1. frida-trace する
frida-trace -i "send" hoge.exe
2. send.js を書き換える
onEnter: function (log, args, state) { var length = parseInt(args[2]); var buf = Memory.readByteArray(args[1], length); console.log(hexdump(buf, { offset: 0, length: length, header: true, ansi: true })); },
バックトレースを表示する
var address = Module.getExportByName('libhoge.so', 'GetValue'); Interceptor.attach(address, { onEnter: function (args) { console.log('This function called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join('\n') + '\n'); } }); /* This function called from: 0x6febb3d6f8 libhoge.so!0x20bc6f4 0x6fec493c38 libhoge.so!0x2a12c34 0x6febb3f98c libhoge.so!0x20be988 ... */
オフセットを指定する場合
frida-trace -U -a libxxx.so!13c8112 xx.xx.xx
DWARF
https://github.com/iGio90/Dwarf
findExport('open')
Module.findExportByName('libc.so', 'open')
Process.findModuleByName('libfooo.so').base.add(0x768440)
dump_so, dump_dex
Android root権限なしでFridaを利用する方法
Android起動時にFridaを自動起動する方法
IPアドレス指定で接続する方法
https://github.com/frida/frida/issues/70#issuecomment-186019188
Javaのhookを楽にする方法
改ざん検知を回避してfrida-gadgetをinjectする方法
IL2Cppのhookを楽にする方法
Anti Anti frida
その他
System.Security.Cryptography.RijndaelManagedTransform のコンストラクタはkey,ivを引数に取っている
AesManagedの場合AesTransformクラスのコンストラクタ。
AesManagedの場合SymmetricAlgorithm の set_Key など
Mono.Security.Cryptography.SymmetricTransformのTransformFinalBlock
System.Security.Cryptography.HashAlgorithm の ComputeHash
System.Security.Cryptography.HMAC のset_Key
BestHTTP の set_RawData はPOSTデータ
BestHttpのSSL証明書チェックはICertificateVerifyerを継承しているIsValidメソッドで行われている。
参考
http://2015.zeronights.org/assets/files/23-Ravnas.pdf
https://www.codemetrix.net/hacking-android-apps-with-frida-1/
https://www.codemetrix.net/hacking-android-apps-with-frida-2/
https://www.codemetrix.net/hacking-android-apps-with-frida-3/
https://codeshare.frida.re/
https://github.com/11x256/frida-android-examples
https://github.com/kingking888/AndroidReverseEngineering/tree/master/Frida
https://github.com/secRet-re/frida-scripts