-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.ts
152 lines (123 loc) · 4.7 KB
/
index.ts
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import WebSocket = require('isomorphic-ws');
import createWebSocketStream = require('@httptoolkit/websocket-stream');
import dbus = require('@httptoolkit/dbus-native');
import { DBusVariantDict, parseDBusVariantDict } from './dbus-value';
export {
getFridaReleaseDetails,
downloadFridaServer
} from './download-frida';
const DEFAULT_FRIDA_PORT = 27042;
export async function connect(options: {
host?: string
} = {}) {
const fridaHost = options.host || `localhost:${DEFAULT_FRIDA_PORT}`;
const socket = new WebSocket(`ws://${fridaHost}/ws`);
socket.binaryType = 'arraybuffer';
await new Promise((resolve, reject) => {
socket.addEventListener('open', resolve);
socket.addEventListener('error', reject);
});
const bus = dbus.createClient({
stream: createWebSocketStream(socket),
direct: true,
authMethods: []
});
return new FridaSession(bus);
}
interface HostSession {
QuerySystemParameters(): Promise<DBusVariantDict>;
EnumerateProcesses(arg: {}): Promise<Array<[number, string]>>;
Attach(pid: number, options: {}): Promise<[string]>;
Spawn(program: string, options: [
hasArgv: boolean,
argv: string[],
hasEnvP: boolean,
envp: string[],
hasEnv: boolean,
env: string[],
cwd: string,
stdio: number,
aux: []
]): Promise<number>;
}
interface AgentSession {
CreateScript(script: string, options: {}): Promise<[number]>;
LoadScript(scriptId: [number]): Promise<void>;
}
export class FridaSession {
constructor(
private bus: dbus.DBusClient
) {}
/**
* Disconnect from Frida. Returns a promise that resolves once the connection has been closed.
*/
async disconnect() {
return this.bus.disconnect();
}
private getHostSession() {
return this.bus
.getService('re.frida.HostSession16')
.getInterface<HostSession>('/re/frida/HostSession', 're.frida.HostSession16');
}
private getAgentSession(sessionId: string) {
return this.bus
.getService('re.frida.AgentSession16')
.getInterface<AgentSession>('/re/frida/AgentSession/' + sessionId, 're.frida.AgentSession16');
}
/**
* Query the system parameters of the target Frida server.
*/
async queryMetadata(): Promise<Record<string, string>> {
const hostSession = await this.getHostSession();
const rawMetadata = await hostSession.QuerySystemParameters();
return parseDBusVariantDict(rawMetadata) as Record<string, string>;
}
/**
* List all running processes accessible to the target Frida server. Returns an array
* of [pid, process name] pairs.
*/
async enumerateProcesses(): Promise<Array<[number, string]>> {
const hostSession = await this.getHostSession();
return hostSession.EnumerateProcesses({});
}
/**
* Attach to a given pid and inject a Frida script to manipulate the target program.
*
* Whether you can attach to the process may depend on system configuration. For
* Linux specifically, if the process is not a child of your own process, you may
* need to run `sudo sysctl kernel.yama.ptrace_scope=0` first.
*/
async injectIntoProcess(pid: number, fridaScript: string) {
const hostSession = await this.getHostSession();
const [sessionId] = await hostSession.Attach(pid, {});
const agentSession = await this.getAgentSession(sessionId);
const scriptId = await agentSession.CreateScript(fridaScript, {});
await agentSession.LoadScript(scriptId);
}
/**
* Run arbitrary Node.js code directly within a target Node process. The given
* code string will be wrapped with a Frida hook that injects it directly into
* the event loop, so it will run immediately.
*/
async injectIntoNodeJSProcess(pid: number, nodeScript: string) {
const fridaScript = require('../scripts/node-js-inject.js')
.buildNodeJsInjectionScript(nodeScript);
return this.injectIntoProcess(pid, fridaScript);
}
async spawnWithScript(command: string, args: string[], fridaScript: string) {
const hostSession: any = await this.getHostSession();
const pid = await hostSession.Spawn(command, [
true, [command, ...args],
false, [],
false, [],
"",
0,
[]
]);
const [sessionId] = await hostSession.Attach(pid, {});
const agentSession = await this.getAgentSession(sessionId);
const scriptId = await agentSession.CreateScript(fridaScript, {});
await agentSession.LoadScript(scriptId);
await hostSession.Resume(pid);
}
}