Ejemplo n.º 1
0
def disassemble(shellcode, mode=32):
    '''
    Does disassembly with distorm3 and handles the string joining
    '''
    if mode == 32:
        disasm = distorm3.Decode(0x0, shellcode, distorm3.Decode32Bits)

    elif mode == 64:
        disasm = distorm3.Decode(0x0, shellcode, distorm3.Decode64Bits)

    elif mode == 16:
        disasm = distorm3.Decode(0x0, shellcode, distorm3.Decode16Bits)

    disassembly = ''
    for line in disasm:

        hexvals = hex_regex.findall(line[2])
        if len(hexvals) > 0 and ('PUSH' in line[2] or 'MOV' in line[2]):
            line = list(line)  # Why you give me tuple Distorm?
            if len(hexvals[0][2:]) > 2:
                line[2] = line[2] + '\t; ' + hexvals[0][2:].decode('hex')
            else:
                line[2] = line[2] + '\t; ' + str(int(hexvals[0], 16))

        disassembly += "0x%08x (%02x) %-20s %s" % (line[0], line[1], line[3],
                                                   line[2]) + "\n"

    return disassembly
Ejemplo n.º 2
0
 def find_function_address(self, proc_as, ret_addr):
     """
     Calculates the function address given a return address. Disassembles code to get through the double indirection
     introduced by the Linux PLT.
     @param proc_as: Process address space
     @param ret_addr: Return address
     @return The function address or None
     """
     if distorm_loaded:
         decode_as = self.decode_as
         retaddr_assembly = distorm3.Decode(ret_addr - 5, proc_as.read(ret_addr - 5, 5), decode_as)
         if len(retaddr_assembly) == 0:
             return None
         #print(retaddr_assembly)
         retaddr_assembly = retaddr_assembly[0] # We're only getting 1 instruction
         # retaddr_assembly[2] = "CALL 0x400620"
         instr = retaddr_assembly[2].split(' ')
         #print(instr)
         if instr[0] == 'CALL':
             try:
                 target = int(instr[1][2:], 16)
             except ValueError:
                 return None
             bytes = proc_as.read(target, 6)
             if not bytes:
                 # We're not sure if this is the function address
                 return target
             plt_instructions = distorm3.Decode(target, bytes, decode_as)
             plt_assembly = plt_instructions[0] # 1 instruction
             #print(plt_assembly)
             instr2 = plt_assembly[2].split(' ')
             #print(instr2)
             if instr2[0] == 'JMP':
                 final_addr = None
                 if instr2[1] == 'DWORD':
                     target2 = int(instr2[2][3:-1], 16)
                 elif instr2[1] == 'QWORD': # if QWORD
                     target2 = int(instr2[2][7:-1], 16)
                 else: # if 0xADDRESS
                     final_addr = int(instr2[1][2:],16)
                 if not final_addr:
                     final_addr = target + 6 + target2
                 debug.info("Found function address from instruction {} at offset 0x{:016x}".format(instr2, target))
                 return read_address(proc_as, final_addr)
             elif instr2[0] == 'PUSH' and instr2[1] == 'RBP':
                 # This is an internal function
                 debug.info("Found function address from instruction {} at offset 0x{:016x}".format(instr, target))
                 return target
             else:
                 # In case push rbp is removed
                 debug.info("Found function address from instruction {} at offset 0x{:016x}".format(instr, target))
                 return target
         return None
     else:
         return None
Ejemplo n.º 3
0
    def _extract_gadget(self, pc, data, mode):
        """ Returns the gadget found with the given data """
        disasm = distorm3.Decode(pc, data, mode)

        instr_list = []
        addr_list  = []
        for d in disasm:
            addr = d[0]
            size = d[1]
            inst = d[2].lower()
            opcodes = d[3]

            ### if inst in blacklist:
            # @Performance: Needed because the above does not work as intended
            if any(True for bl in self.blacklist if bl in inst):
                return None, None

            instr_list.append(inst)
            addr_list.append(addr)

            ### if inst in ends:
            # @Performance: Needed because the above does not work as intended
            # (the above does exact matching and ret 0x20 or something similar does not get flagged)
            if any(True for end in self.ends if end in inst):
                return addr_list, instr_list

        # Did not find an end
        return None, None
Ejemplo n.º 4
0
def asm_to_dasm(asm_shellcode):
    max_instr_len = 3
    if args.two_byte_stager != 'disabled':
        max_instr_len = 2

    ## assemble
    payload = nasm_assemble(asm_shellcode, asm_tmp_bin)

    ## disassemble
    dasm = distorm3.Decode(0, payload, distorm3.Decode32Bits)

    ## perform some simple sanity checks
    for i in range(0, len(dasm)):
        instr = dasm[
            i]  # 0: offset, 1: len, 2: mnemonic 3: opcodes (hexlified)

        ## 1) check if all opcodes are <= 2 or 3 bytes except mov REG32, IMM32
        if instr[LEN] > max_instr_len and not instr_is_mov_reg32_imm32(
                instr[OPCODE]):
            raise Exception(("[-] Instruction \"{:s}\" is greater than {:d} " +
                             "bytes (currently unsupported)").format(
                                 instr[MNEMONIC], max_instr_len))

        ## 2) Jccs have to be preceded by test/cmp/... for 3 byte stager
        if args.two_byte_stager != 'disabled' and instr_is_jcc(
                instr[MNEMONIC]):
            pre_instr = dasm[i - 1]  ## preceding instr
            if not instr_is_compare(pre_instr[MNEMONIC]):
                ## add your allowed preceding instr here
                #if not pre_instr[MNEMONIC].startswith("TEST") and not pre_instr[MNEMONIC].startswith("CMP"):
                raise Exception(
                    "[-] Conditional jumps have to be " +
                    "preceded immediately by flag-setting instruction")

    return dasm
Ejemplo n.º 5
0
def get_gadgets():
    gadget = []
    gadget2 = []
    interesting_gadgets = []
    # chain = []
    off = []  # address of gadget
    for i in range(START, END):
        lst1 = []
        lst2 = []
        flag = 0
        # change i+20 if gadgets not found
        decoded = distorm3.Decode(VA + i, data[i:i + 20], MODE)
        addr = []
        inst = []
        for x in decoded:
            addr.append(x[0])
            inst.append(x[2])
        for x, y in zip(inst, addr):
            lst1.append("0x%.4x:  %s" % (y, x))
            lst2.append(x)
            if "RET" in x:
                flag = 1
                break
        if flag:
            tmp = "\n".join(lst1)
            tmp2 = "; ".join(lst2)
            if "DB " in tmp:  # If the disassembly process failed
                continue
            if tmp in gadget:  # Checking if its not already found
                continue
            off.append(lst1[0].split()[0])
            gadget.append(tmp)
            gadget2.append(tmp2)  # gadgets in a single line

    return off, gadget, gadget2
    def disassemble( self, address = None, lines = None ):
        """
        Display unassembley (disassembly) of memory
        Gets:
            unsigned long   address
            unsigned long   lines
        """
        if not IS_DISTORM_SUPPORTED:
            raise Exception("Distrom not found, please install the distorm3 module")

        if( None == address ):
            self.getCurrentContext()
            address = self.context.rip
        if( None != lines ):
            bytes_to_read = [lines * 8, 100][lines * 8 < 100]   # Thats should be enough, and if not who cares.
        else:
            bytes_to_read = 100     # That's a magic number

        # First read the relavent data.
        # Remove all break points, so we wont read them
        self._uninstallAllBreakPoints()
        data = self.readMemory( address, bytes_to_read )
        self._reinstallAllBreakPoints()

        # Now disassemble with distorm.
        data = distorm3.Decode( address, data, distorm3.Decode32Bits )

        # Print the result
        data[:lines]
        for opcode in data:
            print("0x{0:08X} ({1:02X}) {2:<20s} {3:s}".format(opcode[0], opcode[1], opcode[3], opcode[2]))

        return
	def decode(self, addr, data):
		if not isinstance(data, tuple):
			raise TypeError("expected tuple of integers for data, got %s" % type(data))

		str_data = "".join([chr(x) for x in data])
		for ds_inst in distorm3.Decode(addr, str_data, self.decode_size):
			yield self.make_instr(ds_inst)
Ejemplo n.º 8
0
    def canonicalize_distorm(self):
        decoded = distorm3.Decode(self.addr, self.bytes, self.arch.distorm_bits)
        assert len(decoded) == 1
        decoded = decoded[0]

        assert decoded[0] == self.addr
        assert decoded[1] == len(self.bytes)
        self.canonicalsyntax = decoded[2]
 def disasm(self, addr, length=0x100, decodeType=1):
     if IS_DISASSEMBLER_FOUND:
         for opcode in distorm3.Decode(addr, self.readMemory(addr, length),
                                       decodeType):
             print('{0:x} {1:24s} {2:s}'.format(opcode[0], opcode[3],
                                                opcode[2]))
     else:
         raise Exception("No disassembler module")
Ejemplo n.º 10
0
def bytes_to_code(bytestring):
    instructions = [
        '    db  ' + ', '.join('0x%02x' % c for c in bytestring[i:i + w]) +
        ' ' * (18 - len(opcodes) * 3) + ' ; ' + instr
        for i, w, instr, opcodes in distorm3.Decode(0, bytestring,
                                                    distorm3.Decode32Bits)
    ]
    return "\n".join(instructions)
Ejemplo n.º 11
0
def main():
    if (len(sys.argv) != 2) and (len(sys.argv) != 3):
        print os.path.split(
            sys.argv[0])[1] + " <PE file name> <new image base in hex>"
        return None
    filename = sys.argv[1]
    NewImageBase = None
    if (len(sys.argv) == 3):
        NewImageBase = int(sys.argv[2], 16)
    PEObj = PEFile(filename, NewImageBase)
    print "diSlib, http://ragestorm.net/distorm/\n"
    print "Image Base: 0x%08x, Code Size: 0x%x" % (PEObj.ImageBase,
                                                   PEObj.CodeSize)
    print "Entry Point RVA: %08x" % PEObj.EntryPoint
    print "Sections:"
    for i in PEObj.Sections[:-1]:
        print "%d.Name: %s, VA: %x, Size: %x, Flags: %x" % (
            i.Index + 1, i.Name, i.VA, i.Size, i.Flags)
    if PEObj.Imports:
        print "Imports:"
        for i in PEObj.Imports:
            print i
    try:
        if PEObj.Exports:
            print "Exports:"
            for i in PEObj.Exports:
                print i
    except:
        # Ignore corrupted exports.
        pass
    if PEObj.Relocs:
        print "Relocations:"
        for i in PEObj.Relocs:
            print i

    try:
        # If diStorm isn't available, we won't disassemble anything.
        import distorm3

        DecodeType = distorm3.Decode32Bits
        if (PEObj.MachineType == IMAGE_FILE_MACHINE_AMD64):
            DecodeType = distorm3.Decode64Bits

        # Find code section and disassemble entry point routine.
        TextSec = PEObj.GetSectionByVA(PEObj.EntryPoint)
        if TextSec == None:
            return
        l = distorm3.Decode(
            PEObj.ImageBase + PEObj.EntryPoint,
            TextSec.Data[PEObj.EntryPoint - TextSec.VA:][:4 * 1024],
            DecodeType)
        for i in l:
            print "0x%08x (%02x) %-20s %s" % (i[0], i[1], i[3], i[2])
            if ((i[2][:3] == "RET") or (i[2] == "INT 3")
                    or (i[2][:3] == "JMP")):
                break
    except:
        pass
Ejemplo n.º 12
0
def shell_insert_bytes(sl, ni, bytes, label=-1, jmp_label=-1):
    l = distorm3.Decode(0, bytes, distorm3.Decode32Bits)
    tsize = 0
    for (offset, size, instr, hexdump) in l:
        i = _instr(bytes[offset:offset + size], size, 0)
        i.label = label
        i.jmp_label = jmp_label

        sl.insert(ni, i)
        ni += 1
        tsize += size
    recalc_jmps(sl, ni)
Ejemplo n.º 13
0
def print_disasm(sl):

    ni = 0
    ioff = 0
    for i in sl:
        if i.is_data == 0:
            l = distorm3.Decode(ioff, i.bytes, distorm3.Decode32Bits)
            for (offset, size, instr, hexdump) in l:
                print '%-4i %.8x: %-32s %s' % (ni, offset, hexdump, instr)
                ni += 1
                ioff += size
        else:
            print '%-4i %.8x:' % (ni, ioff),
            print_string_hex(i.bytes)
            print ''
            ioff += i.size
Ejemplo n.º 14
0
def get_addressing_modes():
    opcode = b'\x03'
    result = []
    # for all modrm possibilities
    for modrm in range(256):
        # get all address_code possibitilities, including sib if applicable
        has_sib = ((modrm & 0b111 == 4) and ((modrm >> 6) & 0b11 != 0b11))
        if has_sib:
            address_codes = [bytes([modrm, sib]) for sib in range(256)]
        else:
            address_codes = [bytes([modrm])]
        # for all the resulting address codes
        for address_code in address_codes:
            # create dummy instruction and dissassembly to find ops
            bytestring = opcode + address_code + (15 * b'\0')
            _, num_bytes, instr, _ = distorm3.Decode(0, bytestring,
                                                     distorm3.Decode32Bits)[0]
            op1, op2 = instr[3:].strip().split(', ')
            # extract / parse info
            disp_num_bytes = num_bytes - 2 - has_sib
            if op2[0] == '[':
                groups = re.match(
                    r'\[(?P<b>...)(\+(?P<i>...))?(\*(?P<s>[248]))?(\+0x0)?\]',
                    op2).groupdict()
                op2_dict = {
                    'type': 'mem',
                    'base': groups['b'].lower(),
                    'index':
                    groups['i'].lower() if groups['i'] is not None else None,
                    'scale': int(groups['s'] or '1'),
                    'disp': disp_num_bytes * 8,
                }
            else:
                op2_dict = {
                    'type': 'reg',
                    'reg': op2.lower(),
                }
            info = {
                'address_code': address_code,
                'has_sib': has_sib,
                'op1': op1.lower(),
                'op2': op2_dict,
            }
            result.append(info)
            print('ops', op1, ':', op2, 'res', info)
    return result
Ejemplo n.º 15
0
def DecodeAsm(ea, codeChunk):
    global g_cpu_mode

    # binascii.hexlify(d)
    disasm = distorm3.Decode(ea, codeChunk, g_cpu_mode)

    gmap = []
    gtxt = ""

    for (addr, _, inst, _) in disasm:
        inst = inst.lower()
        gtxt += "%s\n" % (inst)
        gmap.append((addr,inst))
        if inst.find("ret") != -1:
            break

    return (gmap, gtxt)
Ejemplo n.º 16
0
def load_shell(bin, range):
    ret = []

    rbin = []
    ibin = []

    if range != '':
        cr = 0
        for r in range.split(','):
            rr = r.split('-')
            br = int(rr[0])
            er = int(rr[1])
            #print 'from', int(rr[0]), 'to', int(rr[1])
            if br > cr:
                rbin.append(bin[cr:br])
                ibin.append(1)
            rbin.append(bin[br:er])
            ibin.append(0)
            cr = er
        if cr == 0:
            rbin.append(bin[:])
            ibin.append(0)
        elif cr < len(bin):
            rbin.append(bin[cr:])
            ibin.append(1)
    else:
        rbin.append(bin[:])
        ibin.append(0)

    i = 0
    for t in rbin:
        #print len(t), ':', ibin[i]
        i += 1

    i = 0
    for rb in rbin:
        if ibin[i] == 0:
            l = distorm3.Decode(0, rb, distorm3.Decode32Bits)
            for (offset, size, instr, hexdump) in l:
                ret.append(_instr(rb[offset:offset + size], size, 0))
        else:
            ret.append(_instr(rb[:], len(rb), 1))
        i += 1

    parse_shell(ret)
    return ret[:]
Ejemplo n.º 17
0
def print_disasm(sl):

    ni = 0
    ioff = 0
    for i in sl:
        if i.is_data == 0:
            #if i.label >= 0 or i.jmp_label >= 0:
            #	print 'label:', i.label, 'jmp_label:', i.jmp_label
            l = distorm3.Decode(ioff, i.bytes, distorm3.Decode32Bits)
            for (offset, size, instr, hexdump) in l:
                print('%-4i %.8x: %-32s %s' % (ni, offset, hexdump, instr))
                ni += 1
                ioff += size
        else:
            print('%-4i %.8x:' % (ni, ioff), )
            print_string_hex(i.bytes)
            print('')
            ioff += i.size
Ejemplo n.º 18
0
    def find_locals_size(self, proc_as, frames):
        """
        Find the size of the locals of the function, similar to GDB's prologue analysis.
        Buggy and not actually used.

        @param proc_as: Process address space
        @param frames: a list of stack frames
        @return None
        """
        if not distorm_loaded: return

        for frame in frames:
            if frame.function:
                instr = distorm3.Decode(frame.function, proc_as.read(frame.function, 8), self.decode_as)
                if self.is_function_header(instr) and len(instr) > 2:
                    test = instr[2][2].split(' ')
                    if test[0] == 'SUB' and test[1] == 'RSP,':
                        frame.locals_size = int(test[2][2:], 16)
Ejemplo n.º 19
0
def disas_str(addr, data, sixtyfour=False):
    parser = optparse.OptionParser()

    if sixtyfour == True:
        parser.set_defaults(dt=distorm3.Decode64Bits)
    else:
        parser.set_defaults(dt=distorm3.Decode32Bits)

    options, args = parser.parse_args(sys.argv)

    out_insn = []

    disas = distorm3.Decode(addr, data, options.dt)

    for (offset, size, instruction, hexdump) in disas:
        out_insn.append(instruction)

    return out_insn
Ejemplo n.º 20
0
 def is_return_address(self, address, process_info):
     """
     Checks if the address is a return address by checking if the preceding instruction is a 'CALL'.
     @param address: An address
     @param process_info: process info object
     @return True or False
     """
     proc_as = process_info.proc_as
     size = 5
     if distorm_loaded and process_info.is_code_pointer(address):
         offset = address - size
         instr = distorm3.Decode(offset, proc_as.read(offset, size), self.decode_as)
         # last instr, third tuple item (instr string), first 7 letters
         # if instr[-1][2][:7] == 'CALL 0x':
         #     print(instr[-1][2])
         if len(instr) > 0:
             return instr[-1][2][:4] == 'CALL'
         # there's also call <register>
     return False
Ejemplo n.º 21
0
def disas_str(addr, data, sixtyfour=False):
    parser = optparse.OptionParser()

    if sixtyfour == True:
        parser.set_defaults(dt=distorm3.Decode64Bits)
    else:
        parser.set_defaults(dt=distorm3.Decode32Bits)

    # this duplication is dirty, should be fixed
    parser.add_option("--section")
    parser.add_option("--single", action="store_true")
    options, args = parser.parse_args(sys.argv)

    out_insn = []

    disas = distorm3.Decode(addr, data, options.dt)

    for (offset, size, instruction, hexdump) in disas:
        out_insn.append(instruction)

    return out_insn
Ejemplo n.º 22
0
def DecodeAsm(pc, d):
    global X86_MODE

    disasm = distorm3.Decode(pc, d, X86_MODE)

    k = []
    l = ""
    ist = ""

    for d in disasm:
        #print d
        addr = d[0]
        size = d[1]
        inst = d[2].lower()
        t = "0x%x    %s" % (addr, inst)
        l += t + "\n"
        ist += "%s\n" % (inst)
        k.append((addr, inst))
        if inst.find('ret') != -1:
            break

    return (l, k, ist)
Ejemplo n.º 23
0
def disas(buf, array_name='', row_width=16, fancy=False, sixtyfour=False):
    parser = optparse.OptionParser()

    if sixtyfour == True:
        parser.set_defaults(dt=distorm3.Decode64Bits)
    else:
        parser.set_defaults(dt=distorm3.Decode32Bits)

    options, args = parser.parse_args([])

    disas = distorm3.Decode(0, buf, options.dt)
    out = ''

    for (offset, size, instruction, hexdump) in disas:
        tmp = ''

        if fancy:
            tmp += colors.fg('cyan')

        tmp += "%.8x: " % (offset)

        if fancy:
            tmp += colors.fg('red')

        tmp += hexdump
        tmp += " " * (20 - len(hexdump))

        if fancy:
            tmp += colors.fg('green')

        tmp += instruction

        if fancy:
            tmp += colors.end()

        out += "  " + tmp + "\n"

    return out.lower()
Ejemplo n.º 24
0
def generate_asm_js_constants(payload_bin):
    max_instr_len = 3
    offset = 1
    if args.two_byte_stager != 'disabled':
        max_instr_len = 2
        offset = 0

    hex_payload = hexlify(payload_bin)
    constants = []
    # payload starts in the middle/ after 1st byte
    dasm = distorm3.Decode(0, payload_bin[offset:], distorm3.Decode32Bits)
    ## FIXME: current transformation may result in long jumps
    for instr in dasm:
        if instr[LEN] > max_instr_len and not instr_is_mov_reg32_imm32(
                instr[OPCODE]):
            raise Exception("[-] Transformed instruction " + instr[MNEMONIC] +
                            " is too long. FIXME")

    ## 3-byte payload
    if args.two_byte_stager == 'disabled':
        ## 5 byte chunks
        for i in range(0, len(hex_payload), 10):
            #print hex_payload[i:i+10]
            constants += [hex_payload[i:i + 10][2:]]  ## strip 1st byte
            ## assume mov and insert
            if constants[-1][-2:] != test_al:
                ## replace least sig, byte in mov REG32, IMM32 with masking byte
                #print constants[-1]
                constants[-1] = "".join(list(constants[-1])[:-2]) + test_al
                #print constants[-1]
    else:
        for i in range(0, len(hex_payload), 8 + byte_distance * 2):
            constants += [hex_payload[i:i + 8]]  ## strip 1st byte
            #print constants[-1]
        while len(constants[-1]) < 8:
            constants[-1] += "90"

    return constants
Ejemplo n.º 25
0
def do_ezrop(text):
    i = 0
    while i < len(text['data']):
        if text['data'][i] == "\xc3":
            block_len = 10

            while block_len > 1:
                start = i - block_len
                end = start + block_len + 1
                disas = distorm3.Decode(text['addr'] + start,
                                        text['data'][start:end], options.dt)

                if disas[len(disas) - 1][2] == "RET" and match_disas(
                        disas, sys.argv[2]) and ok_disas(disas):
                    found_start = False

                    for (offset, size, instruction, hexdump) in disas:
                        if instruction.find(sys.argv[2]) != -1:
                            found_start = True

                        if found_start == True:
                            out = colors.fg('cyan')
                            out += "%.8x: " % (offset)
                            out += colors.fg('red')
                            out += hexdump
                            out += " " * (20 - len(hexdump))
                            out += colors.fg('green')
                            out += instruction + colors.end()
                            print out

                    print "=" * 50

                    i = i + block_len
                    break

                block_len = block_len - 1

        i = i + 1
Ejemplo n.º 26
0
 def is_return_address(self, address, process_info):
     """
     Checks if the address is a return address by checking if the preceding instruction is a 'CALL'.
     @param address: An address
     @param process_info: process info object
     @return True or False
     #这是使用了 distrom3 插件  查看当前地址address是否为返回地址 (这个函数最终没有使用,可以借鉴)
     """
     proc_as = process_info.get_process_address_space()
     size = 5
     # print type(size) ,type(address)
     start_code_address = process_info.mm.start_code
     end_code_address = process_info.mm.end_code
     if distorm_loaded and start_code_address < address < end_code_address:  #and process_info.is_code_pointer(address):
         offset = address - size
         instr = distorm3.Decode(offset, proc_as.read(offset, size),
                                 self.decode_as)
         # last instr, third tuple item (instr string), first 7 letters
         if instr[-1][2][:7] == 'CALL 0x':
             print(instr[-1][2])
         if len(instr) > 0:
             return instr[-1][2][:4] == 'CALL'
         # there's also call <register>
     return False
Ejemplo n.º 27
0
def extract_gadgets(offset, rawcode):
    global _args

    decoded = distorm.Decode(
        offset, rawcode, _args.arch)  # returns: (offset, size, instr, hexdump)

    line = ""
    gadget = ""
    disasm = []

    for d in decoded:
        addr = d[0]
        size = d[1]
        asm = d[2].lower()

        inst = "0x{:x}    {}".format(
            addr, asm)  # instruction: 0x000000    mov eax, ecx
        line += inst + "\n"  # string of all instructions
        gadget += asm + "\n"  # the gadget in itself, as a string
        disasm.append((addr, asm))  # list of each instruction

        if (gadget.find('ret') != -1):
            break
    return (line, disasm, gadget)
Ejemplo n.º 28
0
        def is_return_address(address):
            # Load 1 instruction (Debian)
            #
            # hardcoding 4 bytes
            size = 4
            bytestr = proc_as.read(address - size, size)

            # Instruction in the form of 'CALL RSP+0x18'
            single_instr = distorm3.Decode(address - size, bytestr, self.decode_as)
            if len(single_instr) == 1 and single_instr[0][2][:4] == 'CALL':
                # we use this one
                # print(single_instr)
                part = single_instr[0][2].split('[')[1]
                if part[:4] == 'RSP+':
                    # take the part after the +, slice off the 0x, and convert to an int
                    rspoffset = int(part.split('+')[1][2:-1],16)
                    return rspoffset

            # Arch linux/Ubuntu
            # load 3 instructions, something like this:
            # mov 0x18(%rsp), %rax (size 5)
            # mov (%rax), %rdx (size 3)
            # callq *reg (size 2)

            # hardcoding 10 bytes
            size = 10

            bytestr = proc_as.read(address - size, size)
            possible = ['RCX', 'RAX']
            instr = distorm3.Decode(address - size, bytestr, self.decode_as)
            # print(instr[-1][2])
            checkother = False
            if 0 < len(instr) < 3:
                pass
            elif len(instr) == 3:
                # check all 3
                checkother = True
            else: return False

            last_instr = instr[-1][2].split(' ')
            register = None


            #print(last_instr)

            if last_instr[0] == 'CALL' and last_instr[1] in possible:
                #print(last_instr)
                register = last_instr[1]
            else:
                # print(last_instr)
                return None

            # Find the offset
            if checkother:
                mov = 'MOV ' + register
                confirmed = True
                movinstr = None
                saveinstr = None
                if mov in instr[0][2]:
                    movinstr = instr[0][2]
                    saveinstr = instr[1][2]
                elif mov in instr[1][2]:
                    saveinstr = instr[0][2]
                    movinstr = instr[1][2]
                else:
                    # that's weird
                    confirmed = False

                if movinstr != None:
                    part = movinstr.split('[')[1]
                    if part[:4] == 'RSP+':
                        # take the part after the +, slice off the 0x, and convert to an int
                        rspoffset = int(part.split('+')[1][2:-1],16)
                        return rspoffset
            return False
Ejemplo n.º 29
0
 def invoke(self, arg, from_tty):
     if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64:
         disas_option = distorm3.Decode64Bits
     else:
         disas_option = distorm3.Decode32Bits
     referenced_strings_dict = shelve.open(
         SysUtils.get_referenced_strings_file(pid), writeback=True)
     referenced_jumps_dict = shelve.open(
         SysUtils.get_referenced_jumps_file(pid), writeback=True)
     referenced_calls_dict = shelve.open(
         SysUtils.get_referenced_calls_file(pid), writeback=True)
     region_list, discard_invalid_strings = receive_from_pince()
     dissect_code_status_file = SysUtils.get_dissect_code_status_file(pid)
     region_count = len(region_list)
     self.memory = open(ScriptUtils.mem_file, "rb")
     buffer = 0x130000  # Has the best record of 13.6 sec. Tested on 0ad with Intel i7-4702MQ CPU and 8GB RAM
     ref_str_count = len(referenced_strings_dict)
     ref_jmp_count = len(referenced_jumps_dict)
     ref_call_count = len(referenced_calls_dict)
     for region_index, region in enumerate(region_list):
         region_info = region.addr, "Region " + str(
             region_index + 1) + " of " + str(region_count)
         start_addr, end_addr = region.addr.split("-")
         start_addr = int(
             start_addr, 16
         )  # Becomes address of the last disassembled instruction later on
         end_addr = int(end_addr, 16)
         region_finished = False
         while not region_finished:
             remaining_space = end_addr - start_addr
             if remaining_space < buffer:
                 offset = remaining_space
                 region_finished = True
             else:
                 offset = buffer
             status_info = region_info + (
                 hex(start_addr) + "-" + hex(start_addr + offset),
                 ref_str_count, ref_jmp_count, ref_call_count)
             pickle.dump(status_info, open(dissect_code_status_file, "wb"))
             try:
                 self.memory.seek(start_addr)
             except (OSError, ValueError):
                 break
             code = self.memory.read(offset)
             disas_data = distorm3.Decode(start_addr, code, disas_option)
             if not region_finished:
                 last_disas_addr = disas_data[-4][0]
                 for index in range(4):
                     del disas_data[
                         -1]  # Get rid of last 4 instructions to ensure correct bytecode translation
             else:
                 last_disas_addr = 0
             for (instruction_offset, size, instruction,
                  hexdump) in disas_data:
                 if isinstance(instruction, bytes):
                     instruction = instruction.decode()
                 if instruction.startswith("J") or instruction.startswith(
                         "LOOP"):
                     found = common_regexes.dissect_code_valid_address.search(
                         instruction)
                     if found:
                         referenced_address_str = common_regexes.hex_number.search(
                             found.group(0)).group(0)
                         referenced_address_int = int(
                             referenced_address_str, 16)
                         if self.is_memory_valid(referenced_address_int):
                             instruction_only = common_regexes.alphanumerics.search(
                                 instruction).group(0).casefold()
                             try:
                                 referenced_jumps_dict[
                                     referenced_address_str][
                                         instruction_offset] = instruction_only
                             except KeyError:
                                 referenced_jumps_dict[
                                     referenced_address_str] = {}
                                 referenced_jumps_dict[
                                     referenced_address_str][
                                         instruction_offset] = instruction_only
                                 ref_jmp_count += 1
                 elif instruction.startswith("CALL"):
                     found = common_regexes.dissect_code_valid_address.search(
                         instruction)
                     if found:
                         referenced_address_str = common_regexes.hex_number.search(
                             found.group(0)).group(0)
                         referenced_address_int = int(
                             referenced_address_str, 16)
                         if self.is_memory_valid(referenced_address_int):
                             try:
                                 referenced_calls_dict[
                                     referenced_address_str].add(
                                         instruction_offset)
                             except KeyError:
                                 referenced_calls_dict[
                                     referenced_address_str] = set()
                                 referenced_calls_dict[
                                     referenced_address_str].add(
                                         instruction_offset)
                                 ref_call_count += 1
                 else:
                     found = common_regexes.dissect_code_valid_address.search(
                         instruction)
                     if found:
                         referenced_address_str = common_regexes.hex_number.search(
                             found.group(0)).group(0)
                         referenced_address_int = int(
                             referenced_address_str, 16)
                         if self.is_memory_valid(referenced_address_int,
                                                 discard_invalid_strings):
                             try:
                                 referenced_strings_dict[
                                     referenced_address_str].add(
                                         instruction_offset)
                             except KeyError:
                                 referenced_strings_dict[
                                     referenced_address_str] = set()
                                 referenced_strings_dict[
                                     referenced_address_str].add(
                                         instruction_offset)
                                 ref_str_count += 1
             start_addr = last_disas_addr
     self.memory.close()
Ejemplo n.º 30
0
def solve():
    shellcode = getShellcode()
    print map(binascii.hexlify, shellcode)
    shellcode = map(ord, shellcode)
    actions = []
    actions = [(3, 'H', False, False), (3, 'H', False, False),
               (3, 'HH', False, False), (3, 'H', False, False),
               (3, 'HHH', False, False), (3, 'HHH', False, False),
               (80, 'S', False, True), (3, 'HH', False, False),
               (3, 'HH', False, False), (3, 'HH', False, False),
               (3, 'HHHH', False, False), (3, 'HH', False, False),
               (3, 'HH', False, False), (3, 'HH', False, False),
               (80, 'S', False, True), (3, 'S', False, False),
               (80, 'S', False, True), (3, 'HHH', False, False),
               (3, 'HH', False, False), (3, 'HHH', False, False),
               (3, 'S', False, False), (3, 'S', False, False),
               (3, 'H', False, False), (3, 'HH', False, False),
               (80, 'S', False, True), (21, 'S', True, False),
               (3, 'H', False, False), (3, 'S', False, False),
               (4, 'S', True, True), (117, 'S', True, False),
               (80, 'S', False, True), (3, 'HHH', False, False),
               (3, 'HH', False, False), (3, 'HHH', False, False),
               (80, 'S', False, True), (3, 'S', False, False),
               (4, 'S', True, True), (3, 'HH', False, False),
               (3, 'H', False, False), (3, 'H', False, False),
               (36, 'S', True, True), (61, 'S', True, False),
               (3, 'HH', False, False), (3, 'HHH', False, False),
               (3, 'HHH', False, False), (3, 'HH', False, False),
               (3, 'HH', False, False), (3, 'HHH', False, False),
               (3, 'H', False, False), (3, 'HHHH', False, False),
               (3, 'HH', False, False), (3, 'S', False, False),
               (3, 'HH', False, False), (3, 'S', False, False),
               (80, 'S', False, True), (3, 'H', False, False),
               (3, 'HH', False, False), (3, 'HH', False, False),
               (49, 'S', True, True), (64, 'S', True, False),
               (3, 'HHH', False, False), (3, 'H', False, False),
               (3, 'H', False, False), (3, 'HHH', False, False),
               (3, 'HH', False, False), (3, 'HHH', False, False)]
    tb = []
    for action in actions:
        sc = 0
        if action[2]:
            sc = action[0]
        else:
            sc = 0x100 - action[0]
        tb.append(sc)
    res = ''.join(map(chr, tb))
    for i in ds3.Decode(0, res, ds3.Decode32Bits):
        print i[2]

    print len(actions)

    sys.exit(0)

    name = 'abcd'
    step = 0
    while True:
        step += 1
        print actions
        nx = doRun(name, actions, shellcode)
        if nx:
            print "finished"
            break