Frida-Dexdump脱壳
用于提取DEX文件
https://github.com/hluwa/frida-dexdump
需要先绕过frida反调试
Fart脱壳
一款自动化脱壳工具
https://github.com/hanbinglengyue/FART?tab=readme-ov-file
同样需要先绕过frida反调试
绕过frida反调试
实践一:Hook pthread_create绕过反调试
首先确认哪个库文件创建了检测线程,Patch 所有调用 pthread_create 函数的caller或者自建pthread_create来绕过检测
通过hook dlopen查看哪个.so文件在检测hook,运行
var dlopen_ext =
Module.findExportByName(null,
"android_dlopen_ext"); if (dlopen_ext) {
Interceptor.attach(dlopen_ext,
{ onEnter: function (args) { var pathptr = args[0]; if (pathptr !== undefined && pathptr != null) { var path = ptr(pathptr).readCString();
console.log("load
" + path); } } }); } else {
console.log("android_dlopen_ext
not found!"); }
hook到 android_dlopen_ext,但
libexecmain.so执行后进程退出,可能是libexecmain.so中创建了一个线程检测到了Frida使其退出
确认是否由libexecmain创建的检测线程
function hook_pthread_create(){
Interceptor.attach(Module.findExportByName(null,
"pthread_create"), { onEnter: function (args) { var module =
Process.findModuleByAddress(ptr(this.returnAddress))
if (module != null) {
console.log("[pthread_create]
called from",
module.name)
} else {
console.log("[pthread_create]
called from", ptr(
this.returnAddress))
} }, } ) } hook_pthread_create()
只有
libexec.so创建进程,而libexecmain.so从未出现,而libexec.so是上一个调用的,可能就是由libexec.so创建的检测线程
尝试进行patch hook能不能过掉检测
function patchPthreadCreate(){ let pthread_create =
Module.findExportByName(null,
"pthread_create") let org_pthread_create = new NativeFunction(pthread_create, "int", ["pointer", "pointer", "pointer", "pointer"]) let my_pthread_create = new NativeCallback(function (a, b, c, d) { let m =
Process.getModuleByName("libexec.so");
let base =
m.base
console.log(Process.getModuleByAddress(c).name)
if (
Process.getModuleByAddress(c).name
==
m.name)
{
console.log("pthread_create")
return 0; } return org_pthread_create(a, b, c, d) }, "int", ["pointer", "pointer", "pointer", "pointer"])
Interceptor.replace(pthread_create,
my_pthread_create) } patchPthreadCreate()
未找到
libexec.so
模块,
libexec.so
被嵌入在 APK 内
function patchPthreadCreate() { let pthread_create =
Module.findExportByName(null,
"pthread_create"); if (!pthread_create) {
console.log("Error:
Unable to find pthread_create!"); return; } let org_pthread_create = new NativeFunction(pthread_create, "int", ["pointer", "pointer", "pointer", "pointer"]); let my_pthread_create = new NativeCallback(function (a, b, c, d) { let moduleFound = false; let modulePath = ""; let modules =
Process.enumerateModules();
for (let m of modules) { if (
m.name.includes("libexec.so"))
{ // 兼容不同路径的
libexec.so
console.log("Found
libexec.so
at: " +
m.path);
moduleFound = true; modulePath =
m.path;
break; } } if (!moduleFound) {
console.log("Error:
libexec.so
not found in the loaded modules!"); return org_pthread_create(a, b, c, d); } let moduleName =
Process.getModuleByAddress(c)?.name;
console.log("pthread_create
called from: " + moduleName); if (moduleName &&
moduleName.includes("libexec.so"))
{
console.log("Blocking
pthread_create from
libexec.so");
return 0; } return org_pthread_create(a, b, c, d); }, "int", ["pointer", "pointer", "pointer", "pointer"]);
Interceptor.replace(pthread_create,
my_pthread_create);
console.log("Successfully
patched pthread_create!"); } patchPthreadCreate();
先是报错未找到
libexec.so
模块,后又存在该模块,那么反调试进程可能存在延迟加载
Patch 所有调用 pthread_create 函数的caller不太行,可能是检测了pthread_create 是否被hook,那么就需要自己实现一个 pthread_create 函数,并让应用调用,避开对 pthread_create 的完整性检查
通过拦截 pthread_create 特定偏移量的线程执行,替换特定偏移量到自建的 pthread_create 函数,来防止在hook时检测机制生效,从而绕过检测
Hook pthread_create获取属于
libexec.so线程函数的偏移量
function hook_pthread() { var pthread_create_addr =
Module.findExportByName(null,
'pthread_create');
console.log("pthread_create_addr,",
pthread_create_addr); var pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
Interceptor.replace(pthread_create_addr,
new NativeCallback(function (parg0, parg1, parg2, parg3) { var so_name =
Process.findModuleByAddress(parg2).name;
var so_path =
Process.findModuleByAddress(parg2).path;
var so_base =
Module.getBaseAddress(so_name);
var offset = parg2 - so_base;
console.log("so_name",
so_name, "offset", offset, "path", so_path, "parg2", parg2); var PC = 0; if ((
so_name.indexOf("libexec.so")
> -1)) {
console.log("find
thread func offset", so_name, offset); if ((1 === offset)) {
console.log("anti
bypass"); } else if (1 === offset) {
console.log("anti
bypass"); } else if (1 === offset) {
console.log("anti
bypass"); } else if (1 === offset) {
console.log("anti
bypass"); } else if (1 === offset) {
console.log("anti
bypass"); } else if (1 === offset) {
console.log("anti
bypass"); } else if (1 === offset) {
console.log("anti
bypass"); } else { PC = pthread_create(parg0, parg1, parg2, parg3);
console.log("ordinary
sequence", PC) } } else { PC = pthread_create(parg0, parg1, parg2, parg3); //
console.log("ordinary
sequence", PC) } return PC; }, "int", ["pointer", "pointer", "pointer", "pointer"])) } hook_pthread();
自建pthread_create,将代码中的判断语句中(1 === offset)的1全部替换成获取到的属于
libexec.so线程函数的偏移量
但仅仅获取了一个
libexec.so偏移量就中断了
由于
libexec.so
的加载具有延迟性,就需要实时监视
libexec.so
是否被动态加载,再运行 pthread_create 钩子
function enumerateModules() {
console.log("Enumerating
modules..."); const modules =
Process.enumerateModules();
modules.forEach(m
=> { if (
m.name.includes("libexec.so"))
{
console.log(`Found
module: ${
m.name}
at ${
m.base}
- ${
m.path}`);
} }); return
modules.some(m
=>
m.name
=== "
libexec.so");
} function hook_dlopen() { const dlopen =
Module.findExportByName(null,
"dlopen") ||
Module.findExportByName(null,
"__loader_dlopen"); if (!dlopen) {
console.log("Failed
to find dlopen"); return; }
Interceptor.attach(dlopen,
{ onEnter(args) { const path = args[0].readUtf8String();
console.log("dlopen
called for:", path); if (path &&
path.includes("libexec.so"))
{
this.isLibexec
= true; } }, onLeave(retval) { if (
this.isLibexec
&& retval) {
console.log("libexec.so
loaded at:", retval); setupPthreadHook(); } } }); } function setupPthreadHook() { const pthread_create_addr =
Module.findExportByName(null,
'pthread_create'); if (!pthread_create_addr) {
console.log("Failed
to find pthread_create"); return; }
console.log("pthread_create_addr:",
pthread_create_addr); const pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]); const targetOffset = 274972;
Interceptor.replace(pthread_create_addr,
new NativeCallback( function(parg0, parg1, parg2, parg3) { try { const module =
Process.findModuleByAddress(parg2)
|| {name: "unknown", base: 0}; const so_name =
module.name;
const offset =
module.base
? ptr(parg2).sub(
module.base)
: 0;
console.log("so_name:",
so_name, "offset:", offset); if (so_name === "
libexec.so")
{
console.log("Found
libexec.so
thread func offset:", offset); if (
offset.equals(targetOffset))
{
console.log("Anti-detection
triggered - bypassing"); return 0; } } return pthread_create(parg0, parg1, parg2, parg3); } catch (e) {
console.log("Pthread
hook error:", e); return pthread_create(parg0, parg1, parg2, parg3); } }, "int", ["pointer", "pointer", "pointer", "pointer"]));
console.log("Pthread
hook installed successfully"); } function main() {
console.log("Initializing...");
// First check if
libexec.so
is already loaded if (enumerateModules()) {
console.log("libexec.so
already loaded, setting up hook..."); setupPthreadHook(); } else {
console.log("libexec.so
not found initially, hooking dlopen..."); hook_dlopen(); // Fallback: keep checking periodically let attempts = 0; const maxAttempts = 50; const interval = setInterval(() => { if (enumerateModules()) { clearInterval(interval); setupPthreadHook(); } else if (attempts >= maxAttempts) { clearInterval(interval);
console.log("Gave
up waiting for
libexec.so");
} attempts++; }, 100); } } try { main(); } catch (e) {
console.log("Main
execution error:", e); }
绕过
libexec.so检测后,在另一个
dlopen 调用(
libsotweak.so)后又中断,可能存在多层反调试机制
实践二:阻止反调试库加载
阻止反调试 .so 的加载绕过检测,hook android_dlopen_ext,监控库加载,如果通过.so文件检测 hook,可以阻止其加载,绕过安全检查,尝试不可行
参考:
https://www.cnblogs.com/dxmao/articles/17678351.html
分析出创建检测线程的so文件,hook pthread_create 的偏移量为空函数来绕过检测,尝试不可行
Hook mprotect 提取所有内存数据
由于反调试检测线程的
libexec.bin库文件在程序启动后加载,具有延迟性,而mprotect又是在程序启动时就加载,所以可以在反调试生效前,hook
mprotect提取加载时执行的所有代码
拦截 mprotect 调用,检查内存权限更改,并强制将某些内存区域设置为 rwx,然后尝试进行内存转储,提取所有执行的代码,其中包括了解密后的dex文件
var mprotect =
Module.findExportByName(null,
"mprotect"); if (mprotect) {
Interceptor.attach(mprotect,
{ onEnter: function (args) {
this.addr
= ptr(args[0].toString());
this.size
= args[1].toInt32();
this.prot
= args[2].toInt32(); if (
this.prot
=== 1 ||
this.prot
=== 3 ||
this.prot
=== 7) {
console.log(`mprotect
called: ${
this.addr.toString(16)},
size: ${
this.size},
prot: ${
this.prot}`);
} }, onLeave: function (retval) { if (
retval.toInt32()
=== 0) {
Memory.protect(this.addr,
this.size,
"rwx");
console.log(`Memory
protection patched at ${
this.addr.toString(16)},
size: ${
this.size}`);
var header =
Memory.readByteArray(this.addr,
Math.min(8,
this.size));
var headerBytes = new Uint8Array(header); var headerHex =
Array.from(headerBytes).map(b
=>
b.toString(16).padStart(2,
'0')).join(' ');
console.log(`Header
check: ${headerHex}`); if (
this.size
> 4096) {
console.log(`Dumping
memory region at ${
this.addr.toString(16)}`);
var data =
Memory.readByteArray(this.addr,
this.size);
var fileName = `/data/data/
com.oceanwing.battery.cam/dump_${this.addr.toString(16)}_${this.size}.bin`;
try { var file = new File(fileName, "wb");
file.write(data);
file.close();
console.log(`Saved
to ${fileName}`); } catch (e) {
console.error(`Failed
to save: ${
e.message}`);
console.log("Dumping
first 256 bytes:");
console.log(hexdump(this.addr,
{ length:
Math.min(this.size,
256) })); } } } } }); }
同样从内存提取数据并绕过保护,但没有frida-dexdump针对性的提取dex文件,该脚本 Dump 了所有被 mprotect 标记为可执行的代码段,其中可能包括 Dex 代码、so 库代码等,然后手动逐一分析提取的 bin 文件
解析bin文件,手动提取dex文件,反编译分析dex文件,发现不完整
frida联合gdb动调,结合Frida的Hook,实时获取报错问题
adb shell ps -A | grep
com.oceanwing.battery.cam
# 获取 sPID gdbserver64 :1234 --attach adb forward tcp:1234 tcp:1234 gdb target remote :1234
最终分析:
该脚本使用 Frida Hook 关键系统函数和 Java 方法,以绕过反调试机制、监控动态库加载、拦截进程退出、篡改时间检测、提取 DEX 代码并保持进程存活
在JNI_OnLoad中,原生代码解密这些数据,并通过DexClassLoader动态加载到内存中,所以它可能是应用加载额外DEX文件的触发点,hook它可能会获取到关键的DEX解密数据,但目前程序并未执行到JNI_OnLoad函数就中断了
提取出的解密数据并不是主要业务代码,同时也提出一堆加密的内存数据
通过Frida Hook和内存提取,成功绕过了部分反调试机制,提取了部分DEX文件,但无济于事,针对新版爱加密加固,还是需要虚拟机脱壳
console.log("Script
loaded immediately!"); setImmediate(function () {
console.log("Starting
advanced anti-anti-debugging..."); // Hook mprotect(标记可读内存) var mprotect =
Module.findExportByName(null,
"mprotect"); if (mprotect) {
Interceptor.attach(mprotect,
{ onEnter: function (args) {
this.addr
= ptr(args[0].toString());
this.size
= args[1].toInt32();
this.prot
= args[2].toInt32(); if (
this.prot
=== 1 ||
this.prot
=== 3 ||
this.prot
=== 7) {
console.log(`mprotect
called: ${
this.addr.toString(16)},
size: ${
this.size},
prot: ${
this.prot}`);
} }, onLeave: function (retval) { if (
retval.toInt32()
=== 0 && (
this.prot
& 0x4)) {
console.log(`Memory
protection succeeded at ${
this.addr.toString(16)},
size: ${
this.size}`);
this.safeToRead
= true; } } }); } // Hook dlopen 检测
libexec.so
和
libexecmain.so
var dlopen =
Module.findExportByName(null,
"dlopen"); if (dlopen) {
Interceptor.attach(dlopen,
{ onEnter: function (args) {
this.path
= args[0].readCString();
console.warn(`dlopen
detected for ${
this.path}`);
if (
this.path
&&
this.path.includes("libsotweak.so"))
{
console.warn("Allowing
libsotweak.so
load, hooking its functions..."); } }, onLeave: function (retval) { if (
retval.toInt32()
> 0) { if (
this.path
&& (
this.path.includes("libexec.so")
||
this.path.includes("libexecmain.so")))
{
console.log(`${this.path}
loaded, initiating memory scan...`); scanMemory(); } if (
this.path
&&
this.path.includes("libsotweak.so"))
{
console.log("Scanning
memory after
libsotweak.so
load..."); scanMemory(); } } } }); } // Hook pthread_create 增加扫描 var pthread_create =
Module.findExportByName(null,
"pthread_create"); if (pthread_create) {
Interceptor.attach(pthread_create,
{ onEnter: function (args) {
console.warn("pthread_create
detected");
this.threadFunc
= args[2]; var module =
Process.findModuleByAddress(this.threadFunc)
|| { name: "unknown", base: 0 }; var offset =
module.base
? ptr(
this.threadFunc).sub(module.base)
: ptr(0);
console.log(`pthread_create
- module: ${
module.name},
offset: ${offset}`); if (
module.name
=== "
libexec.so"
&&
offset.toInt32()
=== 0x4321c) {
console.log("Anti-detection
thread detected - bypassing");
this.bypass
= true; scanMemory(); } }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Bypassing
pthread_create");
retval.replace(-1);
} else if (
retval.toInt32()
=== 0) {
console.log("pthread_create
succeeded"); } } }); } // Hook dlsym 防止触发 core 的陷阱并动态 hook JNI_OnLoad var dlsym =
Module.findExportByName(null,
"dlsym"); if (dlsym) {
Interceptor.attach(dlsym,
{ onEnter: function (args) {
this.symbol
= args[1].readCString();
console.warn(`dlsym
detected for ${
this.symbol}`);
if (
this.symbol
=== "ptrace" ||
this.symbol
=== "gettimeofday" ||
this.symbol
=== "clock_gettime" ||
this.symbol
=== "core") {
console.log(`Blocking
dlsym for ${
this.symbol}
to avoid trap`);
this.bypass
= true; } }, onLeave: function (retval) { if (
this.bypass)
{
console.log(`Bypassing
dlsym for ${
this.symbol}`);
retval.replace(ptr(0));
} // 动态 hook JNI_OnLoad if (
this.symbol
=== "JNI_OnLoad" &&
retval.isNull()
=== false) {
console.log(`Attempting
to hook JNI_OnLoad at ${
retval.toString(16)}`);
try {
Interceptor.attach(retval,
{ onEnter: function (args) {
console.log("JNI_OnLoad
called with args:");
console.log(`
vm: ${args[0]}`);
console.log(`
reserved: ${args[1]}`); scanMemory(); // 扫描内存 }, onLeave: function (retval) {
console.log(`JNI_OnLoad
returned: ${retval}`); scanMemory(); // 再次扫描 } }); } catch (e) {
console.error(`Failed
to hook JNI_OnLoad: ${
e.message}`);
} } } }); } // 定时扫描内存 setInterval(function () {
console.log("Periodic
memory scan..."); scanMemory(); }, 500); // 延迟 Java 层 hook setTimeout(function () {
Java.perform(function
() {
console.log("Initializing
Java hooks..."); var AppComponentFactoryC0012A =
Java.use("p000s.p001h.p002e.p003l.p004l.AppComponentFactoryC0012A");
if (AppComponentFactoryC0012A) { AppComponentFactoryC0012A["m43al"].implementation = function (classLoader, applicationInfo, packageName, orignAppName) {
console.log("Java
m43al called with:");
console.log(`
ClassLoader: ${classLoader}`);
console.log(`
ApplicationInfo: ${applicationInfo}`);
console.log(`
PackageName: ${packageName}`);
console.log(`
OrignAppName: ${orignAppName}`); var result = this["m43al"](classLoader, applicationInfo, packageName, orignAppName);
console.log(`Java
m43al returned ClassLoader: ${result}`); scanMemory(); return result; }; } else {
console.error("Failed
to find AppComponentFactoryC0012A"); }
Java.use("java.lang.ClassLoader").loadClass.overload('java.lang.String',
'boolean').implementation = function (className, resolve) {
console.log(`ClassLoader.loadClass
called for: ${className}`); var result =
this.loadClass(className,
resolve); return result; }; }); }, 1000); // Hook sys_exit 和 sys_exit_group var syscall =
Module.findExportByName(null,
"syscall"); if (syscall) {
Interceptor.attach(syscall,
{ onEnter: function (args) { var nr = args[0].toInt32(); if (nr === 93 || nr === 94) {
console.warn(`syscall
detected: ${nr === 93 ? "sys_exit" : "sys_exit_group"}`);
this.bypass
= true; } }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Bypassing
sys_exit/sys_exit_group");
retval.replace(0);
} } }); } // Hook kill 防止信号终止 var kill =
Module.findExportByName(null,
"kill"); if (kill) {
Interceptor.attach(kill,
{ onEnter: function (args) {
console.warn(`kill
detected! PID: ${args[0].toInt32()}, Signal: ${args[1].toInt32()}`); args[1] = ptr(0); // 禁用信号 } }); } // Hook raise 防止信号终止 var raise =
Module.findExportByName(null,
"raise"); if (raise) {
Interceptor.attach(raise,
{ onEnter: function (args) {
console.warn(`raise
detected! Signal: ${args[0].toInt32()}`); args[0] = ptr(0); // 禁用信号 } }); } // Hook pthread_join 防止线程同步退出 var pthread_join =
Module.findExportByName(null,
"pthread_join"); if (pthread_join) {
Interceptor.attach(pthread_join,
{ onEnter: function (args) {
console.warn(`pthread_join
detected! Thread: ${args[0].toString(16)}`);
this.bypass
= true; }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Bypassing
pthread_join");
retval.replace(0);
} } }); } // Hook sched_yield 防止调度检测 var sched_yield =
Module.findExportByName(null,
"sched_yield"); if (sched_yield) {
Interceptor.attach(sched_yield,
{ onEnter: function () {
console.warn("sched_yield
detected");
this.bypass
= true; }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Bypassing
sched_yield");
retval.replace(0);
} } }); } // Hook sigaction 防止信号处理 var sigaction =
Module.findExportByName(null,
"sigaction"); if (sigaction) {
Interceptor.attach(sigaction,
{ onEnter: function (args) {
console.warn(`sigaction
called with signal: ${args[0].toInt32()}`); args[1] = ptr(0); // 禁用信号处理 } }); } var prctl =
Module.findExportByName(null,
"prctl"); if (prctl) {
Interceptor.attach(prctl,
{ onEnter: function (args) {
console.warn(`prctl
detected (bypassing)! Option: ${args[0].toInt32()}`);
this.skip
= true; }, onLeave: function (retval) { if (
this.skip)
{
retval.replace(0);
} } }); } var ptrace =
Module.findExportByName(null,
"ptrace"); if (ptrace) {
Interceptor.attach(ptrace,
{ onEnter: function (args) {
console.warn(`ptrace
detected! Request: ${args[0].toInt32()}`);
this.bypass
= true; }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Bypassing
ptrace");
retval.replace(-1);
} } }); } var fopen =
Module.findExportByName(null,
"fopen"); if (fopen) {
Interceptor.attach(fopen,
{ onEnter: function (args) { var path = args[0].readCString(); if (path && (
path.includes("/proc")
혹은
path.includes("/sys")
||
path.includes("frida")))
{
console.warn(`fopen
detected for ${path}, redirecting to /dev/null`); args[0] =
Memory.allocUtf8String("/dev/null");
} } }); } var gettimeofday =
Module.findExportByName(null,
"gettimeofday"); if (gettimeofday) {
Interceptor.attach(gettimeofday,
{ onEnter: function (args) {
console.warn("gettimeofday
detected");
this.tv
= args[0]; }, onLeave: function (retval) { if (
retval.toInt32()
=== 0 &&
this.tv)
{ var baseTime =
Date.now()
/ 1000; var currentTime =
Math.floor(baseTime
+ (
Date.now()
- baseTime * 1000) / 1000);
Memory.writeLong(this.tv,
currentTime);
Memory.writeLong(this.tv.add(8),
0); } } }); } var clock_gettime =
Module.findExportByName(null,
"clock_gettime"); if (clock_gettime) {
Interceptor.attach(clock_gettime,
{ onEnter: function (args) {
console.warn("clock_gettime
detected");
this.ts
= args[1]; }, onLeave: function (retval) { if (
retval.toInt32()
=== 0 &&
this.ts)
{ var baseTime =
Date.now()
/ 1000; var currentTime =
Math.floor(baseTime
+ (
Date.now()
- baseTime * 1000) / 1000);
Memory.writeLong(this.ts,
currentTime);
Memory.writeLong(this.ts.add(8),
0); } } }); } var exit =
Module.findExportByName(null,
"exit"); if (exit) {
Interceptor.attach(exit,
{ onEnter: function (args) {
console.warn(`exit
detected with status: ${args[0].toInt32()}`);
this.bypass
= true; }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Preventing
exit"); throw new Error("Blocked exit"); } } }); } var _exit =
Module.findExportByName(null,
"_exit"); if (_exit) {
Interceptor.attach(_exit,
{ onEnter: function (args) {
console.warn(`_exit
detected with status: ${args[0].toInt32()}`);
this.bypass
= true; }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Preventing
_exit"); throw new Error("Blocked _exit"); } } }); } var abort =
Module.findExportByName(null,
"abort"); if (abort) {
Interceptor.attach(abort,
{ onEnter: function () {
console.warn("abort
detected");
this.bypass
= true; }, onLeave: function (retval) { if (
this.bypass)
{
console.log("Preventing
abort"); throw new Error("Blocked abort"); } } }); } // Exception handler with stack trace
Process.setExceptionHandler(function
(details) {
console.log("Exception
caught:",
JSON.stringify(details,
null, 2));
console.log("Stack:",
Thread.backtrace(details.context,
Backtracer.ACCURATE)
.map(
DebugSymbol.fromAddress).join("\n"));
return true; // 继续运行 }); // Keep process alive setInterval(function () {
console.log("Keeping
process alive..."); }, 5000);
console.log("Advanced
anti-anti-debugging setup complete!"); }); // 内存扫描函数 function scanMemory() {
console.log("Scanning
memory...");
Process.enumerateRanges('r-x').forEach(range
=> { if (
range.size
> 1024 * 100) { try { var header =
Memory.readByteArray(range.base,
8); var headerBytes = new Uint8Array(header); var headerHex =
Array.from(headerBytes).map(b
=>
b.toString(16).padStart(2,
'0')).join(' '); var dexMagic = "64 65 78 0A 30 33 35 00"; // dex\n035\0 var isDex = headerHex === dexMagic; if (isDex) {
console.log(`DEX
detected at ${
range.base.toString(16)},
size: ${
range.size}`);
var fileName = `/data/data/
com.oceanwing.battery.cam/dump_${range.base.toString(16)}_unencrypted.dex`;
var data =
Memory.readByteArray(range.base,
Math.min(range.size,
1024 * 1024)); var file = new File(fileName, "wb");
file.write(data);
file.close();
console.log(`Dumped
unencrypted DEX to ${fileName}`); } else if (
range.size
> 4096) {
console.log(`Potential
encrypted data at ${
range.base.toString(16)},
size: ${
range.size}`);
var fileName = `/data/data/
com.oceanwing.battery.cam/damp_${range.base.toString(16)}_encrypted.bin`;
var data =
Memory.readByteArray(range.base,
Math.min(range.size,
1024 * 1024)); var file = new File(fileName, "wb");
file.write(data);
file.close();
console.log(`Dumped
encrypted data to ${fileName}`); } } catch (e) {
console.error(`Memory
scan error at ${
range.base.toString(16)}:
${
e.message}`);
} } }); }
https://www.freebuf.com/articles/sectool/428181.html
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论