Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions types/frida-gum/frida-gum-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,42 @@ Interceptor.attach({
},
});

Interceptor.attach({
target: puts,
writeRedirect(details) {
// $ExpectType DefaultInstructionWriter
details.writer;
// $ExpectType NativePointer
details.target;
// $ExpectType number
details.capacity;

// Same register type as carried by InstrumentationTarget.
const scratch: InstrumentationTarget["scratchRegister"] = details.scratchRegister;
void scratch;

const writer = details.writer as Arm64Writer;
writer.putBImm(details.target);
},
redirectSpaceHint: 16,
}, {
onEnter(args) {
// $ExpectType InvocationArguments
args;
},
});

// $ExpectType InstrumentationOptions
Interceptor.defaults;

Interceptor.defaults = {
scratchRegister: "x15",
writeRedirect(details) {
details.writer.flush();
},
redirectSpaceHint: 256,
};

Interceptor.flush();

// $ExpectType void
Expand Down
96 changes: 95 additions & 1 deletion types/frida-gum/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3296,6 +3296,15 @@ declare namespace Interceptor {
*/
function flush(): void;

/**
* Default instrumentation options applied to every subsequent
* `attach()` / `replace()` / `replaceFast()` call.
*
* Options specified per call through `InstrumentationTarget` take
* precedence over these.
*/
let defaults: InstrumentationOptions;

/**
* The kind of breakpoints to use for non-inline hooks.
*
Expand All @@ -3308,12 +3317,20 @@ declare namespace Interceptor {
* Target to instrument, carrying the address alongside optional knobs that
* control how the inline hook is set up.
*/
interface InstrumentationTarget {
interface InstrumentationTarget extends InstrumentationOptions {
/**
* Address of function/instruction to instrument.
*/
target: NativePointerValue;
}

/**
* Knobs that control how an inline hook is set up.
*
* May be specified per call through `InstrumentationTarget`, or globally
* through `Interceptor.defaults`.
*/
interface InstrumentationOptions {
/**
* Register that Interceptor may clobber when building the trampoline.
*
Expand Down Expand Up @@ -3343,8 +3360,85 @@ interface InstrumentationTarget {
* Defaults to `checked`.
*/
relocation?: RelocationPolicy | undefined;

/**
* Callback that emits a custom redirect from the instrumented function or
* instruction to Interceptor's trampoline.
*
* The primary use-case is defeating fingerprinting: emitting a redirect
* that a RASP implementation won't recognize as an inline hook. It is also
* useful when space is tight and you want to locate a nearby code cave
* reachable through a short immediate branch, and then branch from there to
* the trampoline farther away.
*
* Throwing from the callback declines the redirect. There is no fallback to
* the default strategy in that case: the `attach()` / `replace()` /
* `replaceFast()` call fails as if the target had a signature that could
* not be instrumented.
*/
writeRedirect?: WriteRedirectCallback | undefined;

/**
* Upper bound on the number of bytes that `writeRedirect` will need.
*
* Your callback may end up using less. Specifying a larger value means
* Interceptor has to explore further to determine that it is safe to use
* that much space — looking for back-branches, call return sites, etc. —
* which is more expensive.
*
* Defaults to the size needed for a full redirect, e.g. 16 bytes on arm64.
*/
redirectSpaceHint?: number | undefined;
}

/**
* Callback that emits a custom redirect from the target to Interceptor's
* trampoline.
*/
type WriteRedirectCallback = (details: WriteRedirectDetails) => void;

/**
* Details passed to a `WriteRedirectCallback`.
*/
interface WriteRedirectDetails {
/**
* Code writer to emit the redirect with.
*
* The concrete type depends on the architecture, e.g. an `X86Writer` on
* x86 and an `Arm64Writer` on arm64. On 32-bit ARM it may be either an
* `ArmWriter` or a `ThumbWriter`, depending on the instruction set at the
* instrumented site.
*/
writer: DefaultInstructionWriter;

/**
* Address of Interceptor's trampoline, i.e. where your redirect should
* branch to.
*/
target: NativePointer;

/**
* Scratch register that the redirect may clobber.
*
* Only present on architectures that expose scratch registers, i.e.
* arm64 and mips.
*/
scratchRegister?: Arm64Register | MipsRegister | undefined;

/**
* Number of bytes available for the redirect.
*/
capacity: number;
}

/**
* Default code writer for the current architecture.
*
* On 32-bit ARM this is either an `ArmWriter` or a `ThumbWriter`, depending on
* the instruction set at the instrumented site.
*/
type DefaultInstructionWriter = X86Writer | ArmWriter | ThumbWriter | Arm64Writer | MipsWriter;

type InstrumentationScenario = "online" | "offline";

/**
Expand Down
2 changes: 1 addition & 1 deletion types/frida-gum/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@types/frida-gum",
"version": "19.2.9999",
"version": "19.3.9999",
"nonNpm": true,
"nonNpmDescription": "frida-gum",
"projects": [
Expand Down