evandrix

Untitled

Mar 12th, 2023
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* load shared from memory, sort of (x) 2021 by herm1t.vx@gmail.com / https://twitter.com/vx_herm1t */
  2. #include <stdio.h>
  3. #include <stdint.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <sys/mman.h>
  7. #include <unistd.h>
  8. #include <elf.h>
  9. #include <assert.h>
  10. #include <link.h>
  11. #include <fcntl.h>
  12.  
  13. static int load(unsigned char *lib, int size)
  14. {
  15.     uint8_t *map;
  16.     Elf64_Ehdr *ehdr = (Elf64_Ehdr*)lib;
  17.     Elf64_Phdr *phdr = (Elf64_Phdr*)(lib + ehdr->e_phoff);
  18.     Elf64_Addr lo = ~0, hi = 0, t;
  19.     int i;
  20.     struct elf {
  21.         int relent, relpltsz, symcnt, relasz, gnuhash;
  22.         char *dynstr;
  23.         Elf64_Sym * dynsym;
  24.         void *relplt, *rela;
  25.         void *delta;
  26.         void (*init)(void);
  27.         uint32_t *hash;
  28.     } lm, lc;
  29.     bzero(&lm, sizeof(lm));
  30.     bzero(&lc, sizeof(lc));
  31.  
  32.     /* get ELF size */
  33.     for (i = 0; i < ehdr->e_phnum; i++)
  34.         if (phdr[i].p_type == PT_LOAD) {
  35.             if (phdr[i].p_vaddr < lo)
  36.                 lo = phdr[i].p_vaddr;
  37.             t = phdr[i].p_vaddr + phdr[i].p_memsz;
  38.             if (t > hi)
  39.                 hi = t;
  40.         }
  41.  
  42.     /* allocate memory */
  43.     map = mmap(NULL, hi - lo, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  44.     if (map == MAP_FAILED) {
  45.         printf("failed to allocate memory\n");
  46.         return 2;
  47.     }
  48.  
  49.     /* copy segments and find DYNAMIC */
  50.     Elf64_Dyn *dyn = NULL;
  51.     int f2p(int f) {
  52.         int p = PROT_READ;
  53.         if (f & PF_X)
  54.             p |= PROT_EXEC;
  55.         if (f & PF_W)
  56.             p |= PROT_WRITE;
  57.         return p;
  58.     }
  59.     for (i = 0; i < ehdr->e_phnum; i++) {
  60.         if (phdr[i].p_type == PT_LOAD) {
  61.             if (phdr[i].p_offset == 0)
  62.                 lm.delta = map - lo;
  63.             Elf64_Addr off = phdr[i].p_vaddr & 4095ULL;
  64.             void *seg = phdr[i].p_vaddr - off + lm.delta;
  65.             memcpy(seg + off, lib + phdr[i].p_offset, phdr[i].p_filesz);
  66.             mprotect(seg, phdr[i].p_memsz + off, f2p(phdr[i].p_flags));
  67.         }
  68.         if (phdr[i].p_type == PT_DYNAMIC)
  69.             dyn = (Elf64_Dyn*)(lm.delta + phdr[i].p_vaddr);
  70.     }
  71.     assert(dyn != NULL);
  72.  
  73.     /* get init(), relocations and symbols */
  74.     void parse_dyn(Elf64_Dyn *dyn, struct elf *elf) {
  75. #define GET_PTR(tag, var)   if (dyn->d_tag == tag) elf->var = (void*)(dyn->d_un.d_val + elf->delta);
  76. #define GET_VAL(tag, var)   if (dyn->d_tag == tag) elf->var = dyn->d_un.d_val;
  77.         for ( ; dyn->d_tag != DT_NULL; dyn++) {
  78.             GET_PTR(DT_INIT, init)
  79.             GET_PTR(DT_JMPREL, relplt)
  80.             GET_VAL(DT_RELENT, relent)
  81.             GET_VAL(DT_RELAENT, relent)
  82.             GET_VAL(DT_PLTRELSZ, relpltsz)
  83.             GET_PTR(DT_REL, rela)
  84.             GET_PTR(DT_RELA, rela)
  85.             GET_VAL(DT_RELSZ, relasz)
  86.             GET_VAL(DT_RELASZ, relasz)
  87.             GET_PTR(DT_SYMTAB, dynsym)
  88.             GET_PTR(DT_STRTAB, dynstr)
  89.             GET_PTR(DT_HASH, hash)
  90.             GET_PTR(DT_GNU_HASH, hash)
  91.             if (dyn->d_tag == DT_GNU_HASH)
  92.                 elf->gnuhash = 1;
  93.         }
  94.         /* get symbol count */
  95.         uint32_t *hash = elf->hash;
  96.         if (elf->gnuhash) {
  97.             int i;
  98.             uint32_t nbucket = hash[0];
  99.             uint32_t base = hash[1];
  100.             uint32_t bloom_size = hash[2];
  101.             uint64_t *bloom = (void*)&hash[4];
  102.             uint32_t *bucket = (void*)&bloom[bloom_size];
  103.             uint32_t *chain = &bucket[nbucket];
  104.                 unsigned int last_sym = 0;
  105.                 for (i = 0; i < nbucket; i++)
  106.                         if (bucket[i] > last_sym)
  107.                                 last_sym = bucket[i];
  108.             for (i = last_sym - base; !(chain[i] & 1); i++)
  109.                 last_sym++;
  110.             elf->symcnt= last_sym + 1;
  111.         } else
  112.         if (hash) {
  113.             elf->symcnt = hash[1];
  114.         } else {
  115.             /* it's outdated, but... */
  116.             elf->symcnt = (elf->dynstr - (char*)elf->dynsym) / sizeof(Elf64_Sym);
  117.         }
  118.     }
  119.     parse_dyn(dyn, &lm);
  120.  
  121.     /* find libc */
  122.         struct link_map *l = _r_debug.r_map;
  123.     for ( ; l != NULL; l = l->l_next)
  124.         if (l->l_name && *l->l_name && strstr(l->l_name, "libc")) {
  125.             printf("Found %s %p\n", l->l_name, l->l_ld);
  126.             parse_dyn(l->l_ld, &lc);
  127.             lc.delta = (void*)l->l_addr;
  128.             break;
  129.     }
  130.     assert(lc.dynsym != NULL);
  131.  
  132.     /* relocate, sort of */
  133.     void relocate(void *rela, int relasz, int relaent) {
  134.         void *r;
  135.         for (r = rela; (r - rela) < relasz; r += relaent) {
  136.             Elf64_Rela *rela = (Elf64_Rela*)r;
  137.             int index = ELF64_R_SYM(rela->r_info);
  138.             void *value = 0;
  139.             char *name = NULL;
  140.             if (index) {
  141.                 if (lm.dynsym[index].st_value) {
  142.                     value = lm.dynsym[index].st_value + lm.delta;
  143.                 } else {
  144.                     /* FIXME: use hash, search all libraries */
  145.                     int found = 0;
  146.                     name = lm.dynsym[index].st_name + lm.dynstr;
  147.                     for (i = 0; i < lc.symcnt; i++)
  148.                         if (! strcmp(name, lc.dynsym[i].st_name + lc.dynstr)) {
  149.                             value = lc.dynsym[i].st_value + lc.delta;
  150.                             found = 1;
  151.                         }
  152.                     if (! found)
  153.                         printf("Failed to resolve %d %s\n", index, name);
  154.                 }
  155.             }
  156.             if (lm.relent == sizeof(Elf64_Rela))
  157.                 value += rela->r_addend;
  158.             printf("%p (%s + %x) %p\n", rela->r_offset, name ? name : "",
  159.                 rela->r_addend, value - lm.delta);
  160.             *(void**)(rela->r_offset + lm.delta) = value;
  161.         }
  162.     }
  163.     relocate(lm.relplt, lm.relpltsz, lm.relent);
  164.     relocate(lm.rela, lm.relasz, lm.relent);
  165.  
  166.     printf("Done! Call init\n");
  167.     if (lm.init)
  168.         lm.init();
  169. }
  170.  
  171. int main(int argc, char **argv)
  172. {
  173.     int h = open(argv[1], 0);
  174.     int l = lseek(h, 0, 2);
  175.     lseek(h, 0, 0);
  176.     unsigned char lib[l];
  177.     if (h > 0 && l > 0 && read(h, lib, l) == l)
  178.         load(lib, l);
  179.     else
  180.         printf("Failed to read %s\n", argv[1]);
  181.     close(h);
  182.     return 0;
  183. }
Add Comment
Please, Sign In to add comment