Example #1
0
def patch_32_esp(addr, sub_value, is_sub_esp):
    count = idc.ItemSize(addr)

    #get value
    v = idc.GetOperandValue(addr, 1)
    #print(hex(v))

    if v == -1:
        print('get value error')
        return

    if count == 3:
        #.text:0804867C 83 EC 18                                sub     esp, 18h
        off = 0xff - v
        if sub_value < off:
            idc.PatchByte(addr + 2, v + sub_value)
        else:
            idc.PatchByte(addr + 2, 0xff)

        idc.MakeCode(addr)
    else:
        #.text:0804875B 81 EC 30 02 00 00                       sub     esp, 230h
        idc.PatchDword(addr + 2, v + sub_value)
        idc.MakeCode(addr)

    if is_sub_esp != 0:
        print('patch [sub esp, %s] ok, addr: %s' % (hex(v), hex(addr)))
    else:
        print('patch [add esp, %s] ok, addr: %s' % (hex(v), hex(addr)))

    return
Example #2
0
def patch_64_rsp(addr, sub_value, is_sub_rsp):
    count = idc.ItemSize(addr)

    #get value
    v = idc.GetOperandValue(addr, 1)
    #print(hex(v))

    if v == -1:
        print('get value error')
        return

    if count == 4:
        #.text:000055BBF4127FD9 48 83 EC 10                             sub     rsp, 10h
        off = 0xff - v

        if sub_value < off:
            idc.PatchByte(addr + 3, v + sub_value)
        else:
            idc.PatchByte(addr + 3, 0xff)

        idc.MakeCode(addr)
    else:
        #.text:00007EFEA44A5310 48 81 EC 20 01 00 00                    sub     rsp, 120h
        idc.PatchDword(addr + 3, v + sub_value)
        idc.MakeCode(addr)

    if is_sub_rsp != 0:
        print('patch [sub rsp, %s] ok, addr: %s' % (hex(v), hex(addr)))
    else:
        print('patch [add rsp, %s] ok, addr: %s' % (hex(v), hex(addr)))

    return
Example #3
0
def FixFmulY(head, y, bFun):
    # fix y
    global g_off_y
    for off in g_off_y:
        if bFun:
            idc.PatchByte(head + off + 7, y)
        else:
            idc.PatchByte(head + off, y)
    return
Example #4
0
File: elt.py Project: hakril/midap
    def patch(self, patch, fill_nop=True):
        """Change the content of object by `patch`
                if fill_nop is True and size(patch) < size(object): add some 0x90
        """
        print("PATCH ASKED at <{0}| size {1}> with {2}".format(
            self.addr, self.size, patch))
        nop = 0x90  #<- need to adapt to other platform
        if self.size < len(patch):
            raise ValueError("Patch if too big for {0}".format(self))
        if self.size != len(patch) and not fill_nop:
            pass
            # raise Value("Patch is too small for {0} and no fill_patch (better idea than raise ?)".format(self))
            # Not patching other bytes seems cool ?

        full_patch = list(patch) + [nop] * (self.size - len(patch))
        for addr, byte in zip(range(self.addr, self.addr + self.size),
                              full_patch):
            if isinstance(byte, str):
                byte = ord(byte)
            if idc.Byte(addr) == byte:
                print("NOPATCH BYTE : SAME VALUE")
                continue
            if not idc.PatchByte(addr, byte):
                print("PATCH addr {0} with byte {1} failed".format(
                    hex(addr), hex(byte)))
Example #5
0
def patchBinary(start, data, size=-1):
    if size < 0:
        size = len(data)
    else:
        size = min(len(data), size)

    for i in range(size):
        idc.PatchByte(start + i, ord(data[i]))
def resolve_loops():

    PATTERNS = ["81 FB ?? ?? ?? ?? 75"]

    count_patched = 0
    count_not_patched = 0

    for pattern in PATTERNS:

        ea = 0

        while ea != BADADDR:
            '''
             pattern: 81 FB ?? ?? ?? ?? 75
            .text:00406AA0 01 C7                add     edi, eax
            .text:00406AA2 66 41                inc     cx
            .text:00406AA4 43                   inc     ebx
            .text:00406AA5 81 FB A6 01 00 00    cmp     ebx, 1A6h
            .text:00406AAB 75 F3                jnz     short loc_406AA0

            patched:
            .text:00406AA0 01 C7                add     edi, eax
            .text:00406AA2 66 41                inc     cx
            .text:00406AA4 43                   inc     ebx
            .text:00406AA5 90                   nop
            .text:00406AA6 90                   nop
            .text:00406AA7 90                   nop
            .text:00406AA8 90                   nop
            .text:00406AA9 90                   nop
            .text:00406AAA 90                   nop
            .text:00406AAB 90                   nop
            .text:00406AAC 90                   nop
            '''

            ea = idc.FindBinary(ea, SEARCH_NEXT | SEARCH_DOWN | SEARCH_CASE,
                                pattern)

            if ea_in_bounds(ea):

                # Patch CMP and conditional jmp instructions in order to remove the loop
                idc.PatchByte(ea + 0, 0x90)
                idc.PatchByte(ea + 1, 0x90)
                idc.PatchByte(ea + 2, 0x90)
                idc.PatchByte(ea + 3, 0x90)
                idc.PatchByte(ea + 4, 0x90)
                idc.PatchByte(ea + 5, 0x90)
                idc.PatchByte(ea + 6, 0x90)
                idc.PatchByte(ea + 7, 0x90)

                idc.MakeCode(ea)

                count_patched += 1

    print "\tPatched resolve_loops: {0}".format(count_patched)
    print "\tNot Patched resolve_loops: {0}".format(count_not_patched)
Example #7
0
def copy(fl, ea=None):
    if ea is None:
        ea = idc.ScreenEA()

    fl = open(fl, 'rb')
    ctn = fl.read()
    fl.close()

    for i, c in enumerate(ctn):
        idc.PatchByte(ea + i, ord(c))
def mem_hook(unicornObject, accessType, memAccessAddress, memAccessSize,
             memValue, userData):
    #if accessType == UC.UC_MEM_READ:
    #    print("Read: ", hex(memAccessAddress), memAccessSize, hex(memValue))
    if accessType == UC.UC_MEM_WRITE:
        #print("Write: ", hex(memAccessAddress), memAccessSize, hex(memValue))
        if memAccessSize == 1:
            idc.PatchByte(memAccessAddress, memValue)
        elif memAccessSize == 2:
            idc.PatchWord(memAccessAddress, memValue)
        elif memAccessSize == 4:
            idc.PatchDword(memAccessAddress, memValue)
Example #9
0
def patch_call_free(addr):
    count = idc.ItemSize(addr)

    #.text:000011E1         E8 5A FE FF FF                  call    _free
    #.text:000055BBF4127EFF E8 5C F9 FF FF                  call    _free
    for i in range(count):
        idc.PatchByte(addr + i, 0x90)  #patch to NOP instr

    idc.MakeCode(addr)

    print('patch [call _free] ok, addr: %s' % hex(addr))

    return
def PatchCall(addr):
    '''
    To improve IDA's analysis, the patch converts call abuse
    into push and jmp instructions. The patched data is saved
    as a comment.
    '''

    if idc.Byte(addr) == 0xE8:
        logger = logging.getLogger(__name__)
        logger.info("Patching push as call @ %x" % addr)
        data_size = idc.Dword(addr + 1)
        if (data_size) >= 0xfe:
            logger.info("Can't patch: 0x%x" % addr)
            return
        fname = idc.GetFunctionName(addr)
        target = idc.GetOperandValue(addr, 0)
        data_addr = addr + idautils.DecodeInstruction(addr).size
        orig_data = idc.Word(data_addr)
        orig_asm = idc.GetDisasm(addr)
        idc.MakeUnknown(addr, target - addr,
                        idaapi.DOUNK_EXPAND | idaapi.DOUNK_DELNAMES)
        idc.PatchByte(addr, 0x68)
        idc.PatchDword(addr + 1, data_addr)
        idc.PatchByte(data_addr, 0xEB)
        idc.PatchByte(data_addr + 1, data_size - 2)
        # idaapi.analyze_area(addr, data_addr + 2)
        uksize = 0
        if fname != idc.GetFunctionName(target) and fname is not None:
            while uksize < 32:
                x = idautils.DecodeInstruction(target + uksize)
                if x is None:
                    break
                uksize += x.size
            idc.MakeUnknown(target, uksize,
                            idaapi.DOUNK_EXPAND | idaapi.DOUNK_DELNAMES)
            # idaapi.analyze_area(target, target + uksize + 1)
        idc.MakeComm(addr, "Original: " + orig_asm)
        idc.MakeComm(data_addr, "Original: %x" % orig_data)
Example #11
0
 def to_dbg(self, found_state):
     if type(found_state) == StateManager:
         return self.to_dbg(found_state.state)
     for key in self.symbolics:
         try:
             if key in load_project().arch.registers:
                 r = found_state.solver.eval(self.symbolics[key][0],
                                             cast_to=int)
                 idc.SetRegValue(r, key)
             else:
                 r = found_state.solver.eval(self.symbolics[key][0],
                                             cast_to=str)
                 for i in xrange(len(r)):
                     idc.PatchByte(key + i, ord(r[i]))
         except Exception as ee:
             print " >> failed to write %s to debugger" % key
Example #12
0
def patch_word(ea, value, wordsize=WORD_SIZE):
    """Patch the word at the given address.

    Words are patched using PatchByte(), PatchWord(), PatchDword(), or PatchQword(), as
    appropriate.
    """
    if wordsize == 1:
        idc.PatchByte(ea, value)
    elif wordsize == 2:
        idc.PatchWord(ea, value)
    elif wordsize == 4:
        idc.PatchDword(ea, value)
    elif wordsize == 8:
        idc.PatchQword(ea, value)
    else:
        raise ValueError('Invalid argument: wordsize={}'.format(wordsize))
def resolve_opaque_jnz_jz():

    PATTERNS = [
        "0F 84 ?? ?? ?? ?? 0F 85 ?? ?? ?? ??",
        "0F 85 ?? ?? ?? ?? 0F 84 ?? ?? ?? ??"
    ]

    count_patched = 0
    count_not_patched = 0

    for pattern in PATTERNS:

        ea = 0

        while ea != BADADDR:

            ea = idc.FindBinary(ea, SEARCH_NEXT | SEARCH_DOWN | SEARCH_CASE,
                                pattern)
            ''' 
            pattern: 0F 85 ?? ?? ?? ?? 0F 84 ?? ?? ?? ??
            .text:0040690E 66 21 CF            and     di, cx
            .text:00406911 0F 85 AE F4 FF FF   jnz     loc_405DC5 <- j_1_pos
            .text:00406917 0F 84 A8 F4 FF FF   jz      loc_405DC5 <- j_2_pos
            
            patched:
            .text:0040690E 66 21 CF            and     di, cx
            .text:00406911 90                  nop
            .text:00406912 90                  nop
            .text:00406913 90                  nop
            .text:00406914 90                  nop
            .text:00406915 90                  nop
            .text:00406916 90                  nop
            .text:00406917 E9 A9 F4 FF FF      jmp     loc_405DC5

            '''

            if ea_in_bounds(ea):

                # .text:00406911 0F 85 AE F4 FF FF  jnz loc_405DC5 <- j_1_pos
                #                      AE F4 FF FF                 <- j_1_value Relative offset value
                j_1_pos = ea
                j_1_value = Dword(j_1_pos + 0x2)

                j_2_pos = j_1_pos + 0x6
                j_2_value = Dword(j_2_pos + 0x2)

                pos_jmp = j_1_pos + j_1_value + 0x6

                if j_1_value - j_2_value == 0x6:

                    addr_to_jmp = j_2_value + 0x1

                    # Patch the jz and jnz instructions with NOPs (12 bytes)
                    for i in range(0, 12):
                        idc.PatchByte(j_1_pos + i, 0x90)

                    # Patch with a relative jmp (size = 5) in the position of the second conditional jmp
                    idc.PatchByte(j_2_pos, 0xE9)
                    idc.PatchDword(j_2_pos + 0x1, addr_to_jmp)

                    idc.MakeCode(ea)

                    count_patched += 1

                else:

                    count_not_patched += 1

    print "\tPatched resolve_opaque_jnz_jz: {0}".format(count_patched)
    print "\tNot Patched resolve_opaque_jnz_jz: {0}".format(count_not_patched)
def patch(dest, seq):
    for i, c in enumerate(seq):
        idc.PatchByte(dest+i, ord(c))
Example #15
0
def MemCopy( dest, src, length ) :
	for i in xrange(0, length):
		#if (i < 20):
		#	print "set byte at %#x to %#x" % (dest+i, idc.Byte(src+i))
		idc.PatchByte(dest+i,idc.Byte(src+i))
Example #16
0
def fix_callgraph(msgsend, segname, class_param, sel_param):
    '''
  fix_callgraph: msgsend, segname, class_param, sel_param

  Given the msgsend flavour address as a parameter, looks
  for the parameters (class and selector, identified by
  class_param and sel_param) and creates a new segment where
  it places a set of dummy calls named as classname_methodname
  (we use method instead of selector most of the time).
  '''

    t1 = time.time()
    if not msgsend:
        print 'ERROR: msgSend not found'
        return

    total = 0
    resolved = 0
    call_table = dict()

    for xref in idautils.XrefsTo(msgsend, idaapi.XREF_ALL):
        total += 1
        ea_call = xref.frm
        func_start = idc.GetFunctionAttr(ea_call, idc.FUNCATTR_START)
        if not func_start or func_start == idc.BADADDR:
            continue
        ea = ea_call

        method_name_ea = track_param(ea, func_start, idc.o_displ, sel_param)
        if method_name_ea:
            method_name = idc.GetString(method_name_ea, -1, idc.ASCSTR_C)
            if not method_name:
                method_name = ''
        else:
            method_name = ''

        class_name_ea = track_param(ea, func_start, idc.o_phrase, class_param)
        if class_name_ea:
            class_name = idc.GetString(class_name_ea, -1, idc.ASCSTR_C)
            if not class_name:
                class_name = ''
        else:
            class_name = ''

        if not method_name and not class_name:
            continue

        # Using this name convention, if the class and method
        # are identified by IDA, the patched call will point to
        # the REAL call and not one of our dummy functions
        #
        class_name = class_name.replace('_objc_class_name_', '')

        new_name = '_[' + class_name + '_' + method_name + ']'
        call_table[ea_call] = new_name
        resolved += 1

    print '\nFinal stats:\n\t%d total calls, %d resolved' % (total, resolved)
    print '\tAnalysis took %.2f seconds' % (time.time() - t1)

    if resolved == 0:
        print 'Nothing to patch.'
        return

    print 'Adding new segment to store new nullsubs'

    # segment size = opcode ret (4 bytes) * num_calls
    seg_size = resolved * 4
    seg_start = idc.MaxEA() + 4
    idaapi.add_segm(0, seg_start, seg_start + seg_size, segname, 'CODE')

    print 'Patching database...'
    seg_ptr = seg_start
    for ea, new_name in call_table.items():
        if idc.LocByName(new_name) != idc.BADADDR:
            offset = (idc.LocByName(new_name) - ea) & idc.BADADDR
        else:
            # create code and name it
            idc.PatchDword(seg_ptr, 0x90)  # nop
            idc.MakeName(seg_ptr, new_name)
            idc.MakeCode(seg_ptr)
            idc.MakeFunction(seg_ptr, seg_ptr + 4)
            idc.MakeRptCmt(seg_ptr, new_name)
            offset = seg_ptr - ea
            seg_ptr += 4

        dw = offset - 5
        idc.PatchByte(ea, 0xE8)
        idc.PatchDword(ea + 1, dw)
def resolve_opaque_mov_push():

    PATTERNS = [
        "BB 00 00 00 00", "BB 01 00 00 00", "BB 02 00 00 00", "BB 03 00 00 00",
        "BB 04 00 00 00", "BB 05 00 00 00", "BB 06 00 00 00", "BB 07 00 00 00",
        "BB 08 00 00 00", "BB 09 00 00 00", "6A ?? 5B"
    ]

    count_patched = 0
    count_not_patched = 0

    for pattern in PATTERNS:

        ea = 0

        print pattern

        while ea != BADADDR:

            ea = idc.FindBinary(ea, SEARCH_NEXT | SEARCH_DOWN | SEARCH_CASE,
                                pattern)
            ''' pattern: BB 00 00 00 00
            .text:00406A83 BB 00 00 00 00     mov     ebx, 0
            .text:00406A88 66 01 D0           add     ax, dx
            .text:00406A8B 81 F1 B5 15 00 00  xor     ecx, 15B5h
            .text:00406A91 66 35 7A 13        xor     ax, 137Ah
            .text:00406A95 85 DB              test    ebx, ebx
            .text:00406A97 74 14              jz      short loc_406AAD

            Patched EBX > 0
            pattern: BB 09 00 00 00
            .text:00406BE3 BB 09 00 00 00     mov     ebx, 9
            .text:00406BE8 20 D1              and     cl, dl
            .text:00406BEA 66 09 D6           or      si, dx
            .text:00406BED 66 89 D6           mov     si, dx
            .text:00406BF0 85 DB              test    ebx, ebx
            .text:00406BF2 74 02              jz      short loc_406BF6

            Patched EBX == 0
            .text:00406A83 90                 nop
            .text:00406A84 90                 nop
            .text:00406A85 90                 nop
            .text:00406A86 90                 nop
            .text:00406A87 90                 nop
            .text:00406A88 90                 nop
            .text:00406A89 90                 nop
            .text:00406A8A 90                 nop
            .text:00406A8B 90                 nop
            .text:00406A8C 90                 nop
            .text:00406A8D 90                 nop
            .text:00406A8E 90                 nop
            .text:00406A8F 90                 nop
            .text:00406A90 90                 nop
            .text:00406A91 90                 nop
            .text:00406A92 90                 nop
            .text:00406A93 90                 nop
            .text:00406A94 90                 nop
            .text:00406A95 90                 nop
            .text:00406A96 90                 nop
            .text:00406A97 EB 14              jmp     short loc_406AAD

            '''

            if ea_in_bounds(ea):
                '''
                .text:00406A83 BB 00 00 00 00     mov     ebx, <0-9> <- ebx_value
                .text:00406A88 66 01 D0           add     ax, dx
                .text:00406A8B 81 F1 B5 15 00 00  xor     ecx, 15B5h
                .text:00406A91 66 35 7A 13        xor     ax, 137Ah
                .text:00406A95 85 DB              test    ebx, ebx
                .text:00406A97 74 14              jz      short loc_406AAD
                '''

                original_ea = ea

                ebx_value = Byte(ea + 1)

                instr = idautils.DecodeInstruction(ea)

                if instr:

                    has_test = False

                    # while not jmp related instruction found
                    while ((instr.itype <= idaapi.NN_ja)
                           or (instr.itype >= idaapi.NN_jmpshort)):

                        # move to next instr
                        ea = ea + instr.size
                        instr = idautils.DecodeInstruction(ea)

                        # Check in order to validate that has test func and is candidate to be patched
                        if instr.itype == idaapi.NN_test:

                            has_test = True

                    # at this point "ea" variable contains the last instruction address
                    # that is the conditional jump found
                    if has_test:

                        if instr.itype == idaapi.NN_jz:

                            # ebx_value > 0 and NN_jz -> Patch with NOPs
                            if ebx_value > 0:
                                '''
                                .text:00406BE3 BB 09 00 00 00     mov     ebx, 9
                                .text:00406BE8 20 D1              and     cl, dl
                                .text:00406BEA 66 09 D6           or      si, dx
                                .text:00406BED 66 89 D6           mov     si, dx
                                .text:00406BF0 85 DB              test    ebx, ebx
                                .text:00406BF2 74 02              jz      short loc_406BF6
                                '''

                                relative_offset = ea - original_ea

                                # Patch the complete function
                                number_nops = ea - original_ea + instr.size

                                for i in range(0, number_nops):

                                    idc.PatchByte(original_ea + i, 0x90)

                                idc.MakeCode(ea)

                            # ebx_value = 0 and NN_jz -> Patch with JMP
                            else:
                                '''
                                .text:00406A83 BB 00 00 00 00     mov     ebx, 0
                                .text:00406A88 66 01 D0           add     ax, dx
                                .text:00406A8B 81 F1 B5 15 00 00  xor     ecx, 15B5h
                                .text:00406A91 66 35 7A 13        xor     ax, 137Ah
                                .text:00406A95 85 DB              test    ebx, ebx
                                .text:00406A97 74 14              jz      short loc_406AAD
                                '''

                                # ea contains the conditional jmp address
                                relative_offset = Byte(ea + 1)

                                # NOP
                                number_nops = ea - original_ea + instr.size

                                for i in range(0, number_nops):

                                    idc.PatchByte(original_ea + i, 0x90)

                                # Patch the conditional jmp to unconditional jmp
                                idc.PatchByte(ea, 0xEB)
                                idc.PatchByte(ea + 1, relative_offset)

                                idc.MakeCode(ea)

                            count_patched += 1

                    else:

                        count_not_patched += 1

    print "\tPatched resolve_opaque_mov_push: {0}".format(count_patched)
    print "\tNot Patched resolve_opaque_mov_push: {0}".format(
        count_not_patched)
Example #18
0
def load_file(li, neflags, format):
    li.seek(0)
    ndsRom = NintendoDSRom(li.read(li.size()))
    retval = 1

    useArm9 = ask_yn(
        1,
        "This ROM potentially contains both ARM9 and ARM7 code\nDo you want to load the ARM9 binary?"
    )
    if (useArm9 == -1):
        useArm9 = 0

    useArm9 = bool(useArm9)

    proc = ""
    startEA = 0
    endEA = 0
    offset = 0
    entryAddr = 0
    size = 0
    name = ""
    rom = ""
    if (useArm9):
        name = "ARM9 ROM"
        proc = "ARM"
        entryAddr = ndsRom.arm9EntryAddress
        startEA = ndsRom.arm9RamAddress
        endEA = ndsRom.arm9RamAddress + ndsRom.arm9Len
        offset = ndsRom.arm9Offset
        size = ndsRom.arm9Len
        rom = ndsRom.arm9
    else:
        name = "ARM7 ROM"
        proc = "ARM710A"
        entryAddr = ndsRom.arm7EntryAddress
        startEA = ndsRom.arm7RamAddress
        endEA = ndsRom.arm7RamAddress + ndsRom.arm7Len
        offset = ndsRom.arm7Offset
        size = ndsRom.arm7Len
        rom = ndsRom.arm7

    idaapi.set_processor_type(
        proc, idaapi.SETPROC_LOADER_NON_FATAL | idaapi.SETPROC_LOADER)

    memory =  \
    [
        [ startEA, endEA, "RAM" ],
        [ 0x04000000, 0x04001056, "General_Regs" ],
        [ 0x05000000, 0x05000600, "VMEM_Regs" ],
    ]

    if ((startEA < memory[0][0] or endEA > memory[0][1])
            and (startEA < memory[1][0] or endEA > memory[1][1])
            and (startEA < memory[2][0] or endEA > memory[2][1])):
        raise Exception("ROM not mapped into valid mem!")

    for segment in memory:
        idc.AddSeg(segment[0], segment[1], 0, 1, idaapi.saRelPara,
                   idaapi.scPub)
        idc.RenameSeg(segment[0], segment[2])

        if "RAM" not in segment[2]:
            for i in xrange(segment[0], segment[1]):
                idc.PatchByte(i, 0)

    idaapi.add_entry(entryAddr, entryAddr, "start", 1)
    idc.MakeNameEx(entryAddr, "start", idc.SN_NOCHECK | idc.SN_NOWARN)
    idaapi.cvar.inf.startIP = entryAddr
    idaapi.cvar.inf.beginEA = entryAddr
    ida_segment.set_selector(1, 0)
    idaapi.cvar.inf.startCS = 1

    li.seek(0)
    li.file2base(offset, startEA, endEA, 1)

    idaapi.cvar.inf.startCS = 0
    idaapi.cvar.inf.startIP = entryAddr

    idc.ExtLinA(startEA, 1, "; Title : " + str(ndsRom.name))
    idc.ExtLinA(startEA, 1, "; Software Version: " + str(ndsRom.version))

    # Add TwlHdr
    MakeVideoRegs()
    MakeVMemRegs()
    MakeJoypadRegs()
    MakeSystemRegs()
    if name == "ARM7 ROM":
        MakeARM7Regs()
    else:
        MakeARM9Regs()

    print("Done! Entry point @ " + hex(entryAddr))
    return 1
Example #19
0
    def BuildAsmString(self, instr, function):
        if instr.GetMnem() == 'retn':
            mnem = 'ret '
        else:
            if instr.GetMnemPrefix(1) != '':
                mnem = instr.GetMnemPrefix(1) + ' ' + instr.GetMnem(1) + ' '
            else:
                mnem = instr.GetMnem(1) + ' '

        refs = list(function.GetRefsFrom(instr.GetOriginEA()))
        if len(refs) > 1 and instr.GetMnem() != "jmp":
            key = refs[0][0] if refs[0][1] else refs[1][0]

            if self.nasm:
                self.NasmWriteToFile("\t%s L%08x" % (instr.GetMnem(1), key),
                                     instr)
            else:
                if self.bb_head_ea.has_key(key):
                    mnem += '%09xh' % self.bb_head_ea[key]
                    return mnem

                else:
                    for i in xrange(0, 6):
                        idc.PatchByte(self.free_ea + i, 0x90)

                    if self.jmp_deps.has_key(key):
                        self.jmp_deps[key].append(self.free_ea)
                    else:
                        self.jmp_deps[key] = [self.free_ea]

                    self.ref_instr[self.free_ea] = instr
                    self.free_ea += 6

            return ''

        if instr.GetMnem() == 'call':
            if instr.GetOpndType(1) in [2, 5, 6]:
                mnem += '%09xh' % instr.GetOpndValue(1)
            elif instr.GetOpndType(1) == 7:
                comment = instr.GetComment()
                if comment != None and comment == "Artificial: Gen from call $+5":
                    mnem += '$+5'
                else:
                    mnem += '%09xh' % instr.GetOpndValue(1)

            elif instr.GetOpndType(1) == 1:
                mnem += instr.GetOpnd(1)
            else:
                mnem += instr.GetOpnd(1)

            if self.nasm:
                self.NasmWriteToFile("\t%s" % mnem, instr)

            return mnem

        elif instr.GetMnem() == 'jmp':
            if self.nasm:
                tref_from = list(function.GetRefsFrom(
                    instr.GetOriginEA()))[0][0]

                if tref_from == None:
                    #can be unknown
                    if debug:
                        print ">Assemble:BuildAsmString - tref_from = None @ [%08x] " % instr.GetOriginEA(
                        ), instr.GetOpnd(1)

                    if instr.GetOpndType(1) == 2:
                        size_prefix = idaapi.get_item_size(
                            instr.GetOpndValue(1))
                        self.NasmWriteToFile(
                            "\tjmp %s 0x%08x" %
                            (instr.BytesToPrefix(size_prefix),
                             instr.GetOpndValue(1)), instr)
                    else:
                        self.NasmWriteToFile("\tjmp %s" % instr.GetOpnd(1),
                                             instr)
                else:
                    if len(refs) > 1:
                        instr_string = "jmp %s" % instr.GetOpnd(1).replace(
                            "SUBS", "sj_%08x_1" % instr.GetOriginEA())
                        self.NasmWriteToFile("\t%s\n" % instr_string)

                        self.jmp_table_refs.append(instr_string)

                        self.jmp_table += "\n"
                        #self.NasmWriteToFile("\tsj_%08x " % instr.GetOriginEA())

                        counter = 1
                        name = 'sj_%08x' % instr.GetOriginEA()
                        for ref in refs:
                            #self.NasmWriteToFile("%s_%d dd L%08x\n" % (name, counter, ref[0]))
                            self.jmp_table += "%s_%d dd L%08x\n" % (
                                name, counter, ref[0])
                            counter += 1
                    else:
                        self.NasmWriteToFile("\tjmp L%08x" % tref_from, instr)

                return None

            if debug:
                print ">Assemble:BuildAsmString - Got mnem JMP ", refs

            if len(refs) > 1:
                key = refs[0][0] if refs[0][1] else refs[1][0]
            else:
                key = refs[0][0]

            if self.bb_head_ea.has_key(key):
                mnem += '%xh' % self.bb_head_ea[key]
                return mnem

            elif refs[0][0] == None:
                #NOTICE!
                mnem += instr.GetOpnd(1)
                return mnem

            else:
                for i in xrange(0, 6):
                    idc.PatchByte(self.free_ea + i, 0x90)

                if self.jmp_deps.has_key(key):
                    self.jmp_deps[key].append(self.free_ea)
                else:
                    self.jmp_deps[key] = [self.free_ea]

                self.ref_instr[self.free_ea] = instr
                self.free_ea += 6
                return None

        #regular (non CFG) instruction
        if instr.GetOpnd(1) != None and instr.GetOpnd(1) != '':
            if instr.GetOpndType(1) == 2 and re.search(
                    r"\*.*?\+", instr.GetOpnd(1)) == None:
                op_size = idaapi.get_item_size(instr.GetOpndValue(1))

                op_pref_size = instr.GetOpndPrefixSize(1)
                if op_pref_size != None:
                    op_size = op_pref_size

                op_size_2 = 0
                if instr.GetOpndType(2) == 1:
                    op_size_2 = instr.GetRegSize(instr.GetOpnd(2))

                if op_size >= op_size_2:
                    opnd = '%s [0x%08x]' % (instr.BytesToPrefix(op_size),
                                            instr.GetOpndValue(1))
                else:
                    opnd = '%s [0x%08x]' % (instr.BytesToPrefix(op_size_2),
                                            instr.GetOpndValue(1))

                mnem += opnd

            elif instr.GetOpndPrefix(1) != None:
                mnem += '%s %s' % (instr.GetOpndPrefix(1), instr.GetOpnd(1))

            else:
                mnem += instr.GetOpnd(1)

            if instr.GetOpnd(2) != None:
                if instr.GetOpndType(2) == 2 and re.search(
                        r"\*+", instr.GetOpnd(2)) == None:
                    op_disas = instr.GetOpnd(2)
                    op_size = idaapi.get_item_size(instr.GetOpndValue(2))

                    op_pref_size = instr.GetOpndPrefixSize(1)
                    if op_pref_size != None:
                        op_size = op_pref_size

                    op_size_2 = 0
                    if instr.GetOpndType(1) == 1:
                        op_size_2 = instr.GetRegSize(instr.GetOpnd(1))

                    if op_size >= op_size_2:
                        opnd = '%s [0x%08x]' % (instr.BytesToPrefix(op_size),
                                                instr.GetOpndValue(2))
                    else:
                        opnd = '%s [0x%08x]' % (instr.BytesToPrefix(op_size_2),
                                                instr.GetOpndValue(2))

                    if instr.GetMnem() == "lea":
                        opnd = '[0x%08x]' % (instr.GetOpndValue(2))
                        mnem += ', ' + opnd
                    else:
                        mnem += ', ' + opnd

                else:
                    mnem += ', ' + instr.GetOpnd(2)

        elif instr.GetOpnd(2) != None and instr.GetOpnd(2) != '':
            if instr.GetOpndType(2) == 2 and re.search(
                    r"\*+", instr.GetOpnd(2)) == None:
                op_disas = instr.GetOpnd(2)
                op_size = idaapi.get_item_size(instr.GetOpndValue(2))

                op_pref_size = instr.GetOpndPrefixSize(2)
                if op_pref_size != None:
                    op_size = op_pref_size

                op_size_2 = 0
                if instr.GetOpndType(1) == 1:
                    op_size_2 = instr.GetRegSize(instr.GetOpnd(1))

                if op_size >= op_size_2:
                    opnd = '%s [0x%08x]' % (instr.BytesToPrefix(op_size),
                                            instr.GetOpndValue(2))
                else:
                    opnd = '%s [0x%08x]' % (instr.BytesToPrefix(op_size_2),
                                            instr.GetOpndValue(2))

                mnem += opnd

            elif instr.GetOpndType(
                    2) == 3 and instr.GetMnem().upper()[:2] == "FS":
                #this is a special case to handle FS* fp instructions that have 1st argument hidden in IDA
                #and to handle the difference in masm vs nasm (tbyte bs tword).

                #NOTE: GetOpnd(1,1) is used because the first argument is empty when it gets populated
                # by the taint function, so original operand is in GetOpnd(2,0) and cleand (no prefix)
                # operand is in GetOpnd(1,1)
                opnd = '%s %s' % (instr.BytesToPrefix(
                    instr.GetOpndPrefixSize(1)),
                                  instr.StripOpndPrefix(instr.GetOpnd(2)))
                mnem += ' ' + opnd

            else:
                mnem += ' ' + instr.GetOpnd(2)

        if self.nasm:
            self.NasmWriteToFile("\t%s" % mnem, instr)

        return mnem
Example #20
0
    def NasmAssemble(self, function_ea, write_ea):
        dir = self.opty_dir

        nasm = "C:\\Program Files\\nasm\\nasm.exe"
        arg1 = "f_%08x.asm" % function_ea
        arg2 = "-o f_%08x.o" % function_ea
        arg3 = "-l f_%08x.lst" % function_ea
        arg4 = "-Ox"

        orig_dir = os.getcwd()
        os.chdir(dir)

        idc.Batch(0)
        while 1:
            try:
                p = subprocess.Popen([nasm, arg1, arg2, arg3, arg4],
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     stdin=subprocess.PIPE)
                o, e = p.communicate()

                if o != "": print o
                if e != "": print e

                fop = open("f_%08x.o" % function_ea, "rb")

                ans = idaapi.askyn_c(
                    0,
                    "HIDECANCEL\nDo you want to manually edit function before writing to IDA?"
                )
                if ans == 1:
                    os.startfile(arg1, "open")
                    idaapi.warning(
                        "Press OK button when you're done editing file.")
                    fop.close()
                    continue
                else:
                    idc.Batch(1)
                    break

            except:
                error_msg = '\n'.join(e.split("\n")[:15])

                os.startfile(arg1, "open")
                ans = idaapi.askyn_c(
                    1, """HIDECANCEL\nNASM failed to assemble [f_%08x.o] file.
You can manually edit and NASM this file [f_%08x.asm] and click Yes when you're done.
File is located in directory where your IDB is located.
If you want to skip this function press No.

Nasm output:
%s""" % (function_ea, function_ea, error_msg))

                if ans == 1:
                    continue
                else:
                    os.chdir(orig_dir)
                    idc.Batch(1)
                    return None

        os.chdir(orig_dir)

        print ">>>Writing function [%08x] @ [%08x]" % (function_ea, write_ea)

        data = fop.read()
        data_len = len(data)
        for offset in xrange(0, data_len):
            idc.PatchByte(write_ea + offset, ord(data[offset]))
        fop.close()

        idc.MakeCode(write_ea)

        fp = open("%s\\f_%08x.lst" % (dir, function_ea), "r")
        asm_lst = fp.read()

        base_addr = re.search(r"ORG ([\dABCDEF]+)H", asm_lst).group(1)
        base_addr = int(base_addr, 16)

        for jt in self.jmp_table_refs:
            m = re.search(r"\s*\d+\s+([\dABCDEF]{8}).*?%s" % re.escape(jt),
                          asm_lst, re.IGNORECASE)
            if m != None:
                jt_ea = int(m.group(1), 16)
                jt_str = re.search(r"SJ_.{8}", jt, re.IGNORECASE).group()
                for m in re.findall(
                        r"(?i)\n\s*\d+\s+[\dABCDEF]{8}\s+.*?\s+%s" %
                        re.escape(jt_str), asm_lst):
                    r = re.search(r"\d+\s([\dABCDEF]{8})", m.strip(),
                                  re.IGNORECASE).group(1)

                    #print "AddCodeXref(0x%08x, 0x%08x, idc.XREF_USER)" % (jt_ea+base_addr, idc.Dword(int(r, 16)+base_addr))
                    idc.AddCodeXref(jt_ea + base_addr,
                                    idc.Dword(int(r, 16) + base_addr),
                                    idc.XREF_USER)
            else:
                raise MiscError

        for line in asm_lst.split("\n"):
            comment = re.search(r"###(.*?)###", line)
            if comment != None:
                data = re.search(r"\s*\d+\s([\dABCDEF]+)\s([\dABCDEF\(\)]+)",
                                 line)
                if data != None:
                    offset = int(data.group(1), 16)
                    idc.MakeComm(write_ea + offset, comment.group(1))

        fp.close()

        return write_ea + data_len + 10
Example #21
0
def nop(start_address, end_address):
    for junk_code in range(start_address, end_address):
        idc.PatchByte(junk_code, 0x90)
Example #22
0
path = '/'.join(GetInputFilePath().split('\\')[:-1])
path = idc.AskStr(path, 'Enter path of the dump directory: ')

# Open the heap_map
heapmap = open(path + "/heaps/heap_map.txt", 'r')

if heapmap == None:
    print "Wrong path!\n"
    sys.exit(0)

for line in heapmap:
    line = line.split(' ')[:-1]

    heap_bin = open(path + "/heaps/" + line[0], 'rb')

    heap_bin_size = os.fstat(heap_bin.fileno()).st_size
    start_addr = int(line[1], 16)
    end_addr = start_addr + int(line[2], 10)

    # Create a new section that will contain the heap data
    is32bitSeg = 1
    SegAlignment = 32
    idc.SegCreate(start_addr, end_addr, 0, is32bitSeg, SegAlignment, 0)

    # Copy from the heap dump the data inside the new created Section
    addr = start_addr
    for i in xrange(1, heap_bin_size):
        byte = ord(heap_bin.read(1))
        idc.PatchByte(addr, byte)
        addr = NextAddr(addr)
Example #23
0
def PatchArr(dest, str):
    for i, c in enumerate(str):
        if ord(c) != 0x99:
            idc.PatchByte(dest + i, ord(c))
Example #24
0
def zeromemory(ea, size):
    for i in xrange(0, size):
        idc.PatchByte(ea + i, 0)
def resolve_fs30():

    PATTERNS = ["64 ?? 30 00 00 00", "64 ?? ?? 30 00 00 00"]

    count_patched = 0
    count_not_patched = 0

    for pattern in PATTERNS:

        ea = 0

        while ea != BADADDR:
            '''
             pattern: 64 ?? 30 00 00 00
            .text:00407644 64 A1 30 00 00 00                       mov     eax, large fs:30h
            .text:0040764A 50                                      push    eax
            .text:0040764B 80 ED AD                                sub     ch, 0ADh
            .text:0040764E B5 32                                   mov     ch, 32h
            .text:00407650 66 21 D7                                and     di, dx
            .text:00407653 5A                                      pop     edx
            .text:00407654 8A 72 02                                mov     dh, [edx+2]
            .text:00407657 84 F6                                   test    dh, dh
            .text:00407659 74 11                                   jz      short loc_40766C

             pattern: 64 ?? ?? 30 00 00 00
            .text:00406E42 64 8B 15 30 00 00 00                    mov     edx, large fs:30h
            .text:00406E49 52                                      push    edx
            .text:00406E4A 66 35 3D 1B                             xor     ax, 1B3Dh
            .text:00406E4E 20 CD                                   and     ch, cl
            .text:00406E50 28 D1                                   sub     cl, dl
            .text:00406E52 59                                      pop     ecx
            .text:00406E53 8A 51 02                                mov     dl, [ecx+2]
            .text:00406E56 84 D2                                   test    dl, dl
            .text:00406E58 74 11                                   jz      short loc_406E6B

            patched:
            .text:00406E42 64 8B 15 30 00 00 00                    mov     edx, large fs:30h
            .text:00406E49 52                                      push    edx
            .text:00406E4A 66 35 3D 1B                             xor     ax, 1B3Dh
            .text:00406E4E 20 CD                                   and     ch, cl
            .text:00406E50 28 D1                                   sub     cl, dl
            .text:00406E52 59                                      pop     ecx
            .text:00406E53 8A 51 02                                mov     dl, [ecx+2]
            .text:00406E56 84 D2                                   test    dl, dl
            .text:00406E58 EB 11                                   jmp     short loc_406E6B <-----

            '''

            ea = idc.FindBinary(ea, SEARCH_NEXT | SEARCH_DOWN | SEARCH_CASE,
                                pattern)

            if ea_in_bounds(ea):

                instr = idautils.DecodeInstruction(ea)

                if instr:

                    # while not jmp related instruction found
                    while ((instr.itype <= idaapi.NN_ja)
                           or (instr.itype >= idaapi.NN_jmpshort)):

                        # move to next instr
                        ea = ea + instr.size
                        instr = idautils.DecodeInstruction(ea)

                    # ea contains conditional jmp instruction
                    # Patch with relative unconditional jmp
                    idc.PatchByte(ea, 0xEB)
                    idc.MakeCode(ea)

                    count_patched += 1

                else:

                    count_not_patched += 1

    print "\tPatched resolve_fs30: {0}".format(count_patched)
    print "\tNot Patched resolve_fs30: {0}".format(count_not_patched)
 def patch(self, temp=None):
     #用object.buffer中的数据给idb打补丁
     if temp != None:
         self.buffer = temp
         for index, byte in enumerate(self.buffer):
             idc.PatchByte(self.start + index, ord(byte))
Example #27
0
 def reset():
     idc.MakeUnknown(idc.MinEA(), 0x1000, 0)
     for i in range(0x1000):
         idc.PatchByte(idc.MinEA() + i, 0)
Example #28
0
def memset_seg(ea, size):
    for i in xrange(0, size):
        idc.PatchByte(ea + i, 0)
Example #29
0
    def AsmAndWrite(self, mnem, instr=None, write_ea=None, function=None):
        if mnem == '':
            return

        if write_ea != None:
            ea_write = write_ea
        else:
            ea_write = self.free_ea

        idc.MakeUnkn(ea_write, 0)
        #tmp = idaapi.assemble(self.free_ea, self.segment_start, self.free_ea, 1, mnem)

        if debug:
            print ">Assemble:AsmAndWrite - !Writing @ ea[%08x] ip[%08x] instr[%s]" % (
                ea_write, ea_write, mnem)
        tmp = idaapi.assemble(ea_write, 0, ea_write, 1, mnem)

        if instr != None:
            idaapi.set_cmt(ea_write, "%08x" % instr.GetOriginEA(), 0)

        if tmp == 0:
            if instr == None and function != None:
                raise MiscError

            if debug:
                print '>Assemble:AsmAndWrite - !Messy instruction', mnem
                print '>Assemble:AsmAndWrite - Trying original opcodes!'

            refs_from = [
                x for x in function.GetRefsFrom(instr.GetOriginEA())
                if x != None
            ]
            if len(refs_from) == 0:
                if instr.GetIsModified() == True:
                    raise MiscError

                instr_op = instr.GetOpcode()
                for pos in xrange(0, len(instr_op)):
                    idc.PatchByte(ea_write + pos, ord(instr_op[pos]))

                if idc.MakeCode(ea_write) == 0:
                    raise MiscError

                ea_write += idc.ItemSize(ea_write)

            elif len(refs_from) == 1:
                instr_op = instr.GetOpcode()
                for pos in xrange(0, len(instr_op)):
                    idc.PatchByte(ea_write + pos, ord(instr_op[pos]))

                if idc.MakeCode(ea_write) == 0:
                    raise MiscError

                ea_write += idc.ItemSize(ea_write)

            else:
                #print '>Assemble:AsmAndWrite - GetRefsFrom(%08x)' % instr.GetOriginEA(), [hex(x) for x in function.GetRefsFrom(instr.GetOriginEA()) if x != None]
                print '>Assemble:AsmAndWrite - refs_from', refs_from
                print '>Assemble:AsmAndWrite - ea_write [%08x]' % ea_write
                print '>Assemble:AsmAndWrite - mnem', mnem
                print '>Assemble:AsmAndWrite - instr.GetMnem', instr.GetMnem()
                print '>Assemble:AsmAndWrite - instr.GetDisasm', instr.GetDisasm(
                )
                raise MiscError
        else:
            if idc.MakeCode(ea_write) == 0:
                raise MiscError

            ea_write += idc.ItemSize(ea_write)

        if write_ea == None:
            self.free_ea = ea_write
    def __to_native(self, function, is_recursive_mode=False, fixupfile=None):
        """
            Process translating VM byte code to native machine code
            :param function: Function descriptor
            :param is_recursive_mode: Enable recursive mode
            :param fixupfile: Path to fixup file
            :return:  Address of new segment where were native code wrote
        """
        print "[+] Translate begin. Function %s" % hex(function.begin_ea)
        ks = None

        if self.mode == 32:
            ks = Ks(KS_ARCH_X86, KS_MODE_32)
        else:
            ks = Ks(KS_ARCH_X86, KS_MODE_64)

        locs = {
            function.graph.nodes[na].begin_ea
            for na in function.graph.nodes
        }
        func_addresses = []
        for x in function.graph.nodes:
            for y in range(
                    function.graph.nodes[x].begin_ea,
                    function.graph.nodes[x].end_ea + self.instruction_size,
                    self.instruction_size):
                func_addresses.append(y)

        func_ins = {x: self.instructions[x] for x in func_addresses}

        vr0x86_blocks = self.get_vr0blocks(func_ins)

        print "[+] Blocks for %s" % hex(function.begin_ea).replace("L", "")
        i = 0
        for pc in vr0x86_blocks.keys():
            c_vr0, c_end_vr0_block = vr0x86_blocks[pc]
            print "----BLOCK %s----" % i
            print "   -> [?] Block begin: %s" % hex(pc).replace("L", "")
            print "   -> [?] Block end: %s" % hex(c_end_vr0_block).replace(
                "L", "")
            print "   -> [?] Block vr0: %s" % c_vr0
            i += 1

        labels = {}
        li = 0
        for loc in locs:
            labels[loc] = "label_%s" % li
            li += 1

        function_real_base = function.machine_handler
        print "[+] Real function base: %s" % hex(function_real_base).replace(
            "L", "")

        if self.mode == 32:
            asm_text = self._asm_creator_x86(
                func_ins,
                labels,
                vr0x86_blocks,
                function.machine_handler,
                is_recursive_mode=is_recursive_mode,
                fixupfile=fixupfile)
        else:
            asm_text = self._asm_creator_x64(
                func_ins,
                labels,
                vr0x86_blocks,
                function.machine_handler,
                is_recursive_mode=is_recursive_mode,
                fixupfile=fixupfile)

        print asm_text

        segs = list(idautils.Segments())
        last_seg_ea = idc.SegEnd(segs[len(segs) - 1])

        encoding, count = ks.asm(asm_text, addr=last_seg_ea)

        seg_name = ".devirt_%s" % function.name
        seg_size = len(encoding) + self.machine_word_size
        if not idc.AddSeg(last_seg_ea, last_seg_ea + seg_size, 0, 1, 0,
                          idaapi.scPub):
            print "[~] Can't create segment at address %s" % hex(last_seg_ea)
            return

        if not idc.RenameSeg(last_seg_ea, seg_name):
            print "[!] Failed rename segment. Segment name %s" % seg_name

        if not idc.SetSegClass(last_seg_ea, 'CODE'):
            print "[!] Failed set CODE class. Segment name %s" % seg_name

        if not idc.SegAlign(last_seg_ea, idc.saRelPara):
            print "[!] Failed set align. Segment name %s" % seg_name

        bitness = 1
        if self.mode == 64:
            bitness = 2

        if not idc.SetSegAddressing(last_seg_ea, bitness):
            print "[!] Failed set bitness. Segment name %s" % seg_name

        if self.mode == 32:
            idc.PatchDword(last_seg_ea, 0)
        else:
            idc.PatchQword(last_seg_ea, 0)

        last_seg_ea += self.machine_word_size

        waddr = last_seg_ea
        for b in encoding:
            idc.PatchByte(waddr, b)
            waddr += 1

        print "[+] Write binary to: %s" % hex(last_seg_ea).replace("L", "")
        self.devirtualized_functions[function.begin_ea] = (last_seg_ea,
                                                           len(encoding) + 4)
        return last_seg_ea