@efffrida/frida-tools 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FridaDevice/package.json +6 -0
- package/FridaDeviceAcquisitionError/package.json +6 -0
- package/FridaScript/package.json +6 -0
- package/FridaSession/package.json +6 -0
- package/FridaSessionError/package.json +6 -0
- package/LICENSE +674 -0
- package/README.md +30 -0
- package/dist/cjs/FridaDevice.js +61 -0
- package/dist/cjs/FridaDevice.js.map +1 -0
- package/dist/cjs/FridaDeviceAcquisitionError.js +34 -0
- package/dist/cjs/FridaDeviceAcquisitionError.js.map +1 -0
- package/dist/cjs/FridaScript.js +41 -0
- package/dist/cjs/FridaScript.js.map +1 -0
- package/dist/cjs/FridaSession.js +46 -0
- package/dist/cjs/FridaSession.js.map +1 -0
- package/dist/cjs/FridaSessionError.js +38 -0
- package/dist/cjs/FridaSessionError.js.map +1 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/internal/device.js +69 -0
- package/dist/cjs/internal/device.js.map +1 -0
- package/dist/cjs/internal/script.js +164 -0
- package/dist/cjs/internal/script.js.map +1 -0
- package/dist/cjs/internal/session.js +56 -0
- package/dist/cjs/internal/session.js.map +1 -0
- package/dist/dts/FridaDevice.d.ts +69 -0
- package/dist/dts/FridaDevice.d.ts.map +1 -0
- package/dist/dts/FridaDeviceAcquisitionError.d.ts +35 -0
- package/dist/dts/FridaDeviceAcquisitionError.d.ts.map +1 -0
- package/dist/dts/FridaScript.d.ts +80 -0
- package/dist/dts/FridaScript.d.ts.map +1 -0
- package/dist/dts/FridaSession.d.ts +56 -0
- package/dist/dts/FridaSession.d.ts.map +1 -0
- package/dist/dts/FridaSessionError.d.ts +35 -0
- package/dist/dts/FridaSessionError.d.ts.map +1 -0
- package/dist/dts/index.d.ts +31 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/internal/device.d.ts +2 -0
- package/dist/dts/internal/device.d.ts.map +1 -0
- package/dist/dts/internal/script.d.ts +2 -0
- package/dist/dts/internal/script.d.ts.map +1 -0
- package/dist/dts/internal/session.d.ts +2 -0
- package/dist/dts/internal/session.d.ts.map +1 -0
- package/dist/esm/FridaDevice.js +52 -0
- package/dist/esm/FridaDevice.js.map +1 -0
- package/dist/esm/FridaDeviceAcquisitionError.js +23 -0
- package/dist/esm/FridaDeviceAcquisitionError.js.map +1 -0
- package/dist/esm/FridaScript.js +32 -0
- package/dist/esm/FridaScript.js.map +1 -0
- package/dist/esm/FridaSession.js +37 -0
- package/dist/esm/FridaSession.js.map +1 -0
- package/dist/esm/FridaSessionError.js +27 -0
- package/dist/esm/FridaSessionError.js.map +1 -0
- package/dist/esm/index.js +31 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/device.js +55 -0
- package/dist/esm/internal/device.js.map +1 -0
- package/dist/esm/internal/script.js +155 -0
- package/dist/esm/internal/script.js.map +1 -0
- package/dist/esm/internal/session.js +44 -0
- package/dist/esm/internal/session.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/package.json +76 -0
- package/src/FridaDevice.ts +103 -0
- package/src/FridaDeviceAcquisitionError.ts +42 -0
- package/src/FridaScript.ts +117 -0
- package/src/FridaSession.ts +76 -0
- package/src/FridaSessionError.ts +42 -0
- package/src/index.ts +34 -0
- package/src/internal/device.ts +93 -0
- package/src/internal/script.ts +208 -0
- package/src/internal/session.ts +73 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frida sessions
|
|
3
|
+
*
|
|
4
|
+
* @since 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type * as Context from "effect/Context";
|
|
8
|
+
import type * as Effect from "effect/Effect";
|
|
9
|
+
import type * as Layer from "effect/Layer";
|
|
10
|
+
import type * as Scope from "effect/Scope";
|
|
11
|
+
import type * as Frida from "frida";
|
|
12
|
+
import type * as FridaDevice from "./FridaDevice.js";
|
|
13
|
+
import type * as FridaSessionError from "./FridaSessionError.js";
|
|
14
|
+
|
|
15
|
+
import * as internal from "./internal/session.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @since 1.0.0
|
|
19
|
+
* @category Type ids
|
|
20
|
+
*/
|
|
21
|
+
export const FridaSessionTypeId: unique symbol = internal.FridaSessionTypeId;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @since 1.0.0
|
|
25
|
+
* @category Type ids
|
|
26
|
+
*/
|
|
27
|
+
export type FridaSessionTypeId = typeof FridaSessionTypeId;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @since 1.0.0
|
|
31
|
+
* @category Models
|
|
32
|
+
*/
|
|
33
|
+
export interface FridaSession {
|
|
34
|
+
readonly session: Frida.Session;
|
|
35
|
+
readonly [FridaSessionTypeId]: typeof FridaSessionTypeId;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
* @category Tags
|
|
41
|
+
*/
|
|
42
|
+
export const FridaSession: Context.Tag<FridaSession, FridaSession> = internal.Tag;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @since 1.0.0
|
|
46
|
+
* @category Predicates
|
|
47
|
+
*/
|
|
48
|
+
export const isFridaSession: (u: unknown) => u is FridaSession = internal.isFridaSession;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @since 1.0.0
|
|
52
|
+
* @category Frida
|
|
53
|
+
*/
|
|
54
|
+
export const spawn: (
|
|
55
|
+
program: string | Array<string>,
|
|
56
|
+
options?: Frida.SpawnOptions | undefined
|
|
57
|
+
) => Effect.Effect<number, FridaSessionError.FridaSessionError, FridaDevice.FridaDevice | Scope.Scope> = internal.spawn;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @since 1.0.0
|
|
61
|
+
* @category Frida
|
|
62
|
+
*/
|
|
63
|
+
export const attach: (
|
|
64
|
+
target: Frida.TargetProcess,
|
|
65
|
+
options?: Frida.SessionOptions | undefined
|
|
66
|
+
) => Effect.Effect<FridaSession, FridaSessionError.FridaSessionError, FridaDevice.FridaDevice | Scope.Scope> =
|
|
67
|
+
internal.attach;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @since 1.0.0
|
|
71
|
+
* @category Layers
|
|
72
|
+
*/
|
|
73
|
+
export const layer: (
|
|
74
|
+
target: string,
|
|
75
|
+
options?: (Frida.SpawnOptions & Frida.SessionOptions) | undefined
|
|
76
|
+
) => Layer.Layer<FridaSession, FridaSessionError.FridaSessionError, FridaDevice.FridaDevice> = internal.layer;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frida session errors
|
|
3
|
+
*
|
|
4
|
+
* @since 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as PlatformError from "@effect/platform/Error";
|
|
8
|
+
import * as Predicate from "effect/Predicate";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @since 1.0.0
|
|
12
|
+
* @category Errors
|
|
13
|
+
*/
|
|
14
|
+
export const FridaSessionErrorTypeId: unique symbol = Symbol.for(
|
|
15
|
+
"@efffrida/FridaError/FridaSessionError"
|
|
16
|
+
) as FridaSessionErrorTypeId;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
* @category Errors
|
|
21
|
+
*/
|
|
22
|
+
export type FridaSessionErrorTypeId = typeof FridaSessionErrorTypeId;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
* @category Errors
|
|
27
|
+
*/
|
|
28
|
+
export const isFridaSessionError = (u: unknown): u is FridaSessionError =>
|
|
29
|
+
Predicate.hasProperty(u, FridaSessionErrorTypeId);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @since 1.0.0
|
|
33
|
+
* @category Errors
|
|
34
|
+
*/
|
|
35
|
+
export class FridaSessionError extends PlatformError.TypeIdError(FridaSessionErrorTypeId, "FridaSessionError")<{
|
|
36
|
+
cause: unknown;
|
|
37
|
+
when: "spawn" | "kill" | "attach" | "detach" | "compile" | "load" | "unload" | "resume" | "message" | "rpcCall";
|
|
38
|
+
}> {
|
|
39
|
+
get message() {
|
|
40
|
+
return `A Frida session error occurred on ${this.when}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frida devices
|
|
3
|
+
*
|
|
4
|
+
* @since 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
export * as FridaDevice from "./FridaDevice.js"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Frida device acquisition errors
|
|
10
|
+
*
|
|
11
|
+
* @since 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
export * as FridaDeviceAcquisitionError from "./FridaDeviceAcquisitionError.js"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Frida scripts
|
|
17
|
+
*
|
|
18
|
+
* @since 1.0.0
|
|
19
|
+
*/
|
|
20
|
+
export * as FridaScript from "./FridaScript.js"
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Frida sessions
|
|
24
|
+
*
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
*/
|
|
27
|
+
export * as FridaSession from "./FridaSession.js"
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Frida session errors
|
|
31
|
+
*
|
|
32
|
+
* @since 1.0.0
|
|
33
|
+
*/
|
|
34
|
+
export * as FridaSessionError from "./FridaSessionError.js"
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type * as FridaDevice from "../FridaDevice.js";
|
|
2
|
+
|
|
3
|
+
import * as Context from "effect/Context";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Layer from "effect/Layer";
|
|
6
|
+
import * as Predicate from "effect/Predicate";
|
|
7
|
+
import * as Frida from "frida";
|
|
8
|
+
import * as FridaDeviceAcquisitionError from "../FridaDeviceAcquisitionError.js";
|
|
9
|
+
|
|
10
|
+
/** @internal */
|
|
11
|
+
export const FridaDeviceTypeId: FridaDevice.FridaDeviceTypeId = Symbol.for(
|
|
12
|
+
"@efffrida/frida-tools/FridaDevice"
|
|
13
|
+
) as FridaDevice.FridaDeviceTypeId;
|
|
14
|
+
|
|
15
|
+
/** @internal */
|
|
16
|
+
export const Tag = Context.GenericTag<FridaDevice.FridaDevice>("@efffrida/frida-tools/FridaDevice");
|
|
17
|
+
|
|
18
|
+
/** @internal */
|
|
19
|
+
export const isFridaDevice = (u: unknown): u is FridaDevice.FridaDevice => Predicate.hasProperty(u, FridaDeviceTypeId);
|
|
20
|
+
|
|
21
|
+
/** @internal */
|
|
22
|
+
export const acquireUsbDevice = (
|
|
23
|
+
options?: Frida.GetDeviceOptions | undefined
|
|
24
|
+
): Effect.Effect<FridaDevice.FridaDevice, FridaDeviceAcquisitionError.FridaDeviceAcquisitionError, never> =>
|
|
25
|
+
Effect.map(
|
|
26
|
+
Effect.tryPromise({
|
|
27
|
+
try: () => Frida.getUsbDevice(options),
|
|
28
|
+
catch: (cause) =>
|
|
29
|
+
new FridaDeviceAcquisitionError.FridaDeviceAcquisitionError({
|
|
30
|
+
cause,
|
|
31
|
+
attempts: 1,
|
|
32
|
+
acquisitionMethod: "usb",
|
|
33
|
+
}),
|
|
34
|
+
}),
|
|
35
|
+
(device) => ({ device, [FridaDeviceTypeId]: FridaDeviceTypeId }) as const
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
/** @internal */
|
|
39
|
+
export const acquireRemoteDevice = (
|
|
40
|
+
address: string,
|
|
41
|
+
options?: Frida.RemoteDeviceOptions | undefined
|
|
42
|
+
): Effect.Effect<FridaDevice.FridaDevice, FridaDeviceAcquisitionError.FridaDeviceAcquisitionError, never> =>
|
|
43
|
+
Effect.map(
|
|
44
|
+
Effect.tryPromise({
|
|
45
|
+
try: () => Frida.getDeviceManager().addRemoteDevice(address, options),
|
|
46
|
+
catch: (cause) =>
|
|
47
|
+
new FridaDeviceAcquisitionError.FridaDeviceAcquisitionError({
|
|
48
|
+
cause,
|
|
49
|
+
attempts: 1,
|
|
50
|
+
acquisitionMethod: "remote",
|
|
51
|
+
}),
|
|
52
|
+
}),
|
|
53
|
+
(device) => ({ device, [FridaDeviceTypeId]: FridaDeviceTypeId }) as const
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
/** @internal */
|
|
57
|
+
export const acquireLocalDevice = (): Effect.Effect<
|
|
58
|
+
FridaDevice.FridaDevice,
|
|
59
|
+
FridaDeviceAcquisitionError.FridaDeviceAcquisitionError,
|
|
60
|
+
never
|
|
61
|
+
> =>
|
|
62
|
+
Effect.map(
|
|
63
|
+
Effect.tryPromise({
|
|
64
|
+
try: () => Frida.getLocalDevice(),
|
|
65
|
+
catch: (cause) =>
|
|
66
|
+
new FridaDeviceAcquisitionError.FridaDeviceAcquisitionError({
|
|
67
|
+
cause,
|
|
68
|
+
attempts: 1,
|
|
69
|
+
acquisitionMethod: "local",
|
|
70
|
+
}),
|
|
71
|
+
}),
|
|
72
|
+
(device) => ({ device, [FridaDeviceTypeId]: FridaDeviceTypeId }) as const
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
/** @internal */
|
|
76
|
+
export const layerRemoteDevice = (
|
|
77
|
+
address: string,
|
|
78
|
+
options?: Frida.RemoteDeviceOptions | undefined
|
|
79
|
+
): Layer.Layer<FridaDevice.FridaDevice, FridaDeviceAcquisitionError.FridaDeviceAcquisitionError, never> =>
|
|
80
|
+
Layer.effect(Tag, acquireRemoteDevice(address, options));
|
|
81
|
+
|
|
82
|
+
/** @internal */
|
|
83
|
+
export const layerUsbDevice = (
|
|
84
|
+
options?: Frida.GetDeviceOptions | undefined
|
|
85
|
+
): Layer.Layer<FridaDevice.FridaDevice, FridaDeviceAcquisitionError.FridaDeviceAcquisitionError, never> =>
|
|
86
|
+
Layer.effect(Tag, acquireUsbDevice(options));
|
|
87
|
+
|
|
88
|
+
/** @internal */
|
|
89
|
+
export const layerLocalDevice: Layer.Layer<
|
|
90
|
+
FridaDevice.FridaDevice,
|
|
91
|
+
FridaDeviceAcquisitionError.FridaDeviceAcquisitionError,
|
|
92
|
+
never
|
|
93
|
+
> = Layer.effect(Tag, acquireLocalDevice());
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import type * as Scope from "effect/Scope";
|
|
2
|
+
import type * as FridaScript from "../FridaScript.js";
|
|
3
|
+
|
|
4
|
+
import * as Context from "effect/Context";
|
|
5
|
+
import * as Deferred from "effect/Deferred";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Function from "effect/Function";
|
|
8
|
+
import * as Layer from "effect/Layer";
|
|
9
|
+
import * as Option from "effect/Option";
|
|
10
|
+
import * as Predicate from "effect/Predicate";
|
|
11
|
+
import * as Queue from "effect/Queue";
|
|
12
|
+
import * as Sink from "effect/Sink";
|
|
13
|
+
import * as Stream from "effect/Stream";
|
|
14
|
+
import * as Take from "effect/Take";
|
|
15
|
+
import * as Frida from "frida";
|
|
16
|
+
import * as FridaDevice from "../FridaDevice.js";
|
|
17
|
+
import * as FridaSession from "../FridaSession.js";
|
|
18
|
+
import * as FridaSessionError from "../FridaSessionError.js";
|
|
19
|
+
|
|
20
|
+
/** @internal */
|
|
21
|
+
export const FridaScriptTypeId: FridaScript.FridaScriptTypeId = Symbol.for(
|
|
22
|
+
"@efffrida/frida-tools/FridaScript"
|
|
23
|
+
) as FridaScript.FridaScriptTypeId;
|
|
24
|
+
|
|
25
|
+
/** @internal */
|
|
26
|
+
export const Tag = Context.GenericTag<FridaScript.FridaScript>("@efffrida/frida-tools/FridaScript");
|
|
27
|
+
|
|
28
|
+
/** @internal */
|
|
29
|
+
export const isFridaScript = (u: unknown): u is FridaScript.FridaScript => Predicate.hasProperty(u, FridaScriptTypeId);
|
|
30
|
+
|
|
31
|
+
/** @internal */
|
|
32
|
+
export const load = Function.dual<
|
|
33
|
+
(
|
|
34
|
+
options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
|
|
35
|
+
) => (
|
|
36
|
+
source: string | Buffer
|
|
37
|
+
) => Effect.Effect<
|
|
38
|
+
FridaScript.FridaScript,
|
|
39
|
+
FridaSessionError.FridaSessionError,
|
|
40
|
+
FridaSession.FridaSession | FridaDevice.FridaDevice | Scope.Scope
|
|
41
|
+
>,
|
|
42
|
+
(
|
|
43
|
+
source: string | Buffer,
|
|
44
|
+
options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
|
|
45
|
+
) => Effect.Effect<
|
|
46
|
+
FridaScript.FridaScript,
|
|
47
|
+
FridaSessionError.FridaSessionError,
|
|
48
|
+
FridaSession.FridaSession | FridaDevice.FridaDevice | Scope.Scope
|
|
49
|
+
>
|
|
50
|
+
>(
|
|
51
|
+
(arguments_) => Predicate.isString(arguments_[0]) || Buffer.isBuffer(arguments_[0]),
|
|
52
|
+
Effect.fnUntraced(
|
|
53
|
+
function* (
|
|
54
|
+
source: string | Buffer,
|
|
55
|
+
options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
|
|
56
|
+
) {
|
|
57
|
+
const { device } = yield* FridaDevice.FridaDevice;
|
|
58
|
+
const { session } = yield* FridaSession.FridaSession;
|
|
59
|
+
|
|
60
|
+
const script = Predicate.isString(source)
|
|
61
|
+
? yield* Effect.tryPromise({
|
|
62
|
+
try: () => session.createScript(source, { runtime: Frida.ScriptRuntime.V8, ...options }),
|
|
63
|
+
catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "compile" }),
|
|
64
|
+
})
|
|
65
|
+
: yield* Effect.tryPromise({
|
|
66
|
+
try: () => session.createScriptFromBytes(source, { runtime: Frida.ScriptRuntime.V8, ...options }),
|
|
67
|
+
catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "compile" }),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const messageQueue =
|
|
71
|
+
yield* Queue.unbounded<
|
|
72
|
+
Take.Take<{ message: any; data: Option.Option<Buffer> }, FridaSessionError.FridaSessionError>
|
|
73
|
+
>();
|
|
74
|
+
|
|
75
|
+
let scriptDefectCause: unknown = undefined;
|
|
76
|
+
const messageHandler: Frida.ScriptMessageHandler = (message: Frida.Message, data: Buffer | null): void => {
|
|
77
|
+
switch (message.type) {
|
|
78
|
+
case Frida.MessageType.Error: {
|
|
79
|
+
const error = new Error();
|
|
80
|
+
error.name = "FridaScriptDefect";
|
|
81
|
+
error.stack = message.stack ?? "";
|
|
82
|
+
error.message = message.description.replace(/Error: /, "") ?? "";
|
|
83
|
+
scriptDefectCause = error;
|
|
84
|
+
const sessionError = new FridaSessionError.FridaSessionError({
|
|
85
|
+
when: "message",
|
|
86
|
+
cause: error.cause,
|
|
87
|
+
});
|
|
88
|
+
const asTake = Take.fail(sessionError);
|
|
89
|
+
Queue.unsafeOffer(messageQueue, asTake);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
case Frida.MessageType.Send: {
|
|
94
|
+
const asTake = Take.of({ message: message.payload, data: Option.fromNullable(data) });
|
|
95
|
+
Queue.unsafeOffer(messageQueue, asTake);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
default:
|
|
100
|
+
Function.absurd(message);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const disconnectMessageHandler = Effect.sync(() => script.message.disconnect(messageHandler));
|
|
105
|
+
yield* Effect.addFinalizer(() => Effect.flatMap(messageQueue.shutdown, () => disconnectMessageHandler));
|
|
106
|
+
script.message.connect(messageHandler);
|
|
107
|
+
|
|
108
|
+
const stream = Stream.fromQueue(messageQueue).pipe(Stream.flattenTake);
|
|
109
|
+
const sink = Sink.forEach<
|
|
110
|
+
{ message: any; data: Option.Option<Buffer> },
|
|
111
|
+
void,
|
|
112
|
+
FridaSessionError.FridaSessionError,
|
|
113
|
+
never
|
|
114
|
+
>(({ data, message }) => {
|
|
115
|
+
if (Predicate.isNotUndefined(scriptDefectCause)) {
|
|
116
|
+
return Effect.fail(
|
|
117
|
+
new FridaSessionError.FridaSessionError({
|
|
118
|
+
when: "rpcCall",
|
|
119
|
+
cause: scriptDefectCause,
|
|
120
|
+
})
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
return Effect.sync(() => script.post(message, Option.getOrNull(data)));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const destroyed = yield* Deferred.make<void, never>();
|
|
128
|
+
const destroyedHandler = () => Deferred.unsafeDone(destroyed, Effect.void);
|
|
129
|
+
script.destroyed.connect(destroyedHandler);
|
|
130
|
+
|
|
131
|
+
const callExport = (exportName: string) =>
|
|
132
|
+
Effect.fn(`call frida export ${exportName}`)(function* (...args: Array<any>) {
|
|
133
|
+
yield* Effect.annotateCurrentSpan("args", args);
|
|
134
|
+
|
|
135
|
+
const isDestroyed = yield* Deferred.isDone(destroyed);
|
|
136
|
+
if (isDestroyed) {
|
|
137
|
+
return yield* new FridaSessionError.FridaSessionError({
|
|
138
|
+
when: "rpcCall",
|
|
139
|
+
cause: "Script is destroyed",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (Predicate.isNotUndefined(scriptDefectCause)) {
|
|
144
|
+
return yield* new FridaSessionError.FridaSessionError({
|
|
145
|
+
when: "rpcCall",
|
|
146
|
+
cause: scriptDefectCause,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const result = yield* Effect.tryPromise({
|
|
151
|
+
try: () => script.exports[exportName](...args) as Promise<unknown>,
|
|
152
|
+
catch: (cause) => new FridaSessionError.FridaSessionError({ when: "rpcCall", cause }),
|
|
153
|
+
});
|
|
154
|
+
yield* Effect.annotateCurrentSpan("result", result);
|
|
155
|
+
return result;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
yield* Effect.tryPromise({
|
|
159
|
+
try: () => script.load(),
|
|
160
|
+
catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "load" }),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (options?.resume === true) {
|
|
164
|
+
yield* Effect.tryPromise({
|
|
165
|
+
try: () => device.resume(session.pid),
|
|
166
|
+
catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "resume" }),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
script,
|
|
172
|
+
stream,
|
|
173
|
+
sink,
|
|
174
|
+
destroyed,
|
|
175
|
+
callExport,
|
|
176
|
+
[FridaScriptTypeId]: FridaScriptTypeId,
|
|
177
|
+
} as const;
|
|
178
|
+
},
|
|
179
|
+
Effect.acquireRelease(({ script }: FridaScript.FridaScript) => Effect.promise(() => script.unload()))
|
|
180
|
+
)
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
/** @internal */
|
|
184
|
+
export const layer = Function.dual<
|
|
185
|
+
(
|
|
186
|
+
options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
|
|
187
|
+
) => (
|
|
188
|
+
source: string | Buffer
|
|
189
|
+
) => Layer.Layer<
|
|
190
|
+
FridaScript.FridaScript,
|
|
191
|
+
FridaSessionError.FridaSessionError,
|
|
192
|
+
FridaSession.FridaSession | FridaDevice.FridaDevice
|
|
193
|
+
>,
|
|
194
|
+
(
|
|
195
|
+
source: string | Buffer,
|
|
196
|
+
options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
|
|
197
|
+
) => Layer.Layer<
|
|
198
|
+
FridaScript.FridaScript,
|
|
199
|
+
FridaSessionError.FridaSessionError,
|
|
200
|
+
FridaSession.FridaSession | FridaDevice.FridaDevice
|
|
201
|
+
>
|
|
202
|
+
>(
|
|
203
|
+
(arguments_) => Predicate.isString(arguments_[0]),
|
|
204
|
+
(
|
|
205
|
+
source: string | Buffer,
|
|
206
|
+
options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
|
|
207
|
+
) => Layer.scoped(Tag, load(source, options))
|
|
208
|
+
);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type * as Scope from "effect/Scope";
|
|
2
|
+
import type * as Frida from "frida";
|
|
3
|
+
import type * as FridaSession from "../FridaSession.js";
|
|
4
|
+
|
|
5
|
+
import * as Context from "effect/Context";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
8
|
+
import * as Predicate from "effect/Predicate";
|
|
9
|
+
import * as FridaDevice from "../FridaDevice.js";
|
|
10
|
+
import * as FridaSessionError from "../FridaSessionError.js";
|
|
11
|
+
|
|
12
|
+
/** @internal */
|
|
13
|
+
export const FridaSessionTypeId: FridaSession.FridaSessionTypeId = Symbol.for(
|
|
14
|
+
"@efffrida/frida-tools/FridaSession"
|
|
15
|
+
) as FridaSession.FridaSessionTypeId;
|
|
16
|
+
|
|
17
|
+
/** @internal */
|
|
18
|
+
export const Tag = Context.GenericTag<FridaSession.FridaSession>("@efffrida/frida-tools/FridaSession");
|
|
19
|
+
|
|
20
|
+
/** @internal */
|
|
21
|
+
export const isFridaSession = (u: unknown): u is FridaSession.FridaSession =>
|
|
22
|
+
Predicate.hasProperty(u, FridaSessionTypeId);
|
|
23
|
+
|
|
24
|
+
/** @internal */
|
|
25
|
+
export const spawn = (
|
|
26
|
+
program: string | Array<string>,
|
|
27
|
+
options?: Frida.SpawnOptions | undefined
|
|
28
|
+
): Effect.Effect<number, FridaSessionError.FridaSessionError, FridaDevice.FridaDevice | Scope.Scope> =>
|
|
29
|
+
Effect.flatMap(FridaDevice.FridaDevice, ({ device }) =>
|
|
30
|
+
Effect.acquireRelease(
|
|
31
|
+
Effect.tryPromise({
|
|
32
|
+
try: () => device.spawn(program, options),
|
|
33
|
+
catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "spawn" }),
|
|
34
|
+
}),
|
|
35
|
+
(pid) => Effect.promise(() => device.kill(pid))
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
/** @internal */
|
|
40
|
+
export const attach = (
|
|
41
|
+
target: Frida.TargetProcess,
|
|
42
|
+
options?: Frida.SessionOptions | undefined
|
|
43
|
+
): Effect.Effect<
|
|
44
|
+
FridaSession.FridaSession,
|
|
45
|
+
FridaSessionError.FridaSessionError,
|
|
46
|
+
FridaDevice.FridaDevice | Scope.Scope
|
|
47
|
+
> =>
|
|
48
|
+
Effect.flatMap(FridaDevice.FridaDevice, ({ device }) =>
|
|
49
|
+
Effect.acquireRelease(
|
|
50
|
+
Effect.map(
|
|
51
|
+
Effect.tryPromise({
|
|
52
|
+
try: () => device.attach(target, options),
|
|
53
|
+
catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "attach" }),
|
|
54
|
+
}),
|
|
55
|
+
(session) => ({ session, [FridaSessionTypeId]: FridaSessionTypeId }) as const
|
|
56
|
+
),
|
|
57
|
+
({ session }: FridaSession.FridaSession) => Effect.promise(() => session.detach())
|
|
58
|
+
)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
/** @internal */
|
|
62
|
+
export const layer = (
|
|
63
|
+
target: string,
|
|
64
|
+
options?: (Frida.SpawnOptions & Frida.SessionOptions) | undefined
|
|
65
|
+
): Layer.Layer<FridaSession.FridaSession, FridaSessionError.FridaSessionError, FridaDevice.FridaDevice> =>
|
|
66
|
+
Layer.scoped(
|
|
67
|
+
Tag,
|
|
68
|
+
Effect.gen(function* () {
|
|
69
|
+
const pid = yield* spawn(target, options);
|
|
70
|
+
const session = yield* attach(pid, options);
|
|
71
|
+
return session;
|
|
72
|
+
})
|
|
73
|
+
);
|