Last active
May 18, 2019 00:08
-
-
Save lighth7015/34226b46518ee30477cbe6c1e3d2dcd6 to your computer and use it in GitHub Desktop.
loader.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <dlfcn.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <libelf.h> | |
#include <sys/stat.h> | |
#include <sys/mman.h> | |
char* buffer; | |
static struct stat fileinfo; | |
void printk(const char* msg) | |
{ | |
fputs(msg, stderr); | |
} | |
int is_image_valid(Elf32_Ehdr *hdr) | |
{ | |
return 1; | |
} | |
void *resolve(const char* sym) | |
{ | |
static void *handle = NULL; | |
if (handle == NULL) { | |
handle = dlopen("libc.so", RTLD_NOW); | |
} | |
return dlsym(handle, sym); | |
} | |
void relocate(Elf32_Shdr* shdr, const Elf32_Sym* syms, const char* strings, const char* src, char* dst) | |
{ | |
Elf32_Rel* rel = (Elf32_Rel*)(src + shdr->sh_offset); | |
int j; | |
for(j = 0; j < shdr->sh_size / sizeof(Elf32_Rel); j += 1) { | |
const char* sym = strings + syms[ELF32_R_SYM(rel[j].r_info)].st_name; | |
printf( "relocating: [%s] %p -> %p\n", sym, (Elf32_Word *) dst + rel[j].r_offset, (Elf32_Word *)resolve(sym)); | |
switch(ELF32_R_TYPE(rel[j].r_info)) { | |
case R_386_JMP_SLOT: | |
case R_386_GLOB_DAT: | |
*(Elf32_Word*)(dst + rel[j].r_offset) = (Elf32_Word)resolve(sym); | |
break; | |
} | |
} | |
} | |
void* find_sym(const char* name, Elf32_Shdr* shdr, const char* strings, const char* src, char* dst) | |
{ | |
Elf32_Sym* syms = (Elf32_Sym*)(src + shdr->sh_offset); | |
int i; | |
for(i = 0; i < shdr->sh_size / sizeof(Elf32_Sym); i += 1) { | |
if (strcmp(name, strings + syms[i].st_name) == 0) { | |
return dst + syms[i].st_value; | |
} | |
} | |
return NULL; | |
} | |
void *image_load (char *image_base) | |
{ | |
Elf32_Ehdr *hdr = (Elf32_Ehdr *) image_base; | |
Elf32_Phdr *phdr = (Elf32_Phdr *) image_base + hdr->e_phoff; | |
if(!is_image_valid(hdr)) { | |
printk("image_load:: invalid ELF image\n"); | |
return 0; | |
} | |
char *exec = mmap(NULL, fileinfo.st_size, PROT_READ | PROT_WRITE | PROT_EXEC, | |
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); | |
if(!exec) { | |
printk("image_load:: error allocating memory\n"); | |
return 0; | |
} | |
// Start with clean memory. | |
memset(exec,0x0, fileinfo.st_size); | |
for(uint32_t i=0; i < hdr->e_phnum; ++i) { | |
if(phdr[i].p_type == PT_LOAD) { | |
if(phdr[i].p_filesz > phdr[i].p_memsz) { | |
munmap(exec, fileinfo.st_size); | |
goto failure; | |
} | |
else if(phdr[i].p_filesz) { | |
// p_filesz can be smaller than p_memsz, | |
// the difference is zeroe'd out. | |
char *offset = phdr[i].p_vaddr + exec; | |
memmove(offset, (image_base + phdr[i].p_offset), | |
phdr[i].p_filesz); | |
uint32_t is_read_only = PF_R, | |
is_read_exec = PF_R | PF_X, | |
is_rd_wr_ex = PF_R | PF_W | PF_X; | |
int32_t page_flags = | |
phdr[i].p_flags & is_read_only? PROT_READ: | |
phdr[i].p_flags & is_read_exec? PROT_READ | PROT_EXEC: | |
phdr[i].p_flags & is_rd_wr_ex? PROT_READ | PROT_WRITE | PROT_EXEC: | |
-1; | |
if (page_flags >= 0) { | |
mprotect((unsigned char *) offset, phdr[i].p_memsz, page_flags); | |
} | |
} | |
} | |
} | |
Elf32_Shdr *shdr = (Elf32_Shdr *) | |
(image_base + hdr->e_shoff); | |
void* entry = NULL; | |
uint32_t i = 0; | |
while(i++ < hdr->e_shnum) { | |
Elf32_Sym *symbols = NULL; | |
char *strings = NULL; | |
if (shdr[i].sh_addr > 0) { | |
if (shdr[i].sh_type == SHT_DYNSYM) { | |
symbols = (Elf32_Sym*) (image_base + shdr[i].sh_offset); | |
strings = (image_base + shdr[shdr[i].sh_link].sh_offset); | |
entry = find_sym("main", shdr + i, strings, image_base, exec); | |
} | |
if (shdr[i].sh_type == SHT_REL) { | |
relocate(shdr + i, symbols, strings, image_base, exec); | |
} | |
} | |
} | |
return entry; | |
failure: | |
printk("image_load:: p_filesz > p_memsz\n"); | |
return (void *) -1; | |
}/* image_load */ | |
int main(int argc, char** argv, char** envp) | |
{ | |
const char* image = "elf"; | |
FILE* elf = fopen( image , "rb"); | |
fstat(fileno(elf), &fileinfo); | |
printf( "Reading %lx bytes from \"%s\".\n", | |
fileinfo.st_size, image); | |
buffer = (char *) calloc(sizeof(char), fileinfo.st_size); | |
fread(buffer, fileinfo.st_size, 1, elf); | |
int (*ptr)(int, char **, char**) | |
= image_load(buffer); | |
return (ptr && ptr(argc,argv,envp)) || 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment