I was wondering if there was an API, however obscure it would be, that would allow someone to send data to another process's stdin
stream under Mac OS X. Under Linux, if I remember correctly, you can use the filesystem in /proc
to access these streams (with the correct permissions, of course).
I dunno. Mach ports, anyone?
Unfortunately, I don't believe you can do that -- MacPorts are all userland, and the operation you require needs (either a lot of trickery, see below, or) kernel cooperation, which, I believe, isn't forthcoming. For example, Mac OSX Internals, a System Approach in the section on file-descriptor passing, says
The descriptor is local to the process
in that it is meaningful only in the
process that acquired the
descriptorsay, by opening a file. In
particular, a process A cannot access
a file that is open in another process
B by simply using the value of the
descriptor representing that file in
B.
and then goes on to describe how FDs are sent.
The "trickery" part would require you getting some code of yours to run (either in userland or as part of the kernel) within the other process.
For example, you could do it in userland by patching the binary file that's their executable -- find any instruction early in its startup path that's sure to be executed, and put in its stead a jump to your own code which sends the FD to your watching daemon process, executes the patched-away instruction, then jumps back to the other process's normal sequential flow.
To do it at kernel level would require similar patches to either the kernel code itself, or to code which the kernel loads and runs with entire, unverified trust (so they can hijack an unrelated process's file descriptor table entries) -- I sure hope there are no such code paths left in Mac OS X (since their main use would no doubt be by viruses, trojan horses, and other malware of all kinds) but, if there are and you can find them, this might be a more general solution than patching every single binary executable of interest.
Back to userland, another fairly general approach might be to patch dynamically loaded libraries that all processes of interest load, instead of patching the various processes' several executables.
Just a thought, but couldn't you make a pipe, and redirect that (named) pipe to the standard input of the process when starting that process?
Roughly somethink like
mkfifo MYPIPE
Prog < MYPIPE
echo "test" > MYPIPE
If you are running the target process at a terminal then you can use writevt, whose source code is here.
Suppose for example that you are running the "cat" command on terminal ttys000.
On Terminal 1:
$ tty
/dev/ttys000
$ cat
On Terminal 2:
$ sudo ./writevt /dev/ttys000 'Hello!^M'
The ^M
above is a control character. On my mac, you can input this character by typing Ctrl-V
followed by Ctrl-<enter>
.
Here is the result at Terminal 1:
$ tty
/dev/ttys000
$ cat
Hello!
Hello!
The writevt program can be compiled from the writevt.c source file with gcc:
$ gcc -o writevt writevt.c
Presuming that it's with the users permission (i.e. you want to capture information from a third party app, to redirect to another app, like Rogue Amoeba's audio apps or some video stream capture apps) then I'd say you either want to look at kernel extensions, or Input Managers.
(See also fscript anywhere, SIMBL and Application Enhancer - all examples of software that inject functionality into third party apps).
A lot of older techniques for user driven code injection have been restricted in 10.6 (input managers are harder to install, for instance).
If you're interested in user input rather than stdin, the replacement Input Method Kit may actually be 'good enough' - classically, Input Managers have been used to inject all sorts of code into applications.
On the other hand, if you want to do this without user permission (i.e. key logging) then you're into hacking. There probably is a chain of as yet unpatched vulnerabilities that can be combined to do what you want to do, but whoever knows it is likely to be making money from it.
Well, technically you could mach-inject a thread into the target process and then have it send a dup of the stdin file descriptor back to you… But you probably shouldn't. :-)
What are you really trying to do?