Last active
May 14, 2022 03:02
-
-
Save andyrudoff/aa37894bad22baf7ccaa to your computer and use it in GitHub Desktop.
interpose on libc syscalls by code patching
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.o | |
tester | |
elmo.so |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This is a quickie example of how to interpose on libc syscalls. | |
Example is x86_64 only. | |
To run: make test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* elmo.c -- (e)xecution (l)ocation (mo)difier | |
* | |
* Force load this using LD_PRELOAD. | |
*/ | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <err.h> | |
#include <sys/types.h> | |
#include <sys/mman.h> | |
#include <sys/reg.h> | |
#include <sys/user.h> | |
#include <sys/wait.h> | |
#include <sys/syscall.h> | |
#include <sys/uio.h> | |
/* | |
* elmo_write -- this gets control when libc's write() is called | |
* | |
* If you print something from this routine, you'll get infinite recursion. | |
*/ | |
static ssize_t | |
elmo_write(int fd, const void *buf, size_t count) | |
{ | |
return syscall(SYS_write, fd, buf, count); | |
} | |
/* | |
* elmo_read -- this gets control when libc's read() is called | |
*/ | |
static ssize_t | |
elmo_read(int fd, void *buf, size_t count) | |
{ | |
ssize_t retval; | |
fprintf(stderr, "elmo_read(%d, %p, %zu)", fd, buf, count); | |
retval = syscall(SYS_read, fd, buf, count); | |
fprintf(stderr, " = %zu\n", retval); | |
return retval; | |
} | |
/* | |
* patch -- hot patch the code at "from" to jump to "to" | |
* | |
* This is x86_64 specific. | |
* | |
* The code at "from" is overwritten to contain a jump instruction to | |
* the new routine at "to". The patched routine is destroyed -- you never | |
* jump back to it. Instead, the new routine is expected to use syscall(2) | |
* to perform the function of the old routine as necessary. | |
* | |
* The mprotect() call could be optimized not to change protections more | |
* than once on the same page. | |
*/ | |
static void | |
patch(void *from, void *to) | |
{ | |
unsigned char *p = (unsigned char *)from; | |
unsigned long long pgbegin = (unsigned long long)from & PAGE_MASK; | |
unsigned long long pgend = ((unsigned long long)from + 12) & PAGE_MASK; | |
/* allow writes to the normally read-only code pages */ | |
if (mprotect((void *) pgbegin, pgend - pgbegin + PAGE_SIZE, | |
PROT_READ|PROT_WRITE|PROT_EXEC) < 0) | |
err(1, "elmo mprotect"); | |
p[0] = 0x49; /* movabs */ | |
p[1] = 0xbb; /* %r11 */ | |
memcpy(&p[2], &to, 8); /* 64-bit abs value */ | |
p[10] = 0x41; /* jmp */ | |
p[11] = 0xff; /* jmp */ | |
p[12] = 0xe3; /* *%r11 */ | |
} | |
/* | |
* elmo_constructor -- constructor for elmo library | |
* | |
* Called automatically by the run-time loader. | |
*/ | |
__attribute__((constructor)) | |
static void | |
elmo_constructor(void) | |
{ | |
patch((void *) write, (void *) elmo_write); | |
patch((void *) read, (void *) elmo_read); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Makefile for elmo | |
# | |
CFLAGS = -std=gnu99 -Wall -Werror -fPIC | |
all: elmo.so tester | |
tester: tester.o | |
$(CC) -o tester tester.o | |
elmo.so: elmo.o | |
$(CC) -Wl,-z,relro -shared -Wl,-soname,elmo.so -o elmo.so elmo.o | |
test: all | |
LD_PRELOAD=elmo.so LD_LIBRARY_PATH=. ./tester | |
clobber: clean | |
rm -f elmo.so tester | |
clean: | |
rm -f *.o core a.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* trivial program for testing | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
int | |
main(int argc, char *argv[]) | |
{ | |
printf("hello from main.\n"); | |
FILE *fp = fopen("/etc/passwd", "r"); | |
char buf[8192]; | |
fgets(buf, 8192, fp); | |
printf("read line from /etc/passwd: %s", buf); | |
fclose(fp); | |
exit(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment