mirror of
https://github.com/QM4RS/FridaBox.git
synced 2026-09-30 21:12:09 +02:00
feat: deliver first successful FridaBox MVP
Integrate Frida Gadget into BlackBox guest startup, add the host workflow and controller tooling, and validate the complete sample hook flow on ARM64 Android 16.
This commit is contained in:
Vendored
+1887
File diff suppressed because one or more lines are too long
Vendored
+1887
File diff suppressed because one or more lines are too long
Vendored
+1887
File diff suppressed because one or more lines are too long
@@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
import Java from 'frida-java-bridge';
|
||||
|
||||
const REGISTRY = 'top.niunaijun.blackbox.instrumentation.GuestRuntimeRegistry';
|
||||
const MAX_ATTEMPTS = 40;
|
||||
const RETRY_MS = 250;
|
||||
let registry = null;
|
||||
let guestLoader = null;
|
||||
|
||||
function findRegistry() {
|
||||
try {
|
||||
return Java.use(REGISTRY);
|
||||
} catch (_) {
|
||||
let found = null;
|
||||
Java.enumerateClassLoaders({
|
||||
onMatch(loader) {
|
||||
if (found !== null) return;
|
||||
try {
|
||||
loader.loadClass(REGISTRY);
|
||||
const factory = Java.ClassFactory.get(loader);
|
||||
found = factory.use(REGISTRY);
|
||||
} catch (_) {}
|
||||
},
|
||||
onComplete() {}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
function bootstrap(attempt) {
|
||||
Java.perform(() => {
|
||||
registry = findRegistry();
|
||||
if (registry !== null) {
|
||||
guestLoader = registry.getGuestClassLoader();
|
||||
if (guestLoader !== null) {
|
||||
Java.classFactory.loader = guestLoader;
|
||||
console.log('[FridaBox] package=' + registry.getGuestPackageName());
|
||||
console.log('[FridaBox] process=' + registry.getGuestProcessName());
|
||||
console.log('[FridaBox] userId=' + registry.getGuestUserId());
|
||||
console.log('[FridaBox] virtualProcessId=' + registry.getVirtualProcessId());
|
||||
console.log('[FridaBox] source=' + registry.getGuestSourceDir());
|
||||
console.log('[FridaBox] ClassLoader=' + guestLoader.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (attempt + 1 < MAX_ATTEMPTS) {
|
||||
setTimeout(() => bootstrap(attempt + 1), RETRY_MS);
|
||||
} else {
|
||||
console.error('[FridaBox] guest ClassLoader unavailable after ' + (MAX_ATTEMPTS * RETRY_MS) + ' ms');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bootstrap(0);
|
||||
|
||||
rpc.exports = {
|
||||
info() {
|
||||
return Java.performNow(() => registry === null ? { error: 'registry unavailable' } : JSON.parse(registry.describe()));
|
||||
},
|
||||
useclass(className) {
|
||||
return Java.performNow(() => {
|
||||
if (guestLoader === null) throw new Error('guest ClassLoader is not ready');
|
||||
Java.classFactory.loader = guestLoader;
|
||||
return Java.use(className).$className;
|
||||
});
|
||||
},
|
||||
enumerateloadedclasses(prefix) {
|
||||
const match = prefix || '';
|
||||
return Java.performNow(() => Java.enumerateLoadedClassesSync().filter(name => name.indexOf(match) === 0));
|
||||
},
|
||||
enumeratemodules() {
|
||||
return Process.enumerateModules().map(module => ({ name: module.name, base: module.base.toString(), path: module.path }));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
const seen = new Set();
|
||||
|
||||
function report(module) {
|
||||
if (seen.has(module.path)) return;
|
||||
seen.add(module.path);
|
||||
console.log('[native-load] ' + module.name + ' base=' + module.base + ' path=' + module.path);
|
||||
if (typeof globalThis.onGuestModuleLoaded === 'function') {
|
||||
try { globalThis.onGuestModuleLoaded(module); } catch (error) { console.error(error.stack || error); }
|
||||
}
|
||||
}
|
||||
|
||||
Process.enumerateModules().forEach(report);
|
||||
Process.attachModuleObserver({ onAdded: report, onRemoved() {} });
|
||||
|
||||
['dlopen', 'android_dlopen_ext'].forEach(name => {
|
||||
const address = Module.findGlobalExportByName(name);
|
||||
if (address === null) return;
|
||||
Interceptor.attach(address, {
|
||||
onEnter(args) { this.path = args[0].isNull() ? null : args[0].readCString(); },
|
||||
onLeave(result) {
|
||||
if (this.path !== null) console.log('[' + name + '] ' + this.path + ' => ' + result);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
import Java from 'frida-java-bridge';
|
||||
|
||||
Java.performNow(function () {
|
||||
try {
|
||||
const name = 'top.niunaijun.blackbox.instrumentation.GuestRuntimeRegistry';
|
||||
let Registry = null;
|
||||
try {
|
||||
Registry = Java.use(name);
|
||||
} catch (_) {
|
||||
Java.enumerateClassLoaders({
|
||||
onMatch(loader) {
|
||||
if (Registry !== null) return;
|
||||
try {
|
||||
loader.loadClass(name);
|
||||
Registry = Java.ClassFactory.get(loader).use(name);
|
||||
} catch (_) {}
|
||||
},
|
||||
onComplete() {}
|
||||
});
|
||||
}
|
||||
if (Registry === null) throw new Error('GuestRuntimeRegistry ClassLoader was not found');
|
||||
send({kind: 'fridabox-registry', value: Registry.describe()});
|
||||
} catch (error) {
|
||||
send({kind: 'fridabox-error', value: String(error.stack || error)});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
import Java from 'frida-java-bridge';
|
||||
|
||||
Java.perform(() => {
|
||||
const registryName = 'top.niunaijun.blackbox.instrumentation.GuestRuntimeRegistry';
|
||||
let Registry = null;
|
||||
try {
|
||||
Registry = Java.use(registryName);
|
||||
} catch (_) {
|
||||
Java.enumerateClassLoaders({
|
||||
onMatch(loader) {
|
||||
if (Registry !== null) return;
|
||||
try {
|
||||
loader.loadClass(registryName);
|
||||
Registry = Java.ClassFactory.get(loader).use(registryName);
|
||||
} catch (_) {}
|
||||
},
|
||||
onComplete() {}
|
||||
});
|
||||
}
|
||||
if (Registry === null) throw new Error('GuestRuntimeRegistry ClassLoader was not found');
|
||||
const loader = Registry.getGuestClassLoader();
|
||||
if (loader === null) throw new Error('GuestRuntimeRegistry has no guest ClassLoader');
|
||||
Java.classFactory.loader = loader;
|
||||
const Target = Java.use('com.qm4rs.fridabox.sample.Target');
|
||||
const add = Target.add.overload('int', 'int');
|
||||
add.implementation = function (a, b) {
|
||||
console.log('[sample-hook] Target.add(' + a + ', ' + b + ') => 1337');
|
||||
return 1337;
|
||||
};
|
||||
console.log('[sample-hook] installed for ' + Registry.getGuestPackageName());
|
||||
});
|
||||
Reference in New Issue
Block a user