def apply(self): """ Apply patches to found opaque branch :return: None """ for src, dst in self._flow_patches_map.items(): ir_block: IRBlock = self._ir_cfg.get_block(src) asm_instr = ir_block.assignblks[ir_block.dst_linenb].instr if asm_instr.name not in conditional_branch: log(f"Unsupported asm pattern at {hex(src)}", code='!') continue patch_addr = asm_instr.offset opcode1 = ida_bytes.get_byte(patch_addr) # Fast and Furious if opcode1 == 0x0F: ida_bytes.patch_bytes( patch_addr, b"\xe9" + pack("<I", (dst - (patch_addr + 5)) & (2**32 - 1))) elif ((opcode1 & 0xe0) == 0xe0) or ((opcode1 & 0x70) == 0x70): ida_bytes.patch_byte(patch_addr, 0xeb) ida_bytes.patch_byte(patch_addr + 1, (dst - (patch_addr + 2)) & 0xFF) else: log(f"Unknown first part of opcode at {hex(patch_addr)}", code='!') continue log(f"Apply patch JCC -> JMP at {hex(patch_addr)}")
def main(): print('[*] start debfuscation') for s in get_code_segments(): print('[*] try to deobfuscate {} section'.format( ida_segment.get_segm_name(s))) if s.use32(): junk_patterns = junk_patterns_x86 elif s.use64(): junk_patterns = junk_patterns_x64 else: print('[!] unsupported arch') print('[*] replace junk code to nop') for pattern, pattern_len in junk_patterns: addr_from = idc.find_binary(s.start_ea, ida_search.SEARCH_DOWN, pattern) while addr_from != idaapi.BADADDR and addr_from < s.end_ea: ida_bytes.patch_bytes(addr_from, '\x90' * pattern_len) addr_from = idc.find_binary(addr_from + pattern_len, ida_search.SEARCH_DOWN, pattern) print('[*] hide nop code') addr_from = ida_search.find_text( s.start_ea, 0, 0, 'nop', ida_search.SEARCH_CASE | ida_search.SEARCH_DOWN) while addr_from != idaapi.BADADDR and addr_from < s.end_ea: func_offset = idc.get_func_off_str(addr_from) if type(func_offset) == str and func_offset.find('+') == -1: addr_from = ida_search.find_text( idc.next_head(addr_from), 0, 0, 'nop', ida_search.SEARCH_CASE | ida_search.SEARCH_DOWN) else: i = 0 while True: if ida_bytes.get_byte(addr_from + i) == 0x90: i += 1 else: break if i >= 3: idc.add_hidden_range(addr_from, addr_from + i, 'nop', None, None, 0xFFFFFFFF) print("%08X" % addr_from) addr_from = ida_search.find_text( idc.next_head(addr_from + i), 0, 0, 'nop', ida_search.SEARCH_CASE | ida_search.SEARCH_DOWN) #print('[*] renanlyze') #idc.del_items(s.start_ea, size=s.size()) #time.sleep(1) #idc.plan_and_wait(s.start_ea, s.end_ea) print('[*] done')
def main(): # generated by create_patch.py # test_tamper.exe patches = [(5368713922L, '\xeb\x05'), (5368713991L, '\x90\x90')] # patches = [(5368713887L, '\x90\x90\x90'), (5368713890L, '\x90\x90\x90'), (5368714371L, '\x90'), (5368713914L, '\x90\x90'), (5368713893L, '\x90\x90\x90'), (5368714256L, '\x90'), (5368713896L, '\x90\x90\x90\x90\x90'), (5368713910L, '\x90\x90\x90\x90'), (5368713901L, '\x90\x90\x90'), (5368713916L, '\xeb\x05'), (5368713904L, '\x90\x90\x90'), (5368713907L, '\x90\x90\x90'), (5368713878L, '\x90\x90\x90\x90'), (5368713882L, '\x90\x90'), (5368713979L, '\x90\x90\x90'), (5368713884L, '\x90\x90\x90')] # test_medium.exe # patches = [(5368713486L, '\xeb\x05'), (5368714020L, '\x90\x90'), (5368713951L, '\xeb\x05'), (5368713555L, '\x90\x90'), (5368713833L, '\x90\x90\x90\x90\x90\x90')] # test_large_debug.exe # patches = [(5368714301L, '\xeb\x05'), (5368714826L, '\xeb\x05'), (5368713575L, '\xeb\x05'), (5368714370L, '\x90\x90\x90\x90\x90\x90'), (5368713348L, '\x90\x90\x90\x90\x90\x90'), (5368714893L, '\x90\x90\x90\x90\x90\x90'), (140724005432014L, '\x90\x90'), (5368713425L, '\x90\x90\x90\x90\x90\x90'), (5368713644L, '\x90\x90'), (5368714678L, '\x90\x90\x90\x90\x90\x90'), (140724005415877L, '\xeb\x12')] for addr, val in patches: print('patching {:#x} with {}'.format(addr, hexlify(val))) ida_bytes.patch_bytes(addr, val)
def patch(ea, data): if ida_api_is_new: return ida_bytes.patch_bytes(ea, data) else: for b in data: idc.PatchByte(ea, struct.unpack('B', b)[0]) ea += 1
def bytes(self, value): """ Setter allowing to change the bytes value of the element. .. warning:: No check is made on the size of the array of the setter and it can rewrite more than the size of the element, :param value: A list of int corresponding to the bytes to change. """ if isinstance(value, bytes): ida_bytes.patch_bytes(self.ea, value) elif isinstance(value, list): i = 0 for e in value: ida_bytes.patch_byte(self.ea + i, e) i += 1 else: raise TypeError( "Invalid arg {} for BipElt.bytes setter".format(value))
def start_patch(leetbabes): dec_key_data = [['0x7777', '0x700000018', '0x8', '0x41', '0x0'], ['0x7777', '0x7000000018', '0x8', '0x42', '0x0'], ['0x7777', '0xdb00000018', '0x8', '0x43', '0x0'], ['0x7777', '0x3b00000018', '0x8', '0x27', '0x0'], ['0x7777', '0xa300000018', '0x8', '0x94', '0x0'], ['0x707', '0x700000014', '0x8', '0x41', '0x0'], ['0x707', '0x800000014', '0x8', '0x42', '0x0'], ['0x707', '0xb00000014', '0x8', '0x43', '0x0'], ['0x707', '0x700000014', '0x8', '0x27', '0x0'], ['0x707', '0x700000014', '0x8', '0x94', '0x0'], ['0xaabb', '0x700000014', '0x8', '0x41', '0x0'], ['0xaabb', '0xb00000014', '0x8', '0x42', '0x0'], ['0xaabb', '0x1200000014', '0x8', '0x43', '0x0'], ['0xaabb', '0x800000014', '0x8', '0x27', '0x0'], ['0xaabb', '0xc00000014', '0x8', '0x94', '0x0'], ['0x202', '0x700000018', '0x8', '0x41', '0x0'], ['0x202', '0x9000000018', '0x8', '0x42', '0x0'], ['0x202', '0x11b00000018', '0x8', '0x43', '0x0'], ['0x202', '0x4b00000018', '0x8', '0x27', '0x0'], ['0x202', '0xd300000018', '0x8', '0x94', '0x0'], ['0xabcd', '0x700000018', '0x8', '0x41', '0x0'], ['0xabcd', '0x9000000018', '0x8', '0x42', '0x0'], ['0xabcd', '0x11c00000018', '0x8', '0x43', '0x0'], ['0xabcd', '0x4b00000018', '0x8', '0x27', '0x0'], ['0xabcd', '0xd300000018', '0x8', '0x94', '0x0'], ['0x1234', '0x700000018', '0x8', '0x41', '0x0'], ['0x1234', '0x7700000018', '0x8', '0x42', '0x0'], ['0x1234', '0xe900000018', '0x8', '0x43', '0x0'], ['0x1234', '0x3e00000018', '0x8', '0x27', '0x0'], ['0x1234', '0xad00000018', '0x8', '0x94', '0x0'], ['0x301', '0x700000018', '0x8', '0x41', '0x0'], ['0x301', '0x7800000018', '0x8', '0x42', '0x0'], ['0x301', '0xec00000018', '0x8', '0x43', '0x0'], ['0x301', '0x3f00000018', '0x8', '0x27', '0x0'], ['0x301', '0xaf00000018', '0x8', '0x94', '0x0']] dec_key_data = [[int(x,16) for x in lst] for lst in dec_key_data] for leetbabe_addr in leetbabes: feedcode_addr = FindBinary(leetbabe_addr, SEARCH_DOWN , "DE C0 ED FE") deadcode_addr = FindBinary(leetbabe_addr, SEARCH_DOWN , "DE C0 AD DE") print("1337BABE @ "+hex(leetbabe_addr)) print("FEEDC0DE @ "+hex(feedcode_addr)) print("DEADC0DE @ "+hex(deadcode_addr)) ref_bytes = Qword(leetbabe_addr+4) & 0xffff for qword in dec_key_data: if qword[0] == ref_bytes: patch_addr = leetbabe_addr + 4 + (qword[1] & 0xff) + (qword[1] >> 32) crackme_bytes = Qword(patch_addr) dec_res = decrypt(crackme_bytes, qword) print("Patching " + hex(crackme_bytes) + " with " + hex(dec_res) + " @ " + hex(patch_addr)) ida_bytes.patch_qword(patch_addr, dec_res) print("Patching unnecessary code with NOPS :)") ida_bytes.patch_bytes(leetbabe_addr-1, "\x90"*7) # 0xcc + 1337babe + 2 bytes ida_bytes.patch_bytes(feedcode_addr, "\x90"*4) # feedc0de ida_bytes.patch_bytes(deadcode_addr-1, "\x90"*5) # 0xcc + deadc0de print("======================================")
patches_compare_char = [(0x13b9, 0xb04a5b749d359b75), (0x13bd, 0x28c197b658b3b38d), (0x13c4, 0x1ebfc4589ffc1d0), (0x13ba, 0x3bc43e2f0001b807), (0x13be, 0xffffffb805eb0000)] patches_calculate = [(0x1373, 0x17e27f613f63871), (0x1376, 0x1ebfc453a63b257), (0x1372, 0x89d001e4458bc289)] # Patch the irrelevant 0xCC bytes rip = [0x17f9, 0x16d4, 0x17cb, 0x1404, 0x13b2, 0x13d2, 0x136b, 0x1384, 0x152d] CC = [0x17dc, 0x16b7, 0x17c6, 0x13E7, 0x1399, 0x13cd, 0x1352, 0x137f, 0x1528] for i in range(len(rip)): ida_bytes.patch_bytes(CC[i], b'\x90' * (rip[i] - CC[i])) # Patch the encrypted bytes def patch(patches): for i in patches: print(hex(i[0])) ida_bytes.patch_qword(i[0], i[1]) patch(patches_main) patch(patches_read_file) patch(patches_check_key) patch(patches_compare_char) patch(patches_calculate)
buf[dst:dst + 3].encode('hex')) else: pass p = buf.find(pattern, p + 1) # stx / jx fake_jcc = ['\xF8\x73', '\xF9\x72'] for pattern in fake_jcc: p = buf.find(pattern) while p != -1: if ord(buf[p + 2]) < 0x80: dst = p + 3 + ord(buf[p + 2]) ln = dst - p patch_at(p, ln) else: print("CLC", hex(p + addr)) p = buf.find(pattern, p + 1) fake_jcc = ['\x7C\x03\xEB\x03'] for pattern in fake_jcc: p = buf.find(pattern) while p != -1: if buf[p + 5:p + 5 + 2] == '\x74\xFB': ln = 7 patch_at(p, ln) else: print("CLC", hex(p + addr)) p = buf.find(pattern, p + 1) patch_bytes(addr, buf) print('done')
buf = get_bytes(addr, 0x4E837D - addr) def patch_at(p, ln): global buf buf = buf[:p] + "\x90" * ln + buf[p + ln:] pattern = 'B00184C00F85'.decode('hex') p = buf.find(pattern) while p != -1: if buf[p + 6 + 4:p + 6 + 4 + 5] == '\xE9\x00\x00\x00\x00': dst = p + 6 + 4 + get_dword(addr + p + 6) off = dst - p - 5 t = '\xE9' + pack('<I', off) t = t.ljust(6 + 4 + 5, '\x90') patch_bytes(addr + p, t) print(hex(addr + p), hex(addr + dst)) else: pass p = buf.find(pattern, p + 1) pattern = '31C088C184C90F85'.decode('hex') p = buf.find(pattern) while p != -1: if buf[p + 8 + 4:p + 8 + 4 + 5] == '\xE9\x00\x00\x00\x00': patch_bytes(addr + p, '\x90' * (8 + 4 + 5)) print(hex(addr + p), hex(addr + dst)) else: pass p = buf.find(pattern, p + 1)
def on_patchnop(self, code=0): from ida_bytes import patch_bytes patch_bytes(here(), '\x90' * get_item_size(here())) self.Close(0)
import ida_bytes #decryption of encrypted bytes def decrypt_data(encrypted_bytes): xor_key = b'f424' decrypted_bytes = b"" for i in encrypted_bytes: #be careful each byte is process through round as integer, dont want to process null bytes if i != 0: #result of "not" operation "~" is signed int and must be converted to unsigned (& 0xff) decrypted_bytes += ((~((( (i ^ xor_key[0]) ^ xor_key[1]) ^ xor_key[2]) ^ xor_key[3])) & 0xff).to_bytes(1, byteorder='big', signed=False) else: decrypted_bytes += i.to_bytes(1, byteorder='big', signed=False) return decrypted_bytes start_address = 0x405068 #start address of encrypted bytes end_address = 0x405388 #end address of encrypted bytes size = end_address - start_address #size of encrypted bytes original_bytes = ida_bytes.get_bytes(start_address, size) #getting all encrypted bytes decrypted_bytes = decrypt_data(original_bytes) ida_bytes.patch_bytes( start_address, decrypted_bytes) #patching original bytes with decrypted bytes print("Bytes decrypted - start address: 0x%x" % (start_address))
def handler(s): global REG_D, REG_S print("-------------Found-----------") g0 = s.group(0) print("---->Orig bytes and assemble") print_bytes(g0) dism(g0) print(REG_D, REG_S) print("---->Replace bytes and assemble") dism_str = "mov {},{}".format(REG_D, REG_S) print(dism_str + '\nnop') mov_encode = asm(dism_str) nop_encode = asm('nop') replace_encode = mov_encode + nop_encode print[hex(b) for b in replace_encode] r = bytearray(replace_encode) print(r, type(r)) return str(r) pattern = r'[\x00-\xFF]\xB4[\x00-\xFF]\xBC' buf = re.sub(pattern, handler, buf, flags=re.I) #print_bytes(buf) # patch patch_bytes(startAddr, buf)