Skip to content

Commit

Permalink
Changes to add metadata to corpse
Browse files Browse the repository at this point in the history
  • Loading branch information
Your Name committed Nov 19, 2024
1 parent cbccd56 commit 7790038
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
frida-cshell.js
frida-cshell
src/version.ts
core
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frida-cshell",
"version": "1.7.8",
"version": "1.7.9",
"description": "Frida's CShell",
"scripts": {
"prepare": "npm run version && npm run build && npm run package && npm run copy",
Expand Down
86 changes: 86 additions & 0 deletions src/cmdlets/misc/corpse/corpse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import { Dumpable } from './dumpable.js';
import { Proc } from './proc.js';
import { Rlimit } from './rlimit.js';
import { SeLinux } from './selinux.js';
import { Mem, MemProtection } from './mem.js';
import { APP_VERSION, GIT_COMMIT_HASH } from '../../../version.js';
import { Overlay } from '../../../memory/overlay.js';
import { Regs } from '../../../breakpoints/regs.js';
import { Vars } from '../../../vars/vars.js';

export class CorpseCmdLet extends CmdLetBase {
name = 'corpse';
Expand All @@ -28,6 +33,7 @@ corpse - create a corpse file`;
private dumpable: Dumpable | null = null;
private clone: Fork | null = null;
private proc: Proc | null = null;
private mem: Mem | null = null;

public runSync(tokens: Token[]): Var {
if (tokens.length != 0) return this.usage();
Expand Down Expand Up @@ -126,6 +132,13 @@ corpse - create a corpse file`;
debug(`Restoring default signal action using rt_sigaction`);
proc.rt_sigaction(Proc.SIGABRT, Proc.SIG_DFL);

for (const overlay of Overlay.all()) {
debug(`Reverting overlay: ${overlay.toString()}`);
overlay.revert();
}

this.writeMetadata(debug);

debug(`Suicide`);
proc.kill(pid, Proc.SIGABRT);
} catch (error) {
Expand All @@ -141,6 +154,78 @@ corpse - create a corpse file`;
}
}

private writeMetadata(debug: (msg: string) => void) {
const magicLen = 8;
/* 43 4f 52 50 53 45 20 33 |CORPSE 3| */
const magics: [Uint8Array, Uint8Array] = [
new Uint8Array([0xde, 0xad, 0xfa, 0xce, 0xde, 0xad, 0xfa, 0xce]),
new Uint8Array([0x9d, 0xe2, 0xa8, 0x9e, 0x8d, 0xe8, 0xda, 0xfd]),
];
const ranges = Process.enumerateRanges('---').map(r => {
return {
base: `0x${r.base.toString(16)}`,
size: r.size,
protection: r.protection,
file_path: r.file?.path ?? null,
file_offset: r.file?.offset ?? null,
file_size: r.file?.size ?? null,
};
});
const modules = Process.enumerateModules().map(m => {
return {
name: m.name,
base: `0x${m.base.toString(16)}`,
size: m.size,
path: m.path,
};
});
const regs = Regs.all().map(([name, value]) => {
return {
name: name,
addr: value.toPointer(),
value: value.getLiteral(),
};
});
const vars = Vars.all().map(([name, value]) => {
return {
name: name,
addr: value.toPointer(),
value: value.getLiteral(),
};
});
const metatdata = {
version: APP_VERSION,
hash: GIT_COMMIT_HASH,
ranges,
modules,
regs,
vars,
};

const data = JSON.stringify(metatdata, null, 2);
debug(`data: ${data}`);
debug(`metadata size: ${Format.toSize(data.length)}`);

const alignedSize = Mem.pageAlign(magicLen + data.length);
const totalSize = Process.pageSize * 2 + alignedSize;
const mem = this.mem as Mem;
const buffer = mem.map_anonymous(totalSize);
mem.protect(buffer, Process.pageSize, MemProtection.PROT_NONE);
mem.protect(
buffer.add(Process.pageSize + alignedSize),
Process.pageSize,
MemProtection.PROT_NONE,
);
let cursor = buffer.add(Process.pageSize);
for (let i = 0; i < magicLen; i++) {
const x = magics[0][i] as number;
const y = magics[1][i] as number;
cursor.writeU8(x ^ y);
cursor = cursor.add(1);
}
cursor.writeUtf8String(data);
}

private checkCorpse(corePattern: string, pid: number) {
const corePath = CorePattern.appendPid()
? `${corePattern}.${pid}`
Expand Down Expand Up @@ -208,6 +293,7 @@ corpse - create a corpse file`;
this.dumpable = new Dumpable();
this.clone = new Fork();
this.proc = new Proc();
this.mem = new Mem();
} catch {
return false;
}
Expand Down
78 changes: 78 additions & 0 deletions src/cmdlets/misc/corpse/mem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
export enum MemProtection {
PROT_NONE = 0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
PROT_READ_WRITE = PROT_READ | PROT_WRITE,
}

export class Mem {
private static readonly MAP_PRIVATE: number = 0x2;
private static readonly MAP_ANONYMOUS: number = 0x20;

private static readonly MAP_FAILED: NativePointer = ptr(-1);

/* void *mmap(void addr[.length], size_t length, int prot, int flags,
int fd, off_t offset); */
private fnMmap: SystemFunction<
NativePointer,
[NativePointer, number | UInt64, number, number, number, number | UInt64]
>;

/* int mprotect(void addr[.len], size_t len, int prot); */
private fnMprotect: SystemFunction<
number,
[NativePointer, number | UInt64, number]
>;

public constructor() {
const pMmap = Module.findExportByName(null, 'mmap');
if (pMmap === null) throw new Error('failed to find mmap');

this.fnMmap = new SystemFunction(pMmap, 'pointer', [
'pointer',
'size_t',
'int',
'int',
'int',
'size_t',
]);

const pMprotect = Module.findExportByName(null, 'mprotect');
if (pMprotect === null) throw new Error('failed to find mprotect');

this.fnMprotect = new SystemFunction(pMprotect, 'int', [
'pointer',
'size_t',
'int',
]);
}

public map_anonymous(size: number): NativePointer {
const ret = this.fnMmap(
ptr(0),
size,
MemProtection.PROT_READ | MemProtection.PROT_WRITE,
Mem.MAP_ANONYMOUS | Mem.MAP_PRIVATE,
-1,
0,
) as UnixSystemFunctionResult<NativePointer>;
if (ret.value.equals(Mem.MAP_FAILED))
throw new Error(`failed to mmap, errno: ${ret.errno}`);
return ret.value;
}

public protect(addr: NativePointer, size: number, prot: MemProtection) {
const ret = this.fnMprotect(
addr,
size,
prot,
) as UnixSystemFunctionResult<number>;
if (ret.value === -1)
throw new Error(`failed to mprotect, errno: ${ret.errno}`);
}

public static pageAlign(size: number): number {
const mask = Process.pageSize - 1;
return (size + mask) & ~mask;
}
}
2 changes: 1 addition & 1 deletion src/memory/mem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class Mem {
}
}

private static modifyMemory(address: NativePointer, data: Uint8Array) {
public static modifyMemory(address: NativePointer, data: Uint8Array) {
const alignStart = this.pageAlignDown(address);
const alignEnd = this.pageAlignUp(address.add(data.length));
const pageShift = Math.log2(Process.pageSize);
Expand Down
12 changes: 12 additions & 0 deletions src/memory/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,16 @@ export class Overlay {
if (this.address.compare(addr.add(length)) >= 0) return false;
return true;
}

public static all(): Overlay[] {
return Overlay.overlays.map(([_, overlay]) => overlay);
}

public revert() {
Mem.modifyMemory(this.address, this.data);
}

public toString(): string {
return `addr: ${this.address}, length: ${this.data.length}`;
}
}

0 comments on commit 7790038

Please sign in to comment.