69,371
社区成员
发帖
与我相关
我的任务
分享
#include <stdio.h>
#include <stdint.h>
#include <sys/mman.h>
#include <assert.h>
#include <elf.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#ifndef __USE_GNU
# define __USE_GNU
#endif
#include <ucontext.h>
#undef __USE_GNU
#include <signal.h>
#define true 1
#define false 0
#define AS_START (uintptr_t)0x8048000
#define AS_SIZE (1 << 24) // 16MB
// create an address space to loader the program
void init_address_space(void) {
void *ret = mmap((void *)AS_START, AS_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
assert(ret != MAP_FAILED);
uint32_t *p = ret;
int i;
for (i = 0; i < AS_SIZE / sizeof(uint32_t); i ++) {
p[i] = rand();
}
}
void bt(uint32_t ebp, uint32_t eip);
// SIGSEGV signal handler
void segv_handler(int signum, siginfo_t *siginfo, void *ucontext) {
printf("catch SIGSEGV\n");
// get ebp and eip from the context
int *regs = ((ucontext_t *)ucontext)->uc_mcontext.gregs;
uint32_t ebp = regs[REG_EBP];
uint32_t eip = regs[REG_EIP];
printf("ebp = %x, eip = %x\n", ebp, eip);
bt(ebp, eip);
exit(0);
}
// install signal handler
void init_signal() {
struct sigaction s;
memset(&s, 0, sizeof(s));
s.sa_flags = SA_SIGINFO;
s.sa_sigaction = segv_handler;
int ret = sigaction(SIGSEGV, &s, NULL);
assert(ret == 0);
}
void init_rand() {
srand(time(0));
}
static char *strtab = NULL;
static Elf32_Sym *symtab = NULL;
static int nr_symtab_entry;
// load symbol table and string table for future use
void load_elf_tables(char *filename) {
int ret;
FILE *fp = fopen(filename, "rb");
assert(fp != NULL);
uint8_t buf[sizeof(Elf32_Ehdr)];
ret = fread(buf, sizeof(Elf32_Ehdr), 1, fp);
assert(ret == 1);
// the first several bytes contain the ELF header
Elf32_Ehdr *elf = (void *)buf;
char magic[] = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3};
// check ELF header
assert(memcmp(elf->e_ident, magic, 4) == 0); // magic number
assert(elf->e_ident[EI_CLASS] == ELFCLASS32); // 32-bit architecture
assert(elf->e_ident[EI_DATA] == ELFDATA2LSB); // littel-endian
assert(elf->e_ident[EI_VERSION] == EV_CURRENT); // current version
assert(elf->e_ident[EI_OSABI] == ELFOSABI_SYSV || // UNIX System V ABI
elf->e_ident[EI_OSABI] == ELFOSABI_LINUX); // UNIX - GNU
assert(elf->e_ident[EI_ABIVERSION] == 0); // should be 0
assert(elf->e_type == ET_EXEC); // executable file
assert(elf->e_machine == EM_386); // Intel 80386 architecture
assert(elf->e_version == EV_CURRENT); // current version
// load section header table
uint32_t sh_size = elf->e_shentsize * elf->e_shnum;
Elf32_Shdr *sh = malloc(sh_size);
fseek(fp, elf->e_shoff, SEEK_SET);
ret = fread(sh, sh_size, 1, fp);
assert(ret == 1);
// load section header string table
char *shstrtab = malloc(sh[elf->e_shstrndx].sh_size);
fseek(fp, sh[elf->e_shstrndx].sh_offset, SEEK_SET);
ret = fread(shstrtab, sh[elf->e_shstrndx].sh_size, 1, fp);
assert(ret == 1);
int i;
for(i = 0; i < elf->e_shnum; i ++) {
if(sh[i].sh_type == SHT_SYMTAB &&
strcmp(shstrtab + sh[i].sh_name, ".symtab") == 0) {
// load symbol table
symtab = malloc(sh[i].sh_size);
fseek(fp, sh[i].sh_offset, SEEK_SET);
ret = fread(symtab, sh[i].sh_size, 1, fp);
assert(ret == 1);
nr_symtab_entry = sh[i].sh_size / sizeof(symtab[0]);
}
else if(sh[i].sh_type == SHT_STRTAB &&
strcmp(shstrtab + sh[i].sh_name, ".strtab") == 0) {
// load string table
strtab = malloc(sh[i].sh_size);
fseek(fp, sh[i].sh_offset, SEEK_SET);
ret = fread(strtab, sh[i].sh_size, 1, fp);
assert(ret == 1);
}
}
free(sh);
free(shstrtab);
assert(strtab != NULL && symtab != NULL);
fclose(fp);
}
// TODO: implement the following functions
uintptr_t look_up_symtab(char *sym, int *success) {
int i;
for(i = 0; i < nr_symtab_entry; i ++) {
uint8_t type = ELF32_ST_TYPE(symtab[i].st_info);
if((type == STT_FUNC) && strcmp(strtab + symtab[i].st_name, sym) == 0) {
*success = true;
return symtab[i].st_value;
}
}
*success = false;
return 0;
}
const char* find_fun_name(uint32_t eip) {
static const char not_found[] = "???";
int i;
for(i = 0; i < nr_symtab_entry; i ++) {
if(ELF32_ST_TYPE(symtab[i].st_info) == STT_FUNC &&
eip >= symtab[i].st_value && eip < symtab[i].st_value + symtab[i].st_size) {
return strtab + symtab[i].st_name;
}
}
return not_found;
}
//任务一:寻找正确的入口地址
uintptr_t get_entry(void)
{
(*(void(*)())0x00002b57)();
return 0;
}
//任务二:实现框架代码中的loader()函数
void loader(char *filename)
{
FILE *fp = fopen(filename, "r");
assert(fp != NULL);
Elf32_Ehdr *elf;
Elf32_Phdr *ph = NULL, *eph;
uint8_t buf[4096];
int ret = fread(buf, 4096, 1, fp);
assert(ret == 1);
// scan the program header table, load each loadable segment into memory
//需要补充实现以下代码,作用在于扫描程序头表,装载各装载的段到虚拟内存中
}
//任务三:实现框架代码中的loader()函数,可选做
void bt(uint32_t ebp, uint32_t eip)
{
struct PartOfStackFrame {
struct PartOfStackFrame *prev_ebp;
uint32_t ret_addr;
uint32_t args[4];
} *sf;
int i = 0;
//需要补充实现以下代码,作用在于让程序发生段错误的时候,打印出当前的栈帧链。
}
int main(int argc, char *argv[]) {
assert(argc >= 2);
init_signal();
init_rand();
init_address_space();
load_elf_tables(argv[1]);
uintptr_t entry = get_entry();
printf("entry = 0x%x\n", entry);
loader(argv[1]);
((void (*) (void))entry)();
return 0;
}