Rewind

From MultimediaWiki
Jump to navigation Jump to search

Rewind is the project name of my (Benjamin Larsson) collection of different tools to aid Reverse Engineering. The goal is to combine all the tools into 'the' tool for codec RE'ing work under Linux.


Elftractor

This Perl script can analyze elf binaries to extract the data tables. The produced tables look quite good and tables with 1 or 2 dimensions can be produced. The script uses a database which can be edited to adjust the different types of possibe tables. Rudimentary function skeleton generation can also be done.

Features missing:

  • >2 dimensions for table generation
  • always generate compilable tables


REbug

A set of macros and functions that can trace a selected calltree. Based partly on this code [1]. Currently the output can then be processed to produce call graphs over executed code.

Current features:

  • function call tracing
  • function argument dumping
  • function return value dumping
  • executed calltree graphing
  • memory tracking - lookup the use of malloc in the executed code
  • structure resolver - check all malloced memory for pointers to other malloced memory
  • dumping of the process memory map - this will aid the argument typing check

Features missing:

  • argument typing - check/guess if the arguments are pointers to allocateded or stack memory, table elements or something else
  • loop detection - guess existence of loop construct by checking the amount of consecutive calls
  • code skeleton generation - generate a code template with the generated information
  • structure graphing - generate a nice looking graph over the relations in the structures
  • IDA pro idc script - generate idc code to propagate function prototypes into IDA pro

Current code and theory of operation:

/* this macro starts execution logging */
#define START_TRAP() {\
    call_count = 0; \
    ret_count = 0; \
    opcount = 0; \
    last_opcode_was_call = 0; \
    asm("push %eax"); \
    asm("pushf"); \
    asm("pop %eax"); \
    asm("or $0x100, %eax"); \
    asm("push %eax"); \
    asm("popf"); \
    asm("pop %eax"); }

/* this macro shuts off execution logging */
#define STOP_TRAP() {\
    asm("push %eax"); \
    asm("pushf"); \
    asm("pop %eax"); \
    asm("and $0xFFFFFEFF, %eax"); \
    asm("push %eax"); \
    asm("popf"); \
    asm("pop %eax"); }


/* The TrapHander, this function is called after every executed instruction when the trap is installed */  
static void TrapHandler(int parm, siginfo_t* sigInfo, ucontext_t *uap) {

    opcount++;
    disassemble_address_f(sigInfo->si_addr, &instruction);

    if (last_opcode_was_call) {
        last_opcode_was_call = 0;
        fprintf (addressfile, "%08X call %08X\n", sigInfo->si_addr, called_address);
        call_count++;
    }

    if ((instruction.mnemonic[0] == 'r') &&
        (instruction.mnemonic[1] == 'e') &&
        (instruction.mnemonic[2] == 't') &&
        (instruction.mnemonic[3] == '\0')) {
        fprintf (addressfile, "%08X ret\n", sigInfo->si_addr);
        //Dump the return value
        fprintf (addressfile, "%08X\n", uap->uc_mcontext.gregs[REG_EAX]);
        ret_count++;
    }

    if ((instruction.mnemonic[0] == 'c') &&
        (instruction.mnemonic[1] == 'a') &&
        (instruction.mnemonic[2] == 'l') &&
        (instruction.mnemonic[3] == 'l') &&
        (instruction.mnemonic[4] == '\0')) {
        called_address = sigInfo->si_addr;
        last_opcode_was_call = 1;
        //Dump the arguments pased on the stack, the 10 can be changed o what is needed
        for (i = 0; i < 10; i++)
            fprintf (addressfile, "%08X,", *(unsigned int *)(uap->uc_mcontext.gregs[REG_ESP] + (i * 4)));
        fprintf (addressfile, "\n");
    }
}


/* set up the disassembler types*/
#include "../libdis.h"
typedef int (*disassemble_address_type)(char *buf, struct instr *i);
typedef int (*disassemble_init_type)(int options, int format);
typedef int (*disassemble_cleanup_type)(void);
static disassemble_address_type disassemble_address_f;
static disassemble_init_type disassemble_init_f;
static disassemble_cleanup_type disassemble_cleanup_f;

/* set up the disassembler code */
dl_handle2 = dlopen("/usr/lib/libdisasm.so",RTLD_NOW);
if (dl_handle2) {
    disassemble_address_f = dlsym(dl_handle2,"disassemble_address");
    disassemble_init_f = dlsym(dl_handle2,"disassemble_init");
    disassemble_cleanup_f = dlsym(dl_handle2,"disassemble_cleanup");
} else {
    printf("can't open libdisasm.so - %s\n",dlerror());
    return -1;
}
disassemble_init_f(0, INTEL_SYNTAX);


/* install the traphandler */
#include <signal.h>
struct sigaction sa;
sa.sa_handler = TrapHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART|SA_SIGINFO;  /* Restart functions if interrupted by handler */
if (sigaction(SIGTRAP, &sa, NULL) == -1)
    printf("signal handler failed to attach!\n");

To use this code one has to first setup and init the disassembling functions and the trap handler. Then start and stop the trapping with the help of the START_TRAP/STOP_TRAP macros. When the start macro is run the CPU interupts and runs the trap handler after every executed instruction. The trap handler disassembles the EIP (instruction pointer, points to the next instruction to be executed) and checks if it is a "call" or a "ret" instruction. If a "call" is found the arguments on the stack are dumped. If it is a "ret" the content of "eax" is dumped.

The most current files can be found at http://tranquillity.campus.ltu.se/~banan/rewind.

Argument resolver

This Perl script can analyse the IDA Pro produced assembly of a binary and give a fairly accurate number of arguments to a function and its return type. This script is meant to be used together with REbug output.