I'm trying to conduct a little experiment which basically consists of changing the EP of an ELF file and executing an exit(9) syscall, without returning to the OEP. As shown in the image everything seems fine
However when I run the original program it segfaults rather than exiting via the exit(9), I can't figure out why. What's really happening here?
EDIT: Here's how I'm changing the entry-point:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <elf.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#define INVALID_IDX -32
#define PAGE_SIZE 4096
int check_elf(uint8_t *, char **);
// exit(9)
unsigned char shellcode[] = "\x48\x31\xc0"
"\xb0\x3c"
"\x40\xb7\x09"
"\x0f\x05";
unsigned char nop_sled[] = "\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90"
"\x90\x90\xcc\x90\x90"
"\x90\x90\x90\x90\x90";
int main(int argc, char **argv)
{
int fd, i;
uint8_t *mapped_file;
struct stat st;
char *interp;
int magic = 1337;
Elf64_Ehdr *ehdr = NULL;
Elf64_Phdr *phdr = NULL;
Elf64_Shdr *shdr = NULL;
if (argc < 2)
{
printf("Usage: %s <executable>\n", argv[0]);
exit(EXIT_SUCCESS);
}
fd = open(argv[1], O_RDWR);
if (fd < 0)
{
perror("open");
exit(EXIT_FAILURE);
}
if (fstat(fd, &st) < 0)
{
perror("fstat");
exit(EXIT_FAILURE);
}
/* map whole executable into memory */
mapped_file = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mapped_file < 0)
{
perror("mmap");
exit(EXIT_FAILURE);
}
check_elf(mapped_file, argv);
ehdr = (Elf64_Ehdr *) mapped_file;
phdr = (Elf64_Phdr *) &mapped_file[ehdr->e_phoff];
shdr = (Elf64_Shdr *) &mapped_file[ehdr->e_shoff];
if (ehdr->e_type != ET_EXEC)
{
fprintf(stderr, "%s is not an ELF executable.\n", argv[1]);
exit(EXIT_FAILURE);
}
printf("Program entry point: %08x\n", ehdr->e_entry);
char jmp_code[7];
int text_found = 0;
uint64_t parasite_addr;
uint64_t text_end;
size_t parasite_len = strlen(shellcode);
int text_idx = INVALID_IDX;
for (i = 0; i < ehdr->e_phnum; ++i)
{
if (text_found)
{
phdr[i].p_offset += PAGE_SIZE;
continue;
}
if (phdr[i].p_type == PT_LOAD && phdr[i].p_flags == ( PF_R | PF_X))
{
// set parasite to the end of the text segment
parasite_addr = phdr[i].p_vaddr + phdr[i].p_filesz;
text_end = phdr[i].p_vaddr + phdr[i].p_filesz;
printf("TEXT SEGMENT ends at 0x%x\n", text_end);
text_idx = i;
puts("Changing entry point...");
ehdr->e_entry = (Elf64_Addr)parasite_addr;
memmove(mapped_file + phdr[i].p_offset + phdr[i].p_filesz,
shellcode, parasite_len);
phdr[i].p_filesz += parasite_len;
phdr[i].p_memsz += parasite_len;
text_found++;
}
}
//patch sections
for (i = 0; i < ehdr->e_shnum; ++i)
{
if (shdr->sh_offset >= parasite_addr)
shdr->sh_offset += PAGE_SIZE;
else
if (shdr->sh_size + shdr->sh_addr == parasite_addr)
shdr->sh_size += parasite_len;
}
ehdr->e_shoff += PAGE_SIZE;
close(fd);
}
int check_elf(uint8_t *mapped_file, char **argv)
{
const uint8_t magic[] = {0x7F, 'E', 'L', 'F'};
if (memcmp(magic, mapped_file, sizeof(magic)))
{
fprintf(stderr, "%s is not an ELF file.\n", argv[1]);
exit(EXIT_FAILURE);
}
return 1;
}
As for the program whose entry-point i'm trying to change it's just a simple hello world.