Basic detour support
authornorly <ny-git@enpas.org>
Tue, 18 Jun 2013 07:47:33 +0000 (08:47 +0100)
committernorly <ny-git@enpas.org>
Tue, 18 Jun 2013 07:49:07 +0000 (08:49 +0100)
include/libelfu/modelops.h
src/elfucli.c
src/modelops/detour.c [new file with mode: 0644]
src/modelops/symtab.c

index cf11b203672bfc78cf26386b5e9ddf1abf9cc7b8..fec6821add902d67204b49f176eacdf29e78bd85 100644 (file)
@@ -11,6 +11,7 @@
 
 
 GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry);
+GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name);
 void elfu_mSymtabFlatten(ElfuElf *me);
 
 
@@ -54,4 +55,6 @@ ElfuElf* elfu_mFromElf(Elf *e);
 
 void elfu_mReladd(ElfuElf *me, const ElfuElf *mrel);
 
+void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to);
+
 #endif
index 0fd5a2d0ad752ec8af635123a301d4b8c532419a..cd8f0baa378d618dba1a2076e86706348ec124e1 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <getopt.h>
 #include <libelfu/libelfu.h>
 
@@ -19,6 +20,7 @@ static void printUsage(char *progname)
          "  -c, --check                    Do a few sanity checks and print any errors\n"
          "  -d, --dump                     Dump current model state (debug only)\n"
          "      --reladd        obj.o      Insert object file contents\n"
+         "      --detour        from,to    Write a jump to <to> at <from>\n"
          "  -o, --output        outfile    Where to write the modified ELF file to\n"
          "\n");
 }
@@ -42,6 +44,7 @@ int main(int argc, char **argv)
     {"input", 1, 0, 'i'},
     {"output", 1, 0, 'o'},
     {"reladd", 1, 0, 10001},
+    {"detour", 1, 0, 10002},
     {NULL, 0, NULL, 0}
   };
 
@@ -148,6 +151,41 @@ int main(int argc, char **argv)
           }
         }
         break;
+      case 10002:
+        if (!me) {
+          goto ERR_NO_INPUT;
+        } else {
+          GElf_Addr from;
+          GElf_Addr to;
+          char *second;
+
+          strtok_r(optarg, ",", &second);
+          printf("--detour: From '%s' to '%s'\n", optarg, second);
+
+
+          from = strtoul(optarg, NULL, 0);
+          if (from == 0) {
+            from = elfu_mSymtabLookupAddrByName(me, me->symtab, optarg);
+          }
+          if (from == 0) {
+            printf("--detour: Cannot parse argument 1, aborting.\n");
+            goto ERR;
+          }
+          printf("--detour: From %x\n", (unsigned)from);
+
+          to = strtoul(second, NULL, 0);
+          if (to == 0) {
+            to = elfu_mSymtabLookupAddrByName(me, me->symtab, second);
+          }
+          if (to == 0) {
+            printf("--detour: Cannot parse argument 2, aborting.\n");
+            goto ERR;
+          }
+          printf("--detour: To %x\n", (unsigned)to);
+
+          elfu_mDetour(me, from, to);
+        }
+        break;
       case '?':
       default:
         printUsage(progname);
diff --git a/src/modelops/detour.c b/src/modelops/detour.c
new file mode 100644 (file)
index 0000000..075d945
--- /dev/null
@@ -0,0 +1,51 @@
+#include <libelfu/libelfu.h>
+#include <string.h>
+
+static void* subFindByAddr(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+  GElf_Addr a = *(GElf_Addr*)aux1;
+
+  if (OVERLAPPING(ms->shdr.sh_addr, ms->shdr.sh_size, a, 1)) {
+    return ms;
+  }
+
+  /* Continue */
+  return NULL;
+}
+
+
+void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to)
+{
+  ElfuScn *ms;
+  GElf_Word scnoffset;
+  unsigned char detourcode[] = {0xe9, 0xfc, 0xff, 0xff, 0xff};
+
+  ms = elfu_mScnForall(me, subFindByAddr, &from, NULL);
+
+  if (!ms) {
+    ELFU_WARN("mDetour: Cannot find address %x in any section.\n",
+              (unsigned)from);
+    return;
+  }
+
+  if (ms->shdr.sh_type != SHT_PROGBITS) {
+    ELFU_WARN("mDetour: Cannot detour in non-PROGBITS section %s.\n",
+              elfu_mScnName(me, ms));
+    return;
+  }
+
+  scnoffset = from - ms->shdr.sh_addr;
+
+  if (ms->shdr.sh_size - scnoffset < 5) {
+    ELFU_WARN("mDetour: Not enough space to insert a detour.\n");
+    return;
+  }
+
+  ELFU_DEBUG("mDetour: Detouring at address %x in section %s to %x.\n",
+             (unsigned)from,
+             elfu_mScnName(me, ms),
+             (unsigned)to);
+
+  *(Elf32_Word*)(detourcode + 1) = to - from - 5;
+  memcpy((char*)ms->data.d_buf + scnoffset, detourcode, 5);
+}
index e62871fa8c70d642043147a43800578f4952d2b1..ef8443fab79cd1c03acd75160afadf8bc993ae06 100644 (file)
@@ -141,6 +141,52 @@ GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry)
 }
 
 
+/* Look up a value in the symbol table section *msst which is in *me. */
+GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name)
+{
+  ElfuSym *sym;
+
+  assert(me);
+  assert(msst);
+  assert(name);
+  assert(strlen(name) > 0);
+  assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
+
+  CIRCLEQ_FOREACH(sym, &msst->symtab.syms, elem) {
+    char *symname = ELFU_SYMSTR(msst, sym->name);
+
+    if (!strcmp(symname, name)) {
+      goto SYMBOL_FOUND;
+    }
+  }
+  return 0;
+
+
+  SYMBOL_FOUND:
+
+  switch (sym->type) {
+    case STT_NOTYPE:
+    case STT_OBJECT:
+    case STT_FUNC:
+      if (sym->scnptr) {
+        GElf_Addr a = sym->value;
+        a += me->ehdr.e_type == ET_REL ? sym->scnptr->shdr.sh_addr : 0;
+        return a;
+      } else if (sym->shndx == SHN_UNDEF) {
+        return 0;
+      } else if (sym->shndx == SHN_ABS) {
+        return sym->value;
+      } else {
+        ELFU_WARN("elfu_mSymtabLookupAddrByName: Symbol binding COMMON is not supported, using 0.\n");
+        return 0;
+      }
+      break;
+    default:
+      return 0;
+  }
+}
+
+
 
 /* Convert symtab from memory model to elfclass specific format */
 void elfu_mSymtabFlatten(ElfuElf *me)