備忘録

備忘録

Frida の使い方

Ⅰ. はじめに

Frida は JavaScriptを用いてネイティブアプリをデバッグすることができる強力なツールです。
www.frida.re

Ⅱ. インストール

pip install frida

Ⅲ. 使い方

Androidのアプリをトレースする

※予めAndroidにfrida-serverを入れ、起動しておく必要があります。

frida-trace -U -i *Func* app

Windows上のプロセスをトレースする

frida-trace -i *Func* notepad.exe

プロセス一覧を表示する

frida-ps

引数を表示する

onEnter: function (log, args, state) {
  for(var i=0; i<10; i++) {
    log("Func args[" + i + "]" + Memory.readUtf8String(args[i]));
  }
},

メモリダンプ

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);

f:id:kagasu:20161124114917p:plain

レジスタ(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, 0x8);
  var length = Memory.readInt(lengthPointer);

  // data
  var dataPointer = addOffset(pointer, 0xC);
  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();
  })
})

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

onLeave の retval を書き換える方法

replace() を使うと書き換える事が出来る。

onLeave: function (log, retval, state) {
  retval.replace(1);  // retvalを1に書き換える
}

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
    }));
},

オフセットを指定する場合

frida-trace -U -a libxxx.so!13c8112 xx.xx.xx

その他

System.Security.Cryptography.RijndaelManagedTransform のコンストラクタはkey,ivを引数に取っている
AesManagedの場合AesTransformクラスのコンストラクタ。
AesManagedの場合SymmetricAlgorithm の set_Key など

criWareUnity_SetDecryptionKey
System.Security.Cryptography.HashAlgorithm の ComputeHash
BestHTTP の set_RawData はPOSTデータ
BestHttpのSSL証明書チェックはICertificateVerifyerを継承しているIsValidメソッドで行われている。