def _eval_load(self, ins: minsn_t, environment: MicroCodeEnvironment) -> Union[None, int]: res_mask = AND_TABLE[ins.d.size] if ins.opcode == m_ldx: load_address = self.eval(ins.r, environment) formatted_seg_register = format_mop_t(ins.l) if formatted_seg_register == "ss.2": stack_mop = mop_t() stack_mop.erase() stack_mop._make_stkvar(environment.cur_blk.mba, load_address) emulator_log.debug("Searching for stack mop {0}".format( format_mop_t(stack_mop))) stack_mop_value = environment.lookup(stack_mop) emulator_log.debug(" stack mop {0} value : {1}".format( format_mop_t(stack_mop), stack_mop_value)) return stack_mop_value & res_mask else: mem_seg = getseg(load_address) seg_perm = mem_seg.perm if (seg_perm & SEGPERM_WRITE) != 0: raise WritableMemoryReadException( "ldx {0:x} (writable -> return None)".format( load_address)) else: memory_value = get_qword(load_address) emulator_log.debug( "ldx {0:x} (non writable -> return {1:x})".format( load_address, memory_value & res_mask)) return memory_value & res_mask
def eval(self, mop: mop_t, environment: MicroCodeEnvironment) -> Union[None, int]: if mop.t == mop_n: return mop.nnn.value elif mop.t in [mop_r, mop_S]: return environment.lookup(mop) elif mop.t == mop_d: return self._eval_instruction(mop.d, environment) elif mop.t == mop_a: if mop.a.t == mop_v: emulator_log.debug("Reading a mop_a '{0}' -> {1:x}".format( format_mop_t(mop), mop.a.g)) return mop.a.g elif mop.a.t == mop_S: emulator_log.debug("Reading a mop_a '{0}' -> {1:x}".format( format_mop_t(mop), mop.a.s.off)) return mop.a.s.off raise UnresolvedMopException( "Calling get_cst with unsupported mop type {0} - {1}: '{2}'". format(mop.t, mop.a.t, format_mop_t(mop))) elif mop.t == mop_v: mem_seg = getseg(mop.g) seg_perm = mem_seg.perm if (seg_perm & SEGPERM_WRITE) != 0: emulator_log.debug("Reading a (writable) mop_v {0}".format( format_mop_t(mop))) return environment.lookup(mop) else: memory_value = get_qword(mop.g) emulator_log.debug( "Reading a mop_v {0:x} (non writable -> return {1:x})". format(mop.g, memory_value)) return mop.g raise EmulationException("Unsupported mop type '{0}': '{1}'".format( mop_type_to_string(mop.t), format_mop_t(mop)))
def resolve_symbols(self, dll): tmpdir = tempfile.gettempdir().replace('\\', '/') + '/' # File who will first contain ordinals then symbols tmpfile = tmpdir + "dotNIETsymbols.txt" tmplog = tmpdir + "dotNIETlogs.txt" # Destination path for a copy of SharedLibrary.dll tmpdll = tmpdir + os.path.basename(dll) # Path to the idat binary, needed to parse a remote idb idat = idc.idadir().replace('\\','/') + '/' + 'idat' + \ ['64' if utils.is_x64(dll) else ''][0] if os.getenv("windir") is not None: idat += '.exe' # script called along with idat in order to parse SharedLibrary.idb parsing_script_path = '"' + os.path.dirname(os.path.realpath(__file__)).replace('\\','/')\ + '/dotNIET/resolve.py"' # we first copy SharedLibrary.dll to tmp to be sure we are in a # writable location shutil.copyfile(dll, tmpdll) # we have to use temporary files because of the ida headless stuff... # pretty dirty ordinals = [] with open(tmpfile, 'w') as f: for i in range(self.nb_symbols): ordinals.append((idaapi.get_qword(self.ordinals + i * 8) & ~0x8000000000000000) * 4) f.write(",".join([str(x) for x in ordinals])) # be prepared to wait as this will load the binary + pdb idaapi.msg("Starting parsing of %d symbols...\n" % self.nb_symbols) subprocess.run([idat, "-L" + tmplog, "-c", "-A", "-S" + \ parsing_script_path + " " + tmpfile, tmpdll], creationflags=subprocess.CREATE_NO_WINDOW, check=True) # we read back tmpfile which now contains symbols symbols = [] with open(tmpfile, 'r') as f: symbolsArray = f.read() symbols = symbolsArray.split(',') # we first have to undef structure as it is an array and ida will # refuse to set names within it idc.del_items(self.ordinals) idc.set_cmt(self.ordinals - 8, "Custom imports from SharedLibrary.dll", 0) # we then apply the symbols at this very same location (start of .idata) for i in range(self.nb_symbols): idc.set_name(self.ordinals + i * 8, symbols[i], SN_NOCHECK | SN_FORCE | SN_NODUMMY) # finally we remove our temp files os.remove(tmpfile) os.remove(tmpdll) # ida generate a db os.remove(tmpdll + '.i64') # if everything went smoothly, we should not need this anymore os.remove(tmplog)
def znullptr(address, end, search, struct): magic = idaapi.find_binary(address, end, search, 0x10, idc.SEARCH_DOWN) pattern = '%02X %02X %02X %02X FF FF FF FF' % (magic & 0xFF, ((magic >> 0x8) & 0xFF), ((magic >> 0x10) & 0xFF), ((magic >> 0x18) & 0xFF)) sysvec = idaapi.find_binary(address, cvar.inf.maxEA, pattern, 0x10, idc.SEARCH_UP) - 0x60 idaapi.set_name(sysvec, 'sysentvec', SN_NOCHECK | SN_NOWARN | SN_FORCE) sysent = idaapi.get_qword(sysvec + 0x8) idaapi.set_name(sysent, 'sv_table', SN_NOCHECK | SN_NOWARN | SN_FORCE) sysnames = idaapi.get_qword(sysvec + 0xD0) idaapi.set_name(sysnames, 'sv_syscallnames', SN_NOCHECK | SN_NOWARN | SN_FORCE) # Get the list of syscalls offset = idaapi.find_binary(address, cvar.inf.maxEA, '73 79 73 63 61 6C 6C 00 65 78 69 74 00', 0x10, SEARCH_DOWN) numsyscalls = idaapi.get_qword(sysvec) for entry in xrange(numsyscalls): initial = sysnames + (entry * 0x8) idc.create_data(initial, FF_QWORD, 0x8, BADNODE) offset = idaapi.get_qword(initial) length = idaapi.get_max_strlit_length(offset, STRTYPE_C) name = idaapi.get_strlit_contents(offset, length, STRTYPE_C) sysentoffset = sysent + 0x8 + (entry * 0x30) idaapi.do_unknown_range(sysentoffset - 0x8, 0x30, 0) idaapi.create_struct(sysentoffset - 0x8, 0x30, struct) idc.set_cmt(sysentoffset - 0x8, '#%i' % entry, False) if '{' in name: continue # Rename the functions function = idaapi.get_qword(sysentoffset) idaapi.set_name(function, name.replace('#', 'sys_'), SN_NOCHECK | SN_NOWARN | SN_FORCE)
def update_mop_tracker(self, mba: mbl_array_t, mop_tracker: MopTracker): stack_array_base_address = mba.stkoff_ida2vd(self.sp_offset) # print("stack_array_base_address: {0:x}".format(stack_array_base_address)) for i in range(self.nb_elt): tmp_mop = mop_t() tmp_mop.erase() tmp_mop._make_stkvar(mba, stack_array_base_address + 8 * i) tmp_mop.size = 8 mem_val = idaapi.get_qword(self.mem_offset + 8 * i) & AND_TABLE[8] mop_tracker.add_mop_definition(tmp_mop, mem_val)
def fix_relocs(base_address, relocs_address, relocs_size): cursor = relocs_address end = relocs_address+relocs_size multiplier = 4 * (idaapi.get_dword(cursor) & 1) + 4 cursor += 4 print 'starting to fix relocs...' nb_relocs = 0 delta = idaapi.get_dword(cursor) while delta != 0xFFFFFFFF and cursor < end: current_reloc = base_address + delta while True: decorated_addr = idaapi.get_qword(current_reloc) if decorated_addr & 0x4000000000000000 == 0: if decorated_addr & 0x8000000000000000: #tagged ptr sign_type = (decorated_addr >> 49) & 3 real_addr = base_address + (decorated_addr & 0xFFFFFFFF) modifier = ((decorated_addr >> 32) & 0xFFFF) if decorated_addr & 0x1000000000000: if modifier == 0: modifier = current_reloc modifier_type = 'ptr_addr' else: modifier_type = '0x%X << 48 | ptr_addr & 0xFFFFFFFFFFFF'%(modifier) modifier = (current_reloc & 0xFFFFFFFFFFFF) | (modifier << 48) else: modifier_type = '0x%X'%modifier if sign_type == 0: decorator = 'PACIA %s'%modifier_type if modifier else 'PACIZA' elif sign_type == 1: decorator = 'PACIB %s'%modifier_type if modifier else 'PACIZB' elif sign_type == 2: decorator = 'PACDA %s'%modifier_type if modifier else 'PACDZA' elif sign_type == 3: decorator = 'PACDB %s'%modifier_type if modifier else 'PACDZB' idaapi.set_cmt(current_reloc , decorator, 1) else: real_addr = ((decorated_addr << 13) & 0xFF00000000000000) | (decorated_addr & 0x7ffffffffff) if decorated_addr & 0x40000000000: real_addr |= 0xfffc0000000000 idaapi.patch_qword(current_reloc, real_addr) idaapi.op_offset(current_reloc, 0, idaapi.REF_OFF64) nb_relocs += 1 delta_next_reloc = ((decorated_addr >> 51) & 0x7ff) * multiplier if delta_next_reloc == 0: break current_reloc += delta_next_reloc cursor += 4 delta = idaapi.get_dword(cursor) print '%d relocs fixed!'%nb_relocs
def Pablo(address, end): while address < end: offset = idaapi.find_binary(address, end, '?? FF FF FF FF', 0x10, SEARCH_DOWN) offset -= 0x3 if idaapi.is_unknown(idaapi.get_flags(offset)): if text.start_ea <= idaapi.get_qword(offset) <= abs.end_ea: idaapi.create_data(offset, FF_QWORD, 0x8, BADNODE) address = offset + 0x4
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 pablo(address, end, search): while address < end: address = idaapi.find_binary(address, end, search, 0x10, SEARCH_DOWN) if address > idaapi.get_segm_by_name('CODE').end_ea: offset = address - 0x3 if idaapi.isUnknown(idaapi.getFlags(offset)): if idaapi.get_qword(offset) <= end: idaapi.create_data(offset, FF_QWORD, 0x8, BADNODE) address = offset + 4 else: idaapi.do_unknown(address, 0) idaapi.create_insn(address) idaapi.add_func(address, BADADDR) address += 4
def __get_ptr_val(cls, ea): if idaapi.cvar.inf.is_64bit(): return idaapi.get_qword(ea) return (idaapi.get_dword if idaapi.IDA_SDK_VERSION >= 700 else idaapi.get_long)(ea)
def read_ptr(ea): if EA64: return idaapi.get_qword(ea) return idaapi.get_dword(ea)
def get_qword(self, addr): return idaapi.get_qword(addr)
segX_start = 0 segX_end = 0 for ea in idautils.Segments(): seg = idaapi.getseg(ea) if seg and (seg.perm & idaapi.SEGPERM_EXEC): SigmName = idc.SegName(ea) print '[+] Segments with +X permission: ' + SigmName segX_start = seg.startEA segX_end = seg.endEA # Loop through hypercall table hypercalls = [] valid_hypercall = True addr = hypercall_dispatch_table while valid_hypercall: func_ptr = idaapi.get_qword(addr) # Set struct field sizes in IDA in the HypercallDispatchFormat format if APPLY_TO_IDB: MakeQword(addr) addr += 8 call_code = idaapi.get_word(addr) if APPLY_TO_IDB: MakeWord(addr) addr += 2 is_rep_call = idaapi.get_word(addr) if APPLY_TO_IDB: MakeWord(addr) addr += 2
def get_pointer(address): if arch_size == 32: return idaapi.get_dword(address) else: return idaapi.get_qword(address)