diff options
author | Camil Staps | 2016-01-31 14:46:55 +0100 |
---|---|---|
committer | Camil Staps | 2016-01-31 14:46:55 +0100 |
commit | 2fb8dc632b4c007033d9a40c6d6ab060d1ea1fe3 (patch) | |
tree | 1877df4581887fd0e79aa396b64e61b28ada87a3 /hacking.c | |
parent | Makefile (diff) |
Working version
Diffstat (limited to 'hacking.c')
-rw-r--r-- | hacking.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/hacking.c b/hacking.c new file mode 100644 index 0000000..3b42819 --- /dev/null +++ b/hacking.c @@ -0,0 +1,106 @@ +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <ffi.h> +#include <elf.h> +#include <libelf.h> + +#include "hacking.h" + +Callable* newCallable() { + Callable* c = malloc(sizeof(Callable)); + c->cif = malloc(sizeof(ffi_cif)); + c->fp = NULL; + return c; +} + +Callable* funcnameToCallable(char* fname, + uint8_t n_params, ffi_type** parameter_types, ffi_type* return_type) { + // http://stackoverflow.com/a/1118808/1544337 + Elf64_Shdr * shdr; + Elf64_Ehdr * ehdr; + Elf * elf; + Elf_Scn * scn; + Elf_Data * data; + int cnt; + void (*fp)() = NULL; + Callable* callable = newCallable(); + if (callable == NULL) return NULL; + + int fd = 0; + + /* This is probably Linux specific - Read in our own executable*/ + if ((fd = open("/proc/self/exe", O_RDONLY)) == -1) + exit(1); + + elf_version(EV_CURRENT); + + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { + fprintf(stderr, "file is not an ELF binary\n"); + exit(1); + } + /* Let's get the elf sections */ + if (((ehdr = elf64_getehdr(elf)) == NULL) || + ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) || + ((data = elf_getdata(scn, NULL)) == NULL)) { + fprintf(stderr, "Failed to get SOMETHING\n"); + exit(1); + } + + /* Let's go through each elf section looking for the symbol table */ + for (cnt = 1, scn = NULL; (scn = elf_nextscn(elf, scn)); cnt++) { + if ((shdr = elf64_getshdr(scn)) == NULL) + exit(1); + + if (shdr->sh_type == SHT_SYMTAB) { + char *name; + data = 0; + if ((data = elf_getdata(scn, data)) == 0 || data->d_size == 0) { + fprintf(stderr, "No data in symbol table\n"); + continue; + } + + Elf64_Sym *esym = (Elf64_Sym*) data->d_buf; + Elf64_Sym *lastsym = (Elf64_Sym*) ((char*) data->d_buf + data->d_size); + + /* Look through all symbols */ + for (; esym < lastsym; esym++) { + if ((esym->st_value == 0) || + (ELF64_ST_BIND(esym->st_info)== STB_WEAK) || + (ELF64_ST_BIND(esym->st_info)== STB_NUM) || + (ELF64_ST_TYPE(esym->st_info)!= STT_FUNC)) + continue; + + name = elf_strptr(elf,shdr->sh_link , (size_t)esym->st_name); + + if(!name){ + fprintf(stderr,"%s\n",elf_errmsg(elf_errno())); + } else if(strcmp(fname, name) == 0 ) { + fp = (void(*)(void)) esym->st_value; + } + } + + /* Call and hope we don't segfault!*/ + if (fp != NULL) { + if (ffi_prep_cif(callable->cif, FFI_DEFAULT_ABI, n_params, return_type, parameter_types) == FFI_OK) { + elf_end(elf); + callable->fp = fp; + return callable; + } + } + } + } + + elf_end(elf); + + fprintf(stderr, "No function %s found\n", fname); + + return NULL; +} + +void call(Callable* callable, void** parameters, void* return_val) { + ffi_call(callable->cif, callable->fp, return_val, parameters); +} + |