def patch_segment(self, seg_name): for seg in self.segments: if seg_name in seg['name']: print("patch %s: 0x%x - 0x%x" % (seg['name'], seg['start'], seg['end'])) for i in range(len(seg['data'])): idc.patch_byte(seg['start'] + i, seg['data'][i])
def deobfuscate_rets(ea): if idc.get_wide_byte(ea) == 0x83: fill_with_nops(ea, ea + 7) else: fill_with_nops(ea, ea + 8) idc.patch_byte(ea, 0xC3) idc.create_insn(ea) return True
def simplify_jumps(ea): # If we got long first conditional jump if idc.get_wide_byte(ea) == 0x0F: alternative_jmp_cmd = idc.get_wide_byte(ea + 1) ^ 1 interm_jmp_offt = 6 else: alternative_jmp_cmd = idc.get_wide_byte(ea) ^ 0xF1 interm_jmp_offt = 2 # Get intermediate jump's value if idc.get_wide_byte(ea + interm_jmp_offt) == 0x0F: interm_jmp_param = idc.get_wide_dword(ea + interm_jmp_offt + 2) final_jmp_addr = ea + interm_jmp_param + interm_jmp_offt + 6 else: interm_jmp_param = idc.get_wide_byte(ea + interm_jmp_offt + 1) final_jmp_addr = ea + interm_jmp_param + interm_jmp_offt + 2 # Check the last conditional jump # 75 ?? ... 0F 85 ?? ?? ?? ?? if idc.get_wide_byte(final_jmp_addr) == 0x0F and \ idc.get_wide_byte(final_jmp_addr + 1) == alternative_jmp_cmd: final_jmp_param = idc.get_wide_dword(final_jmp_addr + 2) final_jmp_target = (final_jmp_addr + final_jmp_param + 6) & 0xFFFFFFFF # 75 ?? ... 75 ?? elif idc.get_wide_byte(final_jmp_addr) ^ 0xF0 == alternative_jmp_cmd: final_jmp_param = idc.get_wide_byte(final_jmp_addr + 1) final_jmp_target = (final_jmp_addr + final_jmp_param + 2) & 0xFFFFFFFF # Make a little cleanup: remove garbage code elif interm_jmp_param < 0x10: fill_with_nops(ea + interm_jmp_offt, final_jmp_addr) return True else: return if final_jmp_target - ea < 0xFF: fill_with_nops(ea + interm_jmp_offt, final_jmp_target) else: fill_with_nops(ea + interm_jmp_offt, final_jmp_addr + 6) # Restore seconds jump idc.patch_byte(ea + interm_jmp_offt, 0x0F) idc.patch_byte(ea + interm_jmp_offt + 1, alternative_jmp_cmd) idc.patch_dword(ea + interm_jmp_offt + 2, final_jmp_target - (ea + interm_jmp_offt) - 6) idc.create_insn(ea + interm_jmp_offt) return True
def dbg_process_start(self, pid, tid, ea, name, base, size): self.mem_for_inline_hooks = 0 self.virtualalloc = 0 ntdll = DllHook('ntdll.dll') ntdll.add_func( FuncHook('ntdll_NtClose', NtClose_inline_hook_code_32, NtClose_bpt_cond_hook_code_32)) ntdll.add_func( FuncHook('ntdll_NtQueryInformationProcess', NtQueryInformationProcess_inline_hook_code_32, NtQueryInformationProcess_bpt_cond_hook_code_32)) self.dlls = [ntdll] # IDA creates a segment named "TIB[XXXXXXXX]", which points to # wow_peb64 antually. We can get peb from wow_peb64 with 0x1000 offset. # peb_addr = wow_peb64_addr + 0x1000 # Note: IDA has not created segment "TIB[XXXXXXXX]" at this point. # tid = get_current_thread() # tib_segm_name = "TIB[%08X]" % tid # print tib_segm_name # tib_segm = get_segm_by_name(tib_segm_name) # wow_peb64 = tib_segm.start_ea # peb = tib_segm.start_ea + 0x1000 # on debugging start, ebx points to peb # get addrs of peb and wow_peb64 ebx = idc.get_reg_value("ebx") peb = ebx wow_peb64 = peb - 0x1000 # patch peb->BeingDebugged # solving peb->NtGlobalFlag and "Heap Magic" anti-debug method # at the same time. idc.patch_byte(peb + 2, 0) idc.patch_byte(wow_peb64 + 2, 0) # patching peb process paramters peb_process_parameters = idaapi.get_dword(peb + 0x10) flag = idaapi.get_dword(peb_process_parameters + 0x8) idc.patch_dword(peb_process_parameters + 0x8, flag | 0x4000) # patching peb64 process paramters peb64_process_parameters = idaapi.get_qword(wow_peb64 + 0x20) flag = idaapi.get_dword(peb64_process_parameters + 0x8) idc.patch_dword(peb64_process_parameters + 0x8, flag | 0x4000)
def resolve_calls_through_register(ea): next_instr_addr = idc.get_wide_dword(ea + 1) # Check if that's just a parameter passing through stack if ea & 0xFFFF0000 != next_instr_addr & 0xFFFF0000: return if next_instr_addr - ea > 0x100: return if idc.get_wide_byte(ea + 6) & 0xF0 in [0x20, 0xE0]: call_param = 0x9000 + idc.get_wide_byte(ea + 6) ^ 0x30 else: call_param = idc.get_wide_word(ea + 6) ^ 0x30 fill_with_nops(ea, next_instr_addr) idc.patch_byte(ea, 0xFF) idc.patch_word(ea + 1, call_param) idc.create_insn(ea) return True
def cleanup_resolveapi_calls(ea): delta = 0 if idc.get_wide_byte(ea) == 0x6A else 3 intermediate_call_target = idc.get_wide_dword(ea + 8 + delta) if intermediate_call_target > 0x40: return # Check if we got library name if idc.get_wide_dword(ea + intermediate_call_target + 8 + delta) != 0x006c6c64: # "dll\x00" return # Check if we got enough space for patching if idc.get_wide_dword(ea + intermediate_call_target + 0x11 + delta) != 0x90909090 or \ idc.get_wide_byte(ea + intermediate_call_target + 0x15 + delta) != 0x90: return idc.patch_byte(ea + 7 + delta, 0xEB) idc.patch_byte(ea + 8 + delta, intermediate_call_target + 3) fill_with_nops(ea + 9 + delta, ea + 0xC + delta) idc.create_insn(ea + 7 + delta) # Now we need to pass module name parameter through stack resolve_api_call_param = idc.get_wide_dword(ea + intermediate_call_target + 0xD + delta) resolve_api_call_param = resolve_api_call_param - 5 # offset due to inserted PUSH command # Insert new PUSH command idc.patch_byte(ea + intermediate_call_target + 0xC + delta, 0x68) idc.patch_dword(ea + intermediate_call_target + 0xD + delta, ea + 0xC + delta) idc.create_insn(ea + intermediate_call_target + 0xC + delta) # Restore call ResolveApi idc.patch_byte(ea + intermediate_call_target + 0x11 + delta, 0xE8) idc.patch_dword(ea + intermediate_call_target + 0x12 + delta, resolve_api_call_param) idc.create_insn(ea + intermediate_call_target + 0x11 + delta) return True
def cmd_patch_byte(self, a, v): if idc.patch_byte(int(a, 0), int(v, 0)): return "ok" return ""
def memset_seg(ea, size): for i in range(0, size): idc.patch_byte(ea + i, 0)