Skip to content

Instantly share code, notes, and snippets.

@lighth7015
Last active May 18, 2019 00:08
Show Gist options
  • Save lighth7015/34226b46518ee30477cbe6c1e3d2dcd6 to your computer and use it in GitHub Desktop.
Save lighth7015/34226b46518ee30477cbe6c1e3d2dcd6 to your computer and use it in GitHub Desktop.
loader.c
#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