From ec742759d4b59152215fc8e58b42dfebb92dcec2 Mon Sep 17 00:00:00 2001 From: Misty Date: Tue, 29 Nov 2022 03:59:47 +0800 Subject: [PATCH 1/6] Support Frida v16.0.5 --- Fermion/core.js | 3 + Fermion/package.json | 5 +- Fermion/pages/index.html | 22 +- Fermion/pages/proc.html | 8 +- Fermion/src/lang/frida.d.ts | 7690 ----------------------------------- Fermion/src/renderer.js | 4 +- 6 files changed, 27 insertions(+), 7705 deletions(-) delete mode 100644 Fermion/src/lang/frida.d.ts diff --git a/Fermion/core.js b/Fermion/core.js index dd2cc84..4f3669d 100644 --- a/Fermion/core.js +++ b/Fermion/core.js @@ -26,6 +26,9 @@ function createWindow() { webviewTag: true } }); + // needed after electron v14.0.1 + // https://stackoverflow.com/questions/69059668/enableremotemodule-is-missing-from-electron-v14-typescript-type-definitions/69059669#69059669 + require('@electron/remote/main').enable(bWin.webContents); // and load the index.html of the app. bWin.loadFile(path.join(__dirname, '/pages/index.html')); diff --git a/Fermion/package.json b/Fermion/package.json index 72cd772..62e5726 100644 --- a/Fermion/package.json +++ b/Fermion/package.json @@ -11,8 +11,9 @@ "license": "BSD-3-Clause", "dependencies": { "@electron/remote": "^2.0.0", - "electron": "13.3.0", - "frida": "15.1.3", + "@types/frida-gum": "^18.3.0", + "electron": "21.0.0", + "frida": "^16.0.5", "jquery": "3.6.0", "monaco-editor": "0.30.0", "mutex-promise": "0.1.0", diff --git a/Fermion/pages/index.html b/Fermion/pages/index.html index 5e06dcd..628b622 100644 --- a/Fermion/pages/index.html +++ b/Fermion/pages/index.html @@ -175,7 +175,7 @@

Frida Tools

- + diff --git a/Fermion/pages/proc.html b/Fermion/pages/proc.html index 8886f04..9ba755d 100644 --- a/Fermion/pages/proc.html +++ b/Fermion/pages/proc.html @@ -97,8 +97,14 @@ // Create IPC renderer const ipc = require('electron').ipcRenderer; + var deviceId = null; // Device ID - var deviceId = window.process.argv[window.process.argv.length - 1]; + for (let i = window.process.argv.length - 1; i >= 0; i--) { + arg = window.process.argv[i]; + if (arg.startsWith("FERMION_DEVICEID=")) { + deviceId = arg.substr("FERMION_DEVICEID=".length) + } + } // Retrieve device list async function getDeviceList(devInst) { diff --git a/Fermion/src/lang/frida.d.ts b/Fermion/src/lang/frida.d.ts deleted file mode 100644 index 5942fe5..0000000 --- a/Fermion/src/lang/frida.d.ts +++ /dev/null @@ -1,7690 +0,0 @@ -// Type definitions for non-npm package frida-gum 17.1 -// Project: https://github.com/frida/frida -// Definitions by: Ole André Vadla Ravnås -// Francesco Tamagni -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// Minimum TypeScript Version: 4.1 - -/** - * Returns a hexdump of the provided ArrayBuffer or NativePointerValue target. - * - * @param target The ArrayBuffer or NativePointerValue to dump. - * @param options Options customizing the output. - */ - declare function hexdump(target: ArrayBuffer | NativePointerValue, options?: HexdumpOptions): string; - - interface HexdumpOptions { - /** - * Specifies byte offset of where to start dumping. Defaults to 0. - */ - offset?: number | undefined; - - /** - * Limits how many bytes to dump. - */ - length?: number | undefined; - - /** - * Whether a header should be included. Defaults to true. - */ - header?: boolean | undefined; - - /** - * Whether ANSI colors should be used. Defaults to false. - */ - ansi?: boolean | undefined; - } - - /** - * Short-hand for `new Int64(value)`. - */ - declare function int64(value: string | number): Int64; - - /** - * Short-hand for `new UInt64(value)`. - */ - declare function uint64(value: string | number): UInt64; - - /** - * Short-hand for `new NativePointer(value)`. - */ - declare function ptr(value: string | number): NativePointer; - - /** - * Short-hand for `ptr("0")`. - */ - declare const NULL: NativePointer; - - /** - * Requests callback to be called on the next message received from your Frida-based application. - * - * This will only give you one message, so you need to call `recv()` again to receive the next one. - */ - declare function recv(callback: MessageCallback): MessageRecvOperation; - - /** - * Requests callback to be called when the next message of the given `type` has been received from your - * Frida-based application. - * - * This will only give you one message, so you need to call `recv()` again to receive the next one. - */ - declare function recv(type: string, callback: MessageCallback): MessageRecvOperation; - - interface MessageCallback { (message: any, data: ArrayBuffer | null): void; } - - interface MessageRecvOperation { - /** - * Blocks until the message has been received and callback has returned. - */ - wait(): void; - } - - /** - * Sends a JSON-serializable message to your Frida-based application, - * with (optionally) some raw binary data included. The latter is useful - * if you e.g. dumped some memory using `NativePointer#readByteArray()`. - * - * @param message Any JSON-serializable value. - * @param data Raw binary data. - */ - declare function send(message: any, data?: ArrayBuffer | number[] | null): void; - - /** - * Calls `func` after `delay` milliseconds, or if omitted: as soon as Frida's - * JavaScript thread is idle. Any additional `params` are passed along. - * - * Returns an id that can be passed to `clearTimeout()` to cancel it. - */ - declare function setTimeout(func: ScheduledCallback, delay?: number, ...params: any[]): TimeoutId; - - /** - * Cancels a previously scheduled `setTimeout()`. - */ - declare function clearTimeout(id: TimeoutId): void; - - /** - * Opaque ID returned by `setTimeout()`. Pass it to `clearTimeout()` to cancel a pending `setTimeout()`. - */ - type TimeoutId = number; - - /** - * Calls `func` every `delay` milliseconds, optionally passing it the provided params. - * Returns an id that can be passed to clearInterval() to cancel it. - */ - declare function setInterval(func: ScheduledCallback, delay: number, ...params: any[]): IntervalId; - - /** - * Cancels a previously scheduled `setInterval()`. - */ - declare function clearInterval(id: IntervalId): void; - - /** - * Opaque ID returned by `setInterval()`. Pass it to `clearInterval()` to cancel a pending `setInterval()`. - */ - type IntervalId = number; - - /** - * Schedules `func` to be called on Frida's JavaScript thread, optionally passing it the provided params. - * Returns an id that can be passed to clearImmediate() to cancel it. - */ - declare function setImmediate(func: ScheduledCallback, ...params: any[]): ImmediateId; - - /** - * Cancels a previously scheduled `clearImmediate()`. - */ - declare function clearImmediate(id: ImmediateId): void; - - /** - * Opaque ID returned by `setImmediate()`. Pass it to `clearImmediate()` to cancel a pending `setImmediate()`. - */ - type ImmediateId = number; - - type ScheduledCallback = (...params: any[]) => void; - - declare namespace rpc { - /** - * Empty object that you can either replace or insert into to expose an RPC-style API to your application. - * The key specifies the method name and the value is your exported function. This function may either return - * a plain value for returning that to the caller immediately, or a Promise for returning asynchronously. - */ - let exports: RpcExports; - } - - interface RpcExports { - [name: string]: AnyFunction; - } - - type AnyFunction = (...args: any[]) => any; - - declare namespace Frida { - /** - * The current Frida version. - */ - const version: string; - - /** - * The current size – in bytes – of Frida’s private heap, which is shared by all scripts and Frida’s own runtime. - * This is useful for keeping an eye on how much memory your instrumentation is using out of the total consumed by - * the hosting process. - */ - const heapSize: number; - - /** - * Source map for the GumJS runtime. - */ - const sourceMap: SourceMap; - } - - declare namespace Script { - /** - * Runtime being used. - */ - const runtime: ScriptRuntime; - - /** - * File name of the current script. - */ - const fileName: string; - - /** - * Source map of the current script. - */ - const sourceMap: SourceMap; - - /** - * Runs `func` on the next tick, i.e. when the current native thread exits - * the JavaScript runtime. Any additional `params` are passed to it. - */ - function nextTick(func: ScheduledCallback, ...params: any[]): void; - - /** - * Temporarily prevents the current script from being unloaded. - * This is reference-counted, so there must be one matching `unpin()` - * happening at a later point. - * - * Typically used in the callback of `WeakRef.bind()` when you need to - * schedule cleanup on another thread. - */ - function pin(): void; - - /** - * Reverses a previous `pin()` so the current script may be unloaded. - */ - function unpin(): void; - - /** - * Starts monitoring the lifetime of `target`. Calls `callback` as soon as - * value has been garbage-collected, or the script is about to get - * unloaded. - * - * Useful when you're building a language-binding where you need to free - * native resources when a JS value is no longer needed. - * - * Be careful so `callback` is not a closure that accidentally captures - * `target` and keeps it alive beyond its intended lifetime. - * - * @param target Heap-allocated JavaScript value to monitor lifetime of. - * @param callback Function to call when `target` gets GCed. - */ - function bindWeak(target: any, callback: WeakRefCallback): WeakRefId; - - /** - * Stops monitoring the value passed to `WeakRef.bind()` and calls the - * callback immediately. - * - * @param id ID returned by a previous call to `WeakRef.bind()`. - */ - function unbindWeak(id: WeakRefId): void; - - /** - * Installs or uninstalls a handler that is used to resolve attempts to - * access non-existent global variables. - * - * Useful for implementing a REPL where unknown identifiers may be fetched - * lazily from a database. - * - * @param handler The handler to install, or `null` to uninstall a - * previously installed handler. - */ - function setGlobalAccessHandler(handler: GlobalAccessHandler | null): void; - } - - type ScriptRuntime = "DUK" | "V8"; - - type WeakRefCallback = () => void; - - /** - * Opaque ID returned by `Script.bindWeak()`. Pass it to `Script.unbindWeak()` - * to stop monitoring the target value. - */ - type WeakRefId = number; - - interface GlobalAccessHandler { - /** - * Queries which additional globals exist. - */ - enumerate(): string[]; - - /** - * Called whenever an attempt to access a non-existent global variable is - * made. Return `undefined` to treat the variable as inexistent. - * - * @param property Name of non-existent global that is being accessed. - */ - get(property: string): any; - } - - declare namespace Process { - /** - * PID of the current process. - */ - const id: number; - - /** - * Architecture of the current process. - */ - const arch: Architecture; - - /** - * Platform of the current process. - */ - const platform: Platform; - - /** - * Size of a virtual memory page in bytes. This is used to make your scripts more portable. - */ - const pageSize: number; - - /** - * Size of a pointer in bytes. This is used to make your scripts more portable. - */ - const pointerSize: number; - - /** - * Whether Frida will avoid modifying existing code in memory and will not try to run unsigned code. - * Currently this property will always be set to Optional unless you are using Gadget and have configured - * it to assume that code-signing is required. This property allows you to determine whether the Interceptor - * API is off limits, and whether it is safe to modify code or run unsigned code. - */ - const codeSigningPolicy: CodeSigningPolicy; - - /** - * Determines whether a debugger is currently attached. - */ - function isDebuggerAttached(): boolean; - - /** - * Gets this thread’s OS-specific id. - */ - function getCurrentThreadId(): ThreadId; - - /** - * Enumerates all threads. - */ - function enumerateThreads(): ThreadDetails[]; - - /** - * Looks up a module by address. Returns null if not found. - */ - function findModuleByAddress(address: NativePointerValue): Module | null; - - /** - * Looks up a module by address. Throws an exception if not found. - */ - function getModuleByAddress(address: NativePointerValue): Module; - - /** - * Looks up a module by name. Returns null if not found. - */ - function findModuleByName(name: string): Module | null; - - /** - * Looks up a module by name. Throws an exception if not found. - */ - function getModuleByName(name: string): Module; - - /** - * Enumerates modules loaded right now. - */ - function enumerateModules(): Module[]; - - /** - * Looks up a memory range by address. Returns null if not found. - */ - function findRangeByAddress(address: NativePointerValue): RangeDetails | null; - - /** - * Looks up a memory range by address. Throws an exception if not found. - */ - function getRangeByAddress(address: NativePointerValue): RangeDetails; - - /** - * Enumerates memory ranges satisfying `specifier`. - * - * @param specifier The kind of ranges to include. - */ - function enumerateRanges(specifier: PageProtection | EnumerateRangesSpecifier): RangeDetails[]; - - /** - * Just like `enumerateRanges()`, but for individual memory allocations known to the system heap. - */ - function enumerateMallocRanges(): RangeDetails[]; - - /** - * Installs a process-wide exception handler callback that gets a chance to - * handle native exceptions before the hosting process itself does. - * - * It is up to your callback to decide what to do with the exception. - * It could for example: - * - Log the issue. - * - Notify your application through a `send()` followed by a blocking `recv()` for acknowledgement of the sent data - * being received. - * - Modify registers and memory to recover from the exception. - * - * You should return `true` if you did handle the exception, in which case - * Frida will resume the thread immediately. If you do not return `true`, - * Frida will forward the exception to the hosting process' exception - * handler, if it has one, or let the OS terminate the process. - */ - function setExceptionHandler(callback: ExceptionHandlerCallback): void; - } - - declare class Module { - /** - * Canonical module name. - */ - name: string; - - /** - * Base address. - */ - base: NativePointer; - - /** - * Size in bytes. - */ - size: number; - - /** - * Full filesystem path. - */ - path: string; - - /** - * Enumerates imports of module. - */ - enumerateImports(): ModuleImportDetails[]; - - /** - * Enumerates exports of module. - */ - enumerateExports(): ModuleExportDetails[]; - - /** - * Enumerates symbols of module. - */ - enumerateSymbols(): ModuleSymbolDetails[]; - - /** - * Enumerates memory ranges of module with the `name` as seen in `Process#enumerateModules()`. - * - * @param protection Minimum protection of ranges to include. - */ - enumerateRanges(protection: PageProtection): RangeDetails[]; - - /** - * Looks up the absolute address of the export named `exportName`. - * - * Returns null if the export doesn't exist. - * - * @param exportName Export name to find the address of. - */ - findExportByName(exportName: string): NativePointer | null; - - /** - * Looks up the absolute address of the export named `exportName`. - * - * Throws an exception if the export doesn't exist. - * - * @param exportName Export name to find the address of. - */ - getExportByName(exportName: string): NativePointer; - - /** - * Loads the specified module. - */ - static load(name: string): Module; - - /** - * Ensures that initializers of the specified module have been run. This is important during early instrumentation, - * i.e. code run early in the process lifetime, to be able to safely interact with APIs. - * - * One such use-case is interacting with ObjC classes provided by a given module. - */ - static ensureInitialized(name: string): void; - - /** - * Looks up the base address of the `name` module. Returns null if the module isn’t loaded. - * - * @param name Module name or path. - */ - static findBaseAddress(name: string): NativePointer | null; - - /** - * Looks up the base address of the `name` module. Throws an exception if the module isn’t loaded. - * - * @param name Module name or path. - */ - static getBaseAddress(name: string): NativePointer; - - /** - * Looks up the absolute address of the export named `exportName` in `moduleName`. If the module isn’t known you may - * pass null instead of its name, but this can be a costly search and should be avoided. - * - * Returns null if the module or export doesn't exist. - * - * @param moduleName Module name or path. - * @param exportName Export name to find the address of. - */ - static findExportByName(moduleName: string | null, exportName: string): NativePointer | null; - - /** - * Looks up the absolute address of the export named `exportName` in `moduleName`. If the module isn’t known you may - * pass null instead of its name, but this can be a costly search and should be avoided. - * - * Throws an exception if the module or export doesn't exist. - * - * @param moduleName Module name or path. - * @param exportName Export name to find the address of. - */ - static getExportByName(moduleName: string | null, exportName: string): NativePointer; - } - - declare class ModuleMap { - /** - * Creates a new module map optimized for determining which module a given memory address belongs to, if any. - * Takes a snapshot of the currently loaded modules when created, which may be refreshed by calling `update()`. - * - * The `filter` argument is optional and allows you to pass a function used for filtering the list of modules. - * This is useful if you e.g. only care about modules owned by the application itself, and allows you to quickly - * check if an address belongs to one of its modules. The filter function is given the module's details and must - * return true for each module that should be kept in the map. It is called for each loaded module every time the - * map is updated. - * - * @param filter Filter function to decide which modules are kept in the map. - */ - constructor(filter?: ModuleMapFilter); - - /** - * Determines if `address` belongs to any of the contained modules. - * - * @param address Address that might belong to a module in the map. - */ - has(address: NativePointerValue): boolean; - - /** - * Looks up a module by address. Returns null if not found. - * - * @param address Address that might belong to a module in the map. - */ - find(address: NativePointerValue): Module | null; - - /** - * Looks up a module by address. Throws an exception if not found. - * - * @param address Address that might belong to a module in the map. - */ - get(address: NativePointerValue): Module; - - /** - * Just like `find()`, but only returns the `name` field, which means less overhead when you don’t need the - * other details. Returns null if not found. - * - * @param address Address that might belong to a module in the map. - */ - findName(address: NativePointerValue): string | null; - - /** - * Just like `get()`, but only returns the `name` field, which means less overhead when you don’t need the - * other details. Throws an exception if not found. - * - * @param address Address that might belong to a module in the map. - */ - getName(address: NativePointerValue): string; - - /** - * Just like `find()`, but only returns the `path` field, which means less overhead when you don’t need the - * other details. Returns null if not found. - * - * @param address Address that might belong to a module in the map. - */ - findPath(address: NativePointerValue): string | null; - - /** - * Just like `get()`, but only returns the `path` field, which means less overhead when you don’t need the - * other details. Throws an exception if not found. - * - * @param address Address that might belong to a module in the map. - */ - getPath(address: NativePointerValue): string; - - /** - * Updates the map. - * - * You should call this after a module has been loaded or unloaded to avoid operating on stale data. - */ - update(): void; - - /** - * Gets the modules currently in the map. The returned array is a deep copy and will not mutate after a - * call to `update()`. - */ - values(): Module[]; - } - - type ModuleMapFilter = (m: Module) => boolean; - - declare namespace Memory { - /** - * Scans memory for occurences of `pattern` in the memory range given by `address` and `size`. - * - * @param address Starting address to scan from. - * @param size Number of bytes to scan. - * @param pattern Match pattern of the form “13 37 ?? ff” to match 0x13 followed by 0x37 followed by any byte - * followed by 0xff. For more advanced matching it is also possible to specify an r2-style mask. - * The mask is bitwise AND-ed against both the needle and the haystack. To specify the mask append - * a `:` character after the needle, followed by the mask using the same syntax. - * For example: “13 37 13 37 : 1f ff ff f1”. - * For convenience it is also possible to specify nibble-level wildcards, like “?3 37 13 ?7”, - * which gets translated into masks behind the scenes. - * @param callbacks Object with callbacks. - */ - function scan(address: NativePointerValue, size: number | UInt64, pattern: string, callbacks: MemoryScanCallbacks): void; - - /** - * Synchronous version of `scan()`. - * - * @param address Starting address to scan from. - * @param size Number of bytes to scan. - * @param pattern Match pattern, see `Memory.scan()` for details. - */ - function scanSync(address: NativePointerValue, size: number | UInt64, pattern: string): MemoryScanMatch[]; - - /** - * Allocates `size` bytes of memory on Frida's private heap, or, if `size` is a multiple of Process#pageSize, - * one or more raw memory pages managed by the OS. The allocated memory will be released when the returned - * NativePointer value gets garbage collected. This means you need to keep a reference to it while the pointer - * is being used by code outside the JavaScript runtime. - * - * @param size Number of bytes to allocate. - * @param options Options to customize the memory allocation. - */ - function alloc(size: number | UInt64, options?: MemoryAllocOptions): NativePointer; - - /** - * Allocates, encodes and writes out `str` as a UTF-8 string on Frida's private heap. - * See Memory#alloc() for details about its lifetime. - * - * @param str String to allocate. - */ - function allocUtf8String(str: string): NativePointer; - - /** - * Allocates, encodes and writes out `str` as a UTF-16 string on Frida's private heap. - * See Memory#alloc() for details about its lifetime. - * - * @param str String to allocate. - */ - function allocUtf16String(str: string): NativePointer; - - /** - * Allocates, encodes and writes out `str` as an ANSI string on Frida's private heap. - * See Memory#alloc() for details about its lifetime. - * - * @param str String to allocate. - */ - function allocAnsiString(str: string): NativePointer; - - /** - * Just like memcpy. - * - * @param dst Destination address. - * @param src Sources address. - * @param n Number of bytes to copy. - */ - function copy(dst: NativePointerValue, src: NativePointerValue, n: number | UInt64): void; - - /** - * Short-hand for Memory#alloc() followed by Memory#copy(). See Memory#alloc() for details about lifetime. - * - * @param address Address to copy from. - * @param size Number of bytes to copy. - */ - function dup(address: NativePointerValue, size: number | UInt64): NativePointer; - - /** - * Changes the page protection on a region of memory. - * - * @param address Starting address. - * @param size Number of bytes. Must be a multiple of Process#pageSize. - * @param protection Desired page protection. - */ - function protect(address: NativePointerValue, size: number | UInt64, protection: PageProtection): boolean; - - /** - * Safely modifies `size` bytes at `address`. The supplied function `apply` gets called with a writable pointer - * where you must write the desired modifications before returning. Do not make any assumptions about this being - * the same location as address, as some systems require modifications to be written to a temporary location before - * being mapped into memory on top of the original memory page (e.g. on iOS, where directly modifying in-memory - * code may result in the process losing its CS_VALID status). - * - * @param address Starting address to modify. - * @param size Number of bytes to modify. - * @param apply Function that applies the desired changes. - */ - function patchCode(address: NativePointerValue, size: number | UInt64, apply: MemoryPatchApplyCallback): void; - } - - interface MemoryRange { - /** - * Base address. - */ - base: NativePointer; - - /** - * Size in bytes. - */ - size: number; - } - - /** - * Monitors one or more memory ranges for access, and notifies on the first - * access of each contained memory page. - * - * Only available on Windows for now. We would love to support this on the other - * platforms too, so if you find this useful and would like to help out, please - * get in touch. - */ - declare namespace MemoryAccessMonitor { - /** - * Starts monitoring one or more memory ranges for access, and notifies on - * the first access of each contained memory page. - * - * @param ranges One or more ranges to monitor. - * @param callbacks Callbacks to be notified on access. - */ - function enable(ranges: MemoryAccessRange | MemoryAccessRange[], callbacks: MemoryAccessCallbacks): void; - - /** - * Stops monitoring the remaining memory ranges passed to - * `MemoryAccessMonitor.enable()`. - */ - function disable(): void; - } - - interface MemoryAccessRange { - /** - * Base address. - */ - base: NativePointer; - - /** - * Size in bytes. - */ - size: number; - } - - /** - * Callbacks to be notified synchronously on memory access. - */ - interface MemoryAccessCallbacks { - onAccess: (details: MemoryAccessDetails) => void; - } - - interface MemoryAccessDetails { - /** - * The kind of operation that triggered the access. - */ - operation: MemoryOperation; - - /** - * Address of instruction performing the access. - */ - from: NativePointer; - - /** - * Address being accessed. - */ - address: NativePointer; - - /** - * Index of the accessed range in the ranges provided to - * `MemoryAccessMonitor.enable()`. - */ - rangeIndex: number; - - /** - * Index of the accessed memory page inside the specified range. - */ - pageIndex: number; - - /** - * Overall number of pages which have been accessed so far, and are thus - * no longer being monitored. - */ - pagesCompleted: number; - - /** - * Overall number of pages that were initially monitored. - */ - pagesTotal: number; - } - - declare namespace Thread { - /** - * Generates a backtrace for the given thread's `context`. - * - * If you call this from Interceptor's `onEnter` or `onLeave` callbacks - * you should provide `this.context` for the optional `context` argument, - * as it will give you a more accurate backtrace. Omitting `context` means - * the backtrace will be generated from the current stack location, which - * may not give you a very good backtrace due to the JavaScript VM's - * potentially JITed stack frames. - * - * @param context CPU context to use for generating the backtrace. - * @param backtracer The kind of backtracer to use. Must be either - * `Backtracer.FUZZY` or `Backtracer.ACCURATE`, - * where the latter is the default if not specified. - */ - function backtrace(context?: CpuContext, backtracer?: Backtracer): NativePointer[]; - - /** - * Suspends execution of the current thread for `delay` seconds. - * - * For example `0.05` to sleep for 50 ms. - * - * @param delay Delay in seconds. - */ - function sleep(delay: number): void; - } - - // tslint:disable-next-line:no-unnecessary-class - declare class Backtracer { - /** - * The accurate kind of backtracers rely on debugger-friendly binaries or - * presence of debug information to do a good job, but avoid false - * positives. - */ - static ACCURATE: Backtracer; - - /** - * The fuzzy backtracers perform forensics on the stack in order to guess - * the return addresses, which means you will get false positives, but it - * will work on any binary. - */ - static FUZZY: Backtracer; - } - - type Architecture = - | "ia32" - | "x64" - | "arm" - | "arm64" - | "mips" - ; - - type Platform = - | "windows" - | "darwin" - | "linux" - | "qnx" - ; - - type CodeSigningPolicy = "optional" | "required"; - - /** - * Given as a string of the form: rwx, where rw- means “readable and writable”. - */ - type PageProtection = string; - - type ThreadId = number; - - type ThreadState = - | "running" - | "stopped" - | "waiting" - | "uninterruptible" - | "halted" - ; - - interface ThreadDetails { - /** - * OS-specific ID. - */ - id: ThreadId; - - /** - * Snapshot of state. - */ - state: ThreadState; - - /** - * Snapshot of CPU registers. - */ - context: CpuContext; - } - - interface KernelModuleDetails { - /** - * Canonical module name. - */ - name: string; - - /** - * Base address. - */ - base: UInt64; - - /** - * Size in bytes. - */ - size: number; - } - - interface ModuleImportDetails { - /** - * The kind of import, if available. - */ - type?: ModuleImportType | undefined; - - /** - * Imported symbol name. - */ - name: string; - - /** - * Module name, if available. - */ - module?: string | undefined; - - /** - * Absolute address, if available. - */ - address?: NativePointer | undefined; - - /** - * Memory location where the import is stored, if available. - */ - slot?: NativePointer | undefined; - } - - interface ModuleExportDetails { - /** - * The kind of export. - */ - type: ModuleExportType; - - /** - * Exported symbol name. - */ - name: string; - - /** - * Absolute address. - */ - address: NativePointer; - } - - interface ModuleSymbolDetails { - /** - * Whether symbol is globally visible. - */ - isGlobal: boolean; - - /** - * The kind of symbol. - */ - type: ModuleSymbolType; - - /** - * Which section this symbol resides in, if available. - */ - section?: ModuleSymbolSectionDetails | undefined; - - /** - * Symbol name. - */ - name: string; - - /** - * Absolute address. - */ - address: NativePointer; - - /** - * Size in bytes, if available. - */ - size?: number | undefined; - } - - type ModuleImportType = "function" | "variable"; - - type ModuleExportType = "function" | "variable"; - - type ModuleSymbolType = - // Common - | "unknown" - | "section" - - // Mach-O - | "undefined" - | "absolute" - | "prebound-undefined" - | "indirect" - - // ELF - | "object" - | "function" - | "file" - | "common" - | "tls" - ; - - interface ModuleSymbolSectionDetails { - /** - * Section index, segment name (if applicable) and section name – same format as r2’s section IDs. - */ - id: string; - - /** - * Section's memory protection. - */ - protection: PageProtection; - } - - interface RangeDetails { - /** - * Base address. - */ - base: NativePointer; - - /** - * Size in bytes. - */ - size: number; - - /** - * Protection. - */ - protection: PageProtection; - - /** - * File mapping details, if available. - */ - file?: FileMapping | undefined; - } - - interface KernelRangeDetails { - /** - * Base address. - */ - base: UInt64; - - /** - * Size in bytes. - */ - size: number; - - /** - * Protection. - */ - protection: PageProtection; - } - - interface KernelModuleRangeDetails { - /** - * Name. - */ - name: string; - - /** - * Base address. - */ - base: UInt64; - - /** - * Size in bytes. - */ - size: number; - - /** - * Protection. - */ - protection: PageProtection; - } - - interface FileMapping { - /** - * Full filesystem path. - */ - path: string; - - /** - * Offset in the mapped file on disk, in bytes. - */ - offset: number; - - /** - * Size in the mapped file on disk, in bytes. - */ - size: number; - } - - interface EnumerateRangesSpecifier { - /** - * Minimum protection required to be included in the result. - */ - protection: PageProtection; - - /** - * Whether neighboring ranges with the same protection should be coalesced. The default is false. - */ - coalesce: boolean; - } - - type ExceptionHandlerCallback = (exception: ExceptionDetails) => boolean | void; - - interface ExceptionDetails { - /** - * The kind of exception that occurred. - */ - type: ExceptionType; - - /** - * Address where the exception occurred. - */ - address: NativePointer; - - /** - * Memory operation details, if relevant. - */ - memory?: ExceptionMemoryDetails | undefined; - - /** - * CPU registers. You may also update register values by assigning to these keys. - */ - context: CpuContext; - - /** - * Address of the OS and architecture-specific CPU context struct. - * - * This is only exposed as a last resort for edge-cases where `context` isn’t providing enough details. - * We would however discourage using this and rather submit a pull-request to add the missing bits needed - * for your use-case. - */ - nativeContext: NativePointer; - } - - type ExceptionType = - | "abort" - | "access-violation" - | "guard-page" - | "illegal-instruction" - | "stack-overflow" - | "arithmetic" - | "breakpoint" - | "single-step" - | "system" - ; - - interface ExceptionMemoryDetails { - /** - * The kind of operation that triggered the exception. - */ - operation: MemoryOperation; - - /** - * Address that was accessed when the exception occurred. - */ - address: NativePointer; - } - - type MemoryOperation = "read" | "write" | "execute"; - - interface EnumerateCallbacks { - onMatch: (item: T) => void | EnumerateAction; - onComplete: () => void; - } - - type EnumerateAction = "stop"; - - interface MemoryScanCallbacks { - /** - * Called with each occurence that was found. - * - * @param address Memory address where a match was found. - * @param size Size of this match. - */ - onMatch: (address: NativePointer, size: number) => void | EnumerateAction; - - /** - * Called when there was a memory access error while scanning. - * - * @param reason Why the memory access failed. - */ - onError?: ((reason: string) => void) | undefined; - - /** - * Called when the memory range has been fully scanned. - */ - onComplete: () => void; - } - - interface MemoryScanMatch { - /** - * Memory address where a match was found. - */ - address: NativePointer; - - /** - * Size of this match. - */ - size: number; - } - - interface KernelMemoryScanCallbacks { - /** - * Called with each occurence that was found. - * - * @param address Memory address where a match was found. - * @param size Size of this match. - */ - onMatch: (address: UInt64, size: number) => void | EnumerateAction; - - /** - * Called when there was a memory access error while scanning. - * - * @param reason Why the memory access failed. - */ - onError?: ((reason: string) => void) | undefined; - - /** - * Called when the memory range has been fully scanned. - */ - onComplete: () => void; - } - - interface KernelMemoryScanMatch { - /** - * Memory address where a match was found. - */ - address: UInt64; - - /** - * Size of this match. - */ - size: number; - } - - type MemoryAllocOptions = Record | MemoryAllocNearOptions; - - interface MemoryAllocNearOptions { - /** - * Memory address to try allocating near. - */ - near: NativePointer; - - /** - * Maximum distance to the given memory address, in bytes. - */ - maxDistance: number; - } - - type MemoryPatchApplyCallback = (code: NativePointer) => void; - - /** - * Represents a signed 64-bit value. - */ - declare class Int64 { - /** - * Creates a new Int64 from `v`, which is either a string containing the value in decimal, or hexadecimal - * if prefixed with “0x”, or a number. You may use the int64(v) short-hand for brevity. - */ - constructor(v: string | number | Int64); - - /** - * Makes a new Int64 whose value is `this` + `v`. - */ - add(v: Int64 | number | string): Int64; - - /** - * Makes a new Int64 whose value is `this` - `v`. - */ - sub(v: Int64 | number | string): Int64; - - /** - * Makes a new Int64 whose value is `this` & `v`. - */ - and(v: Int64 | number | string): Int64; - - /** - * Makes a new Int64 whose value is `this` | `v`. - */ - or(v: Int64 | number | string): Int64; - - /** - * Makes a new Int64 whose value is `this` ^ `v`. - */ - xor(v: Int64 | number | string): Int64; - - /** - * Makes a new Int64 whose value is `this` << `v`. - */ - shl(v: Int64 | number | string): Int64; - - /** - * Makes a new Int64 whose value is `this` >> `v`. - */ - shr(v: Int64 | number | string): Int64; - - /** - * Makes a new Int64 whose value is ~`this`. - */ - not(): Int64; - - /** - * Returns an integer comparison result just like String#localeCompare(). - */ - compare(v: Int64 | number | string): number; - - /** - * Returns a boolean indicating whether `v` is equal to `this`. - */ - equals(v: Int64 | number | string): boolean; - - /** - * Converts to a number. - */ - toNumber(): number; - - /** - * Converts to a string, optionally with a custom `radix`. - */ - toString(radix?: number): string; - - /** - * Converts to a JSON-serializable value. Same as `toString()`. - */ - toJSON(): string; - - /** - * Converts to a number. Same as `toNumber()`. - */ - valueOf(): number; - } - - /** - * Represents an unsigned 64-bit value. - */ - declare class UInt64 { - /** - * Creates a new UInt64 from `v`, which is either a string containing the value in decimal, or hexadecimal - * if prefixed with “0x”, or a number. You may use the uint64(v) short-hand for brevity. - */ - constructor(v: string | number | UInt64); - - /** - * Makes a new UInt64 whose value is `this` + `v`. - */ - add(v: UInt64 | number | string): UInt64; - - /** - * Makes a new UInt64 whose value is `this` - `v`. - */ - sub(v: UInt64 | number | string): UInt64; - - /** - * Makes a new UInt64 whose value is `this` & `v`. - */ - and(v: UInt64 | number | string): UInt64; - - /** - * Makes a new UInt64 whose value is `this` | `v`. - */ - or(v: UInt64 | number | string): UInt64; - - /** - * Makes a new UInt64 whose value is `this` ^ `v`. - */ - xor(v: UInt64 | number | string): UInt64; - - /** - * Makes a new UInt64 whose value is `this` << `v`. - */ - shr(v: UInt64 | number | string): UInt64; - - /** - * Makes a new UInt64 whose value is `this` >> `v`. - */ - shl(v: UInt64 | number | string): UInt64; - - /** - * Makes a new UInt64 whose value is ~`this`. - */ - not(): UInt64; - - /** - * Returns an integer comparison result just like String#localeCompare(). - */ - compare(v: UInt64 | number | string): number; - - /** - * Returns a boolean indicating whether `v` is equal to `this`. - */ - equals(v: UInt64 | number | string): boolean; - - /** - * Converts to a number. - */ - toNumber(): number; - - /** - * Converts to a string, optionally with a custom `radix`. - */ - toString(radix?: number): string; - - /** - * Converts to a JSON-serializable value. Same as `toString()`. - */ - toJSON(): string; - - /** - * Converts to a number. Same as `toNumber()`. - */ - valueOf(): number; - } - - /** - * Represents a native pointer value whose size depends on Process#pointerSize. - */ - declare class NativePointer { - /** - * Creates a new NativePointer from `v`, which is either a string containing the memory address in decimal, - * or hexadecimal if prefixed with “0x”, or a number. You may use the ptr(v) short-hand for brevity. - */ - constructor(v: string | number | UInt64 | Int64 | NativePointerValue); - - /** - * Returns a boolean allowing you to conveniently check if a pointer is `NULL`. - */ - isNull(): boolean; - - /** - * Makes a new NativePointer whose value is `this` + `v`. - */ - add(v: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer whose value is `this` - `v`. - */ - sub(v: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer whose value is `this` & `v`. - */ - and(v: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer whose value is `this` | `v`. - */ - or(v: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer whose value is `this` ^ `v`. - */ - xor(v: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer whose value is `this` << `v`. - */ - shr(v: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer whose value is `this` >> `v`. - */ - shl(v: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer whose value is ~`this`. - */ - not(): NativePointer; - - /** - * Makes a new NativePointer by taking the bits of `this` and adding - * pointer authentication bits, creating a signed pointer. This is a - * no-op if the current process does not support pointer - * authentication, returning `this` instead of a new value. - * - * @param key The key to use. Defaults to `ia`. - * @param data The data to use. Defaults to `0`. - */ - sign(key?: PointerAuthenticationKey, data?: NativePointerValue | UInt64 | Int64 | number | string): NativePointer; - - /** - * Makes a new NativePointer by taking the bits of `this` and - * removing its pointer authentication bits, creating a raw pointer. - * This is a no-op if the current process does not support pointer - * authentication, returning `this` instead of a new value. - * - * @param key The key that was used to sign `this`. Defaults to `ia`. - */ - strip(key?: PointerAuthenticationKey): NativePointer; - - /** - * Makes a new NativePointer by taking `this` and blending it with - * a constant, which may in turn be passed to `sign()` as `data`. - * - * @param smallInteger Value to blend with. - */ - blend(smallInteger: number): NativePointer; - - /** - * Returns a boolean indicating whether `v` is equal to `this`; i.e. it contains the same memory address. - */ - equals(v: NativePointerValue | UInt64 | Int64 | number | string): boolean; - - /** - * Returns an integer comparison result just like String#localeCompare(). - */ - compare(v: NativePointerValue | UInt64 | Int64 | number | string): number; - - /** - * Converts to a signed 32-bit integer. - */ - toInt32(): number; - - /** - * Converts to an unsigned 32-bit integer. - */ - toUInt32(): number; - - /** - * Converts to a “0x”-prefixed hexadecimal string, unless a `radix` - * is specified. - */ - toString(radix?: number): string; - - /** - * Converts to a JSON-serializable value. Same as `toString()`. - */ - toJSON(): string; - - /** - * Returns a string containing a `Memory#scan()`-compatible match pattern for this pointer’s raw value. - */ - toMatchPattern(): string; - - readPointer(): NativePointer; - readS8(): number; - readU8(): number; - readS16(): number; - readU16(): number; - readS32(): number; - readU32(): number; - readS64(): Int64; - readU64(): UInt64; - readShort(): number; - readUShort(): number; - readInt(): number; - readUInt(): number; - readLong(): number | Int64; - readULong(): number | UInt64; - readFloat(): number; - readDouble(): number; - readByteArray(length: number): ArrayBuffer | null; - readCString(size?: number): string | null; - readUtf8String(size?: number): string | null; - readUtf16String(length?: number): string | null; - readAnsiString(size?: number): string | null; - - writePointer(value: NativePointerValue): NativePointer; - writeS8(value: number | Int64): NativePointer; - writeU8(value: number | UInt64): NativePointer; - writeS16(value: number | Int64): NativePointer; - writeU16(value: number | UInt64): NativePointer; - writeS32(value: number | Int64): NativePointer; - writeU32(value: number | UInt64): NativePointer; - writeS64(value: number | Int64): NativePointer; - writeU64(value: number | UInt64): NativePointer; - writeShort(value: number | Int64): NativePointer; - writeUShort(value: number | UInt64): NativePointer; - writeInt(value: number | Int64): NativePointer; - writeUInt(value: number | UInt64): NativePointer; - writeLong(value: number | Int64): NativePointer; - writeULong(value: number | UInt64): NativePointer; - writeFloat(value: number): NativePointer; - writeDouble(value: number): NativePointer; - writeByteArray(value: ArrayBuffer | number[]): NativePointer; - writeUtf8String(value: string): NativePointer; - writeUtf16String(value: string): NativePointer; - writeAnsiString(value: string): NativePointer; - } - - type PointerAuthenticationKey = "ia" | "ib" | "da" | "db"; - - interface ObjectWrapper { - handle: NativePointer; - } - - interface ArrayBufferConstructor { - /** - * Creates an ArrayBuffer backed by an existing memory region. Unlike - * the NativePointer `read*()` and `write*()` APIs, no validation is - * performed on access, meaning a bad pointer will crash the process. - * - * @param address Base address of the region. Passing `NULL` will result - * in an empty buffer. - * @param size Size of the region. Passing `0` will result in an empty - * buffer. - */ - wrap(address: NativePointerValue, size: number): ArrayBuffer; - } - - interface ArrayBuffer { - /** - * Gets a pointer to the base address of the ArrayBuffer's backing store. - * It is the caller's responsibility to keep the buffer alive while the - * backing store is still being used. - */ - unwrap(): NativePointer; - } - - type NativePointerValue = NativePointer | ObjectWrapper; - - declare const NativeFunction: NativeFunctionConstructor; - - interface NativeFunctionConstructor { - new ( - address: NativePointerValue, - retType: RetType, - argTypes: ArgTypes, - abiOrOptions?: NativeABI | NativeFunctionOptions, - ): NativeFunction< - GetNativeFunctionReturnValue, - ResolveVariadic, unknown[]>> - >; - readonly prototype: NativeFunction; - } - - interface NativeFunction - extends NativePointer { - (...args: ArgTypes): RetType; - apply(thisArg: NativePointerValue | null | undefined, args: ArgTypes): RetType; - call(thisArg?: NativePointerValue | null, ...args: ArgTypes): RetType; - } - - declare const SystemFunction: SystemFunctionConstructor; - - interface SystemFunctionConstructor { - new ( - address: NativePointerValue, - retType: RetType, - argTypes: ArgTypes, - abiOrOptions?: NativeABI | NativeFunctionOptions, - ): SystemFunction< - GetNativeFunctionReturnValue, - ResolveVariadic, unknown[]>> - >; - readonly prototype: SystemFunction; - } - - interface SystemFunction - extends NativePointer { - (...args: ArgTypes): SystemFunctionResult; - apply(thisArg: NativePointerValue | null | undefined, args: ArgTypes): SystemFunctionResult; - call(thisArg?: NativePointerValue | null, ...args: ArgTypes): SystemFunctionResult; - } - - type SystemFunctionResult = - | WindowsSystemFunctionResult - | UnixSystemFunctionResult - ; - - interface WindowsSystemFunctionResult { - value: Value; - lastError: number; - } - - interface UnixSystemFunctionResult { - value: Value; - errno: number; - } - - declare class NativeCallback< - RetType extends NativeCallbackReturnType, - ArgTypes extends NativeCallbackArgumentType[] | [], - > extends NativePointer { - constructor( - func: NativeCallbackImplementation< - GetNativeCallbackReturnValue, - Extract, unknown[]> - >, - retType: RetType, - argTypes: ArgTypes, - abi?: NativeABI, - ); - } - - type NativeCallbackImplementation< - RetType extends NativeCallbackReturnValue, - ArgTypes extends NativeCallbackArgumentValue[] | [], - > = (this: CallbackContext | InvocationContext, ...args: ArgTypes) => RetType; - - interface CallbackContext { - /** - * Return address. - */ - returnAddress: NativePointer; - - /** - * CPU registers, but unlike `InvocationContext` this is read-only and only - * contains the bare minimum needed for `Thread.backtrace()` - all others - * are zeroed out. - */ - context: CpuContext; - } - - type Variadic = "..."; - - type ResolveVariadic = List extends [Variadic, ...infer Tail] - ? [...Array] - : List extends [infer Head, ...infer Tail] - ? [Head, ...ResolveVariadic] - : []; - - type RecursiveValuesOf = T[keyof T] | Array>; - - type RecursiveKeysOf = keyof T | Array> | []; - - type GetValue = Type[] extends T - ? Value - : T extends keyof Map - ? Map[T] - : { [P in keyof T]: T[P] extends Type ? GetValue : never }; - - // tslint:disable-next-line:interface-over-type-literal - type BaseNativeTypeMap = { - int: number; - uint: number; - long: number; - ulong: number; - char: number; - uchar: number; - float: number; - double: number; - int8: number; - uint8: number; - int16: number; - uint16: number; - int32: number; - uint32: number; - bool: number; - }; - - type NativeFunctionArgumentTypeMap = BaseNativeTypeMap & { - void: undefined; - pointer: NativePointerValue; - size_t: number | UInt64; - ssize_t: number | Int64; - int64: number | Int64; - uint64: number | UInt64; - "...": Variadic; - }; - - type NativeFunctionArgumentValue = RecursiveValuesOf; - - type NativeFunctionArgumentType = RecursiveKeysOf; - - type GetNativeFunctionArgumentValue = GetValue< - NativeFunctionArgumentTypeMap, - NativeFunctionArgumentValue, - NativeFunctionArgumentType, - T - >; - - type NativeFunctionReturnTypeMap = BaseNativeTypeMap & { - // tslint:disable-next-line:void-return - void: void; - pointer: NativePointer; - size_t: UInt64; - ssize_t: Int64; - int64: Int64; - uint64: UInt64; - }; - - type NativeFunctionReturnValue = RecursiveValuesOf; - - type NativeFunctionReturnType = RecursiveKeysOf; - - type GetNativeFunctionReturnValue = GetValue< - NativeFunctionReturnTypeMap, - NativeFunctionReturnValue, - NativeFunctionReturnType, - T - >; - - type NativeCallbackArgumentTypeMap = BaseNativeTypeMap & { - void: undefined; - pointer: NativePointer; - size_t: UInt64; - ssize_t: Int64; - int64: Int64; - uint64: UInt64; - }; - - type NativeCallbackArgumentValue = RecursiveValuesOf; - - type NativeCallbackArgumentType = RecursiveKeysOf; - - type GetNativeCallbackArgumentValue = GetValue< - NativeCallbackArgumentTypeMap, - NativeCallbackArgumentValue, - NativeCallbackArgumentType, - T - >; - - type NativeCallbackReturnTypeMap = BaseNativeTypeMap & { - // tslint:disable-next-line:void-return - void: void; - pointer: NativePointerValue; - size_t: number | UInt64; - ssize_t: number | Int64; - int64: number | Int64; - uint64: number | UInt64; - }; - - type NativeCallbackReturnValue = RecursiveValuesOf; - - type NativeCallbackReturnType = RecursiveKeysOf; - - type GetNativeCallbackReturnValue = GetValue< - NativeCallbackReturnTypeMap, - NativeCallbackReturnValue, - NativeCallbackReturnType, - T - >; - - type NativeABI = - | "default" - | "sysv" - | "stdcall" - | "thiscall" - | "fastcall" - | "mscdecl" - | "win64" - | "unix64" - | "vfp" - ; - - interface NativeFunctionOptions { - abi?: NativeABI | undefined; - scheduling?: SchedulingBehavior | undefined; - exceptions?: ExceptionsBehavior | undefined; - traps?: CodeTraps | undefined; - } - - type SchedulingBehavior = "cooperative" | "exclusive"; - - type ExceptionsBehavior = "steal" | "propagate"; - - type CodeTraps = "default" | "all"; - - type CpuContext = PortableCpuContext | Ia32CpuContext | X64CpuContext | ArmCpuContext | Arm64CpuContext | MipsCpuContext; - - interface PortableCpuContext { - pc: NativePointer; - sp: NativePointer; - } - - interface Ia32CpuContext extends PortableCpuContext { - eax: NativePointer; - ecx: NativePointer; - edx: NativePointer; - ebx: NativePointer; - esp: NativePointer; - ebp: NativePointer; - esi: NativePointer; - edi: NativePointer; - - eip: NativePointer; - } - - interface X64CpuContext extends PortableCpuContext { - rax: NativePointer; - rcx: NativePointer; - rdx: NativePointer; - rbx: NativePointer; - rsp: NativePointer; - rbp: NativePointer; - rsi: NativePointer; - rdi: NativePointer; - - r8: NativePointer; - r9: NativePointer; - r10: NativePointer; - r11: NativePointer; - r12: NativePointer; - r13: NativePointer; - r14: NativePointer; - r15: NativePointer; - - rip: NativePointer; - } - - interface ArmCpuContext extends PortableCpuContext { - r0: NativePointer; - r1: NativePointer; - r2: NativePointer; - r3: NativePointer; - r4: NativePointer; - r5: NativePointer; - r6: NativePointer; - r7: NativePointer; - - r8: NativePointer; - r9: NativePointer; - r10: NativePointer; - r11: NativePointer; - r12: NativePointer; - - lr: NativePointer; - } - - interface Arm64CpuContext extends PortableCpuContext { - x0: NativePointer; - x1: NativePointer; - x2: NativePointer; - x3: NativePointer; - x4: NativePointer; - x5: NativePointer; - x6: NativePointer; - x7: NativePointer; - x8: NativePointer; - x9: NativePointer; - x10: NativePointer; - x11: NativePointer; - x12: NativePointer; - x13: NativePointer; - x14: NativePointer; - x15: NativePointer; - x16: NativePointer; - x17: NativePointer; - x18: NativePointer; - x19: NativePointer; - x20: NativePointer; - x21: NativePointer; - x22: NativePointer; - x23: NativePointer; - x24: NativePointer; - x25: NativePointer; - x26: NativePointer; - x27: NativePointer; - x28: NativePointer; - - fp: NativePointer; - lr: NativePointer; - } - - interface MipsCpuContext extends PortableCpuContext { - gp: NativePointer; - fp: NativePointer; - ra: NativePointer; - - hi: NativePointer; - lo: NativePointer; - - at: NativePointer; - - v0: NativePointer; - v1: NativePointer; - - a0: NativePointer; - a1: NativePointer; - a2: NativePointer; - a3: NativePointer; - - t0: NativePointer; - t1: NativePointer; - t2: NativePointer; - t3: NativePointer; - t4: NativePointer; - t5: NativePointer; - t6: NativePointer; - t7: NativePointer; - t8: NativePointer; - t9: NativePointer; - - s0: NativePointer; - s1: NativePointer; - s2: NativePointer; - s3: NativePointer; - s4: NativePointer; - s5: NativePointer; - s6: NativePointer; - s7: NativePointer; - - k0: NativePointer; - k1: NativePointer; - } - - /** - * Helper used internally for source map parsing in order to provide helpful - * JavaScript stack-traces. - */ - declare class SourceMap { - /** - * Constructs a source map from JSON. - * - * @param json String containing the source map encoded as JSON. - */ - constructor(json: string); - - /** - * Attempts to map a generated source position back to the original. - * - * @param generatedPosition Position in generated code. - */ - resolve(generatedPosition: GeneratedSourcePosition): OriginalSourcePosition | null; - } - - interface GeneratedSourcePosition { - /** - * Line number. - */ - line: number; - - /** - * Column number, if available. - */ - column?: number | undefined; - } - - interface OriginalSourcePosition { - /** - * Source file name. - */ - source: string; - - /** - * Line number. - */ - line: number; - - /** - * Column number. - */ - column: number; - - /** - * Identifier, if available. - */ - name: string | null; - } - - /** - * TCP and UNIX sockets. - */ - declare namespace Socket { - /** - * Opens a TCP or UNIX listening socket. - * - * Defaults to listening on both IPv4 and IPv6, if supported, and binding on all interfaces on a randomly - * selected port. - */ - function listen(options?: SocketListenOptions): Promise; - - /** - * Connects to a TCP or UNIX server. - */ - function connect(options: SocketConnectOptions): Promise; - - /** - * Inspects the OS socket `handle` and returns its type, or `null` if invalid or unknown. - */ - function type(handle: number): SocketType | null; - - /** - * Inspects the OS socket `handle` and returns its local address, or `null` if invalid or unknown. - */ - function localAddress(handle: number): SocketEndpointAddress | null; - - /** - * Inspects the OS socket `handle` and returns its peer address, or `null` if invalid or unknown. - */ - function peerAddress(handle: number): SocketEndpointAddress | null; - } - - /** - * Listener created by `Socket.listen()`. - */ - type SocketListener = TcpListener | UnixListener; - - interface BaseListener { - /** - * Closes the listener, releasing resources related to it. Once the listener is closed, all other operations - * will fail. Closing a listener multiple times is allowed and will not result in an error. - */ - close(): Promise; - - /** - * Waits for the next client to connect. - */ - accept(): Promise; - } - - interface TcpListener extends BaseListener { - /** - * IP port being listened on. - */ - port: number; - } - - interface UnixListener extends BaseListener { - /** - * Path being listened on. - */ - path: string; - } - - declare abstract class SocketConnection extends IOStream { - /** - * Disables the Nagle algorithm if `noDelay` is `true`, otherwise enables it. The Nagle algorithm is enabled - * by default, so it is only necessary to call this method if you wish to optimize for low delay instead of - * high throughput. - */ - setNoDelay(noDelay: boolean): Promise; - } - - declare abstract class IOStream { - /** - * The `InputStream` to read from. - */ - input: InputStream; - - /** - * The `OutputStream` to write to. - */ - output: OutputStream; - - /** - * Closes the stream, releasing resources related to it. This will also close the individual input and output - * streams. Once the stream is closed, all other operations will fail. Closing a stream multiple times is allowed - * and will not result in an error. - */ - close(): Promise; - } - - declare abstract class InputStream { - /** - * Closes the stream, releasing resources related to it. Once the stream is closed, all other operations will fail. - * Closing a stream multiple times is allowed and will not result in an error. - */ - close(): Promise; - - /** - * Reads up to `size` bytes from the stream. The resulting buffer is up to `size` bytes long. End of stream is - * signalled through an empty buffer. - */ - read(size: number): Promise; - - /** - * Keeps reading from the stream until exactly `size` bytes have been consumed. The resulting buffer is exactly - * `size` bytes long. Premature error or end of stream results in an `Error` object with a `partialData` property - * containing the incomplete data. - */ - readAll(size: number): Promise; - } - - declare abstract class OutputStream { - /** - * Closes the stream, releasing resources related to it. Once the stream is closed, all other operations will fail. - * Closing a stream multiple times is allowed and will not result in an error. - */ - close(): Promise; - - /** - * Tries to write `data` to the stream. Returns how many bytes of `data` were written to the stream. - */ - write(data: ArrayBuffer | number[]): Promise; - - /** - * Keeps writing to the stream until all of `data` has been written. Premature error or end of stream results in an - * `Error` object with a `partialSize` property specifying how many bytes of `data` were written to the stream - * before the error occurred. - */ - writeAll(data: ArrayBuffer | number[]): Promise; - - /** - * Tries to write `size` bytes to the stream, reading them from `address`. Returns how many bytes were written - * to the stream. Premature error or end of stream results in an `Error` object with a `partialSize` property - * specifying how many bytes of `data` were written to the stream before the error occurred. - */ - writeMemoryRegion(address: NativePointerValue, size: number): Promise; - } - - /** - * Input stream backed by a file descriptor. - * - * Only available on UNIX-like OSes. - */ - declare class UnixInputStream extends InputStream { - /** - * Creates a new input stream from the specified file descriptor `fd`. - * - * @param fd File descriptor to read from. - * @param options Options to customize the stream. - */ - constructor(fd: number, options?: UnixStreamOptions); - } - - /** - * Output stream backed by a file descriptor. - * - * Only available on UNIX-like OSes. - */ - declare class UnixOutputStream extends OutputStream { - /** - * Creates a new output stream from the specified file descriptor `fd`. - * - * @param fd File descriptor to write to. - * @param options Options to customize the stream. - */ - constructor(fd: number, options?: UnixStreamOptions); - } - - /** - * Input stream backed by a Windows file handle. - * - * Only available on Windows. - */ - declare class Win32InputStream extends InputStream { - /** - * Creates a new input stream from the specified Windows file handle. - * - * @param handle Windows file `HANDLE` to read from. - * @param options Options to customize the stream. - */ - constructor(handle: NativePointerValue, options?: WindowsStreamOptions); - } - - /** - * Output stream backed by a Windows file handle. - * - * Only available on Windows. - */ - declare class Win32OutputStream extends OutputStream { - /** - * Creates a new output stream from the specified Windows file handle. - * - * @param handle Windows file `HANDLE` to write to. - * @param options Options to customize the stream. - */ - constructor(handle: NativePointerValue, options?: WindowsStreamOptions); - } - - interface UnixStreamOptions { - /** - * Whether the file descriptor should be closed when the stream is closed, - * either through `close()` or future garbage-collection. - */ - autoClose?: boolean | undefined; - } - - interface WindowsStreamOptions { - /** - * Whether the Windows `HANDLE` should be closed when the stream is closed, - * either through `close()` or future garbage-collection. - */ - autoClose?: boolean | undefined; - } - - type AddressFamily = - | "unix" - | "ipv4" - | "ipv6" - ; - - type SocketType = - | "tcp" - | "udp" - | "tcp6" - | "udp6" - | "unix:stream" - | "unix:dgram" - ; - - type UnixSocketType = - | "anonymous" - | "path" - | "abstract" - | "abstract-padded" - ; - - type SocketListenOptions = TcpListenOptions | UnixListenOptions; - - interface TcpListenOptions extends BaseListenOptions { - /** - * Address family. Omit to listen on both ipv4 and ipv6 – if supported by the OS. - */ - family?: "ipv4" | "ipv6" | undefined; - - /** - * Host or IP address to listen on. Omit to listen on all interfaces. - */ - host?: string | undefined; - - /** - * Port to listen on. Omit to listen on a randomly selected port. - */ - port?: number | undefined; - } - - interface UnixListenOptions extends BaseListenOptions { - /** - * Address family. - */ - family: "unix"; - - /** - * Type of UNIX socket to listen on. Defaults to UnixSocketType.Path. - */ - type?: UnixSocketType | undefined; - - /** - * UNIX socket path to listen on. - */ - path: string; - } - - interface BaseListenOptions { - /** - * Listen backlog. Defaults to 10. - */ - backlog?: number | undefined; - } - - type SocketConnectOptions = TcpConnectOptions | UnixConnectOptions; - - interface TcpConnectOptions { - /** - * Address family. Omit to determine based on the host specified. - */ - family?: "ipv4" | "ipv6" | undefined; - - /** - * Host or IP address to connect to. Defaults to `localhost`. - */ - host?: string | undefined; - - /** - * IP port to connect to. - */ - port: number; - - /** - * Whether to create a TLS connection. Defaults to `false`. - */ - tls?: boolean | undefined; - } - - interface UnixConnectOptions { - /** - * Address family. - */ - family: "unix"; - - /** - * Type of UNIX socket to connect to. Defaults to UnixSocketType.Path. - */ - type?: UnixSocketType | undefined; - - /** - * Path to UNIX socket to connect to. - */ - path: string; - - /** - * Whether to create a TLS connection. Defaults to `false`. - */ - tls?: boolean | undefined; - } - - type SocketEndpointAddress = TcpEndpointAddress | UnixEndpointAddress; - - interface TcpEndpointAddress { - /** - * IP address. - */ - ip: string; - - /** - * Port. - */ - port: number; - } - - interface UnixEndpointAddress { - /** - * UNIX socket path. - */ - path: string; - } - - /** - * Provides basic filesystem access. - */ - declare class File { - /** - * Opens or creates the file at `filePath` with `mode` specifying how - * it should be opened. For example `"wb"` to open the file for writing - * in binary mode. This is the same format as `fopen()` from the C - * standard library. - * - * @param filePath Path to file to open or create. - * @param mode Mode to use. - */ - constructor(filePath: string, mode: string); - - /** - * Synchronously writes `data` to the file. - * - * @param data Data to write. - */ - write(data: string | ArrayBuffer): void; - - /** - * Flushes any buffered data to the underlying file. - */ - flush(): void; - - /** - * Closes the file. You should call this function when you’re done with - * the file unless you are fine with this happening when the object is - * garbage-collected or the script is unloaded. - */ - close(): void; - } - - /** - * Provides read/write access to a SQLite database. Useful for persistence - * and to embed a cache in an agent. - */ - declare class SqliteDatabase { - /** - * Opens the SQLite v3 database at `path` on the filesystem. The database - * will by default be opened read-write, and the returned `SqliteDatabase` - * object will allow you to perform queries on it. Throws an exception if - * the database cannot be opened. - * - * @param path Filesystem path to database. - * @param options Options to customize how the database should be opened. - */ - static open(path: string, options?: SqliteOpenOptions): SqliteDatabase; - - /** - * Just like `open()` but the contents of the database is provided as a - * string containing its data, Base64-encoded. We recommend gzipping the - * database before Base64-encoding it, but this is optional and detected - * by looking for a gzip magic marker. The database is opened read-write, - * but is 100% in-memory and never touches the filesystem. Throws an - * exception if the database is malformed. - * - * This is useful for agents that need to bundle a cache of precomputed - * data, e.g. static analysis data used to guide dynamic analysis. - * - * @param encodedContents Base64-encoded database contents. - */ - static openInline(encodedContents: string): SqliteDatabase; - - /** - * Closes the database. You should call this function when you're done with - * the database, unless you are fine with this happening when the object is - * garbage-collected or the script is unloaded. - */ - close(): void; - - /** - * Executes a raw SQL query. Throws an exception if the query is invalid. - * - * The query's result is ignored, so this should only be used for queries - * for setting up the database, e.g. table creation. - * - * @param sql Text-representation of the SQL query. - */ - exec(sql: string): void; - - /** - * Compiles the provided SQL into a `SqliteStatement` object. Throws an - * exception if the query is invalid. - * - * @param sql Text-representation of the SQL query. - */ - prepare(sql: string): SqliteStatement; - - /** - * Dumps the database to a gzip-compressed blob encoded as Base64. - * - * This is useful for inlining a cache in your agent's code, loaded by - * calling `SqliteDatabase.openInline()`. - */ - dump(): string; - } - - interface SqliteOpenOptions { - flags?: SqliteOpenFlag[] | undefined; - } - - type SqliteOpenFlag = - | "readonly" - | "readwrite" - | "create" - ; - - /** - * Pre-compiled SQL statement. - */ - declare class SqliteStatement { - /** - * Binds the integer `value` to `index`. - * - * @param index 1-based index. - * @param value Integer value to bind. - */ - bindInteger(index: number, value: number): void; - - /** - * Binds the floating point `value` to `index`. - * - * @param index 1-based index. - * @param value Floating point value to bind. - */ - bindFloat(index: number, value: number): void; - - /** - * Binds the text `value` to `index`. - * @param index 1-based index. - * @param value Text value to bind. - */ - bindText(index: number, value: string): void; - - /** - * Binds the blob `bytes` to `index`. - * - * @param index 1-based index. - * @param bytes Blob value to bind. - */ - bindBlob(index: number, bytes: ArrayBuffer | number[] | string): void; - - /** - * Binds a `null` value to `index`. - * - * @param index 1-based index. - */ - bindNull(index: number): void; - - /** - * Either starts a new query and gets the first result, or moves to the - * next one. - * - * Returns an array containing the values in the order specified by the - * query, or `null` when the last result is reached. You should call - * `reset()` at that point if you intend to use this object again. - */ - step(): any[] | null; - - /** - * Resets internal state to allow subsequent queries. - */ - reset(): void; - } - - /** - * Intercepts execution through inline hooking. - */ - declare namespace Interceptor { - /** - * Intercepts calls to function/instruction at `target`. It is important - * to specify a `InstructionProbeCallback` if `target` is not the first - * instruction of a function. - * - * @param target Address of function/instruction to intercept. - * @param callbacksOrProbe Callbacks or instruction-level probe callback. - * @param data User data exposed to `NativeInvocationListenerCallbacks` - * through the `GumInvocationContext *`. - */ - function attach(target: NativePointerValue, callbacksOrProbe: InvocationListenerCallbacks | InstructionProbeCallback, - data?: NativePointerValue): InvocationListener; - - /** - * Detaches all previously attached listeners. - */ - function detachAll(): void; - - /** - * Replaces function at `target` with implementation at `replacement`. - * - * May be implemented using e.g. `NativeCallback` or `CModule`. - * - * @param target Address of function to replace. - * @param replacement Replacement implementation. - * @param data User data exposed to native replacement through the - * `GumInvocationContext *`, obtained using - * `gum_interceptor_get_current_invocation()`. - */ - function replace(target: NativePointerValue, replacement: NativePointerValue, - data?: NativePointerValue): void; - - /** - * Reverts the previously replaced function at `target`. - */ - function revert(target: NativePointerValue): void; - - /** - * Ensure any pending changes have been committed to memory. - */ - function flush(): void; - } - - declare class InvocationListener { - /** - * Detaches listener previously attached through `Interceptor#attach()`. - */ - detach(): void; - } - - /** - * Callbacks to invoke synchronously before and after a function call. - */ - type InvocationListenerCallbacks = ScriptInvocationListenerCallbacks | NativeInvocationListenerCallbacks; - - interface ScriptInvocationListenerCallbacks { - /** - * Called synchronously when a thread is about to enter the target function. - */ - onEnter?: ((this: InvocationContext, args: InvocationArguments) => void) | undefined; - - /** - * Called synchronously when a thread is about to leave the target function. - */ - onLeave?: ((this: InvocationContext, retval: InvocationReturnValue) => void) | undefined; - } - - interface NativeInvocationListenerCallbacks { - /** - * Called synchronously when a thread is about to enter the target function. - * - * Typically implemented using `CModule`. - * - * Signature: `void onEnter (GumInvocationContext * ic)` - */ - onEnter?: NativePointer | undefined; - - /** - * Called synchronously when a thread is about to leave the target function. - * - * Typically implemented using `CModule`. - * - * Signature: `void onLeave (GumInvocationContext * ic)` - */ - onLeave?: NativePointer | undefined; - } - - /** - * Callback to invoke when an instruction is about to be executed. - */ - type InstructionProbeCallback = (this: InvocationContext, args: InvocationArguments) => void; - - /** - * Virtual array providing access to the argument list. Agnostic to the number of arguments and their types. - */ - type InvocationArguments = NativePointer[]; - - /** - * Value that is about to be returned. - */ - declare class InvocationReturnValue extends NativePointer { - /** - * Replaces the return value that would otherwise be returned. - */ - replace(value: NativePointerValue): void; - } - - type InvocationContext = PortableInvocationContext | WindowsInvocationContext | UnixInvocationContext; - - interface PortableInvocationContext { - /** - * Return address. - */ - returnAddress: NativePointer; - - /** - * CPU registers. You may also update register values by assigning to these keys. - */ - context: CpuContext; - - /** - * OS thread ID. - */ - threadId: ThreadId; - - /** - * Call depth of relative to other invocations. - */ - depth: number; - - /** - * User-defined invocation data. Useful if you want to read an argument in `onEnter` and act on it in `onLeave`. - */ - [x: string]: any; - } - - interface WindowsInvocationContext extends PortableInvocationContext { - /** - * Current OS error value (you may replace it). - */ - lastError: number; - } - - interface UnixInvocationContext extends PortableInvocationContext { - /** - * Current errno value (you may replace it). - */ - errno: number; - } - - /** - * Follows execution on a per thread basis. - */ - declare namespace Stalker { - /** - * Marks a memory range as excluded. This means Stalker will not follow - * execution when encountering a call to an instruction in such a range. - * You will thus be able to observe/modify the arguments going in, and - * the return value coming back, but won't see the instructions that - * happened between. - * - * Useful to improve performance and reduce noise. - * - * @param range Range to exclude. - */ - function exclude(range: MemoryRange): void; - - /** - * Starts following the execution of a given thread. - * - * @param threadId Thread ID to start following the execution of, or the - * current thread if omitted. - * @param options Options to customize the instrumentation. - */ - function follow(threadId?: ThreadId, options?: StalkerOptions): void; - - /** - * Stops following the execution of a given thread. - * - * @param threadId Thread ID to stop following the execution of, or the - * current thread if omitted. - */ - function unfollow(threadId?: ThreadId): void; - - /** - * Parses a binary blob comprised of `Gum.Event` values. - * - * @param events Binary blob containing zero or more `Gum.Event` values. - * @param options Options for customizing the output. - */ - function parse(events: ArrayBuffer, options?: StalkerParseOptions): StalkerEventFull[] | StalkerEventBare[]; - - /** - * Flushes out any buffered events. Useful when you don't want to wait - * until the next `queueDrainInterval` tick. - */ - function flush(): void; - - /** - * Frees accumulated memory at a safe point after `unfollow()`. This is - * needed to avoid race-conditions where the thread just unfollowed is - * executing its last instructions. - */ - function garbageCollect(): void; - - /** - * Invalidates the current thread's translated code for a given basic block. - * Useful when providing a transform callback and wanting to dynamically - * adapt the instrumentation for a given basic block. This is much more - * efficient than unfollowing and re-following the thread, which would - * discard all cached translations and require all encountered basic blocks - * to be compiled from scratch. - * - * @param address Start address of basic block to invalidate. - */ - function invalidate(address: NativePointerValue): void; - - /** - * Invalidates a specific thread's translated code for a given basic block. - * Useful when providing a transform callback and wanting to dynamically - * adapt the instrumentation for a given basic block. This is much more - * efficient than unfollowing and re-following the thread, which would - * discard all cached translations and require all encountered basic blocks - * to be compiled from scratch. - * - * @param threadId Thread that should have some of its code invalidated. - * @param address Start address of basic block to invalidate. - */ - function invalidate(threadId: ThreadId, address: NativePointerValue): void; - - /** - * Calls `callback` synchronously when a call is made to `address`. - * Returns an id that can be passed to `removeCallProbe()` later. - * - * @param address Address of function to monitor stalked calls to. - * @param callback Function to be called synchronously when a stalked - * thread is about to call the function at `address`. - * @param data User data to be passed to `StalkerNativeCallProbeCallback`. - */ - function addCallProbe(address: NativePointerValue, callback: StalkerCallProbeCallback, - data?: NativePointerValue): StalkerCallProbeId; - - /** - * Removes a call probe added by `addCallProbe()`. - * - * @param callbackId ID of probe to remove. - */ - function removeCallProbe(callbackId: StalkerCallProbeId): void; - - /** - * How many times a piece of code needs to be executed before it is assumed - * it can be trusted to not mutate. Specify -1 for no trust (slow), 0 to - * trust code from the get-go, and N to trust code after it has been - * executed N times. - * - * Defaults to 1. - */ - let trustThreshold: number; - - /** - * Capacity of the event queue in number of events. - * - * Defaults to 16384 events. - */ - let queueCapacity: number; - - /** - * Time in milliseconds between each time the event queue is drained. - * - * Defaults to 250 ms, which means that the event queue is drained four - * times per second. You may also set this property to zero to disable - * periodic draining and instead call `Stalker.flush()` when you would - * like the queue to be drained. - */ - let queueDrainInterval: number; - } - - /** - * Options to customize Stalker's instrumentation. - * - * Note that the callbacks provided have a significant impact on performance. - * If you only need periodic call summaries but do not care about the raw - * events, or the other way around, make sure you omit the callback that you - * don't need; i.e. avoid putting your logic in `onCallSummary` and leaving - * `onReceive` in there as an empty callback. - */ - interface StalkerOptions { - /** - * Which events, if any, should be generated and periodically delivered to - * `onReceive()` and/or `onCallSummary()`. - */ - events?: { - /** - * Whether to generate events for CALL/BLR instructions. - */ - call?: boolean | undefined; - - /** - * Whether to generate events for RET instructions. - */ - ret?: boolean | undefined; - - /** - * Whether to generate events for all instructions. - * - * Not recommended as it's potentially a lot of data. - */ - exec?: boolean | undefined; - - /** - * Whether to generate an event whenever a basic block is executed. - * - * Useful to record a coarse execution trace. - */ - block?: boolean | undefined; - - /** - * Whether to generate an event whenever a basic block is compiled. - * - * Useful for coverage. - */ - compile?: boolean | undefined; - } | undefined; - - /** - * Callback that periodically receives batches of events. - * - * @param events Binary blob comprised of one or more `Gum.Event` structs. - * See `gumevent.h` for details about the format. - * Use `Stalker.parse()` to examine the data. - */ - onReceive?: ((events: ArrayBuffer) => void) | undefined; - - /** - * Callback that periodically receives a summary of `call` events that - * happened in each time window. - * - * You would typically implement this instead of `onReceive()` for - * efficiency, i.e. when you only want to know which targets were called - * and how many times, but don't care about the order that the calls - * happened in. - * - * @param summary Key-value mapping of call target to number of calls, in - * the current time window. - */ - onCallSummary?: ((summary: StalkerCallSummary) => void) | undefined; - - /** - * C callback that processes events as they occur, allowing synchronous - * processing of events in native code – typically implemented using - * CModule. - * - * This is useful when wanting to implement custom filtering and/or queuing - * logic to improve performance, or sacrifice performance in exchange for - * reliable event delivery. - * - * Note that this precludes usage of `onReceive()` and `onCallSummary()`. - */ - onEvent?: StalkerNativeEventCallback | undefined; - - /** - * Callback that transforms each basic block compiled whenever Stalker - * wants to recompile a basic block of the code that's about to be executed - * by the stalked thread. - */ - transform?: StalkerTransformCallback | undefined; - - /** - * User data to be passed to `StalkerNativeEventCallback` and `StalkerNativeTransformCallback`. - */ - data?: NativePointerValue | undefined; - } - - interface StalkerParseOptions { - /** - * Whether to include the type of each event. Defaults to `true`. - */ - annotate?: boolean | undefined; - - /** - * Whether to format pointer values as strings instead of `NativePointer` - * values, i.e. less overhead if you're just going to `send()` the result - * and not actually parse the data agent-side. - */ - stringify?: boolean | undefined; - } - - interface StalkerCallSummary { - [target: string]: number; - } - - type StalkerCallProbeCallback = StalkerScriptCallProbeCallback | StalkerNativeCallProbeCallback; - - /** - * Called synchronously when a call is made to the given address. - */ - type StalkerScriptCallProbeCallback = (args: InvocationArguments) => void; - - /** - * Called synchronously when a call is made to the given address. - * - * Signature: `void onCall (GumCallSite * site, gpointer user_data)` - */ - type StalkerNativeCallProbeCallback = NativePointer; - - type StalkerCallProbeId = number; - - type StalkerEventType = - | "call" - | "ret" - | "exec" - | "block" - | "compile" - ; - - type StalkerEventFull = StalkerCallEventFull | StalkerRetEventFull | StalkerExecEventFull | - StalkerBlockEventFull | StalkerCompileEventFull; - type StalkerEventBare = StalkerCallEventBare | StalkerRetEventBare | StalkerExecEventBare | - StalkerBlockEventBare | StalkerCompileEventBare; - - type StalkerCallEventFull = [ "call", NativePointer | string, NativePointer | string, number ]; - type StalkerCallEventBare = [ NativePointer | string, NativePointer | string, number ]; - - type StalkerRetEventFull = [ "ret", NativePointer | string, NativePointer | string, number ]; - type StalkerRetEventBare = [ NativePointer | string, NativePointer | string, number ]; - - type StalkerExecEventFull = [ "exec", NativePointer | string ]; - type StalkerExecEventBare = [ NativePointer | string ]; - - type StalkerBlockEventFull = [ "block", NativePointer | string, NativePointer | string ]; - type StalkerBlockEventBare = [ NativePointer | string, NativePointer | string ]; - - type StalkerCompileEventFull = [ "compile", NativePointer | string, NativePointer | string ]; - type StalkerCompileEventBare = [ NativePointer | string, NativePointer | string ]; - - /** - * Signature: `void process (const GumEvent * event, GumCpuContext * cpu_context, gpointer user_data)` - */ - type StalkerNativeEventCallback = NativePointer; - - type StalkerTransformCallback = - | StalkerX86TransformCallback - | StalkerArm32TransformCallback - | StalkerArm64TransformCallback - | StalkerNativeTransformCallback - ; - - type StalkerX86TransformCallback = (iterator: StalkerX86Iterator) => void; - type StalkerArm32TransformCallback = (iterator: StalkerArmIterator | StalkerThumbIterator) => void; - type StalkerArm64TransformCallback = (iterator: StalkerArm64Iterator) => void; - - /** - * Signature: `void transform (GumStalkerIterator * iterator, GumStalkerOutput * output, gpointer user_data)` - */ - type StalkerNativeTransformCallback = NativePointer; - - interface StalkerX86Iterator extends X86Writer { - next(): X86Instruction | null; - keep(): void; - putCallout(callout: StalkerCallout, data?: NativePointerValue): void; - } - - interface StalkerArmIterator extends ArmWriter { - next(): ArmInstruction | null; - keep(): void; - putCallout(callout: StalkerCallout, data?: NativePointerValue): void; - } - - interface StalkerThumbIterator extends ThumbWriter { - next(): ArmInstruction | null; - keep(): void; - putCallout(callout: StalkerCallout, data?: NativePointerValue): void; - } - - interface StalkerArm64Iterator extends Arm64Writer { - next(): Arm64Instruction | null; - keep(): void; - putCallout(callout: StalkerCallout, data?: NativePointerValue): void; - } - - type StalkerCallout = StalkerScriptCallout | StalkerNativeCallout; - - type StalkerScriptCallout = (context: CpuContext) => void; - - /** - * Signature: `void onAesEnc (GumCpuContext * cpu_context, gpointer user_data)` - */ - type StalkerNativeCallout = NativePointer; - - /** - * Provides efficient API resolving using globs, allowing you to quickly - * find functions by name, with globs permitted. - */ - declare class ApiResolver { - /** - * Creates a new resolver of the given `type`. - * - * Precisely which resolvers are available depends on the current - * platform and runtimes loaded in the current process. - * - * The resolver will load the minimum amount of data required on creation, - * and lazy-load the rest depending on the queries it receives. It is thus - * recommended to use the same instance for a batch of queries, but - * recreate it for future batches to avoid looking at stale data. - * - * @param type The type of resolver to create. - */ - constructor(type: ApiResolverType); - - /** - * Performs the resolver-specific query. - * - * @param query Resolver-specific query, optionally suffixed with `/i` to - * perform case-insensitive matching. - */ - enumerateMatches(query: string): ApiResolverMatch[]; - } - - interface ApiResolverMatch { - /** - * Canonical name of the function that was found. - */ - name: string; - - /** - * Memory address that the given function is loaded at. - */ - address: NativePointer; - } - - type ApiResolverType = - /** - * Resolves exported and imported functions of shared libraries - * currently loaded. - * - * Always available. - * - * Example query: `"exports:*!open*"` - * Which may resolve to: `"/usr/lib/libSystem.B.dylib!opendir$INODE64"` - * Suffix with `/i` to perform case-insensitive matching. - */ - | "module" - - /** - * Resolves Objective-C methods of classes currently loaded. - * - * Available on macOS and iOS in processes that have the Objective-C - * runtime loaded. Use `ObjC.available` to check at runtime, or wrap - * your `new ApiResolver(ApiResolverType.ObjC)` call in a try-catch. - * - * Example query: `"-[NSURL* *HTTP*]"` - * Which may resolve to: `"-[NSURLRequest valueForHTTPHeaderField:]"` - * Suffix with `/i` to perform case-insensitive matching. - */ - | "objc" - ; - - declare class DebugSymbol { - /** - * Address that this symbol is for. - */ - address: NativePointer; - - /** - * Name of the symbol, or `null` if unknown. - */ - name: string | null; - - /** - * Module name owning this symbol, or `null` if unknown. - */ - moduleName: string | null; - - /** - * File name owning this symbol, or `null` if unknown. - */ - fileName: string | null; - - /** - * Line number in `fileName`, or `null` if unknown. - */ - lineNumber: number | null; - - /** - * Looks up debug information for `address`. - * - * @param address Address to look up details for. - */ - static fromAddress(address: NativePointerValue): DebugSymbol; - - /** - * Looks up debug information for `name`. - * - * @param name Name to look up details for. - */ - static fromName(name: string): DebugSymbol; - - /** - * Resolves a function name and returns its address. Returns the first if - * more than one function is found. Throws an exception if the name cannot - * be resolved. - * - * @param name Function name to resolve the address of. - */ - static getFunctionByName(name: string): NativePointer; - - /** - * Resolves a function name and returns its addresses. - * - * @param name Function name to resolve the addresses of. - */ - static findFunctionsNamed(name: string): NativePointer[]; - - /** - * Resolves function names matching `glob` and returns their addresses. - * - * @param glob Glob matching functions to resolve the addresses of. - */ - static findFunctionsMatching(glob: string): NativePointer[]; - - /** - * Loads debug symbols for a specific module. - * - * @param path Path of module to load symbols for. - */ - static load(path: string): void; - - /** - * Converts to a human-readable string. - */ - toString(): string; - } - - /** - * Compiles C source code to machine code, straight to memory. May also be - * constructed from a precompiled shared library. - * - * Useful for implementing hot callbacks, e.g. for `Interceptor` and `Stalker`, - * but also useful when needing to start new threads in order to call functions - * in a tight loop, e.g. for fuzzing purposes. - * - * Global functions are automatically exported as `NativePointer` properties - * named exactly like in the C source code. This means you can pass them to - * `Interceptor` and `Stalker`, or call them using `NativeFunction`. - * - * In addition to accessing a curated subset of Gum, GLib, and standard C APIs, - * the code being mapped in can also communicate with JavaScript through the - * symbols exposed to it. These can be plugged in at creation, e.g. to share - * memory allocated using `Memory.alloc()`, or `NativeCallback` values for - * receiving callbacks from the C module. - * - * To perform initialization and cleanup, you may define functions with the - * following names and signatures: - * - * `void init (void)` - * `void finalize (void)` - * - * Note that all data is read-only, so writable globals should be declared - * `extern`, allocated using e.g. `Memory.alloc()`, and passed in as symbols - * through the constructor's second argument. - */ - declare class CModule { - /** - * Creates a new C module from the provided `code`. - * - * @param code C source code to compile, or a precompiled shared library. - * @param symbols Symbols to expose to the C module. Declare them as `extern`. - * This may for example be one or more memory blocks allocated using - * `Memory.alloc()`, and/or `NativeCallback` values for receiving - * callbacks from the C module. - * @param options Options for customizing the construction. - */ - constructor(code: string | ArrayBuffer, symbols?: CSymbols, options?: CModuleOptions); - - /** - * Eagerly unmaps the module from memory. Useful for short-lived modules - * when waiting for a future garbage collection isn't desirable. - */ - dispose(): void; - - readonly [name: string]: any; - - static builtins: CModuleBuiltins; - } - - interface CModuleOptions { - toolchain?: CModuleToolchain | undefined; - } - - /** - * Toolchain to use when constructing a CModule from C source code. - * - * `internal`: Use TinyCC, which is statically linked into the runtime. - * Never touches the filesystem and works even in sandboxed processes. - * The generated code is however not optimized, as TinyCC optimizes for - * small compiler footprint and short compilation times. - * `external`: Use toolchain provided by the target system, assuming it is - * accessible to the process we're executing inside. - * `any`: Same as `internal` if `Process.arch` is supported by TinyCC, and - * `external` otherwise. - */ - type CModuleToolchain = "any" | "internal" | "external"; - - interface CSymbols { - [name: string]: NativePointerValue; - } - - /** - * Builtins present when constructing a CModule from C source code. - * - * This is typically used by a scaffolding tool such as `frida-create` in order - * to set up a build environment that matches what CModule uses. - */ - interface CModuleBuiltins { - defines: CModuleDefines; - headers: CModuleHeaders; - } - - /** - * Preprocessor defines present when constructing a CModule from C source code. - * - * The mapping to GCC-style command-line arguments depends on the type of the value: - * `string`: `-Dname=value` - * `true`: `-Dname` - */ - interface CModuleDefines { - readonly [name: string]: string | true; - } - - /** - * C headers present when constructing a CModule from C source code. - * - * The `name` is a relative filesystem path, and the value is the contents of - * the header. - */ - interface CModuleHeaders { - readonly [name: string]: string; - } - - declare class Instruction { - /** - * Parses the instruction at the `target` address in memory. - * - * Note that on 32-bit ARM this address must have its least significant bit - * set to 0 for ARM functions, and 1 for Thumb functions. Frida takes care - * of this detail for you if you get the address from a Frida API, for - * example `Module.getExportByName()`. - * - * @param target Memory location containing instruction to parse. - */ - static parse(target: NativePointerValue): Instruction | X86Instruction | ArmInstruction | Arm64Instruction | MipsInstruction; - - /** - * Address (EIP) of this instruction. - */ - address: NativePointer; - - /** - * Pointer to the next instruction, so you can `parse()` it. - */ - next: NativePointer; - - /** - * Size of this instruction. - */ - size: number; - - /** - * Instruction mnemonic. - */ - mnemonic: string; - - /** - * String representation of instruction operands. - */ - opStr: string; - - /** - * Group names that this instruction belongs to. - */ - groups: string[]; - - /** - * Converts to a human-readable string. - */ - toString(): string; - } - - declare class X86Instruction extends Instruction { - /** - * Array of objects describing each operand. - */ - operands: X86Operand[]; - - /** - * Registers implicitly read by this instruction. - */ - regsRead: X86Register[]; - - /** - * Registers implicitly written to by this instruction. - */ - regsWritten: X86Register[]; - } - - declare class ArmInstruction extends Instruction { - /** - * Array of objects describing each operand. - */ - operands: ArmOperand[]; - - /** - * Registers implicitly read by this instruction. - */ - regsRead: ArmRegister[]; - - /** - * Registers implicitly written to by this instruction. - */ - regsWritten: ArmRegister[]; - } - - declare class Arm64Instruction extends Instruction { - /** - * Array of objects describing each operand. - */ - operands: Arm64Operand[]; - - /** - * Registers implicitly read by this instruction. - */ - regsRead: Arm64Register[]; - - /** - * Registers implicitly written to by this instruction. - */ - regsWritten: Arm64Register[]; - } - - declare class MipsInstruction extends Instruction { - /** - * Array of objects describing each operand. - */ - operands: MipsOperand[]; - - /** - * Registers implicitly read by this instruction. - */ - regsRead: MipsRegister[]; - - /** - * Registers implicitly written to by this instruction. - */ - regsWritten: MipsRegister[]; - } - - type X86Operand = X86RegOperand | X86ImmOperand | X86MemOperand; - - type X86OperandType = "reg" | "imm" | "mem"; - - interface X86BaseOperand { - size: number; - } - - interface X86RegOperand extends X86BaseOperand { - type: "reg"; - value: X86Register; - } - - interface X86ImmOperand extends X86BaseOperand { - type: "imm"; - value: number | Int64; - } - - interface X86MemOperand extends X86BaseOperand { - type: "mem"; - value: { - segment?: X86Register | undefined; - base?: X86Register | undefined; - index?: X86Register | undefined; - scale: number; - disp: number; - }; - } - - type ArmOperand = ArmRegOperand | ArmImmOperand | ArmMemOperand | - ArmFpOperand | ArmCimmOperand | ArmPimmOperand | ArmSetendOperand | - ArmSysregOperand; - - type ArmOperandType = - | "reg" - | "imm" - | "mem" - | "fp" - | "cimm" - | "pimm" - | "setend" - | "sysreg" - ; - - interface ArmBaseOperand { - shift?: { - type: ArmShifter; - value: number; - } | undefined; - vectorIndex?: number | undefined; - subtracted: boolean; - } - - interface ArmRegOperand extends ArmBaseOperand { - type: "reg"; - value: ArmRegister; - } - - interface ArmImmOperand extends ArmBaseOperand { - type: "imm"; - value: number; - } - - interface ArmMemOperand extends ArmBaseOperand { - type: "mem"; - value: { - base?: ArmRegister | undefined; - index?: ArmRegister | undefined; - scale: number; - disp: number; - }; - } - - interface ArmFpOperand extends ArmBaseOperand { - type: "fp"; - value: number; - } - - interface ArmCimmOperand extends ArmBaseOperand { - type: "cimm"; - value: number; - } - - interface ArmPimmOperand extends ArmBaseOperand { - type: "pimm"; - value: number; - } - - interface ArmSetendOperand extends ArmBaseOperand { - type: "setend"; - value: Endian; - } - - interface ArmSysregOperand extends ArmBaseOperand { - type: "sysreg"; - value: ArmRegister; - } - - type Arm64Operand = Arm64RegOperand | Arm64ImmOperand | Arm64MemOperand | - Arm64FpOperand | Arm64CimmOperand | Arm64RegMrsOperand | Arm64RegMsrOperand | - Arm64PstateOperand | Arm64SysOperand | Arm64PrefetchOperand | Arm64BarrierOperand; - - type Arm64OperandType = - | "reg" - | "imm" - | "mem" - | "fp" - | "cimm" - | "reg-mrs" - | "reg-msr" - | "pstate" - | "sys" - | "prefetch" - | "barrier" - ; - - interface Arm64BaseOperand { - shift?: { - type: Arm64Shifter; - value: number; - } | undefined; - ext?: Arm64Extender | undefined; - vas?: Arm64Vas | undefined; - vectorIndex?: number | undefined; - } - - interface Arm64RegOperand extends Arm64BaseOperand { - type: "reg"; - value: Arm64Register; - } - - interface Arm64ImmOperand extends Arm64BaseOperand { - type: "imm"; - value: Int64; - } - - interface Arm64MemOperand extends Arm64BaseOperand { - type: "mem"; - value: { - base?: Arm64Register | undefined; - index?: Arm64Register | undefined; - disp: number; - }; - } - - interface Arm64FpOperand extends Arm64BaseOperand { - type: "fp"; - value: number; - } - - interface Arm64CimmOperand extends Arm64BaseOperand { - type: "cimm"; - value: Int64; - } - - interface Arm64RegMrsOperand extends Arm64BaseOperand { - type: "reg-mrs"; - value: Arm64Register; - } - - interface Arm64RegMsrOperand extends Arm64BaseOperand { - type: "reg-msr"; - value: Arm64Register; - } - - interface Arm64PstateOperand extends Arm64BaseOperand { - type: "pstate"; - value: number; - } - - interface Arm64SysOperand extends Arm64BaseOperand { - type: "sys"; - value: number; - } - - interface Arm64PrefetchOperand extends Arm64BaseOperand { - type: "prefetch"; - value: number; - } - - interface Arm64BarrierOperand extends Arm64BaseOperand { - type: "barrier"; - value: number; - } - - type Arm64Shifter = - | "lsl" - | "msl" - | "lsr" - | "asr" - | "ror" - ; - - type Arm64Extender = - | "uxtb" - | "uxth" - | "uxtw" - | "uxtx" - | "sxtb" - | "sxth" - | "sxtw" - | "sxtx" - ; - - type Arm64Vas = - | "8b" - | "16b" - | "4h" - | "8h" - | "2s" - | "4s" - | "1d" - | "2d" - | "1q" - ; - - type MipsOperand = MipsRegOperand | MipsImmOperand | MipsMemOperand; - - type MipsOperandType = "reg" | "imm" | "mem"; - - interface MipsRegOperand { - type: "reg"; - value: MipsRegister; - } - - interface MipsImmOperand { - type: "imm"; - value: number; - } - - interface MipsMemOperand { - type: "mem"; - value: { - base?: MipsRegister | undefined; - disp: number; - }; - } - - type Endian = "be" | "le"; - - declare namespace Kernel { - /** - * Whether the Kernel API is available. - */ - const available: boolean; - - /** - * Base address of the kernel. Can be overridden with any non-zero UInt64. - */ - let base: UInt64; - - /** - * Size of kernel page in bytes. - */ - const pageSize: number; - - /** - * Enumerates kernel modules loaded right now. - */ - function enumerateModules(): KernelModuleDetails[]; - - /** - * Enumerates all kernel memory ranges matching `specifier`. - * - * @param specifier The kind of ranges to include. - */ - function enumerateRanges(specifier: PageProtection | EnumerateRangesSpecifier): KernelRangeDetails[]; - - /** - * Enumerates all ranges of a kernel module. - * - * @param name Name of the module, or `null` for the module of the kernel itself. - * @param protection Include ranges with at least this protection. - */ - function enumerateModuleRanges(name: string | null, protection: PageProtection): KernelModuleRangeDetails[]; - - /** - * Allocates kernel memory. - * - * @param size Size of the allocation in bytes (will be rounded up to a multiple of the kernel's page size). - */ - function alloc(size: number | UInt64): UInt64; - - /** - * Changes the page protection on a region of kernel memory. - * - * @param address Starting address. - * @param size Number of bytes. Must be a multiple of Process#pageSize. - * @param protection Desired page protection. - */ - function protect(address: UInt64, size: number | UInt64, protection: PageProtection): boolean; - - /** - * Scans kernel memory for occurences of `pattern` in the memory range given by `address` and `size`. - * - * @param address Starting address to scan from. - * @param size Number of bytes to scan. - * @param pattern Match pattern of the form “13 37 ?? ff” to match 0x13 followed by 0x37 followed by any byte - * followed by 0xff. For more advanced matching it is also possible to specify an r2-style mask. - * The mask is bitwise AND-ed against both the needle and the haystack. To specify the mask append - * a `:` character after the needle, followed by the mask using the same syntax. - * For example: “13 37 13 37 : 1f ff ff f1”. - * For convenience it is also possible to specify nibble-level wildcards, like “?3 37 13 ?7”, - * which gets translated into masks behind the scenes. - * @param callbacks Object with callbacks. - */ - function scan(address: UInt64, size: number | UInt64, pattern: string, callbacks: KernelMemoryScanCallbacks): void; - - /** - * Synchronous version of `scan()`. - * - * @param address Starting address to scan from. - * @param size Number of bytes to scan. - * @param pattern Match pattern, see `Memory.scan()` for details. - */ - function scanSync(address: UInt64, size: number | UInt64, pattern: string): KernelMemoryScanMatch[]; - - function readS8(address: UInt64): number; - function readU8(address: UInt64): number; - function readS16(address: UInt64): number; - function readU16(address: UInt64): number; - function readS32(address: UInt64): number; - function readU32(address: UInt64): number; - function readS64(address: UInt64): Int64; - function readU64(address: UInt64): UInt64; - function readShort(address: UInt64): number; - function readUShort(address: UInt64): number; - function readInt(address: UInt64): number; - function readUInt(address: UInt64): number; - function readLong(address: UInt64): number | Int64; - function readULong(address: UInt64): number | UInt64; - function readFloat(address: UInt64): number; - function readDouble(address: UInt64): number; - function readByteArray(address: UInt64, length: number): ArrayBuffer | null; - function readCString(address: UInt64, size: number): string | null; - function readUtf8String(address: UInt64, size: number): string | null; - function readUtf16String(address: UInt64, length: number): string | null; - - function writeS8(address: UInt64, value: number | Int64): void; - function writeU8(address: UInt64, value: number | UInt64): void; - function writeS16(address: UInt64, value: number | Int64): void; - function writeU16(address: UInt64, value: number | UInt64): void; - function writeS32(address: UInt64, value: number | Int64): void; - function writeU32(address: UInt64, value: number | UInt64): void; - function writeS64(address: UInt64, value: number | Int64): void; - function writeU64(address: UInt64, value: number | UInt64): void; - function writeShort(address: UInt64, value: number | Int64): void; - function writeUShort(address: UInt64, value: number | UInt64): void; - function writeInt(address: UInt64, value: number | Int64): void; - function writeUInt(address: UInt64, value: number | UInt64): void; - function writeLong(address: UInt64, value: number | Int64): void; - function writeULong(address: UInt64, value: number | UInt64): void; - function writeFloat(address: UInt64, value: number): void; - function writeDouble(address: UInt64, value: number): void; - function writeByteArray(address: UInt64, value: ArrayBuffer | number[]): void; - function writeUtf8String(address: UInt64, value: string): void; - function writeUtf16String(address: UInt64, value: string): void; - } - - declare namespace ObjC { - // tslint:disable:no-unnecessary-qualifier - - /** - * Whether the current process has an Objective-C runtime loaded. Do not invoke any other ObjC properties or - * methods unless this is the case. - */ - const available: boolean; - - /** - * Direct access to a big portion of the Objective-C runtime API. - */ - const api: { - [name: string]: any; - }; - - /** - * Dynamically generated bindings for each of the currently registered classes. - * - * You can interact with objects by using dot notation and replacing colons with underscores, i.e.: - * - * ``` - * [NSString stringWithString:@"Hello World"]; - * ``` - * - * becomes: - * - * ``` - * const NSString = ObjC.classes.NSString; - * NSString.stringWithString_("Hello World"); - * ``` - * - * Note the underscore after the method name. - */ - const classes: { - [name: string]: ObjC.Object - }; - - /** - * Dynamically generated bindings for each of the currently registered protocols. - */ - const protocols: { - [name: string]: Protocol - }; - - /** - * GCD queue of the main thread. - */ - const mainQueue: NativePointer; - - /** - * Schedule the JavaScript function `work` on the GCD queue specified by `queue`. An NSAutoreleasePool is created - * just before calling `work`, and cleaned up on return. - * - * E.g. on macOS: - * ``` - * const { NSSound } = ObjC.classes; - * ObjC.schedule(ObjC.mainQueue, () => { - * const sound = NSSound.alloc().initWithContentsOfFile_byReference_("/Users/oleavr/.Trash/test.mp3", true).autorelease(); - * sound.play(); - * }); - * ``` - * - * @param queue GCD queue to schedule `work` on. - * @param work Function to call on the specified `queue`. - */ - function schedule(queue: NativePointerValue, work: () => void): void; - - /** - * Dynamically generated wrapper for any Objective-C instance, class, or meta-class. - */ - class Object implements ObjectWrapper, ObjectMethods { - constructor(handle: NativePointer, protocol?: Protocol); - - handle: NativePointer; - - /** - * Whether this is an instance, class, or meta-class. - */ - $kind: ObjectKind; - - /** - * Instance used for chaining up to super-class method implementations. - */ - $super: ObjC.Object; - - /** - * Super-class of this object's class. - */ - $superClass: ObjC.Object; - - /** - * Class that this object is an instance of. - */ - $class: ObjC.Object; - - /** - * Class name of this object. - */ - $className: string; - - /** - * Name of module where this object is implemented. - */ - $moduleName: string; - - /** - * Protocols that this object conforms to. - */ - $protocols: { - [name: string]: Protocol; - }; - - /** - * Native method names exposed by this object’s class and parent classes. - */ - $methods: string[]; - - /** - * Native method names exposed by this object’s class, not including parent classes. - */ - $ownMethods: string[]; - - /** - * Instance variables on this object. Supports both access and assignment. - */ - $ivars: { - [name: string]: any; - }; - - /** - * Determines whether two instances refer to the same underlying object. - * - * @param other Other object instance or address to compare to. - */ - equals(other: ObjC.Object | NativePointer): boolean; - - [name: string]: any; - } - - interface ObjectMethods { - [name: string]: ObjectMethod; - } - - interface ObjectMethod extends ObjectWrapper, AnyFunction { - handle: NativePointer; - - /** - * Objective-C selector. Use `ObjC.selectorAsString()` to convert it to a string. - */ - selector: NativePointer; - - /** - * Current implementation. - * - * You may replace it by assigning to this property. See `ObjC.implement()` for details. - */ - implementation: NativePointer; - - /** - * Return type name. - */ - returnType: string; - - /** - * Argument type names. - */ - argumentTypes: string[]; - - /** - * Signature. - */ - types: string; - - /** - * Makes a new method wrapper with custom NativeFunction options. - * - * Useful for e.g. setting `traps: "all"` to perform execution tracing - * in conjunction with Stalker. - */ - clone: (options: NativeFunctionOptions) => ObjectMethod; - } - - /** - * What kind of object an ObjC.Object represents. - */ - type ObjectKind = "instance" | "class" | "meta-class"; - - /** - * Dynamically generated language binding for any Objective-C protocol. - */ - class Protocol implements ObjectWrapper { - constructor(handle: NativePointer); - - handle: NativePointer; - - /** - * Name visible to the Objective-C runtime. - */ - name: string; - - /** - * Protocols that this protocol conforms to. - */ - protocols: { - [name: string]: Protocol - }; - - /** - * Properties declared by this protocol. - */ - properties: { - [name: string]: ProtocolPropertyAttributes; - }; - - /** - * Methods declared by this protocol. - */ - methods: { - [name: string]: ProtocolMethodDescription; - }; - } - - interface ProtocolPropertyAttributes { - [name: string]: string; - } - - interface ProtocolMethodDescription { - /** - * Whether this method is required or optional. - */ - required: boolean; - - /** - * Method signature. - */ - types: string; - } - - /** - * Dynamically generated language binding for any Objective-C block. - * - * Also supports implementing a block from scratch by passing in an - * implementation. - */ - class Block implements ObjectWrapper { - constructor(target: NativePointer | MethodSpec, options?: NativeFunctionOptions); - - handle: NativePointer; - - /** - * Signature, if available. - */ - types?: string | undefined; - - /** - * Current implementation. You may replace it by assigning to this property. - */ - implementation: AnyFunction; - - /** - * Declares the signature of an externally defined block. This is needed - * when working with blocks without signature metadata, i.e. when - * `block.types === undefined`. - * - * @param signature Signature to use. - */ - declare(signature: BlockSignature): void; - } - - type BlockImplementation = (this: Block, ...args: any[]) => any; - - type BlockSignature = SimpleBlockSignature | DetailedBlockSignature; - - interface SimpleBlockSignature { - /** - * Return type. - */ - retType: string; - - /** - * Argument types. - */ - argTypes: string[]; - } - - interface DetailedBlockSignature { - /** - * Signature. - */ - types: string; - } - - /** - * Creates a JavaScript implementation compatible with the signature of `method`, where `fn` is used as the - * implementation. Returns a `NativeCallback` that you may assign to an ObjC method’s `implementation` property. - * - * @param method Method to implement. - * @param fn Implementation. - */ - function implement(method: ObjectMethod, fn: AnyFunction): NativeCallback; - - /** - * Creates a new class designed to act as a proxy for a target object. - * - * @param spec Proxy specification. - */ - function registerProxy(spec: ProxySpec): ProxyConstructor; - - /** - * Creates a new Objective-C class. - * - * @param spec Class specification. - */ - function registerClass(spec: ClassSpec): ObjC.Object; - - /** - * Creates a new Objective-C protocol. - * - * @param spec Protocol specification. - */ - function registerProtocol(spec: ProtocolSpec): Protocol; - - /** - * Binds some JavaScript data to an Objective-C instance. - * - * @param obj Objective-C instance to bind data to. - * @param data Data to bind. - */ - function bind(obj: ObjC.Object | NativePointer, data: InstanceData): void; - - /** - * Unbinds previously associated JavaScript data from an Objective-C instance. - * - * @param obj Objective-C instance to unbind data from. - */ - function unbind(obj: ObjC.Object | NativePointer): void; - - /** - * Looks up previously bound data from an Objective-C object. - * - * @param obj Objective-C instance to look up data for. - */ - function getBoundData(obj: ObjC.Object | NativePointer): any; - - /** - * Enumerates loaded classes. - * - * @param callbacks Object with callbacks. - */ - function enumerateLoadedClasses(callbacks: EnumerateLoadedClassesCallbacks): void; - - /** - * Enumerates loaded classes. - * - * @param options Options customizing the enumeration. - * @param callbacks Object with callbacks. - */ - function enumerateLoadedClasses(options: EnumerateLoadedClassesOptions, callbacks: EnumerateLoadedClassesCallbacks): void; - - /** - * Synchronous version of `enumerateLoadedClasses()`. - * - * @param options Options customizing the enumeration. - */ - function enumerateLoadedClassesSync(options?: EnumerateLoadedClassesOptions): EnumerateLoadedClassesResult; - - interface EnumerateLoadedClassesOptions { - /** - * Limit enumeration to modules in the given module map. - */ - ownedBy?: ModuleMap | undefined; - } - - interface EnumerateLoadedClassesCallbacks { - onMatch: (name: string, owner: string) => void; - onComplete: () => void; - } - - interface EnumerateLoadedClassesResult { - /** - * Class names grouped by name of owner module. - */ - [owner: string]: string[]; - } - - function choose(specifier: ChooseSpecifier, callbacks: EnumerateCallbacks): void; - - /** - * Synchronous version of `choose()`. - * - * @param specifier What kind of objects to look for. - */ - function chooseSync(specifier: ChooseSpecifier): ObjC.Object[]; - - /** - * Converts the JavaScript string `name` to a selector. - * - * @param name Name to turn into a selector. - */ - function selector(name: string): NativePointer; - - /** - * Converts the selector `sel` to a JavaScript string. - * - * @param sel Selector to turn into a string. - */ - function selectorAsString(sel: NativePointerValue): string; - - interface ProxySpec { - /** - * Name of the proxy class. - * - * Omit this if you don’t care about the globally visible name and would like the runtime to auto-generate one - * for you. - */ - name?: string | undefined; - - /** - * Protocols this proxy class conforms to. - */ - protocols?: Protocol[] | undefined; - - /** - * Methods to implement. - */ - methods?: { - [name: string]: UserMethodImplementation | MethodSpec>; - } | undefined; - - /** - * Callbacks for getting notified about events. - */ - events?: ProxyEventCallbacks | undefined; - } - - interface ProxyEventCallbacks { - /** - * Gets notified right after the object has been deallocated. - * - * This is where you might clean up any associated state. - */ - dealloc?(this: UserMethodInvocation): void; - - /** - * Gets notified about the method name that we’re about to forward - * a call to. - * - * This might be where you’d start out with a temporary callback - * that just logs the names to help you decide which methods to - * override. - * - * @param name Name of method that is about to get called. - */ - forward?(this: UserMethodInvocation, name: string): void; - } - - /** - * Constructor for instantiating a proxy object. - * - * @param target Target object to proxy to. - * @param data Object with arbitrary data. - */ - interface ProxyConstructor { - new (target: ObjC.Object | NativePointer, data?: InstanceData): ProxyInstance; - } - - interface ProxyInstance { - handle: NativePointer; - } - - interface ProxyData extends InstanceData { - /** - * This proxy's target object. - */ - target: ObjC.Object; - - /** - * Used by the implementation. - */ - events: {}; - } - - interface ClassSpec { - /** - * Name of the class. - * - * Omit this if you don’t care about the globally visible name and would like the runtime to auto-generate one - * for you. - */ - name?: string | undefined; - - /** - * Super-class, or `null` to create a new root class. Omit to inherit from `NSObject`. - */ - super?: ObjC.Object | null | undefined; - - /** - * Protocols this class conforms to. - */ - protocols?: Protocol[] | undefined; - - /** - * Methods to implement. - */ - methods?: { - [name: string]: UserMethodImplementation | MethodSpec>; - } | undefined; - } - - type MethodSpec = SimpleMethodSpec | DetailedMethodSpec; - - interface SimpleMethodSpec { - /** - * Return type. - */ - retType: string; - - /** - * Argument types. - */ - argTypes: string[]; - - /** - * Implementation. - */ - implementation: I; - } - - interface DetailedMethodSpec { - /** - * Signature. - */ - types: string; - - /** - * Implementation. - */ - implementation: I; - } - - type UserMethodImplementation = (this: UserMethodInvocation, ...args: any[]) => any; - - interface UserMethodInvocation { - self: T; - super: S; - data: D; - } - - /** - * User-defined data that can be accessed from method implementations. - */ - interface InstanceData { - [name: string]: any; - } - - interface ProtocolSpec { - /** - * Name of the protocol. - * - * Omit this if you don’t care about the globally visible name and would like the runtime to auto-generate one - * for you. - */ - name?: string | undefined; - - /** - * Protocols this protocol conforms to. - */ - protocols?: Protocol[] | undefined; - - methods?: { - [name: string]: ProtocolMethodSpec; - } | undefined; - } - - type ProtocolMethodSpec = SimpleProtocolMethodSpec | DetailedProtocolMethodSpec; - - interface SimpleProtocolMethodSpec { - /** - * Return type. - */ - retType: string; - - /** - * Argument types. - */ - argTypes: string[]; - - /** - * Whether this method is required or optional. Default is required. - */ - optional?: boolean | undefined; - } - - interface DetailedProtocolMethodSpec { - /** - * Method signature. - */ - types: string; - - /** - * Whether this method is required or optional. Default is required. - */ - optional?: boolean | undefined; - } - - type ChooseSpecifier = SimpleChooseSpecifier | DetailedChooseSpecifier; - - type SimpleChooseSpecifier = ObjC.Object; - - interface DetailedChooseSpecifier { - /** - * Which class to look for instances of. E.g.: `ObjC.classes.UIButton`. - */ - class: ObjC.Object; - - /** - * Whether you’re also interested in subclasses matching the given class selector. - * - * The default is to also include subclasses. - */ - subclasses?: boolean | undefined; - } - - // tslint:enable:no-unnecessary-qualifier - } - - declare namespace Java { - /** - * Whether the current process has a Java runtime loaded. Do not invoke any other Java properties or - * methods unless this is the case. - */ - const available: boolean; - - /** - * Which version of Android we're running on. - */ - const androidVersion: string; - - /** - * Calls `func` with the `obj` lock held. - * - * @param obj Instance whose lock to hold. - * @param fn Function to call with lock held. - */ - function synchronized(obj: Wrapper, fn: () => void): void; - - /** - * Enumerates loaded classes. - * - * @param callbacks Object with callbacks. - */ - function enumerateLoadedClasses(callbacks: EnumerateLoadedClassesCallbacks): void; - - /** - * Synchronous version of `enumerateLoadedClasses()`. - */ - function enumerateLoadedClassesSync(): string[]; - - /** - * Enumerates class loaders. - * - * You may pass such a loader to `Java.ClassFactory.get()` to be able to - * `.use()` classes on the specified class loader. - * - * @param callbacks Object with callbacks. - */ - function enumerateClassLoaders(callbacks: EnumerateClassLoadersCallbacks): void; - - /** - * Synchronous version of `enumerateClassLoaders()`. - */ - function enumerateClassLoadersSync(): Wrapper[]; - - /** - * Enumerates methods matching `query`. - * - * @param query Query specified as `class!method`, with globs permitted. May - * also be suffixed with `/` and one or more modifiers: - * - `i`: Case-insensitive matching. - * - `s`: Include method signatures, so e.g. `"putInt"` becomes - * `"putInt(java.lang.String, int): void"`. - * - `u`: User-defined classes only, ignoring system classes. - */ - function enumerateMethods(query: string): EnumerateMethodsMatchGroup[]; - - /** - * Runs `fn` on the main thread of the VM. - * - * @param fn Function to run on the main thread of the VM. - */ - function scheduleOnMainThread(fn: () => void): void; - - /** - * Ensures that the current thread is attached to the VM and calls `fn`. - * (This isn't necessary in callbacks from Java.) - * - * Will defer calling `fn` if the app's class loader is not available yet. - * Use `Java.performNow()` if access to the app's classes is not needed. - * - * @param fn Function to run while attached to the VM. - */ - function perform(fn: () => void): void; - - /** - * Ensures that the current thread is attached to the VM and calls `fn`. - * (This isn't necessary in callbacks from Java.) - * - * @param fn Function to run while attached to the VM. - */ - function performNow(fn: () => void): void; - - /** - * Dynamically generates a JavaScript wrapper for `className` that you can - * instantiate objects from by calling `$new()` on to invoke a constructor. - * Call `$dispose()` on an instance to clean it up explicitly, or wait for - * the JavaScript object to get garbage-collected, or script to get - * unloaded. Static and non-static methods are available, and you can even - * replace method implementations. - * - * Uses the app's class loader, but you may access classes on other loaders - * by calling `Java.ClassFactory.get()`. - * - * @param className Canonical class name to get a wrapper for. - */ - function use = {}>(className: string): Wrapper; - - /** - * Opens the .dex file at `filePath`. - * - * @param filePath Path to .dex to open. - */ - function openClassFile(filePath: string): DexFile; - - /** - * Enumerates live instances of the `className` class by scanning the Java - * VM's heap. - * - * @param className Name of class to enumerate instances of. - * @param callbacks Object with callbacks. - */ - function choose(className: string, callbacks: ChooseCallbacks): void; - - /** - * Duplicates a JavaScript wrapper for later use outside replacement method. - * - * @param obj An existing wrapper retrieved from `this` in replacement method. - */ - function retain = {}>(obj: Wrapper): Wrapper; - - /** - * Creates a JavaScript wrapper given the existing instance at `handle` of - * given class `klass` as returned from `Java.use()`. - * - * @param handle An existing wrapper or a JNI handle. - * @param klass Class wrapper for type to cast to. - */ - function cast = {}, To extends Members = {}>( - handle: Wrapper | NativePointerValue, - klass: Wrapper - ): Wrapper; - - /** - * Creates a Java array with elements of the specified `type`, from a - * JavaScript array `elements`. The resulting Java array behaves like - * a JS array, but can be passed by reference to Java APIs in order to - * allow them to modify its contents. - * - * @param type Type name of elements. - * @param elements Array of JavaScript values to use for constructing the - * Java array. - */ - function array(type: string, elements: any[]): any[]; - - /** - * Determines whether the caller is running on the main thread. - */ - function isMainThread(): boolean; - - /** - * Creates a new Java class. - * - * @param spec Object describing the class to be created. - */ - function registerClass(spec: ClassSpec): Wrapper; - - /** - * Forces the VM to execute everything with its interpreter. Necessary to - * prevent optimizations from bypassing method hooks in some cases, and - * allows ART's Instrumentation APIs to be used for tracing the runtime. - */ - function deoptimizeEverything(): void; - - /** - * Similar to deoptimizeEverything but only deoptimizes boot image code. - * Use with `dalvik.vm.dex2oat-flags --inline-max-code-units=0` for best - * results. - */ - function deoptimizeBootImage(): void; - - const vm: VM; - - /** - * The default class factory used to implement e.g. `Java.use()`. - * Uses the application's main class loader. - */ - const classFactory: ClassFactory; - - interface EnumerateLoadedClassesCallbacks { - /** - * Called with the name of each currently loaded class, and a JNI - * reference for its Java Class object. - * - * Pass the `name` to `Java.use()` to get a JavaScript wrapper. - * You may also `Java.cast()` the `handle` to `java.lang.Class`. - */ - onMatch: (name: string, handle: NativePointer) => void; - - /** - * Called when all loaded classes have been enumerated. - */ - onComplete: () => void; - } - - interface EnumerateClassLoadersCallbacks { - /** - * Called with a `java.lang.ClassLoader` wrapper for each class loader - * found in the VM. - */ - onMatch: (loader: Wrapper) => void; - - /** - * Called when all class loaders have been enumerated. - */ - onComplete: () => void; - } - - /** - * Matching methods grouped by class loader. - */ - interface EnumerateMethodsMatchGroup { - /** - * Class loader, or `null` for the bootstrap class loader. - * - * Typically passed to `ClassFactory.get()` to interact with classes of - * interest. - */ - loader: Wrapper | null; - - /** - * One or more matching classes that have one or more methods matching - * the given query. - */ - classes: [EnumerateMethodsMatchClass, ...EnumerateMethodsMatchClass[]]; - } - - /** - * Class matching query which has one or more matching methods. - */ - interface EnumerateMethodsMatchClass { - /** - * Class name that matched the given query. - */ - name: string; - - /** - * One or more matching method names, each followed by signature when - * the `s` modifier is used. - */ - methods: [string, ...string[]]; - } - - interface ChooseCallbacks { - /** - * Called with each live instance found with a ready-to-use `instance` - * just as if you would have called `Java.cast()` with a raw handle to - * this particular instance. - * - * May return `EnumerateAction.Stop` to stop the enumeration early. - */ - onMatch: (instance: Wrapper) => void | EnumerateAction; - - /** - * Called when all instances have been enumerated. - */ - onComplete: () => void; - } - - type Members = Record; - - /** - * Dynamically generated wrapper for any Java class, instance, or interface. - */ - type Wrapper = {}> = { - /** - * Automatically inject holder's type to all fields and methods - */ - [K in keyof T]: T[K] extends Field ? Field : MethodDispatcher - } & { - /** - * Allocates and initializes a new instance of the given class. - * - * Use this to create a new instance. - */ - $new: MethodDispatcher; - - /** - * Allocates a new instance without initializing it. - * - * Call `$init()` to initialize it. - */ - $alloc: MethodDispatcher; - - /** - * Initializes an instance that was allocated but not yet initialized. - * This wraps the constructor(s). - * - * Replace the `implementation` property to hook a given constructor. - */ - $init: MethodDispatcher; - - /** - * Eagerly deletes the underlying JNI global reference without having to - * wait for the object to become unreachable and the JavaScript - * runtime's garbage collector to kick in (or script to be unloaded). - * - * Useful when a lot of short-lived objects are created in a loop and - * there's a risk of running out of global handles. - */ - $dispose(): void; - - /** - * Retrieves a `java.lang.Class` wrapper for the current class. - */ - class: Wrapper; - - /** - * Canonical name of class being wrapped. - */ - $className: string; - - /** - * Method and field names exposed by this object’s class, not including - * parent classes. - */ - $ownMembers: string[]; - - /** - * Instance used for chaining up to super-class method implementations. - */ - $super: Wrapper; - - /** - * Methods and fields. - */ - [name: string]: any; - }; - - interface MethodDispatcher = {}> extends Method { - /** - * Available overloads. - */ - overloads: Array>; - - /** - * Obtains a specific overload. - * - * @param args Signature of the overload to obtain. - * For example: `"java.lang.String", "int"`. - */ - overload(...args: string[]): Method; - } - - interface Method = {}> { - (...params: any[]): any; - - /** - * Name of this method. - */ - methodName: string; - - /** - * Class that this method belongs to. - */ - holder: Wrapper; - - /** - * What kind of method this is, i.e. constructor vs static vs instance. - */ - type: MethodType; - - /** - * Pointer to the VM's underlying method object. - */ - handle: NativePointer; - - /** - * Implementation. Assign a new implementation to this property to - * replace the original implementation. Assign `null` at a future point - * to revert back to the original implementation. - */ - implementation: MethodImplementation | null; - - /** - * Method return type. - */ - returnType: Type; - - /** - * Method argument types. - */ - argumentTypes: Type[]; - - /** - * Queries whether the method may be invoked with a given argument list. - */ - canInvokeWith: (...args: any[]) => boolean; - - /** - * Makes a new method wrapper with custom NativeFunction options. - * - * Useful for e.g. setting `traps: "all"` to perform execution tracing - * in conjunction with Stalker. - */ - clone: (options: NativeFunctionOptions) => Method; - } - - type MethodImplementation = {}> = (this: Wrapper, ...params: any[]) => any; - - interface Field = {}> { - /** - * Current value of this field. Assign to update the field's value. - */ - value: Value; - - /** - * Class that this field belongs to. - */ - holder: Wrapper; - - /** - * What kind of field this is, i.e. static vs instance. - */ - fieldType: FieldType; - - /** - * Type of value. - */ - fieldReturnType: Type; - } - - // tslint:disable-next-line:no-const-enum - const enum MethodType { - Constructor = 1, - Static = 2, - Instance = 3, - } - - // tslint:disable-next-line:no-const-enum - const enum FieldType { - Static = 1, - Instance = 2, - } - - interface Type { - /** - * VM type name. For example `I` for `int`. - */ - name: string; - - /** - * Frida type name. For example `pointer` for a handle. - */ - type: string; - - /** - * Size in words. - */ - size: number; - - /** - * Size in bytes. - */ - byteSize: number; - - /** - * Class name, if applicable. - */ - className?: string | undefined; - - /** - * Checks whether a given JavaScript `value` is compatible. - */ - isCompatible: (value: any) => boolean; - - /** - * Converts `value` from a JNI value to a JavaScript value. - */ - fromJni?: ((value: any) => any) | undefined; - - /** - * Converts `value` from a JavaScript value to a JNI value. - */ - toJni?: ((value: any) => any) | undefined; - - /** - * Reads a value from memory. - */ - read?: ((address: NativePointerValue) => any) | undefined; - - /** - * Writes a value to memory. - */ - write?: ((address: NativePointerValue, value: any) => void) | undefined; - } - - interface DexFile { - /** - * Loads the contained classes into the VM. - */ - load(): void; - - /** - * Determines available class names. - */ - getClassNames(): string[]; - } - - interface ClassSpec { - /** - * Name of the class. - */ - name: string; - - /** - * Super-class. Omit to inherit from `java.lang.Object`. - */ - superClass?: Wrapper | undefined; - - /** - * Interfaces implemented by this class. - */ - implements?: Wrapper[] | undefined; - - /** - * Name and type of each field to expose. - */ - fields?: { - [name: string]: string; - } | undefined; - - /** - * Methods to implement. Use the special name `$init` to define one or more constructors. - */ - methods?: { - [name: string]: MethodImplementation | MethodSpec | MethodSpec[]; - } | undefined; - } - - interface MethodSpec { - /** - * Return type. Defaults to `void` if omitted. - */ - returnType?: string | undefined; - - /** - * Argument types. Defaults to `[]` if omitted. - */ - argumentTypes?: string[] | undefined; - - /** - * Implementation. - */ - implementation: MethodImplementation; - } - - interface VM { - /** - * Ensures that the current thread is attached to the VM and calls `fn`. - * (This isn't necessary in callbacks from Java.) - * - * @param fn Function to run while attached to the VM. - */ - perform(fn: () => void): void; - - /** - * Gets a wrapper for the current thread's `JNIEnv`. - * - * Throws an exception if the current thread is not attached to the VM. - */ - getEnv(): Env; - - /** - * Tries to get a wrapper for the current thread's `JNIEnv`. - * - * Returns `null` if the current thread is not attached to the VM. - */ - tryGetEnv(): Env | null; - } - - type Env = any; - - class ClassFactory { - /** - * Gets the class factory instance for a given class loader, or the - * default factory when passing `null`. - * - * The default class factory used behind the scenes only interacts - * with the application's main class loader. Other class loaders - * can be discovered through APIs such as `Java.enumerateMethods()` and - * `Java.enumerateClassLoaders()`, and subsequently interacted with - * through this API. - */ - static get(classLoader: Wrapper | null): ClassFactory; - - /** - * Class loader currently being used. For the default class factory this - * is updated by the first call to `Java.perform()`. - */ - readonly loader: Wrapper | null; - - /** - * Path to cache directory currently being used. For the default class - * factory this is updated by the first call to `Java.perform()`. - */ - cacheDir: string; - - /** - * Naming convention to use for temporary files. - * - * Defaults to `{ prefix: "frida", suffix: "dat" }`. - */ - tempFileNaming: TempFileNaming; - - /** - * Dynamically generates a JavaScript wrapper for `className` that you can - * instantiate objects from by calling `$new()` on to invoke a constructor. - * Call `$dispose()` on an instance to clean it up explicitly, or wait for - * the JavaScript object to get garbage-collected, or script to get - * unloaded. Static and non-static methods are available, and you can even - * replace method implementations. - * - * @param className Canonical class name to get a wrapper for. - */ - use = {}>(className: string): Wrapper; - - /** - * Opens the .dex file at `filePath`. - * - * @param filePath Path to .dex to open. - */ - openClassFile(filePath: string): DexFile; - - /** - * Enumerates live instances of the `className` class by scanning the Java - * VM's heap. - * - * @param className Name of class to enumerate instances of. - * @param callbacks Object with callbacks. - */ - choose(className: string, callbacks: ChooseCallbacks): void; - - /** - * Duplicates a JavaScript wrapper for later use outside replacement method. - * - * @param obj An existing wrapper retrieved from `this` in replacement method. - */ - retain = {}>(obj: Wrapper): Wrapper; - - /** - * Creates a JavaScript wrapper given the existing instance at `handle` of - * given class `klass` as returned from `Java.use()`. - * - * @param handle An existing wrapper or a JNI handle. - * @param klass Class wrapper for type to cast to. - */ - cast = {}, To extends Members = {}>( - handle: Wrapper | NativePointerValue, - klass: Wrapper - ): Wrapper; - - /** - * Creates a Java array with elements of the specified `type`, from a - * JavaScript array `elements`. The resulting Java array behaves like - * a JS array, but can be passed by reference to Java APIs in order to - * allow them to modify its contents. - * - * @param type Type name of elements. - * @param elements Array of JavaScript values to use for constructing the - * Java array. - */ - array(type: string, elements: any[]): any[]; - - /** - * Creates a new Java class. - * - * @param spec Object describing the class to be created. - */ - registerClass(spec: ClassSpec): Wrapper; - } - - interface TempFileNaming { - /** - * File name prefix to use. - * - * For example: `frida`. - */ - prefix: string; - - /** - * File name suffix to use. - * - * For example: `dat`. - */ - suffix: string; - } - } - - /** - * Generates machine code for x86. - */ - declare class X86Writer { - /** - * Creates a new code writer for generating x86 machine code - * written directly to memory at `codeAddress`. - * - * @param codeAddress Memory address to write generated code to. - * @param options Options for customizing code generation. - */ - constructor(codeAddress: NativePointerValue, options?: X86WriterOptions); - - /** - * Recycles instance. - */ - reset(codeAddress: NativePointerValue, options?: X86WriterOptions): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Resolves label references and writes pending data to memory. You - * should always call this once you've finished generating code. It - * is usually also desirable to do this between pieces of unrelated - * code, e.g. when generating multiple functions in one go. - */ - flush(): void; - - /** - * Memory location of the first byte of output. - */ - base: NativePointer; - - /** - * Memory location of the next byte of output. - */ - code: NativePointer; - - /** - * Program counter at the next byte of output. - */ - pc: NativePointer; - - /** - * Current offset in bytes. - */ - offset: number; - - /** - * Puts a label at the current position, where `id` is an identifier - * that may be referenced in past and future `put*Label()` calls. - */ - putLabel(id: string): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallAddressWithArguments(func: NativePointerValue, args: X86CallArgument[]): void; - - /** - * Like `putCallWithArguments()`, but also - * ensures that the argument list is aligned on a 16 byte boundary. - */ - putCallAddressWithAlignedArguments(func: NativePointerValue, args: X86CallArgument[]): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallRegWithArguments(reg: X86Register, args: X86CallArgument[]): void; - - /** - * Like `putCallWithArguments()`, but also - * ensures that the argument list is aligned on a 16 byte boundary. - */ - putCallRegWithAlignedArguments(reg: X86Register, args: X86CallArgument[]): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallRegOffsetPtrWithArguments(reg: X86Register, offset: number | Int64 | UInt64, args: X86CallArgument[]): void; - - /** - * Puts a CALL instruction. - */ - putCallAddress(address: NativePointerValue): void; - - /** - * Puts a CALL instruction. - */ - putCallReg(reg: X86Register): void; - - /** - * Puts a CALL instruction. - */ - putCallRegOffsetPtr(reg: X86Register, offset: number | Int64 | UInt64): void; - - /** - * Puts a CALL instruction. - */ - putCallIndirect(addr: NativePointerValue): void; - - /** - * Puts a CALL instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putCallIndirectLabel(labelId: string): void; - - /** - * Puts a CALL instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putCallNearLabel(labelId: string): void; - - /** - * Puts a LEAVE instruction. - */ - putLeave(): void; - - /** - * Puts a RET instruction. - */ - putRet(): void; - - /** - * Puts a RET instruction. - */ - putRetImm(immValue: number): void; - - /** - * Puts a JMP instruction. - */ - putJmpAddress(address: NativePointerValue): void; - - /** - * Puts a JMP instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putJmpShortLabel(labelId: string): void; - - /** - * Puts a JMP instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putJmpNearLabel(labelId: string): void; - - /** - * Puts a JMP instruction. - */ - putJmpReg(reg: X86Register): void; - - /** - * Puts a JMP instruction. - */ - putJmpRegPtr(reg: X86Register): void; - - /** - * Puts a JMP instruction. - */ - putJmpRegOffsetPtr(reg: X86Register, offset: number | Int64 | UInt64): void; - - /** - * Puts a JMP instruction. - */ - putJmpNearPtr(address: NativePointerValue): void; - - /** - * Puts a JCC instruction. - */ - putJccShort(instructionId: X86InstructionId, target: NativePointerValue, hint: X86BranchHint): void; - - /** - * Puts a JCC instruction. - */ - putJccNear(instructionId: X86InstructionId, target: NativePointerValue, hint: X86BranchHint): void; - - /** - * Puts a JCC instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putJccShortLabel(instructionId: X86InstructionId, labelId: string, hint: X86BranchHint): void; - - /** - * Puts a JCC instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putJccNearLabel(instructionId: X86InstructionId, labelId: string, hint: X86BranchHint): void; - - /** - * Puts an ADD instruction. - */ - putAddRegImm(reg: X86Register, immValue: number | Int64 | UInt64): void; - - /** - * Puts an ADD instruction. - */ - putAddRegReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts an ADD instruction. - */ - putAddRegNearPtr(dstReg: X86Register, srcAddress: NativePointerValue): void; - - /** - * Puts a SUB instruction. - */ - putSubRegImm(reg: X86Register, immValue: number | Int64 | UInt64): void; - - /** - * Puts a SUB instruction. - */ - putSubRegReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts a SUB instruction. - */ - putSubRegNearPtr(dstReg: X86Register, srcAddress: NativePointerValue): void; - - /** - * Puts an INC instruction. - */ - putIncReg(reg: X86Register): void; - - /** - * Puts a DEC instruction. - */ - putDecReg(reg: X86Register): void; - - /** - * Puts an INC instruction. - */ - putIncRegPtr(target: X86PointerTarget, reg: X86Register): void; - - /** - * Puts a DEC instruction. - */ - putDecRegPtr(target: X86PointerTarget, reg: X86Register): void; - - /** - * Puts a LOCK XADD instruction. - */ - putLockXaddRegPtrReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts a LOCK CMPXCHG instruction. - */ - putLockCmpxchgRegPtrReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts a LOCK INC IMM32 instruction. - */ - putLockIncImm32Ptr(target: NativePointerValue): void; - - /** - * Puts a LOCK DEC IMM32 instruction. - */ - putLockDecImm32Ptr(target: NativePointerValue): void; - - /** - * Puts an AND instruction. - */ - putAndRegReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts an AND instruction. - */ - putAndRegU32(reg: X86Register, immValue: number): void; - - /** - * Puts a SHL instruction. - */ - putShlRegU8(reg: X86Register, immValue: number): void; - - /** - * Puts a SHR instruction. - */ - putShrRegU8(reg: X86Register, immValue: number): void; - - /** - * Puts an XOR instruction. - */ - putXorRegReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts a MOV instruction. - */ - putMovRegReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts a MOV instruction. - */ - putMovRegU32(dstReg: X86Register, immValue: number): void; - - /** - * Puts a MOV instruction. - */ - putMovRegU64(dstReg: X86Register, immValue: number | UInt64): void; - - /** - * Puts a MOV instruction. - */ - putMovRegAddress(dstReg: X86Register, address: NativePointerValue): void; - - /** - * Puts a MOV instruction. - */ - putMovRegPtrU32(dstReg: X86Register, immValue: number): void; - - /** - * Puts a MOV instruction. - */ - putMovRegOffsetPtrU32(dstReg: X86Register, dstOffset: number | Int64 | UInt64, immValue: number): void; - - /** - * Puts a MOV instruction. - */ - putMovRegPtrReg(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts a MOV instruction. - */ - putMovRegOffsetPtrReg(dstReg: X86Register, dstOffset: number | Int64 | UInt64, srcReg: X86Register): void; - - /** - * Puts a MOV instruction. - */ - putMovRegRegPtr(dstReg: X86Register, srcReg: X86Register): void; - - /** - * Puts a MOV instruction. - */ - putMovRegRegOffsetPtr(dstReg: X86Register, srcReg: X86Register, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts a MOV instruction. - */ - putMovRegBaseIndexScaleOffsetPtr(dstReg: X86Register, baseReg: X86Register, indexReg: X86Register, scale: number, offset: number | Int64 | UInt64): void; - - /** - * Puts a MOV instruction. - */ - putMovRegNearPtr(dstReg: X86Register, srcAddress: NativePointerValue): void; - - /** - * Puts a MOV instruction. - */ - putMovNearPtrReg(dstAddress: NativePointerValue, srcReg: X86Register): void; - - /** - * Puts a MOV FS instruction. - */ - putMovFsU32PtrReg(fsOffset: number, srcReg: X86Register): void; - - /** - * Puts a MOV FS instruction. - */ - putMovRegFsU32Ptr(dstReg: X86Register, fsOffset: number): void; - - /** - * Puts a MOV GS instruction. - */ - putMovGsU32PtrReg(fsOffset: number, srcReg: X86Register): void; - - /** - * Puts a MOV GS instruction. - */ - putMovRegGsU32Ptr(dstReg: X86Register, fsOffset: number): void; - - /** - * Puts a MOVQ XMM0 ESP instruction. - */ - putMovqXmm0EspOffsetPtr(offset: number): void; - - /** - * Puts a MOVQ EAX XMM0 instruction. - */ - putMovqEaxOffsetPtrXmm0(offset: number): void; - - /** - * Puts a MOVDQU XMM0 ESP instruction. - */ - putMovdquXmm0EspOffsetPtr(offset: number): void; - - /** - * Puts a MOVDQU EAX XMM0 instruction. - */ - putMovdquEaxOffsetPtrXmm0(offset: number): void; - - /** - * Puts a LEA instruction. - */ - putLeaRegRegOffset(dstReg: X86Register, srcReg: X86Register, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts an XCHG instruction. - */ - putXchgRegRegPtr(leftReg: X86Register, rightReg: X86Register): void; - - /** - * Puts a PUSH instruction. - */ - putPushU32(immValue: number): void; - - /** - * Puts a PUSH instruction. - */ - putPushNearPtr(address: NativePointerValue): void; - - /** - * Puts a PUSH instruction. - */ - putPushReg(reg: X86Register): void; - - /** - * Puts a POP instruction. - */ - putPopReg(reg: X86Register): void; - - /** - * Puts a PUSH instruction. - */ - putPushImmPtr(immPtr: NativePointerValue): void; - - /** - * Puts a PUSHAX instruction. - */ - putPushax(): void; - - /** - * Puts a POPAX instruction. - */ - putPopax(): void; - - /** - * Puts a PUSHFX instruction. - */ - putPushfx(): void; - - /** - * Puts a POPFX instruction. - */ - putPopfx(): void; - - /** - * Puts a TEST instruction. - */ - putTestRegReg(regA: X86Register, regB: X86Register): void; - - /** - * Puts a TEST instruction. - */ - putTestRegU32(reg: X86Register, immValue: number): void; - - /** - * Puts a CMP instruction. - */ - putCmpRegI32(reg: X86Register, immValue: number): void; - - /** - * Puts a CMP instruction. - */ - putCmpRegOffsetPtrReg(regA: X86Register, offset: number | Int64 | UInt64, regB: X86Register): void; - - /** - * Puts a CMP instruction. - */ - putCmpImmPtrImmU32(immPtr: NativePointerValue, immValue: number): void; - - /** - * Puts a CMP instruction. - */ - putCmpRegReg(regA: X86Register, regB: X86Register): void; - - /** - * Puts a CLC instruction. - */ - putClc(): void; - - /** - * Puts a STC instruction. - */ - putStc(): void; - - /** - * Puts a CLD instruction. - */ - putCld(): void; - - /** - * Puts a STD instruction. - */ - putStd(): void; - - /** - * Puts a CPUID instruction. - */ - putCpuid(): void; - - /** - * Puts an LFENCE instruction. - */ - putLfence(): void; - - /** - * Puts an RDTSC instruction. - */ - putRdtsc(): void; - - /** - * Puts a PAUSE instruction. - */ - putPause(): void; - - /** - * Puts a NOP instruction. - */ - putNop(): void; - - /** - * Puts an OS/architecture-specific breakpoint instruction. - */ - putBreakpoint(): void; - - /** - * Puts `n` guard instruction. - */ - putPadding(n: number): void; - - /** - * Puts `n` NOP instructions. - */ - putNopPadding(n: number): void; - - /** - * Puts a uint8. - */ - putU8(value: number): void; - - /** - * Puts an int8. - */ - putS8(value: number): void; - - /** - * Puts raw data. - */ - putBytes(data: ArrayBuffer | number[] | string): void; - } - - interface X86WriterOptions { - /** - * Specifies the initial program counter, which is useful when - * generating code to a scratch buffer. This is essential when using - * `Memory.patchCode()` on iOS, which may provide you with a - * temporary location that later gets mapped into memory at the - * intended memory location. - */ - pc?: NativePointer | undefined; - } - - type X86CallArgument = X86Register | number | UInt64 | Int64 | NativePointerValue; - - /** - * Relocates machine code for x86. - */ - declare class X86Relocator { - /** - * Creates a new code relocator for copying x86 instructions - * from one memory location to another, taking care to adjust - * position-dependent instructions accordingly. - * - * @param inputCode Source address to copy instructions from. - * @param output X86Writer pointed at the desired target memory - * address. - */ - constructor(inputCode: NativePointerValue, output: X86Writer); - - /** - * Recycles instance. - */ - reset(inputCode: NativePointerValue, output: X86Writer): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Latest `Instruction` read so far. Starts out `null` and changes - * on every call to `readOne()`. - */ - input: Instruction | null; - - /** - * Indicates whether end-of-block has been reached, i.e. we've - * reached a branch of any kind, like CALL, JMP, BL, RET. - */ - eob: boolean; - - /** - * Indicates whether end-of-input has been reached, e.g. we've - * reached JMP/B/RET, an instruction after which there may or may - * not be valid code. - */ - eoi: boolean; - - /** - * Reads the next instruction into the relocator's internal buffer - * and returns the number of bytes read so far, including previous - * calls. - * - * You may keep calling this method to keep buffering, or immediately - * call either `writeOne()` or `skipOne()`. Or, you can buffer up - * until the desired point and then call `writeAll()`. - * - * Returns zero when end-of-input is reached, which means the `eoi` - * property is now `true`. - */ - readOne(): number; - - /** - * Peeks at the next `Instruction` to be written or skipped. - */ - peekNextWriteInsn(): Instruction | null; - - /** - * Peeks at the address of the next instruction to be written or skipped. - */ - peekNextWriteSource(): NativePointer; - - /** - * Skips the instruction that would have been written next. - */ - skipOne(): void; - - /** - * Skips the instruction that would have been written next, - * but without a label for internal use. This breaks relocation of branches to - * locations inside the relocated range, and is an optimization for use-cases - * where all branches are rewritten (e.g. Frida's Stalker). - */ - skipOneNoLabel(): void; - - /** - * Writes the next buffered instruction. - */ - writeOne(): boolean; - - /** - * Writes the next buffered instruction, but without a - * label for internal use. This breaks relocation of branches to locations - * inside the relocated range, and is an optimization for use-cases where all - * branches are rewritten (e.g. Frida's Stalker). - */ - writeOneNoLabel(): boolean; - - /** - * Writes all buffered instructions. - */ - writeAll(): void; - } - - type X86Register = - | "xax" - | "xcx" - | "xdx" - | "xbx" - | "xsp" - | "xbp" - | "xsi" - | "xdi" - | "eax" - | "ecx" - | "edx" - | "ebx" - | "esp" - | "ebp" - | "esi" - | "edi" - | "rax" - | "rcx" - | "rdx" - | "rbx" - | "rsp" - | "rbp" - | "rsi" - | "rdi" - | "r8" - | "r9" - | "r10" - | "r11" - | "r12" - | "r13" - | "r14" - | "r15" - | "r8d" - | "r9d" - | "r10d" - | "r11d" - | "r12d" - | "r13d" - | "r14d" - | "r15d" - | "xip" - | "eip" - | "rip" - ; - - type X86InstructionId = - | "jo" - | "jno" - | "jb" - | "jae" - | "je" - | "jne" - | "jbe" - | "ja" - | "js" - | "jns" - | "jp" - | "jnp" - | "jl" - | "jge" - | "jle" - | "jg" - | "jcxz" - | "jecxz" - | "jrcxz" - ; - - type X86BranchHint = "no-hint" | "likely" | "unlikely"; - - type X86PointerTarget = "byte" | "dword" | "qword"; - - /** - * Generates machine code for arm. - */ - declare class ArmWriter { - /** - * Creates a new code writer for generating ARM machine code - * written directly to memory at `codeAddress`. - * - * @param codeAddress Memory address to write generated code to. - * @param options Options for customizing code generation. - */ - constructor(codeAddress: NativePointerValue, options?: ArmWriterOptions); - - /** - * Recycles instance. - */ - reset(codeAddress: NativePointerValue, options?: ArmWriterOptions): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Resolves label references and writes pending data to memory. You - * should always call this once you've finished generating code. It - * is usually also desirable to do this between pieces of unrelated - * code, e.g. when generating multiple functions in one go. - */ - flush(): void; - - /** - * Memory location of the first byte of output. - */ - base: NativePointer; - - /** - * Memory location of the next byte of output. - */ - code: NativePointer; - - /** - * Program counter at the next byte of output. - */ - pc: NativePointer; - - /** - * Current offset in bytes. - */ - offset: number; - - /** - * Skips `nBytes`. - */ - skip(nBytes: number): void; - - /** - * Puts a label at the current position, where `id` is an identifier - * that may be referenced in past and future `put*Label()` calls. - */ - putLabel(id: string): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallAddressWithArguments(func: NativePointerValue, args: ArmCallArgument[]): void; - - /** - * Puts code needed for branching/jumping to the given address. - */ - putBranchAddress(address: NativePointerValue): void; - - /** - * Determines whether a direct branch is possible between the two - * given memory locations. - */ - canBranchDirectlyBetween(from: NativePointerValue, to: NativePointerValue): boolean; - - /** - * Puts a B instruction. - */ - putBImm(target: NativePointerValue): void; - - /** - * Puts a B COND instruction. - */ - putBCondImm(cc: ArmConditionCode, target: NativePointerValue): void; - - /** - * Puts a B instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBLabel(labelId: string): void; - - /** - * Puts a B COND instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBCondLabel(cc: ArmConditionCode, labelId: string): void; - - /** - * Puts a BL instruction. - */ - putBlImm(target: NativePointerValue): void; - - /** - * Puts a BLX instruction. - */ - putBlxImm(target: NativePointerValue): void; - - /** - * Puts a BL instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBlLabel(labelId: string): void; - - /** - * Puts a BX instruction. - */ - putBxReg(reg: ArmRegister): void; - - /** - * Puts a BLX instruction. - */ - putBlxReg(reg: ArmRegister): void; - - /** - * Puts a RET instruction. - */ - putRet(): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegAddress(reg: ArmRegister, address: NativePointerValue): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegU32(reg: ArmRegister, val: number): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegRegOffset(dstReg: ArmRegister, srcReg: ArmRegister, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts an LDR COND instruction. - */ - putLdrCondRegRegOffset(cc: ArmConditionCode, dstReg: ArmRegister, srcReg: ArmRegister, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts an LDMIA MASK instruction. - */ - putLdmiaRegMask(reg: ArmRegister, mask: number): void; - - /** - * Puts a STR instruction. - */ - putStrRegRegOffset(srcReg: ArmRegister, dstReg: ArmRegister, dstOffset: number | Int64 | UInt64): void; - - /** - * Puts a STR COND instruction. - */ - putStrCondRegRegOffset(cc: ArmConditionCode, srcReg: ArmRegister, dstReg: ArmRegister, dstOffset: number | Int64 | UInt64): void; - - /** - * Puts a MOV instruction. - */ - putMovRegReg(dstReg: ArmRegister, srcReg: ArmRegister): void; - - /** - * Puts a MOV SHIFT instruction. - */ - putMovRegRegShift(dstReg: ArmRegister, srcReg: ArmRegister, shift: ArmShifter, shiftValue: number): void; - - /** - * Puts a MOV CPSR instruction. - */ - putMovRegCpsr(reg: ArmRegister): void; - - /** - * Puts a MOV CPSR instruction. - */ - putMovCpsrReg(reg: ArmRegister): void; - - /** - * Puts an ADD U16 instruction. - */ - putAddRegU16(dstReg: ArmRegister, val: number): void; - - /** - * Puts an ADD instruction. - */ - putAddRegU32(dstReg: ArmRegister, val: number): void; - - /** - * Puts an ADD instruction. - */ - putAddRegRegImm(dstReg: ArmRegister, srcReg: ArmRegister, immVal: number): void; - - /** - * Puts an ADD instruction. - */ - putAddRegRegReg(dstReg: ArmRegister, srcReg1: ArmRegister, srcReg2: ArmRegister): void; - - /** - * Puts an ADD SHIFT instruction. - */ - putAddRegRegRegShift(dstReg: ArmRegister, srcReg1: ArmRegister, srcReg2: ArmRegister, shift: ArmShifter, shiftValue: number): void; - - /** - * Puts a SUB U16 instruction. - */ - putSubRegU16(dstReg: ArmRegister, val: number): void; - - /** - * Puts a SUB instruction. - */ - putSubRegU32(dstReg: ArmRegister, val: number): void; - - /** - * Puts a SUB instruction. - */ - putSubRegRegImm(dstReg: ArmRegister, srcReg: ArmRegister, immVal: number): void; - - /** - * Puts a SUB instruction. - */ - putSubRegRegReg(dstReg: ArmRegister, srcReg1: ArmRegister, srcReg2: ArmRegister): void; - - /** - * Puts an ANDS instruction. - */ - putAndsRegRegImm(dstReg: ArmRegister, srcReg: ArmRegister, immVal: number): void; - - /** - * Puts a CMP instruction. - */ - putCmpRegImm(dstReg: ArmRegister, immVal: number): void; - - /** - * Puts a NOP instruction. - */ - putNop(): void; - - /** - * Puts an OS/architecture-specific breakpoint instruction. - */ - putBreakpoint(): void; - - /** - * Puts a BRK instruction. - */ - putBrkImm(imm: number): void; - - /** - * Puts a raw instruction. - */ - putInstruction(insn: number): void; - - /** - * Puts raw data. - */ - putBytes(data: ArrayBuffer | number[] | string): void; - } - - interface ArmWriterOptions { - /** - * Specifies the initial program counter, which is useful when - * generating code to a scratch buffer. This is essential when using - * `Memory.patchCode()` on iOS, which may provide you with a - * temporary location that later gets mapped into memory at the - * intended memory location. - */ - pc?: NativePointer | undefined; - } - - type ArmCallArgument = ArmRegister | number | UInt64 | Int64 | NativePointerValue; - - /** - * Relocates machine code for arm. - */ - declare class ArmRelocator { - /** - * Creates a new code relocator for copying ARM instructions - * from one memory location to another, taking care to adjust - * position-dependent instructions accordingly. - * - * @param inputCode Source address to copy instructions from. - * @param output ArmWriter pointed at the desired target memory - * address. - */ - constructor(inputCode: NativePointerValue, output: ArmWriter); - - /** - * Recycles instance. - */ - reset(inputCode: NativePointerValue, output: ArmWriter): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Latest `Instruction` read so far. Starts out `null` and changes - * on every call to `readOne()`. - */ - input: Instruction | null; - - /** - * Indicates whether end-of-block has been reached, i.e. we've - * reached a branch of any kind, like CALL, JMP, BL, RET. - */ - eob: boolean; - - /** - * Indicates whether end-of-input has been reached, e.g. we've - * reached JMP/B/RET, an instruction after which there may or may - * not be valid code. - */ - eoi: boolean; - - /** - * Reads the next instruction into the relocator's internal buffer - * and returns the number of bytes read so far, including previous - * calls. - * - * You may keep calling this method to keep buffering, or immediately - * call either `writeOne()` or `skipOne()`. Or, you can buffer up - * until the desired point and then call `writeAll()`. - * - * Returns zero when end-of-input is reached, which means the `eoi` - * property is now `true`. - */ - readOne(): number; - - /** - * Peeks at the next `Instruction` to be written or skipped. - */ - peekNextWriteInsn(): Instruction | null; - - /** - * Peeks at the address of the next instruction to be written or skipped. - */ - peekNextWriteSource(): NativePointer; - - /** - * Skips the instruction that would have been written next. - */ - skipOne(): void; - - /** - * Writes the next buffered instruction. - */ - writeOne(): boolean; - - /** - * Writes all buffered instructions. - */ - writeAll(): void; - } - - /** - * Generates machine code for arm. - */ - declare class ThumbWriter { - /** - * Creates a new code writer for generating ARM machine code - * written directly to memory at `codeAddress`. - * - * @param codeAddress Memory address to write generated code to. - * @param options Options for customizing code generation. - */ - constructor(codeAddress: NativePointerValue, options?: ThumbWriterOptions); - - /** - * Recycles instance. - */ - reset(codeAddress: NativePointerValue, options?: ThumbWriterOptions): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Resolves label references and writes pending data to memory. You - * should always call this once you've finished generating code. It - * is usually also desirable to do this between pieces of unrelated - * code, e.g. when generating multiple functions in one go. - */ - flush(): void; - - /** - * Memory location of the first byte of output. - */ - base: NativePointer; - - /** - * Memory location of the next byte of output. - */ - code: NativePointer; - - /** - * Program counter at the next byte of output. - */ - pc: NativePointer; - - /** - * Current offset in bytes. - */ - offset: number; - - /** - * Skips `nBytes`. - */ - skip(nBytes: number): void; - - /** - * Puts a label at the current position, where `id` is an identifier - * that may be referenced in past and future `put*Label()` calls. - */ - putLabel(id: string): void; - - /** - * Commits the first pending reference to the given label, returning - * `true` on success. Returns `false` if the given label hasn't been - * defined yet, or there are no more pending references to it. - */ - commitLabel(id: string): boolean; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallAddressWithArguments(func: NativePointerValue, args: ArmCallArgument[]): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallRegWithArguments(reg: ArmRegister, args: ArmCallArgument[]): void; - - /** - * Puts a B instruction. - */ - putBImm(target: NativePointerValue): void; - - /** - * Puts a B instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBLabel(labelId: string): void; - - /** - * Puts a B WIDE instruction. - */ - putBLabelWide(labelId: string): void; - - /** - * Puts a BX instruction. - */ - putBxReg(reg: ArmRegister): void; - - /** - * Puts a BL instruction. - */ - putBlImm(target: NativePointerValue): void; - - /** - * Puts a BL instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBlLabel(labelId: string): void; - - /** - * Puts a BLX instruction. - */ - putBlxImm(target: NativePointerValue): void; - - /** - * Puts a BLX instruction. - */ - putBlxReg(reg: ArmRegister): void; - - /** - * Puts a CMP instruction. - */ - putCmpRegImm(reg: ArmRegister, immValue: number): void; - - /** - * Puts a BEQ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBeqLabel(labelId: string): void; - - /** - * Puts a BNE instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBneLabel(labelId: string): void; - - /** - * Puts a B COND instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBCondLabel(cc: ArmConditionCode, labelId: string): void; - - /** - * Puts a B COND WIDE instruction. - */ - putBCondLabelWide(cc: ArmConditionCode, labelId: string): void; - - /** - * Puts a CBZ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putCbzRegLabel(reg: ArmRegister, labelId: string): void; - - /** - * Puts a CBNZ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putCbnzRegLabel(reg: ArmRegister, labelId: string): void; - - /** - * Puts a PUSH instruction with the specified registers. - */ - putPushRegs(regs: ArmRegister[]): void; - - /** - * Puts a POP instruction with the specified registers. - */ - putPopRegs(regs: ArmRegister[]): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegAddress(reg: ArmRegister, address: NativePointerValue): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegU32(reg: ArmRegister, val: number): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegReg(dstReg: ArmRegister, srcReg: ArmRegister): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegRegOffset(dstReg: ArmRegister, srcReg: ArmRegister, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts an LDRB instruction. - */ - putLdrbRegReg(dstReg: ArmRegister, srcReg: ArmRegister): void; - - /** - * Puts a VLDR instruction. - */ - putVldrRegRegOffset(dstReg: ArmRegister, srcReg: ArmRegister, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts an LDMIA MASK instruction. - */ - putLdmiaRegMask(reg: ArmRegister, mask: number): void; - - /** - * Puts a STR instruction. - */ - putStrRegReg(srcReg: ArmRegister, dstReg: ArmRegister): void; - - /** - * Puts a STR instruction. - */ - putStrRegRegOffset(srcReg: ArmRegister, dstReg: ArmRegister, dstOffset: number | Int64 | UInt64): void; - - /** - * Puts a MOV instruction. - */ - putMovRegReg(dstReg: ArmRegister, srcReg: ArmRegister): void; - - /** - * Puts a MOV instruction. - */ - putMovRegU8(dstReg: ArmRegister, immValue: number): void; - - /** - * Puts a MOV CPSR instruction. - */ - putMovRegCpsr(reg: ArmRegister): void; - - /** - * Puts a MOV CPSR instruction. - */ - putMovCpsrReg(reg: ArmRegister): void; - - /** - * Puts an ADD instruction. - */ - putAddRegImm(dstReg: ArmRegister, immValue: number | Int64 | UInt64): void; - - /** - * Puts an ADD instruction. - */ - putAddRegReg(dstReg: ArmRegister, srcReg: ArmRegister): void; - - /** - * Puts an ADD instruction. - */ - putAddRegRegReg(dstReg: ArmRegister, leftReg: ArmRegister, rightReg: ArmRegister): void; - - /** - * Puts an ADD instruction. - */ - putAddRegRegImm(dstReg: ArmRegister, leftReg: ArmRegister, rightValue: number | Int64 | UInt64): void; - - /** - * Puts a SUB instruction. - */ - putSubRegImm(dstReg: ArmRegister, immValue: number | Int64 | UInt64): void; - - /** - * Puts a SUB instruction. - */ - putSubRegReg(dstReg: ArmRegister, srcReg: ArmRegister): void; - - /** - * Puts a SUB instruction. - */ - putSubRegRegReg(dstReg: ArmRegister, leftReg: ArmRegister, rightReg: ArmRegister): void; - - /** - * Puts a SUB instruction. - */ - putSubRegRegImm(dstReg: ArmRegister, leftReg: ArmRegister, rightValue: number | Int64 | UInt64): void; - - /** - * Puts an AND instruction. - */ - putAndRegRegImm(dstReg: ArmRegister, leftReg: ArmRegister, rightValue: number | Int64 | UInt64): void; - - /** - * Puts a LSLS instruction. - */ - putLslsRegRegImm(dstReg: ArmRegister, leftReg: ArmRegister, rightValue: number): void; - - /** - * Puts a LSRS instruction. - */ - putLsrsRegRegImm(dstReg: ArmRegister, leftReg: ArmRegister, rightValue: number): void; - - /** - * Puts a MRS instruction. - */ - putMrsRegReg(dstReg: ArmRegister, srcReg: ArmSystemRegister): void; - - /** - * Puts a MSR instruction. - */ - putMsrRegReg(dstReg: ArmSystemRegister, srcReg: ArmRegister): void; - - /** - * Puts a NOP instruction. - */ - putNop(): void; - - /** - * Puts a BKPT instruction. - */ - putBkptImm(imm: number): void; - - /** - * Puts an OS/architecture-specific breakpoint instruction. - */ - putBreakpoint(): void; - - /** - * Puts a raw instruction. - */ - putInstruction(insn: number): void; - - /** - * Puts a raw Thumb-2 instruction. - */ - putInstructionWide(upper: number, lower: number): void; - - /** - * Puts raw data. - */ - putBytes(data: ArrayBuffer | number[] | string): void; - } - - interface ThumbWriterOptions { - /** - * Specifies the initial program counter, which is useful when - * generating code to a scratch buffer. This is essential when using - * `Memory.patchCode()` on iOS, which may provide you with a - * temporary location that later gets mapped into memory at the - * intended memory location. - */ - pc?: NativePointer | undefined; - } - - /** - * Relocates machine code for arm. - */ - declare class ThumbRelocator { - /** - * Creates a new code relocator for copying ARM instructions - * from one memory location to another, taking care to adjust - * position-dependent instructions accordingly. - * - * @param inputCode Source address to copy instructions from. - * @param output ThumbWriter pointed at the desired target memory - * address. - */ - constructor(inputCode: NativePointerValue, output: ThumbWriter); - - /** - * Recycles instance. - */ - reset(inputCode: NativePointerValue, output: ThumbWriter): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Latest `Instruction` read so far. Starts out `null` and changes - * on every call to `readOne()`. - */ - input: Instruction | null; - - /** - * Indicates whether end-of-block has been reached, i.e. we've - * reached a branch of any kind, like CALL, JMP, BL, RET. - */ - eob: boolean; - - /** - * Indicates whether end-of-input has been reached, e.g. we've - * reached JMP/B/RET, an instruction after which there may or may - * not be valid code. - */ - eoi: boolean; - - /** - * Reads the next instruction into the relocator's internal buffer - * and returns the number of bytes read so far, including previous - * calls. - * - * You may keep calling this method to keep buffering, or immediately - * call either `writeOne()` or `skipOne()`. Or, you can buffer up - * until the desired point and then call `writeAll()`. - * - * Returns zero when end-of-input is reached, which means the `eoi` - * property is now `true`. - */ - readOne(): number; - - /** - * Peeks at the next `Instruction` to be written or skipped. - */ - peekNextWriteInsn(): Instruction | null; - - /** - * Peeks at the address of the next instruction to be written or skipped. - */ - peekNextWriteSource(): NativePointer; - - /** - * Skips the instruction that would have been written next. - */ - skipOne(): void; - - /** - * Writes the next buffered instruction. - */ - writeOne(): boolean; - - /** - * Copies out the next buffered instruction without advancing the - * output cursor, allowing the same instruction to be written out - * multiple times. - */ - copyOne(): boolean; - - /** - * Writes all buffered instructions. - */ - writeAll(): void; - } - - type ArmRegister = - | "r0" - | "r1" - | "r2" - | "r3" - | "r4" - | "r5" - | "r6" - | "r7" - | "r8" - | "r9" - | "r10" - | "r11" - | "r12" - | "r13" - | "r14" - | "r15" - | "sp" - | "lr" - | "sb" - | "sl" - | "fp" - | "ip" - | "pc" - ; - - type ArmSystemRegister = "apsr-nzcvq"; - - type ArmConditionCode = - | "eq" - | "ne" - | "hs" - | "lo" - | "mi" - | "pl" - | "vs" - | "vc" - | "hi" - | "ls" - | "ge" - | "lt" - | "gt" - | "le" - | "al" - ; - - type ArmShifter = - | "asr" - | "lsl" - | "lsr" - | "ror" - | "rrx" - | "asr-reg" - | "lsl-reg" - | "lsr-reg" - | "ror-reg" - | "rrx-reg" - ; - - /** - * Generates machine code for arm64. - */ - declare class Arm64Writer { - /** - * Creates a new code writer for generating AArch64 machine code - * written directly to memory at `codeAddress`. - * - * @param codeAddress Memory address to write generated code to. - * @param options Options for customizing code generation. - */ - constructor(codeAddress: NativePointerValue, options?: Arm64WriterOptions); - - /** - * Recycles instance. - */ - reset(codeAddress: NativePointerValue, options?: Arm64WriterOptions): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Resolves label references and writes pending data to memory. You - * should always call this once you've finished generating code. It - * is usually also desirable to do this between pieces of unrelated - * code, e.g. when generating multiple functions in one go. - */ - flush(): void; - - /** - * Memory location of the first byte of output. - */ - base: NativePointer; - - /** - * Memory location of the next byte of output. - */ - code: NativePointer; - - /** - * Program counter at the next byte of output. - */ - pc: NativePointer; - - /** - * Current offset in bytes. - */ - offset: number; - - /** - * Skips `nBytes`. - */ - skip(nBytes: number): void; - - /** - * Puts a label at the current position, where `id` is an identifier - * that may be referenced in past and future `put*Label()` calls. - */ - putLabel(id: string): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallAddressWithArguments(func: NativePointerValue, args: Arm64CallArgument[]): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallRegWithArguments(reg: Arm64Register, args: Arm64CallArgument[]): void; - - /** - * Puts code needed for branching/jumping to the given address. - */ - putBranchAddress(address: NativePointerValue): void; - - /** - * Determines whether a direct branch is possible between the two - * given memory locations. - */ - canBranchDirectlyBetween(from: NativePointerValue, to: NativePointerValue): boolean; - - /** - * Puts a B instruction. - */ - putBImm(address: NativePointerValue): void; - - /** - * Puts a B instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBLabel(labelId: string): void; - - /** - * Puts a B COND instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBCondLabel(cc: Arm64ConditionCode, labelId: string): void; - - /** - * Puts a BL instruction. - */ - putBlImm(address: NativePointerValue): void; - - /** - * Puts a BL instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBlLabel(labelId: string): void; - - /** - * Puts a BR instruction. - */ - putBrReg(reg: Arm64Register): void; - - /** - * Puts a BR instruction expecting a raw pointer without - * any authentication bits. - */ - putBrRegNoAuth(reg: Arm64Register): void; - - /** - * Puts a BLR instruction. - */ - putBlrReg(reg: Arm64Register): void; - - /** - * Puts a BLR instruction expecting a raw pointer without - * any authentication bits. - */ - putBlrRegNoAuth(reg: Arm64Register): void; - - /** - * Puts a RET instruction. - */ - putRet(): void; - - /** - * Puts a CBZ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putCbzRegLabel(reg: Arm64Register, labelId: string): void; - - /** - * Puts a CBNZ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putCbnzRegLabel(reg: Arm64Register, labelId: string): void; - - /** - * Puts a TBZ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putTbzRegImmLabel(reg: Arm64Register, bit: number, labelId: string): void; - - /** - * Puts a TBNZ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putTbnzRegImmLabel(reg: Arm64Register, bit: number, labelId: string): void; - - /** - * Puts a PUSH instruction. - */ - putPushRegReg(regA: Arm64Register, regB: Arm64Register): void; - - /** - * Puts a POP instruction. - */ - putPopRegReg(regA: Arm64Register, regB: Arm64Register): void; - - /** - * Puts code needed for pushing all X registers on the stack. - */ - putPushAllXRegisters(): void; - - /** - * Puts code needed for popping all X registers off the stack. - */ - putPopAllXRegisters(): void; - - /** - * Puts code needed for pushing all Q registers on the stack. - */ - putPushAllQRegisters(): void; - - /** - * Puts code needed for popping all Q registers off the stack. - */ - putPopAllQRegisters(): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegAddress(reg: Arm64Register, address: NativePointerValue): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegU64(reg: Arm64Register, val: number | UInt64): void; - - /** - * Puts an LDR instruction with a dangling data reference, - * returning an opaque ref value that should be passed to `putLdrRegValue()` - * at the desired location. - */ - putLdrRegRef(reg: Arm64Register): number; - - /** - * Puts the value and updates the LDR instruction - * from a previous `putLdrRegRef()`. - */ - putLdrRegValue(ref: number, value: NativePointerValue): void; - - /** - * Puts an LDR instruction. - */ - putLdrRegRegOffset(dstReg: Arm64Register, srcReg: Arm64Register, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts an LDRSW instruction. - */ - putLdrswRegRegOffset(dstReg: Arm64Register, srcReg: Arm64Register, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts an ADRP instruction. - */ - putAdrpRegAddress(reg: Arm64Register, address: NativePointerValue): void; - - /** - * Puts a STR instruction. - */ - putStrRegRegOffset(srcReg: Arm64Register, dstReg: Arm64Register, dstOffset: number | Int64 | UInt64): void; - - /** - * Puts an LDP instruction. - */ - putLdpRegRegRegOffset(regA: Arm64Register, regB: Arm64Register, regSrc: Arm64Register, srcOffset: number | Int64 | UInt64, mode: Arm64IndexMode): void; - - /** - * Puts a STP instruction. - */ - putStpRegRegRegOffset(regA: Arm64Register, regB: Arm64Register, regDst: Arm64Register, dstOffset: number | Int64 | UInt64, mode: Arm64IndexMode): void; - - /** - * Puts a MOV instruction. - */ - putMovRegReg(dstReg: Arm64Register, srcReg: Arm64Register): void; - - /** - * Puts an UXTW instruction. - */ - putUxtwRegReg(dstReg: Arm64Register, srcReg: Arm64Register): void; - - /** - * Puts an ADD instruction. - */ - putAddRegRegImm(dstReg: Arm64Register, leftReg: Arm64Register, rightValue: number | Int64 | UInt64): void; - - /** - * Puts an ADD instruction. - */ - putAddRegRegReg(dstReg: Arm64Register, leftReg: Arm64Register, rightReg: Arm64Register): void; - - /** - * Puts a SUB instruction. - */ - putSubRegRegImm(dstReg: Arm64Register, leftReg: Arm64Register, rightValue: number | Int64 | UInt64): void; - - /** - * Puts a SUB instruction. - */ - putSubRegRegReg(dstReg: Arm64Register, leftReg: Arm64Register, rightReg: Arm64Register): void; - - /** - * Puts an AND instruction. - */ - putAndRegRegImm(dstReg: Arm64Register, leftReg: Arm64Register, rightValue: number | Int64 | UInt64): void; - - /** - * Puts a TST instruction. - */ - putTstRegImm(reg: Arm64Register, immValue: number | UInt64): void; - - /** - * Puts a CMP instruction. - */ - putCmpRegReg(regA: Arm64Register, regB: Arm64Register): void; - - /** - * Puts an XPACI instruction. - */ - putXpaciReg(reg: Arm64Register): void; - - /** - * Puts a NOP instruction. - */ - putNop(): void; - - /** - * Puts a BRK instruction. - */ - putBrkImm(imm: number): void; - - /** - * Puts a raw instruction. - */ - putInstruction(insn: number): void; - - /** - * Puts raw data. - */ - putBytes(data: ArrayBuffer | number[] | string): void; - - /** - * Signs the given pointer value. - */ - sign(value: NativePointerValue): NativePointer; - } - - interface Arm64WriterOptions { - /** - * Specifies the initial program counter, which is useful when - * generating code to a scratch buffer. This is essential when using - * `Memory.patchCode()` on iOS, which may provide you with a - * temporary location that later gets mapped into memory at the - * intended memory location. - */ - pc?: NativePointer | undefined; - } - - type Arm64CallArgument = Arm64Register | number | UInt64 | Int64 | NativePointerValue; - - /** - * Relocates machine code for arm64. - */ - declare class Arm64Relocator { - /** - * Creates a new code relocator for copying AArch64 instructions - * from one memory location to another, taking care to adjust - * position-dependent instructions accordingly. - * - * @param inputCode Source address to copy instructions from. - * @param output Arm64Writer pointed at the desired target memory - * address. - */ - constructor(inputCode: NativePointerValue, output: Arm64Writer); - - /** - * Recycles instance. - */ - reset(inputCode: NativePointerValue, output: Arm64Writer): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Latest `Instruction` read so far. Starts out `null` and changes - * on every call to `readOne()`. - */ - input: Instruction | null; - - /** - * Indicates whether end-of-block has been reached, i.e. we've - * reached a branch of any kind, like CALL, JMP, BL, RET. - */ - eob: boolean; - - /** - * Indicates whether end-of-input has been reached, e.g. we've - * reached JMP/B/RET, an instruction after which there may or may - * not be valid code. - */ - eoi: boolean; - - /** - * Reads the next instruction into the relocator's internal buffer - * and returns the number of bytes read so far, including previous - * calls. - * - * You may keep calling this method to keep buffering, or immediately - * call either `writeOne()` or `skipOne()`. Or, you can buffer up - * until the desired point and then call `writeAll()`. - * - * Returns zero when end-of-input is reached, which means the `eoi` - * property is now `true`. - */ - readOne(): number; - - /** - * Peeks at the next `Instruction` to be written or skipped. - */ - peekNextWriteInsn(): Instruction | null; - - /** - * Peeks at the address of the next instruction to be written or skipped. - */ - peekNextWriteSource(): NativePointer; - - /** - * Skips the instruction that would have been written next. - */ - skipOne(): void; - - /** - * Writes the next buffered instruction. - */ - writeOne(): boolean; - - /** - * Writes all buffered instructions. - */ - writeAll(): void; - } - - type Arm64Register = - | "x0" - | "x1" - | "x2" - | "x3" - | "x4" - | "x5" - | "x6" - | "x7" - | "x8" - | "x9" - | "x10" - | "x11" - | "x12" - | "x13" - | "x14" - | "x15" - | "x16" - | "x17" - | "x18" - | "x19" - | "x20" - | "x21" - | "x22" - | "x23" - | "x24" - | "x25" - | "x26" - | "x27" - | "x28" - | "x29" - | "x30" - | "w0" - | "w1" - | "w2" - | "w3" - | "w4" - | "w5" - | "w6" - | "w7" - | "w8" - | "w9" - | "w10" - | "w11" - | "w12" - | "w13" - | "w14" - | "w15" - | "w16" - | "w17" - | "w18" - | "w19" - | "w20" - | "w21" - | "w22" - | "w23" - | "w24" - | "w25" - | "w26" - | "w27" - | "w28" - | "w29" - | "w30" - | "sp" - | "lr" - | "fp" - | "wsp" - | "wzr" - | "xzr" - | "nzcv" - | "ip0" - | "ip1" - | "s0" - | "s1" - | "s2" - | "s3" - | "s4" - | "s5" - | "s6" - | "s7" - | "s8" - | "s9" - | "s10" - | "s11" - | "s12" - | "s13" - | "s14" - | "s15" - | "s16" - | "s17" - | "s18" - | "s19" - | "s20" - | "s21" - | "s22" - | "s23" - | "s24" - | "s25" - | "s26" - | "s27" - | "s28" - | "s29" - | "s30" - | "s31" - | "d0" - | "d1" - | "d2" - | "d3" - | "d4" - | "d5" - | "d6" - | "d7" - | "d8" - | "d9" - | "d10" - | "d11" - | "d12" - | "d13" - | "d14" - | "d15" - | "d16" - | "d17" - | "d18" - | "d19" - | "d20" - | "d21" - | "d22" - | "d23" - | "d24" - | "d25" - | "d26" - | "d27" - | "d28" - | "d29" - | "d30" - | "d31" - | "q0" - | "q1" - | "q2" - | "q3" - | "q4" - | "q5" - | "q6" - | "q7" - | "q8" - | "q9" - | "q10" - | "q11" - | "q12" - | "q13" - | "q14" - | "q15" - | "q16" - | "q17" - | "q18" - | "q19" - | "q20" - | "q21" - | "q22" - | "q23" - | "q24" - | "q25" - | "q26" - | "q27" - | "q28" - | "q29" - | "q30" - | "q31" - ; - - type Arm64ConditionCode = - | "eq" - | "ne" - | "hs" - | "lo" - | "mi" - | "pl" - | "vs" - | "vc" - | "hi" - | "ls" - | "ge" - | "lt" - | "gt" - | "le" - | "al" - | "nv" - ; - - type Arm64IndexMode = "post-adjust" | "signed-offset" | "pre-adjust"; - - /** - * Generates machine code for mips. - */ - declare class MipsWriter { - /** - * Creates a new code writer for generating MIPS machine code - * written directly to memory at `codeAddress`. - * - * @param codeAddress Memory address to write generated code to. - * @param options Options for customizing code generation. - */ - constructor(codeAddress: NativePointerValue, options?: MipsWriterOptions); - - /** - * Recycles instance. - */ - reset(codeAddress: NativePointerValue, options?: MipsWriterOptions): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Resolves label references and writes pending data to memory. You - * should always call this once you've finished generating code. It - * is usually also desirable to do this between pieces of unrelated - * code, e.g. when generating multiple functions in one go. - */ - flush(): void; - - /** - * Memory location of the first byte of output. - */ - base: NativePointer; - - /** - * Memory location of the next byte of output. - */ - code: NativePointer; - - /** - * Program counter at the next byte of output. - */ - pc: NativePointer; - - /** - * Current offset in bytes. - */ - offset: number; - - /** - * Skips `nBytes`. - */ - skip(nBytes: number): void; - - /** - * Puts a label at the current position, where `id` is an identifier - * that may be referenced in past and future `put*Label()` calls. - */ - putLabel(id: string): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallAddressWithArguments(func: NativePointerValue, args: MipsCallArgument[]): void; - - /** - * Puts code needed for calling a C function with the specified `args`. - */ - putCallRegWithArguments(reg: MipsRegister, args: MipsCallArgument[]): void; - - /** - * Puts a J instruction. - */ - putJAddress(address: NativePointerValue): void; - - /** - * Puts a J WITHOUT NOP instruction. - */ - putJAddressWithoutNop(address: NativePointerValue): void; - - /** - * Puts a J instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putJLabel(labelId: string): void; - - /** - * Puts a JR instruction. - */ - putJrReg(reg: MipsRegister): void; - - /** - * Puts a JAL instruction. - */ - putJalAddress(address: number): void; - - /** - * Puts a JALR instruction. - */ - putJalrReg(reg: MipsRegister): void; - - /** - * Puts a B instruction. - */ - putBOffset(offset: number): void; - - /** - * Puts a BEQ instruction referencing `labelId`, defined by a past - * or future `putLabel()`. - */ - putBeqRegRegLabel(rightReg: MipsRegister, leftReg: MipsRegister, labelId: string): void; - - /** - * Puts a RET instruction. - */ - putRet(): void; - - /** - * Puts a LA instruction. - */ - putLaRegAddress(reg: MipsRegister, address: NativePointerValue): void; - - /** - * Puts a LUI instruction. - */ - putLuiRegImm(reg: MipsRegister, imm: number): void; - - /** - * Puts a DSLL instruction. - */ - putDsllRegReg(dstReg: MipsRegister, srcReg: MipsRegister, amount: number): void; - - /** - * Puts an ORI instruction. - */ - putOriRegRegImm(rt: MipsRegister, rs: MipsRegister, imm: number): void; - - /** - * Puts an LD instruction. - */ - putLdRegRegOffset(dstReg: MipsRegister, srcReg: MipsRegister, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts a LW instruction. - */ - putLwRegRegOffset(dstReg: MipsRegister, srcReg: MipsRegister, srcOffset: number | Int64 | UInt64): void; - - /** - * Puts a SW instruction. - */ - putSwRegRegOffset(srcReg: MipsRegister, dstReg: MipsRegister, dstOffset: number | Int64 | UInt64): void; - - /** - * Puts a MOVE instruction. - */ - putMoveRegReg(dstReg: MipsRegister, srcReg: MipsRegister): void; - - /** - * Puts an ADDU instruction. - */ - putAdduRegRegReg(dstReg: MipsRegister, leftReg: MipsRegister, rightReg: MipsRegister): void; - - /** - * Puts an ADDI instruction. - */ - putAddiRegRegImm(dstReg: MipsRegister, leftReg: MipsRegister, imm: number): void; - - /** - * Puts an ADDI instruction. - */ - putAddiRegImm(dstReg: MipsRegister, imm: number): void; - - /** - * Puts a SUB instruction. - */ - putSubRegRegImm(dstReg: MipsRegister, leftReg: MipsRegister, imm: number): void; - - /** - * Puts a PUSH instruction. - */ - putPushReg(reg: MipsRegister): void; - - /** - * Puts a POP instruction. - */ - putPopReg(reg: MipsRegister): void; - - /** - * Puts a MFHI instruction. - */ - putMfhiReg(reg: MipsRegister): void; - - /** - * Puts a MFLO instruction. - */ - putMfloReg(reg: MipsRegister): void; - - /** - * Puts a MTHI instruction. - */ - putMthiReg(reg: MipsRegister): void; - - /** - * Puts a MTLO instruction. - */ - putMtloReg(reg: MipsRegister): void; - - /** - * Puts a NOP instruction. - */ - putNop(): void; - - /** - * Puts a BREAK instruction. - */ - putBreak(): void; - - /** - * Puts a minimal sized trampoline for vectoring to the given address. - */ - putPrologueTrampoline(reg: MipsRegister, address: NativePointerValue): void; - - /** - * Puts a raw instruction. - */ - putInstruction(insn: number): void; - - /** - * Puts raw data. - */ - putBytes(data: ArrayBuffer | number[] | string): void; - } - - interface MipsWriterOptions { - /** - * Specifies the initial program counter, which is useful when - * generating code to a scratch buffer. This is essential when using - * `Memory.patchCode()` on iOS, which may provide you with a - * temporary location that later gets mapped into memory at the - * intended memory location. - */ - pc?: NativePointer | undefined; - } - - type MipsCallArgument = MipsRegister | number | UInt64 | Int64 | NativePointerValue; - - /** - * Relocates machine code for mips. - */ - declare class MipsRelocator { - /** - * Creates a new code relocator for copying MIPS instructions - * from one memory location to another, taking care to adjust - * position-dependent instructions accordingly. - * - * @param inputCode Source address to copy instructions from. - * @param output MipsWriter pointed at the desired target memory - * address. - */ - constructor(inputCode: NativePointerValue, output: MipsWriter); - - /** - * Recycles instance. - */ - reset(inputCode: NativePointerValue, output: MipsWriter): void; - - /** - * Eagerly cleans up memory. - */ - dispose(): void; - - /** - * Latest `Instruction` read so far. Starts out `null` and changes - * on every call to `readOne()`. - */ - input: Instruction | null; - - /** - * Indicates whether end-of-block has been reached, i.e. we've - * reached a branch of any kind, like CALL, JMP, BL, RET. - */ - eob: boolean; - - /** - * Indicates whether end-of-input has been reached, e.g. we've - * reached JMP/B/RET, an instruction after which there may or may - * not be valid code. - */ - eoi: boolean; - - /** - * Reads the next instruction into the relocator's internal buffer - * and returns the number of bytes read so far, including previous - * calls. - * - * You may keep calling this method to keep buffering, or immediately - * call either `writeOne()` or `skipOne()`. Or, you can buffer up - * until the desired point and then call `writeAll()`. - * - * Returns zero when end-of-input is reached, which means the `eoi` - * property is now `true`. - */ - readOne(): number; - - /** - * Peeks at the next `Instruction` to be written or skipped. - */ - peekNextWriteInsn(): Instruction | null; - - /** - * Peeks at the address of the next instruction to be written or skipped. - */ - peekNextWriteSource(): NativePointer; - - /** - * Skips the instruction that would have been written next. - */ - skipOne(): void; - - /** - * Writes the next buffered instruction. - */ - writeOne(): boolean; - - /** - * Writes all buffered instructions. - */ - writeAll(): void; - } - - type MipsRegister = - | "v0" - | "v1" - | "a0" - | "a1" - | "a2" - | "a3" - | "t0" - | "t1" - | "t2" - | "t3" - | "t4" - | "t5" - | "t6" - | "t7" - | "s0" - | "s1" - | "s2" - | "s3" - | "s4" - | "s5" - | "s6" - | "s7" - | "t8" - | "t9" - | "k0" - | "k1" - | "gp" - | "sp" - | "fp" - | "s8" - | "ra" - | "hi" - | "lo" - | "zero" - | "at" - | "0" - | "1" - | "2" - | "3" - | "4" - | "5" - | "6" - | "7" - | "8" - | "9" - | "10" - | "11" - | "12" - | "13" - | "14" - | "15" - | "16" - | "17" - | "18" - | "19" - | "20" - | "21" - | "22" - | "23" - | "24" - | "25" - | "26" - | "27" - | "28" - | "29" - | "30" - | "31" - ; \ No newline at end of file diff --git a/Fermion/src/renderer.js b/Fermion/src/renderer.js index 36b3371..4353b4b 100644 --- a/Fermion/src/renderer.js +++ b/Fermion/src/renderer.js @@ -385,7 +385,7 @@ document.getElementById("FridaProc").onclick = function () { enableRemoteModule: true, contextIsolation: false, webviewTag: true, - additionalArguments: [deviceId] + additionalArguments: ["FERMION_DEVICEID=" + deviceId] } }) @@ -587,7 +587,7 @@ function ChangeLogExclusive(mutex, locktype, data) { // Monaco Editor ////////////////////////////////////////////////// -var LocalLoadLang = function (url, method) { +function LocalLoadLang(url, method) { var request = new XMLHttpRequest(); return new Promise(function (resolve, reject) { request.onreadystatechange = function () { From 4ffb2d98359bf8a905c21fda79fa6f93eb1edc3d Mon Sep 17 00:00:00 2001 From: Misty Date: Wed, 30 Nov 2022 04:10:51 +0800 Subject: [PATCH 2/6] Fix browser additional process arguments parsing --- Fermion/pages/device.html | 3 ++- Fermion/pages/proc.html | 9 ++------- Fermion/pages/trace.html | 3 ++- Fermion/src/helper.js | 20 ++++++++++++++++++++ Fermion/src/renderer.js | 9 +++++---- 5 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 Fermion/src/helper.js diff --git a/Fermion/pages/device.html b/Fermion/pages/device.html index 5664299..c89d9c7 100644 --- a/Fermion/pages/device.html +++ b/Fermion/pages/device.html @@ -73,9 +73,10 @@

Remote Socket + \ No newline at end of file diff --git a/Fermion/pages/docs.html b/Fermion/pages/docs.html index d1245b6..30e9625 100644 --- a/Fermion/pages/docs.html +++ b/Fermion/pages/docs.html @@ -25,25 +25,26 @@ -webkit-app-region:no-drag; position:fixed; top:40px; - margin-top: 8px; - padding:4px; - overflow-x: hidden; - overflow-x: auto; - text-align:justify; + margin-top: 8px; + padding:4px; + overflow-x: hidden; + overflow-x: auto; + text-align:justify; overflow-y:scroll; height: 94vh; width: 100%; } .item_found { - background: yellow; - color: black; - } + background: yellow; + color: black; + } - .highlighted + .highlighted { background-color: yellow; } + .highlight { background-color: #fff34d; @@ -54,6 +55,7 @@ -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* Saf3.0+, Chrome */ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* Opera 10.5+, IE 9.0 */ } + .highlight { padding: 1px 4px; @@ -92,5015 +94,5021 @@
- -

Table of contents

- -
    -
  1. Runtime information -
      -
    1. Frida
    2. -
    3. Script
    4. -
    -
  2. -
  3. Process, Thread, Module and Memory -
      -
    1. Thread
    2. -
    3. Process
    4. -
    5. Module
    6. -
    7. ModuleMap
    8. -
    9. Memory
    10. -
    11. MemoryAccessMonitor
    12. -
    13. CModule
    14. -
    15. ApiResolver
    16. -
    17. DebugSymbol
    18. -
    19. Kernel
    20. -
    -
  4. -
  5. Data Types, Function and Callback -
      -
    1. Int64
    2. -
    3. UInt64
    4. -
    5. NativePointer
    6. -
    7. ArrayBuffer
    8. -
    9. NativeFunction
    10. -
    11. NativeCallback
    12. -
    13. SystemFunction
    14. -
    -
  6. -
  7. Network -
      -
    1. Socket
    2. -
    3. SocketListener
    4. -
    5. SocketConnection
    6. -
    -
  8. -
  9. File and Stream -
      -
    1. File
    2. -
    3. IOStream
    4. -
    5. InputStream
    6. -
    7. OutputStream
    8. -
    9. UnixInputStream
    10. -
    11. UnixOutputStream
    12. -
    13. Win32InputStream
    14. -
    15. Win32OutputStream
    16. -
    -
  10. -
  11. Database -
      -
    1. SqliteDatabase
    2. -
    3. SqliteStatement
    4. -
    -
  12. -
  13. Instrumentation -
      -
    1. Interceptor
    2. -
    3. Stalker
    4. -
    5. ObjC
    6. -
    7. Java
    8. -
    -
  14. -
  15. CPU Instruction -
      -
    1. Instruction
    2. -
    3. X86Writer
    4. -
    5. X86Relocator
    6. -
    7. x86 enum types
    8. -
    9. ArmWriter
    10. -
    11. ArmRelocator
    12. -
    13. ThumbWriter
    14. -
    15. ThumbRelocator
    16. -
    17. ARM enum types
    18. -
    19. Arm64Writer
    20. -
    21. Arm64Relocator
    22. -
    23. AArch64 enum types
    24. -
    25. MipsWriter
    26. -
    27. MipsRelocator
    28. -
    29. MIPS enum types
    30. -
    -
  16. -
  17. Other -
      -
    1. Console
    2. -
    3. Hexdump
    4. -
    5. Shorthand
    6. -
    7. Communication between host and injected process
    8. -
    9. Timing events
    10. -
    11. Garbage collection
    12. -
    -
  18. -
- -
- -

Runtime information

- -

Frida

- -
    -
  • -

    Frida.version: property containing the current Frida version, as a string.

    -
  • -
  • -

    Frida.heapSize: dynamic property containing the current size of Frida’s -private heap, shared by all scripts and Frida’s own runtime. This is useful -for keeping an eye on how much memory your instrumentation is using out of -the total consumed by the hosting process.

    -
  • -
- -

Script

- -
    -
  • -

    Script.runtime: string property containing the runtime being used. -Either QJS or V8.

    -
  • -
  • -

    Script.pin(): temporarily prevents the current script from being unloaded. -This is reference-counted, so there must be one matching unpin() happening -at a later point. Typically used in the callback of bindWeak() when you -need to schedule cleanup on another thread.

    -
  • -
  • -

    Script.unpin(): reverses a previous pin() so the current script may be -unloaded.

    -
  • -
  • -

    Script.bindWeak(value, fn): monitors value and calls the fn callback -as soon as value has been garbage-collected, or the script is about to get -unloaded. Returns an ID that you can pass to Script.unbindWeak() -for explicit cleanup.

    - -

    This API is useful if you’re building a language-binding, where you need to -free native resources when a JS value is no longer needed.

    -
  • -
  • -

    Script.unbindWeak(id): stops monitoring the value passed to -Script.bindWeak(value, fn), and call the fn callback immediately.

    -
  • -
  • -

    Script.setGlobalAccessHandler(handler | null): installs or uninstalls a -handler that is used to resolve attempts to access non-existent global -variables. Useful for implementing a REPL where unknown identifiers may be -fetched lazily from a database.

    - -

    The handler is an object containing two properties:

    - -
      -
    • enumerate(): queries which additional globals exist. Must return an - array of strings.
    • -
    • get(property): retrieves the value for the given property.
    • -
    -
  • -
- -
- -

Process, Thread, Module and Memory

- -

Thread

- -
    -
  • -

    Thread.backtrace([context, backtracer]): generate a backtrace for the -current thread, returned as an array of NativePointer objects.

    - -

    If you call this from Interceptor’s onEnter or -onLeave callbacks you -should provide this.context for the optional context argument, as it -will give you a more accurate backtrace. Omitting context means the -backtrace will be generated from the current stack location, which may -not give you a very good backtrace due to the JavaScript VM’s stack frames. -The optional backtracer argument specifies the kind of backtracer to use, -and must be either Backtracer.FUZZY or Backtracer.ACCURATE, where the -latter is the default if not specified. The accurate kind of backtracers -rely on debugger-friendly binaries or presence of debug information to do a -good job, whereas the fuzzy backtracers perform forensics on the stack in -order to guess the return addresses, which means you will get false -positives, but it will work on any binary.

    -
  • -
- -
const f = Module.getExportByName('libcommonCrypto.dylib',
-    'CCCryptorCreate');
-Interceptor.attach(f, {
-  onEnter(args) {
-    console.log('CCCryptorCreate called from:\n' +
-        Thread.backtrace(this.context, Backtracer.ACCURATE)
-        .map(DebugSymbol.fromAddress).join('\n') + '\n');
-  }
-});
- -
    -
  • Thread.sleep(delay): suspend execution of the current thread for delay -seconds specified as a number. For example 0.05 to sleep for 50 ms.
  • -
- -

Process

- -
    -
  • -

    Process.id: property containing the PID as a number

    -
  • -
  • -

    Process.arch: property containing the string ia32, x64, arm -or arm64

    -
  • -
  • -

    Process.platform: property containing the string windows, -darwin, linux or qnx

    -
  • -
  • -

    Process.pageSize: property containing the size of a virtual memory page -(in bytes) as a number. This is used to make your scripts more portable.

    -
  • -
  • -

    Process.pointerSize: property containing the size of a pointer -(in bytes) as a number. This is used to make your scripts more portable.

    -
  • -
  • -

    Process.codeSigningPolicy: property containing the string optional or -required, where the latter means Frida will avoid modifying existing code -in memory and will not try to run unsigned code. Currently this property -will always be set to optional unless you are using Gadget -and have configured it to assume that code-signing is required. This -property allows you to determine whether the Interceptor API -is off limits, and whether it is safe to modify code or run unsigned code.

    -
  • -
  • -

    Process.isDebuggerAttached(): returns a boolean indicating whether a -debugger is currently attached

    -
  • -
  • -

    Process.getCurrentThreadId(): get this thread’s OS-specific id as a number

    -
  • -
  • -

    Process.enumerateThreads(): enumerates all threads, returning an array of -objects containing the following properties:

    - -
      -
    • id: OS-specific id
    • -
    • state: string specifying either running, stopped, waiting, -uninterruptible or halted
    • -
    • context: object with the keys pc and sp, which are -NativePointer objects specifying EIP/RIP/PC and -ESP/RSP/SP, respectively, for ia32/x64/arm. Other processor-specific keys -are also available, e.g. eax, rax, r0, x0, etc.
    • -
    -
  • -
  • -

    Process.findModuleByAddress(address), -Process.getModuleByAddress(address), -Process.findModuleByName(name), -Process.getModuleByName(name): -returns a Module whose address or name matches the one -specified. In the event that no such module could be found, the -find-prefixed functions return null whilst the get-prefixed functions -throw an exception.

    -
  • -
  • -

    Process.enumerateModules(): enumerates modules loaded right now, returning -an array of Module objects.

    -
  • -
  • -

    Process.findRangeByAddress(address), getRangeByAddress(address): -return an object with details about the range containing address. In the -event that no such range could be found, findRangeByAddress() returns -null whilst getRangeByAddress() throws an exception. See -Process.enumerateRanges() for details about which -fields are included.

    -
  • -
  • -

    Process.enumerateRanges(protection|specifier): enumerates memory ranges -satisfying protection given as a string of the form: rwx, where rw- -means “must be at least readable and writable”. Alternatively you may -provide a specifier object with a protection key whose value is as -aforementioned, and a coalesce key set to true if you’d like neighboring -ranges with the same protection to be coalesced (the default is false; -i.e. keeping the ranges separate). Returns an array of objects containing -the following properties:

    - -
      -
    • base: base address as a NativePointer
    • -
    • size: size in bytes
    • -
    • protection: protection string (see above)
    • -
    • -

      file: (when available) file mapping details as an object -containing:

      - -
        -
      • path: full filesystem path as a string
      • -
      • offset: offset in the mapped file on disk, in bytes
      • -
      • size: size in the mapped file on disk, in bytes
      • -
      -
    • -
    -
  • -
  • -

    Process.enumerateMallocRanges(): just like enumerateRanges(), -but for individual memory allocations known to the system heap.

    -
  • -
  • -

    Process.setExceptionHandler(callback): install a process-wide exception -handler callback that gets a chance to handle native exceptions before the -hosting process itself does. Called with a single argument, details, that -is an object containing:

    - -
      -
    • type: string specifying one of: -
        -
      • abort
      • -
      • access-violation
      • -
      • guard-page
      • -
      • illegal-instruction
      • -
      • stack-overflow
      • -
      • arithmetic
      • -
      • breakpoint
      • -
      • single-step
      • -
      • system
      • -
      -
    • -
    • address: address where the exception occurred, as a NativePointer
    • -
    • memory: if present, is an object containing: -
        -
      • operation: the kind of operation that triggered the exception, as -a string specifying either read, write, or execute
      • -
      • address: address that was accessed when the exception occurred, as -a NativePointer
      • -
      -
    • -
    • context: object with the keys pc and sp, which are -NativePointer objects specifying EIP/RIP/PC and -ESP/RSP/SP, respectively, for ia32/x64/arm. Other processor-specific keys -are also available, e.g. eax, rax, r0, x0, etc. -You may also update register values by assigning to these keys.
    • -
    • nativeContext: address of the OS and architecture-specific CPU context -struct, as a NativePointer. This is only exposed as a -last resort for edge-cases where context isn’t providing enough details. We -would however discourage using this and rather submit a pull-request to add -the missing bits needed for your use-case.
    • -
    - -

    It is up to your callback to decide what to do with the exception. It could -log the issue, notify your application through a send() -followed by a blocking recv() for acknowledgement of the sent data being received, -or it can modify registers and memory to recover from the exception. You should -return true if you did handle the exception, in which case Frida will -resume the thread immediately. If you do not return true, Frida will -forward the exception to the hosting process’ exception handler, if it has -one, or let the OS terminate the process.

    -
  • -
- -

Module

- -

Objects returned by e.g. Module.load() and Process.enumerateModules().

- -
    -
  • -

    name: canonical module name as a string

    -
  • -
  • -

    base: base address as a NativePointer

    -
  • -
  • -

    size: size in bytes

    -
  • -
  • -

    path: full filesystem path as a string

    -
  • -
  • -

    enumerateImports(): enumerates imports of module, returning an array of -objects containing the following properties:

    - -
      -
    • type: string specifying either function or variable
    • -
    • name: import name as a string
    • -
    • module: module name as a string
    • -
    • address: absolute address as a NativePointer
    • -
    • slot: memory location where the import is stored, as a -NativePointer
    • -
    - -

    Only the name field is guaranteed to be present for all imports. The -platform-specific backend will do its best to resolve the other fields -even beyond what the native metadata provides, but there is no guarantee -that it will succeed.

    -
  • -
  • -

    enumerateExports(): enumerates exports of module, returning an array -of objects containing the following properties:

    - -
      -
    • type: string specifying either function or variable
    • -
    • name: export name as a string
    • -
    • address: absolute address as a NativePointer
    • -
    -
  • -
  • -

    enumerateSymbols(): enumerates symbols of module, returning an array of -objects containing the following properties:

    - -
      -
    • isGlobal: boolean specifying whether symbol is globally visible
    • -
    • type: string specifying one of: -
        -
      • unknown
      • -
      • section
      • -
      • undefined (Mach-O)
      • -
      • absolute (Mach-O)
      • -
      • prebound-undefined (Mach-O)
      • -
      • indirect (Mach-O)
      • -
      • object (ELF)
      • -
      • function (ELF)
      • -
      • file (ELF)
      • -
      • common (ELF)
      • -
      • tls (ELF)
      • -
      -
    • -
    • section: if present, is an object containing: -
        -
      • id: string containing section index, segment name (if - applicable) and section name – same format as - r2’s section IDs
      • -
      • protection: protection like in Process.enumerateRanges()
      • -
      -
    • -
    • name: symbol name as a string
    • -
    • address: absolute address as a NativePointer
    • -
    • size: if present, a number specifying the symbol’s size in bytes
    • -
    -
  • -
- -
-
enumerateSymbols() is only available on i/macOS and Linux-based OSes
-

- We would love to support this on the other platforms too, so if you find - this useful and would like to help out, please get in touch. You may also - find the DebugSymbol API adequate, depending on your use-case. -

-
- -
    -
  • -

    enumerateRanges(protection): just like Process.enumerateRanges, -except it’s scoped to the module.

    -
  • -
  • -

    findExportByName(exportName), -getExportByName(exportName): returns the absolute address of the export -named exportName. In the event that no such export could be found, the -find-prefixed function returns null whilst the get-prefixed function -throws an exception.

    -
  • -
  • -

    Module.load(path): loads the specified module from the filesystem path -and returns a Module object. Throws an exception if the specified -module cannot be loaded.

    -
  • -
  • -

    Module.ensureInitialized(name): ensures that initializers of the specified -module have been run. This is important during early instrumentation, i.e. -code run early in the process lifetime, to be able to safely interact with -APIs. One such use-case is interacting with ObjC classes provided -by a given module.

    -
  • -
  • -

    Module.findBaseAddress(name), -Module.getBaseAddress(name): returns the base address of the name -module. In the event that no such module could be found, the find-prefixed -function returns null whilst the get-prefixed function throws an -exception.

    -
  • -
  • -

    Module.findExportByName(moduleName|null, exportName), -Module.getExportByName(moduleName|null, exportName): returns the absolute -address of the export named exportName in moduleName. If the module -isn’t known you may pass null instead of its name, but this can be a -costly search and should be avoided. In the event that no such module or -export could be found, the find-prefixed function returns null whilst -the get-prefixed function throws an exception.

    -
  • -
- -

ModuleMap

- -
    -
  • -

    new ModuleMap([filter]): create a new module map optimized for determining -which module a given memory address belongs to, if any. Takes a snapshot of -the currently loaded modules when created, which may be refreshed by calling -update(). The filter argument is optional and allows -you to pass a function used for filtering the list of modules. This is useful if -you e.g. only care about modules owned by the application itself, and allows you -to quickly check if an address belongs to one of its modules. The filter -function is passed a Module object and must return true for -each module that should be kept in the map. It is called for each loaded -module every time the map is updated.

    -
  • -
  • -

    has(address): check if address belongs to any of the contained modules, -and returns the result as a boolean

    -
  • -
  • -

    find(address), get(address): returns a Module with details -about the module that address belongs to. In the event that no such module -could be found, find() returns null whilst get() throws an exception.

    -
  • -
  • -

    findName(address), -getName(address), -findPath(address), -getPath(address): -just like find() and get(), but only -returns the name or path field, which means less overhead when you don’t need -the other details.

    -
  • -
  • -

    update(): update the map. You should call this after a module has been -loaded or unloaded to avoid operating on stale data.

    -
  • -
  • -

    values(): returns an array with the Module objects currently in -the map. The returned array is a deep copy and will not mutate after a call -to update().

    -
  • -
- -

Memory

- -
    -
  • -

    Memory.scan(address, size, pattern, callbacks): scan memory for -occurrences of pattern in the memory range given by address and size.

    - -
      -
    • -

      pattern must be of the form “13 37 ?? ff” to match 0x13 followed by -0x37 followed by any byte followed by 0xff. -For more advanced matching it is also possible to specify an -r2-style mask. The mask is bitwise AND-ed against both the needle -and the haystack. To specify the mask append a : character after the -needle, followed by the mask using the same syntax. -For example: “13 37 13 37 : 1f ff ff f1”. -For convenience it is also possible to specify nibble-level wildcards, -like “?3 37 13 ?7”, which gets translated into masks behind the scenes.

      -
    • -
    • -

      callbacks is an object with:

      - -
        -
      • -

        onMatch(address, size): called with address containing the -address of the occurence as a NativePointer and -size specifying the size as a number.

        - -

        This function may return the string stop to cancel the memory -scanning early.

        -
      • -
      • -

        onError(reason): called with reason when there was a memory -access error while scanning

        -
      • -
      • -

        onComplete(): called when the memory range has been fully scanned

        -
      • -
      -
    • -
    -
  • -
  • -

    Memory.scanSync(address, size, pattern): synchronous version of scan() -that returns an array of objects containing the following properties:

    - -
      -
    • address: absolute address as a NativePointer.
    • -
    • size: size in bytes
    • -
    - -

    For example:

    -
  • -
- -
// Find the module for the program itself, always at index 0:
-const m = Process.enumerateModules()[0];
-
-// Or load a module by name:
-//const m = Module.load('win32u.dll');
-
-// Print its properties:
-console.log(JSON.stringify(m));
-
-// Dump it from its base address:
-console.log(hexdump(m.base));
-
-// The pattern that you are interested in:
-const pattern = '00 00 00 00 ?? 13 37 ?? 42';
-
-Memory.scan(m.base, m.size, pattern, {
-  onMatch(address, size) {
-    console.log('Memory.scan() found match at', address,
-        'with size', size);
-
-    // Optionally stop scanning early:
-    return 'stop';
-  },
-  onComplete() {
-    console.log('Memory.scan() complete');
-  }
-});
-
-const results = Memory.scanSync(m.base, m.size, pattern);
-console.log('Memory.scanSync() result:\n' +
-    JSON.stringify(results));
- -
    -
  • -

    Memory.alloc(size[, options]): allocate size bytes of memory on the -heap, or, if size is a multiple of -Process.pageSize, one or more raw memory pages -managed by the OS. When using page granularity you may also specify an -options object if you need the memory allocated close to a given address, -by specifying { near: address, maxDistance: distanceInBytes }. -The returned value is a NativePointer and the underlying -memory will be released when all JavaScript handles to it are gone. This -means you need to keep a reference to it while the pointer is being used by -code outside the JavaScript runtime.

    -
  • -
  • -

    Memory.copy(dst, src, n): just like memcpy(). Returns nothing.

    - -
      -
    • dst: a NativePointer specifying the destination base address.
    • -
    • src: a NativePointer specifying the source base address.
    • -
    • n: size in bytes to be copied.
    • -
    -
  • -
  • -

    Memory.dup(address, size): short-hand for Memory.alloc() -followed by Memory.copy(). Returns a NativePointer -containing the base address of the freshly allocated memory. See Memory.copy() -for details on the memory allocation’s lifetime.

    -
  • -
  • -

    Memory.protect(address, size, protection): update protection on a region -of memory, where protection is a string of the same format as -Process.enumerateRanges().

    - -

    Returns a boolean indicating whether the operation completed successfully.

    - -

    For example:

    -
  • -
- -
Memory.protect(ptr('0x1234'), 4096, 'rw-');
- -
    -
  • -

    Memory.patchCode(address, size, apply): safely modify size bytes at -address, specified as a NativePointer. The supplied -JavaScript function apply gets called with a writable pointer where you must -write the desired modifications before returning. Do not make any assumptions -about this being the same location as address, as some systems require -modifications to be written to a temporary location before being mapped into -memory on top of the original memory page (e.g. on iOS, where directly modifying -in-memory code may result in the process losing its CS_VALID status).

    - -

    For example:

    -
  • -
- -
const getLivesLeft = Module.getExportByName('game-engine.so', 'get_lives_left');
-const maxPatchSize = 64; // Do not write out of bounds, may be a temporary buffer!
-Memory.patchCode(getLivesLeft, maxPatchSize, code => {
-  const cw = new X86Writer(code, { pc: getLivesLeft });
-  cw.putMovRegU32('eax', 9000);
-  cw.putRet();
-  cw.flush();
-});
- -
    -
  • Memory.allocUtf8String(str), -Memory.allocUtf16String(str), -Memory.allocAnsiString(str): -allocate, encode and write out str as a UTF-8/UTF-16/ANSI string on the -heap. The returned object is a NativePointer. See -Memory.alloc() for details about its lifetime.
  • -
- -

MemoryAccessMonitor

- -
    -
  • -

    MemoryAccessMonitor.enable(ranges, callbacks): monitor one or more memory -ranges for access, and notify on the first access of each contained memory -page. ranges is either a single range object or an array of such objects, -each of which contains:

    - -
      -
    • base: base address as a NativePointer
    • -
    • size: size in bytes
    • -
    - -

    callbacks is an object specifying:

    - -
      -
    • onAccess(details): called synchronously with details object -containing: -
        -
      • operation: the kind of operation that triggered the access, as a -string specifying either read, write, or execute
      • -
      • from: address of instruction performing the access as a -NativePointer
      • -
      • address: address being accessed as a NativePointer
      • -
      • rangeIndex: index of the accessed range in the ranges provided to -MemoryAccessMonitor.enable()
      • -
      • pageIndex: index of the accessed memory page inside the specified -range
      • -
      • pagesCompleted: overall number of pages which have been accessed -so far (and are no longer being monitored)
      • -
      • pagesTotal: overall number of pages that were initially monitored
      • -
      -
    • -
    -
  • -
  • -

    MemoryAccessMonitor.disable(): stop monitoring the remaining memory ranges -passed to MemoryAccessMonitor.enable().

    -
  • -
- -

CModule

- -
    -
  • -

    new CModule(code[, symbols, options]): creates a new C module from the -provided code, either a string containing the C source code to compile, or -an ArrayBuffer containing a precompiled shared library. The C module gets -mapped into memory and becomes fully accessible to JavaScript.

    - -

    Useful for implementing hot callbacks, e.g. for Interceptor -and Stalker, but also useful when needing to start new threads -in order to call functions in a tight loop, e.g. for fuzzing purposes.

    - -

    Global functions are automatically exported as NativePointer -properties named exactly like in the C source code. This means you can pass them -to Interceptor and Stalker, or call them -using NativePointer.

    - -

    In addition to accessing a curated subset of Gum, GLib, and standard C APIs, -the code being mapped in can also communicate with JavaScript through the -symbols exposed to it. This is the optional second argument, an object -specifying additional symbol names and their -NativePointer values, each of which will be plugged in -at creation. This may for example be one or more memory blocks allocated -using Memory.alloc(), and/or -NativeCallback values for receiving callbacks from -the C module.

    - -

    To perform initialization and cleanup, you may define functions with the -following names and signatures:

    - -
      -
    • void init (void)
    • -
    • void finalize (void)
    • -
    - -

    Note that all data is read-only, so writable globals should be declared -extern, allocated using e.g. Memory.alloc(), and passed -in as symbols through the constructor’s second argument.

    - -

    The optional third argument, options, is an object that may be used to -specify which toolchain to use, e.g.: { toolchain: 'external' }. Supported -values are:

    - -
      -
    • internal: use TinyCC, which is statically linked into the runtime. -Never touches the filesystem and works even in sandboxed processes. The -generated code is however not optimized, as TinyCC optimizes for small -compiler footprint and short compilation times.
    • -
    • external: use toolchain provided by the target system, assuming it is -accessible to the process we’re executing inside.
    • -
    • any: same as internal if Process.arch is -supported by TinyCC, and external otherwise. This is the default -behavior if left unspecified.
    • -
    -
  • -
  • -

    dispose(): eagerly unmaps the module from memory. Useful for short-lived -modules when waiting for a future garbage collection isn’t desirable.

    -
  • -
  • -

    builtins: an object specifying builtins present when constructing a -CModule from C source code. This is typically used by a scaffolding tool -such as frida-create in order to set up a build environment that matches -what CModule uses. The exact contents depends on the -Process.arch and Frida version, but may look something -like the following:

    - -
    {
    -  defines: {
    -    'GLIB_SIZEOF_VOID_P': '8',
    -    'G_GINT16_MODIFIER': '"h"',
    -    'G_GINT32_MODIFIER': '""',
    -    'G_GINT64_MODIFIER': '"ll"',
    -    'G_GSIZE_MODIFIER': '"l"',
    -    'G_GSSIZE_MODIFIER': '"l"',
    -    'HAVE_I386': true
    -  },
    -  headers: {
    -    'gum/arch-x86/gumx86writer.h': '…',
    -    'gum/gumdefs.h': '…',
    -    'gum/guminterceptor.h': '…',
    -    'gum/gummemory.h': '…',
    -    'gum/gummetalarray.h': '…',
    -    'gum/gummetalhash.h': '…',
    -    'gum/gummodulemap.h': '…',
    -    'gum/gumprocess.h': '…',
    -    'gum/gumspinlock.h': '…',
    -    'gum/gumstalker.h': '…',
    -    'glib.h': '…',
    -    'json-glib/json-glib.h': '…',
    -    'capstone.h': '…'
    -  }
    -}
    -
    -
  • -
- -

Examples

- -
const cm = new CModule(`
-#include <stdio.h>
-
-void hello(void) {
-  printf("Hello World from CModule\\n");
-}
-`);
-
-console.log(JSON.stringify(cm));
-
-const hello = new NativeFunction(cm.hello, 'void', []);
-hello();
- -

Which you might load using Frida’s REPL:

- -
$ frida -p 0 -l example.js
- -

(The REPL monitors the file on disk and reloads the script on change.)

- -

You can then type hello() in the REPL to call the C function.

- -

For prototyping we recommend using the Frida REPL’s built-in CModule support:

- -
$ frida -p 0 -C example.c
- -

You may also add -l example.js to load some JavaScript next to it. -The JavaScript code may use the global variable named cm to access -the CModule object, but only after rpc.exports.init() has been -called, so perform any initialization depending on the CModule there. You may -also inject symbols by assigning to the global object named cs, but this -must be done before rpc.exports.init() gets called.

- -

More details on CModule can be found in the Frida 12.7 release notes.

- -

ApiResolver

- -
    -
  • -

    new ApiResolver(type): create a new resolver of the given type, allowing -you to quickly find functions by name, with globs permitted. Precisely which -resolvers are available depends on the current platform and runtimes loaded -in the current process. As of the time of writing, the available resolvers -are:

    - -
      -
    • module: Resolves exported and imported functions of shared libraries - currently loaded. Always available.
    • -
    • objc: Resolves Objective-C methods of classes currently loaded. - Available on macOS and iOS in processes that have the Objective-C - runtime loaded. Use ObjC.available to check at - runtime, or wrap your new ApiResolver('objc') call in a try-catch.
    • -
    - -

    The resolver will load the minimum amount of data required on creation, and -lazy-load the rest depending on the queries it receives. It is thus -recommended to use the same instance for a batch of queries, but recreate it -for future batches to avoid looking at stale data.

    -
  • -
  • -

    enumerateMatches(query): performs the resolver-specific query string, -optionally suffixed with /i to perform case-insensitive matching, -returning an array of objects containing the following properties:

    - -
      -
    • name: name of the API that was found
    • -
    • address: address as a NativePointer
    • -
    -
  • -
- -
const resolver = new ApiResolver('module');
-const matches = resolver.enumerateMatches('exports:*!open*');
-const first = matches[0];
-/*
- * Where `first` is an object similar to:
- *
- * {
- *   name: '/usr/lib/libSystem.B.dylib!opendir$INODE64',
- *   address: ptr('0x7fff870135c9')
- * }
- */
- -
const resolver = new ApiResolver('objc');
-const matches = resolver.enumerateMatches('-[NSURL* *HTTP*]');
-const first = matches[0];
-/*
- * Where `first` contains an object like this one:
- *
- * {
- *   name: '-[NSURLRequest valueForHTTPHeaderField:]',
- *   address: ptr('0x7fff94183e22')
- * }
- */
- -

DebugSymbol

- -
    -
  • -

    DebugSymbol.fromAddress(address), DebugSymbol.fromName(name): -look up debug information for address/name and return it as an object -containing:

    - -
      -
    • address: Address that this symbol is for, as a NativePointer.
    • -
    • name: Name of the symbol, as a string, or null if unknown.
    • -
    • moduleName: Module name owning this symbol, as a string, or null if - unknown.
    • -
    • fileName: File name owning this symbol, as a string, or null if - unknown.
    • -
    • lineNumber: Line number in fileName, as a number, or null if - unknown.
    • -
    - -

    You may also call toString() on it, which is very useful when combined -with Thread.backtrace():

    -
  • -
- -
const f = Module.getExportByName('libcommonCrypto.dylib',
-    'CCCryptorCreate');
-Interceptor.attach(f, {
-  onEnter(args) {
-    console.log('CCCryptorCreate called from:\n' +
-        Thread.backtrace(this.context, Backtracer.ACCURATE)
-        .map(DebugSymbol.fromAddress).join('\n') + '\n');
-  }
-});
- -
    -
  • -

    DebugSymbol.getFunctionByName(name): resolves a function name and -returns its address as a NativePointer. Returns the first if -more than one function is found. Throws an exception if the name cannot be -resolved.

    -
  • -
  • -

    DebugSymbol.findFunctionsNamed(name): resolves a function name and returns -its addresses as an array of NativePointer objects.

    -
  • -
  • -

    DebugSymbol.findFunctionsMatching(glob): resolves function names matching -glob and returns their addresses as an array of NativePointer -objects.

    -
  • -
  • -

    DebugSymbol.load(path): loads debug symbols for a specific module.

    -
  • -
- -

Kernel

- -
    -
  • -

    Kernel.available: a boolean specifying whether the Kernel API is -available. Do not invoke any other Kernel properties or methods unless -this is the case.

    -
  • -
  • -

    Kernel.base: base address of the kernel, as a UInt64.

    -
  • -
  • -

    Kernel.pageSize: size of a kernel page in bytes, as a number.

    -
  • -
  • -

    Kernel.enumerateModules(): enumerates kernel modules loaded right now, -returning an array of objects containing the following properties:

    - -
      -
    • name: canonical module name as a string
    • -
    • base: base address as a NativePointer
    • -
    • size: size in bytes
    • -
    -
  • -
  • -

    Kernel.enumerateRanges(protection|specifier): enumerate kernel memory -ranges satisfying protection given as a string of the form: rwx, where -rw- means “must be at least readable and writable”. Alternatively you may -provide a specifier object with a protection key whose value is as -aforementioned, and a coalesce key set to true if you’d like neighboring -ranges with the same protection to be coalesced (the default is false; -i.e. keeping the ranges separate). Returns an array of objects containing -the following properties:

    - -
      -
    • base: base address as a NativePointer
    • -
    • size: size in bytes
    • -
    • protection: protection string (see above)
    • -
    -
  • -
  • -

    Kernel.enumerateModuleRanges(name, protection): just like -Kernel.enumerateRanges, except it’s scoped to the -specified module name – which may be null for the module of the kernel -itself. Each range also has a name field containing a unique identifier as a -string.

    -
  • -
  • -

    Kernel.alloc(size): allocate size bytes of kernel memory, rounded up to -a multiple of the kernel’s page size. The returned value is a UInt64 -specifying the base address of the allocation.

    -
  • -
  • -

    Kernel.protect(address, size, protection): update protection on a region -of kernel memory, where protection is a string of the same format as -Kernel.enumerateRanges().

    - -

    For example:

    -
  • -
- -
Kernel.protect(UInt64('0x1234'), 4096, 'rw-');
- -
    -
  • -

    Kernel.readByteArray(address, length): just like -NativePointer#readByteArray, but reading from -kernel memory.

    -
  • -
  • -

    Kernel.writeByteArray(address, bytes): just like -NativePointer#writeByteArray, but writing to -kernel memory.

    -
  • -
  • -

    Kernel.scan(address, size, pattern, callbacks): just like Memory.scan, -but scanning kernel memory.

    -
  • -
  • -

    Kernel.scanSync(address, size, pattern): synchronous version of scan() -that returns the matches in an array.

    -
  • -
- -
- -

Data Types, Function and Callback

- -

Int64

- -
    -
  • -

    new Int64(v): create a new Int64 from v, which is either a number or a -string containing a value in decimal, or hexadecimal if prefixed with “0x”. -You may use the int64(v) short-hand for brevity.

    -
  • -
  • -

    add(rhs), sub(rhs), -and(rhs), or(rhs), -xor(rhs): -make a new Int64 with this Int64 plus/minus/and/or/xor rhs, which may -either be a number or another Int64

    -
  • -
  • -

    shr(n), shl(n): -make a new Int64 with this Int64 shifted right/left by n bits

    -
  • -
  • -

    compare(rhs): returns an integer comparison result just like -String#localeCompare()

    -
  • -
  • -

    toNumber(): cast this Int64 to a number

    -
  • -
  • -

    toString([radix = 10]): convert to a string of optional radix (defaults to -10)

    -
  • -
- -

UInt64

- -
    -
  • -

    new UInt64(v): create a new UInt64 from v, which is either a number or a -string containing a value in decimal, or hexadecimal if prefixed with “0x”. -You may use the uint64(v) short-hand for brevity.

    -
  • -
  • -

    add(rhs), sub(rhs), -and(rhs), or(rhs), -xor(rhs): -make a new UInt64 with this UInt64 plus/minus/and/or/xor rhs, which may -either be a number or another UInt64

    -
  • -
  • -

    shr(n), shl(n): -make a new UInt64 with this UInt64 shifted right/left by n bits

    -
  • -
  • -

    compare(rhs): returns an integer comparison result just like -String#localeCompare()

    -
  • -
  • -

    toNumber(): cast this UInt64 to a number

    -
  • -
  • -

    toString([radix = 10]): convert to a string of optional radix (defaults to -10)

    -
  • -
- -

NativePointer

- -
    -
  • -

    new NativePointer(s): creates a new NativePointer from the -string s containing a memory address in either decimal, or hexadecimal if -prefixed with ‘0x’. You may use the ptr(s) short-hand for brevity.

    -
  • -
  • -

    isNull(): returns a boolean allowing you to conveniently check if a -pointer is NULL

    -
  • -
  • -

    add(rhs), sub(rhs), -and(rhs), or(rhs), -xor(rhs): -makes a new NativePointer with this NativePointer -plus/minus/and/or/xor rhs, which may either be a number or another NativePointer

    -
  • -
  • -

    shr(n), shl(n): -makes a new NativePointer with this NativePointer -shifted right/left by n bits

    -
  • -
  • -

    not(): makes a new NativePointer with this NativePointer’s -bits inverted

    -
  • -
  • -

    sign([key, data]): makes a new NativePointer by taking this -NativePointer’s bits and adding pointer authentication bits, -creating a signed pointer. This is a no-op if the current process does not support -pointer authentication, returning this NativePointer instead -of a new value.

    - -

    Optionally, key may be specified as a string. Supported values are:

    -
      -
    • ia: The IA key, for signing code pointers. This is the default.
    • -
    • ib: The IB key, for signing code pointers.
    • -
    • da: The DA key, for signing data pointers.
    • -
    • db: The DB key, for signing data pointers.
    • -
    - -

    The data argument may also be specified as a NativePointer/number-like -value to provide extra data used for the signing, and defaults to 0.

    -
  • -
  • -

    strip([key]): makes a new NativePointer by taking this NativePointer’s -bits and removing its pointer authentication bits, creating a raw pointer. -This is a no-op if the current process does not support pointer -authentication, returning this NativePointer instead of a -new value.

    - -

    Optionally, key may be passed to specify which key was used to sign the -pointer being stripped. Defaults to ia. (See sign() -for supported values.)

    -
  • -
  • -

    blend(smallInteger): makes a new NativePointer by taking -this NativePointer’s bits and blending them with a constant, -which may in turn be passed to sign() as data.

    -
  • -
  • -

    equals(rhs): returns a boolean indicating whether rhs is equal to -this one; i.e. it has the same pointer value

    -
  • -
  • -

    compare(rhs): returns an integer comparison result just like -String#localeCompare()

    -
  • -
  • -

    toInt32(): casts this NativePointer to a signed 32-bit integer

    -
  • -
  • -

    toString([radix = 16]): converts to a string of optional radix (defaults -to 16)

    -
  • -
  • -

    toMatchPattern(): returns a string containing a Memory.scan()-compatible -match pattern for this pointer’s raw value

    -
  • -
  • -

    readPointer(): reads a NativePointer from this memory location.

    - -

    A JavaScript exception will be thrown if the address isn’t readable.

    -
  • -
  • -

    writePointer(ptr): writes ptr to this memory location.

    - -

    A JavaScript exception will be thrown if the address isn’t writable.

    -
  • -
  • -

    readS8(), readU8(), -readS16(), readU16(), -readS32(), readU32(), -readShort(), readUShort(), -readInt(), readUInt(), -readFloat(), readDouble(): -reads a signed or unsigned 8/16/32/etc. or float/double value from -this memory location and returns it as a number.

    - -

    A JavaScript exception will be thrown if the address isn’t readable.

    -
  • -
  • -

    writeS8(value), writeU8(value), -writeS16(value), writeU16(value), -writeS32(value), writeU32(value), -writeShort(value), writeUShort(value), -writeInt(value), writeUInt(value), -writeFloat(value), writeDouble(value): -writes a signed or unsigned 8/16/32/etc. or float/double value to this -memory location.

    - -

    A JavaScript exception will be thrown if the address isn’t writable.

    -
  • -
  • -

    readS64(), readU64(), -readLong(), readULong(): -reads a signed or unsigned 64-bit, or long-sized, value from this memory -location and returns it as an Int64/UInt64 value.

    - -

    A JavaScript exception will be thrown if the address isn’t readable.

    -
  • -
  • -

    writeS64(value), writeU64(value), -writeLong(value), writeULong(value): -writes the Int64/UInt64 value to this memory -location.

    - -

    A JavaScript exception will be thrown if the address isn’t writable.

    -
  • -
  • -

    readByteArray(length): reads length bytes from this memory location, and -returns it as an ArrayBuffer. This buffer may be efficiently -transferred to your Frida-based application by passing it as the second argument -to send().

    - -

    A JavaScript exception will be thrown if any of the length bytes read from -the address isn’t readable.

    -
  • -
  • -

    writeByteArray(bytes): writes bytes to this memory location, where -bytes is either an ArrayBuffer, typically returned from -readByteArray(), or an array of integers between 0 and 255. For example: -[ 0x13, 0x37, 0x42 ].

    - -

    A JavaScript exception will be thrown if any of the bytes written to -the address isn’t writable.

    -
  • -
  • -

    readCString([size = -1]), -readUtf8String([size = -1]), -readUtf16String([length = -1]), -readAnsiString([size = -1]): -reads the bytes at this memory location as an ASCII, UTF-8, UTF-16, or ANSI -string. Supply the optional size argument if you know the size of the -string in bytes, or omit it or specify -1 if the string is NUL-terminated. -Likewise you may supply the optional length argument if you know the -length of the string in characters.

    - -

    A JavaScript exception will be thrown if any of the size / length bytes -read from the address isn’t readable.

    - -

    Note that readAnsiString() is only available (and relevant) on Windows.

    -
  • -
  • -

    writeUtf8String(str), -writeUtf16String(str), -writeAnsiString(str): -encodes and writes the JavaScript string to this memory location (with -NUL-terminator).

    - -

    A JavaScript exception will be thrown if any of the bytes written to -the address isn’t writable.

    - -

    Note that writeAnsiString() is only available (and relevant) on Windows.

    -
  • -
- -

ArrayBuffer

- -
    -
  • -

    wrap(address, size): creates an ArrayBuffer backed by an existing memory -region, where address is a NativePointer specifying the -base address of the region, and size is a number specifying its size. Unlike -the NativePointer read/write APIs, no validation is performed -on access, meaning a bad pointer will crash the process.

    -
  • -
  • -

    unwrap(): returns a NativePointer specifying the base -address of the ArrayBuffer’s backing store. It is the caller’s responsibility to -keep the buffer alive while the backing store is still being used.

    -
  • -
- -

NativeFunction

- -
    -
  • -

    new NativeFunction(address, returnType, argTypes[, abi]): create a new -NativeFunction to call the function at address (specified with a -NativePointer), where returnType specifies the return type, -and the argTypes array specifies the argument types. You may optionally also -specify abi if not system default. For variadic functions, add a '...' -entry to argTypes between the fixed arguments and the variadic ones.

    - -
      -
    • -

      Structs & Classes by Value

      - -

      As for structs or classes passed by value, instead of a string provide an - array containing the struct’s field types following each other. You may nest - these as deep as desired for representing structs inside structs. Note that - the returned object is also a NativePointer, and can thus - be passed to Interceptor#attach.

      - -

      This must match the struct/class exactly, so if you have a struct with three - ints, you must pass ['int', 'int', 'int'].

      - -

      For a class that has virtual methods, the first field will be a pointer - to the vtable.

      - -

      For C++ scenarios involving a return value that is larger than - Process.pointerSize, a typical ABI may expect - that a NativePointer to preallocated space must be - passed in as the first parameter. (This scenario is common in WebKit, - for example.)

      -
    • -
    • -

      Supported Types

      -
        -
      • void
      • -
      • pointer
      • -
      • int
      • -
      • uint
      • -
      • long
      • -
      • ulong
      • -
      • char
      • -
      • uchar
      • -
      • size_t
      • -
      • ssize_t
      • -
      • float
      • -
      • double
      • -
      • int8
      • -
      • uint8
      • -
      • int16
      • -
      • uint16
      • -
      • int32
      • -
      • uint32
      • -
      • int64
      • -
      • uint64
      • -
      • bool
      • -
      -
    • -
    • -

      Supported ABIs

      -
        -
      • default
      • -
      • Windows 32-bit: -
          -
        • sysv
        • -
        • stdcall
        • -
        • thiscall
        • -
        • fastcall
        • -
        • mscdecl
        • -
        -
      • -
      • Windows 64-bit: -
          -
        • win64
        • -
        -
      • -
      • UNIX x86: -
          -
        • sysv
        • -
        • unix64
        • -
        -
      • -
      • UNIX ARM: -
          -
        • sysv
        • -
        • vfp
        • -
        -
      • -
      -
    • -
    -
  • -
  • -

    new NativeFunction(address, returnType, argTypes[, options]): just like -the previous constructor, but where the fourth argument, options, is an -object that may contain one or more of the following keys:

    - -
      -
    • abi: same enum as above.
    • -
    • scheduling: scheduling behavior as a string. Supported values are: -
        -
      • cooperative: Allow other threads to execute JavaScript code while - calling the native function, i.e. let go of the lock - before the call, and re-acquire it afterwards. - This is the default behavior.
      • -
      • exclusive: Do not allow other threads to execute JavaScript code - while calling the native function, i.e. keep holding the - JavaScript lock. - This is faster but may result in deadlocks.
      • -
      -
    • -
    • exceptions: exception behavior as a string. Supported values are: -
        -
      • steal: If the called function generates a native exception, e.g. - by dereferencing an invalid pointer, Frida will unwind the - stack and steal the exception, turning it into a JavaScript - exception that can be handled. This may leave the application - in an undefined state, but is useful to avoid crashing the - process while experimenting. - This is the default behavior.
      • -
      • propagate: Let the application deal with any native exceptions that - occur during the function call. (Or, the handler - installed through Process.setExceptionHandler().)
      • -
      -
    • -
    • traps: code traps to be enabled, as a string. Supported values are: -
        -
      • default: Interceptor.attach() callbacks will be - called if any hooks are triggered by a function call.
      • -
      • all: In addition to Interceptor callbacks, Stalker - may also be temporarily reactivated for the duration of each function - call. This is useful for e.g. measuring code coverage while guiding a - fuzzer, implementing “step into” in a debugger, etc. - Note that this is also possible when using the Java - and ObjC APIs, as method wrappers also provide a - clone(options) API to create a new method wrapper with custom - NativeFunction options.
      • -
      -
    • -
    -
  • -
- -

NativeCallback

- -
    -
  • new NativeCallback(func, returnType, argTypes[, abi]): create a new -NativeCallback implemented by the JavaScript function func, where -returnType specifies the return type, and the argTypes array specifies -the argument types. You may also specify the abi if not system default. -See NativeFunction for details about supported types and -abis. Note that the returned object is also a NativePointer, -and can thus be passed to Interceptor#replace. -When using the resulting callback with Interceptor.replace(), -func will be invoked with this bound to an object with some useful properties, -just like the one in Interceptor.attach().
  • -
- -

SystemFunction

- -
    -
  • -

    new SystemFunction(address, returnType, argTypes[, abi]): just like -NativeFunction, but also provides a snapshot of the thread’s -last error status. The return value is an object wrapping the actual return value -as value, with one additional platform-specific field named either errno -(UNIX) or lastError (Windows).

    -
  • -
  • -

    new SystemFunction(address, returnType, argTypes[, options]): same as -above but accepting an options object like NativeFunction’s -corresponding constructor.

    -
  • -
- -
- -

Network

- -

Socket

- -
    -
  • -

    Socket.listen([options]): open a TCP or UNIX listening socket. Returns a -Promise that receives a SocketListener.

    - -

    Defaults to listening on both IPv4 and IPv6, if supported, and binding on -all interfaces on a randomly selected TCP port.

    - -

    The optional options argument is an object that may contain some of the -following keys:

    - -
      -
    • family: address family as a string. Supported values are: -
        -
      • unix
      • -
      • ipv4
      • -
      • ipv6 -Defaults to listening on both ipv4 and ipv6 if supported.
      • -
      -
    • -
    • host: (IP family) IP address as a string. Defaults to all interfaces.
    • -
    • port: (IP family) IP port as a number. Defaults to any available.
    • -
    • type: (UNIX family) UNIX socket type as a string. Supported types are: -
        -
      • anonymous
      • -
      • path
      • -
      • abstract
      • -
      • abstract-padded -Defaults to path.
      • -
      -
    • -
    • path: (UNIX family) UNIX socket path as a string.
    • -
    • backlog: Listen backlog as a number. Defaults to 10.
    • -
    -
  • -
  • -

    Socket.connect(options): connect to a TCP or UNIX server. Returns a -Promise that receives a SocketConnection.

    - -

    The options argument is an object that should contain some of the -following keys:

    - -
      -
    • family: address family as a string. Supported values are: -
        -
      • unix
      • -
      • ipv4
      • -
      • ipv6 -Defaults to an IP family depending on the host specified.
      • -
      -
    • -
    • host: (IP family) IP address as a string. Defaults to localhost.
    • -
    • port: (IP family) IP port as a number.
    • -
    • type: (UNIX family) UNIX socket type as a string. Supported types are: -
        -
      • anonymous
      • -
      • path
      • -
      • abstract
      • -
      • abstract-padded -Defaults to path.
      • -
      -
    • -
    • path: (UNIX family) UNIX socket path as a string.
    • -
    -
  • -
  • -

    Socket.type(handle): inspect the OS socket handle and return its type -as a string which is either tcp, udp, tcp6, udp6, unix:stream, -unix:dgram, or null if invalid or unknown.

    -
  • -
  • -

    Socket.localAddress(handle), -Socket.peerAddress(handle): -inspect the OS socket handle and return its local or peer address, or -null if invalid or unknown.

    - -

    The object returned has the fields:

    - -
      -
    • ip: (IP sockets) IP address as a string.
    • -
    • port: (IP sockets) IP port as a number.
    • -
    • path: (UNIX sockets) UNIX path as a string.
    • -
    -
  • -
- -

SocketListener

- -

All methods are fully asynchronous and return Promise objects.

- -
    -
  • -

    path: (UNIX family) path being listened on.

    -
  • -
  • -

    port: (IP family) IP port being listened on.

    -
  • -
  • -

    close(): close the listener, releasing resources related to it. Once the -listener is closed, all other operations will fail. Closing a listener -multiple times is allowed and will not result in an error.

    -
  • -
  • -

    accept(): wait for the next client to connect. The returned Promise -receives a SocketConnection.

    -
  • -
- -

SocketConnection

- -

Inherits from IOStream. -All methods are fully asynchronous and return Promise objects.

- -
    -
  • setNoDelay(noDelay): disable the Nagle algorithm if noDelay is true, -otherwise enable it. The Nagle algorithm is enabled by default, so it is -only necessary to call this method if you wish to optimize for low delay -instead of high throughput.
  • -
- -
- -

File and Stream

- -

File

- -
    -
  • -

    new File(filePath, mode): open or create the file at filePath with -the mode string specifying how it should be opened. For example "wb" -to open the file for writing in binary mode (this is the same format as -fopen() from the C standard library).

    -
  • -
  • -

    write(data): synchronously write data to the file, where data is -either a string or a buffer as returned by NativePointer#readByteArray

    -
  • -
  • -

    flush(): flush any buffered data to the underlying file

    -
  • -
  • -

    close(): close the file. You should call this function when you’re done -with the file unless you are fine with this happening when the object is -garbage-collected or the script is unloaded.

    -
  • -
- -

IOStream

- -

All methods are fully asynchronous and return Promise objects.

- -
    -
  • -

    input: the InputStream to read from.

    -
  • -
  • -

    output: the OutputStream to write to.

    -
  • -
  • -

    close(): close the stream, releasing resources related to it. This will -also close the individual input and output streams. Once the stream is -closed, all other operations will fail. Closing a stream multiple times is -allowed and will not result in an error.

    -
  • -
- -

InputStream

- -

All methods are fully asynchronous and return Promise objects.

- -
    -
  • -

    close(): close the stream, releasing resources related to it. Once the -stream is closed, all other operations will fail. Closing a stream multiple -times is allowed and will not result in an error.

    -
  • -
  • -

    read(size): read up to size bytes from the stream. The returned -Promise receives an ArrayBuffer up to size bytes long. -End of stream is signalled through an empty buffer.

    -
  • -
  • -

    readAll(size): keep reading from the stream until exactly size bytes -have been consumed. The returned Promise receives an ArrayBuffer -that is exactly size bytes long. Premature error or end of stream results in the -Promise getting rejected with an error, where the Error object has a -partialData property containing the incomplete data.

    -
  • -
- -

OutputStream

- -

All methods are fully asynchronous and return Promise objects.

- -
    -
  • -

    close(): close the stream, releasing resources related to it. Once the -stream is closed, all other operations will fail. Closing a stream multiple -times is allowed and will not result in an error.

    -
  • -
  • -

    write(data): try to write data to the stream. The data value is either -an ArrayBuffer or an array of integers between 0 and 255. The -returned Promise receives a Number specifying how many bytes of data were -written to the stream.

    -
  • -
  • -

    writeAll(data): keep writing to the stream until all of data has been -written. The data value is either an ArrayBuffer or an array -of integers between 0 and 255. Premature error or end of stream results in an -error, where the Error object has a partialSize property specifying how many -bytes of data were written to the stream before the error occurred.

    -
  • -
  • -

    writeMemoryRegion(address, size): try to write size bytes to the stream, -reading them from address, which is a NativePointer. The -returned Promise receives a Number specifying how many bytes of data were -written to the stream.

    -
  • -
- -

UnixInputStream

- -

(Only available on UNIX-like OSes.)

- -
    -
  • -

    new UnixInputStream(fd[, options]): create a new -InputStream from the specified file descriptor fd.

    - -

    You may also supply an options object with autoClose set to true to -make the stream close the underlying file descriptor when the stream is -released, either through close() or future garbage-collection.

    -
  • -
- -

UnixOutputStream

- -

(Only available on UNIX-like OSes.)

- -
    -
  • -

    new UnixOutputStream(fd[, options]): create a new -OutputStream from the specified file descriptor fd.

    - -

    You may also supply an options object with autoClose set to true to -make the stream close the underlying file descriptor when the stream is -released, either through close() or future garbage-collection.

    -
  • -
- -

Win32InputStream

- -

(Only available on Windows.)

- -
    -
  • -

    new Win32InputStream(handle[, options]): create a new -InputStream from the specified handle, which is a Windows -HANDLE value.

    - -

    You may also supply an options object with autoClose set to true to -make the stream close the underlying handle when the stream is released, -either through close() or future garbage-collection.

    -
  • -
- -

Win32OutputStream

- -

(Only available on Windows.)

- -
    -
  • -

    new Win32OutputStream(handle[, options]): create a new -OutputStream from the specified handle, which is a -Windows HANDLE value.

    - -

    You may also supply an options object with autoClose set to true to -make the stream close the underlying handle when the stream is released, -either through close() or future garbage-collection.

    -
  • -
- -

Database

- -

SqliteDatabase

- -
    -
  • -

    SqliteDatabase.open(path[, options]): opens the SQLite v3 database -specified by path, a string containing the filesystem path to the -database. By default the database will be opened read-write, but you may -customize this behavior by providing an options object with a property -named flags, specifying an array of strings containing one or more of the -following values: readonly, readwrite, create. The returned -SqliteDatabase object will allow you to perform queries on the database.

    -
  • -
  • -

    SqliteDatabase.openInline(encodedContents): just like open() but the -contents of the database is provided as a string containing its data, -Base64-encoded. We recommend gzipping the database before Base64-encoding -it, but this is optional and detected by looking for a gzip magic marker. -The database is opened read-write, but is 100% in-memory and never touches -the filesystem. This is useful for agents that need to bundle a cache of -precomputed data, e.g. static analysis data used to guide dynamic analysis.

    -
  • -
  • -

    close(): close the database. You should call this function when you’re -done with the database, unless you are fine with this happening when the -object is garbage-collected or the script is unloaded.

    -
  • -
  • -

    exec(sql): execute a raw SQL query, where sql is a string containing -the text-representation of the query. The query’s result is ignored, so this -should only be used for queries for setting up the database, e.g. table -creation.

    -
  • -
  • -

    prepare(sql): compile the provided SQL into a -SqliteStatement object, where sql is a string -containing the text-representation of the query.

    - -

    For example:

    -
  • -
- -
const db = SqliteDatabase.open('/path/to/people.db');
-
-const smt = db.prepare('SELECT name, bio FROM people WHERE age = ?');
-
-console.log('People whose age is 42:');
-smt.bindInteger(1, 42);
-let row;
-while ((row = smt.step()) !== null) {
-  const [name, bio] = row;
-  console.log('Name:', name);
-  console.log('Bio:', bio);
-}
-smt.reset();
-
    -
  • dump(): dump the database to a gzip-compressed blob encoded as Base64, -where the result is returned as a string. This is useful for inlining a -cache in your agent’s code, loaded by calling SqliteDatabase.openInline().
  • -
- -

SqliteStatement

- -
    -
  • bindInteger(index, value): bind the integer value to index
  • -
  • bindFloat(index, value): bind the floating point value to index
  • -
  • bindText(index, value): bind the text value to index
  • -
  • bindBlob(index, bytes): bind the blob bytes to index, where bytes -is an ArrayBuffer, array of byte values, or a string
  • -
  • bindNull(index): bind a null value to index
  • -
  • step(): either start a new query and get the first result, or move to the -next one. Returns an array containing the values in the order specified by -the query, or null when the last result is reached. You should call -reset() at that point if you intend to use this object again.
  • -
  • reset(): reset internal state to allow subsequent queries
  • -
- -
- -

Instrumentation

- -

Interceptor

- -
    -
  • -

    Interceptor.attach(target, callbacks[, data]): intercept calls to function -at target. This is a NativePointer specifying the address -of the function you would like to intercept calls to. Note that on 32-bit ARM this -address must have its least significant bit set to 0 for ARM functions, and -1 for Thumb functions. Frida takes care of this detail for you if you get -the address from a Frida API (for example Module.getExportByName()).

    - -

    The callbacks argument is an object containing one or more of:

    - -
      -
    • -

      onEnter(args): callback function given one argument args that can be -used to read or write arguments as an array of -NativePointer objects. {: #interceptor-onenter}

      -
    • -
    • -

      onLeave(retval): callback function given one argument retval that is -a NativePointer-derived object containing the raw -return value. -You may call retval.replace(1337) to replace the return value with -the integer 1337, or retval.replace(ptr("0x1234")) to replace with -a pointer. -Note that this object is recycled across onLeave calls, so do not -store and use it outside your callback. Make a deep copy if you need -to store the contained value, e.g.: ptr(retval.toString()).

      -
    • -
    - -

    In case the hooked function is very hot, onEnter and onLeave may be -NativePointer values pointing at native C functions compiled -using CModule. Their signatures are:

    - -
      -
    • -

      void onEnter (GumInvocationContext * ic)

      -
    • -
    • -

      void onLeave (GumInvocationContext * ic)

      -
    • -
    - -

    In such cases, the third optional argument data may be a NativePointer -accessible through gum_invocation_context_get_listener_function_data().

    - -

    You may also intercept arbitrary instructions by passing a function instead -of the callbacks object. This function has the same signature as -onEnter, but the args argument passed to it will only give you sensible -values if the intercepted instruction is at the beginning of a function or -at a point where registers/stack have not yet deviated from that point.

    - -

    Just like above, this function may also be implemented in C by specifying -a NativePointer instead of a function.

    - -

    Returns a listener object that you can call detach() on.

    - -

    Note that these functions will be invoked with this bound to a -per-invocation (thread-local) object where you can store arbitrary data, -which is useful if you want to read an argument in onEnter and act on it -in onLeave.

    - -

    For example:

    -
  • -
- -
Interceptor.attach(Module.getExportByName('libc.so', 'read'), {
-  onEnter(args) {
-    this.fileDescriptor = args[0].toInt32();
-  },
-  onLeave(retval) {
-    if (retval.toInt32() > 0) {
-      /* do something with this.fileDescriptor */
-    }
-  }
-});
- -
    -
  • -

    Additionally, the object contains some useful properties:

    - -
      -
    • -

      returnAddress: return address as a NativePointer

      -
    • -
    • -

      context: object with the keys pc and sp, which are -NativePointer objects specifying EIP/RIP/PC and -ESP/RSP/SP, respectively, for ia32/x64/arm. Other processor-specific keys -are also available, e.g. eax, rax, r0, x0, etc. -You may also update register values by assigning to these keys.

      -
    • -
    • -

      errno: (UNIX) current errno value (you may replace it)

      -
    • -
    • -

      lastError: (Windows) current OS error value (you may replace it)

      -
    • -
    • -

      threadId: OS thread ID

      -
    • -
    • -

      depth: call depth of relative to other invocations

      -
    • -
    - -

    For example:

    -
  • -
- -
Interceptor.attach(Module.getExportByName(null, 'read'), {
-  onEnter(args) {
-    console.log('Context information:');
-    console.log('Context  : ' + JSON.stringify(this.context));
-    console.log('Return   : ' + this.returnAddress);
-    console.log('ThreadId : ' + this.threadId);
-    console.log('Depth    : ' + this.depth);
-    console.log('Errornr  : ' + this.err);
-
-    // Save arguments for processing in onLeave.
-    this.fd = args[0].toInt32();
-    this.buf = args[1];
-    this.count = args[2].toInt32();
-  },
-  onLeave(result) {
-    console.log('----------')
-    // Show argument 1 (buf), saved during onEnter.
-    const numBytes = result.toInt32();
-    if (numBytes > 0) {
-      console.log(hexdump(this.buf, { length: numBytes, ansi: true }));
-    }
-    console.log('Result   : ' + numBytes);
-  }
-})
- -
-
Performance considerations
-

- The callbacks provided have a significant impact on performance. If you only - need to inspect arguments but do not care about the return value, or the - other way around, make sure you omit the callback that you don't need; i.e. - avoid putting your logic in onEnter and leaving onLeave in - there as an empty callback. -

-

- On an iPhone 5S the base overhead when providing just onEnter might be - something like 6 microseconds, and 11 microseconds with both onEnter - and onLeave provided. -

-

- Also be careful about intercepting calls to functions that are called a - bazillion times per second; while send() is - asynchronous, the total overhead of sending a single message is not optimized for - high frequencies, so that means Frida leaves it up to you to batch multiple values - into a single send()-call, based on whether low delay - or high throughput is desired. -

-

- However when hooking hot functions you may use Interceptor in conjunction - with CModule to implement the callbacks in C. -

-
- -
    -
  • -

    Interceptor.detachAll(): detach all previously attached callbacks.

    -
  • -
  • -

    Interceptor.replace(target, replacement[, data]): replace function at -target with implementation at replacement. This is typically used if you -want to fully or partially replace an existing function’s implementation.

    - -

    Use NativeCallback to implement a replacement in JavaScript.

    - -

    In case the replaced function is very hot, you may implement replacement -in C using CModule. You may then also specify the third optional -argument data, which is a NativePointer accessible through -gum_invocation_context_get_listener_function_data(). Use -gum_interceptor_get_current_invocation() to get hold of the -GumInvocationContext *.

    - -

    Note that replacement will be kept alive until Interceptor#revert is -called.

    - -

    If you want to chain to the original implementation you can synchronously -call target through a NativeFunction inside your -implementation, which will bypass and go directly to the original implementation.

    - -

    Here’s an example:

    -
  • -
- -
const openPtr = Module.getExportByName('libc.so', 'open');
-const open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
-Interceptor.replace(openPtr, new NativeCallback((pathPtr, flags) => {
-  const path = pathPtr.readUtf8String();
-  log('Opening "' + path + '"');
-  const fd = open(pathPtr, flags);
-  log('Got fd: ' + fd);
-  return fd;
-}, 'int', ['pointer', 'int']));
- -
    -
  • -

    Interceptor.revert(target): revert function at target to the previous -implementation.

    -
  • -
  • -

    Interceptor.flush(): ensure any pending changes have been committed -to memory. This is should only be done in the few cases where this is -necessary, e.g. if you just attach()ed to or replace()d a function that you -are about to call using NativeFunction. Pending changes -are flushed automatically whenever the current thread is about to leave the -JavaScript runtime or calls send(). This includes any -API built on top of send(), like when returning from an -RPC method, and calling any method on the console API.

    -
  • -
- -

Stalker

- -
    -
  • -

    Stalker.exclude(range): marks the specified memory range as excluded, -which is an object with base and size properties – like the properties -in an object returned by e.g. Process.getModuleByName().

    - -

    This means Stalker will not follow execution when encountering a call to an -instruction in such a range. You will thus be able to observe/modify the -arguments going in, and the return value coming back, but won’t see the -instructions that happened between.

    - -

    Useful to improve performance and reduce noise.

    -
  • -
  • -

    Stalker.follow([threadId, options]): start stalking threadId (or the -current thread if omitted), optionally with options for enabling events.

    - -

    For example:

    -
  • -
- -
const mainThread = Process.enumerateThreads()[0];
-
-Stalker.follow(mainThread.id, {
-  events: {
-    call: true, // CALL instructions: yes please
-
-    // Other events:
-    ret: false, // RET instructions
-    exec: false, // all instructions: not recommended as it's
-                 //                   a lot of data
-    block: false, // block executed: coarse execution trace
-    compile: false // block compiled: useful for coverage
-  },
-
-  //
-  // Only specify one of the two following callbacks.
-  // (See note below.)
-  //
-
-  //
-  // onReceive: Called with `events` containing a binary blob
-  //            comprised of one or more GumEvent structs.
-  //            See `gumevent.h` for details about the
-  //            format. Use `Stalker.parse()` to examine the
-  //            data.
-  //
-  //onReceive(events) {
-  //},
-  //
-
-  //
-  // onCallSummary: Called with `summary` being a key-value
-  //                mapping of call target to number of
-  //                calls, in the current time window. You
-  //                would typically implement this instead of
-  //                `onReceive()` for efficiency, i.e. when
-  //                you only want to know which targets were
-  //                called and how many times, but don't care
-  //                about the order that the calls happened
-  //                in.
-  //
-  onCallSummary(summary) {
-  },
-
-  //
-  // Advanced users: This is how you can plug in your own
-  //                 StalkerTransformer, where the provided
-  //                 function is called synchronously
-  //                 whenever Stalker wants to recompile
-  //                 a basic block of the code that's about
-  //                 to be executed by the stalked thread.
-  //
-  //transform(iterator) {
-  //  let instruction = iterator.next();
-  //
-  //  const startAddress = instruction.address;
-  //  const isAppCode = startAddress.compare(appStart) >= 0 &&
-  //      startAddress.compare(appEnd) === -1;
-  //
-  //  do {
-  //    if (isAppCode && instruction.mnemonic === 'ret') {
-  //      iterator.putCmpRegI32('eax', 60);
-  //      iterator.putJccShortLabel('jb', 'nope', 'no-hint');
-  //
-  //      iterator.putCmpRegI32('eax', 90);
-  //      iterator.putJccShortLabel('ja', 'nope', 'no-hint');
-  //
-  //      iterator.putCallout(onMatch);
-  //
-  //      iterator.putLabel('nope');
-  //    }
-  //
-  //    iterator.keep();
-  //  } while ((instruction = iterator.next()) !== null);
-  //},
-  //
-  // The default implementation is just:
-  //
-  //   while (iterator.next() !== null)
-  //     iterator.keep();
-  //
-  // The example above shows how you can insert your own code
-  // just before every `ret` instruction across any code
-  // executed by the stalked thread inside the app's own
-  // memory range. It inserts code that checks if the `eax`
-  // register contains a value between 60 and 90, and inserts
-  // a synchronous callout back into JavaScript whenever that
-  // is the case. The callback receives a single argument
-  // that gives it access to the CPU registers, and it is
-  // also able to modify them.
-  //
-  // function onMatch (context) {
-  //   console.log('Match! pc=' + context.pc +
-  //       ' rax=' + context.rax.toInt32());
-  // }
-  //
-  // Note that not calling keep() will result in the
-  // instruction getting dropped, which makes it possible
-  // for your transform to fully replace certain instructions
-  // when this is desirable.
-  //
-
-  //
-  // Want better performance? Write the callbacks in C:
-  //
-  // /*
-  //  * const cm = new CModule(\`
-  //  *
-  //  * #include <gum/gumstalker.h>
-  //  *
-  //  * static void on_ret (GumCpuContext * cpu_context,
-  //  *     gpointer user_data);
-  //  *
-  //  * void
-  //  * transform (GumStalkerIterator * iterator,
-  //  *            GumStalkerOutput * output,
-  //  *            gpointer user_data)
-  //  * {
-  //  *   cs_insn * insn;
-  //  *
-  //  *   while (gum_stalker_iterator_next (iterator, &insn))
-  //  *   {
-  //  *     if (insn->id == X86_INS_RET)
-  //  *     {
-  //  *       gum_x86_writer_put_nop (output->writer.x86);
-  //  *       gum_stalker_iterator_put_callout (iterator,
-  //  *           on_ret, NULL, NULL);
-  //  *     }
-  //  *
-  //  *     gum_stalker_iterator_keep (iterator);
-  //  *   }
-  //  * }
-  //  *
-  //  * static void
-  //  * on_ret (GumCpuContext * cpu_context,
-  //  *         gpointer user_data)
-  //  * {
-  //  *   printf ("on_ret!\n");
-  //  * }
-  //  *
-  //  * void
-  //  * process (const GumEvent * event,
-  //  *          GumCpuContext * cpu_context,
-  //  *          gpointer user_data)
-  //  * {
-  //  *   switch (event->type)
-  //  *   {
-  //  *     case GUM_CALL:
-  //  *       break;
-  //  *     case GUM_RET:
-  //  *       break;
-  //  *     case GUM_EXEC:
-  //  *       break;
-  //  *     case GUM_BLOCK:
-  //  *       break;
-  //  *     case GUM_COMPILE:
-  //  *       break;
-  //  *     default:
-  //  *       break;
-  //  *   }
-  //  * }
-  //  * `);
-  //  */
-  //
-  //transform: cm.transform,
-  //onEvent: cm.process,
-  //data: ptr(1337) /* user_data */
-  //
-  // You may also use a hybrid approach and only write
-  // some of the callouts in C.
-  //
-});
- -
-
Performance considerations
-

- The callbacks provided have a significant impact on performance. If you only - need periodic call summaries but do not care about the raw events, or the - other way around, make sure you omit the callback that you don't need; i.e. - avoid putting your logic in onCallSummary and leaving - onReceive in there as an empty callback. -

-

- Also note that Stalker may be used in conjunction with CModule, - which means the callbacks may be implemented in C. -

-
- -
    -
  • -

    Stalker.unfollow([threadId]): stop stalking threadId (or the current -thread if omitted).

    -
  • -
  • -

    Stalker.parse(events[, options]): parse GumEvent binary blob, optionally -with options for customizing the output.

    - -

    For example:

    -
  • -
- -
  onReceive(events) {
-    console.log(Stalker.parse(events, {
-      annotate: true, // to display the type of event
-      stringify: true
-        // to format pointer values as strings instead of `NativePointer`
-        // values, i.e. less overhead if you're just going to `send()` the
-        // thing not actually parse the data agent-side
-    }));
-  },
- -
    -
  • -

    Stalker.flush(): flush out any buffered events. Useful when you don’t want -to wait until the next Stalker.queueDrainInterval tick.

    -
  • -
  • -

    Stalker.garbageCollect(): free accumulated memory at a safe point after -Stalker#unfollow. This is needed to avoid race-conditions -where the thread just unfollowed is executing its last instructions.

    -
  • -
  • -

    Stalker.invalidate(address): invalidates the current thread’s translated -code for a given basic block. Useful when providing a transform callback and -wanting to dynamically adapt the instrumentation for a given basic block. -This is much more efficient than unfollowing and re-following the thread, -which would discard all cached translations and require all encountered -basic blocks to be compiled from scratch.

    -
  • -
  • -

    Stalker.invalidate(threadId, address): invalidates a specific thread’s -translated code for a given basic block. Useful when providing a transform -callback and wanting to dynamically adapt the instrumentation for a given -basic block. This is much more efficient than unfollowing and re-following -the thread, which would discard all cached translations and require all -encountered basic blocks to be compiled from scratch.

    -
  • -
  • -

    Stalker.addCallProbe(address, callback[, data]): call callback (see -Interceptor#attach#onEnter for signature) synchronously -when a call is made to address. Returns an id that can be passed to -Stalker#removeCallProbe later.

    - -

    It is also possible to implement callback in C using CModule, -by specifying a NativePointer instead of a function. Signature:

    - -
      -
    • void onCall (GumCallSite * site, gpointer user_data)
    • -
    - -

    In such cases, the third optional argument data may be a NativePointer -whose value is passed to the callback as user_data.

    -
  • -
  • -

    Stalker.removeCallProbe: remove a call probe added by -Stalker#addCallProbe.

    -
  • -
  • -

    Stalker.trustThreshold: an integer specifying how many times a piece of -code needs to be executed before it is assumed it can be trusted to not -mutate. -Specify -1 for no trust (slow), 0 to trust code from the get-go, and N to -trust code after it has been executed N times. Defaults to 1.

    -
  • -
  • -

    Stalker.queueCapacity: an integer specifying the capacity of the event -queue in number of events. Defaults to 16384 events.

    -
  • -
  • -

    Stalker.queueDrainInterval: an integer specifying the time in milliseconds -between each time the event queue is drained. Defaults to 250 ms, which -means that the event queue is drained four times per second. You may also -set this property to zero to disable periodic draining, and instead call -Stalker.flush() when you would like the queue to be drained.

    -
  • -
- -

ObjC

- -
    -
  • -

    ObjC.available: a boolean specifying whether the current process has an -Objective-C runtime loaded. Do not invoke any other ObjC properties or -methods unless this is the case.

    -
  • -
  • -

    ObjC.api: an object mapping function names to NativeFunction instances -for direct access to a big portion of the Objective-C runtime API.

    -
  • -
  • -

    ObjC.classes: an object mapping class names to ObjC.Object -JavaScript bindings for each of the currently registered classes. You can interact -with objects by using dot notation and replacing colons with underscores, i.e.: -[NSString stringWithString:@"Hello World"] -becomes -const { NSString } = ObjC.classes; NSString.stringWithString - _("Hello World");. -Note the underscore after the method name. Refer to iOS Examples section for -more details.

    -
  • -
  • -

    ObjC.protocols: an object mapping protocol names to ObjC.Protocol -JavaScript bindings for each of the currently registered protocols.

    -
  • -
  • -

    ObjC.mainQueue: the GCD queue of the main thread

    -
  • -
  • -

    ObjC.schedule(queue, work): schedule the JavaScript function work on -the GCD queue specified by queue. An NSAutoreleasePool is created just -before calling work, and cleaned up on return.

    -
  • -
- -
const { NSSound } = ObjC.classes; /* macOS */
-ObjC.schedule(ObjC.mainQueue, function () {
-    const sound = NSSound.alloc().initWithContentsOfFile_byReference_("/Users/oleavr/.Trash/test.mp3", true);
-    sound.play();
-});
- -
    -
  • new ObjC.Object(handle[, protocol]): create a JavaScript binding given -the existing object at handle (a NativePointer). You may -also specify the protocol argument if you’d like to treat handle as an object -implementing a certain protocol only.
  • -
- -
Interceptor.attach(myFunction.implementation, {
-  onEnter(args) {
-    // ObjC: args[0] = self, args[1] = selector, args[2-n] = arguments
-    const myString = new ObjC.Object(args[2]);
-    console.log("String argument: " + myString.toString());
-  }
-});
- -
-

This object has some special properties:

- -
    -
  • $kind: string specifying either instance, class or meta-class
  • -
  • $super: an ObjC.Object instance used for chaining up to -super-class method implementations
  • -
  • $superClass: super-class as an ObjC.Object instance
  • -
  • $class: class of this object as an ObjC.Object instance
  • -
  • $className: string containing the class name of this object
  • -
  • $moduleName: string containing the module path of this object
  • -
  • $protocols: object mapping protocol name to ObjC.Protocol -instance for each of the protocols that this object conforms to
  • -
  • $methods: array containing native method names exposed by this object’s -class and parent classes
  • -
  • $ownMethods: array containing native method names exposed by this object’s -class, not including parent classes
  • -
  • $ivars: object mapping each instance variable name to its current -value, allowing you to read and write each through access and assignment
  • -
- -

There is also an equals(other) method for checking whether two instances - refer to the same underlying object.

- -

Note that all method wrappers provide a clone(options) API to create a new - method wrapper with custom NativeFunction options.

-
- -
    -
  • -

    new ObjC.Protocol(handle): create a JavaScript binding given the existing -protocol at handle (a NativePointer).

    -
  • -
  • -

    new ObjC.Block(target[, options]): create a JavaScript binding given the -existing block at target (a NativePointer), or, to define -a new block, target should be an object specifying the type signature and -JavaScript function to call whenever the block is invoked. The function is -specified with an implementation key, and the signature is specified either -through a types key, or through the retType and argTypes keys. See -ObjC.registerClass() for details.

    - -

    Note that if an existing block lacks signature metadata, you may call -declare(signature), where signature is an object with either a types -key, or retType and argTypes keys, as described above.

    - -

    You may also provide an options object with the same options as supported -by NativeFunction, e.g. to pass traps: 'all' in order -to Stalker.follow() the execution when calling the block.

    - -

    The most common use-case is hooking an existing block, which for a block -expecting two arguments would look something like:

    -
  • -
- -
const pendingBlocks = new Set();
-
-Interceptor.attach(..., {
-  onEnter(args) {
-    const block = new ObjC.Block(args[4]);
-    pendingBlocks.add(block); // Keep it alive
-    const appCallback = block.implementation;
-    block.implementation = (error, value) => {
-      // Do your logging here
-      const result = appCallback(error, value);
-      pendingBlocks.delete(block);
-      return result;
-    };
-  }
-});
- -
    -
  • ObjC.implement(method, fn): create a JavaScript implementation compatible -with the signature of method, where the JavaScript function fn is used -as the implementation. Returns a NativeCallback that you may -assign to an ObjC method’s implementation property.
  • -
- -
const NSSound = ObjC.classes.NSSound; /* macOS */
-const oldImpl = NSSound.play.implementation;
-NSSound.play.implementation = ObjC.implement(NSSound.play, (handle, selector) => {
-  return oldImpl(handle, selector);
-});
-
-const NSView = ObjC.classes.NSView; /* macOS */
-const drawRect = NSView['- drawRect:'];
-const oldImpl = drawRect.implementation;
-drawRect.implementation = ObjC.implement(drawRect, (handle, selector) => {
-  oldImpl(handle, selector);
-});
- -
-

As the implementation property is a NativeFunction and thus also a - NativePointer, you may also use Interceptor to hook functions:

-
- -
const { NSSound } = ObjC.classes; /* macOS */
-Interceptor.attach(NSSound.play.implementation, {
-  onEnter() {
-    send("[NSSound play]");
-  }
-});
- -
    -
  • -

    ObjC.registerProxy(properties): create a new class designed to act as a -proxy for a target object, where properties is an object specifying:

    - -
      -
    • protocols: (optional) Array of protocols this class conforms to.
    • -
    • methods: (optional) Object specifying methods to implement.
    • -
    • events: (optional) Object specifying callbacks for getting notified -about events: -
        -
      • dealloc(): Called right after the object has been deallocated. -This is where you might clean up any associated state.
      • -
      • forward(name): Called with name specifying the method name that -we’re about to forward a call to. This might be where you’d start -out with a temporary callback that just logs the names to help you -decide which methods to override.
      • -
      -
    • -
    -
  • -
- -
const MyConnectionDelegateProxy = ObjC.registerProxy({
-  protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
-  methods: {
-    '- connection:didReceiveResponse:': function (conn, resp) {
-      /* fancy logging code here */
-      /* this.data.foo === 1234 */
-      this.data.target
-          .connection_didReceiveResponse_(conn, resp);
-    },
-    '- connection:didReceiveData:': function (conn, data) {
-      /* other logging code here */
-      this.data.target
-          .connection_didReceiveData_(conn, data);
-    }
-  },
-  events: {
-    forward(name) {
-      console.log('*** forwarding: ' + name);
-    }
-  }
-});
-
-const method = ObjC.classes.NSURLConnection[
-    '- initWithRequest:delegate:startImmediately:'];
-Interceptor.attach(method.implementation, {
-  onEnter(args) {
-    args[3] = new MyConnectionDelegateProxy(args[3], {
-      foo: 1234
-    });
-  }
-});
- -
    -
  • -

    ObjC.registerClass(properties): create a new Objective-C class, where -properties is an object specifying:

    - -
      -
    • name: (optional) String specifying the name of the class; omit this -if you don’t care about the globally visible name and would like the -runtime to auto-generate one for you.
    • -
    • super: (optional) Super-class, or null to create a new root class; -omit to inherit from NSObject.
    • -
    • protocols: (optional) Array of protocols this class conforms to.
    • -
    • methods: (optional) Object specifying methods to implement.
    • -
    -
  • -
- -
const MyConnectionDelegateProxy = ObjC.registerClass({
-  name: 'MyConnectionDelegateProxy',
-  super: ObjC.classes.NSObject,
-  protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
-  methods: {
-    '- init': function () {
-      const self = this.super.init();
-      if (self !== null) {
-        ObjC.bind(self, {
-          foo: 1234
-        });
-      }
-      return self;
-    },
-    '- dealloc': function () {
-      ObjC.unbind(this.self);
-      this.super.dealloc();
-    },
-    '- connection:didReceiveResponse:': function (conn, resp) {
-      /* this.data.foo === 1234 */
-    },
-    /*
-     * But those previous methods are declared assuming that
-     * either the super-class or a protocol we conform to has
-     * the same method so we can grab its type information.
-     * However, if that's not the case, you would write it
-     * like this:
-     */
-    '- connection:didReceiveResponse:': {
-      retType: 'void',
-      argTypes: ['object', 'object'],
-      implementation: function (conn, resp) {
-      }
-    },
-    /* Or grab it from an existing class: */
-    '- connection:didReceiveResponse:': {
-      types: ObjC.classes
-          .Foo['- connection:didReceiveResponse:'].types,
-      implementation: function (conn, resp) {
-      }
-    },
-    /* Or from an existing protocol: */
-    '- connection:didReceiveResponse:': {
-      types: ObjC.protocols.NSURLConnectionDataDelegate
-          .methods['- connection:didReceiveResponse:'].types,
-      implementation: function (conn, resp) {
-      }
-    },
-    /* Or write the signature by hand if you really want to: */
-    '- connection:didReceiveResponse:': {
-      types: '[email protected]:[email protected]@24',
-      implementation: function (conn, resp) {
-      }
-    }
-  }
-});
-
-const proxy = MyConnectionDelegateProxy.alloc().init();
-/* use `proxy`, and later: */
-proxy.release();
- -
    -
  • -

    ObjC.registerProtocol(properties): create a new Objective-C protocol, -where properties is an object specifying:

    - -
      -
    • name: (optional) String specifying the name of the protocol; omit this -if you don’t care about the globally visible name and would like the -runtime to auto-generate one for you.
    • -
    • protocols: (optional) Array of protocols this protocol incorporates.
    • -
    • methods: (optional) Object specifying methods to declare.
    • -
    -
  • -
- -
const MyDataDelegate = ObjC.registerProtocol({
-  name: 'MyDataDelegate',
-  protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
-  methods: {
-    /* You must specify the signature: */
-    '- connection:didStuff:': {
-      retType: 'void',
-      argTypes: ['object', 'object']
-    },
-    /* Or grab it from a method of an existing class: */
-    '- connection:didStuff:': {
-      types: ObjC.classes
-          .Foo['- connection:didReceiveResponse:'].types
-    },
-    /* Or from an existing protocol method: */
-    '- connection:didStuff:': {
-      types: ObjC.protocols.NSURLConnectionDataDelegate
-          .methods['- connection:didReceiveResponse:'].types
-    },
-    /* Or write the signature by hand if you really want to: */
-    '- connection:didStuff:': {
-      types: '[email protected]:[email protected]@24'
-    },
-    /* You can also make a method optional (default is required): */
-    '- connection:didStuff:': {
-      retType: 'void',
-      argTypes: ['object', 'object'],
-      optional: true
-    }
-  }
-});
- -
    -
  • -

    ObjC.bind(obj, data): bind some JavaScript data to an Objective-C -instance; see ObjC.registerClass() for an example.

    -
  • -
  • -

    ObjC.unbind(obj): unbind previous associated JavaScript data from an -Objective-C instance; see ObjC.registerClass() for an example.

    -
  • -
  • -

    ObjC.getBoundData(obj): look up previously bound data from an Objective-C -object.

    -
  • -
  • -

    ObjC.enumerateLoadedClasses([options, ]callbacks): enumerate classes -loaded right now, where callbacks is an object specifying:

    - -
      -
    • -

      onMatch(name, owner): called for each loaded class with the name of -the class as a string, and owner specifying the path to the module -where the class was loaded from. To obtain a JavaScript wrapper for a -given class, do: ObjC.classes[name].

      -
    • -
    • -

      onComplete(): called when all classes have been enumerated.

      -
    • -
    - -

    For example:

    -
  • -
- -
ObjC.enumerateLoadedClasses({
-  onMatch(name, owner) {
-    console.log('onMatch:', name, owner);
-  },
-  onComplete() {
-  }
-});
- -

The optional options argument is an object where you may specify the -ownedBy property to limit enumeration to modules in a given ModuleMap.

- -

For example:

- -
const appModules = new ModuleMap(isAppModule);
-ObjC.enumerateLoadedClasses({ ownedBy: appModules }, {
-  onMatch(name, owner) {
-    console.log('onMatch:', name, owner);
-  },
-  onComplete() {
-  }
-});
-
-function isAppModule(m) {
-  return !/^\/(usr\/lib|System|Developer)\//.test(m.path);
-}
- -
    -
  • -

    ObjC.enumerateLoadedClassesSync([options]): synchronous version of -enumerateLoadedClasses() that returns an object -mapping owner module to an array of class names.

    - -

    For example:

    -
  • -
- -
const appModules = new ModuleMap(isAppModule);
-const appClasses = ObjC.enumerateLoadedClassesSync({ ownedBy: appModules });
-console.log('appClasses:', JSON.stringify(appClasses));
-
-function isAppModule(m) {
-  return !/^\/(usr\/lib|System|Developer)\//.test(m.path);
-}
- -
    -
  • -

    ObjC.choose(specifier, callbacks): enumerate live instances of classes -matching specifier by scanning the heap. specifier is either a class -selector or an object specifying a class selector and desired options. -The class selector is an ObjC.Object of a class, e.g. -ObjC.classes.UIButton. -When passing an object as the specifier you should provide the class -field with your class selector, and the subclasses field with a -boolean indicating whether you’re also interested in subclasses matching the -given class selector. The default is to also include subclasses. -The callbacks argument is an object specifying:

    - -
      -
    • -

      onMatch(instance): called once for each live instance found with a -ready-to-use instance just as if you would have called -new ObjC.Object(ptr("0x1234")) knowing that this -particular Objective-C instance lives at 0x1234.

      - -

      This function may return the string stop to cancel the enumeration -early.

      -
    • -
    • -

      onComplete(): called when all instances have been enumerated

      -
    • -
    -
  • -
  • -

    ObjC.chooseSync(specifier): synchronous version of choose() -that returns the instances in an array.

    -
  • -
  • -

    ObjC.selector(name): convert the JavaScript string name to a selector

    -
  • -
  • -

    ObjC.selectorAsString(sel): convert the selector sel to a JavaScript -string

    -
  • -
- -

Java

- -
    -
  • -

    Java.available: a boolean specifying whether the current process has the -a Java VM loaded, i.e. Dalvik or ART. Do not invoke any other Java -properties or methods unless this is the case.

    -
  • -
  • -

    Java.androidVersion: a string specifying which version of Android we’re -running on.

    -
  • -
  • -

    Java.enumerateLoadedClasses(callbacks): enumerate classes loaded right -now, where callbacks is an object specifying:

    - -
      -
    • -

      onMatch(name, handle): called for each loaded class with name that -may be passed to use() to get a JavaScript wrapper. -You may also Java.cast() the handle to java.lang.Class.

      -
    • -
    • -

      onComplete(): called when all classes have been enumerated.

      -
    • -
    -
  • -
  • -

    Java.enumerateLoadedClassesSync(): synchronous version of -enumerateLoadedClasses() that returns the -class names in an array.

    -
  • -
  • -

    Java.enumerateClassLoaders(callbacks): enumerate class loaders present -in the Java VM, where callbacks is an object specifying:

    - -
      -
    • -

      onMatch(loader): called for each class loader with loader, a wrapper -for the specific java.lang.ClassLoader.

      -
    • -
    • -

      onComplete(): called when all class loaders have been enumerated.

      -
    • -
    - -

    You may pass such a loader to Java.ClassFactory.get() to be able to -.use() classes on the specified class loader.

    -
  • -
  • -

    Java.enumerateClassLoadersSync(): synchronous version of -enumerateClassLoaders() that returns the -class loaders in an array.

    -
  • -
  • -

    Java.enumerateMethods(query): enumerate methods matching query, -specified as "class!method", with globs permitted. May also be suffixed -with / and one or more modifiers:

    - -
      -
    • i: Case-insensitive matching.
    • -
    • s: Include method signatures, so e.g. "putInt" becomes -"putInt(java.lang.String, int): void".
    • -
    • u: User-defined classes only, ignoring system classes.
    • -
    -
  • -
- -
Java.perform(() => {
-  const groups = Java.enumerateMethods('*youtube*!on*')
-  console.log(JSON.stringify(groups, null, 2));
-});
- -
[
-  {
-    "loader": "<instance: java.lang.ClassLoader, $className: dalvik.system.PathClassLoader>",
-    "classes": [
-      {
-        "name": "com.google.android.apps.youtube.app.watch.nextgenwatch.ui.NextGenWatchLayout",
-        "methods": [
-          "onAttachedToWindow",
-          "onDetachedFromWindow",
-          "onFinishInflate",
-          "onInterceptTouchEvent",
-          "onLayout",
-          "onMeasure",
-          "onSizeChanged",
-          "onTouchEvent",
-          "onViewRemoved"
-        ]
-      },
-      {
-        "name": "com.google.android.apps.youtube.app.search.suggest.YouTubeSuggestionProvider",
-        "methods": [
-          "onCreate"
-        ]
-      },
-      {
-        "name": "com.google.android.libraries.youtube.common.ui.YouTubeButton",
-        "methods": [
-          "onInitializeAccessibilityNodeInfo"
-        ]
-      },
-      
-    ]
-  }
-]
- -
    -
  • -

    Java.scheduleOnMainThread(fn): run fn on the main thread of the VM.

    -
  • -
  • -

    Java.perform(fn): ensure that the current thread is attached to the VM -and call fn. (This isn’t necessary in callbacks from Java.) -Will defer calling fn if the app’s class loader is not available yet. -Use Java.performNow() if access to the app’s classes is not needed.

    -
  • -
- -
Java.perform(() => {
-  const Activity = Java.use('android.app.Activity');
-  Activity.onResume.implementation = function () {
-    send('onResume() got called! Let\'s call the original implementation');
-    this.onResume();
-  };
-});
- -
    -
  • -

    Java.performNow(fn): ensure that the current thread is attached to the -VM and call fn. (This isn’t necessary in callbacks from Java.)

    -
  • -
  • -

    Java.use(className): dynamically get a JavaScript wrapper for -className that you can instantiate objects from by calling $new() on -it to invoke a constructor. Call $dispose() on an instance to clean it -up explicitly (or wait for the JavaScript object to get garbage-collected, -or script to get unloaded). Static and non-static methods are available, -and you can even replace a method implementation and throw an exception -from it:

    -
  • -
- -
Java.perform(() => {
-  const Activity = Java.use('android.app.Activity');
-  const Exception = Java.use('java.lang.Exception');
-  Activity.onResume.implementation = function () {
-    throw Exception.$new('Oh noes!');
-  };
-});
- -
-

Uses the app’s class loader by default, but you may customize this by - assigning a different loader instance to Java.classFactory.loader.

- -

Note that all method wrappers provide a clone(options) API to create a new - method wrapper with custom NativeFunction options.

-
- -
    -
  • -

    Java.openClassFile(filePath): open the .dex file at filePath, returning -an object with the following methods:

    - -
      -
    • -

      load(): load the contained classes into the VM.

      -
    • -
    • -

      getClassNames(): obtain an array of available class names.

      -
    • -
    -
  • -
  • -

    Java.choose(className, callbacks): enumerate live instances of the -className class by scanning the Java heap, where callbacks is an -object specifying:

    - -
      -
    • -

      onMatch(instance): called with each live instance found with a -ready-to-use instance just as if you would have called -Java.cast() with a raw handle to this particular instance.

      - -

      This function may return the string stop to cancel the enumeration -early.

      -
    • -
    • -

      onComplete(): called when all instances have been enumerated

      -
    • -
    -
  • -
  • -

    Java.retain(obj): duplicates the JavaScript wrapper obj for later use -outside replacement method.

    -
  • -
- -
Java.perform(() => {
-  const Activity = Java.use('android.app.Activity');
-  let lastActivity = null;
-  Activity.onResume.implementation = function () {
-    lastActivity = Java.retain(this);
-    this.onResume();
-  };
-});
- -
    -
  • Java.cast(handle, klass): create a JavaScript wrapper -given the existing instance at handle of given class klass as returned from -Java.use(). -Such a wrapper also has a class property for getting a wrapper for its -class, and a $className property for getting a string representation of -its class-name.
  • -
- -
const Activity = Java.use('android.app.Activity');
-const activity = Java.cast(ptr('0x1234'), Activity);
- -
    -
  • Java.array(type, elements): creates a Java array with - elements of the specified type, from a JavaScript array elements. The - resulting Java array behaves like a JS array, but can be passed by reference to - Java APIs in order to allow them to modify its contents.
  • -
- -
const values = Java.array('int', [ 1003, 1005, 1007 ]);
-
-const JString = Java.use('java.lang.String');
-const str = JString.$new(Java.array('byte', [ 0x48, 0x65, 0x69 ]));
- -
    -
  • -

    Java.isMainThread(): determine whether the caller is running on the main -thread.

    -
  • -
  • -

    Java.registerClass(spec): create a new Java class and return a wrapper for -it, where spec is an object containing:

    - -
      -
    • name: String specifying the name of the class.
    • -
    • superClass: (optional) Super-class. Omit to inherit from - java.lang.Object.
    • -
    • implements: (optional) Array of interfaces implemented by this class.
    • -
    • fields: (optional) Object specifying the name and type of each field - to expose.
    • -
    • methods: (optional) Object specifying methods to implement.
    • -
    -
  • -
- -
const SomeBaseClass = Java.use('com.example.SomeBaseClass');
-const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
-
-const MyTrustManager = Java.registerClass({
-  name: 'com.example.MyTrustManager',
-  implements: [X509TrustManager],
-  methods: {
-    checkClientTrusted(chain, authType) {
-    },
-    checkServerTrusted(chain, authType) {
-    },
-    getAcceptedIssuers() {
-      return [];
-    },
-  }
-});
-
-const MyWeirdTrustManager = Java.registerClass({
-  name: 'com.example.MyWeirdTrustManager',
-  superClass: SomeBaseClass,
-  implements: [X509TrustManager],
-  fields: {
-    description: 'java.lang.String',
-    limit: 'int',
-  },
-  methods: {
-    $init() {
-      console.log('Constructor called');
-    },
-    checkClientTrusted(chain, authType) {
-      console.log('checkClientTrusted');
-    },
-    checkServerTrusted: [{
-      returnType: 'void',
-      argumentTypes: ['[Ljava.security.cert.X509Certificate;', 'java.lang.String'],
-      implementation(chain, authType) {
-        console.log('checkServerTrusted A');
-      }
-    }, {
-      returnType: 'java.util.List',
-      argumentTypes: ['[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'java.lang.String'],
-      implementation(chain, authType, host) {
-        console.log('checkServerTrusted B');
-        return null;
-      }
-    }],
-    getAcceptedIssuers() {
-      console.log('getAcceptedIssuers');
-      return [];
-    },
-  }
-});
- -
    -
  • -

    Java.deoptimizeEverything(): forces the VM to execute everything with -its interpreter. Necessary to prevent optimizations from bypassing method -hooks in some cases, and allows ART’s Instrumentation APIs to be used for -tracing the runtime.

    -
  • -
  • -

    Java.deoptimizeBootImage(): similar to Java.deoptimizeEverything() but - only deoptimizes boot image code. Use with - dalvik.vm.dex2oat-flags --inline-max-code-units=0 for best results.

    -
  • -
  • -

    Java.vm: object with the following methods:

    - -
      -
    • -

      perform(fn): ensures that the current thread is attached to the VM and -calls fn. (This isn’t necessary in callbacks from Java.)

      -
    • -
    • -

      getEnv(): gets a wrapper for the current thread’s JNIEnv. Throws an -exception if the current thread is not attached to the VM.

      -
    • -
    • -

      tryGetEnv(): tries to get a wrapper for the current thread’s JNIEnv. -Returns null if the current thread is not attached to the VM.

      -
    • -
    -
  • -
  • -

    Java.classFactory: the default class factory used to implement e.g. -Java.use(). Uses the application’s main class loader.

    -
  • -
  • -

    Java.ClassFactory: class with the following properties:

    - -
      -
    • -

      get(classLoader): Gets the class factory instance for a given class -loader. The default class factory used behind the scenes only interacts -with the application’s main class loader. Other class loaders can be -discovered through Java.enumerateClassLoaders() and interacted with -through this API.

      -
    • -
    • -

      loader: read-only property providing a wrapper for the class loader -currently being used. For the default class factory this is updated by -the first call to Java.perform().

      -
    • -
    • -

      cacheDir: string containing path to cache directory currently being -used. For the default class factory this is updated by the first call -to Java.perform().

      -
    • -
    • -

      tempFileNaming: object specifying naming convention to use for -temporary files. Defaults to { prefix: 'frida', suffix: 'dat' }.

      -
    • -
    • -

      use(className): like Java.use() but for a specific class loader.

      -
    • -
    • -

      openClassFile(filePath): like Java.openClassFile() -but for a specific class loader.

      -
    • -
    • -

      choose(className, callbacks): like Java.choose() but for a -specific class loader.

      -
    • -
    • -

      retain(obj): like Java.retain() but for a specific class loader.

      -
    • -
    • -

      cast(handle, klass): like Java.cast() but for a specific class -loader.

      -
    • -
    • -

      array(type, elements): like Java.array() but for a specific class -loader.

      -
    • -
    • -

      registerClass(spec): like Java.registerClass() but for a specific - class loader.

      -
    • -
    -
  • -
- -
- -

CPU Instruction

- -

Instruction

- -
    -
  • -

    Instruction.parse(target): parse the instruction at the target address -in memory, represented by a NativePointer. -Note that on 32-bit ARM this address must have its least significant bit -set to 0 for ARM functions, and 1 for Thumb functions. Frida takes care -of this detail for you if you get the address from a Frida API (for -example Module.getExportByName()).

    - -

    The object returned has the fields:

    - -
      -
    • address: address (EIP) of this instruction, as a NativePointer
    • -
    • next: pointer to the next instruction, so you can parse() it
    • -
    • size: size of this instruction
    • -
    • mnemonic: string representation of instruction mnemonic
    • -
    • opStr: string representation of instruction operands
    • -
    • operands: array of objects describing each operand, each specifying - the type and value, at a minimum, but potentially also - additional properties depending on the architecture
    • -
    • regsRead: array of register names implicitly read by this instruction
    • -
    • regsWritten: array of register names implicitly written to by this -instruction
    • -
    • groups: array of group names that this instruction belongs to
    • -
    • toString(): convert to a human-readable string
    • -
    - -

    For details about operands and groups, please consult the -Capstone documentation for your -architecture.

    -
  • -
- -

X86Writer

- -
    -
  • -

    new X86Writer(codeAddress[, { pc: ptr('0x1234') }]): create a new code -writer for generating x86 machine code written directly to memory at -codeAddress, specified as a NativePointer. -The second argument is an optional options object where the initial program -counter may be specified, which is useful when generating code to a scratch -buffer. This is essential when using Memory.patchCode() -on iOS, which may provide you with a temporary location that later gets mapped -into memory at the intended memory location.

    -
  • -
  • -

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    flush(): resolve label references and write pending data to memory. You -should always call this once you’ve finished generating code. It is usually -also desirable to do this between pieces of unrelated code, e.g. when -generating multiple functions in one go.

    -
  • -
  • -

    base: memory location of the first byte of output, as a NativePointer

    -
  • -
  • -

    code: memory location of the next byte of output, as a NativePointer

    -
  • -
  • -

    pc: program counter at the next byte of output, as a NativePointer

    -
  • -
  • -

    offset: current offset as a JavaScript Number

    -
  • -
  • -

    putLabel(id): put a label at the current position, where id is a string -that may be referenced in past and future put*Label() calls

    -
  • -
  • -

    putCallAddressWithArguments(func, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putCallAddressWithAlignedArguments(func, args): like above, but also -ensures that the argument list is aligned on a 16 byte boundary

    -
  • -
  • -

    putCallRegWithArguments(reg, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putCallRegWithAlignedArguments(reg, args): like above, but also -ensures that the argument list is aligned on a 16 byte boundary

    -
  • -
  • -

    putCallRegOffsetPtrWithArguments(reg, offset, args): put code needed for calling -a C function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putCallAddress(address): put a CALL instruction

    -
  • -
  • -

    putCallReg(reg): put a CALL instruction

    -
  • -
  • -

    putCallRegOffsetPtr(reg, offset): put a CALL instruction

    -
  • -
  • -

    putCallIndirect(addr): put a CALL instruction

    -
  • -
  • -

    putCallIndirectLabel(labelId): put a CALL instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putCallNearLabel(labelId): put a CALL instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putLeave(): put a LEAVE instruction

    -
  • -
  • -

    putRet(): put a RET instruction

    -
  • -
  • -

    putRetImm(immValue): put a RET instruction

    -
  • -
  • -

    putJmpAddress(address): put a JMP instruction

    -
  • -
  • -

    putJmpShortLabel(labelId): put a JMP instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putJmpNearLabel(labelId): put a JMP instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putJmpReg(reg): put a JMP instruction

    -
  • -
  • -

    putJmpRegPtr(reg): put a JMP instruction

    -
  • -
  • -

    putJmpRegOffsetPtr(reg, offset): put a JMP instruction

    -
  • -
  • -

    putJmpNearPtr(address): put a JMP instruction

    -
  • -
  • -

    putJccShort(instructionId, target, hint): put a JCC instruction

    -
  • -
  • -

    putJccNear(instructionId, target, hint): put a JCC instruction

    -
  • -
  • -

    putJccShortLabel(instructionId, labelId, hint): put a JCC instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putJccNearLabel(instructionId, labelId, hint): put a JCC instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putAddRegImm(reg, immValue): put an ADD instruction

    -
  • -
  • -

    putAddRegReg(dstReg, srcReg): put an ADD instruction

    -
  • -
  • -

    putAddRegNearPtr(dstReg, srcAddress): put an ADD instruction

    -
  • -
  • -

    putSubRegImm(reg, immValue): put a SUB instruction

    -
  • -
  • -

    putSubRegReg(dstReg, srcReg): put a SUB instruction

    -
  • -
  • -

    putSubRegNearPtr(dstReg, srcAddress): put a SUB instruction

    -
  • -
  • -

    putIncReg(reg): put an INC instruction

    -
  • -
  • -

    putDecReg(reg): put a DEC instruction

    -
  • -
  • -

    putIncRegPtr(target, reg): put an INC instruction

    -
  • -
  • -

    putDecRegPtr(target, reg): put a DEC instruction

    -
  • -
  • -

    putLockXaddRegPtrReg(dstReg, srcReg): put a LOCK XADD instruction

    -
  • -
  • -

    putLockCmpxchgRegPtrReg(dstReg, srcReg): put a LOCK CMPXCHG instruction

    -
  • -
  • -

    putLockIncImm32Ptr(target): put a LOCK INC IMM32 instruction

    -
  • -
  • -

    putLockDecImm32Ptr(target): put a LOCK DEC IMM32 instruction

    -
  • -
  • -

    putAndRegReg(dstReg, srcReg): put an AND instruction

    -
  • -
  • -

    putAndRegU32(reg, immValue): put an AND instruction

    -
  • -
  • -

    putShlRegU8(reg, immValue): put a SHL instruction

    -
  • -
  • -

    putShrRegU8(reg, immValue): put a SHR instruction

    -
  • -
  • -

    putXorRegReg(dstReg, srcReg): put an XOR instruction

    -
  • -
  • -

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    -
  • -
  • -

    putMovRegU32(dstReg, immValue): put a MOV instruction

    -
  • -
  • -

    putMovRegU64(dstReg, immValue): put a MOV instruction

    -
  • -
  • -

    putMovRegAddress(dstReg, address): put a MOV instruction

    -
  • -
  • -

    putMovRegPtrU32(dstReg, immValue): put a MOV instruction

    -
  • -
  • -

    putMovRegOffsetPtrU32(dstReg, dstOffset, immValue): put a MOV instruction

    -
  • -
  • -

    putMovRegPtrReg(dstReg, srcReg): put a MOV instruction

    -
  • -
  • -

    putMovRegOffsetPtrReg(dstReg, dstOffset, srcReg): put a MOV instruction

    -
  • -
  • -

    putMovRegRegPtr(dstReg, srcReg): put a MOV instruction

    -
  • -
  • -

    putMovRegRegOffsetPtr(dstReg, srcReg, srcOffset): put a MOV instruction

    -
  • -
  • -

    putMovRegBaseIndexScaleOffsetPtr(dstReg, baseReg, indexReg, -scale, offset): put a MOV instruction

    -
  • -
  • -

    putMovRegNearPtr(dstReg, srcAddress): put a MOV instruction

    -
  • -
  • -

    putMovNearPtrReg(dstAddress, srcReg): put a MOV instruction

    -
  • -
  • -

    putMovFsU32PtrReg(fsOffset, srcReg): put a MOV FS instruction

    -
  • -
  • -

    putMovRegFsU32Ptr(dstReg, fsOffset): put a MOV FS instruction

    -
  • -
  • -

    putMovGsU32PtrReg(fsOffset, srcReg): put a MOV GS instruction

    -
  • -
  • -

    putMovRegGsU32Ptr(dstReg, fsOffset): put a MOV GS instruction

    -
  • -
  • -

    putMovqXmm0EspOffsetPtr(offset): put a MOVQ XMM0 ESP instruction

    -
  • -
  • -

    putMovqEaxOffsetPtrXmm0(offset): put a MOVQ EAX XMM0 instruction

    -
  • -
  • -

    putMovdquXmm0EspOffsetPtr(offset): put a MOVDQU XMM0 ESP instruction

    -
  • -
  • -

    putMovdquEaxOffsetPtrXmm0(offset): put a MOVDQU EAX XMM0 instruction

    -
  • -
  • -

    putLeaRegRegOffset(dstReg, srcReg, srcOffset): put a LEA instruction

    -
  • -
  • -

    putXchgRegRegPtr(leftReg, rightReg): put an XCHG instruction

    -
  • -
  • -

    putPushU32(immValue): put a PUSH instruction

    -
  • -
  • -

    putPushNearPtr(address): put a PUSH instruction

    -
  • -
  • -

    putPushReg(reg): put a PUSH instruction

    -
  • -
  • -

    putPopReg(reg): put a POP instruction

    -
  • -
  • -

    putPushImmPtr(immPtr): put a PUSH instruction

    -
  • -
  • -

    putPushax(): put a PUSHAX instruction

    -
  • -
  • -

    putPopax(): put a POPAX instruction

    -
  • -
  • -

    putPushfx(): put a PUSHFX instruction

    -
  • -
  • -

    putPopfx(): put a POPFX instruction

    -
  • -
  • -

    putTestRegReg(regA, regB): put a TEST instruction

    -
  • -
  • -

    putTestRegU32(reg, immValue): put a TEST instruction

    -
  • -
  • -

    putCmpRegI32(reg, immValue): put a CMP instruction

    -
  • -
  • -

    putCmpRegOffsetPtrReg(regA, offset, regB): put a CMP instruction

    -
  • -
  • -

    putCmpImmPtrImmU32(immPtr, immValue): put a CMP instruction

    -
  • -
  • -

    putCmpRegReg(regA, regB): put a CMP instruction

    -
  • -
  • -

    putClc(): put a CLC instruction

    -
  • -
  • -

    putStc(): put a STC instruction

    -
  • -
  • -

    putCld(): put a CLD instruction

    -
  • -
  • -

    putStd(): put a STD instruction

    -
  • -
  • -

    putCpuid(): put a CPUID instruction

    -
  • -
  • -

    putLfence(): put an LFENCE instruction

    -
  • -
  • -

    putRdtsc(): put an RDTSC instruction

    -
  • -
  • -

    putPause(): put a PAUSE instruction

    -
  • -
  • -

    putNop(): put a NOP instruction

    -
  • -
  • -

    putBreakpoint(): put an OS/architecture-specific breakpoint instruction

    -
  • -
  • -

    putPadding(n): put n guard instruction

    -
  • -
  • -

    putNopPadding(n): put n NOP instructions

    -
  • -
  • -

    putU8(value): put a uint8

    -
  • -
  • -

    putS8(value): put an int8

    -
  • -
  • -

    putBytes(data): put raw data from the provided ArrayBuffer

    -
  • -
- -

X86Relocator

- -
    -
  • -

    new X86Relocator(inputCode, output): create a new code relocator for -copying x86 instructions from one memory location to another, taking -care to adjust position-dependent instructions accordingly. -The source address is specified by inputCode, a NativePointer. -The destination is given by output, an X86Writer pointed -at the desired target memory address.

    -
  • -
  • -

    reset(inputCode, output): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    input: latest Instruction read so far. Starts out null -and changes on every call to readOne().

    -
  • -
  • -

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve -reached a branch of any kind, like CALL, JMP, BL, RET.

    -
  • -
  • -

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve -reached JMP/B/RET, an instruction after which there may or may not be valid -code.

    -
  • -
  • -

    readOne(): read the next instruction into the relocator’s internal buffer -and return the number of bytes read so far, including previous calls. -You may keep calling this method to keep buffering, or immediately call -either writeOne() or skipOne(). -Or, you can buffer up until the desired point and then call writeAll(). -Returns zero when end-of-input is reached, which means the eoi property is -now true.

    -
  • -
  • -

    peekNextWriteInsn(): peek at the next Instruction to be -written or skipped

    -
  • -
  • -

    peekNextWriteSource(): peek at the address of the next instruction to be -written or skipped

    -
  • -
  • -

    skipOne(): skip the instruction that would have been written next

    -
  • -
  • -

    skipOneNoLabel(): skip the instruction that would have been written next, -but without a label for internal use. This breaks relocation of branches to -locations inside the relocated range, and is an optimization for use-cases -where all branches are rewritten (e.g. Frida’s Stalker).

    -
  • -
  • -

    writeOne(): write the next buffered instruction

    -
  • -
  • -

    writeOneNoLabel(): write the next buffered instruction, but without a -label for internal use. This breaks relocation of branches to locations -inside the relocated range, and is an optimization for use-cases where all -branches are rewritten (e.g. Frida’s Stalker).

    -
  • -
  • -

    writeAll(): write all buffered instructions

    -
  • -
- -

x86 enum types

- -
    -
  • Register: xax xcx xdx xbx xsp xbp xsi xdi eax ecx edx -ebx esp ebp esi edi rax rcx rdx rbx rsp rbp rsi -rdi r8 r9 r10 r11 r12 r13 r14 r15 r8d r9d r10d -r11d r12d r13d r14d r15d xip eip rip
  • -
  • InstructionId: jo jno jb jae je jne jbe ja js jns jp -jnp jl jge jle jg jcxz jecxz jrcxz
  • -
  • BranchHint: no-hint likely unlikely
  • -
  • PointerTarget: byte dword qword
  • -
- -

ArmWriter

- -
    -
  • -

    new ArmWriter(codeAddress[, { pc: ptr('0x1234') }]): create a new code -writer for generating ARM machine code written directly to memory at -codeAddress, specified as a NativePointer. -The second argument is an optional options object where the initial program -counter may be specified, which is useful when generating code to a scratch -buffer. This is essential when using Memory.patchCode() -on iOS, which may provide you with a temporary location that later gets mapped -into memory at the intended memory location.

    -
  • -
  • -

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    flush(): resolve label references and write pending data to memory. You -should always call this once you’ve finished generating code. It is usually -also desirable to do this between pieces of unrelated code, e.g. when -generating multiple functions in one go.

    -
  • -
  • -

    base: memory location of the first byte of output, as a NativePointer

    -
  • -
  • -

    code: memory location of the next byte of output, as a NativePointer

    -
  • -
  • -

    pc: program counter at the next byte of output, as a NativePointer

    -
  • -
  • -

    offset: current offset as a JavaScript Number

    -
  • -
  • -

    skip(nBytes): skip nBytes

    -
  • -
  • -

    putLabel(id): put a label at the current position, where id is a string -that may be referenced in past and future put*Label() calls

    -
  • -
  • -

    putCallAddressWithArguments(func, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putBranchAddress(address): put code needed for branching/jumping to the -given address

    -
  • -
  • -

    canBranchDirectlyBetween(from, to): determine whether a direct branch is -possible between the two given memory locations

    -
  • -
  • -

    putBImm(target): put a B instruction

    -
  • -
  • -

    putBCondImm(cc, target): put a B COND instruction

    -
  • -
  • -

    putBLabel(labelId): put a B instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBCondLabel(cc, labelId): put a B COND instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBlImm(target): put a BL instruction

    -
  • -
  • -

    putBlxImm(target): put a BLX instruction

    -
  • -
  • -

    putBlLabel(labelId): put a BL instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBxReg(reg): put a BX instruction

    -
  • -
  • -

    putBlxReg(reg): put a BLX instruction

    -
  • -
  • -

    putRet(): put a RET instruction

    -
  • -
  • -

    putLdrRegAddress(reg, address): put an LDR instruction

    -
  • -
  • -

    putLdrRegU32(reg, val): put an LDR instruction

    -
  • -
  • -

    putLdrRegRegOffset(dstReg, srcReg, srcOffset): put an LDR instruction

    -
  • -
  • -

    putLdrCondRegRegOffset(cc, dstReg, srcReg, srcOffset): put an LDR COND instruction

    -
  • -
  • -

    putLdmiaRegMask(reg, mask): put an LDMIA MASK instruction

    -
  • -
  • -

    putStrRegRegOffset(srcReg, dstReg, dstOffset): put a STR instruction

    -
  • -
  • -

    putStrCondRegRegOffset(cc, srcReg, dstReg, dstOffset): put a STR COND instruction

    -
  • -
  • -

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    -
  • -
  • -

    putMovRegRegShift(dstReg, srcReg, shift, shiftValue): put a MOV SHIFT instruction

    -
  • -
  • -

    putMovRegCpsr(reg): put a MOV CPSR instruction

    -
  • -
  • -

    putMovCpsrReg(reg): put a MOV CPSR instruction

    -
  • -
  • -

    putAddRegU16(dstReg, val): put an ADD U16 instruction

    -
  • -
  • -

    putAddRegU32(dstReg, val): put an ADD instruction

    -
  • -
  • -

    putAddRegRegImm(dstReg, srcReg, immVal): put an ADD instruction

    -
  • -
  • -

    putAddRegRegReg(dstReg, srcReg1, srcReg2): put an ADD instruction

    -
  • -
  • -

    putAddRegRegRegShift(dstReg, srcReg1, srcReg2, shift, - shiftValue): put an ADD SHIFT instruction

    -
  • -
  • -

    putSubRegU16(dstReg, val): put a SUB U16 instruction

    -
  • -
  • -

    putSubRegU32(dstReg, val): put a SUB instruction

    -
  • -
  • -

    putSubRegRegImm(dstReg, srcReg, immVal): put a SUB instruction

    -
  • -
  • -

    putSubRegRegReg(dstReg, srcReg1, srcReg2): put a SUB instruction

    -
  • -
  • -

    putAndsRegRegImm(dstReg, srcReg, immVal): put an ANDS instruction

    -
  • -
  • -

    putCmpRegImm(dstReg, immVal): put a CMP instruction

    -
  • -
  • -

    putNop(): put a NOP instruction

    -
  • -
  • -

    putBreakpoint(): put an OS/architecture-specific breakpoint instruction

    -
  • -
  • -

    putBrkImm(imm): put a BRK instruction

    -
  • -
  • -

    putInstruction(insn): put a raw instruction as a JavaScript Number

    -
  • -
  • -

    putBytes(data): put raw data from the provided ArrayBuffer

    -
  • -
- -

ArmRelocator

- -
    -
  • -

    new ArmRelocator(inputCode, output): create a new code relocator for -copying ARM instructions from one memory location to another, taking -care to adjust position-dependent instructions accordingly. -The source address is specified by inputCode, a NativePointer. -The destination is given by output, an ArmWriter pointed -at the desired target memory address.

    -
  • -
  • -

    reset(inputCode, output): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    input: latest Instruction read so far. Starts out null -and changes on every call to readOne().

    -
  • -
  • -

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve -reached a branch of any kind, like CALL, JMP, BL, RET.

    -
  • -
  • -

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve -reached JMP/B/RET, an instruction after which there may or may not be valid -code.

    -
  • -
  • -

    readOne(): read the next instruction into the relocator’s internal buffer -and return the number of bytes read so far, including previous calls. -You may keep calling this method to keep buffering, or immediately call -either writeOne() or skipOne(). -Or, you can buffer up until the desired point and then call writeAll(). -Returns zero when end-of-input is reached, which means the eoi property is -now true.

    -
  • -
  • -

    peekNextWriteInsn(): peek at the next Instruction to be -written or skipped

    -
  • -
  • -

    peekNextWriteSource(): peek at the address of the next instruction to be -written or skipped

    -
  • -
  • -

    skipOne(): skip the instruction that would have been written next

    -
  • -
  • -

    writeOne(): write the next buffered instruction

    -
  • -
  • -

    writeAll(): write all buffered instructions

    -
  • -
- -

ThumbWriter

- -
    -
  • -

    new ThumbWriter(codeAddress[, { pc: ptr('0x1234') }]): create a new code -writer for generating ARM machine code written directly to memory at -codeAddress, specified as a NativePointer. -The second argument is an optional options object where the initial program -counter may be specified, which is useful when generating code to a scratch -buffer. This is essential when using Memory.patchCode() -on iOS, which may provide you with a temporary location that later gets mapped -into memory at the intended memory location.

    -
  • -
  • -

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    flush(): resolve label references and write pending data to memory. You -should always call this once you’ve finished generating code. It is usually -also desirable to do this between pieces of unrelated code, e.g. when -generating multiple functions in one go.

    -
  • -
  • -

    base: memory location of the first byte of output, as a NativePointer

    -
  • -
  • -

    code: memory location of the next byte of output, as a NativePointer

    -
  • -
  • -

    pc: program counter at the next byte of output, as a NativePointer

    -
  • -
  • -

    offset: current offset as a JavaScript Number

    -
  • -
  • -

    skip(nBytes): skip nBytes

    -
  • -
  • -

    putLabel(id): put a label at the current position, where id is a string -that may be referenced in past and future put*Label() calls

    -
  • -
  • -

    commitLabel(id): commit the first pending reference to the given label, -returning true on success. Returns false if the given label hasn’t been -defined yet, or there are no more pending references to it.

    -
  • -
  • -

    putCallAddressWithArguments(func, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putCallRegWithArguments(reg, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putBImm(target): put a B instruction

    -
  • -
  • -

    putBLabel(labelId): put a B instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBLabelWide(labelId): put a B WIDE instruction

    -
  • -
  • -

    putBxReg(reg): put a BX instruction

    -
  • -
  • -

    putBlImm(target): put a BL instruction

    -
  • -
  • -

    putBlLabel(labelId): put a BL instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBlxImm(target): put a BLX instruction

    -
  • -
  • -

    putBlxReg(reg): put a BLX instruction

    -
  • -
  • -

    putCmpRegImm(reg, immValue): put a CMP instruction

    -
  • -
  • -

    putBeqLabel(labelId): put a BEQ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBneLabel(labelId): put a BNE instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBCondLabel(cc, labelId): put a B COND instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBCondLabelWide(cc, labelId): put a B COND WIDE instruction

    -
  • -
  • -

    putCbzRegLabel(reg, labelId): put a CBZ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putCbnzRegLabel(reg, labelId): put a CBNZ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putPushRegs(regs): put a PUSH instruction with the specified registers, -specified as a JavaScript array where each element is a string specifying -the register name.

    -
  • -
  • -

    putPopRegs(regs): put a POP instruction with the specified registers, -specified as a JavaScript array where each element is a string specifying -the register name.

    -
  • -
  • -

    putLdrRegAddress(reg, address): put an LDR instruction

    -
  • -
  • -

    putLdrRegU32(reg, val): put an LDR instruction

    -
  • -
  • -

    putLdrRegReg(dstReg, srcReg): put an LDR instruction

    -
  • -
  • -

    putLdrRegRegOffset(dstReg, srcReg, srcOffset): put an LDR instruction

    -
  • -
  • -

    putLdrbRegReg(dstReg, srcReg): put an LDRB instruction

    -
  • -
  • -

    putVldrRegRegOffset(dstReg, srcReg, srcOffset): put a VLDR instruction

    -
  • -
  • -

    putLdmiaRegMask(reg, mask): put an LDMIA MASK instruction

    -
  • -
  • -

    putStrRegReg(srcReg, dstReg): put a STR instruction

    -
  • -
  • -

    putStrRegRegOffset(srcReg, dstReg, dstOffset): put a STR instruction

    -
  • -
  • -

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    -
  • -
  • -

    putMovRegU8(dstReg, immValue): put a MOV instruction

    -
  • -
  • -

    putMovRegCpsr(reg): put a MOV CPSR instruction

    -
  • -
  • -

    putMovCpsrReg(reg): put a MOV CPSR instruction

    -
  • -
  • -

    putAddRegImm(dstReg, immValue): put an ADD instruction

    -
  • -
  • -

    putAddRegReg(dstReg, srcReg): put an ADD instruction

    -
  • -
  • -

    putAddRegRegReg(dstReg, leftReg, rightReg): put an ADD instruction

    -
  • -
  • -

    putAddRegRegImm(dstReg, leftReg, rightValue): put an ADD instruction

    -
  • -
  • -

    putSubRegImm(dstReg, immValue): put a SUB instruction

    -
  • -
  • -

    putSubRegReg(dstReg, srcReg): put a SUB instruction

    -
  • -
  • -

    putSubRegRegReg(dstReg, leftReg, rightReg): put a SUB instruction

    -
  • -
  • -

    putSubRegRegImm(dstReg, leftReg, rightValue): put a SUB instruction

    -
  • -
  • -

    putAndRegRegImm(dstReg, leftReg, rightValue): put an AND instruction

    -
  • -
  • -

    putLslsRegRegImm(dstReg, leftReg, rightValue): put a LSLS instruction

    -
  • -
  • -

    putLsrsRegRegImm(dstReg, leftReg, rightValue): put a LSRS instruction

    -
  • -
  • -

    putMrsRegReg(dstReg, srcReg): put a MRS instruction

    -
  • -
  • -

    putMsrRegReg(dstReg, srcReg): put a MSR instruction

    -
  • -
  • -

    putNop(): put a NOP instruction

    -
  • -
  • -

    putBkptImm(imm): put a BKPT instruction

    -
  • -
  • -

    putBreakpoint(): put an OS/architecture-specific breakpoint instruction

    -
  • -
  • -

    putInstruction(insn): put a raw instruction as a JavaScript Number

    -
  • -
  • -

    putInstructionWide(upper, lower): put a raw Thumb-2 instruction from -two JavaScript Number values

    -
  • -
  • -

    putBytes(data): put raw data from the provided ArrayBuffer

    -
  • -
- -

ThumbRelocator

- -
    -
  • -

    new ThumbRelocator(inputCode, output): create a new code relocator for -copying ARM instructions from one memory location to another, taking -care to adjust position-dependent instructions accordingly. -The source address is specified by inputCode, a NativePointer. -The destination is given by output, a ThumbWriter pointed -at the desired target memory address.

    -
  • -
  • -

    reset(inputCode, output): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    input: latest Instruction read so far. Starts out null -and changes on every call to readOne().

    -
  • -
  • -

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve -reached a branch of any kind, like CALL, JMP, BL, RET.

    -
  • -
  • -

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve -reached JMP/B/RET, an instruction after which there may or may not be valid -code.

    -
  • -
  • -

    readOne(): read the next instruction into the relocator’s internal buffer -and return the number of bytes read so far, including previous calls. -You may keep calling this method to keep buffering, or immediately call -either writeOne() or skipOne(). -Or, you can buffer up until the desired point and then call writeAll(). -Returns zero when end-of-input is reached, which means the eoi property is -now true.

    -
  • -
  • -

    peekNextWriteInsn(): peek at the next Instruction to be -written or skipped

    -
  • -
  • -

    peekNextWriteSource(): peek at the address of the next instruction to be -written or skipped

    -
  • -
  • -

    skipOne(): skip the instruction that would have been written next

    -
  • -
  • -

    writeOne(): write the next buffered instruction

    -
  • -
  • -

    copyOne(): copy out the next buffered instruction without advancing the -output cursor, allowing the same instruction to be written out multiple -times

    -
  • -
  • -

    writeAll(): write all buffered instructions

    -
  • -
- -

ARM enum types

- -
    -
  • Register: r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 -r12 r13 r14 r15 sp lr sb sl fp ip pc
  • -
  • SystemRegister: apsr-nzcvq
  • -
  • ConditionCode: eq ne hs lo mi pl vs vc hi ls ge lt -gt le al
  • -
  • Shifter: asr lsl lsr ror rrx asr-reg lsl-reg lsr-reg -ror-reg rrx-reg
  • -
- -

Arm64Writer

- -
    -
  • -

    new Arm64Writer(codeAddress[, { pc: ptr('0x1234') }]): create a new code -writer for generating AArch64 machine code written directly to memory at -codeAddress, specified as a NativePointer. -The second argument is an optional options object where the initial program -counter may be specified, which is useful when generating code to a scratch -buffer. This is essential when using Memory.patchCode() -on iOS, which may provide you with a temporary location that later gets mapped -into memory at the intended memory location.

    -
  • -
  • -

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    flush(): resolve label references and write pending data to memory. You -should always call this once you’ve finished generating code. It is usually -also desirable to do this between pieces of unrelated code, e.g. when -generating multiple functions in one go.

    -
  • -
  • -

    base: memory location of the first byte of output, as a NativePointer

    -
  • -
  • -

    code: memory location of the next byte of output, as a NativePointer

    -
  • -
  • -

    pc: program counter at the next byte of output, as a NativePointer

    -
  • -
  • -

    offset: current offset as a JavaScript Number

    -
  • -
  • -

    skip(nBytes): skip nBytes

    -
  • -
  • -

    putLabel(id): put a label at the current position, where id is a string -that may be referenced in past and future put*Label() calls

    -
  • -
  • -

    putCallAddressWithArguments(func, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putCallRegWithArguments(reg, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putBranchAddress(address): put code needed for branching/jumping to the -given address

    -
  • -
  • -

    canBranchDirectlyBetween(from, to): determine whether a direct branch is -possible between the two given memory locations

    -
  • -
  • -

    putBImm(address): put a B instruction

    -
  • -
  • -

    putBLabel(labelId): put a B instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBCondLabel(cc, labelId): put a B COND instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBlImm(address): put a BL instruction

    -
  • -
  • -

    putBlLabel(labelId): put a BL instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putBrReg(reg): put a BR instruction

    -
  • -
  • -

    putBrRegNoAuth(reg): put a BR instruction expecting a raw pointer -without any authentication bits

    -
  • -
  • -

    putBlrReg(reg): put a BLR instruction

    -
  • -
  • -

    putBlrRegNoAuth(reg): put a BLR instruction expecting a raw pointer -without any authentication bits

    -
  • -
  • -

    putRet(): put a RET instruction

    -
  • -
  • -

    putCbzRegLabel(reg, labelId): put a CBZ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putCbnzRegLabel(reg, labelId): put a CBNZ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putTbzRegImmLabel(reg, bit, labelId): put a TBZ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putTbnzRegImmLabel(reg, bit, labelId): put a TBNZ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putPushRegReg(regA, regB): put a PUSH instruction

    -
  • -
  • -

    putPopRegReg(regA, regB): put a POP instruction

    -
  • -
  • -

    putPushAllXRegisters(): put code needed for pushing all X registers on the stack

    -
  • -
  • -

    putPopAllXRegisters(): put code needed for popping all X registers off the stack

    -
  • -
  • -

    putPushAllQRegisters(): put code needed for pushing all Q registers on the stack

    -
  • -
  • -

    putPopAllQRegisters(): put code needed for popping all Q registers off the stack

    -
  • -
  • -

    putLdrRegAddress(reg, address): put an LDR instruction

    -
  • -
  • -

    putLdrRegU64(reg, val): put an LDR instruction

    -
  • -
  • -

    putLdrRegRef(reg): put an LDR instruction with a dangling data reference, -returning an opaque ref value that should be passed to putLdrRegValue() -at the desired location

    -
  • -
  • -

    putLdrRegValue(ref, value): put the value and update the LDR instruction -from a previous putLdrRegRef()

    -
  • -
  • -

    putLdrRegRegOffset(dstReg, srcReg, srcOffset): put an LDR instruction

    -
  • -
  • -

    putLdrswRegRegOffset(dstReg, srcReg, srcOffset): put an LDRSW instruction

    -
  • -
  • -

    putAdrpRegAddress(reg, address): put an ADRP instruction

    -
  • -
  • -

    putStrRegRegOffset(srcReg, dstReg, dstOffset): put a STR instruction

    -
  • -
  • -

    putLdpRegRegRegOffset(regA, regB, regSrc, srcOffset, mode): put an LDP instruction

    -
  • -
  • -

    putStpRegRegRegOffset(regA, regB, regDst, dstOffset, mode): put a STP instruction

    -
  • -
  • -

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    -
  • -
  • -

    putUxtwRegReg(dstReg, srcReg): put an UXTW instruction

    -
  • -
  • -

    putAddRegRegImm(dstReg, leftReg, rightValue): put an ADD instruction

    -
  • -
  • -

    putAddRegRegReg(dstReg, leftReg, rightReg): put an ADD instruction

    -
  • -
  • -

    putSubRegRegImm(dstReg, leftReg, rightValue): put a SUB instruction

    -
  • -
  • -

    putSubRegRegReg(dstReg, leftReg, rightReg): put a SUB instruction

    -
  • -
  • -

    putAndRegRegImm(dstReg, leftReg, rightValue): put an AND instruction

    -
  • -
  • -

    putTstRegImm(reg, immValue): put a TST instruction

    -
  • -
  • -

    putCmpRegReg(regA, regB): put a CMP instruction

    -
  • -
  • -

    putXpaciReg(reg): put an XPACI instruction

    -
  • -
  • -

    putNop(): put a NOP instruction

    -
  • -
  • -

    putBrkImm(imm): put a BRK instruction

    -
  • -
  • -

    putInstruction(insn): put a raw instruction as a JavaScript Number

    -
  • -
  • -

    putBytes(data): put raw data from the provided ArrayBuffer

    -
  • -
  • -

    sign(value): sign the given pointer value

    -
  • -
- -

Arm64Relocator

- -
    -
  • -

    new Arm64Relocator(inputCode, output): create a new code relocator for -copying AArch64 instructions from one memory location to another, taking -care to adjust position-dependent instructions accordingly. -The source address is specified by inputCode, a NativePointer. -The destination is given by output, an Arm64Writer pointed -at the desired target memory address.

    -
  • -
  • -

    reset(inputCode, output): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    input: latest Instruction read so far. Starts out null -and changes on every call to readOne().

    -
  • -
  • -

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve -reached a branch of any kind, like CALL, JMP, BL, RET.

    -
  • -
  • -

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve -reached JMP/B/RET, an instruction after which there may or may not be valid -code.

    -
  • -
  • -

    readOne(): read the next instruction into the relocator’s internal buffer -and return the number of bytes read so far, including previous calls. -You may keep calling this method to keep buffering, or immediately call -either writeOne() or skipOne(). -Or, you can buffer up until the desired point and then call writeAll(). -Returns zero when end-of-input is reached, which means the eoi property is -now true.

    -
  • -
  • -

    peekNextWriteInsn(): peek at the next Instruction to be -written or skipped

    -
  • -
  • -

    peekNextWriteSource(): peek at the address of the next instruction to be -written or skipped

    -
  • -
  • -

    skipOne(): skip the instruction that would have been written next

    -
  • -
  • -

    writeOne(): write the next buffered instruction

    -
  • -
  • -

    writeAll(): write all buffered instructions

    -
  • -
- -

AArch64 enum types

- -
    -
  • Register: x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 -x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 -x24 x25 x26 x27 x28 x29 x30 w0 w1 w2 w3 w4 w5 -w6 w7 w8 w9 w10 w11 w12 w13 w14 w15 w16 w17 w18 -w19 w20 w21 w22 w23 w24 w25 w26 w27 w28 w29 w30 -sp lr fp wsp wzr xzr nzcv ip0 ip1 s0 s1 s2 s3 -s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 -s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 -s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 -d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 -d23 d24 d25 d26 d27 d28 d29 d30 d31 q0 q1 q2 q3 -q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 q16 -q17 q18 q19 q20 q21 q22 q23 q24 q25 q26 q27 q28 -q29 q30 q31
  • -
  • ConditionCode: eq ne hs lo mi pl vs vc hi ls ge lt -gt le al nv
  • -
  • IndexMode: post-adjust signed-offset pre-adjust
  • -
- -

MipsWriter

- -
    -
  • -

    new MipsWriter(codeAddress[, { pc: ptr('0x1234') }]): create a new code -writer for generating MIPS machine code written directly to memory at -codeAddress, specified as a NativePointer. -The second argument is an optional options object where the initial program -counter may be specified, which is useful when generating code to a scratch -buffer. This is essential when using Memory.patchCode() -on iOS, which may provide you with a temporary location that later gets mapped -into memory at the intended memory location.

    -
  • -
  • -

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    flush(): resolve label references and write pending data to memory. You -should always call this once you’ve finished generating code. It is usually -also desirable to do this between pieces of unrelated code, e.g. when -generating multiple functions in one go.

    -
  • -
  • -

    base: memory location of the first byte of output, as a NativePointer

    -
  • -
  • -

    code: memory location of the next byte of output, as a NativePointer

    -
  • -
  • -

    pc: program counter at the next byte of output, as a NativePointer

    -
  • -
  • -

    offset: current offset as a JavaScript Number

    -
  • -
  • -

    skip(nBytes): skip nBytes

    -
  • -
  • -

    putLabel(id): put a label at the current position, where id is a string -that may be referenced in past and future put*Label() calls

    -
  • -
  • -

    putCallAddressWithArguments(func, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putCallRegWithArguments(reg, args): put code needed for calling a C -function with the specified args, specified as a JavaScript array where -each element is either a string specifying the register, or a Number or -NativePointer specifying the immediate value.

    -
  • -
  • -

    putJAddress(address): put a J instruction

    -
  • -
  • -

    putJAddressWithoutNop(address): put a J WITHOUT NOP instruction

    -
  • -
  • -

    putJLabel(labelId): put a J instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putJrReg(reg): put a JR instruction

    -
  • -
  • -

    putJalAddress(address): put a JAL instruction

    -
  • -
  • -

    putJalrReg(reg): put a JALR instruction

    -
  • -
  • -

    putBOffset(offset): put a B instruction

    -
  • -
  • -

    putBeqRegRegLabel(rightReg, leftReg, labelId): put a BEQ instruction -referencing labelId, defined by a past or future putLabel()

    -
  • -
  • -

    putRet(): put a RET instruction

    -
  • -
  • -

    putLaRegAddress(reg, address): put a LA instruction

    -
  • -
  • -

    putLuiRegImm(reg, imm): put a LUI instruction

    -
  • -
  • -

    putDsllRegReg(dstReg, srcReg, amount): put a DSLL instruction

    -
  • -
  • -

    putOriRegRegImm(rt, rs, imm): put an ORI instruction

    -
  • -
  • -

    putLdRegRegOffset(dstReg, srcReg, srcOffset): put an LD instruction

    -
  • -
  • -

    putLwRegRegOffset(dstReg, srcReg, srcOffset): put a LW instruction

    -
  • -
  • -

    putSwRegRegOffset(srcReg, dstReg, dstOffset): put a SW instruction

    -
  • -
  • -

    putMoveRegReg(dstReg, srcReg): put a MOVE instruction

    -
  • -
  • -

    putAdduRegRegReg(dstReg, leftReg, rightReg): put an ADDU instruction

    -
  • -
  • -

    putAddiRegRegImm(dstReg, leftReg, imm): put an ADDI instruction

    -
  • -
  • -

    putAddiRegImm(dstReg, imm): put an ADDI instruction

    -
  • -
  • -

    putSubRegRegImm(dstReg, leftReg, imm): put a SUB instruction

    -
  • -
  • -

    putPushReg(reg): put a PUSH instruction

    -
  • -
  • -

    putPopReg(reg): put a POP instruction

    -
  • -
  • -

    putMfhiReg(reg): put a MFHI instruction

    -
  • -
  • -

    putMfloReg(reg): put a MFLO instruction

    -
  • -
  • -

    putMthiReg(reg): put a MTHI instruction

    -
  • -
  • -

    putMtloReg(reg): put a MTLO instruction

    -
  • -
  • -

    putNop(): put a NOP instruction

    -
  • -
  • -

    putBreak(): put a BREAK instruction

    -
  • -
  • -

    putPrologueTrampoline(reg, address): put a minimal sized trampoline for -vectoring to the given address

    -
  • -
  • -

    putInstruction(insn): put a raw instruction as a JavaScript Number

    -
  • -
  • -

    putBytes(data): put raw data from the provided ArrayBuffer

    -
  • -
- -

MipsRelocator

- -
    -
  • -

    new MipsRelocator(inputCode, output): create a new code relocator for -copying MIPS instructions from one memory location to another, taking -care to adjust position-dependent instructions accordingly. -The source address is specified by inputCode, a NativePointer. -The destination is given by output, a MipsWriter pointed -at the desired target memory address.

    -
  • -
  • -

    reset(inputCode, output): recycle instance

    -
  • -
  • -

    dispose(): eagerly clean up memory

    -
  • -
  • -

    input: latest Instruction read so far. Starts out null -and changes on every call to readOne().

    -
  • -
  • -

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve -reached a branch of any kind, like CALL, JMP, BL, RET.

    -
  • -
  • -

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve -reached JMP/B/RET, an instruction after which there may or may not be valid -code.

    -
  • -
  • -

    readOne(): read the next instruction into the relocator’s internal buffer -and return the number of bytes read so far, including previous calls. -You may keep calling this method to keep buffering, or immediately call -either writeOne() or skipOne(). -Or, you can buffer up until the desired point and then call writeAll(). -Returns zero when end-of-input is reached, which means the eoi property is -now true.

    -
  • -
  • -

    peekNextWriteInsn(): peek at the next Instruction to be -written or skipped

    -
  • -
  • -

    peekNextWriteSource(): peek at the address of the next instruction to be -written or skipped

    -
  • -
  • -

    skipOne(): skip the instruction that would have been written next

    -
  • -
  • -

    writeOne(): write the next buffered instruction

    -
  • -
  • -

    writeAll(): write all buffered instructions

    -
  • -
- -

MIPS enum types

- -
    -
  • Register: v0 v1 a0 a1 a2 a3 t0 t1 t2 t3 t4 t5 t6 -t7 s0 s1 s2 s3 s4 s5 s6 s7 t8 t9 k0 k1 gp sp -fp s8 ra hi lo zero at 0 1 2 3 4 5 6 7 8 -9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 -24 25 26 27 28 29 30 31
  • -
- -
- -

Others

- -

Console

- -
    -
  • -

    console.log(line), console.warn(line), console.error(line): -write line to the console of your Frida-based application. The exact -behavior depends on where frida-core -is integrated. -For example, this output goes to stdout or stderr when using Frida -through frida-python, -qDebug when using -frida-qml, etc.

    - -

    Arguments that are ArrayBuffer objects will be substituted by -the result of hexdump() with default options.

    -
  • -
- -

Hexdump

- -
    -
  • -

    hexdump(target[, options]): generate a hexdump from the provided -ArrayBuffer or NativePointer target, -optionally with options for customizing the output.

    - -

    For example:

    -
  • -
- -
const libc = Module.findBaseAddress('libc.so');
-console.log(hexdump(libc, {
-  offset: 0,
-  length: 64,
-  header: true,
-  ansi: true
-}));
- -
           0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
-00000000  7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  .ELF............
-00000010  03 00 28 00 01 00 00 00 00 00 00 00 34 00 00 00  ..(.........4...
-00000020  34 a8 04 00 00 00 00 05 34 00 20 00 08 00 28 00  4.......4. ...(.
-00000030  1e 00 1d 00 06 00 00 00 34 00 00 00 34 00 00 00  ........4...4...
- -

Shorthand

- - - -

Communication between host and injected process

- -
    -
  • -

    recv([type, ]callback): request callback to be called on the next -message received from your Frida-based application. Optionally type may -be specified to only receive a message where the type field is set to -type.

    - -

    This will only give you one message, so you need to call recv() again -to receive the next one.

    -
  • -
  • -

    send(message[, data]): send the JavaScript object message to your -Frida-based application (it must be serializable to JSON). If you also have -some raw binary data that you’d like to send along with it, e.g. you dumped -some memory using NativePointer#readByteArray, -then you may pass this through the optional data argument. This requires it to -either be an ArrayBuffer or an array of integers between -0 and 255.

    - -
    -
    Performance considerations
    -

    - While send() is asynchronous, the total overhead of sending a single - message is not optimized for high frequencies, so that means Frida leaves - it up to you to batch multiple values into a single send()-call, - based on whether low delay or high throughput is desired. -

    -
    -
  • -
  • -

    rpc.exports: empty object that you can either replace or insert into to -expose an RPC-style API to your application. The key specifies the method -name and the value is your exported function. This function may either -return a plain value for returning that to the caller immediately, or a -Promise for returning asynchronously.

    -
  • -
- -
-

For example:

-
- -
rpc.exports = {
-  add(a, b) {
-    return a + b;
-  },
-  sub(a, b) {
-    return new Promise(resolve => {
-      setTimeout(() => {
-        resolve(a - b);
-      }, 100);
-    });
-  }
-};
- -
-

From an application using the Node.js bindings this API would be consumed - like this:

-
- -
const frida = require('frida');
-const fs = require('fs');
-const path = require('path');
-const util = require('util');
-
-const readFile = util.promisify(fs.readFile);
-
-let session, script;
-async function run() {
-  const source = await readFile(path.join(__dirname, '_agent.js'), 'utf8');
-  session = await frida.attach('iTunes');
-  script = await session.createScript(source);
-  script.message.connect(onMessage);
-  await script.load();
-  console.log(await script.exports.add(2, 3));
-  console.log(await script.exports.sub(5, 3));
-}
-
-run().catch(onError);
-
-function onError(error) {
-  console.error(error.stack);
-}
-
-function onMessage(message, data) {
-  if (message.type === 'send') {
-    console.log(message.payload);
-  } else if (message.type === 'error') {
-    console.error(message.stack);
-  }
-}
- -
-

The Python version would be very similar:

-
- -
import codecs
-import frida
-
-def on_message(message, data):
-    if message['type'] == 'send':
-        print(message['payload'])
-    elif message['type'] == 'error':
-        print(message['stack'])
-
-session = frida.attach('iTunes')
-with codecs.open('./agent.js', 'r', 'utf-8') as f:
-    source = f.read()
-script = session.create_script(source)
-script.on('message', on_message)
-script.load()
-print(script.exports.add(2, 3))
-print(script.exports.sub(5, 3))
-session.detach()
- -

In the example above we used script.on('message', on_message) to monitor for -any messages from the injected process, JavaScript side. There are other -notifications that you can watch for as well on both the script and session. -If you want to be notified when the target process exits, use -session.on('detached', your_function).

- -

Timing events

- -
    -
  • -

    setTimeout(func, delay[, ...parameters]): call func after delay -milliseconds, optionally passing it one or more parameters. -Returns an id that can be passed to clearTimeout to cancel it.

    -
  • -
  • -

    clearTimeout(id): cancel id returned by call to setTimeout.

    -
  • -
  • -

    setInterval(func, delay[, ...parameters]): call func every delay -milliseconds, optionally passing it one or more parameters. -Returns an id that can be passed to clearInterval to cancel it.

    -
  • -
  • -

    clearInterval(id): cancel id returned by call to setInterval.

    -
  • -
  • -

    setImmediate(func[, ...parameters]): schedules func to be called on -Frida’s JavaScript thread as soon as possible, optionally passing it one -or more parameters. -Returns an id that can be passed to clearImmediate to cancel it.

    -
  • -
  • -

    clearImmediate(id): cancel id returned by call to setImmediate.

    -
  • -
- -

Garbage collection

+ -
    -
  • gc(): force garbage collection. Useful for testing, especially logic -involving Script.bindWeak().
  • -
+

Table of contents

+ +
    +
  1. Runtime information +
      +
    1. Frida
    2. +
    3. Script
    4. +
    +
  2. +
  3. Process, Thread, Module and Memory +
      +
    1. Thread
    2. +
    3. Process
    4. +
    5. Module
    6. +
    7. ModuleMap
    8. +
    9. Memory
    10. +
    11. MemoryAccessMonitor
    12. +
    13. CModule
    14. +
    15. ApiResolver
    16. +
    17. DebugSymbol
    18. +
    19. Kernel
    20. +
    +
  4. +
  5. Data Types, Function and Callback +
      +
    1. Int64
    2. +
    3. UInt64
    4. +
    5. NativePointer
    6. +
    7. ArrayBuffer
    8. +
    9. NativeFunction
    10. +
    11. NativeCallback
    12. +
    13. SystemFunction
    14. +
    +
  6. +
  7. Network +
      +
    1. Socket
    2. +
    3. SocketListener
    4. +
    5. SocketConnection
    6. +
    +
  8. +
  9. File and Stream +
      +
    1. File
    2. +
    3. IOStream
    4. +
    5. InputStream
    6. +
    7. OutputStream
    8. +
    9. UnixInputStream
    10. +
    11. UnixOutputStream
    12. +
    13. Win32InputStream
    14. +
    15. Win32OutputStream
    16. +
    +
  10. +
  11. Database +
      +
    1. SqliteDatabase
    2. +
    3. SqliteStatement
    4. +
    +
  12. +
  13. Instrumentation +
      +
    1. Interceptor
    2. +
    3. Stalker
    4. +
    5. ObjC
    6. +
    7. Java
    8. +
    +
  14. +
  15. CPU Instruction +
      +
    1. Instruction
    2. +
    3. X86Writer
    4. +
    5. X86Relocator
    6. +
    7. x86 enum types
    8. +
    9. ArmWriter
    10. +
    11. ArmRelocator
    12. +
    13. ThumbWriter
    14. +
    15. ThumbRelocator
    16. +
    17. ARM enum types
    18. +
    19. Arm64Writer
    20. +
    21. Arm64Relocator
    22. +
    23. AArch64 enum types
    24. +
    25. MipsWriter
    26. +
    27. MipsRelocator
    28. +
    29. MIPS enum types
    30. +
    +
  16. +
  17. Other +
      +
    1. Console
    2. +
    3. Hexdump
    4. +
    5. Shorthand
    6. +
    7. Communication between host and injected process
    8. +
    9. Timing events
    10. +
    11. Garbage collection
    12. +
    +
  18. +
+ +
+ +

Runtime information

+ +

Frida

+ +
    +
  • +

    Frida.version: property containing the current Frida version, as a string.

    +
  • +
  • +

    Frida.heapSize: dynamic property containing the current size of Frida’s + private heap, shared by all scripts and Frida’s own runtime. This is useful + for keeping an eye on how much memory your instrumentation is using out of + the total consumed by the hosting process.

    +
  • +
+ +

Script

+ +
    +
  • +

    Script.runtime: string property containing the runtime being used. + Either QJS or V8.

    +
  • +
  • +

    Script.pin(): temporarily prevents the current script from being unloaded. + This is reference-counted, so there must be one matching unpin() happening + at a later point. Typically used in the callback of bindWeak() when you + need to schedule cleanup on another thread.

    +
  • +
  • +

    Script.unpin(): reverses a previous pin() so the current script may be + unloaded.

    +
  • +
  • +

    Script.bindWeak(value, fn): monitors value and calls the fn callback + as soon as value has been garbage-collected, or the script is about to get + unloaded. Returns an ID that you can pass to Script.unbindWeak() + for explicit cleanup.

    + +

    This API is useful if you’re building a language-binding, where you need to + free native resources when a JS value is no longer needed.

    +
  • +
  • +

    Script.unbindWeak(id): stops monitoring the value passed to + Script.bindWeak(value, fn), and call the fn callback immediately.

    +
  • +
  • +

    Script.setGlobalAccessHandler(handler | null): installs or uninstalls a + handler that is used to resolve attempts to access non-existent global + variables. Useful for implementing a REPL where unknown identifiers may be + fetched lazily from a database.

    + +

    The handler is an object containing two properties:

    + +
      +
    • enumerate(): queries which additional globals exist. Must return an + array of strings.
    • +
    • get(property): retrieves the value for the given property.
    • +
    +
  • +
+ +
+ +

Process, Thread, Module and Memory

+ +

Thread

+ +
    +
  • +

    Thread.backtrace([context, backtracer]): generate a backtrace for the + current thread, returned as an array of NativePointer objects.

    + +

    If you call this from Interceptor’s onEnter or + onLeave callbacks you + should provide this.context for the optional context argument, as it + will give you a more accurate backtrace. Omitting context means the + backtrace will be generated from the current stack location, which may + not give you a very good backtrace due to the JavaScript VM’s stack frames. + The optional backtracer argument specifies the kind of backtracer to use, + and must be either Backtracer.FUZZY or Backtracer.ACCURATE, where the + latter is the default if not specified. The accurate kind of backtracers + rely on debugger-friendly binaries or presence of debug information to do a + good job, whereas the fuzzy backtracers perform forensics on the stack in + order to guess the return addresses, which means you will get false + positives, but it will work on any binary. The generated backtrace is + currently limited to 16 frames and is not adjustable without recompiling + Frida.

    +
  • +
+ +
const f = Module.getExportByName('libcommonCrypto.dylib',
+				'CCCryptorCreate');
+			Interceptor.attach(f, {
+			  onEnter(args) {
+				console.log('CCCryptorCreate called from:\n' +
+					Thread.backtrace(this.context, Backtracer.ACCURATE)
+					.map(DebugSymbol.fromAddress).join('\n') + '\n');
+			  }
+			});
+ +
    +
  • Thread.sleep(delay): suspend execution of the current thread for delay + seconds specified as a number. For example 0.05 to sleep for 50 ms.
  • +
+ +

Process

+ +
    +
  • +

    Process.id: property containing the PID as a number

    +
  • +
  • +

    Process.arch: property containing the string ia32, x64, arm + or arm64

    +
  • +
  • +

    Process.platform: property containing the string windows, + darwin, linux or qnx

    +
  • +
  • +

    Process.pageSize: property containing the size of a virtual memory page + (in bytes) as a number. This is used to make your scripts more portable.

    +
  • +
  • +

    Process.pointerSize: property containing the size of a pointer + (in bytes) as a number. This is used to make your scripts more portable.

    +
  • +
  • +

    Process.codeSigningPolicy: property containing the string optional or + required, where the latter means Frida will avoid modifying existing code + in memory and will not try to run unsigned code. Currently this property + will always be set to optional unless you are using Gadget + and have configured it to assume that code-signing is required. This + property allows you to determine whether the Interceptor API + is off limits, and whether it is safe to modify code or run unsigned code.

    +
  • +
  • +

    Process.isDebuggerAttached(): returns a boolean indicating whether a + debugger is currently attached

    +
  • +
  • +

    Process.getCurrentThreadId(): get this thread’s OS-specific id as a number

    +
  • +
  • +

    Process.enumerateThreads(): enumerates all threads, returning an array of + objects containing the following properties:

    + +
      +
    • id: OS-specific id
    • +
    • state: string specifying either running, stopped, waiting, + uninterruptible or halted
    • +
    • context: object with the keys pc and sp, which are + NativePointer objects specifying EIP/RIP/PC and + ESP/RSP/SP, respectively, for ia32/x64/arm. Other processor-specific keys + are also available, e.g. eax, rax, r0, x0, etc.
    • +
    +
  • +
  • +

    Process.findModuleByAddress(address), + Process.getModuleByAddress(address), + Process.findModuleByName(name), + Process.getModuleByName(name): + returns a Module whose address or name matches the one + specified. In the event that no such module could be found, the + find-prefixed functions return null whilst the get-prefixed functions + throw an exception.

    +
  • +
  • +

    Process.enumerateModules(): enumerates modules loaded right now, returning + an array of Module objects.

    +
  • +
  • +

    Process.findRangeByAddress(address), getRangeByAddress(address): + return an object with details about the range containing address. In the + event that no such range could be found, findRangeByAddress() returns + null whilst getRangeByAddress() throws an exception. See + Process.enumerateRanges() for details about which + fields are included.

    +
  • +
  • +

    Process.enumerateRanges(protection|specifier): enumerates memory ranges + satisfying protection given as a string of the form: rwx, where rw- + means “must be at least readable and writable”. Alternatively you may + provide a specifier object with a protection key whose value is as + aforementioned, and a coalesce key set to true if you’d like neighboring + ranges with the same protection to be coalesced (the default is false; + i.e. keeping the ranges separate). Returns an array of objects containing + the following properties:

    + +
      +
    • base: base address as a NativePointer
    • +
    • size: size in bytes
    • +
    • protection: protection string (see above)
    • +
    • +

      file: (when available) file mapping details as an object + containing:

      + +
        +
      • path: full filesystem path as a string
      • +
      • offset: offset in the mapped file on disk, in bytes
      • +
      • size: size in the mapped file on disk, in bytes
      • +
      +
    • +
    +
  • +
  • +

    Process.enumerateMallocRanges(): just like enumerateRanges(), + but for individual memory allocations known to the system heap.

    +
  • +
  • +

    Process.setExceptionHandler(callback): install a process-wide exception + handler callback that gets a chance to handle native exceptions before the + hosting process itself does. Called with a single argument, details, that + is an object containing:

    + +
      +
    • type: string specifying one of: +
        +
      • abort
      • +
      • access-violation
      • +
      • guard-page
      • +
      • illegal-instruction
      • +
      • stack-overflow
      • +
      • arithmetic
      • +
      • breakpoint
      • +
      • single-step
      • +
      • system
      • +
      +
    • +
    • address: address where the exception occurred, as a NativePointer
    • +
    • memory: if present, is an object containing: +
        +
      • operation: the kind of operation that triggered the exception, as + a string specifying either read, write, or execute
      • +
      • address: address that was accessed when the exception occurred, as + a NativePointer
      • +
      +
    • +
    • context: object with the keys pc and sp, which are + NativePointer objects specifying EIP/RIP/PC and + ESP/RSP/SP, respectively, for ia32/x64/arm. Other processor-specific keys + are also available, e.g. eax, rax, r0, x0, etc. + You may also update register values by assigning to these keys.
    • +
    • nativeContext: address of the OS and architecture-specific CPU context + struct, as a NativePointer. This is only exposed as a + last resort for edge-cases where context isn’t providing enough details. We + would however discourage using this and rather submit a pull-request to add + the missing bits needed for your use-case.
    • +
    + +

    It is up to your callback to decide what to do with the exception. It could + log the issue, notify your application through a send() + followed by a blocking recv() for acknowledgement of the sent data being received, + or it can modify registers and memory to recover from the exception. You should + return true if you did handle the exception, in which case Frida will + resume the thread immediately. If you do not return true, Frida will + forward the exception to the hosting process’ exception handler, if it has + one, or let the OS terminate the process.

    +
  • +
+ +

Module

+ +

Objects returned by e.g. Module.load() and Process.enumerateModules().

+ +
    +
  • +

    name: canonical module name as a string

    +
  • +
  • +

    base: base address as a NativePointer

    +
  • +
  • +

    size: size in bytes

    +
  • +
  • +

    path: full filesystem path as a string

    +
  • +
  • +

    enumerateImports(): enumerates imports of module, returning an array of + objects containing the following properties:

    + +
      +
    • type: string specifying either function or variable
    • +
    • name: import name as a string
    • +
    • module: module name as a string
    • +
    • address: absolute address as a NativePointer
    • +
    • slot: memory location where the import is stored, as a + NativePointer
    • +
    + +

    Only the name field is guaranteed to be present for all imports. The + platform-specific backend will do its best to resolve the other fields + even beyond what the native metadata provides, but there is no guarantee + that it will succeed.

    +
  • +
  • +

    enumerateExports(): enumerates exports of module, returning an array + of objects containing the following properties:

    + +
      +
    • type: string specifying either function or variable
    • +
    • name: export name as a string
    • +
    • address: absolute address as a NativePointer
    • +
    +
  • +
  • +

    enumerateSymbols(): enumerates symbols of module, returning an array of + objects containing the following properties:

    + +
      +
    • isGlobal: boolean specifying whether symbol is globally visible
    • +
    • type: string specifying one of: +
        +
      • unknown
      • +
      • section
      • +
      • undefined (Mach-O)
      • +
      • absolute (Mach-O)
      • +
      • prebound-undefined (Mach-O)
      • +
      • indirect (Mach-O)
      • +
      • object (ELF)
      • +
      • function (ELF)
      • +
      • file (ELF)
      • +
      • common (ELF)
      • +
      • tls (ELF)
      • +
      +
    • +
    • section: if present, is an object containing: +
        +
      • id: string containing section index, segment name (if + applicable) and section name – same format as + r2’s section IDs
      • +
      • protection: protection like in Process.enumerateRanges()
      • +
      +
    • +
    • name: symbol name as a string
    • +
    • address: absolute address as a NativePointer
    • +
    • size: if present, a number specifying the symbol’s size in bytes
    • +
    +
  • +
+ +
+
enumerateSymbols() is only available on i/macOS and Linux-based OSes
+

+ We would love to support this on the other platforms too, so if you find + this useful and would like to help out, please get in touch. You may also + find the DebugSymbol API adequate, depending on your use-case. +

+
+ +
    +
  • +

    enumerateRanges(protection): just like Process.enumerateRanges, + except it’s scoped to the module.

    +
  • +
  • +

    findExportByName(exportName), + getExportByName(exportName): returns the absolute address of the export + named exportName. In the event that no such export could be found, the + find-prefixed function returns null whilst the get-prefixed function + throws an exception.

    +
  • +
  • +

    Module.load(path): loads the specified module from the filesystem path + and returns a Module object. Throws an exception if the specified + module cannot be loaded.

    +
  • +
  • +

    Module.ensureInitialized(name): ensures that initializers of the specified + module have been run. This is important during early instrumentation, i.e. + code run early in the process lifetime, to be able to safely interact with + APIs. One such use-case is interacting with ObjC classes provided + by a given module.

    +
  • +
  • +

    Module.findBaseAddress(name), + Module.getBaseAddress(name): returns the base address of the name + module. In the event that no such module could be found, the find-prefixed + function returns null whilst the get-prefixed function throws an + exception.

    +
  • +
  • +

    Module.findExportByName(moduleName|null, exportName), + Module.getExportByName(moduleName|null, exportName): returns the absolute + address of the export named exportName in moduleName. If the module + isn’t known you may pass null instead of its name, but this can be a + costly search and should be avoided. In the event that no such module or + export could be found, the find-prefixed function returns null whilst + the get-prefixed function throws an exception.

    +
  • +
+ +

ModuleMap

+ +
    +
  • +

    new ModuleMap([filter]): create a new module map optimized for determining + which module a given memory address belongs to, if any. Takes a snapshot of + the currently loaded modules when created, which may be refreshed by calling + update(). The filter argument is optional and allows + you to pass a function used for filtering the list of modules. This is useful if + you e.g. only care about modules owned by the application itself, and allows you + to quickly check if an address belongs to one of its modules. The filter + function is passed a Module object and must return true for + each module that should be kept in the map. It is called for each loaded + module every time the map is updated.

    +
  • +
  • +

    has(address): check if address belongs to any of the contained modules, + and returns the result as a boolean

    +
  • +
  • +

    find(address), get(address): returns a Module with details + about the module that address belongs to. In the event that no such module + could be found, find() returns null whilst get() throws an exception.

    +
  • +
  • +

    findName(address), + getName(address), + findPath(address), + getPath(address): + just like find() and get(), but only + returns the name or path field, which means less overhead when you don’t need + the other details.

    +
  • +
  • +

    update(): update the map. You should call this after a module has been + loaded or unloaded to avoid operating on stale data.

    +
  • +
  • +

    values(): returns an array with the Module objects currently in + the map. The returned array is a deep copy and will not mutate after a call + to update().

    +
  • +
+ +

Memory

+ +
    +
  • +

    Memory.scan(address, size, pattern, callbacks): scan memory for + occurrences of pattern in the memory range given by address and size.

    + +
      +
    • +

      pattern must be of the form “13 37 ?? ff” to match 0x13 followed by + 0x37 followed by any byte followed by 0xff. + For more advanced matching it is also possible to specify an + r2-style mask. The mask is bitwise AND-ed against both the needle + and the haystack. To specify the mask append a : character after the + needle, followed by the mask using the same syntax. + For example: “13 37 13 37 : 1f ff ff f1”. + For convenience it is also possible to specify nibble-level wildcards, + like “?3 37 13 ?7”, which gets translated into masks behind the scenes.

      +
    • +
    • +

      callbacks is an object with:

      + +
        +
      • +

        onMatch(address, size): called with address containing the + address of the occurence as a NativePointer and + size specifying the size as a number.

        + +

        This function may return the string stop to cancel the memory + scanning early.

        +
      • +
      • +

        onError(reason): called with reason when there was a memory + access error while scanning

        +
      • +
      • +

        onComplete(): called when the memory range has been fully scanned

        +
      • +
      +
    • +
    +
  • +
  • +

    Memory.scanSync(address, size, pattern): synchronous version of scan() + that returns an array of objects containing the following properties:

    + +
      +
    • address: absolute address as a NativePointer.
    • +
    • size: size in bytes
    • +
    + +

    For example:

    +
  • +
+ +
// Find the module for the program itself, always at index 0:
+			const m = Process.enumerateModules()[0];
+			
+			// Or load a module by name:
+			//const m = Module.load('win32u.dll');
+			
+			// Print its properties:
+			console.log(JSON.stringify(m));
+			
+			// Dump it from its base address:
+			console.log(hexdump(m.base));
+			
+			// The pattern that you are interested in:
+			const pattern = '00 00 00 00 ?? 13 37 ?? 42';
+			
+			Memory.scan(m.base, m.size, pattern, {
+			  onMatch(address, size) {
+				console.log('Memory.scan() found match at', address,
+					'with size', size);
+			
+				// Optionally stop scanning early:
+				return 'stop';
+			  },
+			  onComplete() {
+				console.log('Memory.scan() complete');
+			  }
+			});
+			
+			const results = Memory.scanSync(m.base, m.size, pattern);
+			console.log('Memory.scanSync() result:\n' +
+				JSON.stringify(results));
+ +
    +
  • +

    Memory.alloc(size[, options]): allocate size bytes of memory on the + heap, or, if size is a multiple of + Process.pageSize, one or more raw memory pages + managed by the OS. When using page granularity you may also specify an + options object if you need the memory allocated close to a given address, + by specifying { near: address, maxDistance: distanceInBytes }. + The returned value is a NativePointer and the underlying + memory will be released when all JavaScript handles to it are gone. This + means you need to keep a reference to it while the pointer is being used by + code outside the JavaScript runtime.

    +
  • +
  • +

    Memory.copy(dst, src, n): just like memcpy(). Returns nothing.

    + +
      +
    • dst: a NativePointer specifying the destination base address.
    • +
    • src: a NativePointer specifying the source base address.
    • +
    • n: size in bytes to be copied.
    • +
    +
  • +
  • +

    Memory.dup(address, size): short-hand for Memory.alloc() + followed by Memory.copy(). Returns a NativePointer + containing the base address of the freshly allocated memory. See Memory.copy() + for details on the memory allocation’s lifetime.

    +
  • +
  • +

    Memory.protect(address, size, protection): update protection on a region + of memory, where protection is a string of the same format as + Process.enumerateRanges().

    + +

    Returns a boolean indicating whether the operation completed successfully.

    + +

    For example:

    +
  • +
+ +
Memory.protect(ptr('0x1234'), 4096, 'rw-');
+ +
    +
  • +

    Memory.patchCode(address, size, apply): safely modify size bytes at + address, specified as a NativePointer. The supplied + JavaScript function apply gets called with a writable pointer where you must + write the desired modifications before returning. Do not make any assumptions + about this being the same location as address, as some systems require + modifications to be written to a temporary location before being mapped into + memory on top of the original memory page (e.g. on iOS, where directly modifying + in-memory code may result in the process losing its CS_VALID status).

    + +

    For example:

    +
  • +
+ +
const getLivesLeft = Module.getExportByName('game-engine.so', 'get_lives_left');
+			const maxPatchSize = 64; // Do not write out of bounds, may be a temporary buffer!
+			Memory.patchCode(getLivesLeft, maxPatchSize, code => {
+			  const cw = new X86Writer(code, { pc: getLivesLeft });
+			  cw.putMovRegU32('eax', 9000);
+			  cw.putRet();
+			  cw.flush();
+			});
+ +
    +
  • Memory.allocUtf8String(str), + Memory.allocUtf16String(str), + Memory.allocAnsiString(str): + allocate, encode and write out str as a UTF-8/UTF-16/ANSI string on the + heap. The returned object is a NativePointer. See + Memory.alloc() for details about its lifetime.
  • +
+ +

MemoryAccessMonitor

+ +
    +
  • +

    MemoryAccessMonitor.enable(ranges, callbacks): monitor one or more memory + ranges for access, and notify on the first access of each contained memory + page. ranges is either a single range object or an array of such objects, + each of which contains:

    + +
      +
    • base: base address as a NativePointer
    • +
    • size: size in bytes
    • +
    + +

    callbacks is an object specifying:

    + +
      +
    • onAccess(details): called synchronously with details object + containing: +
        +
      • operation: the kind of operation that triggered the access, as a + string specifying either read, write, or execute
      • +
      • from: address of instruction performing the access as a + NativePointer
      • +
      • address: address being accessed as a NativePointer
      • +
      • rangeIndex: index of the accessed range in the ranges provided to + MemoryAccessMonitor.enable()
      • +
      • pageIndex: index of the accessed memory page inside the specified + range
      • +
      • pagesCompleted: overall number of pages which have been accessed + so far (and are no longer being monitored)
      • +
      • pagesTotal: overall number of pages that were initially monitored
      • +
      +
    • +
    +
  • +
  • +

    MemoryAccessMonitor.disable(): stop monitoring the remaining memory ranges + passed to MemoryAccessMonitor.enable().

    +
  • +
+ +

CModule

+ +
    +
  • +

    new CModule(code[, symbols, options]): creates a new C module from the + provided code, either a string containing the C source code to compile, or + an ArrayBuffer containing a precompiled shared library. The C module gets + mapped into memory and becomes fully accessible to JavaScript.

    + +

    Useful for implementing hot callbacks, e.g. for Interceptor + and Stalker, but also useful when needing to start new threads + in order to call functions in a tight loop, e.g. for fuzzing purposes.

    + +

    Global functions are automatically exported as NativePointer + properties named exactly like in the C source code. This means you can pass them + to Interceptor and Stalker, or call them + using NativePointer.

    + +

    In addition to accessing a curated subset of Gum, GLib, and standard C APIs, + the code being mapped in can also communicate with JavaScript through the + symbols exposed to it. This is the optional second argument, an object + specifying additional symbol names and their + NativePointer values, each of which will be plugged in + at creation. This may for example be one or more memory blocks allocated + using Memory.alloc(), and/or + NativeCallback values for receiving callbacks from + the C module.

    + +

    To perform initialization and cleanup, you may define functions with the + following names and signatures:

    + +
      +
    • void init (void)
    • +
    • void finalize (void)
    • +
    + +

    Note that all data is read-only, so writable globals should be declared + extern, allocated using e.g. Memory.alloc(), and passed + in as symbols through the constructor’s second argument.

    + +

    The optional third argument, options, is an object that may be used to + specify which toolchain to use, e.g.: { toolchain: 'external' }. Supported + values are:

    + +
      +
    • internal: use TinyCC, which is statically linked into the runtime. + Never touches the filesystem and works even in sandboxed processes. The + generated code is however not optimized, as TinyCC optimizes for small + compiler footprint and short compilation times.
    • +
    • external: use toolchain provided by the target system, assuming it is + accessible to the process we’re executing inside.
    • +
    • any: same as internal if Process.arch is + supported by TinyCC, and external otherwise. This is the default + behavior if left unspecified.
    • +
    +
  • +
  • +

    dispose(): eagerly unmaps the module from memory. Useful for short-lived + modules when waiting for a future garbage collection isn’t desirable.

    +
  • +
  • +

    builtins: an object specifying builtins present when constructing a + CModule from C source code. This is typically used by a scaffolding tool + such as frida-create in order to set up a build environment that matches + what CModule uses. The exact contents depends on the + Process.arch and Frida version, but may look something + like the following:

    + +
    {
    +			  defines: {
    +				'GLIB_SIZEOF_VOID_P': '8',
    +				'G_GINT16_MODIFIER': '"h"',
    +				'G_GINT32_MODIFIER': '""',
    +				'G_GINT64_MODIFIER': '"ll"',
    +				'G_GSIZE_MODIFIER': '"l"',
    +				'G_GSSIZE_MODIFIER': '"l"',
    +				'HAVE_I386': true
    +			  },
    +			  headers: {
    +				'gum/arch-x86/gumx86writer.h': '…',
    +				'gum/gumdefs.h': '…',
    +				'gum/guminterceptor.h': '…',
    +				'gum/gummemory.h': '…',
    +				'gum/gummetalarray.h': '…',
    +				'gum/gummetalhash.h': '…',
    +				'gum/gummodulemap.h': '…',
    +				'gum/gumprocess.h': '…',
    +				'gum/gumspinlock.h': '…',
    +				'gum/gumstalker.h': '…',
    +				'glib.h': '…',
    +				'json-glib/json-glib.h': '…',
    +				'capstone.h': '…'
    +			  }
    +			}
    +			
    +
  • +
+ +

Examples

+ +
const cm = new CModule(`
+			#include <stdio.h>
+			
+			void hello(void) {
+			  printf("Hello World from CModule\\n");
+			}
+			`);
+			
+			console.log(JSON.stringify(cm));
+			
+			const hello = new NativeFunction(cm.hello, 'void', []);
+			hello();
+ +

Which you might load using Frida’s REPL:

+ +
$ frida -p 0 -l example.js
+ +

(The REPL monitors the file on disk and reloads the script on change.)

+ +

You can then type hello() in the REPL to call the C function.

+ +

For prototyping we recommend using the Frida REPL’s built-in CModule support:

+ +
$ frida -p 0 -C example.c
+ +

You may also add -l example.js to load some JavaScript next to it. + The JavaScript code may use the global variable named cm to access + the CModule object, but only after rpc.exports.init() has been + called, so perform any initialization depending on the CModule there. You may + also inject symbols by assigning to the global object named cs, but this + must be done before rpc.exports.init() gets called.

+ +

Here’s an example:

+ +

CModule REPL example

+ +

More details on CModule can be found in the Frida 12.7 release notes.

+ +

ApiResolver

+ +
    +
  • +

    new ApiResolver(type): create a new resolver of the given type, allowing + you to quickly find functions by name, with globs permitted. Precisely which + resolvers are available depends on the current platform and runtimes loaded + in the current process. As of the time of writing, the available resolvers + are:

    + +
      +
    • module: Resolves exported and imported functions of shared libraries + currently loaded. Always available.
    • +
    • objc: Resolves Objective-C methods of classes currently loaded. + Available on macOS and iOS in processes that have the Objective-C + runtime loaded. Use ObjC.available to check at + runtime, or wrap your new ApiResolver('objc') call in a try-catch.
    • +
    + +

    The resolver will load the minimum amount of data required on creation, and + lazy-load the rest depending on the queries it receives. It is thus + recommended to use the same instance for a batch of queries, but recreate it + for future batches to avoid looking at stale data.

    +
  • +
  • +

    enumerateMatches(query): performs the resolver-specific query string, + optionally suffixed with /i to perform case-insensitive matching, + returning an array of objects containing the following properties:

    + +
      +
    • name: name of the API that was found
    • +
    • address: address as a NativePointer
    • +
    +
  • +
+ +
const resolver = new ApiResolver('module');
+			const matches = resolver.enumerateMatches('exports:*!open*');
+			const first = matches[0];
+			/*
+			 * Where `first` is an object similar to:
+			 *
+			 * {
+			 *   name: '/usr/lib/libSystem.B.dylib!opendir$INODE64',
+			 *   address: ptr('0x7fff870135c9')
+			 * }
+			 */
+ +
const resolver = new ApiResolver('objc');
+			const matches = resolver.enumerateMatches('-[NSURL* *HTTP*]');
+			const first = matches[0];
+			/*
+			 * Where `first` contains an object like this one:
+			 *
+			 * {
+			 *   name: '-[NSURLRequest valueForHTTPHeaderField:]',
+			 *   address: ptr('0x7fff94183e22')
+			 * }
+			 */
+ +

DebugSymbol

+ +
    +
  • +

    DebugSymbol.fromAddress(address), DebugSymbol.fromName(name): + look up debug information for address/name and return it as an object + containing:

    + +
      +
    • address: Address that this symbol is for, as a NativePointer.
    • +
    • name: Name of the symbol, as a string, or null if unknown.
    • +
    • moduleName: Module name owning this symbol, as a string, or null if + unknown.
    • +
    • fileName: File name owning this symbol, as a string, or null if + unknown.
    • +
    • lineNumber: Line number in fileName, as a number, or null if + unknown.
    • +
    + +

    You may also call toString() on it, which is very useful when combined + with Thread.backtrace():

    +
  • +
+ +
const f = Module.getExportByName('libcommonCrypto.dylib',
+				'CCCryptorCreate');
+			Interceptor.attach(f, {
+			  onEnter(args) {
+				console.log('CCCryptorCreate called from:\n' +
+					Thread.backtrace(this.context, Backtracer.ACCURATE)
+					.map(DebugSymbol.fromAddress).join('\n') + '\n');
+			  }
+			});
+ +
    +
  • +

    DebugSymbol.getFunctionByName(name): resolves a function name and + returns its address as a NativePointer. Returns the first if + more than one function is found. Throws an exception if the name cannot be + resolved.

    +
  • +
  • +

    DebugSymbol.findFunctionsNamed(name): resolves a function name and returns + its addresses as an array of NativePointer objects.

    +
  • +
  • +

    DebugSymbol.findFunctionsMatching(glob): resolves function names matching + glob and returns their addresses as an array of NativePointer + objects.

    +
  • +
  • +

    DebugSymbol.load(path): loads debug symbols for a specific module.

    +
  • +
+ +

Kernel

+ +
    +
  • +

    Kernel.available: a boolean specifying whether the Kernel API is + available. Do not invoke any other Kernel properties or methods unless + this is the case.

    +
  • +
  • +

    Kernel.base: base address of the kernel, as a UInt64.

    +
  • +
  • +

    Kernel.pageSize: size of a kernel page in bytes, as a number.

    +
  • +
  • +

    Kernel.enumerateModules(): enumerates kernel modules loaded right now, + returning an array of objects containing the following properties:

    + +
      +
    • name: canonical module name as a string
    • +
    • base: base address as a NativePointer
    • +
    • size: size in bytes
    • +
    +
  • +
  • +

    Kernel.enumerateRanges(protection|specifier): enumerate kernel memory + ranges satisfying protection given as a string of the form: rwx, where + rw- means “must be at least readable and writable”. Alternatively you may + provide a specifier object with a protection key whose value is as + aforementioned, and a coalesce key set to true if you’d like neighboring + ranges with the same protection to be coalesced (the default is false; + i.e. keeping the ranges separate). Returns an array of objects containing + the following properties:

    + +
      +
    • base: base address as a NativePointer
    • +
    • size: size in bytes
    • +
    • protection: protection string (see above)
    • +
    +
  • +
  • +

    Kernel.enumerateModuleRanges(name, protection): just like + Kernel.enumerateRanges, except it’s scoped to the + specified module name – which may be null for the module of the kernel + itself. Each range also has a name field containing a unique identifier as a + string.

    +
  • +
  • +

    Kernel.alloc(size): allocate size bytes of kernel memory, rounded up to + a multiple of the kernel’s page size. The returned value is a UInt64 + specifying the base address of the allocation.

    +
  • +
  • +

    Kernel.protect(address, size, protection): update protection on a region + of kernel memory, where protection is a string of the same format as + Kernel.enumerateRanges().

    + +

    For example:

    +
  • +
+ +
Kernel.protect(UInt64('0x1234'), 4096, 'rw-');
+ +
    +
  • +

    Kernel.readByteArray(address, length): just like + NativePointer#readByteArray, but reading from + kernel memory.

    +
  • +
  • +

    Kernel.writeByteArray(address, bytes): just like + NativePointer#writeByteArray, but writing to + kernel memory.

    +
  • +
  • +

    Kernel.scan(address, size, pattern, callbacks): just like Memory.scan, + but scanning kernel memory.

    +
  • +
  • +

    Kernel.scanSync(address, size, pattern): synchronous version of scan() + that returns the matches in an array.

    +
  • +
+ +
+ +

Data Types, Function and Callback

+ +

Int64

+ +
    +
  • +

    new Int64(v): create a new Int64 from v, which is either a number or a + string containing a value in decimal, or hexadecimal if prefixed with “0x”. + You may use the int64(v) short-hand for brevity.

    +
  • +
  • +

    add(rhs), sub(rhs), + and(rhs), or(rhs), + xor(rhs): + make a new Int64 with this Int64 plus/minus/and/or/xor rhs, which may + either be a number or another Int64

    +
  • +
  • +

    shr(n), shl(n): + make a new Int64 with this Int64 shifted right/left by n bits

    +
  • +
  • +

    compare(rhs): returns an integer comparison result just like + String#localeCompare()

    +
  • +
  • +

    toNumber(): cast this Int64 to a number

    +
  • +
  • +

    toString([radix = 10]): convert to a string of optional radix (defaults to + 10)

    +
  • +
+ +

UInt64

+ +
    +
  • +

    new UInt64(v): create a new UInt64 from v, which is either a number or a + string containing a value in decimal, or hexadecimal if prefixed with “0x”. + You may use the uint64(v) short-hand for brevity.

    +
  • +
  • +

    add(rhs), sub(rhs), + and(rhs), or(rhs), + xor(rhs): + make a new UInt64 with this UInt64 plus/minus/and/or/xor rhs, which may + either be a number or another UInt64

    +
  • +
  • +

    shr(n), shl(n): + make a new UInt64 with this UInt64 shifted right/left by n bits

    +
  • +
  • +

    compare(rhs): returns an integer comparison result just like + String#localeCompare()

    +
  • +
  • +

    toNumber(): cast this UInt64 to a number

    +
  • +
  • +

    toString([radix = 10]): convert to a string of optional radix (defaults to + 10)

    +
  • +
+ +

NativePointer

+ +
    +
  • +

    new NativePointer(s): creates a new NativePointer from the + string s containing a memory address in either decimal, or hexadecimal if + prefixed with ‘0x’. You may use the ptr(s) short-hand for brevity.

    +
  • +
  • +

    isNull(): returns a boolean allowing you to conveniently check if a + pointer is NULL

    +
  • +
  • +

    add(rhs), sub(rhs), + and(rhs), or(rhs), + xor(rhs): + makes a new NativePointer with this NativePointer + plus/minus/and/or/xor rhs, which may either be a number or another NativePointer

    +
  • +
  • +

    shr(n), shl(n): + makes a new NativePointer with this NativePointer + shifted right/left by n bits

    +
  • +
  • +

    not(): makes a new NativePointer with this NativePointer’s + bits inverted

    +
  • +
  • +

    sign([key, data]): makes a new NativePointer by taking this + NativePointer’s bits and adding pointer authentication bits, + creating a signed pointer. This is a no-op if the current process does not support + pointer authentication, returning this NativePointer instead + of a new value.

    + +

    Optionally, key may be specified as a string. Supported values are:

    +
      +
    • ia: The IA key, for signing code pointers. This is the default.
    • +
    • ib: The IB key, for signing code pointers.
    • +
    • da: The DA key, for signing data pointers.
    • +
    • db: The DB key, for signing data pointers.
    • +
    + +

    The data argument may also be specified as a NativePointer/number-like + value to provide extra data used for the signing, and defaults to 0.

    +
  • +
  • +

    strip([key]): makes a new NativePointer by taking this NativePointer’s + bits and removing its pointer authentication bits, creating a raw pointer. + This is a no-op if the current process does not support pointer + authentication, returning this NativePointer instead of a + new value.

    + +

    Optionally, key may be passed to specify which key was used to sign the + pointer being stripped. Defaults to ia. (See sign() + for supported values.)

    +
  • +
  • +

    blend(smallInteger): makes a new NativePointer by taking + this NativePointer’s bits and blending them with a constant, + which may in turn be passed to sign() as data.

    +
  • +
  • +

    equals(rhs): returns a boolean indicating whether rhs is equal to + this one; i.e. it has the same pointer value

    +
  • +
  • +

    compare(rhs): returns an integer comparison result just like + String#localeCompare()

    +
  • +
  • +

    toInt32(): casts this NativePointer to a signed 32-bit integer

    +
  • +
  • +

    toString([radix = 16]): converts to a string of optional radix (defaults + to 16)

    +
  • +
  • +

    toMatchPattern(): returns a string containing a Memory.scan()-compatible + match pattern for this pointer’s raw value

    +
  • +
  • +

    readPointer(): reads a NativePointer from this memory location.

    + +

    A JavaScript exception will be thrown if the address isn’t readable.

    +
  • +
  • +

    writePointer(ptr): writes ptr to this memory location.

    + +

    A JavaScript exception will be thrown if the address isn’t writable.

    +
  • +
  • +

    readS8(), readU8(), + readS16(), readU16(), + readS32(), readU32(), + readShort(), readUShort(), + readInt(), readUInt(), + readFloat(), readDouble(): + reads a signed or unsigned 8/16/32/etc. or float/double value from + this memory location and returns it as a number.

    + +

    A JavaScript exception will be thrown if the address isn’t readable.

    +
  • +
  • +

    writeS8(value), writeU8(value), + writeS16(value), writeU16(value), + writeS32(value), writeU32(value), + writeShort(value), writeUShort(value), + writeInt(value), writeUInt(value), + writeFloat(value), writeDouble(value): + writes a signed or unsigned 8/16/32/etc. or float/double value to this + memory location.

    + +

    A JavaScript exception will be thrown if the address isn’t writable.

    +
  • +
  • +

    readS64(), readU64(), + readLong(), readULong(): + reads a signed or unsigned 64-bit, or long-sized, value from this memory + location and returns it as an Int64/UInt64 value.

    + +

    A JavaScript exception will be thrown if the address isn’t readable.

    +
  • +
  • +

    writeS64(value), writeU64(value), + writeLong(value), writeULong(value): + writes the Int64/UInt64 value to this memory + location.

    + +

    A JavaScript exception will be thrown if the address isn’t writable.

    +
  • +
  • +

    readByteArray(length): reads length bytes from this memory location, and + returns it as an ArrayBuffer. This buffer may be efficiently + transferred to your Frida-based application by passing it as the second argument + to send().

    + +

    A JavaScript exception will be thrown if any of the length bytes read from + the address isn’t readable.

    +
  • +
  • +

    writeByteArray(bytes): writes bytes to this memory location, where + bytes is either an ArrayBuffer, typically returned from + readByteArray(), or an array of integers between 0 and 255. For example: + [ 0x13, 0x37, 0x42 ].

    + +

    A JavaScript exception will be thrown if any of the bytes written to + the address isn’t writable.

    +
  • +
  • +

    readCString([size = -1]), + readUtf8String([size = -1]), + readUtf16String([length = -1]), + readAnsiString([size = -1]): + reads the bytes at this memory location as an ASCII, UTF-8, UTF-16, or ANSI + string. Supply the optional size argument if you know the size of the + string in bytes, or omit it or specify -1 if the string is NUL-terminated. + Likewise you may supply the optional length argument if you know the + length of the string in characters.

    + +

    A JavaScript exception will be thrown if any of the size / length bytes + read from the address isn’t readable.

    + +

    Note that readAnsiString() is only available (and relevant) on Windows.

    +
  • +
  • +

    writeUtf8String(str), + writeUtf16String(str), + writeAnsiString(str): + encodes and writes the JavaScript string to this memory location (with + NUL-terminator).

    + +

    A JavaScript exception will be thrown if any of the bytes written to + the address isn’t writable.

    + +

    Note that writeAnsiString() is only available (and relevant) on Windows.

    +
  • +
+ +

ArrayBuffer

+ +
    +
  • +

    wrap(address, size): creates an ArrayBuffer backed by an existing memory + region, where address is a NativePointer specifying the + base address of the region, and size is a number specifying its size. Unlike + the NativePointer read/write APIs, no validation is performed + on access, meaning a bad pointer will crash the process.

    +
  • +
  • +

    unwrap(): returns a NativePointer specifying the base + address of the ArrayBuffer’s backing store. It is the caller’s responsibility to + keep the buffer alive while the backing store is still being used.

    +
  • +
+ +

NativeFunction

+ +
    +
  • +

    new NativeFunction(address, returnType, argTypes[, abi]): create a new + NativeFunction to call the function at address (specified with a + NativePointer), where returnType specifies the return type, + and the argTypes array specifies the argument types. You may optionally also + specify abi if not system default. For variadic functions, add a '...' + entry to argTypes between the fixed arguments and the variadic ones.

    + +
      +
    • +

      Structs & Classes by Value

      + +

      As for structs or classes passed by value, instead of a string provide an + array containing the struct’s field types following each other. You may nest + these as deep as desired for representing structs inside structs. Note that + the returned object is also a NativePointer, and can thus + be passed to Interceptor#attach.

      + +

      This must match the struct/class exactly, so if you have a struct with three + ints, you must pass ['int', 'int', 'int'].

      + +

      For a class that has virtual methods, the first field will be a pointer + to the vtable.

      + +

      For C++ scenarios involving a return value that is larger than + Process.pointerSize, a typical ABI may expect + that a NativePointer to preallocated space must be + passed in as the first parameter. (This scenario is common in WebKit, + for example.)

      +
    • +
    • +

      Supported Types

      +
        +
      • void
      • +
      • pointer
      • +
      • int
      • +
      • uint
      • +
      • long
      • +
      • ulong
      • +
      • char
      • +
      • uchar
      • +
      • size_t
      • +
      • ssize_t
      • +
      • float
      • +
      • double
      • +
      • int8
      • +
      • uint8
      • +
      • int16
      • +
      • uint16
      • +
      • int32
      • +
      • uint32
      • +
      • int64
      • +
      • uint64
      • +
      • bool
      • +
      +
    • +
    • +

      Supported ABIs

      +
        +
      • default
      • +
      • Windows 32-bit: +
          +
        • sysv
        • +
        • stdcall
        • +
        • thiscall
        • +
        • fastcall
        • +
        • mscdecl
        • +
        +
      • +
      • Windows 64-bit: +
          +
        • win64
        • +
        +
      • +
      • UNIX x86: +
          +
        • sysv
        • +
        • unix64
        • +
        +
      • +
      • UNIX ARM: +
          +
        • sysv
        • +
        • vfp
        • +
        +
      • +
      +
    • +
    +
  • +
  • +

    new NativeFunction(address, returnType, argTypes[, options]): just like + the previous constructor, but where the fourth argument, options, is an + object that may contain one or more of the following keys:

    + +
      +
    • abi: same enum as above.
    • +
    • scheduling: scheduling behavior as a string. Supported values are: +
        +
      • cooperative: Allow other threads to execute JavaScript code while + calling the native function, i.e. let go of the lock + before the call, and re-acquire it afterwards. + This is the default behavior.
      • +
      • exclusive: Do not allow other threads to execute JavaScript code + while calling the native function, i.e. keep holding the + JavaScript lock. + This is faster but may result in deadlocks.
      • +
      +
    • +
    • exceptions: exception behavior as a string. Supported values are: +
        +
      • steal: If the called function generates a native exception, e.g. + by dereferencing an invalid pointer, Frida will unwind the + stack and steal the exception, turning it into a JavaScript + exception that can be handled. This may leave the application + in an undefined state, but is useful to avoid crashing the + process while experimenting. + This is the default behavior.
      • +
      • propagate: Let the application deal with any native exceptions that + occur during the function call. (Or, the handler + installed through Process.setExceptionHandler().)
      • +
      +
    • +
    • traps: code traps to be enabled, as a string. Supported values are: +
        +
      • default: Interceptor.attach() callbacks will be + called if any hooks are triggered by a function call.
      • +
      • all: In addition to Interceptor callbacks, Stalker + may also be temporarily reactivated for the duration of each function + call. This is useful for e.g. measuring code coverage while guiding a + fuzzer, implementing “step into” in a debugger, etc. + Note that this is also possible when using the Java + and ObjC APIs, as method wrappers also provide a + clone(options) API to create a new method wrapper with custom + NativeFunction options.
      • +
      +
    • +
    +
  • +
+ +

NativeCallback

+ +
    +
  • new NativeCallback(func, returnType, argTypes[, abi]): create a new + NativeCallback implemented by the JavaScript function func, where + returnType specifies the return type, and the argTypes array specifies + the argument types. You may also specify the abi if not system default. + See NativeFunction for details about supported types and + abis. Note that the returned object is also a NativePointer, + and can thus be passed to Interceptor#replace. + When using the resulting callback with Interceptor.replace(), + func will be invoked with this bound to an object with some useful properties, + just like the one in Interceptor.attach().
  • +
+ +

SystemFunction

+ +
    +
  • +

    new SystemFunction(address, returnType, argTypes[, abi]): just like + NativeFunction, but also provides a snapshot of the thread’s + last error status. The return value is an object wrapping the actual return value + as value, with one additional platform-specific field named either errno + (UNIX) or lastError (Windows).

    +
  • +
  • +

    new SystemFunction(address, returnType, argTypes[, options]): same as + above but accepting an options object like NativeFunction’s + corresponding constructor.

    +
  • +
+ +
+ +

Network

+ +

Socket

+ +
    +
  • +

    Socket.listen([options]): open a TCP or UNIX listening socket. Returns a + Promise that receives a SocketListener.

    + +

    Defaults to listening on both IPv4 and IPv6, if supported, and binding on + all interfaces on a randomly selected TCP port.

    + +

    The optional options argument is an object that may contain some of the + following keys:

    + +
      +
    • family: address family as a string. Supported values are: +
        +
      • unix
      • +
      • ipv4
      • +
      • ipv6 + Defaults to listening on both ipv4 and ipv6 if supported.
      • +
      +
    • +
    • host: (IP family) IP address as a string. Defaults to all interfaces.
    • +
    • port: (IP family) IP port as a number. Defaults to any available.
    • +
    • type: (UNIX family) UNIX socket type as a string. Supported types are: +
        +
      • anonymous
      • +
      • path
      • +
      • abstract
      • +
      • abstract-padded + Defaults to path.
      • +
      +
    • +
    • path: (UNIX family) UNIX socket path as a string.
    • +
    • backlog: Listen backlog as a number. Defaults to 10.
    • +
    +
  • +
  • +

    Socket.connect(options): connect to a TCP or UNIX server. Returns a + Promise that receives a SocketConnection.

    + +

    The options argument is an object that should contain some of the + following keys:

    + +
      +
    • family: address family as a string. Supported values are: +
        +
      • unix
      • +
      • ipv4
      • +
      • ipv6 + Defaults to an IP family depending on the host specified.
      • +
      +
    • +
    • host: (IP family) IP address as a string. Defaults to localhost.
    • +
    • port: (IP family) IP port as a number.
    • +
    • type: (UNIX family) UNIX socket type as a string. Supported types are: +
        +
      • anonymous
      • +
      • path
      • +
      • abstract
      • +
      • abstract-padded + Defaults to path.
      • +
      +
    • +
    • path: (UNIX family) UNIX socket path as a string.
    • +
    +
  • +
  • +

    Socket.type(handle): inspect the OS socket handle and return its type + as a string which is either tcp, udp, tcp6, udp6, unix:stream, + unix:dgram, or null if invalid or unknown.

    +
  • +
  • +

    Socket.localAddress(handle), + Socket.peerAddress(handle): + inspect the OS socket handle and return its local or peer address, or + null if invalid or unknown.

    + +

    The object returned has the fields:

    + +
      +
    • ip: (IP sockets) IP address as a string.
    • +
    • port: (IP sockets) IP port as a number.
    • +
    • path: (UNIX sockets) UNIX path as a string.
    • +
    +
  • +
+ +

SocketListener

+ +

All methods are fully asynchronous and return Promise objects.

+ +
    +
  • +

    path: (UNIX family) path being listened on.

    +
  • +
  • +

    port: (IP family) IP port being listened on.

    +
  • +
  • +

    close(): close the listener, releasing resources related to it. Once the + listener is closed, all other operations will fail. Closing a listener + multiple times is allowed and will not result in an error.

    +
  • +
  • +

    accept(): wait for the next client to connect. The returned Promise + receives a SocketConnection.

    +
  • +
+ +

SocketConnection

+ +

Inherits from IOStream. + All methods are fully asynchronous and return Promise objects.

+ +
    +
  • setNoDelay(noDelay): disable the Nagle algorithm if noDelay is true, + otherwise enable it. The Nagle algorithm is enabled by default, so it is + only necessary to call this method if you wish to optimize for low delay + instead of high throughput.
  • +
+ +
+ +

File and Stream

+ +

File

+ +
    +
  • +

    new File(filePath, mode): open or create the file at filePath with + the mode string specifying how it should be opened. For example "wb" + to open the file for writing in binary mode (this is the same format as + fopen() from the C standard library).

    +
  • +
  • +

    write(data): synchronously write data to the file, where data is + either a string or a buffer as returned by NativePointer#readByteArray

    +
  • +
  • +

    flush(): flush any buffered data to the underlying file

    +
  • +
  • +

    close(): close the file. You should call this function when you’re done + with the file unless you are fine with this happening when the object is + garbage-collected or the script is unloaded.

    +
  • +
+ +

IOStream

+ +

All methods are fully asynchronous and return Promise objects.

+ +
    +
  • +

    input: the InputStream to read from.

    +
  • +
  • +

    output: the OutputStream to write to.

    +
  • +
  • +

    close(): close the stream, releasing resources related to it. This will + also close the individual input and output streams. Once the stream is + closed, all other operations will fail. Closing a stream multiple times is + allowed and will not result in an error.

    +
  • +
+ +

InputStream

+ +

All methods are fully asynchronous and return Promise objects.

+ +
    +
  • +

    close(): close the stream, releasing resources related to it. Once the + stream is closed, all other operations will fail. Closing a stream multiple + times is allowed and will not result in an error.

    +
  • +
  • +

    read(size): read up to size bytes from the stream. The returned + Promise receives an ArrayBuffer up to size bytes long. + End of stream is signalled through an empty buffer.

    +
  • +
  • +

    readAll(size): keep reading from the stream until exactly size bytes + have been consumed. The returned Promise receives an ArrayBuffer + that is exactly size bytes long. Premature error or end of stream results in the + Promise getting rejected with an error, where the Error object has a + partialData property containing the incomplete data.

    +
  • +
+ +

OutputStream

+ +

All methods are fully asynchronous and return Promise objects.

+ +
    +
  • +

    close(): close the stream, releasing resources related to it. Once the + stream is closed, all other operations will fail. Closing a stream multiple + times is allowed and will not result in an error.

    +
  • +
  • +

    write(data): try to write data to the stream. The data value is either + an ArrayBuffer or an array of integers between 0 and 255. The + returned Promise receives a Number specifying how many bytes of data were + written to the stream.

    +
  • +
  • +

    writeAll(data): keep writing to the stream until all of data has been + written. The data value is either an ArrayBuffer or an array + of integers between 0 and 255. Premature error or end of stream results in an + error, where the Error object has a partialSize property specifying how many + bytes of data were written to the stream before the error occurred.

    +
  • +
  • +

    writeMemoryRegion(address, size): try to write size bytes to the stream, + reading them from address, which is a NativePointer. The + returned Promise receives a Number specifying how many bytes of data were + written to the stream.

    +
  • +
+ +

UnixInputStream

+ +

(Only available on UNIX-like OSes.)

+ +
    +
  • +

    new UnixInputStream(fd[, options]): create a new + InputStream from the specified file descriptor fd.

    + +

    You may also supply an options object with autoClose set to true to + make the stream close the underlying file descriptor when the stream is + released, either through close() or future garbage-collection.

    +
  • +
+ +

UnixOutputStream

+ +

(Only available on UNIX-like OSes.)

+ +
    +
  • +

    new UnixOutputStream(fd[, options]): create a new + OutputStream from the specified file descriptor fd.

    + +

    You may also supply an options object with autoClose set to true to + make the stream close the underlying file descriptor when the stream is + released, either through close() or future garbage-collection.

    +
  • +
+ +

Win32InputStream

+ +

(Only available on Windows.)

+ +
    +
  • +

    new Win32InputStream(handle[, options]): create a new + InputStream from the specified handle, which is a Windows + HANDLE value.

    + +

    You may also supply an options object with autoClose set to true to + make the stream close the underlying handle when the stream is released, + either through close() or future garbage-collection.

    +
  • +
+ +

Win32OutputStream

+ +

(Only available on Windows.)

+ +
    +
  • +

    new Win32OutputStream(handle[, options]): create a new + OutputStream from the specified handle, which is a + Windows HANDLE value.

    + +

    You may also supply an options object with autoClose set to true to + make the stream close the underlying handle when the stream is released, + either through close() or future garbage-collection.

    +
  • +
+ +

Database

+ +

SqliteDatabase

+ +
    +
  • +

    SqliteDatabase.open(path[, options]): opens the SQLite v3 database + specified by path, a string containing the filesystem path to the + database. By default the database will be opened read-write, but you may + customize this behavior by providing an options object with a property + named flags, specifying an array of strings containing one or more of the + following values: readonly, readwrite, create. The returned + SqliteDatabase object will allow you to perform queries on the database.

    +
  • +
  • +

    SqliteDatabase.openInline(encodedContents): just like open() but the + contents of the database is provided as a string containing its data, + Base64-encoded. We recommend gzipping the database before Base64-encoding + it, but this is optional and detected by looking for a gzip magic marker. + The database is opened read-write, but is 100% in-memory and never touches + the filesystem. This is useful for agents that need to bundle a cache of + precomputed data, e.g. static analysis data used to guide dynamic analysis.

    +
  • +
  • +

    close(): close the database. You should call this function when you’re + done with the database, unless you are fine with this happening when the + object is garbage-collected or the script is unloaded.

    +
  • +
  • +

    exec(sql): execute a raw SQL query, where sql is a string containing + the text-representation of the query. The query’s result is ignored, so this + should only be used for queries for setting up the database, e.g. table + creation.

    +
  • +
  • +

    prepare(sql): compile the provided SQL into a + SqliteStatement object, where sql is a string + containing the text-representation of the query.

    + +

    For example:

    +
  • +
+ +
const db = SqliteDatabase.open('/path/to/people.db');
+			
+			const smt = db.prepare('SELECT name, bio FROM people WHERE age = ?');
+			
+			console.log('People whose age is 42:');
+			smt.bindInteger(1, 42);
+			let row;
+			while ((row = smt.step()) !== null) {
+			  const [name, bio] = row;
+			  console.log('Name:', name);
+			  console.log('Bio:', bio);
+			}
+			smt.reset();
+ +
    +
  • dump(): dump the database to a gzip-compressed blob encoded as Base64, + where the result is returned as a string. This is useful for inlining a + cache in your agent’s code, loaded by calling SqliteDatabase.openInline().
  • +
+ +

SqliteStatement

+ +
    +
  • bindInteger(index, value): bind the integer value to index
  • +
  • bindFloat(index, value): bind the floating point value to index
  • +
  • bindText(index, value): bind the text value to index
  • +
  • bindBlob(index, bytes): bind the blob bytes to index, where bytes + is an ArrayBuffer, array of byte values, or a string
  • +
  • bindNull(index): bind a null value to index
  • +
  • step(): either start a new query and get the first result, or move to the + next one. Returns an array containing the values in the order specified by + the query, or null when the last result is reached. You should call + reset() at that point if you intend to use this object again.
  • +
  • reset(): reset internal state to allow subsequent queries
  • +
+ +
+ +

Instrumentation

+ +

Interceptor

+ +
    +
  • +

    Interceptor.attach(target, callbacks[, data]): intercept calls to function + at target. This is a NativePointer specifying the address + of the function you would like to intercept calls to. Note that on 32-bit ARM this + address must have its least significant bit set to 0 for ARM functions, and + 1 for Thumb functions. Frida takes care of this detail for you if you get + the address from a Frida API (for example Module.getExportByName()).

    + +

    The callbacks argument is an object containing one or more of:

    + +
      +
    • +

      onEnter(args): callback function given one argument args that can be + used to read or write arguments as an array of + NativePointer objects. {: #interceptor-onenter}

      +
    • +
    • +

      onLeave(retval): callback function given one argument retval that is + a NativePointer-derived object containing the raw + return value. + You may call retval.replace(1337) to replace the return value with + the integer 1337, or retval.replace(ptr("0x1234")) to replace with + a pointer. + Note that this object is recycled across onLeave calls, so do not + store and use it outside your callback. Make a deep copy if you need + to store the contained value, e.g.: ptr(retval.toString()).

      +
    • +
    + +

    In case the hooked function is very hot, onEnter and onLeave may be + NativePointer values pointing at native C functions compiled + using CModule. Their signatures are:

    + +
      +
    • +

      void onEnter (GumInvocationContext * ic)

      +
    • +
    • +

      void onLeave (GumInvocationContext * ic)

      +
    • +
    + +

    In such cases, the third optional argument data may be a NativePointer + accessible through gum_invocation_context_get_listener_function_data().

    + +

    You may also intercept arbitrary instructions by passing a function instead + of the callbacks object. This function has the same signature as + onEnter, but the args argument passed to it will only give you sensible + values if the intercepted instruction is at the beginning of a function or + at a point where registers/stack have not yet deviated from that point.

    + +

    Just like above, this function may also be implemented in C by specifying + a NativePointer instead of a function.

    + +

    Returns a listener object that you can call detach() on.

    + +

    Note that these functions will be invoked with this bound to a + per-invocation (thread-local) object where you can store arbitrary data, + which is useful if you want to read an argument in onEnter and act on it + in onLeave.

    + +

    For example:

    +
  • +
+ +
Interceptor.attach(Module.getExportByName('libc.so', 'read'), {
+			  onEnter(args) {
+				this.fileDescriptor = args[0].toInt32();
+			  },
+			  onLeave(retval) {
+				if (retval.toInt32() > 0) {
+				  /* do something with this.fileDescriptor */
+				}
+			  }
+			});
+ +
    +
  • +

    Additionally, the object contains some useful properties:

    + +
      +
    • +

      returnAddress: return address as a NativePointer

      +
    • +
    • +

      context: object with the keys pc and sp, which are + NativePointer objects specifying EIP/RIP/PC and + ESP/RSP/SP, respectively, for ia32/x64/arm. Other processor-specific keys + are also available, e.g. eax, rax, r0, x0, etc. + You may also update register values by assigning to these keys.

      +
    • +
    • +

      errno: (UNIX) current errno value (you may replace it)

      +
    • +
    • +

      lastError: (Windows) current OS error value (you may replace it)

      +
    • +
    • +

      threadId: OS thread ID

      +
    • +
    • +

      depth: call depth of relative to other invocations

      +
    • +
    + +

    For example:

    +
  • +
+ +
Interceptor.attach(Module.getExportByName(null, 'read'), {
+			  onEnter(args) {
+				console.log('Context information:');
+				console.log('Context  : ' + JSON.stringify(this.context));
+				console.log('Return   : ' + this.returnAddress);
+				console.log('ThreadId : ' + this.threadId);
+				console.log('Depth    : ' + this.depth);
+				console.log('Errornr  : ' + this.err);
+			
+				// Save arguments for processing in onLeave.
+				this.fd = args[0].toInt32();
+				this.buf = args[1];
+				this.count = args[2].toInt32();
+			  },
+			  onLeave(result) {
+				console.log('----------')
+				// Show argument 1 (buf), saved during onEnter.
+				const numBytes = result.toInt32();
+				if (numBytes > 0) {
+				  console.log(hexdump(this.buf, { length: numBytes, ansi: true }));
+				}
+				console.log('Result   : ' + numBytes);
+			  }
+			})
+ +
+
Performance considerations
+

+ The callbacks provided have a significant impact on performance. If you only + need to inspect arguments but do not care about the return value, or the + other way around, make sure you omit the callback that you don't need; i.e. + avoid putting your logic in onEnter and leaving onLeave in + there as an empty callback. +

+

+ On an iPhone 5S the base overhead when providing just onEnter might be + something like 6 microseconds, and 11 microseconds with both onEnter + and onLeave provided. +

+

+ Also be careful about intercepting calls to functions that are called a + bazillion times per second; while send() is + asynchronous, the total overhead of sending a single message is not optimized for + high frequencies, so that means Frida leaves it up to you to batch multiple values + into a single send()-call, based on whether low delay + or high throughput is desired. +

+

+ However when hooking hot functions you may use Interceptor in conjunction + with CModule to implement the callbacks in C. +

+
+ +
    +
  • +

    Interceptor.detachAll(): detach all previously attached callbacks.

    +
  • +
  • +

    Interceptor.replace(target, replacement[, data]): replace function at + target with implementation at replacement. This is typically used if you + want to fully or partially replace an existing function’s implementation.

    + +

    Use NativeCallback to implement a replacement in JavaScript.

    + +

    In case the replaced function is very hot, you may implement replacement + in C using CModule. You may then also specify the third optional + argument data, which is a NativePointer accessible through + gum_invocation_context_get_listener_function_data(). Use + gum_interceptor_get_current_invocation() to get hold of the + GumInvocationContext *.

    + +

    Note that replacement will be kept alive until Interceptor#revert is + called.

    + +

    If you want to chain to the original implementation you can synchronously + call target through a NativeFunction inside your + implementation, which will bypass and go directly to the original implementation.

    + +

    Here’s an example:

    +
  • +
+ +
const openPtr = Module.getExportByName('libc.so', 'open');
+			const open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
+			Interceptor.replace(openPtr, new NativeCallback((pathPtr, flags) => {
+			  const path = pathPtr.readUtf8String();
+			  log('Opening "' + path + '"');
+			  const fd = open(pathPtr, flags);
+			  log('Got fd: ' + fd);
+			  return fd;
+			}, 'int', ['pointer', 'int']));
+ +
    +
  • +

    Interceptor.revert(target): revert function at target to the previous + implementation.

    +
  • +
  • +

    Interceptor.flush(): ensure any pending changes have been committed + to memory. This is should only be done in the few cases where this is + necessary, e.g. if you just attach()ed to or replace()d a function that you + are about to call using NativeFunction. Pending changes + are flushed automatically whenever the current thread is about to leave the + JavaScript runtime or calls send(). This includes any + API built on top of send(), like when returning from an + RPC method, and calling any method on the console API.

    +
  • +
+ +

Stalker

+ +
    +
  • +

    Stalker.exclude(range): marks the specified memory range as excluded, + which is an object with base and size properties – like the properties + in an object returned by e.g. Process.getModuleByName().

    + +

    This means Stalker will not follow execution when encountering a call to an + instruction in such a range. You will thus be able to observe/modify the + arguments going in, and the return value coming back, but won’t see the + instructions that happened between.

    + +

    Useful to improve performance and reduce noise.

    +
  • +
  • +

    Stalker.follow([threadId, options]): start stalking threadId (or the + current thread if omitted), optionally with options for enabling events.

    + +

    For example:

    +
  • +
+ +
const mainThread = Process.enumerateThreads()[0];
+			
+			Stalker.follow(mainThread.id, {
+			  events: {
+				call: true, // CALL instructions: yes please
+			
+				// Other events:
+				ret: false, // RET instructions
+				exec: false, // all instructions: not recommended as it's
+							 //                   a lot of data
+				block: false, // block executed: coarse execution trace
+				compile: false // block compiled: useful for coverage
+			  },
+			
+			  //
+			  // Only specify one of the two following callbacks.
+			  // (See note below.)
+			  //
+			
+			  //
+			  // onReceive: Called with `events` containing a binary blob
+			  //            comprised of one or more GumEvent structs.
+			  //            See `gumevent.h` for details about the
+			  //            format. Use `Stalker.parse()` to examine the
+			  //            data.
+			  //
+			  //onReceive(events) {
+			  //},
+			  //
+			
+			  //
+			  // onCallSummary: Called with `summary` being a key-value
+			  //                mapping of call target to number of
+			  //                calls, in the current time window. You
+			  //                would typically implement this instead of
+			  //                `onReceive()` for efficiency, i.e. when
+			  //                you only want to know which targets were
+			  //                called and how many times, but don't care
+			  //                about the order that the calls happened
+			  //                in.
+			  //
+			  onCallSummary(summary) {
+			  },
+			
+			  //
+			  // Advanced users: This is how you can plug in your own
+			  //                 StalkerTransformer, where the provided
+			  //                 function is called synchronously
+			  //                 whenever Stalker wants to recompile
+			  //                 a basic block of the code that's about
+			  //                 to be executed by the stalked thread.
+			  //
+			  //transform(iterator) {
+			  //  let instruction = iterator.next();
+			  //
+			  //  const startAddress = instruction.address;
+			  //  const isAppCode = startAddress.compare(appStart) >= 0 &&
+			  //      startAddress.compare(appEnd) === -1;
+			  //
+			  //  do {
+			  //    if (isAppCode && instruction.mnemonic === 'ret') {
+			  //      iterator.putCmpRegI32('eax', 60);
+			  //      iterator.putJccShortLabel('jb', 'nope', 'no-hint');
+			  //
+			  //      iterator.putCmpRegI32('eax', 90);
+			  //      iterator.putJccShortLabel('ja', 'nope', 'no-hint');
+			  //
+			  //      iterator.putCallout(onMatch);
+			  //
+			  //      iterator.putLabel('nope');
+			  //    }
+			  //
+			  //    iterator.keep();
+			  //  } while ((instruction = iterator.next()) !== null);
+			  //},
+			  //
+			  // The default implementation is just:
+			  //
+			  //   while (iterator.next() !== null)
+			  //     iterator.keep();
+			  //
+			  // The example above shows how you can insert your own code
+			  // just before every `ret` instruction across any code
+			  // executed by the stalked thread inside the app's own
+			  // memory range. It inserts code that checks if the `eax`
+			  // register contains a value between 60 and 90, and inserts
+			  // a synchronous callout back into JavaScript whenever that
+			  // is the case. The callback receives a single argument
+			  // that gives it access to the CPU registers, and it is
+			  // also able to modify them.
+			  //
+			  // function onMatch (context) {
+			  //   console.log('Match! pc=' + context.pc +
+			  //       ' rax=' + context.rax.toInt32());
+			  // }
+			  //
+			  // Note that not calling keep() will result in the
+			  // instruction getting dropped, which makes it possible
+			  // for your transform to fully replace certain instructions
+			  // when this is desirable.
+			  //
+			
+			  //
+			  // Want better performance? Write the callbacks in C:
+			  //
+			  // /*
+			  //  * const cm = new CModule(\`
+			  //  *
+			  //  * #include <gum/gumstalker.h>
+			  //  *
+			  //  * static void on_ret (GumCpuContext * cpu_context,
+			  //  *     gpointer user_data);
+			  //  *
+			  //  * void
+			  //  * transform (GumStalkerIterator * iterator,
+			  //  *            GumStalkerOutput * output,
+			  //  *            gpointer user_data)
+			  //  * {
+			  //  *   cs_insn * insn;
+			  //  *
+			  //  *   while (gum_stalker_iterator_next (iterator, &insn))
+			  //  *   {
+			  //  *     if (insn->id == X86_INS_RET)
+			  //  *     {
+			  //  *       gum_x86_writer_put_nop (output->writer.x86);
+			  //  *       gum_stalker_iterator_put_callout (iterator,
+			  //  *           on_ret, NULL, NULL);
+			  //  *     }
+			  //  *
+			  //  *     gum_stalker_iterator_keep (iterator);
+			  //  *   }
+			  //  * }
+			  //  *
+			  //  * static void
+			  //  * on_ret (GumCpuContext * cpu_context,
+			  //  *         gpointer user_data)
+			  //  * {
+			  //  *   printf ("on_ret!\n");
+			  //  * }
+			  //  *
+			  //  * void
+			  //  * process (const GumEvent * event,
+			  //  *          GumCpuContext * cpu_context,
+			  //  *          gpointer user_data)
+			  //  * {
+			  //  *   switch (event->type)
+			  //  *   {
+			  //  *     case GUM_CALL:
+			  //  *       break;
+			  //  *     case GUM_RET:
+			  //  *       break;
+			  //  *     case GUM_EXEC:
+			  //  *       break;
+			  //  *     case GUM_BLOCK:
+			  //  *       break;
+			  //  *     case GUM_COMPILE:
+			  //  *       break;
+			  //  *     default:
+			  //  *       break;
+			  //  *   }
+			  //  * }
+			  //  * `);
+			  //  */
+			  //
+			  //transform: cm.transform,
+			  //onEvent: cm.process,
+			  //data: ptr(1337) /* user_data */
+			  //
+			  // You may also use a hybrid approach and only write
+			  // some of the callouts in C.
+			  //
+			});
+ +
+
Performance considerations
+

+ The callbacks provided have a significant impact on performance. If you only + need periodic call summaries but do not care about the raw events, or the + other way around, make sure you omit the callback that you don't need; i.e. + avoid putting your logic in onCallSummary and leaving + onReceive in there as an empty callback. +

+

+ Also note that Stalker may be used in conjunction with CModule, + which means the callbacks may be implemented in C. +

+
+ +
    +
  • +

    Stalker.unfollow([threadId]): stop stalking threadId (or the current + thread if omitted).

    +
  • +
  • +

    Stalker.parse(events[, options]): parse GumEvent binary blob, optionally + with options for customizing the output.

    + +

    For example:

    +
  • +
+ +
  onReceive(events) {
+				console.log(Stalker.parse(events, {
+				  annotate: true, // to display the type of event
+				  stringify: true
+					// to format pointer values as strings instead of `NativePointer`
+					// values, i.e. less overhead if you're just going to `send()` the
+					// thing not actually parse the data agent-side
+				}));
+			  },
+ +
    +
  • +

    Stalker.flush(): flush out any buffered events. Useful when you don’t want + to wait until the next Stalker.queueDrainInterval tick.

    +
  • +
  • +

    Stalker.garbageCollect(): free accumulated memory at a safe point after + Stalker#unfollow. This is needed to avoid race-conditions + where the thread just unfollowed is executing its last instructions.

    +
  • +
  • +

    Stalker.invalidate(address): invalidates the current thread’s translated + code for a given basic block. Useful when providing a transform callback and + wanting to dynamically adapt the instrumentation for a given basic block. + This is much more efficient than unfollowing and re-following the thread, + which would discard all cached translations and require all encountered + basic blocks to be compiled from scratch.

    +
  • +
  • +

    Stalker.invalidate(threadId, address): invalidates a specific thread’s + translated code for a given basic block. Useful when providing a transform + callback and wanting to dynamically adapt the instrumentation for a given + basic block. This is much more efficient than unfollowing and re-following + the thread, which would discard all cached translations and require all + encountered basic blocks to be compiled from scratch.

    +
  • +
  • +

    Stalker.addCallProbe(address, callback[, data]): call callback (see + Interceptor#attach#onEnter for signature) synchronously + when a call is made to address. Returns an id that can be passed to + Stalker#removeCallProbe later.

    + +

    It is also possible to implement callback in C using CModule, + by specifying a NativePointer instead of a function. Signature:

    + +
      +
    • void onCall (GumCallSite * site, gpointer user_data)
    • +
    + +

    In such cases, the third optional argument data may be a NativePointer + whose value is passed to the callback as user_data.

    +
  • +
  • +

    Stalker.removeCallProbe: remove a call probe added by + Stalker#addCallProbe.

    +
  • +
  • +

    Stalker.trustThreshold: an integer specifying how many times a piece of + code needs to be executed before it is assumed it can be trusted to not + mutate. + Specify -1 for no trust (slow), 0 to trust code from the get-go, and N to + trust code after it has been executed N times. Defaults to 1.

    +
  • +
  • +

    Stalker.queueCapacity: an integer specifying the capacity of the event + queue in number of events. Defaults to 16384 events.

    +
  • +
  • +

    Stalker.queueDrainInterval: an integer specifying the time in milliseconds + between each time the event queue is drained. Defaults to 250 ms, which + means that the event queue is drained four times per second. You may also + set this property to zero to disable periodic draining, and instead call + Stalker.flush() when you would like the queue to be drained.

    +
  • +
+ +

ObjC

+ +
    +
  • +

    ObjC.available: a boolean specifying whether the current process has an + Objective-C runtime loaded. Do not invoke any other ObjC properties or + methods unless this is the case.

    +
  • +
  • +

    ObjC.api: an object mapping function names to NativeFunction instances + for direct access to a big portion of the Objective-C runtime API.

    +
  • +
  • +

    ObjC.classes: an object mapping class names to ObjC.Object + JavaScript bindings for each of the currently registered classes. You can interact + with objects by using dot notation and replacing colons with underscores, i.e.: + [NSString stringWithString:@"Hello World"] + becomes + const { NSString } = ObjC.classes; NSString.stringWithString_("Hello World");. + Note the underscore after the method name. Refer to iOS Examples section for + more details.

    +
  • +
  • +

    ObjC.protocols: an object mapping protocol names to ObjC.Protocol + JavaScript bindings for each of the currently registered protocols.

    +
  • +
  • +

    ObjC.mainQueue: the GCD queue of the main thread

    +
  • +
  • +

    ObjC.schedule(queue, work): schedule the JavaScript function work on + the GCD queue specified by queue. An NSAutoreleasePool is created just + before calling work, and cleaned up on return.

    +
  • +
+ +
const { NSSound } = ObjC.classes; /* macOS */
+			ObjC.schedule(ObjC.mainQueue, () => {
+				const sound = NSSound.alloc().initWithContentsOfFile_byReference_("/Users/oleavr/.Trash/test.mp3", true);
+				sound.play();
+			});
+ +
    +
  • new ObjC.Object(handle[, protocol]): create a JavaScript binding given + the existing object at handle (a NativePointer). You may + also specify the protocol argument if you’d like to treat handle as an object + implementing a certain protocol only.
  • +
+ +
Interceptor.attach(myFunction.implementation, {
+			  onEnter(args) {
+				// ObjC: args[0] = self, args[1] = selector, args[2-n] = arguments
+				const myString = new ObjC.Object(args[2]);
+				console.log("String argument: " + myString.toString());
+			  }
+			});
+ +
+

This object has some special properties:

+ +
    +
  • $kind: string specifying either instance, class or meta-class
  • +
  • $super: an ObjC.Object instance used for chaining up to + super-class method implementations
  • +
  • $superClass: super-class as an ObjC.Object instance
  • +
  • $class: class of this object as an ObjC.Object instance
  • +
  • $className: string containing the class name of this object
  • +
  • $moduleName: string containing the module path of this object
  • +
  • $protocols: object mapping protocol name to ObjC.Protocol + instance for each of the protocols that this object conforms to
  • +
  • $methods: array containing native method names exposed by this object’s + class and parent classes
  • +
  • $ownMethods: array containing native method names exposed by this object’s + class, not including parent classes
  • +
  • $ivars: object mapping each instance variable name to its current + value, allowing you to read and write each through access and assignment
  • +
+ +

There is also an equals(other) method for checking whether two instances + refer to the same underlying object.

+ +

Note that all method wrappers provide a clone(options) API to create a new + method wrapper with custom NativeFunction options.

+
+ +
    +
  • +

    new ObjC.Protocol(handle): create a JavaScript binding given the existing + protocol at handle (a NativePointer).

    +
  • +
  • +

    new ObjC.Block(target[, options]): create a JavaScript binding given the + existing block at target (a NativePointer), or, to define + a new block, target should be an object specifying the type signature and + JavaScript function to call whenever the block is invoked. The function is + specified with an implementation key, and the signature is specified either + through a types key, or through the retType and argTypes keys. See + ObjC.registerClass() for details.

    + +

    Note that if an existing block lacks signature metadata, you may call + declare(signature), where signature is an object with either a types + key, or retType and argTypes keys, as described above.

    + +

    You may also provide an options object with the same options as supported + by NativeFunction, e.g. to pass traps: 'all' in order + to Stalker.follow() the execution when calling the block.

    + +

    The most common use-case is hooking an existing block, which for a block + expecting two arguments would look something like:

    +
  • +
+ +
const pendingBlocks = new Set();
+			
+			Interceptor.attach(..., {
+			  onEnter(args) {
+				const block = new ObjC.Block(args[4]);
+				pendingBlocks.add(block); // Keep it alive
+				const appCallback = block.implementation;
+				block.implementation = (error, value) => {
+				  // Do your logging here
+				  const result = appCallback(error, value);
+				  pendingBlocks.delete(block);
+				  return result;
+				};
+			  }
+			});
+ +
    +
  • ObjC.implement(method, fn): create a JavaScript implementation compatible + with the signature of method, where the JavaScript function fn is used + as the implementation. Returns a NativeCallback that you may + assign to an ObjC method’s implementation property.
  • +
+ +
const NSSound = ObjC.classes.NSSound; /* macOS */
+			const oldImpl = NSSound.play.implementation;
+			NSSound.play.implementation = ObjC.implement(NSSound.play, (handle, selector) => {
+			  return oldImpl(handle, selector);
+			});
+			
+			const NSView = ObjC.classes.NSView; /* macOS */
+			const drawRect = NSView['- drawRect:'];
+			const oldImpl = drawRect.implementation;
+			drawRect.implementation = ObjC.implement(drawRect, (handle, selector) => {
+			  oldImpl(handle, selector);
+			});
+ +
+

As the implementation property is a NativeFunction and thus also a + NativePointer, you may also use Interceptor to hook functions:

+
+ +
const { NSSound } = ObjC.classes; /* macOS */
+			Interceptor.attach(NSSound.play.implementation, {
+			  onEnter() {
+				send("[NSSound play]");
+			  }
+			});
+ +
    +
  • +

    ObjC.registerProxy(properties): create a new class designed to act as a + proxy for a target object, where properties is an object specifying:

    + +
      +
    • protocols: (optional) Array of protocols this class conforms to.
    • +
    • methods: (optional) Object specifying methods to implement.
    • +
    • events: (optional) Object specifying callbacks for getting notified + about events: +
        +
      • dealloc(): Called right after the object has been deallocated. + This is where you might clean up any associated state.
      • +
      • forward(name): Called with name specifying the method name that + we’re about to forward a call to. This might be where you’d start + out with a temporary callback that just logs the names to help you + decide which methods to override.
      • +
      +
    • +
    +
  • +
+ +
const MyConnectionDelegateProxy = ObjC.registerProxy({
+			  protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
+			  methods: {
+				'- connection:didReceiveResponse:': function (conn, resp) {
+				  /* fancy logging code here */
+				  /* this.data.foo === 1234 */
+				  this.data.target
+					  .connection_didReceiveResponse_(conn, resp);
+				},
+				'- connection:didReceiveData:': function (conn, data) {
+				  /* other logging code here */
+				  this.data.target
+					  .connection_didReceiveData_(conn, data);
+				}
+			  },
+			  events: {
+				forward(name) {
+				  console.log('*** forwarding: ' + name);
+				}
+			  }
+			});
+			
+			const method = ObjC.classes.NSURLConnection[
+				'- initWithRequest:delegate:startImmediately:'];
+			Interceptor.attach(method.implementation, {
+			  onEnter(args) {
+				args[3] = new MyConnectionDelegateProxy(args[3], {
+				  foo: 1234
+				});
+			  }
+			});
+ +
    +
  • +

    ObjC.registerClass(properties): create a new Objective-C class, where + properties is an object specifying:

    + +
      +
    • name: (optional) String specifying the name of the class; omit this + if you don’t care about the globally visible name and would like the + runtime to auto-generate one for you.
    • +
    • super: (optional) Super-class, or null to create a new root class; + omit to inherit from NSObject.
    • +
    • protocols: (optional) Array of protocols this class conforms to.
    • +
    • methods: (optional) Object specifying methods to implement.
    • +
    +
  • +
+ +
const MyConnectionDelegateProxy = ObjC.registerClass({
+			  name: 'MyConnectionDelegateProxy',
+			  super: ObjC.classes.NSObject,
+			  protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
+			  methods: {
+				'- init': function () {
+				  const self = this.super.init();
+				  if (self !== null) {
+					ObjC.bind(self, {
+					  foo: 1234
+					});
+				  }
+				  return self;
+				},
+				'- dealloc': function () {
+				  ObjC.unbind(this.self);
+				  this.super.dealloc();
+				},
+				'- connection:didReceiveResponse:': function (conn, resp) {
+				  /* this.data.foo === 1234 */
+				},
+				/*
+				 * But those previous methods are declared assuming that
+				 * either the super-class or a protocol we conform to has
+				 * the same method so we can grab its type information.
+				 * However, if that's not the case, you would write it
+				 * like this:
+				 */
+				'- connection:didReceiveResponse:': {
+				  retType: 'void',
+				  argTypes: ['object', 'object'],
+				  implementation(conn, resp) {
+				  }
+				},
+				/* Or grab it from an existing class: */
+				'- connection:didReceiveResponse:': {
+				  types: ObjC.classes
+					  .Foo['- connection:didReceiveResponse:'].types,
+				  implementation(conn, resp) {
+				  }
+				},
+				/* Or from an existing protocol: */
+				'- connection:didReceiveResponse:': {
+				  types: ObjC.protocols.NSURLConnectionDataDelegate
+					  .methods['- connection:didReceiveResponse:'].types,
+				  implementation(conn, resp) {
+				  }
+				},
+				/* Or write the signature by hand if you really want to: */
+				'- connection:didReceiveResponse:': {
+				  types: '[email protected]:[email protected]@24',
+				  implementation(conn, resp) {
+				  }
+				}
+			  }
+			});
+			
+			const proxy = MyConnectionDelegateProxy.alloc().init();
+			/* use `proxy`, and later: */
+			proxy.release();
+ +
    +
  • +

    ObjC.registerProtocol(properties): create a new Objective-C protocol, + where properties is an object specifying:

    + +
      +
    • name: (optional) String specifying the name of the protocol; omit this + if you don’t care about the globally visible name and would like the + runtime to auto-generate one for you.
    • +
    • protocols: (optional) Array of protocols this protocol incorporates.
    • +
    • methods: (optional) Object specifying methods to declare.
    • +
    +
  • +
+ +
const MyDataDelegate = ObjC.registerProtocol({
+			  name: 'MyDataDelegate',
+			  protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
+			  methods: {
+				/* You must specify the signature: */
+				'- connection:didStuff:': {
+				  retType: 'void',
+				  argTypes: ['object', 'object']
+				},
+				/* Or grab it from a method of an existing class: */
+				'- connection:didStuff:': {
+				  types: ObjC.classes
+					  .Foo['- connection:didReceiveResponse:'].types
+				},
+				/* Or from an existing protocol method: */
+				'- connection:didStuff:': {
+				  types: ObjC.protocols.NSURLConnectionDataDelegate
+					  .methods['- connection:didReceiveResponse:'].types
+				},
+				/* Or write the signature by hand if you really want to: */
+				'- connection:didStuff:': {
+				  types: '[email protected]:[email protected]@24'
+				},
+				/* You can also make a method optional (default is required): */
+				'- connection:didStuff:': {
+				  retType: 'void',
+				  argTypes: ['object', 'object'],
+				  optional: true
+				}
+			  }
+			});
+ +
    +
  • +

    ObjC.bind(obj, data): bind some JavaScript data to an Objective-C + instance; see ObjC.registerClass() for an example.

    +
  • +
  • +

    ObjC.unbind(obj): unbind previous associated JavaScript data from an + Objective-C instance; see ObjC.registerClass() for an example.

    +
  • +
  • +

    ObjC.getBoundData(obj): look up previously bound data from an Objective-C + object.

    +
  • +
  • +

    ObjC.enumerateLoadedClasses([options, ]callbacks): enumerate classes + loaded right now, where callbacks is an object specifying:

    + +
      +
    • +

      onMatch(name, owner): called for each loaded class with the name of + the class as a string, and owner specifying the path to the module + where the class was loaded from. To obtain a JavaScript wrapper for a + given class, do: ObjC.classes[name].

      +
    • +
    • +

      onComplete(): called when all classes have been enumerated.

      +
    • +
    + +

    For example:

    +
  • +
+ +
ObjC.enumerateLoadedClasses({
+			  onMatch(name, owner) {
+				console.log('onMatch:', name, owner);
+			  },
+			  onComplete() {
+			  }
+			});
+ +

The optional options argument is an object where you may specify the + ownedBy property to limit enumeration to modules in a given ModuleMap.

+ +

For example:

+ +
const appModules = new ModuleMap(isAppModule);
+			ObjC.enumerateLoadedClasses({ ownedBy: appModules }, {
+			  onMatch(name, owner) {
+				console.log('onMatch:', name, owner);
+			  },
+			  onComplete() {
+			  }
+			});
+			
+			function isAppModule(m) {
+			  return !/^\/(usr\/lib|System|Developer)\//.test(m.path);
+			}
+ +
    +
  • +

    ObjC.enumerateLoadedClassesSync([options]): synchronous version of + enumerateLoadedClasses() that returns an object + mapping owner module to an array of class names.

    + +

    For example:

    +
  • +
+ +
const appModules = new ModuleMap(isAppModule);
+			const appClasses = ObjC.enumerateLoadedClassesSync({ ownedBy: appModules });
+			console.log('appClasses:', JSON.stringify(appClasses));
+			
+			function isAppModule(m) {
+			  return !/^\/(usr\/lib|System|Developer)\//.test(m.path);
+			}
+ +
    +
  • +

    ObjC.choose(specifier, callbacks): enumerate live instances of classes + matching specifier by scanning the heap. specifier is either a class + selector or an object specifying a class selector and desired options. + The class selector is an ObjC.Object of a class, e.g. + ObjC.classes.UIButton. + When passing an object as the specifier you should provide the class + field with your class selector, and the subclasses field with a + boolean indicating whether you’re also interested in subclasses matching the + given class selector. The default is to also include subclasses. + The callbacks argument is an object specifying:

    + +
      +
    • +

      onMatch(instance): called once for each live instance found with a + ready-to-use instance just as if you would have called + new ObjC.Object(ptr("0x1234")) knowing that this + particular Objective-C instance lives at 0x1234.

      + +

      This function may return the string stop to cancel the enumeration + early.

      +
    • +
    • +

      onComplete(): called when all instances have been enumerated

      +
    • +
    +
  • +
  • +

    ObjC.chooseSync(specifier): synchronous version of choose() + that returns the instances in an array.

    +
  • +
  • +

    ObjC.selector(name): convert the JavaScript string name to a selector

    +
  • +
  • +

    ObjC.selectorAsString(sel): convert the selector sel to a JavaScript + string

    +
  • +
+ +

Java

+ +
    +
  • +

    Java.available: a boolean specifying whether the current process has the + a Java VM loaded, i.e. Dalvik or ART. Do not invoke any other Java + properties or methods unless this is the case.

    +
  • +
  • +

    Java.androidVersion: a string specifying which version of Android we’re + running on.

    +
  • +
  • +

    Java.enumerateLoadedClasses(callbacks): enumerate classes loaded right + now, where callbacks is an object specifying:

    + +
      +
    • +

      onMatch(name, handle): called for each loaded class with name that + may be passed to use() to get a JavaScript wrapper. + You may also Java.cast() the handle to java.lang.Class.

      +
    • +
    • +

      onComplete(): called when all classes have been enumerated.

      +
    • +
    +
  • +
  • +

    Java.enumerateLoadedClassesSync(): synchronous version of + enumerateLoadedClasses() that returns the + class names in an array.

    +
  • +
  • +

    Java.enumerateClassLoaders(callbacks): enumerate class loaders present + in the Java VM, where callbacks is an object specifying:

    + +
      +
    • +

      onMatch(loader): called for each class loader with loader, a wrapper + for the specific java.lang.ClassLoader.

      +
    • +
    • +

      onComplete(): called when all class loaders have been enumerated.

      +
    • +
    + +

    You may pass such a loader to Java.ClassFactory.get() to be able to + .use() classes on the specified class loader.

    +
  • +
  • +

    Java.enumerateClassLoadersSync(): synchronous version of + enumerateClassLoaders() that returns the + class loaders in an array.

    +
  • +
  • +

    Java.enumerateMethods(query): enumerate methods matching query, + specified as "class!method", with globs permitted. May also be suffixed + with / and one or more modifiers:

    + +
      +
    • i: Case-insensitive matching.
    • +
    • s: Include method signatures, so e.g. "putInt" becomes + "putInt(java.lang.String, int): void".
    • +
    • u: User-defined classes only, ignoring system classes.
    • +
    +
  • +
+ +
Java.perform(() => {
+			  const groups = Java.enumerateMethods('*youtube*!on*')
+			  console.log(JSON.stringify(groups, null, 2));
+			});
+ +
[
+			  {
+				"loader": "<instance: java.lang.ClassLoader, $className: dalvik.system.PathClassLoader>",
+				"classes": [
+				  {
+					"name": "com.google.android.apps.youtube.app.watch.nextgenwatch.ui.NextGenWatchLayout",
+					"methods": [
+					  "onAttachedToWindow",
+					  "onDetachedFromWindow",
+					  "onFinishInflate",
+					  "onInterceptTouchEvent",
+					  "onLayout",
+					  "onMeasure",
+					  "onSizeChanged",
+					  "onTouchEvent",
+					  "onViewRemoved"
+					]
+				  },
+				  {
+					"name": "com.google.android.apps.youtube.app.search.suggest.YouTubeSuggestionProvider",
+					"methods": [
+					  "onCreate"
+					]
+				  },
+				  {
+					"name": "com.google.android.libraries.youtube.common.ui.YouTubeButton",
+					"methods": [
+					  "onInitializeAccessibilityNodeInfo"
+					]
+				  },
+				  
+				]
+			  }
+			]
+ +
    +
  • +

    Java.scheduleOnMainThread(fn): run fn on the main thread of the VM.

    +
  • +
  • +

    Java.perform(fn): ensure that the current thread is attached to the VM + and call fn. (This isn’t necessary in callbacks from Java.) + Will defer calling fn if the app’s class loader is not available yet. + Use Java.performNow() if access to the app’s classes is not needed.

    +
  • +
+ +
Java.perform(() => {
+			  const Activity = Java.use('android.app.Activity');
+			  Activity.onResume.implementation = function () {
+				send('onResume() got called! Let\'s call the original implementation');
+				this.onResume();
+			  };
+			});
+ +
    +
  • +

    Java.performNow(fn): ensure that the current thread is attached to the + VM and call fn. (This isn’t necessary in callbacks from Java.)

    +
  • +
  • +

    Java.use(className): dynamically get a JavaScript wrapper for + className that you can instantiate objects from by calling $new() on + it to invoke a constructor. Call $dispose() on an instance to clean it + up explicitly (or wait for the JavaScript object to get garbage-collected, + or script to get unloaded). Static and non-static methods are available, + and you can even replace a method implementation and throw an exception + from it:

    +
  • +
+ +
Java.perform(() => {
+			  const Activity = Java.use('android.app.Activity');
+			  const Exception = Java.use('java.lang.Exception');
+			  Activity.onResume.implementation = function () {
+				throw Exception.$new('Oh noes!');
+			  };
+			});
+ +
+

Uses the app’s class loader by default, but you may customize this by + assigning a different loader instance to Java.classFactory.loader.

+ +

Note that all method wrappers provide a clone(options) API to create a new + method wrapper with custom NativeFunction options.

+
+ +
    +
  • +

    Java.openClassFile(filePath): open the .dex file at filePath, returning + an object with the following methods:

    + +
      +
    • +

      load(): load the contained classes into the VM.

      +
    • +
    • +

      getClassNames(): obtain an array of available class names.

      +
    • +
    +
  • +
  • +

    Java.choose(className, callbacks): enumerate live instances of the + className class by scanning the Java heap, where callbacks is an + object specifying:

    + +
      +
    • +

      onMatch(instance): called with each live instance found with a + ready-to-use instance just as if you would have called + Java.cast() with a raw handle to this particular instance.

      + +

      This function may return the string stop to cancel the enumeration + early.

      +
    • +
    • +

      onComplete(): called when all instances have been enumerated

      +
    • +
    +
  • +
  • +

    Java.retain(obj): duplicates the JavaScript wrapper obj for later use + outside replacement method.

    +
  • +
+ +
Java.perform(() => {
+			  const Activity = Java.use('android.app.Activity');
+			  let lastActivity = null;
+			  Activity.onResume.implementation = function () {
+				lastActivity = Java.retain(this);
+				this.onResume();
+			  };
+			});
+ +
    +
  • Java.cast(handle, klass): create a JavaScript wrapper + given the existing instance at handle of given class klass as returned from + Java.use(). + Such a wrapper also has a class property for getting a wrapper for its + class, and a $className property for getting a string representation of + its class-name.
  • +
+ +
const Activity = Java.use('android.app.Activity');
+			const activity = Java.cast(ptr('0x1234'), Activity);
+ +
    +
  • Java.array(type, elements): creates a Java array with + elements of the specified type, from a JavaScript array elements. The + resulting Java array behaves like a JS array, but can be passed by reference to + Java APIs in order to allow them to modify its contents.
  • +
+ +
const values = Java.array('int', [ 1003, 1005, 1007 ]);
+			
+			const JString = Java.use('java.lang.String');
+			const str = JString.$new(Java.array('byte', [ 0x48, 0x65, 0x69 ]));
+ +
    +
  • +

    Java.isMainThread(): determine whether the caller is running on the main + thread.

    +
  • +
  • +

    Java.registerClass(spec): create a new Java class and return a wrapper for + it, where spec is an object containing:

    + +
      +
    • name: String specifying the name of the class.
    • +
    • superClass: (optional) Super-class. Omit to inherit from + java.lang.Object.
    • +
    • implements: (optional) Array of interfaces implemented by this class.
    • +
    • fields: (optional) Object specifying the name and type of each field + to expose.
    • +
    • methods: (optional) Object specifying methods to implement.
    • +
    +
  • +
+ +
const SomeBaseClass = Java.use('com.example.SomeBaseClass');
+			const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
+			
+			const MyTrustManager = Java.registerClass({
+			  name: 'com.example.MyTrustManager',
+			  implements: [X509TrustManager],
+			  methods: {
+				checkClientTrusted(chain, authType) {
+				},
+				checkServerTrusted(chain, authType) {
+				},
+				getAcceptedIssuers() {
+				  return [];
+				},
+			  }
+			});
+			
+			const MyWeirdTrustManager = Java.registerClass({
+			  name: 'com.example.MyWeirdTrustManager',
+			  superClass: SomeBaseClass,
+			  implements: [X509TrustManager],
+			  fields: {
+				description: 'java.lang.String',
+				limit: 'int',
+			  },
+			  methods: {
+				$init() {
+				  console.log('Constructor called');
+				},
+				checkClientTrusted(chain, authType) {
+				  console.log('checkClientTrusted');
+				},
+				checkServerTrusted: [{
+				  returnType: 'void',
+				  argumentTypes: ['[Ljava.security.cert.X509Certificate;', 'java.lang.String'],
+				  implementation(chain, authType) {
+					console.log('checkServerTrusted A');
+				  }
+				}, {
+				  returnType: 'java.util.List',
+				  argumentTypes: ['[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'java.lang.String'],
+				  implementation(chain, authType, host) {
+					console.log('checkServerTrusted B');
+					return null;
+				  }
+				}],
+				getAcceptedIssuers() {
+				  console.log('getAcceptedIssuers');
+				  return [];
+				},
+			  }
+			});
+ +
    +
  • +

    Java.deoptimizeEverything(): forces the VM to execute everything with + its interpreter. Necessary to prevent optimizations from bypassing method + hooks in some cases, and allows ART’s Instrumentation APIs to be used for + tracing the runtime.

    +
  • +
  • +

    Java.deoptimizeBootImage(): similar to Java.deoptimizeEverything() but + only deoptimizes boot image code. Use with + dalvik.vm.dex2oat-flags --inline-max-code-units=0 for best results.

    +
  • +
  • +

    Java.vm: object with the following methods:

    + +
      +
    • +

      perform(fn): ensures that the current thread is attached to the VM and + calls fn. (This isn’t necessary in callbacks from Java.)

      +
    • +
    • +

      getEnv(): gets a wrapper for the current thread’s JNIEnv. Throws an + exception if the current thread is not attached to the VM.

      +
    • +
    • +

      tryGetEnv(): tries to get a wrapper for the current thread’s JNIEnv. + Returns null if the current thread is not attached to the VM.

      +
    • +
    +
  • +
  • +

    Java.classFactory: the default class factory used to implement e.g. + Java.use(). Uses the application’s main class loader.

    +
  • +
  • +

    Java.ClassFactory: class with the following properties:

    + +
      +
    • +

      get(classLoader): Gets the class factory instance for a given class + loader. The default class factory used behind the scenes only interacts + with the application’s main class loader. Other class loaders can be + discovered through Java.enumerateClassLoaders() and interacted with + through this API.

      +
    • +
    • +

      loader: read-only property providing a wrapper for the class loader + currently being used. For the default class factory this is updated by + the first call to Java.perform().

      +
    • +
    • +

      cacheDir: string containing path to cache directory currently being + used. For the default class factory this is updated by the first call + to Java.perform().

      +
    • +
    • +

      tempFileNaming: object specifying naming convention to use for + temporary files. Defaults to { prefix: 'frida', suffix: 'dat' }.

      +
    • +
    • +

      use(className): like Java.use() but for a specific class loader.

      +
    • +
    • +

      openClassFile(filePath): like Java.openClassFile() + but for a specific class loader.

      +
    • +
    • +

      choose(className, callbacks): like Java.choose() but for a + specific class loader.

      +
    • +
    • +

      retain(obj): like Java.retain() but for a specific class loader.

      +
    • +
    • +

      cast(handle, klass): like Java.cast() but for a specific class + loader.

      +
    • +
    • +

      array(type, elements): like Java.array() but for a specific class + loader.

      +
    • +
    • +

      registerClass(spec): like Java.registerClass() but for a specific + class loader.

      +
    • +
    +
  • +
+ +
+ +

CPU Instruction

+ +

Instruction

+ +
    +
  • +

    Instruction.parse(target): parse the instruction at the target address + in memory, represented by a NativePointer. + Note that on 32-bit ARM this address must have its least significant bit + set to 0 for ARM functions, and 1 for Thumb functions. Frida takes care + of this detail for you if you get the address from a Frida API (for + example Module.getExportByName()).

    + +

    The object returned has the fields:

    + +
      +
    • address: address (EIP) of this instruction, as a NativePointer
    • +
    • next: pointer to the next instruction, so you can parse() it
    • +
    • size: size of this instruction
    • +
    • mnemonic: string representation of instruction mnemonic
    • +
    • opStr: string representation of instruction operands
    • +
    • operands: array of objects describing each operand, each specifying + the type and value, at a minimum, but potentially also + additional properties depending on the architecture
    • +
    • regsRead: array of register names implicitly read by this instruction
    • +
    • regsWritten: array of register names implicitly written to by this + instruction
    • +
    • groups: array of group names that this instruction belongs to
    • +
    • toString(): convert to a human-readable string
    • +
    + +

    For details about operands and groups, please consult the + Capstone documentation for your + architecture.

    +
  • +
+ +

X86Writer

+ +
    +
  • +

    new X86Writer(codeAddress[, { pc: ptr('0x1234') }]): create a new code + writer for generating x86 machine code written directly to memory at + codeAddress, specified as a NativePointer. + The second argument is an optional options object where the initial program + counter may be specified, which is useful when generating code to a scratch + buffer. This is essential when using Memory.patchCode() + on iOS, which may provide you with a temporary location that later gets mapped + into memory at the intended memory location.

    +
  • +
  • +

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    flush(): resolve label references and write pending data to memory. You + should always call this once you’ve finished generating code. It is usually + also desirable to do this between pieces of unrelated code, e.g. when + generating multiple functions in one go.

    +
  • +
  • +

    base: memory location of the first byte of output, as a NativePointer

    +
  • +
  • +

    code: memory location of the next byte of output, as a NativePointer

    +
  • +
  • +

    pc: program counter at the next byte of output, as a NativePointer

    +
  • +
  • +

    offset: current offset as a JavaScript Number

    +
  • +
  • +

    putLabel(id): put a label at the current position, where id is a string + that may be referenced in past and future put*Label() calls

    +
  • +
  • +

    putCallAddressWithArguments(func, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putCallAddressWithAlignedArguments(func, args): like above, but also + ensures that the argument list is aligned on a 16 byte boundary

    +
  • +
  • +

    putCallRegWithArguments(reg, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putCallRegWithAlignedArguments(reg, args): like above, but also + ensures that the argument list is aligned on a 16 byte boundary

    +
  • +
  • +

    putCallRegOffsetPtrWithArguments(reg, offset, args): put code needed for calling + a C function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putCallAddress(address): put a CALL instruction

    +
  • +
  • +

    putCallReg(reg): put a CALL instruction

    +
  • +
  • +

    putCallRegOffsetPtr(reg, offset): put a CALL instruction

    +
  • +
  • +

    putCallIndirect(addr): put a CALL instruction

    +
  • +
  • +

    putCallIndirectLabel(labelId): put a CALL instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putCallNearLabel(labelId): put a CALL instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putLeave(): put a LEAVE instruction

    +
  • +
  • +

    putRet(): put a RET instruction

    +
  • +
  • +

    putRetImm(immValue): put a RET instruction

    +
  • +
  • +

    putJmpAddress(address): put a JMP instruction

    +
  • +
  • +

    putJmpShortLabel(labelId): put a JMP instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putJmpNearLabel(labelId): put a JMP instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putJmpReg(reg): put a JMP instruction

    +
  • +
  • +

    putJmpRegPtr(reg): put a JMP instruction

    +
  • +
  • +

    putJmpRegOffsetPtr(reg, offset): put a JMP instruction

    +
  • +
  • +

    putJmpNearPtr(address): put a JMP instruction

    +
  • +
  • +

    putJccShort(instructionId, target, hint): put a JCC instruction

    +
  • +
  • +

    putJccNear(instructionId, target, hint): put a JCC instruction

    +
  • +
  • +

    putJccShortLabel(instructionId, labelId, hint): put a JCC instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putJccNearLabel(instructionId, labelId, hint): put a JCC instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putAddRegImm(reg, immValue): put an ADD instruction

    +
  • +
  • +

    putAddRegReg(dstReg, srcReg): put an ADD instruction

    +
  • +
  • +

    putAddRegNearPtr(dstReg, srcAddress): put an ADD instruction

    +
  • +
  • +

    putSubRegImm(reg, immValue): put a SUB instruction

    +
  • +
  • +

    putSubRegReg(dstReg, srcReg): put a SUB instruction

    +
  • +
  • +

    putSubRegNearPtr(dstReg, srcAddress): put a SUB instruction

    +
  • +
  • +

    putIncReg(reg): put an INC instruction

    +
  • +
  • +

    putDecReg(reg): put a DEC instruction

    +
  • +
  • +

    putIncRegPtr(target, reg): put an INC instruction

    +
  • +
  • +

    putDecRegPtr(target, reg): put a DEC instruction

    +
  • +
  • +

    putLockXaddRegPtrReg(dstReg, srcReg): put a LOCK XADD instruction

    +
  • +
  • +

    putLockCmpxchgRegPtrReg(dstReg, srcReg): put a LOCK CMPXCHG instruction

    +
  • +
  • +

    putLockIncImm32Ptr(target): put a LOCK INC IMM32 instruction

    +
  • +
  • +

    putLockDecImm32Ptr(target): put a LOCK DEC IMM32 instruction

    +
  • +
  • +

    putAndRegReg(dstReg, srcReg): put an AND instruction

    +
  • +
  • +

    putAndRegU32(reg, immValue): put an AND instruction

    +
  • +
  • +

    putShlRegU8(reg, immValue): put a SHL instruction

    +
  • +
  • +

    putShrRegU8(reg, immValue): put a SHR instruction

    +
  • +
  • +

    putXorRegReg(dstReg, srcReg): put an XOR instruction

    +
  • +
  • +

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    +
  • +
  • +

    putMovRegU32(dstReg, immValue): put a MOV instruction

    +
  • +
  • +

    putMovRegU64(dstReg, immValue): put a MOV instruction

    +
  • +
  • +

    putMovRegAddress(dstReg, address): put a MOV instruction

    +
  • +
  • +

    putMovRegPtrU32(dstReg, immValue): put a MOV instruction

    +
  • +
  • +

    putMovRegOffsetPtrU32(dstReg, dstOffset, immValue): put a MOV instruction

    +
  • +
  • +

    putMovRegPtrReg(dstReg, srcReg): put a MOV instruction

    +
  • +
  • +

    putMovRegOffsetPtrReg(dstReg, dstOffset, srcReg): put a MOV instruction

    +
  • +
  • +

    putMovRegRegPtr(dstReg, srcReg): put a MOV instruction

    +
  • +
  • +

    putMovRegRegOffsetPtr(dstReg, srcReg, srcOffset): put a MOV instruction

    +
  • +
  • +

    putMovRegBaseIndexScaleOffsetPtr(dstReg, baseReg, indexReg, scale, offset): put a MOV instruction

    +
  • +
  • +

    putMovRegNearPtr(dstReg, srcAddress): put a MOV instruction

    +
  • +
  • +

    putMovNearPtrReg(dstAddress, srcReg): put a MOV instruction

    +
  • +
  • +

    putMovFsU32PtrReg(fsOffset, srcReg): put a MOV FS instruction

    +
  • +
  • +

    putMovRegFsU32Ptr(dstReg, fsOffset): put a MOV FS instruction

    +
  • +
  • +

    putMovGsU32PtrReg(fsOffset, srcReg): put a MOV GS instruction

    +
  • +
  • +

    putMovRegGsU32Ptr(dstReg, fsOffset): put a MOV GS instruction

    +
  • +
  • +

    putMovqXmm0EspOffsetPtr(offset): put a MOVQ XMM0 ESP instruction

    +
  • +
  • +

    putMovqEaxOffsetPtrXmm0(offset): put a MOVQ EAX XMM0 instruction

    +
  • +
  • +

    putMovdquXmm0EspOffsetPtr(offset): put a MOVDQU XMM0 ESP instruction

    +
  • +
  • +

    putMovdquEaxOffsetPtrXmm0(offset): put a MOVDQU EAX XMM0 instruction

    +
  • +
  • +

    putLeaRegRegOffset(dstReg, srcReg, srcOffset): put a LEA instruction

    +
  • +
  • +

    putXchgRegRegPtr(leftReg, rightReg): put an XCHG instruction

    +
  • +
  • +

    putPushU32(immValue): put a PUSH instruction

    +
  • +
  • +

    putPushNearPtr(address): put a PUSH instruction

    +
  • +
  • +

    putPushReg(reg): put a PUSH instruction

    +
  • +
  • +

    putPopReg(reg): put a POP instruction

    +
  • +
  • +

    putPushImmPtr(immPtr): put a PUSH instruction

    +
  • +
  • +

    putPushax(): put a PUSHAX instruction

    +
  • +
  • +

    putPopax(): put a POPAX instruction

    +
  • +
  • +

    putPushfx(): put a PUSHFX instruction

    +
  • +
  • +

    putPopfx(): put a POPFX instruction

    +
  • +
  • +

    putTestRegReg(regA, regB): put a TEST instruction

    +
  • +
  • +

    putTestRegU32(reg, immValue): put a TEST instruction

    +
  • +
  • +

    putCmpRegI32(reg, immValue): put a CMP instruction

    +
  • +
  • +

    putCmpRegOffsetPtrReg(regA, offset, regB): put a CMP instruction

    +
  • +
  • +

    putCmpImmPtrImmU32(immPtr, immValue): put a CMP instruction

    +
  • +
  • +

    putCmpRegReg(regA, regB): put a CMP instruction

    +
  • +
  • +

    putClc(): put a CLC instruction

    +
  • +
  • +

    putStc(): put a STC instruction

    +
  • +
  • +

    putCld(): put a CLD instruction

    +
  • +
  • +

    putStd(): put a STD instruction

    +
  • +
  • +

    putCpuid(): put a CPUID instruction

    +
  • +
  • +

    putLfence(): put an LFENCE instruction

    +
  • +
  • +

    putRdtsc(): put an RDTSC instruction

    +
  • +
  • +

    putPause(): put a PAUSE instruction

    +
  • +
  • +

    putNop(): put a NOP instruction

    +
  • +
  • +

    putBreakpoint(): put an OS/architecture-specific breakpoint instruction

    +
  • +
  • +

    putPadding(n): put n guard instruction

    +
  • +
  • +

    putNopPadding(n): put n NOP instructions

    +
  • +
  • +

    putU8(value): put a uint8

    +
  • +
  • +

    putS8(value): put an int8

    +
  • +
  • +

    putBytes(data): put raw data from the provided ArrayBuffer

    +
  • +
+ +

X86Relocator

+ +
    +
  • +

    new X86Relocator(inputCode, output): create a new code relocator for + copying x86 instructions from one memory location to another, taking + care to adjust position-dependent instructions accordingly. + The source address is specified by inputCode, a NativePointer. + The destination is given by output, an X86Writer pointed + at the desired target memory address.

    +
  • +
  • +

    reset(inputCode, output): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    input: latest Instruction read so far. Starts out null + and changes on every call to readOne().

    +
  • +
  • +

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve + reached a branch of any kind, like CALL, JMP, BL, RET.

    +
  • +
  • +

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve + reached JMP/B/RET, an instruction after which there may or may not be valid + code.

    +
  • +
  • +

    readOne(): read the next instruction into the relocator’s internal buffer + and return the number of bytes read so far, including previous calls. + You may keep calling this method to keep buffering, or immediately call + either writeOne() or skipOne(). + Or, you can buffer up until the desired point and then call writeAll(). + Returns zero when end-of-input is reached, which means the eoi property is + now true.

    +
  • +
  • +

    peekNextWriteInsn(): peek at the next Instruction to be + written or skipped

    +
  • +
  • +

    peekNextWriteSource(): peek at the address of the next instruction to be + written or skipped

    +
  • +
  • +

    skipOne(): skip the instruction that would have been written next

    +
  • +
  • +

    skipOneNoLabel(): skip the instruction that would have been written next, + but without a label for internal use. This breaks relocation of branches to + locations inside the relocated range, and is an optimization for use-cases + where all branches are rewritten (e.g. Frida’s Stalker).

    +
  • +
  • +

    writeOne(): write the next buffered instruction

    +
  • +
  • +

    writeOneNoLabel(): write the next buffered instruction, but without a + label for internal use. This breaks relocation of branches to locations + inside the relocated range, and is an optimization for use-cases where all + branches are rewritten (e.g. Frida’s Stalker).

    +
  • +
  • +

    writeAll(): write all buffered instructions

    +
  • +
+ +

x86 enum types

+ +
    +
  • Register: xax xcx xdx xbx xsp xbp xsi xdi eax ecx edx + ebx esp ebp esi edi rax rcx rdx rbx rsp rbp rsi + rdi r8 r9 r10 r11 r12 r13 r14 r15 r8d r9d r10d + r11d r12d r13d r14d r15d xip eip rip
  • +
  • InstructionId: jo jno jb jae je jne jbe ja js jns jp + jnp jl jge jle jg jcxz jecxz jrcxz
  • +
  • BranchHint: no-hint likely unlikely
  • +
  • PointerTarget: byte dword qword
  • +
+ +

ArmWriter

+ +
    +
  • +

    new ArmWriter(codeAddress[, { pc: ptr('0x1234') }]): create a new code + writer for generating ARM machine code written directly to memory at + codeAddress, specified as a NativePointer. + The second argument is an optional options object where the initial program + counter may be specified, which is useful when generating code to a scratch + buffer. This is essential when using Memory.patchCode() + on iOS, which may provide you with a temporary location that later gets mapped + into memory at the intended memory location.

    +
  • +
  • +

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    flush(): resolve label references and write pending data to memory. You + should always call this once you’ve finished generating code. It is usually + also desirable to do this between pieces of unrelated code, e.g. when + generating multiple functions in one go.

    +
  • +
  • +

    base: memory location of the first byte of output, as a NativePointer

    +
  • +
  • +

    code: memory location of the next byte of output, as a NativePointer

    +
  • +
  • +

    pc: program counter at the next byte of output, as a NativePointer

    +
  • +
  • +

    offset: current offset as a JavaScript Number

    +
  • +
  • +

    skip(nBytes): skip nBytes

    +
  • +
  • +

    putLabel(id): put a label at the current position, where id is a string + that may be referenced in past and future put*Label() calls

    +
  • +
  • +

    putCallAddressWithArguments(func, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putBranchAddress(address): put code needed for branching/jumping to the + given address

    +
  • +
  • +

    canBranchDirectlyBetween(from, to): determine whether a direct branch is + possible between the two given memory locations

    +
  • +
  • +

    putBImm(target): put a B instruction

    +
  • +
  • +

    putBCondImm(cc, target): put a B COND instruction

    +
  • +
  • +

    putBLabel(labelId): put a B instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBCondLabel(cc, labelId): put a B COND instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBlImm(target): put a BL instruction

    +
  • +
  • +

    putBlxImm(target): put a BLX instruction

    +
  • +
  • +

    putBlLabel(labelId): put a BL instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBxReg(reg): put a BX instruction

    +
  • +
  • +

    putBlxReg(reg): put a BLX instruction

    +
  • +
  • +

    putRet(): put a RET instruction

    +
  • +
  • +

    putLdrRegAddress(reg, address): put an LDR instruction

    +
  • +
  • +

    putLdrRegU32(reg, val): put an LDR instruction

    +
  • +
  • +

    putLdrRegRegOffset(dstReg, srcReg, srcOffset): put an LDR instruction

    +
  • +
  • +

    putLdrCondRegRegOffset(cc, dstReg, srcReg, srcOffset): put an LDR COND instruction

    +
  • +
  • +

    putLdmiaRegMask(reg, mask): put an LDMIA MASK instruction

    +
  • +
  • +

    putStrRegRegOffset(srcReg, dstReg, dstOffset): put a STR instruction

    +
  • +
  • +

    putStrCondRegRegOffset(cc, srcReg, dstReg, dstOffset): put a STR COND instruction

    +
  • +
  • +

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    +
  • +
  • +

    putMovRegRegShift(dstReg, srcReg, shift, shiftValue): put a MOV SHIFT instruction

    +
  • +
  • +

    putMovRegCpsr(reg): put a MOV CPSR instruction

    +
  • +
  • +

    putMovCpsrReg(reg): put a MOV CPSR instruction

    +
  • +
  • +

    putAddRegU16(dstReg, val): put an ADD U16 instruction

    +
  • +
  • +

    putAddRegU32(dstReg, val): put an ADD instruction

    +
  • +
  • +

    putAddRegRegImm(dstReg, srcReg, immVal): put an ADD instruction

    +
  • +
  • +

    putAddRegRegReg(dstReg, srcReg1, srcReg2): put an ADD instruction

    +
  • +
  • +

    putAddRegRegRegShift(dstReg, srcReg1, srcReg2, shift, shiftValue): put an ADD SHIFT instruction

    +
  • +
  • +

    putSubRegU16(dstReg, val): put a SUB U16 instruction

    +
  • +
  • +

    putSubRegU32(dstReg, val): put a SUB instruction

    +
  • +
  • +

    putSubRegRegImm(dstReg, srcReg, immVal): put a SUB instruction

    +
  • +
  • +

    putSubRegRegReg(dstReg, srcReg1, srcReg2): put a SUB instruction

    +
  • +
  • +

    putAndsRegRegImm(dstReg, srcReg, immVal): put an ANDS instruction

    +
  • +
  • +

    putCmpRegImm(dstReg, immVal): put a CMP instruction

    +
  • +
  • +

    putNop(): put a NOP instruction

    +
  • +
  • +

    putBreakpoint(): put an OS/architecture-specific breakpoint instruction

    +
  • +
  • +

    putBrkImm(imm): put a BRK instruction

    +
  • +
  • +

    putInstruction(insn): put a raw instruction as a JavaScript Number

    +
  • +
  • +

    putBytes(data): put raw data from the provided ArrayBuffer

    +
  • +
+ +

ArmRelocator

+ +
    +
  • +

    new ArmRelocator(inputCode, output): create a new code relocator for + copying ARM instructions from one memory location to another, taking + care to adjust position-dependent instructions accordingly. + The source address is specified by inputCode, a NativePointer. + The destination is given by output, an ArmWriter pointed + at the desired target memory address.

    +
  • +
  • +

    reset(inputCode, output): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    input: latest Instruction read so far. Starts out null + and changes on every call to readOne().

    +
  • +
  • +

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve + reached a branch of any kind, like CALL, JMP, BL, RET.

    +
  • +
  • +

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve + reached JMP/B/RET, an instruction after which there may or may not be valid + code.

    +
  • +
  • +

    readOne(): read the next instruction into the relocator’s internal buffer + and return the number of bytes read so far, including previous calls. + You may keep calling this method to keep buffering, or immediately call + either writeOne() or skipOne(). + Or, you can buffer up until the desired point and then call writeAll(). + Returns zero when end-of-input is reached, which means the eoi property is + now true.

    +
  • +
  • +

    peekNextWriteInsn(): peek at the next Instruction to be + written or skipped

    +
  • +
  • +

    peekNextWriteSource(): peek at the address of the next instruction to be + written or skipped

    +
  • +
  • +

    skipOne(): skip the instruction that would have been written next

    +
  • +
  • +

    writeOne(): write the next buffered instruction

    +
  • +
  • +

    writeAll(): write all buffered instructions

    +
  • +
+ +

ThumbWriter

+ +
    +
  • +

    new ThumbWriter(codeAddress[, { pc: ptr('0x1234') }]): create a new code + writer for generating ARM machine code written directly to memory at + codeAddress, specified as a NativePointer. + The second argument is an optional options object where the initial program + counter may be specified, which is useful when generating code to a scratch + buffer. This is essential when using Memory.patchCode() + on iOS, which may provide you with a temporary location that later gets mapped + into memory at the intended memory location.

    +
  • +
  • +

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    flush(): resolve label references and write pending data to memory. You + should always call this once you’ve finished generating code. It is usually + also desirable to do this between pieces of unrelated code, e.g. when + generating multiple functions in one go.

    +
  • +
  • +

    base: memory location of the first byte of output, as a NativePointer

    +
  • +
  • +

    code: memory location of the next byte of output, as a NativePointer

    +
  • +
  • +

    pc: program counter at the next byte of output, as a NativePointer

    +
  • +
  • +

    offset: current offset as a JavaScript Number

    +
  • +
  • +

    skip(nBytes): skip nBytes

    +
  • +
  • +

    putLabel(id): put a label at the current position, where id is a string + that may be referenced in past and future put*Label() calls

    +
  • +
  • +

    commitLabel(id): commit the first pending reference to the given label, + returning true on success. Returns false if the given label hasn’t been + defined yet, or there are no more pending references to it.

    +
  • +
  • +

    putCallAddressWithArguments(func, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putCallRegWithArguments(reg, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putBImm(target): put a B instruction

    +
  • +
  • +

    putBLabel(labelId): put a B instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBLabelWide(labelId): put a B WIDE instruction

    +
  • +
  • +

    putBxReg(reg): put a BX instruction

    +
  • +
  • +

    putBlImm(target): put a BL instruction

    +
  • +
  • +

    putBlLabel(labelId): put a BL instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBlxImm(target): put a BLX instruction

    +
  • +
  • +

    putBlxReg(reg): put a BLX instruction

    +
  • +
  • +

    putCmpRegImm(reg, immValue): put a CMP instruction

    +
  • +
  • +

    putBeqLabel(labelId): put a BEQ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBneLabel(labelId): put a BNE instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBCondLabel(cc, labelId): put a B COND instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBCondLabelWide(cc, labelId): put a B COND WIDE instruction

    +
  • +
  • +

    putCbzRegLabel(reg, labelId): put a CBZ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putCbnzRegLabel(reg, labelId): put a CBNZ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putPushRegs(regs): put a PUSH instruction with the specified registers, + specified as a JavaScript array where each element is a string specifying + the register name.

    +
  • +
  • +

    putPopRegs(regs): put a POP instruction with the specified registers, + specified as a JavaScript array where each element is a string specifying + the register name.

    +
  • +
  • +

    putLdrRegAddress(reg, address): put an LDR instruction

    +
  • +
  • +

    putLdrRegU32(reg, val): put an LDR instruction

    +
  • +
  • +

    putLdrRegReg(dstReg, srcReg): put an LDR instruction

    +
  • +
  • +

    putLdrRegRegOffset(dstReg, srcReg, srcOffset): put an LDR instruction

    +
  • +
  • +

    putLdrbRegReg(dstReg, srcReg): put an LDRB instruction

    +
  • +
  • +

    putVldrRegRegOffset(dstReg, srcReg, srcOffset): put a VLDR instruction

    +
  • +
  • +

    putLdmiaRegMask(reg, mask): put an LDMIA MASK instruction

    +
  • +
  • +

    putStrRegReg(srcReg, dstReg): put a STR instruction

    +
  • +
  • +

    putStrRegRegOffset(srcReg, dstReg, dstOffset): put a STR instruction

    +
  • +
  • +

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    +
  • +
  • +

    putMovRegU8(dstReg, immValue): put a MOV instruction

    +
  • +
  • +

    putMovRegCpsr(reg): put a MOV CPSR instruction

    +
  • +
  • +

    putMovCpsrReg(reg): put a MOV CPSR instruction

    +
  • +
  • +

    putAddRegImm(dstReg, immValue): put an ADD instruction

    +
  • +
  • +

    putAddRegReg(dstReg, srcReg): put an ADD instruction

    +
  • +
  • +

    putAddRegRegReg(dstReg, leftReg, rightReg): put an ADD instruction

    +
  • +
  • +

    putAddRegRegImm(dstReg, leftReg, rightValue): put an ADD instruction

    +
  • +
  • +

    putSubRegImm(dstReg, immValue): put a SUB instruction

    +
  • +
  • +

    putSubRegReg(dstReg, srcReg): put a SUB instruction

    +
  • +
  • +

    putSubRegRegReg(dstReg, leftReg, rightReg): put a SUB instruction

    +
  • +
  • +

    putSubRegRegImm(dstReg, leftReg, rightValue): put a SUB instruction

    +
  • +
  • +

    putAndRegRegImm(dstReg, leftReg, rightValue): put an AND instruction

    +
  • +
  • +

    putLslsRegRegImm(dstReg, leftReg, rightValue): put a LSLS instruction

    +
  • +
  • +

    putLsrsRegRegImm(dstReg, leftReg, rightValue): put a LSRS instruction

    +
  • +
  • +

    putMrsRegReg(dstReg, srcReg): put a MRS instruction

    +
  • +
  • +

    putMsrRegReg(dstReg, srcReg): put a MSR instruction

    +
  • +
  • +

    putNop(): put a NOP instruction

    +
  • +
  • +

    putBkptImm(imm): put a BKPT instruction

    +
  • +
  • +

    putBreakpoint(): put an OS/architecture-specific breakpoint instruction

    +
  • +
  • +

    putInstruction(insn): put a raw instruction as a JavaScript Number

    +
  • +
  • +

    putInstructionWide(upper, lower): put a raw Thumb-2 instruction from + two JavaScript Number values

    +
  • +
  • +

    putBytes(data): put raw data from the provided ArrayBuffer

    +
  • +
+ +

ThumbRelocator

+ +
    +
  • +

    new ThumbRelocator(inputCode, output): create a new code relocator for + copying ARM instructions from one memory location to another, taking + care to adjust position-dependent instructions accordingly. + The source address is specified by inputCode, a NativePointer. + The destination is given by output, a ThumbWriter pointed + at the desired target memory address.

    +
  • +
  • +

    reset(inputCode, output): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    input: latest Instruction read so far. Starts out null + and changes on every call to readOne().

    +
  • +
  • +

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve + reached a branch of any kind, like CALL, JMP, BL, RET.

    +
  • +
  • +

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve + reached JMP/B/RET, an instruction after which there may or may not be valid + code.

    +
  • +
  • +

    readOne(): read the next instruction into the relocator’s internal buffer + and return the number of bytes read so far, including previous calls. + You may keep calling this method to keep buffering, or immediately call + either writeOne() or skipOne(). + Or, you can buffer up until the desired point and then call writeAll(). + Returns zero when end-of-input is reached, which means the eoi property is + now true.

    +
  • +
  • +

    peekNextWriteInsn(): peek at the next Instruction to be + written or skipped

    +
  • +
  • +

    peekNextWriteSource(): peek at the address of the next instruction to be + written or skipped

    +
  • +
  • +

    skipOne(): skip the instruction that would have been written next

    +
  • +
  • +

    writeOne(): write the next buffered instruction

    +
  • +
  • +

    copyOne(): copy out the next buffered instruction without advancing the + output cursor, allowing the same instruction to be written out multiple + times

    +
  • +
  • +

    writeAll(): write all buffered instructions

    +
  • +
+ +

ARM enum types

+ +
    +
  • Register: r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 + r12 r13 r14 r15 sp lr sb sl fp ip pc
  • +
  • SystemRegister: apsr-nzcvq
  • +
  • ConditionCode: eq ne hs lo mi pl vs vc hi ls ge lt + gt le al
  • +
  • Shifter: asr lsl lsr ror rrx asr-reg lsl-reg lsr-reg + ror-reg rrx-reg
  • +
+ +

Arm64Writer

+ +
    +
  • +

    new Arm64Writer(codeAddress[, { pc: ptr('0x1234') }]): create a new code + writer for generating AArch64 machine code written directly to memory at + codeAddress, specified as a NativePointer. + The second argument is an optional options object where the initial program + counter may be specified, which is useful when generating code to a scratch + buffer. This is essential when using Memory.patchCode() + on iOS, which may provide you with a temporary location that later gets mapped + into memory at the intended memory location.

    +
  • +
  • +

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    flush(): resolve label references and write pending data to memory. You + should always call this once you’ve finished generating code. It is usually + also desirable to do this between pieces of unrelated code, e.g. when + generating multiple functions in one go.

    +
  • +
  • +

    base: memory location of the first byte of output, as a NativePointer

    +
  • +
  • +

    code: memory location of the next byte of output, as a NativePointer

    +
  • +
  • +

    pc: program counter at the next byte of output, as a NativePointer

    +
  • +
  • +

    offset: current offset as a JavaScript Number

    +
  • +
  • +

    skip(nBytes): skip nBytes

    +
  • +
  • +

    putLabel(id): put a label at the current position, where id is a string + that may be referenced in past and future put*Label() calls

    +
  • +
  • +

    putCallAddressWithArguments(func, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putCallRegWithArguments(reg, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putBranchAddress(address): put code needed for branching/jumping to the + given address

    +
  • +
  • +

    canBranchDirectlyBetween(from, to): determine whether a direct branch is + possible between the two given memory locations

    +
  • +
  • +

    putBImm(address): put a B instruction

    +
  • +
  • +

    putBLabel(labelId): put a B instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBCondLabel(cc, labelId): put a B COND instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBlImm(address): put a BL instruction

    +
  • +
  • +

    putBlLabel(labelId): put a BL instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putBrReg(reg): put a BR instruction

    +
  • +
  • +

    putBrRegNoAuth(reg): put a BR instruction expecting a raw pointer + without any authentication bits

    +
  • +
  • +

    putBlrReg(reg): put a BLR instruction

    +
  • +
  • +

    putBlrRegNoAuth(reg): put a BLR instruction expecting a raw pointer + without any authentication bits

    +
  • +
  • +

    putRet(): put a RET instruction

    +
  • +
  • +

    putCbzRegLabel(reg, labelId): put a CBZ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putCbnzRegLabel(reg, labelId): put a CBNZ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putTbzRegImmLabel(reg, bit, labelId): put a TBZ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putTbnzRegImmLabel(reg, bit, labelId): put a TBNZ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putPushRegReg(regA, regB): put a PUSH instruction

    +
  • +
  • +

    putPopRegReg(regA, regB): put a POP instruction

    +
  • +
  • +

    putPushAllXRegisters(): put code needed for pushing all X registers on the stack

    +
  • +
  • +

    putPopAllXRegisters(): put code needed for popping all X registers off the stack

    +
  • +
  • +

    putPushAllQRegisters(): put code needed for pushing all Q registers on the stack

    +
  • +
  • +

    putPopAllQRegisters(): put code needed for popping all Q registers off the stack

    +
  • +
  • +

    putLdrRegAddress(reg, address): put an LDR instruction

    +
  • +
  • +

    putLdrRegU64(reg, val): put an LDR instruction

    +
  • +
  • +

    putLdrRegRef(reg): put an LDR instruction with a dangling data reference, + returning an opaque ref value that should be passed to putLdrRegValue() + at the desired location

    +
  • +
  • +

    putLdrRegValue(ref, value): put the value and update the LDR instruction + from a previous putLdrRegRef()

    +
  • +
  • +

    putLdrRegRegOffset(dstReg, srcReg, srcOffset): put an LDR instruction

    +
  • +
  • +

    putLdrswRegRegOffset(dstReg, srcReg, srcOffset): put an LDRSW instruction

    +
  • +
  • +

    putAdrpRegAddress(reg, address): put an ADRP instruction

    +
  • +
  • +

    putStrRegRegOffset(srcReg, dstReg, dstOffset): put a STR instruction

    +
  • +
  • +

    putLdpRegRegRegOffset(regA, regB, regSrc, srcOffset, mode): put an LDP instruction

    +
  • +
  • +

    putStpRegRegRegOffset(regA, regB, regDst, dstOffset, mode): put a STP instruction

    +
  • +
  • +

    putMovRegReg(dstReg, srcReg): put a MOV instruction

    +
  • +
  • +

    putUxtwRegReg(dstReg, srcReg): put an UXTW instruction

    +
  • +
  • +

    putAddRegRegImm(dstReg, leftReg, rightValue): put an ADD instruction

    +
  • +
  • +

    putAddRegRegReg(dstReg, leftReg, rightReg): put an ADD instruction

    +
  • +
  • +

    putSubRegRegImm(dstReg, leftReg, rightValue): put a SUB instruction

    +
  • +
  • +

    putSubRegRegReg(dstReg, leftReg, rightReg): put a SUB instruction

    +
  • +
  • +

    putAndRegRegImm(dstReg, leftReg, rightValue): put an AND instruction

    +
  • +
  • +

    putTstRegImm(reg, immValue): put a TST instruction

    +
  • +
  • +

    putCmpRegReg(regA, regB): put a CMP instruction

    +
  • +
  • +

    putXpaciReg(reg): put an XPACI instruction

    +
  • +
  • +

    putNop(): put a NOP instruction

    +
  • +
  • +

    putBrkImm(imm): put a BRK instruction

    +
  • +
  • +

    putInstruction(insn): put a raw instruction as a JavaScript Number

    +
  • +
  • +

    putBytes(data): put raw data from the provided ArrayBuffer

    +
  • +
  • +

    sign(value): sign the given pointer value

    +
  • +
+ +

Arm64Relocator

+ +
    +
  • +

    new Arm64Relocator(inputCode, output): create a new code relocator for + copying AArch64 instructions from one memory location to another, taking + care to adjust position-dependent instructions accordingly. + The source address is specified by inputCode, a NativePointer. + The destination is given by output, an Arm64Writer pointed + at the desired target memory address.

    +
  • +
  • +

    reset(inputCode, output): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    input: latest Instruction read so far. Starts out null + and changes on every call to readOne().

    +
  • +
  • +

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve + reached a branch of any kind, like CALL, JMP, BL, RET.

    +
  • +
  • +

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve + reached JMP/B/RET, an instruction after which there may or may not be valid + code.

    +
  • +
  • +

    readOne(): read the next instruction into the relocator’s internal buffer + and return the number of bytes read so far, including previous calls. + You may keep calling this method to keep buffering, or immediately call + either writeOne() or skipOne(). + Or, you can buffer up until the desired point and then call writeAll(). + Returns zero when end-of-input is reached, which means the eoi property is + now true.

    +
  • +
  • +

    peekNextWriteInsn(): peek at the next Instruction to be + written or skipped

    +
  • +
  • +

    peekNextWriteSource(): peek at the address of the next instruction to be + written or skipped

    +
  • +
  • +

    skipOne(): skip the instruction that would have been written next

    +
  • +
  • +

    writeOne(): write the next buffered instruction

    +
  • +
  • +

    writeAll(): write all buffered instructions

    +
  • +
+ +

AArch64 enum types

+ +
    +
  • Register: x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 + x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 + x24 x25 x26 x27 x28 x29 x30 w0 w1 w2 w3 w4 w5 + w6 w7 w8 w9 w10 w11 w12 w13 w14 w15 w16 w17 w18 + w19 w20 w21 w22 w23 w24 w25 w26 w27 w28 w29 w30 + sp lr fp wsp wzr xzr nzcv ip0 ip1 s0 s1 s2 s3 + s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 + s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 + s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 + d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 + d23 d24 d25 d26 d27 d28 d29 d30 d31 q0 q1 q2 q3 + q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 q16 + q17 q18 q19 q20 q21 q22 q23 q24 q25 q26 q27 q28 + q29 q30 q31
  • +
  • ConditionCode: eq ne hs lo mi pl vs vc hi ls ge lt + gt le al nv
  • +
  • IndexMode: post-adjust signed-offset pre-adjust
  • +
+ +

MipsWriter

+ +
    +
  • +

    new MipsWriter(codeAddress[, { pc: ptr('0x1234') }]): create a new code + writer for generating MIPS machine code written directly to memory at + codeAddress, specified as a NativePointer. + The second argument is an optional options object where the initial program + counter may be specified, which is useful when generating code to a scratch + buffer. This is essential when using Memory.patchCode() + on iOS, which may provide you with a temporary location that later gets mapped + into memory at the intended memory location.

    +
  • +
  • +

    reset(codeAddress[, { pc: ptr('0x1234') }]): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    flush(): resolve label references and write pending data to memory. You + should always call this once you’ve finished generating code. It is usually + also desirable to do this between pieces of unrelated code, e.g. when + generating multiple functions in one go.

    +
  • +
  • +

    base: memory location of the first byte of output, as a NativePointer

    +
  • +
  • +

    code: memory location of the next byte of output, as a NativePointer

    +
  • +
  • +

    pc: program counter at the next byte of output, as a NativePointer

    +
  • +
  • +

    offset: current offset as a JavaScript Number

    +
  • +
  • +

    skip(nBytes): skip nBytes

    +
  • +
  • +

    putLabel(id): put a label at the current position, where id is a string + that may be referenced in past and future put*Label() calls

    +
  • +
  • +

    putCallAddressWithArguments(func, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putCallRegWithArguments(reg, args): put code needed for calling a C + function with the specified args, specified as a JavaScript array where + each element is either a string specifying the register, or a Number or + NativePointer specifying the immediate value.

    +
  • +
  • +

    putJAddress(address): put a J instruction

    +
  • +
  • +

    putJAddressWithoutNop(address): put a J WITHOUT NOP instruction

    +
  • +
  • +

    putJLabel(labelId): put a J instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putJrReg(reg): put a JR instruction

    +
  • +
  • +

    putJalAddress(address): put a JAL instruction

    +
  • +
  • +

    putJalrReg(reg): put a JALR instruction

    +
  • +
  • +

    putBOffset(offset): put a B instruction

    +
  • +
  • +

    putBeqRegRegLabel(rightReg, leftReg, labelId): put a BEQ instruction + referencing labelId, defined by a past or future putLabel()

    +
  • +
  • +

    putRet(): put a RET instruction

    +
  • +
  • +

    putLaRegAddress(reg, address): put a LA instruction

    +
  • +
  • +

    putLuiRegImm(reg, imm): put a LUI instruction

    +
  • +
  • +

    putDsllRegReg(dstReg, srcReg, amount): put a DSLL instruction

    +
  • +
  • +

    putOriRegRegImm(rt, rs, imm): put an ORI instruction

    +
  • +
  • +

    putLdRegRegOffset(dstReg, srcReg, srcOffset): put an LD instruction

    +
  • +
  • +

    putLwRegRegOffset(dstReg, srcReg, srcOffset): put a LW instruction

    +
  • +
  • +

    putSwRegRegOffset(srcReg, dstReg, dstOffset): put a SW instruction

    +
  • +
  • +

    putMoveRegReg(dstReg, srcReg): put a MOVE instruction

    +
  • +
  • +

    putAdduRegRegReg(dstReg, leftReg, rightReg): put an ADDU instruction

    +
  • +
  • +

    putAddiRegRegImm(dstReg, leftReg, imm): put an ADDI instruction

    +
  • +
  • +

    putAddiRegImm(dstReg, imm): put an ADDI instruction

    +
  • +
  • +

    putSubRegRegImm(dstReg, leftReg, imm): put a SUB instruction

    +
  • +
  • +

    putPushReg(reg): put a PUSH instruction

    +
  • +
  • +

    putPopReg(reg): put a POP instruction

    +
  • +
  • +

    putMfhiReg(reg): put a MFHI instruction

    +
  • +
  • +

    putMfloReg(reg): put a MFLO instruction

    +
  • +
  • +

    putMthiReg(reg): put a MTHI instruction

    +
  • +
  • +

    putMtloReg(reg): put a MTLO instruction

    +
  • +
  • +

    putNop(): put a NOP instruction

    +
  • +
  • +

    putBreak(): put a BREAK instruction

    +
  • +
  • +

    putPrologueTrampoline(reg, address): put a minimal sized trampoline for + vectoring to the given address

    +
  • +
  • +

    putInstruction(insn): put a raw instruction as a JavaScript Number

    +
  • +
  • +

    putBytes(data): put raw data from the provided ArrayBuffer

    +
  • +
+ +

MipsRelocator

+ +
    +
  • +

    new MipsRelocator(inputCode, output): create a new code relocator for + copying MIPS instructions from one memory location to another, taking + care to adjust position-dependent instructions accordingly. + The source address is specified by inputCode, a NativePointer. + The destination is given by output, a MipsWriter pointed + at the desired target memory address.

    +
  • +
  • +

    reset(inputCode, output): recycle instance

    +
  • +
  • +

    dispose(): eagerly clean up memory

    +
  • +
  • +

    input: latest Instruction read so far. Starts out null + and changes on every call to readOne().

    +
  • +
  • +

    eob: boolean indicating whether end-of-block has been reached, i.e. we’ve + reached a branch of any kind, like CALL, JMP, BL, RET.

    +
  • +
  • +

    eoi: boolean indicating whether end-of-input has been reached, e.g. we’ve + reached JMP/B/RET, an instruction after which there may or may not be valid + code.

    +
  • +
  • +

    readOne(): read the next instruction into the relocator’s internal buffer + and return the number of bytes read so far, including previous calls. + You may keep calling this method to keep buffering, or immediately call + either writeOne() or skipOne(). + Or, you can buffer up until the desired point and then call writeAll(). + Returns zero when end-of-input is reached, which means the eoi property is + now true.

    +
  • +
  • +

    peekNextWriteInsn(): peek at the next Instruction to be + written or skipped

    +
  • +
  • +

    peekNextWriteSource(): peek at the address of the next instruction to be + written or skipped

    +
  • +
  • +

    skipOne(): skip the instruction that would have been written next

    +
  • +
  • +

    writeOne(): write the next buffered instruction

    +
  • +
  • +

    writeAll(): write all buffered instructions

    +
  • +
+ +

MIPS enum types

+ +
    +
  • Register: v0 v1 a0 a1 a2 a3 t0 t1 t2 t3 t4 t5 t6 + t7 s0 s1 s2 s3 s4 s5 s6 s7 t8 t9 k0 k1 gp sp + fp s8 ra hi lo zero at 0 1 2 3 4 5 6 7 8 + 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30 31
  • +
+ +
+ +

Others

+ +

Console

+ +
    +
  • +

    console.log(line), console.warn(line), console.error(line): + write line to the console of your Frida-based application. The exact + behavior depends on where frida-core + is integrated. + For example, this output goes to stdout or stderr when using Frida + through frida-python, + qDebug when using + frida-qml, etc.

    + +

    Arguments that are ArrayBuffer objects will be substituted by + the result of hexdump() with default options.

    +
  • +
+ +

Hexdump

+ +
    +
  • +

    hexdump(target[, options]): generate a hexdump from the provided + ArrayBuffer or NativePointer target, + optionally with options for customizing the output.

    + +

    For example:

    +
  • +
+ +
const libc = Module.findBaseAddress('libc.so');
+			console.log(hexdump(libc, {
+			  offset: 0,
+			  length: 64,
+			  header: true,
+			  ansi: true
+			}));
+ +
           0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
+			00000000  7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  .ELF............
+			00000010  03 00 28 00 01 00 00 00 00 00 00 00 34 00 00 00  ..(.........4...
+			00000020  34 a8 04 00 00 00 00 05 34 00 20 00 08 00 28 00  4.......4. ...(.
+			00000030  1e 00 1d 00 06 00 00 00 34 00 00 00 34 00 00 00  ........4...4...
+ +

Shorthand

+ + + +

Communication between host and injected process

+ +
    +
  • +

    recv([type, ]callback): request callback to be called on the next + message received from your Frida-based application. Optionally type may + be specified to only receive a message where the type field is set to + type.

    + +

    This will only give you one message, so you need to call recv() again + to receive the next one.

    +
  • +
  • +

    send(message[, data]): send the JavaScript object message to your + Frida-based application (it must be serializable to JSON). If you also have + some raw binary data that you’d like to send along with it, e.g. you dumped + some memory using NativePointer#readByteArray, + then you may pass this through the optional data argument. This requires it to + either be an ArrayBuffer or an array of integers between + 0 and 255.

    + +
    +
    Performance considerations
    +

    + While send() is asynchronous, the total overhead of sending a single + message is not optimized for high frequencies, so that means Frida leaves + it up to you to batch multiple values into a single send()-call, + based on whether low delay or high throughput is desired. +

    +
    +
  • +
  • +

    rpc.exports: empty object that you can either replace or insert into to + expose an RPC-style API to your application. The key specifies the method + name and the value is your exported function. This function may either + return a plain value for returning that to the caller immediately, or a + Promise for returning asynchronously.

    +
  • +
+ +
+

For example:

+
+ +
rpc.exports = {
+			  add(a, b) {
+				return a + b;
+			  },
+			  sub(a, b) {
+				return new Promise(resolve => {
+				  setTimeout(() => {
+					resolve(a - b);
+				  }, 100);
+				});
+			  }
+			};
+ +
+

From an application using the Node.js bindings this API would be consumed + like this:

+
+ +
const frida = require('frida');
+			const fs = require('fs');
+			const path = require('path');
+			const util = require('util');
+			
+			const readFile = util.promisify(fs.readFile);
+			
+			let session, script;
+			async function run() {
+			  const source = await readFile(path.join(__dirname, '_agent.js'), 'utf8');
+			  session = await frida.attach('iTunes');
+			  script = await session.createScript(source);
+			  script.message.connect(onMessage);
+			  await script.load();
+			  console.log(await script.exports.add(2, 3));
+			  console.log(await script.exports.sub(5, 3));
+			}
+			
+			run().catch(onError);
+			
+			function onError(error) {
+			  console.error(error.stack);
+			}
+			
+			function onMessage(message, data) {
+			  if (message.type === 'send') {
+				console.log(message.payload);
+			  } else if (message.type === 'error') {
+				console.error(message.stack);
+			  }
+			}
+ +
+

The Python version would be very similar:

+
+ +
import codecs
+			import frida
+			
+			def on_message(message, data):
+				if message['type'] == 'send':
+					print(message['payload'])
+				elif message['type'] == 'error':
+					print(message['stack'])
+			
+			session = frida.attach('iTunes')
+			with codecs.open('./agent.js', 'r', 'utf-8') as f:
+				source = f.read()
+			script = session.create_script(source)
+			script.on('message', on_message)
+			script.load()
+			print(script.exports.add(2, 3))
+			print(script.exports.sub(5, 3))
+			session.detach()
+ +

In the example above we used script.on('message', on_message) to monitor for + any messages from the injected process, JavaScript side. There are other + notifications that you can watch for as well on both the script and session. + If you want to be notified when the target process exits, use + session.on('detached', your_function).

+ +

Timing events

+ +
    +
  • +

    setTimeout(func, delay[, ...parameters]): call func after delay + milliseconds, optionally passing it one or more parameters. + Returns an id that can be passed to clearTimeout to cancel it.

    +
  • +
  • +

    clearTimeout(id): cancel id returned by call to setTimeout.

    +
  • +
  • +

    setInterval(func, delay[, ...parameters]): call func every delay + milliseconds, optionally passing it one or more parameters. + Returns an id that can be passed to clearInterval to cancel it.

    +
  • +
  • +

    clearInterval(id): cancel id returned by call to setInterval.

    +
  • +
  • +

    setImmediate(func[, ...parameters]): schedules func to be called on + Frida’s JavaScript thread as soon as possible, optionally passing it one + or more parameters. + Returns an id that can be passed to clearImmediate to cancel it.

    +
  • +
  • +

    clearImmediate(id): cancel id returned by call to setImmediate.

    +
  • +
+ +

Garbage collection

+ +
    +
  • gc(): force garbage collection. Useful for testing, especially logic + involving Script.bindWeak().
  • +
+
diff --git a/Fermion/pages/index.html b/Fermion/pages/index.html index 52e2da1..f3e3d52 100644 --- a/Fermion/pages/index.html +++ b/Fermion/pages/index.html @@ -1,6 +1,11 @@ + @@ -231,7 +236,7 @@

Frida Tools

'// ░▒█░ ░▒████▒░██▓ ▒██▒▒██▒ ░██▒░██░░ ████▓▒░▒██░ ▓██░', '// ▒ ░ ░░ ▒░ ░░ ▒▓ ░▒▓░░ ▒░ ░ ░░▓ ░ ▒░▒░▒░ ░ ▒░ ▒ ▒ ', '// ░ ░ ░ ░ ░▒ ░ ▒░░ ░ ░ ▒ ░ ░ ▒ ▒░ ░ ░░ ░ ▒░', - '// ░ ░ ░ ░░ v1.9 ░ ▒ ░░ ░ ░ ▒ ░ ~b33f ░ ', + '// ░ ░ ░ ░░ v' + FERMION_VER + ' ░ ▒ ░░ ░ ░ ▒ ░ ~b33f ░ ', '// ░ ░ ░ ░ ░ ░ ░ ░ ', '//', '// -= Editor =-', @@ -269,9 +274,10 @@

Frida Tools

dirname(dirname(require.resolve("frida"))), "package.json" )).version; + const FERMION_VER = require('../package.json').version; // Print release firda version to textarea - appendFridaLog("[+] Fermion v1.8 -> Frida v" + FRIDA_VER); + appendFridaLog("[+] Fermion v" + FERMION_VER + " -> Frida v" + FRIDA_VER); appendFridaLog(" |_ https://github.com/frida/frida/releases/tag/" + FRIDA_VER); diff --git a/Fermion/pages/instrument.html b/Fermion/pages/instrument.html index 5f58939..b69c79f 100644 --- a/Fermion/pages/instrument.html +++ b/Fermion/pages/instrument.html @@ -3,6 +3,7 @@ diff --git a/Fermion/pages/proc.html b/Fermion/pages/proc.html index 353378a..94a6be8 100644 --- a/Fermion/pages/proc.html +++ b/Fermion/pages/proc.html @@ -7,10 +7,6 @@ -webkit-app-region:drag !important; } - ::-webkit-scrollbar { - width: 0px !important; - } - th { background: #767676 !important; color: white !important; @@ -29,11 +25,11 @@ -webkit-app-region:no-drag; position:fixed; top:40px; - margin-top: 8px; - padding:4px; - overflow-x: hidden; - overflow-x: auto; - text-align:justify; + margin-top: 8px; + padding:4px; + overflow-x: hidden; + overflow-x: auto; + text-align:justify; overflow-y:scroll; height: 94vh; width: 100%; @@ -42,6 +38,135 @@ @@ -67,15 +192,15 @@
- +
- - - - - - + + + + + + @@ -191,6 +316,22 @@ // Hacky fix for semantic-ui table bug document.getElementById("ProcSet").deleteRow(1); + // Init sorting + $('table').tablesort(); + + // Custom sort for PID + $('thead th.iPID').data( + 'sortBy', + function(th, td, tablesort) { + return parseInt(td.text()); + }); + + // Custom sort for PPID + $('thead th.iPPID').data( + 'sortBy', + function(th, td, tablesort) { + return parseInt(td.text()); + }); }).catch((err) => { $("#ProcSet").remove(); var node = document.createElement("p"); diff --git a/Fermion/pages/trace.html b/Fermion/pages/trace.html index 008dcd3..4b53c12 100644 --- a/Fermion/pages/trace.html +++ b/Fermion/pages/trace.html @@ -3,14 +3,14 @@
IconUserPIDPPIDProcessAttachIconUserPIDPPIDProcessAttach