First thing I did was make a guinea pig program that needs to take its input from a file specified at the command line. The guinea pig program is not able to read from stdin. The objective is to alter the C Standard Library so that the guinea pig program will be able to read from stdin without having to alter the guinea pig program's code.
I made a simply little guinea pig program that would append a single digit to passwords, it's called append_digit.
Let's say for instance that you started off with the following dictionary file:
Well after you run this through append_digit you'd end up with:
Code:
dog0
dog1
dog2
dog3
dog4
dog5
dog6
dog7
dog8
dog9
cat0
cat1
cat2
cat3
cat4
cat5
cat6
cat7
cat8
cat9
fish0
fish1
fish2
fish3
fish4
fish5
fish6
fish7
fish8
fish9
For anyone who wants to play around with this, you can download the dictionary file and the source code for append_digit and try it out as follows:
Code:
cd
mkdir hijack_fopen
cd hijack_fopen
wget http://virjacode.com/projects/hijack_fopen/dict.txt
wget http://virjacode.com/projects/hijack_fopen/append_digit.c
gcc append_digit.c -o append_digit
./append_digit dict.txt
Now let's take a quick look at the code for append_digit:
Code:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[62+1+1]; /* Buffer to hold line taken from file:
63 for password (not 64 because we're appending a digit)
1 for newline character
1 for null terminator*/
FILE *dict = fopen(argv[1],"r"); /* Open the dictionary file */
if (!dict)
{
puts("Unable to open dictionary file");
return 0;
}
while ( fgets(buffer,sizeof buffer,dict) ) /* Attempt to read a line */
{
unsigned i = 0;
if (buffer[0] == '\0' || buffer[0] == '\n' ) /* Skip line if bad string */
continue;
if (buffer[strlen(buffer)-1] == '\n')
buffer[strlen(buffer)-1] = '\0'; /* Remove the trailing new line if present */
do printf("%s%u\n",buffer,i); /* Print out the new password with number appended */
while (++i != 10);
}
fclose(dict);
}
As you can see, the code reads passwords from a file, and there's no way of getting it to read passwords from stdin.
........so here's where the hijacking comes in. We need to hijack the call made to fopen, and replace it with a call to the following function:
Code:
FILE *fopen_HIJACKED(const char *filename, const char *mode)
{
if (!strcmp(filename,"GIVE_ME_STDIN"))
return stdin;
return fopen(filename,mode);
}
If the input file is specified as "GIVE_ME_STDIN", then as you can see, it will return stdin.
But how exactly do we make sure that this hijacked function gets called... well one method is to use a preproccesor macro:
Code:
#define fopen(filename,mode) fopen_HIJACKED(filename,mode)
If this preprocessor macro were to come into force, then wherever the code contains fopen, it gets replace with fopen_HIJACKED.
But as I said, we don't want to edit the source code for append_digit, so where will we put this preprocessor macro? We navigate to where fopen is declared, in the C Standard Library in a little header file called stdio.h.
We need to open up /usr/include/stdio.h and append the following to the end of it:
Code:
#include <string.h>
inline FILE *fopen_HIJACKED(const char *filename, const char *mode)
{
if (!strcmp(filename,"GIVE_ME_STDIN"))
return stdin;
return fopen(filename,mode);
}
If you want to edit your own stdio.h, then do this:
Code:
sudo cp /usr/include/stdio.h /usr/include/stdio.h.original
wget http://virjacode.com/projects/hijack_fopen/tail_of_stdio.h
sudo sh -c "cat tail_of_stdio.h >> /usr/include/stdio.h"
After we do this, we recompile append_digit, and then try to get it to read from stdin as follows:
Code:
gcc append_digit.c -o append_digit
cat dict.txt | ./append_digit GIVE_ME_STDIN
...and it works!
It won't be as simple though for bigger programs (you'll get problems such as multiple-definition errors if stdio.h is included more than once). Also, there will be more complications if other functions in the fopen family are called.
If anyone can think of a program that they'd like to add this functionality to, then post here and I'll give it a go.
Now don't forget to put your stdio.h file back to the way it was:
Code:
sudo cp /usr/include/stdio.h.original /usr/include/stdio.h