what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

elf-reloc.c

elf-reloc.c
Posted Jul 29, 2003
Authored by sac, Soeren Bleikertz | Site sac.cc

A demonstration of ELF relocation.

tags | exploit
SHA-256 | 15f16677b70d453d8baa3551f84c1a7dff88f2b60f14e3269391e42b8eeba9fb

elf-reloc.c

Change Mirror Download
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Test-code for Kernel-Modules with GRUB - ELF-Relocation
by Soeren Bleikertz <sb@osdev.de>

This is just for demonstration and learning.
I won't explain how relocation works. Please read the ELF-specifications!

http://sac.cc || http://osdev.de || http://soeren.geekgate.org

works more or less. not fully tested!
any questions or comments?
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <elf.h>
#include <sys/mman.h>

//FATAL ERROR
#define FAT_ERROR(s) \
do { \
perror(s); \
exit(-1); \
} while(1);

#define ESUCCESS 0
#define EFAILURE -1
#define ELF_MAGIC "\x7f""ELF"

#define MAX_SYMS 255

#define ENTRY_FUNC "mod_init"

/* TEST-FUNCTION */


/* test.c - I use this small source for relocation-testing. just compile it with
gcc -c test.c

int lala(int *a) {
*a = 2;
return 0;
}

static void mod_init(void)
{
char *bla = "MOD_INIT!!!!\n";
foo();
bar(bla);
}

void hoo(void) {
int bla;
bla = 2;
bla *= 2;
}

EOF */


void foo(void)
{
printf("\nfoo() said: Hello\n");
}

void bar(char *b)
{
printf("\nbar() said: %s(%p)\n", b, b);
}


/* ENTRY-STUFF */

typedef struct entry {
//Elf32_Shdr *shdr;
ulong addr;
} entry_t;

entry_t main_entry;


/* SYMBOL-STUFF */

typedef struct sym_ent {
char *name;
ulong addr;
} sym_t;

// symbol table from module
sym_t sym_tab_mod[MAX_SYMS];
int sym_count;

// global symbol-table
sym_t sym_tab[] = {
{ "foo", (ulong)foo },
{ "bar", (ulong)bar } //test
};

// get addr for a symbol
int sym_lookup(char *sym, ulong *sym_val)
{
int sym_nr = sizeof(sym_tab)/sizeof(sym_t);
int i;

for (i=0; i<sym_nr; i++) {
if (!strcmp(sym_tab[i].name, sym)) {
*sym_val = sym_tab[i].addr;
return ESUCCESS;
}
}
return EFAILURE;
}

//only local/global functions with size>0
int sym_valid_name(Elf32_Sym *symt)
{
if ((symt->st_name != 0) &&
((ELF32_ST_BIND(symt->st_info) == STB_LOCAL) || (ELF32_ST_BIND(symt->st_info) == STB_GLOBAL))
&& (symt->st_size > 0) && (ELF32_ST_TYPE(symt->st_info) == STT_FUNC))
return ESUCCESS;
return EFAILURE;
}


// create symbol-table from mod
int sym_tab_create(char *data)
{
Elf32_Ehdr *elfhdr = (Elf32_Ehdr*)data;
int nr_entry, i, nr_shdr = elfhdr->e_shnum;
Elf32_Shdr *shdr, *off_shdr = (Elf32_Shdr*)(data + elfhdr->e_shoff);
Elf32_Sym *symt;
char *strtab;
ulong text_ofs;

sym_count = 0;

//search Symbol-Table
for (i=0; i < nr_shdr; i++) {
if (off_shdr[i].sh_type == SHT_SYMTAB)
shdr = &off_shdr[i];
}

printf("Debug: symtab: %p\n", shdr->sh_offset);
symt = (Elf32_Sym*)(data+shdr->sh_offset);
nr_entry = shdr->sh_size/sizeof(Elf32_Sym);

//search String-Table
for (i=0; i < nr_shdr; i++) {
if ((off_shdr[i].sh_type == SHT_STRTAB) &&
!(off_shdr[i].sh_flags) && (elfhdr->e_shstrndx != i))
shdr = &off_shdr[i];
}
printf("Debug: strtab: %p\n", shdr->sh_offset);
strtab = (char*)(data+shdr->sh_offset);

//search .text
for (i=0;i<nr_shdr; i++) {
if (!(off_shdr[i].sh_flags & 0x0004))
continue;
text_ofs = (ulong)off_shdr[i].sh_offset;
}


printf("Debug: .text ofs: %p\n", text_ofs);

// create symbol-table of module
for (i=0; i<nr_entry; i++) {
if ((sym_valid_name(&symt[i]) == ESUCCESS) && (sym_count <= MAX_SYMS)) {
sym_tab_mod[sym_count].name = &strtab[symt[i].st_name];
sym_tab_mod[sym_count].addr = (ulong)(symt[i].st_value + data + text_ofs);
printf("Debug: Symbol: %s (%p)\n",
sym_tab_mod[sym_count], sym_tab_mod[sym_count].addr);
sym_count++;
}
}

return ESUCCESS;
}


/* KMOD-STUFF */

// validate ELF
int kmod_check(char *data)
{
Elf32_Ehdr *elfhdr= (Elf32_Ehdr*)data;

if (strncmp(&elfhdr->e_ident[EI_MAG0], ELF_MAGIC, 4) ||
(elfhdr->e_ident[EI_CLASS] != ELFCLASS32) ||
(elfhdr->e_ident[EI_DATA] != ELFDATA2LSB) ||
(elfhdr->e_type != ET_REL) ||
(elfhdr->e_machine != EM_386) ||
(elfhdr->e_version != 1))
return EFAILURE;

return ESUCCESS;
}

int kmod_load(char *data, char *modname)
{
if (kmod_check(data) == EFAILURE) {
printf("Error: loading of '%s' failed!\n", modname);
return EFAILURE;
}
printf("Debug: Valid ELF\n");

return ESUCCESS;
}

int kmod_elf_sym(char *data, uint symidx, ulong *sym_val, ulong symtab_sect)
{
Elf32_Ehdr *elfhdr;
Elf32_Shdr *shdr, *sym_sec, *tmp;
Elf32_Sym *symtab;
char *sym, *strtab;
int i;

elfhdr = (Elf32_Ehdr*)data;

shdr = (Elf32_Shdr*)(data + elfhdr->e_shoff);

//search strtab
for (i=0; i < elfhdr->e_shnum; i++) {
if ((shdr[i].sh_type == SHT_STRTAB) && !(shdr[i].sh_flags) && (elfhdr->e_shstrndx != i))
break;
}
tmp = &shdr[i];

strtab = (char*)(data+tmp->sh_offset);

printf("Debug: StrTab-ofs: %p\n", tmp->sh_offset);

sym_sec = (Elf32_Shdr*)&shdr[symtab_sect];

printf("Debug: SymTab-Sect: %lu, SymTab-IDX: %d\n", symtab_sect, symidx);

if (symidx > sym_sec->sh_size/sym_sec->sh_entsize)
return EFAILURE;

if (sym_sec->sh_type != SHT_SYMTAB) {
printf("Error: Not a SymTab!\n");
return EFAILURE;
}

symtab = (Elf32_Sym*)(data + sym_sec->sh_offset);

printf("Debug: Symtab-ofs: %p\n", sym_sec->sh_offset);


if (!symtab[symidx].st_shndx) {
//external symbol
printf("Debug: External Symbol\n");
sym = &strtab[symtab[symidx].st_name];
printf("Debug: Symbol: \"%s\"\n", sym);
if (sym_lookup(sym, sym_val) == EFAILURE) {
printf("Error: Unknown Symbol!\n");
return EFAILURE;
}
printf("Debug: ext. Symbol-Addr: %p\n", *sym_val);
} else {
//internal symbol
printf("Debug: Internal Symbol\n");
shdr = (Elf32_Shdr*)(data + elfhdr->e_shoff + elfhdr->e_shentsize * symidx);
*sym_val = symtab->st_value + (ulong)(data + shdr->sh_offset);
printf("Debug: int. Symbol-Addr: %p, Symtab-Value: %d\n", *sym_val, symtab->st_value);
}
return ESUCCESS;
}


int kmod_elf_reloc_do(char *data, Elf32_Rel *rel, Elf32_Shdr *shdr)
{
ulong *rel_addr;
Elf32_Shdr *rel_sect; //section for relocation
Elf32_Ehdr *elfhdr;
ulong sym_val;

//ELf-hdr
elfhdr = (Elf32_Ehdr*)data;


//section for relocation
rel_sect = (Elf32_Shdr*)(data + elfhdr->e_shoff + elfhdr->e_shentsize * shdr->sh_info);

//relocation addr
rel_addr = (ulong*)(data + rel_sect->sh_offset + rel->r_offset);
printf("Debug: rel_offset: 0x%x, SYM: 0x%x, TYPE: 0x%x\n",
rel->r_offset, ELF32_R_SYM(rel->r_info), ELF32_R_TYPE(rel->r_info));


printf("Debug: sect_for_rel_ofs: %p, SymTab-Sect-IDX: %d\n", rel_sect->sh_offset, shdr->sh_link);

// get addr of symbol
if (kmod_elf_sym(data, ELF32_R_SYM(rel->r_info), &sym_val, shdr->sh_link) == EFAILURE)
return EFAILURE;
// omg..
switch (ELF32_R_TYPE(rel->r_info)) {
case R_386_32:
*rel_addr = sym_val + *rel_addr;
printf("Debug: R_386_32: rel_addr: %p(%p)\n", rel_addr, *rel_addr);
break;
case R_386_PC32:
*rel_addr = sym_val + *rel_addr - (ulong)rel_addr;
printf("Debug: R_386_PC32: rel_addr: %p(%p)\n", rel_addr, *rel_addr);
break;
default:
printf("Error: wrong Reloc-Type\n");
return EFAILURE;
}

return ESUCCESS;
}


int kmod_elf_reloc(char *data)
{
Elf32_Shdr *shdr;
Elf32_Ehdr *ehdr;
Elf32_Rel *rel;
uint shdr_nr, i=0, shdr_ent_sz, rel_sz=0, j;
ulong entry=0;
char *bss;

ehdr = (Elf32_Ehdr*)data;
shdr_nr = ehdr->e_shnum;
shdr_ent_sz = ehdr->e_shentsize;

shdr = (Elf32_Shdr*)(data+ehdr->e_shoff);

// search BBS
while((shdr[i].sh_type != SHT_NOBITS) && (i<shdr_nr))
i++;
if (shdr[i].sh_type != SHT_NOBITS)
printf("No BSS found!\n");
printf("Debug: Found BSS in Section %d\n", i);
bss = malloc(shdr[i].sh_size);
printf("Debug: new BSS: 0x%x\n", (ulong)bss - (ulong)data);
shdr[i].sh_offset = (ulong)bss - (ulong)data;

// search relocation-sections
for(i=0; i<shdr_nr; i++, rel_sz=0) {
if ((shdr[i].sh_type != SHT_RELA) && (shdr[i].sh_type != SHT_REL))
continue;
rel_sz = shdr[i].sh_entsize;
rel = (Elf32_Rel*)(data+shdr[i].sh_offset);
printf("Debug: rel_section: %d(%p), rel_ent_size: %d -> rel_type: %d, rel_ent_nr: %d\n",
i, shdr[i].sh_offset, rel_sz, shdr[i].sh_type, shdr[i].sh_size/rel_sz);
for(j=0;j<shdr[i].sh_size/rel_sz;j++) {
printf("\nDebug: Relocation-Nr: %d/%d\n", j+1, shdr[i].sh_size/rel_sz);
printf("Debug: rel: %p, shdr: %p\n",
(ulong)&rel[j]-(ulong)data, (ulong)&shdr[i]-(ulong)data);
// do relocation
if(kmod_elf_reloc_do(data, &rel[j], &shdr[i]) == EFAILURE)
return EFAILURE;
}
}

// search for ENTRY_FUNC, set main-entry-addr
for (i=0; i<sym_count; i++) {
if (!strcmp(sym_tab_mod[i].name, ENTRY_FUNC)) {
main_entry.addr = sym_tab_mod[i].addr;
break;
}
}

// ENTRY_FUNC not found, set main-entry-addr to beginning of .text
if (main_entry.addr == 0) {
printf("Debug: No Main-Entry! Set entry to beginning of .text!\n");
for (i=0;i<shdr_nr; i++) {
if (!(shdr[i].sh_flags & 0x0004))
continue;
main_entry.addr = (ulong)(data + shdr[i].sh_offset);
//main_entry.shdr = &shdr[i];
printf("Debug: Entry: %p\n", main_entry.addr);
break;
}
}

return ESUCCESS;
}



/* OTHER STUFF */

int main(int argc, char **argv)
{
ulong elf_sz, entry;
char *elf_ptr;
int fd;
struct stat st;
void (*ble)();

if (argc != 2)
return -1;

//open file
if ((fd = open(argv[1], O_RDONLY, 0)) == -1)
FAT_ERROR("open failed");

//getting file-infos
if (fstat(fd, &st) == -1)
FAT_ERROR("stat failed");

elf_sz = st.st_size;
if ((elf_ptr = malloc(elf_sz)) == NULL)
FAT_ERROR("malloc() failed");
//read file
read(fd, elf_ptr, elf_sz);

close(fd);

printf("KMOD-Testing:\n");

printf("Modul: %s:\n---\n", argv[1]);
printf("[Load Mod]\n");
kmod_load(elf_ptr, argv[1]);
printf("> Done!\n\n");

printf("[Create SymTab]\n");
sym_tab_create(elf_ptr);
printf("> Done!\n\n");

//relocation
bzero(&main_entry, sizeof(entry_t));
printf("[Relocation]\n");
if (kmod_elf_reloc(elf_ptr)==EFAILURE) {
printf("Error: Relocation failed!\n");
return EFAILURE;
} else
printf("> Done!\n\n");

printf("[Start]\n");
ble = (void*)main_entry.addr;
printf("Debug: entry: %p\n", main_entry.addr);
printf("<output>\n");
ble();
printf("</output\n");
printf("> Done!\n");
free(elf_ptr);
return 0;
}
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close