fumo:ffi
fumo:ffi provides intentionally unsafe Win64 native access.
It is available only when:
- Settings → Script Engine → Insecure scripting is enabled.
- The package manifest includes the
fficapability. - The package is reloaded after the setting changes.
import { ffi, NativeType } from "fumo:ffi";
Native types
const NativeType = {
void: "void",
bool: "bool",
int8: "int8",
uint8: "uint8",
int16: "int16",
uint16: "uint16",
int32: "int32",
uint32: "uint32",
int64: "int64",
uint64: "uint64",
pointer: "pointer",
cstring: "cstring",
float32: "float32",
float64: "float64"
};
float32 and float64 are currently supported by read and write, not
by bound function signatures. Bound calls accept at most eight integer,
pointer, or C-string arguments.
Loading and binding
const kernel32 = ffi.openModule("kernel32.dll");
const getCurrentProcessId = kernel32.bind("GetCurrentProcessId", {
abi: "win64",
returns: NativeType.uint32,
args: []
});
console.log("PID", getCurrentProcessId());
ffi.module(name) is an alias for ffi.openModule(name). Existing modules
are reused through GetModuleHandle; otherwise the engine calls
LoadLibrary.
An opened module has:
interface NativeModule {
readonly name: string;
readonly base: bigint;
bind(name: string, signature?: NativeSignature): NativeFunction;
}
interface NativeSignature {
abi?: "win64";
returns?: NativeType;
args?: NativeType[];
}
Pointer and 64-bit return values are JavaScript bigint values. Native calls
are surrounded by a Windows exception boundary, but not every native failure
is recoverable.
Allocating memory
const block = ffi.alloc(64);
try {
ffi.write(block, NativeType.uint32, 0x12345678);
console.log(ffi.read(block, NativeType.uint32));
} finally {
ffi.free(block);
}
alloc uses read/write VirtualAlloc pages. Package-owned allocations are
released automatically when the package unloads. free accepts only an
address returned by that package’s ffi.alloc.
Reading and writing memory
ffi.read(address: bigint, type: NativeType, maxLength?: number): unknown;
ffi.write(address: bigint, type: NativeType, value: unknown): void;
read and write accept arbitrary process addresses. cstring reads stop
at the first null byte and default to a 4 KiB maximum. The optional maximum
is clamped to 1 MiB. C-string writes are not currently supported.
Invalid memory accesses normally throw a JavaScript error containing the Windows exception code.
Warning
Signatures are not verified. Calling an address with the wrong argument or return types can corrupt registers, the stack, heap state, or game state. Only enable insecure mode for code you fully trust.