Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Manage Emulators automatically #55

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
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
Prev Previous commit
Next Next commit
adapt examples
zner0L committed Nov 22, 2024
commit cb8abd22c007868d50efbc65387d620a9dbf9a27
66 changes: 43 additions & 23 deletions examples/multiple-apps.ts
Original file line number Diff line number Diff line change
@@ -7,18 +7,31 @@ import { pause, startAnalysis } from '../src/index';
// `npx tsx examples/multiple-apps.ts <emulator name> <snapshot name> <path to a folder of single APKs>`

(async () => {
const emulatorName = process.argv[2] || 'emulator-name';
const snapshotName = process.argv[3] || 'snapshot-with-setup-emu';
const apkFolder = process.argv[4] || 'path/to/app-files';
const apkFolder = process.argv[2];
const emulatorName = process.argv[3];
const snapshotName = process.argv[4];
zner0L marked this conversation as resolved.
Show resolved Hide resolved

if (!apkFolder) throw Error('Please provide a folder of APKs as the first argument.');

const analysis = await startAnalysis({
platform: 'android',
runTarget: 'emulator',
capabilities: ['frida', 'certificate-pinning-bypass'],
targetOptions: {
snapshotName,
emulatorName,
},
targetOptions:
emulatorName && snapshotName
? {
snapshotName,
emulatorName,
}
: {
createEmulator: {
infix: 'test',
variant: 'google_apis',
architecture: 'x86_64',
attemptRebuilds: 0,
apiLevel: 33,
},
},
});

await analysis.ensureDevice();
@@ -27,28 +40,35 @@ import { pause, startAnalysis } from '../src/index';
// so you can easily loop through an array of apps.
const apks = await readdir(apkFolder);
for (const apkFile of apks) {
const appAnalysis = await analysis.startAppAnalysis(path.join(apkFolder, apkFile) as `${string}.apk`);
try {
await analysis.ensureDevice();
zner0L marked this conversation as resolved.
Show resolved Hide resolved

const appAnalysis = await analysis.startAppAnalysis(path.join(apkFolder, apkFile) as `${string}.apk`);

await analysis.resetDevice();
// await analysis.ensureTrackingDomainResolution();
await analysis.resetDevice();
// await analysis.ensureTrackingDomainResolution();

await appAnalysis.installApp();
await appAnalysis.setAppPermissions();
await appAnalysis.startTrafficCollection();
await appAnalysis.startApp();
await appAnalysis.installApp();
await appAnalysis.setAppPermissions();
await appAnalysis.startTrafficCollection();
await appAnalysis.startApp();

// Pause to wait for the app to generate network traffic.
await pause(6_000);
// Pause to wait for the app to generate network traffic.
await pause(6_000);

await appAnalysis.stopTrafficCollection();
await appAnalysis.stopTrafficCollection();

const result = await appAnalysis.stop();
const result = await appAnalysis.stop();

console.dir(result, { depth: null });
// {
// app: { id: '<app id>', name: '<app name>', version: '<app version>', ... },
// traffic: { '2023-03-27T10:29:44.197Z': { log: ... } } <- The traffic collections are named by a timestamp and contain the collected requests in the HAR format.
// }
console.dir(result, { depth: null });
// {
// app: { id: '<app id>', name: '<app name>', version: '<app version>', ... },
// traffic: { '2023-03-27T10:29:44.197Z': { log: ... } } <- The traffic collections are named by a timestamp and contain the collected requests in the HAR format.
// }
} catch (error: any) {
// Handle the error here, e.g. queue the app for analysis again etc.
if (error.name === 'EmulatorError') console.error(error.message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling EmulatorError isn't enough. Here's what I got when closing the emulator during an analysis (having added an else throw error;):

file:///home/benni/coding/JS/tweasel/cyanoacrylate/node_modules/appstraction/node_modules/andromatic/node_modules/execa/lib/error.js:59
		error = new Error(message);
		        ^

Error: Command failed with exit code 1: /home/benni/.cache/andromatic/platform-tools/adb root
adb: unable to connect for root: device offline
    at makeError (file:///home/benni/coding/JS/tweasel/cyanoacrylate/node_modules/appstraction/node_modules/andromatic/node_modules/execa/lib/error.js:59:11)
    at handlePromise (file:///home/benni/coding/JS/tweasel/cyanoacrylate/node_modules/appstraction/node_modules/andromatic/node_modules/execa/index.js:124:26)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at Object.requireRoot (/home/benni/coding/JS/tweasel/cyanoacrylate/node_modules/appstraction/src/android.ts:299:17)
    at Object.overlayTmpfs (/home/benni/coding/JS/tweasel/cyanoacrylate/node_modules/appstraction/src/android.ts:339:38)
    at Object.removeCertificateAuthority (/home/benni/coding/JS/tweasel/cyanoacrylate/node_modules/appstraction/src/android.ts:841:9)
    at <anonymous> (/home/benni/coding/JS/tweasel/cyanoacrylate/src/index.ts:652:17)
    at async Promise.all (index 0)
    at stopTrafficCollection (/home/benni/coding/JS/tweasel/cyanoacrylate/src/index.ts:634:23)
    at Object.stopTrafficCollection (/home/benni/coding/JS/tweasel/cyanoacrylate/src/index.ts:863:33) {
  shortMessage: 'Command failed with exit code 1: /home/benni/.cache/andromatic/platform-tools/adb root',
  command: '/home/benni/.cache/andromatic/platform-tools/adb root',
  escapedCommand: '"/home/benni/.cache/andromatic/platform-tools/adb" root',
  exitCode: 1,
  signal: undefined,
  signalDescription: undefined,
  stdout: '',
  stderr: 'adb: unable to connect for root: device offline',
  failed: true,
  timedOut: false,
  isCanceled: false,
  killed: false
}

}
}

await analysis.stop();