github

https://frida.re/docs/functions/ 官方教程

https://learnfrida.info/ 挺好的教程

https://www.ol4three.com/2021/01/05/Android/frida/Frida-Android%E9%80%86%E5%90%91%E4%B9%8B%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BDdex-Hook-%E4%B8%8A/

frida byteArray Dump

npm install @types/frida-gum
Java.perform(() => {
  const Cipher = Java.use('javax.crypto.Cipher');
  const Exception = Java.use('java.lang.Exception');
  const Log = Java.use('android.util.Log');
 
  const init = Cipher.init.overload('int', 'java.security.Key');
  init.implementation = function (opmode, key) {
    const result = init.call(this, opmode, key);
 
    console.log('Cipher.init() opmode:', opmode, 'key:', key);
    console.log(stackTraceHere());
 
    return result;
  };
 
  function stackTraceHere() {
    return Log.getStackTraceString(Exception.$new());
  }
});

自定义载入 so 的情况可能会出现 hook 查不到函数的情况,这时要延时在 frida 命令行中重新载入 nativehook

> NativeHook()

native 模板

var so_name = "libUE4.so";
 
function dump_so() {
    var libso = Process.getModuleByName(so_name);
    console.log("[name]:", libso.name);
    console.log("[base]:", libso.base);
    console.log("[size]:", ptr(libso.size));
    console.log("[path]:", libso.path);
    var file_path = "/data/data/com.oacia.apk_protect/" + libso.name + "_" + libso.base + "_" + ptr(libso.size) + ".so";
    var file_handle = new File(file_path, "wb");
    if (file_handle && file_handle != null) {
        Memory.protect(ptr(libso.base), libso.size, 'rwx');
        var libso_buffer = ptr(libso.base).readByteArray(libso.size);
        file_handle.write(libso_buffer);
        file_handle.flush();
        file_handle.close();
        console.log("[dump]:", file_path);
    }
}
 
 
function hook_open() {
    console.log("attaching open...")
    Interceptor.attach(Module.findExportByName(null, "open"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    console.log("open " + path);
                    if (path == "/proc/self/maps") {
                        console.log("find maps");
                        if (first_hook_open) {
                            first_hook_open = false;
                            return;
                        }
                        // redirect to noexits file
                        this.new_path = Memory.allocUtf8String("/proc/self/noexitsssss");
                        args[0] = this.new_path;
                    }
                }
            },
            onLeave: function (ret) {
            }
        }
    );
}
 
 
function hook_rotate() {
    var lib = Module.findBaseAddress(so_name)
    if (!lib) {
        console.log("[x] cannot find lib");
    }
 
    var dest;
    Interceptor.attach(lib.add(0x6044), {
        onEnter: (args) => {
            console.log("RC4 decrypt");
            dest = args[0];
            console.log(hexdump(args[0], {
                offset: 0,
                length: 0x40,
                header: true,
                ansi: false
            }))
            console.log(`len: ${args[1]}`);
        },
        onLeave: () => {
            console.log("RC4 decrypt result:");
            console.log(hexdump(dest, {
                offset: 0,
                length: 0x40,
                header: true,
                ansi: false
            }))
        }
    })
    Interceptor.attach(lib.add(0x05B30), {
        onEnter: function (args) {
            console.log("in the uncompress function, get v4:")
            var v4 = this.context.x23;
            console.log(hexdump(v4, {
                offset: 0,
                length: 0x140,
                header: true,
                ansi: false
            }))
        }
    })
}
 
 
function hook_dlopen() {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(so_name) >= 0) {
                        is_can_hook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (is_can_hook) {
                    main();
                }
            }
        }
    );
}
 
 
 
function main(){
 
}
 
setImmediate(hook_dlopen)

https://crifan.github.io/reverse_debug_frida/website/use_frida/frida_cli/

  • frida/frida-trace 的调试目标方式 概述
    • 支持 2 种模式:SpawnAttach
      • Spawn 模式:只有一种写法
        • -f TARGET
          • TARGET 是 app 包名 或 Executable 二进制文件名
      • Attach 模式:有多种写法=针对 app 或 Executable 有不同写法
        • 同时支持app 或 Executable的:-p PID
          • PID 是 app 或 Executable 的进程 ID
        • 针对Executable的: -n NAME
          • NAME 是 Executable 的二进制文件名,比如 amsaccountsd
        • 针对app的:-N IDENTIFIER
          • IDENTIFIER 是 app 的包名,比如 com.apple.Prefrences
        • 特殊的:针对当前手机中正在运行的 frontmost 最前台的:-F
          • 由于是,当前最前台的正在运行的= 那只能是带页面显示的 app,且也无需再加额外参数指定 app

比较好用的 frida 代码仓库

https://konsumer.js.org/frida-codeshare/