Skip to content

Commit 7ac5656

Browse files
committed
Shut down Frida server & app targets on deactivate
1 parent 7d75d71 commit 7ac5656

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

src/interceptors/frida/frida-android-integration.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,9 @@ export async function launchAndroidHost(adbClient: AdbClient, hostId: string) {
146146
console.log(e.message ?? e);
147147
return false;
148148
}
149-
150149
});
150+
151+
return fridaServerStream;
151152
} catch (e: any) {
152153
console.log(e.message ?? e);
153154
throw new Error(`Failed to launch Frida server for ${hostId}`);
@@ -211,6 +212,8 @@ export async function interceptAndroidFridaTarget(
211212
await launchScript(`Android (${appId})`, session, interceptionScript);
212213
await session.resume();
213214
console.log(`Frida Android interception started: ${appId} on ${hostId} forwarding to ${proxyIp}:${proxyPort}`);
215+
216+
return session;
214217
} catch (e) {
215218
// If anything goes wrong, just make sure we shut down the app again
216219
await killProcess(session).catch(console.log)

src/interceptors/frida/frida-android-interceptor.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import _ from 'lodash';
2+
import * as stream from 'stream';
3+
import * as FridaJs from 'frida-js';
24

35
import { Interceptor } from "..";
46
import { HtkConfig } from '../../config';
57

68
import { createAdbClient } from '../android/adb-commands';
7-
import { FridaHost, FridaTarget } from './frida-integration';
9+
import { FridaHost, FridaTarget, killProcess } from './frida-integration';
810
import {
911
getAndroidFridaHosts,
1012
getAndroidFridaTargets,
@@ -58,6 +60,9 @@ export class FridaAndroidInterceptor implements Interceptor {
5860
}
5961
}
6062

63+
private fridaServers: { [proxyPort: number]: Array<stream.Readable> } = {};
64+
private interceptedApps: { [proxyPort: number]: Array<FridaJs.FridaAgentSession> } = {};
65+
6166
async activate(
6267
proxyPort: number,
6368
options:
@@ -68,24 +73,51 @@ export class FridaAndroidInterceptor implements Interceptor {
6873
if (options.action === 'setup') {
6974
await setupAndroidHost(this.adbClient, options.hostId);
7075
} else if (options.action === 'launch') {
71-
await launchAndroidHost(this.adbClient, options.hostId);
76+
const fridaServer = await launchAndroidHost(this.adbClient, options.hostId);
77+
78+
// Track this server stream, so we can close it to stop the server later
79+
this.fridaServers[proxyPort] = this.fridaServers[proxyPort] ?? [];
80+
this.fridaServers[proxyPort].push(fridaServer);
81+
fridaServer.on('close', () => {
82+
_.remove(this.fridaServers[proxyPort], fridaServer);
83+
});
7284
} else if (options.action === 'intercept') {
73-
await interceptAndroidFridaTarget(
85+
const fridaSession = await interceptAndroidFridaTarget(
7486
this.adbClient,
7587
options.hostId,
7688
options.targetId,
7789
this.config.https.certContent,
7890
proxyPort
7991
);
92+
93+
// Track this session, so we can close it to stop the interception later
94+
this.interceptedApps[proxyPort] = this.interceptedApps[proxyPort] ?? [];
95+
this.interceptedApps[proxyPort].push(fridaSession);
8096
} else {
8197
throw new Error(`Unknown Frida interception command: ${(options as any).action ?? '(none)'}`)
8298
}
8399
}
84100

85101
async deactivate(proxyPort: number): Promise<void | {}> {
102+
this.fridaServers[proxyPort]?.forEach(serverStream => {
103+
serverStream.destroy();
104+
});
105+
106+
await Promise.all(this.interceptedApps[proxyPort]?.map(async fridaSession => {
107+
await killProcess(fridaSession).catch(() => {});
108+
}));
86109
}
87110

88111
async deactivateAll(): Promise<void | {}> {
112+
const allPorts = new Set([
113+
...Object.keys(this.fridaServers),
114+
...Object.keys(this.interceptedApps)
115+
]);
116+
117+
await Promise.all(
118+
[...allPorts]
119+
.map(port => this.deactivate(Number(port)))
120+
);
89121
}
90122

91123
}

src/interceptors/frida/frida-ios-integration.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ export async function interceptIosFridaTarget(
126126
await launchScript(`iOS (${appId})`, session, interceptionScript);
127127
await session.resume();
128128
console.log(`Frida iOS interception started: ${appId} on ${hostId} forwarding to ${proxyIp}:${proxyPort}`);
129+
130+
return session;
129131
} catch (e) {
130132
// If anything goes wrong, just make sure we shut down the app again
131133
await killProcess(session).catch(console.log);

src/interceptors/frida/frida-ios-interceptor.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import _ from 'lodash';
22
import { UsbmuxClient } from 'usbmux-client';
3+
import * as FridaJs from 'frida-js';
34

45
import { Interceptor } from "..";
56
import { HtkConfig } from '../../config';
67

7-
import { FridaHost, FridaTarget } from './frida-integration';
8+
import { FridaHost, FridaTarget, killProcess } from './frida-integration';
89
import {
910
getIosFridaHosts,
1011
getIosFridaTargets,
@@ -56,28 +57,41 @@ export class FridaIosInterceptor implements Interceptor {
5657
}
5758
}
5859

60+
private interceptedApps: { [proxyPort: number]: Array<FridaJs.FridaAgentSession> } = {};
61+
5962
async activate(
6063
proxyPort: number,
6164
options:
6265
| { action: 'intercept', hostId: string, targetId: string }
6366
): Promise<void> {
6467
if (options.action === 'intercept') {
65-
await interceptIosFridaTarget(
68+
const fridaSession = await interceptIosFridaTarget(
6669
this.usbmuxClient,
6770
options.hostId,
6871
options.targetId,
6972
this.config.https.certContent,
7073
proxyPort
7174
);
75+
76+
// Track this session, so we can close it to stop the interception later
77+
this.interceptedApps[proxyPort] = this.interceptedApps[proxyPort] ?? [];
78+
this.interceptedApps[proxyPort].push(fridaSession);
7279
} else {
7380
throw new Error(`Unknown Frida interception command: ${(options as any).action ?? '(none)'}`)
7481
}
7582
}
7683

7784
async deactivate(proxyPort: number): Promise<void | {}> {
85+
await Promise.all(this.interceptedApps[proxyPort]?.map(async fridaSession => {
86+
await killProcess(fridaSession).catch(() => {});
87+
}));
7888
}
7989

8090
async deactivateAll(): Promise<void | {}> {
91+
await Promise.all(
92+
Object.keys(this.interceptedApps)
93+
.map(port => this.deactivate(Number(port)))
94+
);
8195
}
8296

8397
}

0 commit comments

Comments
 (0)