home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 12 / hacker12 / 12_HACKER_12.ISO / exploits / elfreloc / elf-reloc.c
Encoding:
C/C++ Source or Header  |  2003-08-21  |  10.6 KB  |  463 lines

  1. /*
  2.  *  This program is free software; you can redistribute it and/or modify
  3.  *  it under the terms of the GNU General Public License as published by
  4.  *  the Free Software Foundation; either version 2 of the License, or
  5.  *  (at your option) any later version.
  6.  *
  7.  *  This program is distributed in the hope that it will be useful,
  8.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *  GNU Library General Public License for more details.
  11.  *
  12.  *  You should have received a copy of the GNU General Public License
  13.  *  along with this program; if not, write to the Free Software
  14.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15.  */
  16. /*
  17. Test-code for Kernel-Modules with GRUB - ELF-Relocation
  18.     by Soeren Bleikertz <sb@osdev.de>
  19.     
  20. This is just for demonstration and learning.
  21. I won't explain how relocation works. Please read the ELF-specifications!
  22.  
  23. http://sac.cc || http://osdev.de || http://soeren.geekgate.org
  24.  
  25. works more or less. not fully tested!
  26. any questions or comments?
  27. */
  28.  
  29. #include <stdio.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <unistd.h>
  33. #include <fcntl.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <elf.h>
  37. #include <sys/mman.h>
  38.  
  39. //FATAL ERROR
  40. #define FAT_ERROR(s) \
  41.     do { \
  42.         perror(s); \
  43.         exit(-1); \
  44.     } while(1);
  45.     
  46. #define ESUCCESS 0
  47. #define EFAILURE -1
  48. #define ELF_MAGIC "\x7f""ELF"
  49.  
  50. #define MAX_SYMS 255
  51.     
  52. #define ENTRY_FUNC "mod_init"
  53.     
  54. /* TEST-FUNCTION */
  55.     
  56.  
  57. /* test.c - I use this small source for relocation-testing. just compile it with
  58.     gcc -c test.c
  59.     
  60. int lala(int *a) {
  61.     *a = 2;
  62.     return 0;
  63. }
  64.  
  65. static void mod_init(void)
  66. {    
  67.     char *bla = "MOD_INIT!!!!\n";
  68.     foo();
  69.     bar(bla);
  70. }
  71.  
  72. void hoo(void) {
  73.     int bla;
  74.     bla = 2;
  75.     bla *= 2;
  76. }    
  77.     
  78.  EOF */
  79.  
  80.     
  81. void foo(void)
  82. {
  83.     printf("\nfoo() said: Hello\n");
  84. }
  85.     
  86. void bar(char *b)
  87. {
  88.     printf("\nbar() said: %s(%p)\n", b, b);
  89. }
  90.  
  91.  
  92. /* ENTRY-STUFF */
  93.  
  94. typedef struct entry {
  95.     //Elf32_Shdr *shdr;
  96.     ulong addr;
  97. } entry_t;
  98.  
  99. entry_t main_entry;
  100.  
  101.  
  102. /* SYMBOL-STUFF */
  103.     
  104. typedef struct sym_ent {
  105.     char *name;
  106.     ulong addr;
  107. } sym_t;
  108.  
  109. // symbol table from module
  110. sym_t sym_tab_mod[MAX_SYMS];
  111. int sym_count;
  112.  
  113. // global symbol-table
  114. sym_t sym_tab[] = {
  115.     { "foo", (ulong)foo },
  116.     { "bar", (ulong)bar } //test
  117. };
  118.  
  119. // get addr for a symbol
  120. int sym_lookup(char *sym, ulong *sym_val)
  121. {
  122.     int sym_nr = sizeof(sym_tab)/sizeof(sym_t);
  123.     int i;
  124.     
  125.     for (i=0; i<sym_nr; i++) {
  126.         if (!strcmp(sym_tab[i].name, sym)) {
  127.             *sym_val = sym_tab[i].addr;
  128.             return ESUCCESS;
  129.         }
  130.     }
  131.     return EFAILURE;
  132. }
  133.  
  134. //only local/global functions with size>0
  135. int sym_valid_name(Elf32_Sym *symt)
  136. {
  137.     if ((symt->st_name != 0) &&
  138.     ((ELF32_ST_BIND(symt->st_info) == STB_LOCAL) || (ELF32_ST_BIND(symt->st_info) == STB_GLOBAL))
  139.     && (symt->st_size > 0) && (ELF32_ST_TYPE(symt->st_info) == STT_FUNC))
  140.         return ESUCCESS;
  141.     return EFAILURE;
  142. }
  143.     
  144.  
  145. // create symbol-table from mod
  146. int sym_tab_create(char *data)
  147. {
  148.     Elf32_Ehdr *elfhdr = (Elf32_Ehdr*)data;
  149.     int nr_entry, i, nr_shdr = elfhdr->e_shnum;
  150.     Elf32_Shdr *shdr, *off_shdr = (Elf32_Shdr*)(data + elfhdr->e_shoff);
  151.     Elf32_Sym *symt;
  152.     char *strtab;
  153.     ulong text_ofs;
  154.     
  155.     sym_count = 0;
  156.     
  157.     //search Symbol-Table
  158.     for (i=0; i < nr_shdr; i++) {
  159.         if (off_shdr[i].sh_type == SHT_SYMTAB)
  160.             shdr = &off_shdr[i];
  161.     }
  162.     
  163.     printf("Debug: symtab: %p\n", shdr->sh_offset);
  164.     symt = (Elf32_Sym*)(data+shdr->sh_offset);
  165.     nr_entry = shdr->sh_size/sizeof(Elf32_Sym);
  166.     
  167.     //search String-Table
  168.     for (i=0; i < nr_shdr; i++) {
  169.         if ((off_shdr[i].sh_type == SHT_STRTAB) &&
  170.             !(off_shdr[i].sh_flags) && (elfhdr->e_shstrndx != i))
  171.             shdr = &off_shdr[i];
  172.     }
  173.     printf("Debug: strtab: %p\n", shdr->sh_offset);
  174.     strtab = (char*)(data+shdr->sh_offset);
  175.     
  176.     //search .text
  177.     for (i=0;i<nr_shdr; i++) {
  178.         if (!(off_shdr[i].sh_flags & 0x0004))
  179.             continue;
  180.         text_ofs = (ulong)off_shdr[i].sh_offset;
  181.     }
  182.     
  183.     
  184.     printf("Debug: .text ofs: %p\n", text_ofs);
  185.     
  186.     // create symbol-table of module
  187.     for (i=0; i<nr_entry; i++) {
  188.         if ((sym_valid_name(&symt[i]) == ESUCCESS) && (sym_count <= MAX_SYMS)) {
  189.             sym_tab_mod[sym_count].name = &strtab[symt[i].st_name];
  190.             sym_tab_mod[sym_count].addr = (ulong)(symt[i].st_value + data + text_ofs);
  191.             printf("Debug: Symbol: %s (%p)\n",
  192.                 sym_tab_mod[sym_count], sym_tab_mod[sym_count].addr);
  193.             sym_count++;
  194.             }
  195.     }
  196.  
  197.     return ESUCCESS;
  198. }
  199.     
  200.  
  201. /* KMOD-STUFF */
  202.  
  203. // validate ELF
  204. int kmod_check(char *data)
  205. {
  206.     Elf32_Ehdr *elfhdr= (Elf32_Ehdr*)data;
  207.  
  208.     if (strncmp(&elfhdr->e_ident[EI_MAG0], ELF_MAGIC, 4) ||
  209.         (elfhdr->e_ident[EI_CLASS] != ELFCLASS32) ||
  210.         (elfhdr->e_ident[EI_DATA] != ELFDATA2LSB) ||
  211.         (elfhdr->e_type != ET_REL) ||
  212.         (elfhdr->e_machine != EM_386) ||
  213.         (elfhdr->e_version != 1))
  214.             return EFAILURE;
  215.         
  216.     return ESUCCESS;
  217. }
  218.  
  219. int kmod_load(char *data, char *modname)
  220. {
  221.     if (kmod_check(data) == EFAILURE) {
  222.         printf("Error: loading of '%s' failed!\n", modname);
  223.         return EFAILURE;
  224.     }
  225.     printf("Debug: Valid ELF\n");
  226.  
  227.     return ESUCCESS;
  228. }
  229.  
  230. int kmod_elf_sym(char *data, uint symidx, ulong *sym_val, ulong symtab_sect)
  231. {
  232.     Elf32_Ehdr *elfhdr;
  233.     Elf32_Shdr *shdr, *sym_sec, *tmp;
  234.     Elf32_Sym *symtab;
  235.     char *sym, *strtab;
  236.     int i;
  237.     
  238.     elfhdr = (Elf32_Ehdr*)data;
  239.     
  240.     shdr = (Elf32_Shdr*)(data + elfhdr->e_shoff);
  241.     
  242.     //search strtab
  243.     for (i=0; i < elfhdr->e_shnum; i++) {
  244.         if ((shdr[i].sh_type == SHT_STRTAB) && !(shdr[i].sh_flags) && (elfhdr->e_shstrndx != i))
  245.             break;            
  246.     }
  247.     tmp = &shdr[i];
  248.     
  249.     strtab = (char*)(data+tmp->sh_offset);
  250.     
  251.     printf("Debug: StrTab-ofs: %p\n", tmp->sh_offset);
  252.     
  253.     sym_sec = (Elf32_Shdr*)&shdr[symtab_sect];
  254.     
  255.     printf("Debug: SymTab-Sect: %lu, SymTab-IDX: %d\n", symtab_sect, symidx);
  256.     
  257.     if (symidx > sym_sec->sh_size/sym_sec->sh_entsize)
  258.         return EFAILURE;
  259.     
  260.     if (sym_sec->sh_type != SHT_SYMTAB) {
  261.         printf("Error: Not a SymTab!\n");
  262.         return EFAILURE;
  263.     }
  264.     
  265.     symtab = (Elf32_Sym*)(data + sym_sec->sh_offset);
  266.     
  267.     printf("Debug: Symtab-ofs: %p\n", sym_sec->sh_offset);
  268.     
  269.     
  270.     if (!symtab[symidx].st_shndx) {
  271.         //external symbol
  272.         printf("Debug: External Symbol\n");
  273.         sym = &strtab[symtab[symidx].st_name];
  274.         printf("Debug: Symbol: \"%s\"\n", sym);
  275.         if (sym_lookup(sym, sym_val) == EFAILURE) {
  276.             printf("Error: Unknown Symbol!\n");
  277.             return EFAILURE;
  278.         }
  279.         printf("Debug: ext. Symbol-Addr: %p\n", *sym_val);
  280.     } else {
  281.         //internal symbol
  282.         printf("Debug: Internal Symbol\n");
  283.         shdr = (Elf32_Shdr*)(data + elfhdr->e_shoff + elfhdr->e_shentsize * symidx);
  284.         *sym_val = symtab->st_value + (ulong)(data + shdr->sh_offset);
  285.         printf("Debug: int. Symbol-Addr: %p, Symtab-Value: %d\n", *sym_val, symtab->st_value);    
  286.     }
  287.     return ESUCCESS;
  288. }
  289.     
  290.  
  291. int kmod_elf_reloc_do(char *data, Elf32_Rel *rel, Elf32_Shdr *shdr)
  292. {
  293.     ulong *rel_addr;
  294.     Elf32_Shdr *rel_sect; //section for relocation
  295.     Elf32_Ehdr *elfhdr;
  296.     ulong sym_val;
  297.     
  298.     //ELf-hdr
  299.     elfhdr = (Elf32_Ehdr*)data;
  300.     
  301.     
  302.     //section for relocation
  303.     rel_sect = (Elf32_Shdr*)(data + elfhdr->e_shoff + elfhdr->e_shentsize * shdr->sh_info);
  304.     
  305.     //relocation addr
  306.     rel_addr = (ulong*)(data + rel_sect->sh_offset + rel->r_offset);
  307.     printf("Debug: rel_offset: 0x%x, SYM: 0x%x, TYPE: 0x%x\n",
  308.         rel->r_offset, ELF32_R_SYM(rel->r_info), ELF32_R_TYPE(rel->r_info));
  309.     
  310.     
  311.     printf("Debug: sect_for_rel_ofs: %p, SymTab-Sect-IDX: %d\n", rel_sect->sh_offset, shdr->sh_link);
  312.     
  313.     // get addr of symbol
  314.     if (kmod_elf_sym(data, ELF32_R_SYM(rel->r_info), &sym_val, shdr->sh_link) == EFAILURE)
  315.         return EFAILURE;
  316.     // omg..
  317.     switch (ELF32_R_TYPE(rel->r_info)) {
  318.         case R_386_32:
  319.             *rel_addr = sym_val + *rel_addr;
  320.             printf("Debug: R_386_32: rel_addr: %p(%p)\n", rel_addr, *rel_addr);
  321.         break;
  322.         case R_386_PC32:
  323.             *rel_addr = sym_val + *rel_addr - (ulong)rel_addr;
  324.             printf("Debug: R_386_PC32: rel_addr: %p(%p)\n", rel_addr, *rel_addr);
  325.         break;
  326.         default:
  327.             printf("Error: wrong Reloc-Type\n");
  328.             return EFAILURE;
  329.     }
  330.     
  331.     return ESUCCESS;    
  332. }
  333.  
  334.  
  335. int kmod_elf_reloc(char *data)
  336. {
  337.     Elf32_Shdr *shdr;
  338.     Elf32_Ehdr *ehdr;
  339.     Elf32_Rel *rel;
  340.     uint shdr_nr, i=0, shdr_ent_sz, rel_sz=0, j;
  341.     ulong entry=0;
  342.     char *bss;
  343.     
  344.     ehdr = (Elf32_Ehdr*)data;
  345.     shdr_nr = ehdr->e_shnum;
  346.     shdr_ent_sz = ehdr->e_shentsize;
  347.     
  348.     shdr = (Elf32_Shdr*)(data+ehdr->e_shoff);    
  349.     
  350.     // search BBS
  351.     while((shdr[i].sh_type != SHT_NOBITS) && (i<shdr_nr))
  352.         i++;
  353.     if (shdr[i].sh_type != SHT_NOBITS)
  354.         printf("No BSS found!\n");
  355.     printf("Debug: Found BSS in Section %d\n", i);
  356.     bss = malloc(shdr[i].sh_size);
  357.     printf("Debug: new BSS: 0x%x\n", (ulong)bss - (ulong)data);
  358.     shdr[i].sh_offset = (ulong)bss - (ulong)data;
  359.     
  360.     // search relocation-sections
  361.     for(i=0; i<shdr_nr; i++, rel_sz=0) {
  362.         if ((shdr[i].sh_type != SHT_RELA) && (shdr[i].sh_type != SHT_REL))
  363.             continue;
  364.         rel_sz = shdr[i].sh_entsize;
  365.         rel = (Elf32_Rel*)(data+shdr[i].sh_offset);
  366.         printf("Debug: rel_section: %d(%p), rel_ent_size: %d -> rel_type: %d, rel_ent_nr: %d\n",
  367.             i, shdr[i].sh_offset, rel_sz, shdr[i].sh_type, shdr[i].sh_size/rel_sz);
  368.         for(j=0;j<shdr[i].sh_size/rel_sz;j++) {
  369.             printf("\nDebug: Relocation-Nr: %d/%d\n", j+1, shdr[i].sh_size/rel_sz);
  370.             printf("Debug: rel: %p, shdr: %p\n",
  371.                 (ulong)&rel[j]-(ulong)data, (ulong)&shdr[i]-(ulong)data);
  372.             // do relocation
  373.             if(kmod_elf_reloc_do(data, &rel[j], &shdr[i]) == EFAILURE)
  374.                 return EFAILURE;
  375.         }
  376.     }
  377.     
  378.     // search for ENTRY_FUNC, set main-entry-addr
  379.     for (i=0; i<sym_count; i++) {
  380.         if (!strcmp(sym_tab_mod[i].name, ENTRY_FUNC)) {
  381.             main_entry.addr = sym_tab_mod[i].addr;
  382.             break;
  383.         }
  384.     }
  385.     
  386.     // ENTRY_FUNC not found, set main-entry-addr to beginning of .text
  387.     if (main_entry.addr == 0) {
  388.         printf("Debug: No Main-Entry! Set entry to beginning of .text!\n");
  389.         for (i=0;i<shdr_nr; i++) {
  390.             if (!(shdr[i].sh_flags & 0x0004))
  391.                 continue;
  392.             main_entry.addr = (ulong)(data + shdr[i].sh_offset);
  393.             //main_entry.shdr = &shdr[i];
  394.             printf("Debug: Entry: %p\n", main_entry.addr);
  395.             break;
  396.         }
  397.     }    
  398.     
  399.     return ESUCCESS;
  400. }
  401.     
  402.  
  403.  
  404. /* OTHER STUFF */
  405.  
  406. int main(int argc, char **argv)
  407. {
  408.     ulong elf_sz, entry;
  409.     char *elf_ptr;
  410.     int fd;
  411.     struct stat st;
  412.     void (*ble)();
  413.     
  414.     if (argc != 2)
  415.         return -1;
  416.     
  417.     //open file
  418.     if ((fd = open(argv[1], O_RDONLY, 0)) == -1)
  419.         FAT_ERROR("open failed");
  420.  
  421.     //getting file-infos
  422.     if (fstat(fd, &st) == -1)
  423.         FAT_ERROR("stat failed");
  424.  
  425.     elf_sz = st.st_size;
  426.     if ((elf_ptr = malloc(elf_sz)) == NULL)
  427.         FAT_ERROR("malloc() failed");
  428.     //read file
  429.     read(fd, elf_ptr, elf_sz);
  430.     
  431.     close(fd);
  432.     
  433.     printf("KMOD-Testing:\n");
  434.     
  435.     printf("Modul: %s:\n---\n", argv[1]);
  436.     printf("[Load Mod]\n");
  437.     kmod_load(elf_ptr, argv[1]);
  438.     printf("> Done!\n\n");
  439.     
  440.     printf("[Create SymTab]\n");
  441.     sym_tab_create(elf_ptr);
  442.     printf("> Done!\n\n");
  443.     
  444.     //relocation
  445.     bzero(&main_entry, sizeof(entry_t));
  446.     printf("[Relocation]\n");
  447.     if (kmod_elf_reloc(elf_ptr)==EFAILURE) {
  448.         printf("Error: Relocation failed!\n");
  449.         return EFAILURE;
  450.     } else
  451.         printf("> Done!\n\n");
  452.     
  453.     printf("[Start]\n");
  454.     ble = (void*)main_entry.addr;
  455.     printf("Debug: entry: %p\n", main_entry.addr);
  456.     printf("<output>\n");
  457.     ble();
  458.     printf("</output\n");
  459.     printf("> Done!\n");
  460.     free(elf_ptr);
  461.     return 0;
  462. }
  463.