Implement mInsertAfter, for post-.data injection
authornorly <ny-git@enpas.org>
Fri, 1 Mar 2013 18:59:57 +0000 (18:59 +0000)
committernorly <ny-git@enpas.org>
Fri, 1 Mar 2013 18:59:57 +0000 (18:59 +0000)
include/libelfu/modelops.h
include/options.h
src/main.c
src/model/insert.c
src/options.c

index c89630f3aed9b07a98ea6e849728a0de8b130474..d256b07c8c387ed7ece085e44f41d848dd94ebb7 100644 (file)
@@ -19,5 +19,6 @@ ElfuElf* elfu_mFromElf(Elf *e);
 
 
 GElf_Xword elfu_mInsertBefore(ElfuElf *me, GElf_Off off, GElf_Xword size);
+GElf_Xword elfu_mInsertAfter(ElfuElf *me, GElf_Off off, GElf_Xword size);
 
 #endif
index ee9d612780c026d6798c5ec21b48db10018f2a92..f92298f788c1937a29ac11dea0d9e382c239aee4 100644 (file)
@@ -10,6 +10,8 @@ typedef struct {
   int printSections;
   unsigned insertBeforeOffs;
   unsigned insertBeforeSz;
+  unsigned insertAfterOffs;
+  unsigned insertAfterSz;
 } CLIOpts;
 
 
index 4467a2cbcc995887a7ba88f4a5100e687b66f387..1e06d2998bca0642143bbb2deee1a51aaab14ed5 100644 (file)
@@ -74,6 +74,10 @@ int main(int argc, char **argv)
         elfu_mInsertBefore(me, opts.insertBeforeOffs, opts.insertBeforeSz);
       }
 
+      if (opts.insertAfterSz) {
+        elfu_mInsertAfter(me, opts.insertAfterOffs, opts.insertAfterSz);
+      }
+
       elfu_mCheck(me);
       printf("Output model checked.\n");
       elfu_mToElf(me, hOut.e);
index 2086c6e26659268ae0cbc2cb4ce65f743115d19c..b299391a59577d095e23d27ff3e13de1697c5f66 100644 (file)
@@ -4,6 +4,9 @@
 #include <libelfu/libelfu.h>
 
 
+// TODO: Take p_align into account
+
+
 
 /*
  * Insert space at a given position in the file by moving everything
@@ -24,8 +27,6 @@ GElf_Xword elfu_mInsertBefore(ElfuElf *me, GElf_Off off, GElf_Xword size)
 
   assert(me);
 
-  // TODO: Take p_align into account
-
   /* Move SHDRs and PHDRs */
   if (me->ehdr.e_shoff >= off) {
     me->ehdr.e_shoff += size;
@@ -46,8 +47,6 @@ GElf_Xword elfu_mInsertBefore(ElfuElf *me, GElf_Off off, GElf_Xword size)
       /* mp->phdr.p_offset < off */
 
       if (off < end) {
-        /* Mark this as a modified area */
-
         /* Insertion in the middle of PHDR, so let it span the new data */
         mp->phdr.p_filesz += size;
         mp->phdr.p_memsz += size;
@@ -109,3 +108,102 @@ GElf_Xword elfu_mInsertBefore(ElfuElf *me, GElf_Off off, GElf_Xword size)
 
   return size;
 }
+
+
+
+/*
+ * Insert space at a given position in the file by moving everything
+ * after it towards the end of the file, and towards higher memory
+ * regions where it is mapped.
+ *
+ * off must not be in the middle of any data structure, such as
+ * PHDRs, SHDRs, or sections. Behaviour is undefined if it is.
+ *
+ * PHDRs will be patched such that everything AFTER off is shifted to
+ * higher addresses, making space for the new data in-between.
+ */
+GElf_Xword elfu_mInsertAfter(ElfuElf *me, GElf_Off off, GElf_Xword size)
+{
+  ElfuScn *ms;
+  ElfuPhdr *mp;
+
+  assert(me);
+
+/* Move SHDRs and PHDRs */
+  if (me->ehdr.e_shoff >= off) {
+    me->ehdr.e_shoff += size;
+  }
+
+  if (me->ehdr.e_phoff >= off) {
+    me->ehdr.e_phoff += size;
+  }
+
+  /* Patch PHDRs to include new data */
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    GElf_Off end = mp->phdr.p_offset + mp->phdr.p_filesz;
+
+    if (mp->phdr.p_offset >= off) {
+      /* Insertion before PHDR's content, so it's shifted. */
+      mp->phdr.p_offset += size;
+
+      /* It may also need to be remapped. See second pass below. */
+    } else {
+      /* mp->phdr.p_offset < off */
+
+      if (off < end) {
+        /* Insertion in the middle of PHDR, so let it span the new data */
+        mp->phdr.p_filesz += size;
+        mp->phdr.p_memsz += size;
+      } else {
+        /* Insertion after PHDR's content. Nothing to do. */
+      }
+    }
+  }
+
+  /* For each LOAD header, find clashing headers that need to be
+     remapped to lower memory areas.
+   */
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (mp->phdr.p_type == PT_LOAD) {
+      ElfuPhdr *mp2;
+
+      CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
+        if (mp2->phdr.p_type != PT_LOAD
+            && mp2->phdr.p_offset + mp2->phdr.p_filesz > off) {
+          /* The PHDR now ends in the file after the injection site */
+          GElf_Off vend1 = mp->phdr.p_vaddr + mp->phdr.p_memsz;
+          GElf_Off pend1 = mp->phdr.p_paddr + mp->phdr.p_memsz;
+          GElf_Off vend2 = mp2->phdr.p_vaddr + mp2->phdr.p_memsz;
+          GElf_Off pend2 = mp2->phdr.p_paddr + mp2->phdr.p_memsz;
+
+          /* If mp and mp2 now overlap in memory */
+          if ((mp2->phdr.p_vaddr < vend1 && vend2 > mp->phdr.p_vaddr)
+              || (mp2->phdr.p_paddr < pend1 && pend2 > mp->phdr.p_paddr)) {
+            /* Move mp2 up in memory, as mp has been resized.
+               Maintaining the relative offset between them is the best
+               guess at maintaining consistency.
+             */
+
+            mp2->phdr.p_vaddr += size;
+            mp2->phdr.p_paddr += size;
+          }
+        }
+      }
+    }
+  }
+
+  /* Move the sections themselves */
+  CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
+    if (ms->shdr.sh_offset >= off) {
+      ms->shdr.sh_offset += size;
+
+      /* If this was in a LOAD segment, it has been adjusted there
+         and this synchronises it.
+         If not, it doesn't matter anyway.
+       */
+      ms->shdr.sh_addr += size;
+    }
+  }
+
+  return size;
+}
index 55a91c553bfb219beef058c0c824ddc554194b5a..c728d40ac2cf12ee6807cdd5a43dcdd835320d60 100644 (file)
@@ -14,11 +14,19 @@ static void printUsage(char *progname)
           "  -h, --help                     Print this help message\n"
           "  -o, --output                   Where to write the modified ELF file to\n"
           "\n"
+          "ELF dump:\n"
           "      --print-header             Print ELF header\n"
           "      --print-segments           Print program headers\n"
           "      --print-sections           Print sections\n"
           "\n"
-          "      --insert-before off,sz     Insert spacing at given offset\n"
+          "Space insertion:\n"
+          "    off: File offset, not within any structure (headers or sections).\n"
+          "    sz:  A multiple of the maximum alignment of all PHDRs.\n"
+          "\n"
+          "      --insert-before off,sz     Insert spacing at given offset,\n"
+          "                                 mapping everything before it to lower mem addresses.\n"
+          "      --insert-after  off,sz     Insert spacing at given offset,\n"
+          "                                 mapping everything after it to higher mem addresses.\n"
           "\n");
 }
 
@@ -38,6 +46,7 @@ void parseOptions(CLIOpts *opts, int argc, char **argv)
     {"print-segments", 0, 0, 10002},
     {"print-sections", 0, 0, 10003},
     {"insert-before", 1, 0, 10004},
+    {"insert-after", 1, 0, 10005},
     {NULL, 0, NULL, 0}
   };
 
@@ -69,6 +78,16 @@ void parseOptions(CLIOpts *opts, int argc, char **argv)
           goto USAGE;
         }
         break;
+      case 10005:
+        opts->insertAfterOffs = strtoul(optarg, &endptr, 0);
+        if (endptr[0] != ',') {
+          goto USAGE;
+        }
+        opts->insertAfterSz = strtoul(endptr + 1, &endptr, 0);
+        if (endptr[0] != '\0' || opts->insertAfterSz == 0) {
+          goto USAGE;
+        }
+        break;
       case '?':
       default:
         goto USAGE;