aboutsummaryrefslogtreecommitdiff
path: root/magic.c
diff options
context:
space:
mode:
Diffstat (limited to 'magic.c')
-rw-r--r--magic.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/magic.c b/magic.c
new file mode 100644
index 0000000..c99fb06
--- /dev/null
+++ b/magic.c
@@ -0,0 +1,129 @@
+/** The MIT License (MIT)
+
+Copyright (c) 2016 Camil Staps
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ffi.h>
+#include <elf.h>
+#include <libelf.h>
+
+#include "magic.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);
+}
+