備忘録

備忘録

Frida の使い方

Ⅰ. はじめに

Frida (読み:ふりーだ)は JavaScriptを用いてアプリケーションをデバッグすることができる強力なツールです。
http://www.frida.re/

Ⅱ. インストール

pip install frida-tools

Ⅲ. 使い方

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する方法

https://kagasu.hatenablog.com/entry/2018/04/30/194106

Fridaでjava.security.MessageDigestをhookする方法

https://kagasu.hatenablog.com/entry/2018/06/13/221146

Frida を Node.js で利用する場合のサンプル

https://github.com/frida/frida-node/tree/master/examples

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)

Android root権限なしでFridaを利用する方法

https://archive.fo/n8ozY

Android起動時にFridaを自動起動する方法

https://github.com/AeonLucid/MagiskFrida

IPアドレス指定で接続する方法

https://github.com/frida/frida/issues/70#issuecomment-186019188

Javaのhookを楽にする方法

https://github.com/iGio90/frida-java-ext

改ざん検知を回避してfrida-gadgetをinjectする方法

https://github.com/lico-n/ZygiskFrida

IL2Cppのhookを楽にする方法

https://github.com/vfsfitvnm/frida-il2cpp-bridge

その他

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メソッドで行われている。