frida / frida-node

Frida Node.js bindings
282 stars 66 forks source link

Question: how to know when spawned process exited? #77

Closed 0x5e closed 2 years ago

0x5e commented 2 years ago

Here's the example similar to frida-node/examples/interactive.js:

async function spawnExample() {
  const pid = await frida.spawn(['/bin/sleep', '10']);

  console.log(`[*] Spawned pid=${pid}`);

  // This is where you could attach (see below) and instrument APIs before you call resume()
  await frida.resume(pid);
  console.log('[*] Resumed');

  // TODO: wait until the process exited, and get exit code, stdout, stderr
}

Is there any thing similar to node:child_process.spawnSync?

0x5e commented 2 years ago

My workaround is infinity get process every 1 second until process exit, which is really not good:

  while (true) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    try {
      await device.getProcess(name);
    } catch (error) {
      // process exited
      break;
    }
  }
0x5e commented 2 years ago

I'm using node-ssh instead now.

oleavr commented 2 years ago

Hook up a callback to your Session object's detached signal.

0x5e commented 2 years ago

Thanks @oleavr , I have a test between frida.device.spawn and ssh.exec:


async function spawn(device, args) {

  const pid = await device.spawn(args);
  const session = await device.attach(pid);

  await new Promise((resolve, reject) => {

    function onDetached(reason) {
      if (reason === 'process-terminated') {
        resolve();
      } else {
        reject(new Error(reason));
      }
    }

    session.detached.connect(onDetached);
    device.resume(pid);

  });

  return;

}

async function test() {
  const host = '192.168.x.x';
  const device = await frida.getDeviceManager().addRemoteDevice(host);
  const ssh = new NodeSSH();
  await ssh.connect({
    host,
    username: 'root',
    privateKeyPath: path.join(process.env.HOME, '.ssh', 'id_rsa'),
  });

  let start, end;

  start = new Date();
  for (let i = 0; i < 5; i++) {
    await ssh.exec('/bin/ls', ['-alh', '/']);
  }
  end = new Date();
  console.log(`ssh.exec time: ${end - start} ms`);

  start = new Date();
  for (let i = 0; i < 5; i++) {
    await spawn(device, ['/bin/ls', '-alh', '/']);
  }
  end = new Date();
  console.log(`frida.device.spawn time: ${end - start} ms`);
}

run ls -alh / 5 times each, the result is:

ssh.exec time: 426 ms
frida.device.spawn time: 24131 ms

ssh.exec time: 396 ms
frida.device.spawn time: 28506 ms

ssh.exec time: 334 ms
frida.device.spawn time: 8766 ms

ssh.exec time: 441 ms
frida.device.spawn time: 8980 ms

Seems spawn --> attach --> onDetach --> resume cost much more time than I expected. a ls -alh / command cost 1.8 seconds in the best result.