Skip to content

Commit 82ad676

Browse files
committed
Add types & tests for log message listening
1 parent 4882421 commit 82ad676

File tree

2 files changed

+87
-60
lines changed

2 files changed

+87
-60
lines changed

src/index.ts

+19-6
Original file line numberDiff line numberDiff line change
@@ -92,22 +92,35 @@ type AgentMessage = [kind: number, script_id: number[], text: string, has_data:
9292
*/
9393
export enum MessageType {
9494
Send = "send",
95-
Error = "error"
95+
Error = "error",
96+
Log = "log"
9697
}
9798

98-
export type Message = ScriptAgentSendMessage | ScriptAgentErrorMessage;
99-
export type ScriptAgentSendMessage = {
100-
type: MessageType.Send,
101-
payload: any
99+
export type Message =
100+
| ScriptAgentSendMessage
101+
| ScriptAgentErrorMessage
102+
| ScriptAgentLogMessage;
103+
104+
export interface ScriptAgentSendMessage {
105+
type: MessageType.Send;
106+
payload: any;
102107
}
103-
export type ScriptAgentErrorMessage = {
108+
109+
export interface ScriptAgentErrorMessage {
104110
type: MessageType.Error;
105111
description: string;
106112
stack?: string;
107113
fileName?: string;
108114
lineNumber?: number;
109115
columnNumber?: number;
110116
}
117+
118+
export interface ScriptAgentLogMessage {
119+
type: MessageType.Log,
120+
level: string,
121+
payload: string
122+
}
123+
111124
enum AgentMessageKind {
112125
Script = 1,
113126
Debugger = 2,

test/test.spec.ts

+68-54
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import { expect } from 'chai';
88
import { fetch } from 'cross-fetch';
99

1010
import { delay, isNode } from './test-util';
11-
import { connect, FridaSession, Message, MessageType, ScriptAgentSendMessage } from '../src/index';
11+
import {
12+
connect,
13+
FridaSession,
14+
Message
15+
} from '../src/index';
1216

1317
const FIXTURES_BASE = isNode
1418
? path.join(__dirname, 'fixtures')
@@ -33,7 +37,7 @@ describe("Frida-JS", () => {
3337
}
3438
}
3539
spawnedProc = undefined;
36-
})
40+
});
3741

3842
it("can connect to Frida and list target processes", async () => {
3943
fridaClient = await connect();
@@ -113,6 +117,67 @@ describe("Frida-JS", () => {
113117
expect(resultingMessage).to.equal('INJECTED');
114118
});
115119

120+
it("can get a message explicitly sent from the script", async () => {
121+
const expectedMessage = 'Hello from injected script!';
122+
123+
// Start a demo subprocess to inject into:
124+
fridaClient = await connect();
125+
const { session } = await fridaClient.spawnWithScript(
126+
path.join(FIXTURES_BASE, `serve-${process.platform}-${process.arch}`),
127+
[],
128+
`
129+
setTimeout(() => {
130+
send('${expectedMessage}');
131+
}, 100);
132+
`
133+
);
134+
135+
let message = await new Promise<Message | null>((resolve, reject) => {
136+
session.onMessage(resolve);
137+
setTimeout(() => {
138+
reject(new Error('Timed out waiting for message'));
139+
}, 1000);
140+
});
141+
142+
await fetch('http://127.0.0.1:3000'); // Fetch triggers shutdown
143+
144+
expect(message).to.deep.equal({
145+
type: 'send',
146+
payload: expectedMessage
147+
});
148+
});
149+
150+
it("can get a message console logged from a script", async () => {
151+
const expectedMessage = 'Logged warning message!';
152+
153+
// Start a demo subprocess to inject into:
154+
fridaClient = await connect();
155+
const { session } = await fridaClient.spawnWithScript(
156+
path.join(FIXTURES_BASE, `serve-${process.platform}-${process.arch}`),
157+
[],
158+
`
159+
setTimeout(() => {
160+
console.warn('${expectedMessage}');
161+
}, 100);
162+
`
163+
);
164+
165+
let message = await new Promise<Message | null>((resolve, reject) => {
166+
session.onMessage(resolve);
167+
setTimeout(() => {
168+
reject(new Error('Timed out waiting for message'));
169+
}, 1000);
170+
});
171+
172+
await fetch('http://127.0.0.1:3000'); // Fetch triggers shutdown
173+
174+
expect(message).to.deep.equal({
175+
type: 'log',
176+
level: 'warning',
177+
payload: expectedMessage
178+
});
179+
});
180+
116181
it("can receive script errors from a launched process", async () => {
117182
// Launch a server process with a failing script injected
118183
fridaClient = await connect();
@@ -122,7 +187,7 @@ describe("Frida-JS", () => {
122187
// Run an example script that always crashes:
123188
"throw new Error('Intentional script failure error');"
124189
);
125-
const messages: any[] = [];
190+
const messages: Message[] = [];
126191
session.onMessage((msg) => messages.push(msg));
127192

128193
await delay(100); // Wait momentarily for the server to start listening
@@ -255,57 +320,6 @@ describe("Frida-JS", () => {
255320
expect(output).to.equal('Hello from injected script!\n');
256321
});
257322

258-
it("can get the send message from agent", async () => {
259-
// Start a demo subprocess to inject into:
260-
const childProc = ChildProc.spawn(
261-
// Fixture that loops until should_continue() returns false (which it never does).
262-
// Source is in fixtures-setup/rust-loop.
263-
path.join(__dirname, 'fixtures', `loop-${process.platform}-${process.arch}${process.platform === 'win32' ? '.exe' : ''}`),
264-
{ stdio: 'pipe' }
265-
);
266-
childProc.unref();
267-
spawnedProc = childProc; // Ensure this is killed after testing
268-
269-
const outputPromise = new Promise<{
270-
exitCode: number | null,
271-
output: string
272-
}>((resolve, reject) => {
273-
let output = '';
274-
childProc.stdout.on('data', (msg) => output += msg.toString());
275-
childProc.stderr.on('data', (msg) => output += msg.toString());
276-
childProc.stdout.pipe(process.stdout);
277-
childProc.stderr.pipe(process.stderr);
278-
childProc.on('close', (exitCode) => resolve({ exitCode, output }));
279-
childProc.on('error', reject);
280-
});
281-
282-
// Wait for the target to start up:
283-
await new Promise((resolve, reject) => {
284-
childProc.on('spawn', resolve);
285-
childProc.on('error', reject);
286-
});
287-
288-
// Inject into it:
289-
const expectedMessage = 'Hello from injected script!';
290-
fridaClient = await connect();
291-
const data = await fridaClient.injectIntoProcess(childProc.pid!, `
292-
setTimeout(() => {
293-
send('${expectedMessage}');
294-
}, 1000);
295-
`);
296-
297-
let message = await new Promise<Message | null>((resolve, reject) => {
298-
data.session.onMessage(resolve);
299-
setTimeout(() => {
300-
reject(new Error('Timed out waiting for message'));
301-
}, 5000);
302-
});
303-
304-
// Inject into it:
305-
expect(message?.type).to.equal(MessageType.Send);
306-
expect((message as ScriptAgentSendMessage)?.payload).to.equal(expectedMessage);
307-
});
308-
309323
it("can kill a target process", async () => {
310324
// Start a demo subprocess to kill:
311325
const childProc = ChildProc.spawn(

0 commit comments

Comments
 (0)