Пример #1
0
    def handle_class(self, ea):
        clazz_ea = ida_bytes.get_qword(ea)
        clazz = Objc2Class(ida_bytes.get_bytes(clazz_ea, Objc2Class.length))
        # if clazz.info & 7 != 0:
        # swift

        meta_class = Objc2Class(
            ida_bytes.get_bytes(clazz.isa, Objc2Class.length))
        meta_class.info = (meta_class.info >> 3) << 3
        meta_info = Objc2ClassRo(
            ida_bytes.get_bytes(meta_class.info, Objc2ClassRo.length))

        clazz.info = (clazz.info >> 3) << 3
        clazz_info = Objc2ClassRo(
            ida_bytes.get_bytes(clazz.info, Objc2ClassRo.length))

        c = Clazz(cstr(clazz_info.name), ea=clazz_ea)

        self.print('@interface', cstr(clazz_info.name))
        for method in method_list(meta_info.base_meths):
            key = '+ ' + cstr(method.name)
            c.methods[key] = method.imp
            self.print(key)

        for method in method_list(clazz_info.base_meths):
            key = '- ' + cstr(method.name)
            c.methods[key] = method.imp
            self.print(key)

        self.print('@end')
        self.print()

        self.classes.append(c)
        self.class_lookup[c.name] = c
        self.lookup[ea] = c
Пример #2
0
    def get_decode_xrefs():
        """
        Find all cross-refernces to 0x132549a in our REvil malware sample.
        Decode the string and annotate the IDA database, this will make analysis a lot
        easier
        """
        for xref in idautils.XrefsTo(0x132549a):
            # first of all, we need to find the arguments to this function, the signature is:
            # BYTE* __cdecl decode_string(char* base, int keyOffset, int keyLen, int dataLen, BYTE* pOut);
            args = get_decode_args(xref.frm)
            if args:
                base, key_offset, key_len, data_len = args
                # get the data from the image, data = [keyBytes][encryptedData]
                data = ida_bytes.get_bytes(base + key_offset,
                                           key_len + data_len)
                str = data_to_str(decode_string(data, key_len, data_len))
                print("0x%08x: %s" % (xref.frm, str))

                # put a comment in the code
                cfunc = idaapi.decompile(xref.frm)
                if cfunc is not None:
                    tl = idaapi.treeloc_t()
                    tl.ea = xref.frm
                    tl.itp = idaapi.ITP_SEMI
                    cfunc.set_user_cmt(tl, str)
                    cfunc.save_user_cmts()
                    idaapi.set_cmt(int(xref.frm), str, True)
            else:
                # We could not get the arguments, likely because it may be a register and not an immediate
                # value, so we'd need to go back further and find what value that register was assigned with.
                # Would be easier to just tell user, and let him decode it manually (HexRays has the actual args)
                print("0x%08x: Could not decode arguments" % xref.frm)
Пример #3
0
def method_list(ea):
    if not ea:
        return

    count = ida_bytes.get_dword(ea + 4)
    name = idc.get_segm_name(ea)
    first = ea + 8

    def post14format(addr):
        for _ in range(3):
            data = ida_bytes.get_bytes(addr, 4)
            offset, = struct.unpack('<i', data)
            yield addr + offset
            addr += 4
        
    is14 = name and (name.endswith(':__objc_const_ax') or name.endswith(':__objc_methlist'))
    for i in range(count):
        if is14:
            # iOS 14
            yield Post14Method(*post14format(first + i * 12))

        else:
            ea_method_t = first + i * Objc2Method.length
            data = ida_bytes.get_bytes(ea_method_t, Objc2Method.length)
            yield Objc2Method(data)
Пример #4
0
 def getBinary(self):
     result = b""
     segment = ida_segment.get_first_seg()
     while segment:
         result += ida_bytes.get_bytes(segment.start_ea,
                                       segment.end_ea - segment.start_ea)
         segment = ida_segment.get_next_seg(segment.end_ea)
     return result
Пример #5
0
    def read(self, size):
        ea = ida_loader.get_fileregion_ea(self.offset)
        if ea == idc.BADADDR:
            # best guess, such as if file is mapped at address 0x0.
            ea = self.offset

        logger.debug("reading 0x%x bytes at 0x%x (ea: 0x%x)", size, self.offset, ea)
        return ida_bytes.get_bytes(ea, size)
Пример #6
0
def main():
    is_selected, sel_start, sel_end = ida_kernwin.read_selection()
    if not is_selected:
        logger.error('range must be selected')
        return -1

    sel_end = ida_bytes.next_head(sel_end)

    buf = ida_bytes.get_bytes(sel_start, sel_end - sel_start)
    if buf is None:
        logger.error('failed to fetch instruction bytes')
        return -1

    f = ida_funcs.get_func(sel_start)
    if f != ida_funcs.get_func(sel_end):
        logger.error('range must be within a single function')
        return -1

    # find mappings from "$localN" to "custom_name"
    regvars = {}
    for i in range(0x1000):
        regvar = ida_frame.find_regvar(f, sel_start, '$local%d' % i)
        if regvar is None:
            continue
        regvars[regvar.canon] = regvar.user

        if len(regvars) >= f.regvarqty:
            break

    globals_ = {}
    for i, offset in netnode.Netnode('$ wasm.offsets').get('globals',
                                                           {}).items():
        globals_['$global' + i] = ida_name.get_name(offset)

    frame = {}
    if f.frame != ida_idaapi.BADADDR:
        names = set([])
        for i in range(ida_struct.get_struc_size(f.frame)):
            s = ida_struct.get_struc(f.frame)
            if not s:
                continue
            m = ida_struct.get_member(s, i)
            if not m:
                continue
            name = ida_struct.get_member_name(m.id)
            if name in names:
                continue
            frame[i] = name
            names.add(name)

    emu = Emulator(buf)
    emu.run()
    print(
        emu.render(ctx={
            'regvars': regvars,
            'frame': frame,
            'globals': globals_,
        }))
Пример #7
0
def restore_x(unique_name=None, start=None):
    ea = ida_kernwin.get_screen_ea()

    # signature
    if not unique_name:
        if not start:
            seg = ida_segment.getseg(ea)
            start = seg.start_ea
        sig_bytes = ida_bytes.get_bytes(start, SIGNATURE_SIZE)
        sig_hash = hashlib.md5(sig_bytes).hexdigest()
        unique_name = sig_hash

    if not start:
        seg = ida_segment.getseg(ea)
        start = seg.start_ea

    if MD5_hash_data_file and os.path.isfile(MD5_hash_data_file):
        with open(MD5_hash_data_file, "rb") as ifile:
            received_data = pickle.loads(ifile.read())
            saved_data = received_data

            print("dumpDyn::restore\n\
            Name: {}\n\
            Restore address: {}\n".format(unique_name, hex(start)))

            # (start_addr, end_addr, names, comms, bpts, funcs)
            if unique_name in saved_data:
                current_data = saved_data[unique_name]

                # restore names
                names = current_data[2]

                for name in names:
                    # names: (rel_addr, name, is_code)
                    ida_name.set_name(start + name[0], name[1])
                    flags = ida_bytes.get_flags(start + name[0])
                    if name[2] and not ida_bytes.is_code(flags):
                        ida_auto.auto_make_code(start + name[0])

                # restore comments
                # comms: (rel_addr, TYPE, comment)
                comms = current_data[3]
                for comm in comms:
                    # 0:MakeComm and 1:MakeRptCmt
                    ida_bytes.set_cmt(start + comm[0], comm[2], comm[1])

                # restore breakpoints
                # bpts: (rel_addr, size, type)
                bpts = current_data[4]
                for bpt in bpts:
                    ida_dbg.add_bpt(start + bpt[0], bpt[1], bpt[2])

                # restore functions
                funcs_addr = current_data[5]
                for addr in funcs_addr:
                    ida_auto.auto_make_proc(start + addr)  # make code & func
Пример #8
0
def method_list(ea):
    if not ea:
        return

    count = ida_bytes.get_dword(ea + 4)
    first = ea + 8
    for i in range(count):
        ea_method_t = first + i * Objc2Method.length
        data = ida_bytes.get_bytes(ea_method_t, Objc2Method.length)
        yield Objc2Method(data)
Пример #9
0
 def _get_memory(self):
     result = bytearray()
     segment_starts = [ea for ea in idautils.Segments()]
     offsets = []
     start_len = 0
     for start in segment_starts:
         end = idc.get_segm_attr(start, idc.SEGATTR_END)
         result += ida_bytes.get_bytes(start, end - start)
         offsets.append((start, start_len, len(result)))
         start_len = len(result)
     return bytes(result), offsets
Пример #10
0
 def _get_memory(self):
     result = b''
     segment_starts = [ea for ea in idautils.Segments()]
     offsets = []
     start_len = 0
     for start in segment_starts:
         end = idc.get_segm_end(start)
         result += ida_bytes.get_bytes(start, end - start)
         offsets.append((start, start_len, len(result)))
         start_len = len(result)
     return result, offsets
Пример #11
0
 def get_hex(self, start_address, end_address) -> list:
     result = []
     start = int(start_address, 16)
     end = int(end_address, 16)
     while start <= end:
         # https://github.com/idapython/src/blob/master/python/idautils.py#L202
         next_start = ida_bytes.next_head(start, ida_ida.cvar.inf.max_ea)
         result.append(
             binascii.hexlify(ida_bytes.get_bytes(start, next_start -
                                                  start)).decode())
         start = next_start
     return result
Пример #12
0
def main():
    for segstart, segend, segname in enum_segments():
        for head in idautils.Heads(segstart, segend):
            if not is_code(head):
                continue

            # pattern:
            #
            #   lea     rax, unk_6BDF88
            #   mov     [rsp+0], rax
            #   mov     qword ptr [rsp+8], 40h
            if ida_ua.ua_mnem(head) != "lea":
                continue

            next_head = ida_bytes.next_head(head, idc.BADADDR)
            if ida_ua.ua_mnem(next_head) != "mov":
                continue

            next_head2 = ida_bytes.next_head(next_head, idc.BADADDR)
            if ida_ua.ua_mnem(next_head2) != "mov":
                continue

            dst = idc.get_operand_value(head, 1)
            if idc.get_segm_name(dst) not in (".rdata", "UPX1"):
                continue

            size = idc.get_operand_value(next_head2, 1)

            if size > 0x100:
                continue
            if size <= 2:
                continue

            buf = ida_bytes.get_bytes(dst, size)
            if not buf:
                continue

            if b"\x00" in buf:
                continue

            try:
                s = buf.decode("ascii")
            except UnicodeDecodeError:
                continue

            print("string pointer: 0x%x -> 0x%x: %s" % (head, dst, s))
            ida_bytes.del_items(dst, 1)
            ida_bytes.create_data(dst, idc.FF_BYTE, 1, idc.BADADDR)
            ida_bytes.set_cmt(dst, s, True)
            ida_name.set_name(dst, "s_%x" % (dst))
Пример #13
0
def getOpcodes(addr, size):
    md = capstone.Cs(capstone.CS_ARCH_X86, CAPSTONE_MODE)
    md.detail = True
    instr_bytes = ida_bytes.get_bytes(addr, size)
    opcodes_buf = b''
    for i in md.disasm(instr_bytes, size):
        # get last opcode
        if (i.opcode[3] != 0):
            opcodes_buf += "%02x" % (i.opcode[3])
        elif (i.opcode[2] != 0):
            opcodes_buf += "%02x" % (i.opcode[2])
        elif (i.opcode[1] != 0):
            opcodes_buf += "%02x" % (i.opcode[1])
        else:
            opcodes_buf += "%02x" % (i.opcode[0])
    return opcodes_buf
Пример #14
0
    def decode_at_ea(addr, offset, keyLen, dataLen):
        """ use for manually decoding with IDA and will put a comment at screen_ea """
        data = ida_bytes.get_bytes(addr + offset, keyLen + dataLen)
        cmt = data_to_str(decode_string(data, keyLen, dataLen))
        print("%s" % cmt)

        ea = idc.get_screen_ea()
        idaapi.set_cmt(ea, cmt, True)  # disassembly comment
        cfunc = idaapi.decompile(ea)
        if cfunc is not None:
            # decompiled comment
            tl = idaapi.treeloc_t()
            tl.ea = ea
            tl.itp = idaapi.ITP_SEMI
            cfunc.set_user_cmt(tl, cmt)
            cfunc.save_user_cmts()
def main():
    for segstart, segend, segname in enum_segments():
        if segname not in ('.rdata', 'UPX1' ):
            continue

        for src, dst, psize in find_pointers(segstart, segend):
            if idc.get_segm_name(dst) not in (".rdata", "UPX0"):
                continue
                
            if psize == 8:
                size = ida_bytes.get_qword(src + 0x8)
            else:
                size = ida_bytes.get_dword(src + 0x4)
                
            if size > 0x100:
                continue
            if size <= 2:
                continue

            buf = ida_bytes.get_bytes(dst, size)
            if not buf:
                continue

            if b"\x00" in buf:
                continue

            try:
                s = buf.decode("ascii")
            except UnicodeDecodeError:
                continue

            print("string pointer: 0x%x -> 0x%x: %s" % (src, dst, s))

            ida_bytes.del_items(src, 1)
            ida_bytes.set_cmt(dst, s, True)

            # pointer
            ida_bytes.del_items(src, psize)
            ida_bytes.create_data(src, idc.FF_QWORD if size == 8 else idc.FF_DWORD, psize, idc.BADADDR)
            # this doesn't seem to always work :-(
            idc.op_plain_offset(src, -1, 0)
            ida_name.set_name(src, "s_%x" % (src))
            ida_bytes.set_cmt(src, s, True)

            # size
            ida_bytes.del_items(src + psize, psize)
            ida_bytes.create_data(src + psize, idc.FF_QWORD if size == 8 else idc.FF_DWORD, psize, idc.BADADDR)
Пример #16
0
    def add_method_xref(self, xref):
        msg("Adding cross reference to method implementation for %s\n" %
            get_func_name(self.method_pointer))

        add_dref(xref.frm, self.method_pointer, dr_I | XREF_USER)

        offset = self.method_pointer - xref.frm

        instruction_bytes = get_bytes(xref.frm, self.ARM64_INSTRUCTION_SIZE)
        #TODO: are there other instructions that could reference a method selector
        #and then move the selector reference into a register?
        arm64_ldr = AArch64LDRInstruction(instruction_bytes)

        arm64_ldr.patch_offset(offset)

        patch_dword(xref.frm, arm64_ldr.instruction_int)
        return ObjcMethodXref(xref.frm, self.method_pointer, xref.to)
Пример #17
0
def dump_binary(path):
    sections = []
    current_offset = 0
    with open(path, 'wb+') as f:
        # over all segments
        for n in range(ida_segment.get_segm_qty()):
            seg = ida_segment.getnseg(n)
            start_ea = seg.start_ea
            end_ea = seg.end_ea
            size = end_ea - start_ea
            dump_log.debug("Dumping 0x%x bytes from 0x%x", size, start_ea)
            f.write(ida_bytes.get_bytes(start_ea, size))
            sections.append((ida_segment.get_segm_name(seg), start_ea, size,
                             current_offset, size))
            current_offset += size
    dump_log.debug(repr(sections))
    return sections
Пример #18
0
    def find_function_frame_references(
            self, function: Function,
            frame_pointer: int) -> dict[int, list[FrameReference]]:
        """
        scan the given instruction for LOAD or STOREs to the function frame.

        args:
          function (dict[str, any]): function instance.
          frame_pointer (int): local variable index of the frame pointer.

        returns:
          dict[int, list[FrameReference]]: mapping from frame_offset to set of frame references
        """
        buf = ida_bytes.get_bytes(function['offset'], function['size'])
        bc = list(wasm.decode.decode_bytecode(buf))

        offset = function['offset']
        SLICE_SIZE = 3
        references: defaultdict[int, list[FrameReference]] = defaultdict(list)
        for i in range(len(bc) - SLICE_SIZE - 1):
            insns = bc[i:i + SLICE_SIZE]

            try:
                load = self.get_frame_load(function, frame_pointer, insns)
            except ValueError:
                pass
            else:
                load['offset'] += offset
                logger.debug('found function frame load at 0x%X',
                             load['offset'])
                references[load['frame_offset']].append(load)

            try:
                store = self.get_frame_store(function, frame_pointer, insns)
            except ValueError:
                pass
            else:
                store['offset'] += offset
                logger.debug('found function frame store at 0x%X',
                             store['offset'])
                references[store['frame_offset']].append(store)

            offset += bc[i].len

        return dict(references)
Пример #19
0
def main(argv=None):
    if argv is None:
        argv = sys.argv[:]

    try:
        seg_spec = prompt_for_segment()
    except BadInputError:
        logger.error('bad input, exiting...')
        return -1

    seg = ida_segment.get_segm_by_name(seg_spec.name)
    if not seg:
        logger.error("bad segment, exiting...")

    buf = ida_bytes.get_bytes(seg.start_ea, seg.end_ea - seg.start_ea)
    with open(seg_spec.path, "wb") as f:
        f.write(buf)

    logger.info("wrote %x bytes", len(buf))
Пример #20
0
def xex_load_exports(li):
    global export_table_va

    export_table = HvImageExportTable()
    slen = ctypes.sizeof(export_table)
    bytes = ida_bytes.get_bytes(export_table_va, slen)
    fit = min(len(bytes), slen)
    ctypes.memmove(ctypes.addressof(export_table), bytes, fit)

    if export_table.Magic[0] != XEX_EXPORT_MAGIC_0 or export_table.Magic[
            1] != XEX_EXPORT_MAGIC_1 or export_table.Magic[
                2] != XEX_EXPORT_MAGIC_2:
        print("[+] Export table magic is invalid! (0x%X 0x%X 0x%X)" %
              (export_table.Magic[0], export_table.Magic[1],
               export_table.Magic[2]))
        return 0

    print("[+] Loading module exports...")
    print(export_table)

    ordinal_addrs_va = export_table_va + slen
    for i in range(0, export_table.Count):
        func_ord = export_table.Base + i
        func_va = ida_bytes.get_dword(ordinal_addrs_va + (i * 4))
        if func_va == 0:
            continue

        func_va = func_va + (export_table.ImageBaseAddress << 16)
        func_name = x360_imports.DoNameGen(idc.get_root_filename(), 0,
                                           func_ord)

        # Add to exports list & mark as func if inside a code section
        func_segmclass = ida_segment.get_segm_class(
            ida_segment.getseg(func_va))
        idc.add_entry(func_ord, func_va, func_name,
                      1 if func_segmclass == "CODE" else 0)

        if func_segmclass == "CODE":
            idc.add_func(func_va)

    return 1
Пример #21
0
def emulate(startea, endea):
    global reg_overrides
    global stack_bottom
    global uc

    # Align on a 1024-byte boundry
    aligned_startea = startea & ~0x3ff
    aligned_endea = (endea + 0x400) & ~0x3ff

    len = aligned_endea - aligned_startea

    # print("startea {} endea {}".format(hex(startea), hex(endea)))
    # print("start {} end {} len {}".format(hex(aligned_startea), \
    #         hex(aligned_endea), hex(len)))

    uc.reg_write(UC_ARM64_REG_SP, stack_bottom + 0x400)
    uc.mem_write(aligned_startea, ida_bytes.get_bytes(aligned_startea, len))
    uc.hook_add(UC_HOOK_CODE, hook_code, begin=startea, end=endea)
    uc.hook_add(UC_HOOK_INSN_INVALID, hook_invalid_insn)
    # uc.hook_add(UC_HOOK_INSN, hook_invalid_insn)
    uc.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED, hook_invalid)
    # try:
    uc.emu_start(startea, endea)
    # except UcError as e:
    #     print("ERROR: %s" % e)
    # print("Done")

    x1 = uc.reg_read(UC_ARM64_REG_X1)
    x2 = uc.reg_read(UC_ARM64_REG_X2)
    w3 = uc.reg_read(UC_ARM64_REG_W3)

    if x1 == 0:
        x1 = reg_overrides[0]

    if x2 == 0:
        x2 = reg_overrides[1]

    if w3 == 0:
        w3 = reg_overrides[2]

    return [x1, x2, w3]
Пример #22
0
def get_bytes(address: int, size: int, default: int = 0) -> bytes:
    """
    Obtains bytes from given address.
    Replaces non-loaded data with 0 byte.

    :param address: Address to pull bytes from.
    :param size: Number of bytes to pull.
    :param default: Default byte to provide if not loaded.
    :returns: obtained bytes
    """
    if default == 0:
        data = bytearray(size)
    else:
        data = bytearray([default] * size)

    start = address
    for address, size in get_byte_chunks(address, size):
        offset = address - start
        data[offset:offset + size] = ida_bytes.get_bytes(address, size)

    return bytes(data)
Пример #23
0
    def hint(self, ea, tag, val):
        val = val.strip()
        if not val:
            return None

        if tag == ida_lines.SCOLOR_REG:
            if val in self.regs:
                register = self.regs[val]
                return register["long_name"], register["purpose"]

        elif tag == ida_lines.SCOLOR_INSN:
            insn = ida_ua.insn_t()
            ida_ua.decode_insn(insn, ea)
            insn_bs = ida_bytes.get_bytes(insn.ea, insn.size)
            fmt = {2: "<H", 4: "<I", 8: "<Q"}
            insn_bs = struct.unpack(fmt.get(len(insn_bs)), insn_bs)[0]

            enc_type = "A64"
            if isinstance(self, AArch32):
                enc_type = "A32"
                if ida_segregs.get_sreg(ea, 20) > 0:
                    enc_type = "T32"

            insn_enc = self.find_insn_enc(
                enc_type, insn_bs, insn.get_canon_mnem()
            )
            if not insn_enc:
                return
            insn_name, tmpl_name = insn_enc
            insn = self.insns[insn_name]

            desc = insn["authored"]
            if tmpl_name in insn["templates"]:
                desc += "\n\n" + "\n".join(insn["templates"][tmpl_name])
            return insn["heading"], desc

        elif tag == ida_lines.SCOLOR_KEYWORD:
            if val in self.data["keywords"]:
                return val, self.data["keywords"][val]
Пример #24
0
 def data(self) -> bytes:
     """Returns all the bytes contained in the function."""
     return ida_bytes.get_bytes(self.start_ea, self.end_ea - self.start_ea)
Пример #25
0
 def __init__(self, base, rva, size):
     self.__base = base
     super().__init__(PE_Directory_Debug_CodeView.packinfo, ida_bytes.get_bytes(self.__base + rva, size))
Пример #26
0
 def get_prologue_bc(self, offset: int) -> list[Instruction]:
     prologue = ida_bytes.get_bytes(offset, self.PROLOGUE_SIZE)
     try:
         return list(itertools.islice(wasm.decode_bytecode(prologue), 8))
     except:  # NOQA: E722 do not use bare 'except'
         return []
Пример #27
0
    def decode_instruction(self, insn):
        buf = get_bytes(insn.ea, 2)
        hw1 = unpack("<H", buf)[0]

        op = (hw1 & 0x7E0) >> 5  # take bit5->bit10

        # Format I
        if op == 2 and (hw1 >> 11) == 0 and (hw1 & 0x1F) != 0:
            # TODO add vector4 parsing
            insn.itype = NewInstructions.NN_fetrap
            insn.size = 2
            return True

        # Format XIV
        elif op == 0x3D and ((hw1 & 0xFFE0) >> 5) == 0x3D:
            buf = get_bytes(insn.ea + 2, 2)
            hw2 = unpack("<H", buf)[0]
            subop = hw2 & 0x1F

            if subop == 0x07:  # ld.hu
                insn.itype = NewInstructions.NN_ld_hu

                insn.Op1.type = o_displ
                insn.Op2.type = o_reg

                insn.Op1.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED
                insn.Op1.reg = self.parse_r1(hw1)

                buf = get_bytes(insn.ea + 4, 2)
                hw3 = unpack("<H", buf)[0]

                insn.Op1.addr = self.sign_extend(
                    ((hw3 << 6) | ((hw2 & 0x7E0) >> 5)) << 1, 23)
                insn.Op1.dtyp = dt_dword
                insn.Op2.reg = self.parse_r2(hw2)
                insn.Op2.dtyp = dt_dword

                insn.size = 6
                return True

            elif subop == 0xD:  # st.h
                insn.itype = NewInstructions.NN_st_h

                insn.Op1.type = o_reg
                insn.Op2.type = o_displ

                insn.Op2.specflag1 = N850F_USEBRACKETS | N850F_OUTSIGNED
                insn.Op2.reg = self.parse_r1(hw1)

                buf = get_bytes(insn.ea + 4, 2)
                hw3 = unpack("<H", buf)[0]

                insn.Op2.addr = self.sign_extend(
                    ((hw3 << 6) | ((hw2 & 0x7E0) >> 5)) << 1, 23)
                insn.Op2.dtyp = dt_dword
                insn.Op1.reg = self.parse_r2(hw2)
                insn.Op1.dtyp = dt_dword

                insn.size = 6
                return True

        # Format II
        elif op == 0x15:  # sar imm5, reg2
            insn.itype = NewInstructions.NN_sar

            insn.Op1.type = o_imm
            insn.Op2.type = o_reg

            insn.Op1.value = hw1 & 0x1F
            insn.Op2.reg = self.parse_r2(hw1)

            insn.size = 2
            return True

        # Format IX, X, XI
        elif op == 0x3F:
            buf = get_bytes(insn.ea + 2, 2)
            hw2 = unpack("<H", buf)[0]
            subop = hw2 & 0x7FF

            if hw1 & 0x7FF == 0x7E0:
                if hw1 == 0x7E0:
                    if hw2 == 0x14A:  # feret
                        insn.itype = NewInstructions.NN_feret
                        insn.size = 4
                        return insn.size
                    elif hw2 == 0x0148:  # eiret
                        insn.itype = NewInstructions.NN_eiret
                        insn.size = 4
                        return True

                elif subop == 0x366:  # sch1l reg2, reg3
                    insn.itype = NewInstructions.NN_sch1l

                    insn.Op1.type = o_reg
                    insn.Op2.type = o_reg

                    insn.Op1.reg = self.parse_r2(hw1)
                    insn.Op2.reg = self.parse_r3(hw2)

                    insn.size = 4
                    return True

                elif subop == 0x362:  # sch1r reg2, reg3
                    insn.itype = NewInstructions.NN_sch1r

                    insn.Op1.type = o_reg
                    insn.Op2.type = o_reg

                    insn.Op1.reg = self.parse_r2(hw1)
                    insn.Op2.reg = self.parse_r3(hw2)

                    insn.size = 4
                    return True

            insn_handled = False

            if subop == hw2 == 0xA0:  # sar reg1, reg2
                insn.itype = NewInstructions.NN_sar

                insn.Op1.type = o_reg
                insn.Op2.type = o_reg

                insn.Op1.reg = self.parse_r1(hw1)
                insn.Op2.reg = self.parse_r2(hw1)

                insn.size = 4
                return True

            elif subop == 0xEE:  # caxi [reg1], reg2, reg3
                insn.itype = NewInstructions.NN_caxi

                insn.Op1.type = o_displ
                insn.Op1.addr = 0
                insn.Op2.type = o_reg
                insn.Op3.type = o_reg

                insn.Op1.reg = self.parse_r1(hw1)
                insn.Op2.reg = self.parse_r2(hw1)
                insn.Op2.reg = self.parse_r3(hw2)

                insn.size = 4
                return True

            elif subop == 0x2FC:  # divq reg1, reg2, reg3
                insn.itype = NewInstructions.NN_divq
                insn.size = 4
                insn_handled = True

            elif subop == 0x2FE:  # divqu reg1, reg2, reg3
                insn.itype = NewInstructions.NN_divqu
                insn.size = 4
                insn_handled = True

            elif subop == 0xA2:  # sar reg1, reg2, reg3
                insn.itype = NewInstructions.NN_sar
                insn.size = 4
                insn_handled = True

            elif subop == 0xC2:  # shl reg1, reg2, reg3
                insn.itype = NewInstructions.NN_shl
                insn.size = 4
                insn_handled = True

            elif subop == 0x82:  # shr reg1, reg2, reg3
                insn.itype = NewInstructions.NN_shr
                insn.size = 4
                insn_handled = True

            if insn_handled:
                insn.Op1.type = o_reg
                insn.Op2.type = o_reg
                insn.Op3.type = o_reg

                insn.Op1.reg = self.parse_r1(hw1)
                insn.Op2.reg = self.parse_r2(hw1)
                insn.Op3.reg = self.parse_r3(hw2)
                return True

        return False
Пример #28
0
def save_x(unique_name=None, start=None, size=None):
    ea = ida_kernwin.get_screen_ea()

    # signature
    if not unique_name:
        if not start:
            seg = ida_segment.getseg(ea)
            start = seg.start_ea
        sig_bytes = ida_bytes.get_bytes(start, SIGNATURE_SIZE)
        sig_hash = hashlib.md5(sig_bytes).hexdigest()
        unique_name = sig_hash

    if not start or not size:
        seg = ida_segment.getseg(ea)
        start = seg.start_ea
        size = seg.size()

    # (start_addr, end_addr, names, comms)
    saved_data = {}
    if MD5_hash_data_file and os.path.isfile(MD5_hash_data_file):
        with open(MD5_hash_data_file, "rb") as ifile:
            received_data = pickle.loads(ifile.read())
            if received_data:
                saved_data = received_data

    # save names (func_names, labels, etc)
    # (addr, name, is_code)
    names_addr_name = []
    names = idautils.Names()
    for addr, name in names:
        if start <= addr <= start + size:
            flags = ida_bytes.get_flags(addr)
            names_addr_name.append(
                (addr - start, name, ida_bytes.is_code(flags)))

    # save comments
    comms_addr_type_comm = []
    # (addr, TYPE, comment)
    # type 0:comment 1:rpt_comment
    end = start + size
    for i in range(start, end + 1):
        if ida_bytes.get_cmt(i, 0):  # 0 Comment
            comms_addr_type_comm.append((i - start, 0, ida_bytes.get_cmt(i,
                                                                         0)))
        if ida_bytes.get_cmt(i, 1):  # 1 RptCmt
            comms_addr_type_comm.append((i - start, 1, ida_bytes.get_cmt(i,
                                                                         1)))

    # breakpoints
    bpts_addr_size_type = []
    bpt = ida_dbg.bpt_t()
    global remove_on_exit_bpts
    for i in range(start, end + 1):
        if ida_dbg.get_bpt(i, bpt):
            bpts_addr_size_type.append((i - start, bpt.size, bpt.type))
            remove_on_exit_bpts.append(i)

    # functions
    funcs_addr = []
    flag = ida_bytes.get_flags(start)
    if ida_bytes.is_func(flag):
        funcs_addr.append(0)  # start addr
    next_func = ida_funcs.get_next_func(start)
    while next_func:
        funcs_addr.append(next_func.start_ea - start)
        next_func = ida_funcs.get_next_func(next_func.start_ea)

    # SAVE
    saved_data[unique_name] = (start, start + end, names_addr_name,
                               comms_addr_type_comm, bpts_addr_size_type,
                               funcs_addr)

    if MD5_hash_data_file:
        with open(MD5_hash_data_file, "wb") as ifile:
            serial_data = pickle.dumps(saved_data)
            ifile.write(serial_data)
            print("dumpDyn::save:\n\
            Name: {}\n\
            Start address: {}".format(unique_name, hex(start)))
Пример #29
0
    def run(self, arg):

        start_time = time.time()
        is_64bits = idaapi.get_inf_structure().is_64bit()
        if is_64bits:
            print("这个脚本只考虑了32位SO的反编译代码,64位未适配。")

        textStart, textEnd, end = getSegAddr()
        found = {}
        offsets = []

        # 从二进制中搜索,这部分和findcrypt/signsrch中的处理类似
        sig_list = load_signatures()
        bytes = ida_bytes.get_bytes(0, end)
        for sig in sig_list:
            oneInfo = {"describe": 0, "type": 0}
            ea = None
            idx = bytes.find(sig["data"])
            if idx != -1:
                ea = idx

            ## 同一个魔数可能在so文件中出现多次
            while ea != None:
                name = sig["name"]
                offset = hex(ea)
                oneInfo["type"] = 1
                oneInfo["describe"] = name
                found[offset] = oneInfo
                offsets.append(offset)
                idx = bytes.find(sig["data"], ea + sig["size"])
                if idx != -1:
                    ea = idx
                else:
                    ea = None

        # 正则匹配伪C中的魔数初始化,以及哈希运算部分
        for func in idautils.Functions(textStart, textEnd):
            try:
                oneInfo = {'type': 0, "describe": 0, "funcName": 0, "init": 0,
                           "round": 0, "hookOffset": 0}
                decompilerStr = str(idaapi.decompile(func))

                Suspected_magic_num = [i[1] for i in re.findall(
                    "(]|\+ \d{1,3}\)) = -?(0?x?[0-9A-FL]{8,20});",
                    decompilerStr)]
                Suspected_transform_funcs = re.findall(" ([^ (*]{2,}?)\(",
                                                       decompilerStr)[1:]
                funcs_count = list(Counter(Suspected_transform_funcs).values())
                max_func_num = max(funcs_count) if funcs_count else 0

                if len(Suspected_magic_num) >= 3:
                    if hex(func) in offsets:
                        found[hex(func)]["init"] = 1
                    else:
                        functionName = demangle_str(
                            str(idaapi.ida_funcs.get_func_name(func)))
                        oneInfo["type"] = 2
                        oneInfo["funcName"] = functionName
                        oneInfo["init"] = 1
                        found[hex(func)] = oneInfo

                if max_func_num > 60:
                    if hex(func) in offsets:
                        found[hex(func)]["round"] = 1
                    else:
                        functionName = demangle_str(
                            str(idaapi.ida_funcs.get_func_name(func)))
                        oneInfo["type"] = 2
                        oneInfo["funcName"] = functionName
                        oneInfo["round"] = 1
                        found[hex(func)] = oneInfo

            except:
                pass

        funclist, constlist = get_result(found)

        print("***************************在二进制文件中检索hash算法常量************************************")
        for i in constlist:
            print(i[1] + ":" + i[0])

        for i in funclist:
            print(i[2] + ":" + i[1])
        myscript = generate_script(funclist, constlist)

        script_name = so_name.split(".")[0] + "_findhash_" + str(int(time.time())) + ".js"
        save_path = os.path.join(so_path, script_name)
        with open(save_path, "w", encoding="utf-8")as F:
            F.write(myscript)

        # 对哈希相关的字符串和出现的路径进行搜索
        IDAStrings = idautils.Strings()
        IDAStrings = [[str(i), i.ea] for i in IDAStrings]
        hashstring = ["md", "dgst", "digest", "final", "update", "sha"]
        SOURCE_FILES_REGEXP = r"([a-z_\/\\][a-z0-9_/\\:\-\.@]+\.(c|cc|cxx|c\+\+|cpp|h|hpp|m|rs|go|ml))($|:| )"
        Suspected_string = []

        for s, ea in IDAStrings:
            s = demangle_str(s)
            if s and len(s) > 4:
                path = re.findall(SOURCE_FILES_REGEXP, s, re.IGNORECASE)
                if path:
                    Suspected_string.append([ea, path[0][0]])

            for h in hashstring:
                if (h in s) and ("__cxa_finalize" not in s):
                    Suspected_string.append([ea, s])

        print("***************************存在以下可疑的字符串************************************")
        for ea, i in Suspected_string:
            print(f"{hex(ea)}:{i}")

        print("生成对应的hook脚本如下:")
        print(f"frida -UF -l {save_path}")

        print("***********************************************************************************")
        print("花费 %s 秒,因为会对全部函数反编译,所以比较耗时间哈" % (time.time() - start_time))
Пример #30
0
def memcpy(src, dst, length):
    if length == 0:
        return
    data = ida_bytes.get_bytes(src, length)
    ida_bytes.put_bytes(dst, data)