Skip to content

Instantly share code, notes, and snippets.

@FergusInLondon
Last active September 24, 2021 16:20
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FergusInLondon/7ab987b4051a1e594d47903d6ef7ac4c to your computer and use it in GitHub Desktop.
Save FergusInLondon/7ab987b4051a1e594d47903d6ef7ac4c to your computer and use it in GitHub Desktop.
LD_PRELOAD Code Injection and Hooking
/* filesnooper.c - Fergus In London <fergus@fergus.london>
*
* Similar to snoopy.c, wrote to scratch an itch and demonstrate how LD_PRELOAD
* can be used for injecting code and/or hooking/wrapping around function calls.
*
* This is actually a good example, because if you try and use it with different
* ways of writing files, you'll see that to actually do this effectively you'd
* need to examine the target binary with strace, and potentially implement
* signatures from other libraries. (i.e a binary calling fprintf() may not be
* be effected by this.)
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define MAX_FILE_PATH 255
#define FILE_TARGET "secret.txt"
static ssize_t (*real_write)(int fd, const void *buf, size_t count) = NULL;
ssize_t write(int fildes, const void *buf, size_t nbytes) {
// Ignore STDOUT and STDERR
if (fildes < 3){
goto passthrough;
}
// Determine filepath via the file descriptor
char linkpath[MAX_FILE_PATH];
sprintf(linkpath, "/proc/self/fd/%d", fildes);
char filepath[MAX_FILE_PATH];
ssize_t pathLength = readlink(linkpath, filepath, MAX_FILE_PATH);
// Check that the path is valid and readlink worked, additionally check filename
if ((pathLength < 0) || (strstr(filepath, FILE_TARGET) == NULL)){
goto passthrough;
}
// Filename matches, so log out buffer.
printf("Looks like we got ourselves a secret here...\n");
printf("[Message] %s\n", buf);
passthrough:
if (real_write == NULL) real_write = dlsym(RTLD_NEXT, "write");
real_write(fildes, buf, nbytes);
}
/* test.c - example target for filesnooper.c */
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char **argv) {
int sec_desc = open("/tmp/secret.txt", O_WRONLY | O_APPEND);
int std_desc = open("/tmp/boring.txt", O_WRONLY | O_APPEND);
write(sec_desc, "This is a secret.\n", 36);
write(std_desc, "This is a NOT a secret.\n", 36);
return 0;
}
@FergusInLondon
Copy link
Author

$ gcc -fPIC -shared -o libwrite.so filesnooper.c -ldl
$ gcc -o t test.c
$ LD_PRELOAD=/home/fmorrow/libwrite.so ./t
  Looks like we got ourselves a secret here...
  [Message] This is a secret.

$ 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment