[安全] Frida Labs 0x8
总览
反编译

可以看到最重要的比较函数 public native int cmpstr(String str); 是一个 native 函数
native 函数是编译之后储存在 so库 里的函数, 我们需要去对应的 so库 里面找
static {
System.loadLibrary("frida0x8");
}可以看到加载了一个名字叫 frida0x8 的库
如果使用 jadx, 那么在 资源文件 -> lib -> 架构 -> libxxx.so 中会找到你需要的库

使用反编译器 (这里使用 IDA) 打开该 so 文件, 如果你需要找的函数在导出函数里面的话, 那么它的命名应该会是 Java_包名_类名_方法名

查看反编译的函数

到这里, 我们可以想到数个办法来获取 password
- 写简单脚本得到 flag (这里不做展示)
- 由于
__android_log_print(3, "Password", (__int64)&unk_6B0, passwd);打印了 password, 所以我们可以直接查看 log 来获取 password - hook
__android_log_print来查看 password - hook
strcmp来查看 password
方法一: 查看 log
使用
abd logcat来查看 __android_log_print 的打印结果
我们可以使用 frida-ps -Uai 来查看正在运行的 frida0x8 的 pid, 然后为上述命令指定 pid, 可以缩小查看的 log 量
例如我的
> frida-ps -Uai
PID Name Identifier
---- -------------- -----------------------
2850 Frida 0x8 com.ad2001.frida0x8
使用命令
adb logcat --pid=2850可以看到这样的输出

方法二: hook native 函数
spawn 模式下由于 Frida 加载的时机非常早, 会出现库仍未加载所以 hook 不到目标库相关函数的情况
为了防止这种情况发生, 可以 hook 一个用来加载 native 库的函数 android_dlopen_ext, 通过判断其参数来确认目标库是否加载
虽然好像这题的思路都没有 hook libfrida0x8.so 这个库的函数, 所以等不等这个目标库加载完成都没什么关系
放一个板子
function HookDLopen(libname: string, onLoad: () => void) {
const dlopenExtPtr = Module.findGlobalExportByName("android_dlopen_ext");
if (dlopenExtPtr) {
console.log("[+] Hooked android_dlopen_ext");
Interceptor.attach(dlopenExtPtr, {
onEnter: function (this: any, args) {
this.filename = args[0].readCString();
},
onLeave: function (this: any, retval) {
if (retval.isNull()) return ;
if (this.filename && this.filename.indexOf(libname) >= 0) {
console.log(`[!] Target library loaded: ${this.filename}`);
onLoad();
}
}
});
}
}
const funcname = "";
const libname = "";
const onLoad = () => {
console.log(`[+] onLoad triggered for ${libname}`);
const funcPtr = Module.findGlobalExportByName(funcname);
if (funcPtr) {
console.log(`[+] Found ${funcname} at ${funcPtr}`);
Interceptor.attach(funcPtr, {
onEnter: function (this: any, args) {},
onLeave: function (this: any, retv) {}
});
console.log(`[+] Hooked ${funcname}`);
} else {
console.log(`[-] ${funcname} not found`);
}
};
const loadedModule = Process.findModuleByName(libname);
if (loadedModule) {
console.log(`[+] ${libname} already loaded`);
onLoad();
} else {
console.log(`[+] Waiting for ${libname} to load...`);
HookDLopen(libname, onLoad);
}其中 onLoad 函数就是我们需要实现的功能
Interceptor.attach 可以在 hook 某个函数, 使得在调用该函数之前, 先通过 onEnter 函数对参数进行处理, 然后将处理完的参数传入函数中, 获取返回值之后通过 onLeave 函数对返回值进行处理, 再将处理后的返回值传给调用者
由于 hook 的函数不一定只在你想要有效果的地方被 hook, 因此需要一些判定来过滤目标函数调用, 比如可以看参数, 符合你想要的那个调用再输出之类的
-
hook
__android_log_printconst funcname = "__android_log_print"; const libname = "libfrida0x8.so"; const onLoad = () => { console.log(`[+] onLoad triggered for ${libname}`); const funcPtr = Module.findGlobalExportByName(funcname); if (funcPtr) { console.log(`[+] Found ${funcname} at ${funcPtr}`); Interceptor.attach(funcPtr, { onEnter: function (this: any, args) { const prio = args[0].toInt32(); const tagPtr = args[1]; const fmtPtr = args[2]; const passwdPtr = args[3]; if (prio !== 3) return ; const tag = tagPtr.readCString(); if (tag !== "Password") return ; const fmt = fmtPtr.readCString(); console.log(`[+] Captured targeted log call:`); console.log(` Prio: ${prio}`); console.log(` Tag: ${tag}`); console.log(` Fmt: ${fmt}`); console.log(` Passwd (raw): ${passwdPtr}`); const passwdStr = passwdPtr.readCString(); console.log(` Passwd (string): ${passwdStr}`); } }); console.log(`[+] Hooked ${funcname}`); } else { console.log(`[-] ${funcname} not found`); } };点一下 submit 就有调用
-
hook
strcmpconst funcname = "strcmp"; const libname = "libfrida0x8.so"; const onLoad = () => { console.log(`[+] onLoad triggered for ${libname}`); const funcPtr = Module.findGlobalExportByName(funcname); if (funcPtr) { console.log(`[+] Found ${funcname} at ${funcPtr}`); Interceptor.attach(funcPtr, { onEnter: function (this: any, args) { const inputPtr = args[0]; const inputStr = inputPtr.readCString(); const passwdPtr = args[1]; const passwdStr = passwdPtr.readCString(); if (inputStr === "123321") { console.log(`[+] Password is ${passwdStr}`); } } }); console.log(`[+] Hooked ${funcname}`); } else { console.log(`[-] ${funcname} not found`); } };只要你的输入是
123321密码就能被打印出来