Identify a process instance by a deterministic identity returned from the agent (per-OS, with a Process.mainModule + pid fallback) and stash it on ProcessSession.processInfo. Rekey memory_page into memory_page_module (module UUID + offset) so cached bytes survive ASLR, and memory_page_anon (process identity + address) for JIT / heap regions that only survive within one process instance. Purge stale anon pages on every fresh attach. Add updateProcessInfo, updateModuleAnalysis and updateInsight SessionOps plus a side-channel publish-memory-page op and a +fetch-memory-page request. The driver write-throughs every page it fetches; non-drivers pull on miss and persist locally. Module-analysis rows flow the same way so non-drivers can key their cache by module UUID. The lab-join snapshot now carries processInfo and module_analyses too. Refresh actions on the insight detail view: Reread Bytes drops the pages overlapping the visible range; Reanalyze Module drops the module's analysis and pages, re-running r2 on next access. The macOS detail view now reads the insight live from insightsBySession via observation; GTK forwards .insightUpdated into the detail and reschedules a refresh when the resolved address changes.
121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
export interface ProcessInfo {
|
|
platform: Platform;
|
|
arch: Architecture;
|
|
pointerSize: number;
|
|
mainModule: ModuleInfo;
|
|
identity: string;
|
|
}
|
|
|
|
export interface ModuleInfo {
|
|
name: string;
|
|
path: string;
|
|
base: string;
|
|
size: number;
|
|
}
|
|
|
|
export function getProcessInfo(): ProcessInfo {
|
|
const main = Process.mainModule;
|
|
return {
|
|
platform: Process.platform,
|
|
arch: Process.arch,
|
|
pointerSize: Process.pointerSize,
|
|
mainModule: {
|
|
name: main.name,
|
|
path: main.path,
|
|
base: main.base.toString(),
|
|
size: main.size,
|
|
},
|
|
identity: computeProcessIdentity(),
|
|
};
|
|
}
|
|
|
|
function computeProcessIdentity(): string {
|
|
const source = osSpecificIdentitySource() ?? fallbackIdentitySource();
|
|
const sum = new Checksum("sha256");
|
|
sum.update(source);
|
|
return sum.getString().slice(0, 16);
|
|
}
|
|
|
|
function osSpecificIdentitySource(): string | null {
|
|
try {
|
|
switch (Process.platform) {
|
|
case "linux": return linuxIdentitySource();
|
|
case "darwin": return darwinIdentitySource();
|
|
case "windows": return windowsIdentitySource();
|
|
default: return null;
|
|
}
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function fallbackIdentitySource(): string {
|
|
return `mainbase=${Process.mainModule.base.toString()};pid=${Process.id}`;
|
|
}
|
|
|
|
function linuxIdentitySource(): string {
|
|
const bootID = File.readAllText("/proc/sys/kernel/random/boot_id").trim();
|
|
const stat = File.readAllText("/proc/self/stat");
|
|
const afterComm = stat.slice(stat.lastIndexOf(")") + 1).trim().split(/\s+/);
|
|
const startTimeJiffies = afterComm[19];
|
|
return `boot=${bootID};start=${startTimeJiffies};pid=${Process.id}`;
|
|
}
|
|
|
|
function darwinIdentitySource(): string {
|
|
const sysctl: SysctlFunction = new NativeFunction(
|
|
Module.getGlobalExportByName("sysctl"),
|
|
"int",
|
|
["pointer", "uint", "pointer", "pointer", "pointer", "size_t"]
|
|
);
|
|
return `boot=${darwinBootTime(sysctl)};start=${darwinProcStartTime(sysctl)};pid=${Process.id}`;
|
|
}
|
|
|
|
function darwinBootTime(sysctl: SysctlFunction): string {
|
|
const mib = Memory.alloc(8);
|
|
mib.writeU32(CTL_KERN); mib.add(4).writeU32(KERN_BOOTTIME);
|
|
return readSysctlTimeval(sysctl, mib, 2);
|
|
}
|
|
|
|
function darwinProcStartTime(sysctl: SysctlFunction): string {
|
|
const mib = Memory.alloc(16);
|
|
mib.writeU32(CTL_KERN);
|
|
mib.add(4).writeU32(KERN_PROC);
|
|
mib.add(8).writeU32(KERN_PROC_PID);
|
|
mib.add(12).writeU32(Process.id);
|
|
return readSysctlTimeval(sysctl, mib, 4);
|
|
}
|
|
|
|
function readSysctlTimeval(sysctl: SysctlFunction, mib: NativePointer, mibCount: number): string {
|
|
const buf = Memory.alloc(16);
|
|
const len = Memory.alloc(Process.pointerSize);
|
|
len.writeULong(16);
|
|
sysctl(mib, mibCount, buf, len, NULL, 0);
|
|
const sec = buf.readS64();
|
|
const usec = buf.add(8).readS32();
|
|
return `${sec}.${usec}`;
|
|
}
|
|
|
|
type SysctlFunction = NativeFunction<number, [NativePointer, number, NativePointer, NativePointer, NativePointer, number]>;
|
|
|
|
function windowsIdentitySource(): string {
|
|
const getProcessTimes = new NativeFunction(
|
|
Module.getGlobalExportByName("GetProcessTimes"),
|
|
"int32",
|
|
["pointer", "pointer", "pointer", "pointer", "pointer"]
|
|
);
|
|
const buf = Memory.alloc(32);
|
|
getProcessTimes(WINDOWS_CURRENT_PROCESS, buf, buf.add(8), buf.add(16), buf.add(24));
|
|
const low = buf.readU32();
|
|
const high = buf.add(4).readU32();
|
|
return `create=${high}.${low};pid=${Process.id}`;
|
|
}
|
|
|
|
const WINDOWS_CURRENT_PROCESS = ptr(-1);
|
|
|
|
const CTL_KERN = 1;
|
|
const KERN_PROC = 14;
|
|
const KERN_BOOTTIME = 21;
|
|
const KERN_PROC_PID = 1;
|
|
const NULL = ptr(0);
|
|
|