phook - Pluggable run-time code injector


phook is a userspace tool which injects code into another application at runtime using ptrace().
It has a modular design to allow users use different plugins to make the target application do whatever they want.

With a little knowledge of assembly and C, people can write their own plugin.
A plugin skeleton is provided in the sources as well as useful functions to simplify plugin development, such as a basic code relocator.
If you are willing to write a phook module, you should read this file first: DEVELOPERS.

Default plugins are able to read and write into file descriptors belonging to other processes.
To find out more information about available plugins, read: PLUGINS.

If you want your modules to be added to the site and included into future releases, please submit them to the mail address at the bottom of the page.
Write some comments in your code :)
No binary-only plugins will be accepted, as you may imagine.



Requirements and installation:

Nothing special is required to compile phook. Just run make.

phook will search for its plugins in a couple of directories defined into phook.h.

    char *DEFAULT_PLUGIN_PATH[]={ \
        "plugins", \
        "/usr/lib/phook/plugins", \
        NULL };


Feel free to change or add something to the default directories, but remember to end the array with a NULL pointer, as you can see in the above example.
There is NO make install. Put the phook binary and the plugins directory wherever you want and remember to set DEFAULT_PLUGIN_PATH[] into phook.h accordingly.

You may need nasm to assemble the assembly code included in the sources, but this is UNNECESSARY unless you want to change something or develop a new plugin from scratch using the intel syntax.

To build even the assembly code, run:

        make world

I've included the assembly listing files (.lst) of my little programs, just in case you are suspicius and you want to see whether those strange strings, such as "\x5b\x89\xde\x81\xc3\x2c\", are going to completely erase your disk or something along these lines.
You are within your rights to be suspicious of code from strangers.



Usage:

phook accepts by default the following command-line options:

./phook -p|--pid PID -f|--fd FD [ -w|--write STRING | -l|--load PLUGIN_NAME
            -r|--read NUM_BYTES -o|--output FILE [ -t|--timeout TIMEOUT ] ]


You have to choose either --read, --write or --load.

--write STRING      * Write the string STRING to the file descriptor specified by --fd

--read NUM_BYTES      * Read NUM_BYTES bytes from the file descriptor specified by --fd

--load PLUGIN_NAME      * Use the plugin PLUGIN_NAME. Command line options depends upon the plugin.


When using --read or --write, the following options are mandatory (M):

M)    --pid    * The pid of the target application
M)    --fd    * The file descriptor you want to read/write from/to

With --read, you have the following options, which might be mandatory (M) or optional (O):

M)    --output    * Write the data stolen from the file descriptor to this output file
O)    --timeout    * Wait for data for the specified amount of seconds (integer). If timeout is 0, the plugin will wait *FOREVER*.

!!! IMPORTANT NOTE: WHILE READING FROM A FILE DESCRIPTOR, YOUR APPLICATION WILL HANG* UNTIL DATA IS RECEIVED OR THE TIMEOUT EXPIRES.
!!! REMEMBER THAT YOU ARE ACTUALLY STEALING DATA FROM THE FILE DESCRIPTOR AND THIS MEANS THAT YOUR TARGET APPLICATION WON'T BE ABLE TO READ THE DATA YOU'VE "STOLEN".
THIS CAN MAKE YOUR APPLICATION UTTERLY FAIL IN AN UNEXPECTED WAY.

*) The forkedread.so plugin prevents the target application from hanging. See below.



Well, let's start from a quite simple real example: you want to write into a network socket belonging to kvirc (which is a graphical IRC client).

$ ls -al /proc/`pidof kvirc`/fd | grep socket | cut -d " " -f 7-
22:23 12 -> socket:[715784]
22:23 13 -> socket:[762765]
22:23 3 -> socket:[715725]
22:23 4 -> socket:[715727]
22:23 9 -> socket:[715732]

715784, 762765, 715725, 715727 and 715732 are called inodes, while 12, 13, 3, 4 and 9 are file descriptors, in this case we can call them sockets

Since we're only interested in tcp sockets, we're going to read /proc/net/tcp:

$ SOCKETS="$(ls -al /proc/`pidof kvirc`/fd | egrep -o "socket:[[[:digit:]]+" | cut -d \[ -f 2)"
$ egrep "`echo $SOCKETS | tr " " "|"`" /proc/net/tcp
   11: xxxxxxxx:E432 yyyyyyyy:1A0B 01 00000000:00000000 00:00000000 00000000 1000 0 715784 1 caae5800 69 10 30 2 100
   13: xxxxxxxx:826E zzzzzzzz:1A0C 01 00000000:00000000 00:00000000 00000000 1000 0 762765 1 caae5400 74 10 30 2 2

We can see a connection from xxxxx, port E432 (58418), to yyyy, port 1A0B (6667) and another connection from xxxx, port 826E (33390), to zzzz, port 1A0C (6668).
Numbers are in hexadecimal, just convert them with a calculator, for example using bc:

$ bc
ibase=16
e432
58418

1A0B
6667

Netstat may also be really useful:

$ netstat -A inet -p kvirc -n | grep kvirc
tcp 0 0 xx.xx.xx.xx:58418 yyy.yyy.yyy.yyy:6667 ESTABLISHED3984/kvirc
tcp 0 0 xx.xx.xx.xx:33390 zzz.zzz.zzz.zzz:6668 ESTABLISHED3984/kvirc


We want to write to the socket connected to zzz.zzz.zzz.zzz:6668, and so the inode we're looking for is: 762765 (see the line prefixed by "13: " above. The prefix is not the file descriptor number!)

As we can see here: 13 -> socket:[762765]
13 is the socket number associated to inode 762765.

Finally we will start phook in WRITE MODE:

$ ./phook -p `pidof kvirc` -f 13 -w "
privmsg mynickonirc :wo, i'm writing this message from the console
"


Note how the " are used in order to send newlines to the irc server.


READ MODE works pretty much the same:

$ ./phook -p `pidof kvirc` -f 13 -r 1024 -o /tmp/blah -t 5

Here we're reading a maximum of 1024 bytes from file descriptor 13, with a timeout of 5 seconds.
If data is available within this amount of time, it will be placed into the file /tmp/blah.
If no data is received the time expires and NO OUTPUT files will be created.

**** REMEMBER TO SET A REASONABLE TIMEOUT SINCE WITH THE DEFAULT READ PLUGIN [not the forking one, see forkedread.so below] YOUR APPLICATION WILL ELSE HANG UNTIL DATA IS RECEIVED.
THE DEFAULT TIMEOUT IS ZERO, WHICH MEANS THAT THE APPLICATION WILL WAIT FOR SOME DATA FOREVER !!! ****




Plugins:     (send me your modules, I'll list them here!)

forkedread.so:

Example:

$ ./phook -p `pidof kvirc` -l forkedread.so -r 1024 -f 12 -o /tmp/blah


buffy.so:

Example:

$ ps aux | grep kvirc
asus 15688 0.2 10.0 61944 25812 ? Sl 14:22 0:55 kvirc -m
asus 20788 0.0 0.0 0 0 ? Z 20:51 0:00 [kvirc] <defunct>
asus 20814 0.0 0.2 2012 740 pts/1 S+ 20:52 0:00 grep kvirc

$ ./phook -p 15688 -l buffy.so -d 20788


*) I know that Buffy is the vampire and not the zombie slayer, but "vampire" processes don't officially exist yet, under *nix (although openoffice, firefox and other *big* software seem to provide the bloody definition of the word).
And no, I won't rename this plugin "chucknorris.so", the mighty Chuck deserves something better (I'm thinking about a thing that doesn't soil *his* name)



Downloads:


phook-0.2:   (latest)


Links:

The phook sourceforge project page is here.

Google



Contacts:

Please send feedback and bug reports to: