C语言ELF加载和监控难题!

qq_36500632 2019-01-05 12:52:25
#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;

}




哪位大神帮我实现void loader(char *filename) 方法!必有重谢!!!
...全文
305 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
Csdn技术大神 2019-01-08
  • 打赏
  • 举报
回复
参考源代码就可以了呀多看看
qq_36500632 2019-01-08
  • 打赏
  • 举报
回复
引用 3 楼 赵4老师 的回复:
参考linux源代码中ldd命令对应源代码相关片段。
能不能具体说下……
赵4老师 2019-01-06
  • 打赏
  • 举报
回复
参考linux源代码中ldd命令对应源代码相关片段。
qq_36500632 2019-01-05
  • 打赏
  • 举报
回复
哪位大神帮我实现void loader(char *filename) 方法!必有重谢!!!
qq_36500632 2019-01-05
  • 打赏
  • 举报
回复
能不能具体点说说该怎么写,附上代码

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧