All pastes #500951 Raw Edit

Stuff

public c v1 · immutable
·published 2007-05-21 20:19 UTC
rendered paste body
#include <elf.h>#include <errno.h>#include <linux/user.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ptrace.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include "libdasm/libdasm.h"#define GI(dest,src) get_instruction(dest, src, MODE_32)int save_entry_hook;int hook_location;int main_entry;char entered_main;Elf32_Ehdr elf;Elf32_Phdr *phdrs;Elf32_Sym *symtab;char *strtab;#define PAGEMASK 0xfffff000#define PAGESIZE 0x1000struct segment{    int start;    int end;    struct segment *next;} segment;struct func{    struct func *next;    void *addr;    char *name;} func;struct segment *seghead;struct func *funchead;void get_plt(int);int ismapped(int);char *lastfunc;struct func *find_func_by_addr(int *addr){    struct func *f;    for(f = funchead; f; f = f->next)    {        if(f->addr == addr)            return f;    }    return NULL;}int add_func(int *addr, char *name){    struct func *f;    if( find_func_by_addr(addr) ) return 0;    f = calloc(1, sizeof(struct func));    if(!f){ printf("Uhoh malloc: %m\n"); exit(0);}    if( funchead )        f->next = funchead;    funchead = f;    f->addr = addr;    f->name = name;    return 1;}int exec_program(char **args){    int p;    switch(p=fork())    {        case -1:            perror("fork");            return -1;        case 0:            ptrace(PTRACE_TRACEME, 0, 0, 0);            execvp(args[0], args);            perror("execv failed");            kill(getppid(),9);            exit(-1);        default:            wait(NULL); //...            return p;    }}int prevp;int parse_position(int pid, int *next_eip){    struct user_regs_struct regs;    int ops[4];    INSTRUCTION inst;        char string[256];       int x = 0;    memset(&regs, 0, sizeof regs);    ptrace(PTRACE_GETREGS, pid, 0, &regs);    x = prevp == regs.eip;    prevp = regs.eip;    if( !ismapped(regs.eip) && !x)         return regs.eip;    if( regs.eip == main_entry )        entered_main = 1;    printf("eax=%.8x ebx=%.8x ecx=%.8x edx=%.8x "           "esi=%.8x edi=%.8x ebp=%.8x esp=%.8x\n",//           "eip=%.8x\n",            regs.eax, regs.ebx, regs.ecx, regs.edx,             regs.esi, regs.edi, regs.ebp, regs.esp);//            regs.eip);//TODO, optimize me if necessary, corner cases on end of mapped pages?    ops[0] = ptrace(PTRACE_PEEKTEXT, pid, regs.eip, 0);    ops[1] = ptrace(PTRACE_PEEKTEXT, pid, regs.eip+4, 0);    ops[2] = ptrace(PTRACE_PEEKTEXT, pid, regs.eip+8, 0);    ops[3] = ptrace(PTRACE_PEEKTEXT, pid, regs.eip+12, 0);    GI( &inst, &ops );    get_instruction_string(&inst, FORMAT_ATT, regs.eip, string, sizeof(string));//TODO: resove memory addresses, relevant vars//  variable tracking ( to determine whats a string, whats a struct, etc )    printf("%x: %s",regs.eip, string);    if( inst.type == INSTRUCTION_TYPE_CALL ||         inst.type == INSTRUCTION_TYPE_JMP ||        inst.type == INSTRUCTION_TYPE_JMPC)    {        if( inst.immbytes )        {            int *dest =  (int *)((unsigned int)regs.eip + inst.op1.immediate + inst.length);            struct func *f = NULL;            f = find_func_by_addr(dest);            if(f){                printf(" \t###\t%s()",f->name);                lastfunc = f->name;            }                                }    }    printf("\n");////    //TODO: assumption is the brother of failure    if( inst.type == INSTRUCTION_TYPE_CALL )        *next_eip = regs.eip + inst.length;    else if (inst.type == INSTRUCTION_TYPE_RET)        *next_eip = 0;    return 0;}void set_hook(int pid, int location){    hook_location = location; //save to global for run_hook    //save dword @ location    save_entry_hook = ptrace(PTRACE_PEEKTEXT, pid, location, 0);        //hook it w/ an int3    ptrace(PTRACE_POKETEXT, pid, location, (save_entry_hook & 0xffffff00)+0xcc);}void run_hook(int pid){    struct user_regs_struct regs;    int ret;    ret = ptrace(PTRACE_CONT, pid, 0, 0);    if(ret == -1) perror("ptrace");    wait(NULL);    printf("done waiting\n");    //restore hook    ret = ptrace(PTRACE_POKETEXT, pid, hook_location, save_entry_hook);    if(ret == -1) {      if(strcmp(lastfunc,"exit") == 0)        exit(0);       perror("ptrace on run_hook after PTRACE_CONT"); exit(1);     }    //set eip to eip - 1    ptrace(PTRACE_GETREGS, pid, 0, &regs);    regs.eip -= 1;    ptrace(PTRACE_SETREGS, pid, 0, &regs);}void walk_to_end(int pid){    int ret,status=0;    int next_eip; //used to set up hooks, dont want to single-step lib functions...    int i = 0;    do    {        ret = ptrace(PTRACE_SINGLESTEP, pid, 0, 0);        wait(&status);        if(ret == -1)            perror("ptrace");            ret = parse_position(pid, &next_eip);        i += 1;        if(ret != 0 && next_eip && entered_main ) //left to a segment that was not selected        {            set_hook(pid, next_eip);            run_hook(pid);        }            } while (WIFSTOPPED(status));    ptrace(PTRACE_CONT, pid, 0, 0);}int read_data(int pid, void *dest, int src, int len){    int ret;    int i = 0;    unsigned int *p = (unsigned int *)dest;    while(i*4 < len)    {        ret = ptrace(PTRACE_PEEKTEXT, pid, src+i*4, 0);        if(errno) {      perror("ptrace read_data"); exit(1); }        p[i++] = ret;    }    return i*4;}int read_string(int pid, int addr){    char *string;    int i, ret, cursize;    cursize = 4096;    string = malloc(cursize);    if(string == NULL ) { perror("malloc read_string"); exit(1);}    //length is unknown...    string[0] = '\0';    while(1)    {        ret = ptrace(PTRACE_PEEKTEXT, pid, addr, 0);        addr += 4;        if(errno) {      perror("ptrace read_string"); exit(1); }                if(i+4 >= cursize){            if(cursize + 4096 < cursize) {                printf("LOLLERCOPTERZ\n"); exit(1);            }            string = realloc(string, cursize + 4096);            if(string == NULL ) { perror("realloc read_string"); exit(1);}                    }        strncat(string, &ret, 4);        //check for NULL string terminator        if( (ret & 0xff) == 0  || (ret>>8&0xff) == 0             || (ret>>16&0xff) == 0 || (ret>>24&0xff) == 0)            break;    }        return string;}void read_headers(int pid){    char buf[256];    int ret, x, addr;    FILE *f;    //read maps    ret = snprintf(buf, sizeof buf, "/proc/%d/maps",pid);    if( ret >= sizeof buf || ret < 0)    { printf("Path too long. Truncated to %s. Quitting\n",buf); exit(1); }      f = fopen(buf, "r");    if(!f){perror("maps"); exit(1);}    fscanf(f, "%x-", &addr);    fclose(f);        read_data(pid, (void *)&elf, addr, sizeof(Elf32_Ehdr));    phdrs = calloc(elf.e_phnum, sizeof(Elf32_Phdr));        read_data(pid, phdrs, addr + elf.e_phoff, sizeof(Elf32_Phdr)*elf.e_phnum);    for(x = 0; x < elf.e_phnum; x++)    {        if(phdrs[x].p_type == PT_LOAD){                        struct segment *s = calloc(1, sizeof(struct segment));            if(!s){ perror("Uhoh malloc segment\n"); exit(1);}            if(seghead)                s->next = seghead;            seghead = s;            seghead->start = phdrs[x].p_vaddr & PAGEMASK;            seghead->end = ((phdrs[x].p_vaddr + phdrs[x].p_memsz) & PAGEMASK) + PAGESIZE;                        }    }}void hook_entry(int pid){/*    //fetch ehdr->e_entry;    ret = ptrace(PTRACE_PEEKTEXT, pid, &(e->e_entry), 0);    if(errno) {      perror("ptrace"); exit(1); }*/    read_headers(pid);    set_hook(pid, elf.e_entry);    main_entry = ptrace(PTRACE_PEEKTEXT, pid, elf.e_entry+24, 0);    if(errno) {      perror("ptrace find main"); exit(1); }}int main(int argc, char **argv){    int pid;    if(!argv[1])    {   printf("Usage: %s target args\n",argv[0]);   exit(0); }    pid = exec_program(argv+1);    if(pid == -1)    { printf("FAILED TO EXECUTE TARGET %s\n",argv[1]);  exit(0); }    hook_entry(pid);    get_plt(pid);    run_hook(pid);    walk_to_end(pid);    return 0;}int ismapped(int a){    struct segment *s;    s = seghead;    while(s)    {        if((unsigned int)a <= s->end && (unsigned int)a >= s->start)            return 1;        s = s->next;    }    return 0;}char *lookup_rel(int pid, Elf32_Rel *r){    char type;    uint pos;    Elf32_Sym *s;    Elf32_Rel relstruct;    Elf32_Sym symstruct;    read_data(pid, &relstruct, r, sizeof(Elf32_Rel));    type = relstruct.r_info&0xff;    pos = relstruct.r_info >> 8;    s = &symtab[pos];    read_data(pid, &symstruct, s, sizeof(Elf32_Sym));    if(symstruct.st_name)        return read_string(pid, symstruct.st_name+strtab);    else        return NULL;}void get_plt(int pid){    int i, pltrelsz;    int addr;    Elf32_Dyn d;    Elf32_Rel *r, *ri, *jr;    Elf32_Rel relstruct;    for(i = 0; i < elf.e_phnum; i++)    {        if( phdrs[i].p_type == PT_DYNAMIC )            break;    }    if(i == elf.e_phnum)    {        printf("MISSING DYNAMIC PHDR\n");        return;    }    addr = phdrs[i].p_vaddr;    read_data(pid, &d, addr, sizeof(Elf32_Dyn));    for( ; d.d_tag != DT_NULL; )    {        if(d.d_tag == DT_REL)            r = d.d_un.d_val;        else if(d.d_tag == DT_PLTRELSZ)            pltrelsz = d.d_un.d_val;        else if(d.d_tag == DT_JMPREL)            jr = d.d_un.d_val;        else if(d.d_tag == DT_SYMTAB)            symtab = d.d_un.d_val;        else if(d.d_tag == DT_STRTAB)            strtab = d.d_un.d_ptr;        addr += sizeof(Elf32_Dyn);        read_data(pid, &d, addr, sizeof(Elf32_Dyn));    }    for( ri = jr ; (unsigned int)ri < (unsigned int)jr + pltrelsz; ri++ )    {        char *s;        s = lookup_rel(pid, ri);        if(s)            s = strdup(s);        else            s = "unknown";        int func;//        func = (*(int *)( relstruct->r_offset))  -6;        read_data(pid, &relstruct, ri, sizeof(Elf32_Rel));        read_data(pid, &func, relstruct.r_offset, sizeof(int *));        func -= 6;//        printf("GOT@%x plt@%x %s\n",ri->r_offset,func,s);        add_func(func, s);    }}