1

So that I can do some injecting and interposing using the inject_and_interpose code, I need to way to get the PID of a newly-launched process (a typical closed-source user application) before it actually executes.

To be clear, I need to do better than just "notice it quickly"--I can't be polling, or receiving some asynchronous notification that means that the process has already been executing for a few milliseconds by the time I take action.

I need to have a chance to do my injecting and interposing before a single statement executes.

I'm open to writing a background process that gets synchronously notified when a process by a particular name comes into existence. I'm also open to writing a launcher application that in turn fires up the target application.

Any solution needs to support 64-bit code, at a minimum, under 10.5 (Leopard) through 10.8 (Mountain Lion).

In case this proves to be painfully simple, I'll go ahead and admit that I'm new to OS X :) Thanks!

bland328
  • 319
  • 1
  • 4
  • 13
  • On windows, you do this by starting the process in a suspended state, by setting the `CREATE_SUSPENDED` flag when calling `CreateProcess`. Then you call `ResumeThread` once you've done whatever tricky stuff to it you want. Maybe this will help you look in the right direction. – Jonathon Reinhart Jul 27 '12 at 00:13
  • I'm pretty sure there's no way to synchronously intercept a newly-launched processes before it's so much as executed a single statement unless you're in control of the process launch. – Lily Ballard Jul 27 '12 at 00:14
  • @JonathonReinhart, I've been involved in doing this Windows, but no luck under OS X yet, so "looking in the right direction" is what I'm attempting here ;) Thanks! – bland328 Jul 27 '12 at 00:19
  • @KevinBallard, can you expound on "in control of the process launch"? Thanks. – bland328 Jul 27 '12 at 00:20
  • @briguy328: If you are launching the process yourself, you can cause it to wait for a debugger before doing anything (which will give you time to do whatever you want). But if your code is not launching the process, you cannot do this. – Lily Ballard Jul 27 '12 at 00:52
  • Not an answer.. but maybe you could do what you want with DYLD_INSERT_LIBRARIES? –  Jul 27 '12 at 01:06
  • @KevinBallard: Thanks...I like the sound of that. Can you give me a bit more of a push in the right direction? What system call can I use to cause the launched process to wait for a debugger? – bland328 Jul 27 '12 at 01:30

1 Answers1

1

I know how to do this on Linux, so maybe it would be the same(-ish) on OSX.

You first call fork() to duplicate your process. The return value of fork() indicates whether you are the parent or child. The parent gets the pid of the child process, and the child gets zero.

So then, the child calls exec() to actually begin executing the new executable. With the use of a pipe created before the call to fork, the child could wait on the parent to do whatever it needed before execing the new execuatable.

pid_t pid = fork();
if (pid == -1) {
    perror("fork");
    exit(1);
}
if (pid > 0) {
    // I am the parent, and pid is the PID of the child process.

    //TODO: If desired, somehow notify child to proceed with exec
}
else {
    // I am the child.

    //TODO: If desired, wait no notification from parent to continue

    execl("path/to/executable", "executable", "arg1", NULL);

    // Should never get here.
    fprintf(stderr, "ERROR: execl failed!\n");  
}
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • I don't quite follow, Jonathon. How does this enable me to get the PID of the "new executable" before it executes? Are you saying that the parent will get from fork() the PID of the child process, and the exec()-ed process will run in the context of the child process, and therefore have that PID? – bland328 Jul 27 '12 at 00:24
  • Yes, exactly. That's how exec works; it *replaces* the currently executing process image. – Jonathon Reinhart Jul 27 '12 at 00:47
  • 1
    @JonathonReinhart: I think you're answering the wrong question. The OP seems to have a situation where a user is double-clicking on an app in the finder, and he wants to detect this and inject his own code into the newly-launched process before it does anything. He does not control the launching of that process. – Lily Ballard Jul 27 '12 at 00:53
  • @JonathonReinhart, thanks for the code! Unless I'm missing a trick, though, this approach creates a new problem for my particular purposes--instead of learning the PID too late, after the process is executing, I'll learn the PID too early, before the process I want to inject and interpose even exists. Sound right to you? – bland328 Jul 27 '12 at 00:55
  • @KevinBallard, I did say in my original question that I was open to writing a "launcher" in order to accomplish this. What I wrote about double-clicking in the Finder certainly confused the issue, though, so I'll edit that out right now. – bland328 Jul 27 '12 at 00:57
  • @briguy328 I don't know what you're asking for is possible. It sounds like you're asking for a callback that the OS makes that says "hey, I just created this process, and am about to start it, here's his PID, and when you return to me I'll start him". You're not going to get that in userland. – Jonathon Reinhart Jul 27 '12 at 04:10
  • @briguy328 I'm thinking what I've given you, combined with some `ptrace` would do the trick. You could somehow exec, and then start to step into it... – Jonathon Reinhart Jul 27 '12 at 04:11