mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-03-21 18:04:10 -05:00
Add an option to set how the app is started
This commit is contained in:
parent
56a991b03b
commit
31926d83f4
|
|
@ -38,6 +38,10 @@ export function builder(yargs: Argv<ParentArguments>) {
|
|||
describe: 'Path to the frida-server executable on the device',
|
||||
type: 'string',
|
||||
default: '/data/local/tmp/frida-server',
|
||||
}).option('start-method', {
|
||||
describe: 'Method to ensure the app is running (one of "spawn", "none", "activity", "service")',
|
||||
type: 'string',
|
||||
default: 'service',
|
||||
}).option('strict-validate', {
|
||||
describe: 'Validate data exactly matches the format that would be generated by Nintendo\'s Android app',
|
||||
type: 'boolean',
|
||||
|
|
@ -55,6 +59,21 @@ export function builder(yargs: Argv<ParentArguments>) {
|
|||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
enum StartMethod {
|
||||
/** Spawn the app process with Frida, even if the app is already running (recommended) */
|
||||
SPAWN,
|
||||
/** Start the app's main activity using the am command */
|
||||
ACTIVITY,
|
||||
/**
|
||||
* Start a background service using the am command (default)
|
||||
* This tricks Android into not killing the app for some reason and allows the process to be started
|
||||
* in the background.
|
||||
*/
|
||||
SERVICE,
|
||||
/** Do not attempt to start the app - if it is not already running the server will fail */
|
||||
NONE,
|
||||
}
|
||||
|
||||
interface PackageInfo {
|
||||
name: string;
|
||||
version: string;
|
||||
|
|
@ -101,12 +120,18 @@ interface FResult {
|
|||
}
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const start_method =
|
||||
argv.startMethod === 'spawn' ? StartMethod.SPAWN :
|
||||
argv.startMethod === 'activity' ? StartMethod.ACTIVITY :
|
||||
argv.startMethod === 'service' ? StartMethod.SERVICE :
|
||||
StartMethod.NONE;
|
||||
|
||||
await mkdirp(script_dir);
|
||||
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
await setup(argv);
|
||||
await setup(argv, start_method);
|
||||
|
||||
let {session, script} = await attach(argv);
|
||||
let {session, script} = await attach(argv, start_method);
|
||||
let ready: Promise<void> | null = null;
|
||||
|
||||
let api: {
|
||||
|
|
@ -144,7 +169,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
|||
|
||||
debug('Attempting to reconnect to the device');
|
||||
|
||||
ready = attach(argv).then(async a => {
|
||||
ready = attach(argv, start_method).then(async a => {
|
||||
ready = null;
|
||||
session = a.session;
|
||||
script = a.script;
|
||||
|
|
@ -406,12 +431,14 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
|||
|
||||
const frida_script = `
|
||||
const perform = callback => new Promise((rs, rj) => {
|
||||
Java.scheduleOnMainThread(() => {
|
||||
try {
|
||||
rs(callback());
|
||||
} catch (err) {
|
||||
rj(err);
|
||||
}
|
||||
Java.perform(() => {
|
||||
Java.scheduleOnMainThread(() => {
|
||||
try {
|
||||
rs(callback());
|
||||
} catch (err) {
|
||||
rj(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -520,6 +547,7 @@ rpc.exports = {
|
|||
|
||||
const setup_script = (options: {
|
||||
frida_server_path: string;
|
||||
start_method: StartMethod;
|
||||
}) => `#!/system/bin/sh
|
||||
|
||||
# Ensure frida-server is running
|
||||
|
|
@ -534,10 +562,16 @@ fi
|
|||
|
||||
sleep 1
|
||||
|
||||
${(options.start_method === StartMethod.ACTIVITY ? `
|
||||
# Ensure the app is running
|
||||
echo "Starting com.nintendo.znca in foreground"
|
||||
am start-activity com.nintendo.znca/com.nintendo.coral.ui.boot.BootActivity
|
||||
` : options.start_method === StartMethod.SERVICE ? `
|
||||
# Ensure the app is running
|
||||
echo "Starting com.nintendo.znca"
|
||||
am start-foreground-service com.nintendo.znca/com.google.firebase.messaging.FirebaseMessagingService
|
||||
am start-service com.nintendo.znca/com.google.firebase.messaging.FirebaseMessagingService
|
||||
` : '').trim()}
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
echo "Failed to start com.nintendo.znca"
|
||||
|
|
@ -554,7 +588,7 @@ echo "Releasing wake lock"
|
|||
echo androidzncaapiserver > /sys/power/wake_unlock
|
||||
`;
|
||||
|
||||
async function setup(argv: ArgumentsCamelCase<Arguments>) {
|
||||
async function setup(argv: ArgumentsCamelCase<Arguments>, start_method: StartMethod) {
|
||||
debug('Connecting to device %s', argv.device);
|
||||
let co = execFileSync('adb', [
|
||||
'connect',
|
||||
|
|
@ -583,11 +617,12 @@ async function setup(argv: ArgumentsCamelCase<Arguments>) {
|
|||
|
||||
await pushScript(argv.device, setup_script({
|
||||
frida_server_path: argv.fridaServerPath,
|
||||
start_method,
|
||||
}), '/data/local/tmp/android-znca-api-server-setup.sh');
|
||||
await pushScript(argv.device, shutdown_script, '/data/local/tmp/android-znca-api-server-shutdown.sh');
|
||||
}
|
||||
|
||||
async function attach(argv: ArgumentsCamelCase<Arguments>) {
|
||||
async function attach(argv: ArgumentsCamelCase<Arguments>, start_method: StartMethod) {
|
||||
const frida = await import('frida');
|
||||
type Session = import('frida').Session;
|
||||
|
||||
|
|
@ -602,11 +637,17 @@ async function attach(argv: ArgumentsCamelCase<Arguments>) {
|
|||
let session: Session;
|
||||
|
||||
try {
|
||||
const process = await device.getProcess('Nintendo Switch Online');
|
||||
const process = start_method === StartMethod.SPAWN ?
|
||||
{pid: await device.spawn('com.nintendo.znca')} :
|
||||
await device.getProcess('Nintendo Switch Online');
|
||||
|
||||
debug('process', process);
|
||||
|
||||
session = await device.attach(process.pid);
|
||||
|
||||
if (start_method === StartMethod.SPAWN) {
|
||||
await device.resume(session.pid);
|
||||
}
|
||||
} catch (err) {
|
||||
debug('Could not attach to process', err);
|
||||
throw new Error('Failed to attach to process');
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user