base
base
so的加载流程
https://zhuanlan.zhihu.com/p/22652847
so流程分析
dlopen加载
dlopen
整个so就已经被加载进入内存了
-> .init_array会执行这个部分
dlopen函数结束
system.load
dlopen
整个so就已经被加载进入内存了
-> .init_array会执行这个部分
dlopen函数结束
JNI_OnLoad
马上退出去的
检测没有使用到线程
等一会才退出去
开一个线程
pthread_create -> 杀线程
函数替换
function create_pthread_create() {
const pthread_create_addr =
Module.findExportByName(null, "pthread_create")
const pthread_create = new
NativeFunction(pthread_create_addr, "int", ["pointer",
"pointer", "pointer", "pointer"]);
return new NativeCallback((parg0, parg1, parg2, parg3)
=> {
const module = Process.findModuleByAddress(parg2);
const so_name = module.name;
const baseAddr = module.base
console.log("pthread_create", so_name, "0x" +
parg2.sub(baseAddr).toString(16), "0x" +
parg3.toString(16))
// 成功的返回值是0
return pthread_create(parg0, parg1, parg2, parg3)
}, "int", ["pointer", "pointer", "pointer",
"pointer"])
}
// 或者
function replace_thread() {
var new_pthread_create = create_pthread_create()
var pthread_create_addr =
Module.findExportByName(null, "pthread_create")
// 函数替换
Interceptor.replace(pthread_create_addr,
new_pthread_create);
}
replace_thread()
进行函数替换马上退出
在某一个地方,进行了inline hook检测
dlopen顺利结束,JNI_OnLoad
dump so
import frida
js_script = """
function dump_so(so_name) {
console.log("开始dump")
const module = Process.findModuleByName(so_name);
const module_size = module.size;
Memory.protect(ptr(module.base), module_size, 'rwx');
const soMemory = Memory.readByteArray(module.base,
module_size);
send({name: so_name, base: module.base, size:
module_size}, soMemory);
}
dump_so("libDexHelper.so")
"""
# 保存dump的.so文件
with open(so_name, "wb") as f:
f.write(data)
print(f"{so_name} dumped successfully!")
else:
print(f"Error: {message}")
def main():
# 附加到目标进程
device = frida.get_usb_device()
session = device.attach(18819)
# 加载Frida脚本
script = session.create_script(js_script)
# 设置消息处理函数
script.on("message", on_message)
# 加载并执行脚本
script.load()
if __name__ == "__main__":
main()
SoFixer修复so
.\SoFixer-Windows-64.exe -s .\libDexHelper.so -o
.\libDexHelper_xf.so
frida stalker
https://zhuanlan.zhihu.com/p/344222341
mov x1 x2
mov x1 x2
log
因为我们在JNI_OnLoad里面退出的,所以在stalker里面分析JNI_OnLoad这
个部分。
退出
svc退出
跳转不可执行的地方,也是可以退出的
最后代码
function nopFunc(parg2) {
// 修改内存保护,使其可写
Memory.protect(parg2, 4, 'rwx');
// 使用 Arm64Writer 写入 'ret' 指令
var writer = new Arm64Writer(parg2);
writer.putRet();
writer.flush();
writer.dispose();
console.log("nop " + parg2 + " success");
}
function create_pthread_create() {
const pthread_create_addr =
Module.findExportByName(null, "pthread_create")
const pthread_create = new
NativeFunction(pthread_create_addr, "int", ["pointer",
"pointer", "pointer", "pointer"]);
return new NativeCallback((parg0, parg1, parg2, parg3)
=> {
const module = Process.findModuleByAddress(parg2);
const so_name = module.name;
const baseAddr = module.base;
if (so_name.indexOf("libDexHelper.so") !== -1) {
console.log("pthread_create", so_name, "0x" +
parg2.sub(baseAddr).toString(16), "0x" +
parg3.toString(16))
return 0;
}
// 成功的返回值是0
return pthread_create(parg0, parg1, parg2, parg3)
}, "int", ["pointer", "pointer", "pointer",
"pointer"])
}
// 或者
function replace_thread() {
var new_pthread_create = create_pthread_create()
var pthread_create_addr =
Module.findExportByName(null, "pthread_create")
// 函数替换
Interceptor.replace(pthread_create_addr,
new_pthread_create);
}
replace_thread()
function hook_dlopen(so_name) {
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();
console.log(path)
if (path.indexOf(so_name) !== -1) {
this.match = true
}
}
},
onLeave: function (retval) {
if (this.match) {
var module =
Process.findModuleByName("libDexHelper.so");
nopFunc(module.base.add(0x4B014));
if (module) {
var JNI_OnLoad =
module.findExportByName("JNI_OnLoad")
Interceptor.attach(JNI_OnLoad, {
onEnter: function (args) {
var curTid =
Process.getCurrentThreadId();
const startAddress =
module.base.add(0x31C60);
const size = 0x3755C -
0x31C60;
//开始trace
Stalker.follow(curTid, {
events: {
call: true
},
transform: function
(iterator) {
let instruction =
iterator.next();
const baseFirstAddress
= instruction.address;
const module =
Process.findModuleByAddress(baseFirstAddress);
const isModuleCode =
baseFirstAddress.compare(startAddress) >= 0 &&
baseFirstAddress.compare(startAddress.add(size)) < 0;
if (isModuleCode) {
if (module) {
const name =
module.name;
const offset =
baseFirstAddress.sub(module.base);
const base =
module.base;
console.log(`[transform] start: ${baseFirstAddress}
name:${name} offset: ${offset} base: ${base}`);
} else {
hook_dlopen("libDexHelper.so")
toda
java层的hook有问题
似乎还是被检测到了