Ejemplo n.º 1
0
def main():
    print("[*] loading crypto constants")
    for const in non_sparse_consts:
        const["byte_array"] = convert_to_byte_array(const)

    for start in idautils.Segments():
        print("[*] searching for crypto constants in %s" % idc.get_segm_name(start))
        ea = start
        while ea < idc.get_segm_end(start):
            bbbb = list(struct.unpack("BBBB", idc.get_bytes(ea, 4)))
            for const in non_sparse_consts:
                if bbbb != const["byte_array"][:4]:
                    continue
                if map(lambda x:ord(x), idc.get_bytes(ea, len(const["byte_array"]))) == const["byte_array"]:
                    print(("0x%0" + str(digits) + "X: found const array %s (used in %s)") % (ea, const["name"], const["algorithm"]))
                    idc.set_name(ea, const["name"])
                    if const["size"] == "B":
                        idc.create_byte(ea)
                    elif const["size"] == "L":
                        idc.create_dword(ea)
                    elif const["size"] == "Q":
                        idc.create_qword(ea)
                    idc.make_array(ea, len(const["array"]))
                    ea += len(const["byte_array"]) - 4
                    break
            ea += 4

        ea = start
        if idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == 2:
            while ea < idc.get_segm_end(start):
                d = ida_bytes.get_dword(ea)
                for const in sparse_consts:
                    if d != const["array"][0]:
                        continue
                    tmp = ea + 4
                    for val in const["array"][1:]:
                        for i in range(8):
                            if ida_bytes.get_dword(tmp + i) == val:
                                tmp = tmp + i + 4
                                break
                        else:
                            break
                    else:
                        print(("0x%0" + str(digits) + "X: found sparse constants for %s") % (ea, const["algorithm"]))
                        cmt = idc.get_cmt(idc.prev_head(ea), 0)
                        if cmt:
                            idc.set_cmt(idc.prev_head(ea), cmt + ' ' + const["name"], 0)
                        else:
                            idc.set_cmt(idc.prev_head(ea), const["name"], 0)
                        ea = tmp
                        break
                ea += 1
    print("[*] finished")
Ejemplo n.º 2
0
def main():
    print("[*] loading crypto constants")
    for const in non_sparse_consts:
        const["byte_array"] = convert_to_byte_array(const)

    for start in Segments():
        print("[*] searching for crypto constants in %s" %
              get_segm_name(start))
        ea = start
        while ea < get_segm_end(start):
            bbbb = list(struct.unpack("BBBB", get_bytes(ea, 4)))
            for const in non_sparse_consts:
                if bbbb != const["byte_array"][:4]:
                    continue
                if map(lambda x: ord(x), get_bytes(ea, len(
                        const["byte_array"]))) == const["byte_array"]:
                    print("0x%08X: found const array %s (used in %s)" %
                          (ea, const["name"], const["algorithm"]))
                    set_name(ea, const["name"])
                    if const["size"] == "B":
                        idc.create_byte(ea)
                    elif const["size"] == "L":
                        idc.create_dword(ea)
                    elif const["size"] == "Q":
                        idc.create_qword(ea)
                    make_array(ea, len(const["array"]))
                    ea += len(const["byte_array"]) - 4
                    break
            ea += 4

        ea = start
        if get_segm_attr(ea, SEGATTR_TYPE) == 2:
            while ea < get_segm_end(start):
                d = ida_bytes.get_dword(ea)
                for const in sparse_consts:
                    if d != const["array"][0]:
                        continue
                    tmp = ea + 4
                    for val in const["array"][1:]:
                        for i in range(8):
                            if ida_bytes.get_dword(tmp + i) == val:
                                tmp = tmp + i + 4
                                break
                        else:
                            break
                    else:
                        print("0x%08X: found sparse constants for %s" %
                              (ea, const["algorithm"]))
                        ea = tmp
                        break
                ea += 1
    print("[*] finished")
Ejemplo n.º 3
0
def import_objects(objs, add_names=True, always_thumb=True):
    """
    Create IDA function and data according to symbol definitions.
    Create name if add_name is True

    :param add_names: Create name for symbols?

    """

    failed_objs = []
    for name, size, addr, _ in objs:
        if not is_data_start(addr):
            if size:
                ok = idaapi.create_data(addr, idc.FF_BYTE, size, 0)
            else:
                ok = idc.create_byte(addr)
            if not ok:
                reason = "Could not create data at {addr:#x}".format(addr=addr)
                data = (name, size, addr)
                failed_objs.append((data, reason))
                """continue"""
        idc.set_cmt(addr, "obj.%s" % name, 0)
        if add_names:
            ok = idc.set_name(addr, name, idc.SN_CHECK)
            if not ok:
                reason = "Could not add name {name} at {addr:#x}".format(
                    name=name, addr=addr)
                data = (name, size, addr)
                failed_objs.append((data, reason))
    print("waiting for ida to finish analysis")
    ida_auto.auto_wait()
    print("ida finished import")
    return failed_objs
Ejemplo n.º 4
0
    def create_object(obj,
                      overwrite_names,
                      offset,
                      dummy_names=True,
                      always_thumb=True):
        name = obj.get("name")
        addr = int(obj.get("addr"))
        addr = int(addr)
        size = int(obj.get("size"))

        if dummy_names:
            if IDAtools.is_dummy_name(name):
                return
        if type(addr) == int:
            if ida_bytes.is_unknown(ida_bytes.get_full_flags(addr)):
                if size:
                    ok = idaapi.create_data(addr, idc.FF_BYTE, size, 0)
                else:
                    ok = idc.create_byte(addr)
                if not ok:
                    if not ok:
                        reason = "Could not create data at {addr:#x}".format(
                            addr=addr)
                        print(reason)

        if overwrite_names and IDAtools.is_dummy_name_by_addr(addr):
            ok = idc.set_name(addr, name, idc.SN_CHECK)
            if not ok:
                reason = "Could not add name {name} at {addr:#x}".format(
                    name=name, addr=addr)
                print(reason)

        IDAtools.ida_wait()
Ejemplo n.º 5
0
def main():
    print("[*] loading crypto constants")
    for const in non_sparse_consts:
        const["byte_array"] = convert_to_byte_array(const)

    for start in idautils.Segments():
        print("[*] searching for crypto constants in %s" %
              idc.get_segm_name(start))
        ea = start
        while ea < idc.get_segm_end(start):
            bbbb = list(struct.unpack("BBBB", idc.get_bytes(ea, 4)))
            for const in non_sparse_consts:
                if bbbb != const["byte_array"][:4]:
                    continue
                if list(
                        map(lambda x: x if type(x) == int else ord(x),
                            idc.get_bytes(ea, len(
                                const["byte_array"])))) == const["byte_array"]:
                    print(("0x%0" + str(digits) +
                           "X: found const array %s (used in %s)") %
                          (ea, const["name"], const["algorithm"]))
                    idc.set_name(ea, const["name"], ida_name.SN_FORCE)
                    if const["size"] == "B":
                        idc.create_byte(ea)
                    elif const["size"] == "L":
                        idc.create_dword(ea)
                    elif const["size"] == "Q":
                        idc.create_qword(ea)
                    idc.make_array(ea, len(const["array"]))
                    ea += len(const["byte_array"]) - 4
                    break
            ea += 4

        ea = start
        if idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == idc.SEG_CODE:
            while ea < idc.get_segm_end(start):
                d = ida_bytes.get_dword(ea)
                for const in sparse_consts:
                    if d != const["array"][0]:
                        continue
                    tmp = ea + 4
                    for val in const["array"][1:]:
                        for i in range(8):
                            if ida_bytes.get_dword(tmp + i) == val:
                                tmp = tmp + i + 4
                                break
                        else:
                            break
                    else:
                        print(("0x%0" + str(digits) +
                               "X: found sparse constants for %s") %
                              (ea, const["algorithm"]))
                        cmt = idc.get_cmt(idc.prev_head(ea), 0)
                        if cmt:
                            idc.set_cmt(idc.prev_head(ea),
                                        cmt + ' ' + const["name"], 0)
                        else:
                            idc.set_cmt(idc.prev_head(ea), const["name"], 0)
                        ea = tmp
                        break
                ea += 1

    print("[*] searching for crypto constants in immediate operand")
    funcs = idautils.Functions()
    for f in funcs:
        flags = idc.get_func_flags(f)
        if (not flags & (idc.FUNC_LIB | idc.FUNC_THUNK)):
            ea = f
            f_end = idc.get_func_attr(f, idc.FUNCATTR_END)
            while (ea < f_end):
                imm_operands = []
                insn = ida_ua.insn_t()
                ida_ua.decode_insn(insn, ea)
                for i in range(len(insn.ops)):
                    if insn.ops[i].type == ida_ua.o_void:
                        break
                    if insn.ops[i].type == ida_ua.o_imm:
                        imm_operands.append(insn.ops[i].value)
                if len(imm_operands) == 0:
                    ea = idc.find_code(ea, idc.SEARCH_DOWN)
                    continue
                for const in operand_consts:
                    if const["value"] in imm_operands:
                        print(("0x%0" + str(digits) +
                               "X: found immediate operand constants for %s") %
                              (ea, const["algorithm"]))
                        cmt = idc.get_cmt(ea, 0)
                        if cmt:
                            idc.set_cmt(ea, cmt + ' ' + const["name"], 0)
                        else:
                            idc.set_cmt(ea, const["name"], 0)
                        break
                ea = idc.find_code(ea, idc.SEARCH_DOWN)
    print("[*] finished")
def load_file(li, neflags, format):
    # ensure we are not wrongly called
    if not format.startswith("Accessory Firmware Update"):
        return 0

    li.seek(0)
    data = li.read(0x14)
    (magic, xxx1, fw_type, fw_ver, fw_len, unk1, product_id,
     hw_rev_id) = struct.unpack("<HHHHIIHH", data)

    li.seek(0x20)
    AFU_signature_header_data = li.read(24)

    (sig_magic, unknown1, unknown2, digest_type, digest_len, digest_offset,
     sig_type, sig_len, sig_offset) = struct.unpack("<IHHHHIHHI",
                                                    AFU_signature_header_data)

    idaapi.set_processor_type("ARM:ARMv7-M", ida_idp.SETPROC_ALL)

    if product_id == 0x312:  # Apple Pencil
        fw_base = 0x8006080
        msp_base = fw_base
    elif product_id == 0x14c:  # Apple Pencil 2
        if fw_type == 1:
            fw_base = 0x08000980
            msp_base = fw_base + 0x180
        if fw_type == 0x20:
            fw_base = 0x0
            msp_base = fw_base
        if fw_type == 0x30:
            fw_base = 0x0
            msp_base = fw_base
        if fw_type == 0x50:
            fw_base = 0x08000000
            msp_base = fw_base
    elif product_id == 0x26d:  # Siri Remote 2
        if fw_type == 1:
            fw_base = 0x8008080
            msp_base = fw_base + 0x180
        if fw_type == 0xb0:
            fw_base = 0x280
            msp_base = fw_base + 0x180
    elif product_id == 0x268:  # Smart Keyboard 12.9"
        fw_base = 0x08002600
        msp_base = fw_base
    elif product_id == 0x26A:  # Smart Keyboard 9.7"
        fw_base = 0x08002600
        msp_base = fw_base
    elif product_id == 0x26B:  # Smart Keyboard 10.5"
        fw_base = 0x08002600  # don't really know, haven't seen an OTA so far
        msp_base = fw_base
    elif product_id == 0x292:  # Smart Keyboard Folio 11"
        fw_base = 0x08000980  # seems to work
        msp_base = fw_base + 0x180
    elif product_id == 0x293:  # Smart Keyboard Folio 12.9"
        fw_base = 0x08000980  # seems to work
        msp_base = fw_base + 0x180
    else:
        return 0

    # for now a heuristic
    show_header = True
    if fw_type != 1 or fw_base == 0:
        show_header = False

    if show_header:
        li.file2base(0, fw_base - 0x80, fw_base, 1)
    li.file2base(0x80, fw_base, fw_base + fw_len, 1)

    if show_header:
        idaapi.add_segm(0, fw_base - 0x80, fw_base, "HEADER", "DATA")
    idaapi.add_segm(0, fw_base, fw_base + fw_len, "__TEXT", "CODE")
    idaapi.add_segm(0, 0xE000E000, 0xE000F000, "__SYSREG", "DATA")
    idaapi.add_segm(0, SRAM_BASE, SRAM_BASE + SRAM_SIZE, "__SRAM", "DATA")

    if show_header:
        idc.split_sreg_range(fw_base - 0x80, "T", 1)
    idc.split_sreg_range(fw_base, "T", 1)

    # register the structures
    register_structs()

    # apply the structure
    if show_header:
        idc.set_name(fw_base - 0x80, "AFU_HEADER")
        idc.create_struct(fw_base - 0x80, -1, "afu_full_header")
        ida_nalt.unhide_item(fw_base - 0x80 + 1)

    # handle the digest and signature

    if sig_magic == 0x61E34724:

        # apply the structure
        if show_header:
            idc.set_name(fw_base - 0x80 + 0x20, "AFU_SIG_HEADER")
        #idc.create_struct(fw_base - 0x80 + 0x20, -1, "afu_sig_header")
        #ida_nalt.unhide_item(fw_base - 0x80 + 0x20 + 1)

        # first handle the digest
        base = fw_base + fw_len
        li.file2base(digest_offset, base, base + digest_len, 1)
        idaapi.add_segm(0, base, base + digest_len, "__DIGEST", "DATA")
        idc.create_byte(base)
        idc.make_array(base, digest_len)
        idc.set_name(base, "AFU_DIGEST")

        # now handle the signature
        base += digest_len
        li.file2base(sig_offset, base, base + sig_len, 1)
        idaapi.add_segm(0, base, base + sig_len, "__SIGNATURE", "DATA")
        idc.create_byte(base)
        idc.make_array(base, sig_len)
        idc.set_name(base, "AFU_SIGNATURE")

    # check if __TEXT starts with an SRAM address
    # this is the initial MSP that is followed by exception vectors
    initMSP = idc.Dword(msp_base)
    print "initMSP 0x%x" % initMSP
    if (initMSP >= SRAM_BASE) and initMSP <= (SRAM_BASE + SRAM_SIZE):

        idc.set_name(msp_base, "init_MSP")
        idc.create_dword(msp_base)
        idc.op_plain_offset(msp_base, -1, 0)
        idc.set_cmt(msp_base, "Initial MSP value", 0)

        # these are now the exception vectors

        # determine how many exception vectors there are
        cnt = 0
        handlers = {}
        last_multi = None
        multi = False

        while cnt < 255:
            ptr = idc.Dword(msp_base + 4 + 4 * cnt)
            if ptr != 0:

                # must be inside __TEXT
                if (ptr < fw_base) or (ptr > fw_base + fw_len):
                    break

                if (ptr & 1) == 0:  # must be thumb mode
                    break

            # convert into a dword + offset
            idc.create_dword(msp_base + 4 + 4 * cnt)
            if ptr != 0:
                idc.op_offset(msp_base + 4 + 4 * cnt, 0, idc.REF_OFF32, -1, 0,
                              0)
            idc.set_cmt(
                msp_base + 4 + 4 * cnt,
                "exception %d: %s" % (cnt + 1, exception_table[cnt + 1]), 0)

            # should only RESET vector be our entrypoint?
            idc.add_entry(ptr & ~1, ptr & ~1, "", 1)

            # remember how often we see each handler
            if ptr != 0:
                if handlers.has_key(ptr):
                    handlers[ptr] += 1
                    if last_multi != None:
                        if last_multi != ptr:
                            multi = True
                    last_multi = ptr
                else:
                    handlers[ptr] = 1

            cnt += 1

        print "cnt: %d" % cnt

        if cnt > 0:
            i = 1
            while i <= cnt:
                ptr = idc.Dword(msp_base + 4 * i)

                if ptr != 0:
                    # ensure this is
                    if handlers[ptr] == 1:
                        idc.set_name(
                            ptr & ~1,
                            "%s_%s" % (EXCEPTION_PREFIX, exception_table[i]))

                    elif not multi:
                        idc.set_name(ptr & ~1,
                                     "%s_%s" % (EXCEPTION_PREFIX, "UNIMPL"))

                i += 1

    return 1