Exemple #1
0
class Disassembler():
    def __init__(self, filename, raw_bits=0):
        self.code = {}
        self.code_idx = []
        self.binary = Binary(filename, raw_bits)

        arch = self.binary.get_arch()
        if arch == ARCH_x86:
            self.bits = 32
        elif arch == ARCH_x64:
            self.bits = 64
        else:
            die("only x86 and x64 are supported")


    def disasm(self, addr):
        (data, virtual_addr, flags) = self.binary.get_section(addr)

        if not flags["exec"]:
            die("the address 0x%x is not in an executable section" % addr)

        mode = CS_MODE_64 if self.bits == 64 else CS_MODE_32
        md = Cs(CS_ARCH_X86, mode)
        md.detail = True

        for i in md.disasm(data, virtual_addr):
            self.code[i.address] = i
            self.code_idx.append(i.address)

        # Now load imported symbols for PE. This cannot be done before,
        # because we need the code for a better resolution.
        if self.binary.get_type() == T_BIN_PE:
            self.binary.load_import_symbols(self.code)


    def get_addr_from_string(self, opt_addr, raw=False):
        if opt_addr is None:
            if raw:
                return 0
            search = ["main", "_main"]
        else:
            search = [opt_addr]

        found = False
        for s in search:
            if s.startswith("0x"):
                a = int(opt_addr, 16)
            else:
                a = self.binary.symbols.get(s, -1)

            if a != -1:
                found = True
                break

        if not found:
            error("symbol %s not found" % search[0])
            die("Try with --sym to see all symbols.")
        
        return a


    def dump(self, addr, lines):
        i_init = index(self.code_idx, addr)
        end = min(len(self.code_idx), i_init + lines)

        # set jumps color
        i = i_init
        while i < end:
            inst = self.code[self.code_idx[i]]
            if is_jump(inst) and inst.operands[0].type == X86_OP_IMM:
                pick_color(inst.operands[0].value.imm)
            i += 1

        i = i_init
        while i < end:
            inst = self.code[self.code_idx[i]]
            if inst.address in self.binary.reverse_symbols:
                print_symbol(inst.address)
                print()
            print_inst(inst, 0)
            i += 1


    def print_calls(self):
        for i in self.code_idx:
            inst = self.code[i]
            if is_call(inst):
                print_inst(inst)


    def get_graph(self, addr):
        graph = self.__extract_func(addr)
        graph.init()
        return graph


    def print_symbols(self):
        for addr in self.binary.reverse_symbols:
            sy = self.binary.reverse_symbols[addr]
            print("0x%x   %s" % (addr, sy))


    def __error_jmp_reg(self, i):
        error("failed on 0x%x: %s %s" % 
                (i.address, i.mnemonic, i.op_str))
        error("Sorry, I can't generate the flow graph.")
        die("Try with --dump or with --forcejmp")


    def load_user_sym_file(self, fd):
        for l in fd:
            arg = l.split()
            addr = int(arg[0], 16)
            self.binary.reverse_symbols[addr] = arg[1]
            self.binary.symbols[arg[1]] = addr


    # Generate a flow graph of the given function (addr)
    def __extract_func(self, addr):
        curr = self.code[addr]
        gph = Graph(self, addr)
        rest = []

        while 1:
            if not gph.exists(curr):
                if is_uncond_jump(curr) and len(curr.operands) > 0:
                    if curr.operands[0].type == X86_OP_IMM:
                        addr = curr.operands[0].value.imm
                        nxt = self.code[addr]
                        gph.set_next(curr, nxt)
                        rest.append(nxt.address)
                    else:
                        if not forcejmp:
                            self.__error_jmp_reg(curr)
                        gph.add_node(curr)

                elif is_cond_jump(curr) and len(curr.operands) > 0:
                    if curr.operands[0].type == X86_OP_IMM:
                        nxt_jump = self.code[curr.operands[0].value.imm]
                        direct_nxt = self.code[curr.address + curr.size]
                        gph.set_cond_next(curr, nxt_jump, direct_nxt)
                        rest.append(nxt_jump.address)
                        rest.append(direct_nxt.address)
                    else:
                        if not forcejmp:
                            self.__error_jmp_reg(curr)
                        gph.add_node(curr)

                elif is_ret(curr):
                    gph.add_node(curr)

                else:
                    try:
                        nxt = self.code[curr.address + curr.size]
                        gph.set_next(curr, nxt)
                        rest.append(nxt.address)
                    except:
                        gph.add_node(curr)
                        pass

            try:
                curr = self.code[rest.pop()]
            except IndexError:
                break

        return gph