Exemplo n.º 1
0
def convert_code_data_region_to_code(start_ea, end_ea):
    size = end_ea - start_ea
    score, count = code_score(start_ea, end_ea)
    if score >= 0.75:
        #print '{:016x}  {:8x}  {}'.format(start_ea, size, score)
        idc.del_items(start_ea, idc.DELIT_SIMPLE, size)
        for ea in range(start_ea, end_ea, 4):
            ilen = idc.create_insn(ea)
            if ilen == 0:
                idc.create_dword(ea)
Exemplo 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 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")
Exemplo n.º 3
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")
Exemplo n.º 4
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")
Exemplo n.º 5
0
def sync_data_definitions_in(source_units, address_space, ea):
    from edit_source.include.definitions import DATA_TYPES
    def create_array_of(ea, count, size, op, error=False, verbose=False):
        ops.delete_items(ea, size)
        status = op(ea)
        if count != 1:
            status = idc.make_array(ea, count)
        if verbose:
            if status is False:
                print('error: {:07X}: failed to perform operation'.format(ea))
        if error:
            if status is False:
                raise Exception('{:07X}: failed to perform operation'.format(ea))
        return status

    unit = source_unit.get_physical_unit(source_units, ea)
    UNIT_IDS = asm_file.AsmFile.UNIT_IDS
    if unit['unit']['id'] is UNIT_IDS.DATA:
        print('{:07X} <{}>'.format(unit['ea'], unit['name']))
        cur_ea = ea
        for t in unit['types']:
            idc.jumpto(cur_ea)
            data_type = t[0]
            count = t[1]
            print('{} {:07X} {}'.format(DATA_TYPES.STR[data_type], cur_ea, count))

            if data_type is DATA_TYPES.BYTE:
                size = count
                create_array_of(cur_ea, count, size, idc.create_byte, error=True)
                cur_ea += size
            elif data_type is DATA_TYPES.WORD:
                size = count * 4
                create_array_of(cur_ea, count, size, idc.create_dword, error=True)
                cur_ea += size
            elif data_type is DATA_TYPES.HWORD:
                size = count * 2
                create_array_of(cur_ea, count, size, idc.create_word, error=True)
                cur_ea += size
            elif data_type is DATA_TYPES.OFF:
                xrefs = unit['xrefs_from']
                first_label_ea = xrefs[0][0]
                size = count * 4
                if not (gba_address.is_ewram_address(first_label_ea) or gba_address.is_iwram_address(
                        first_label_ea) or gba_address.is_rom_address(first_label_ea)):
                    # a constant, don't point.
                    # TODO: actually include the constant in IDA
                    create_array_status = create_array_of(cur_ea, count, size, idc.create_dword, error=True)
                    idc.set_array_params(ea, 0, 1, 0)
                    pass
                else:
                    ops.delete_items(cur_ea, size)
                    idc.create_dword(cur_ea)
                    idc.op_plain_offset(cur_ea, 0, 0)
                    create_array_status = True
                    if count != 1:
                        create_array_status = idc.make_array(cur_ea, count)
                        idc.set_array_params(cur_ea, 0, 1, 0)
                if create_array_status is False:
                    raise Exception('could not create array at {:07X} with count {}'.format(cur_ea, count))
                    # TODO: check if it has an offset and fix that
                cur_ea += size
            elif data_type is DATA_TYPES.ALIGN:
                pass
            elif data_type is DATA_TYPES.SPACE:
                pass
            elif data_type is DATA_TYPES.INCBIN:
                pass
            idc.jumpto(cur_ea)
Exemplo n.º 6
0
def load_file(li, neflags, format):
    """
    Load the file into database

    @param li: a file-like object which can be used to access the input data
    @param neflags: options selected by the user, see loader.hpp
    @return: 0-failure, 1-ok
    """
    if format == AtariSTTOSImageName:
        idaapi.set_processor_type('68K', ida_idp.SETPROC_LOADER)

        li.seek(0)
        header = read_struct(li, tos_image_header)

        li.seek(0, idaapi.SEEK_END)
        filesize = li.tell()

        idc.add_segm_ex(header.os_beg, header.os_beg + filesize, 0, 1,
                        idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG)
        idc.set_segm_name(header.os_beg, 'TOS')

        li.seek(0)
        li.file2base(0, header.os_beg, header.os_beg + filesize, 0)

        idaapi.add_entry(header.os_beg, header.os_beg, "ostext", 1)
        idc.set_cmt(header.os_beg, 'branch to reset handler', 0)
        idc.set_name(header.os_beg + 2, 'os_version')
        idc.create_word(header.os_beg + 2)
        idc.set_cmt(header.os_beg + 2, 'OS version number', 0)
        idc.set_cmt(header.os_beg + 4, '-> system reset handler', 0)
        reseth = ida_bytes.get_dword(header.os_beg + 4)
        idc.set_name(reseth, 'reseth')
        idc.set_name(header.os_beg + 8, 'os_beg')
        idc.set_cmt(header.os_beg + 8, '-> base of OS', 0)
        idc.set_name(header.os_beg + 12, 'os_end')
        idc.set_cmt(header.os_beg + 12, '-> end of OS memory usage', 0)
        os_end = ida_bytes.get_dword(header.os_beg + 12)
        idc.add_segm_ex(0x0, os_end, 0, 1, idaapi.saRelPara, idaapi.scPub,
                        idc.ADDSEG_NOSREG)
        idc.set_segm_name(0x0, 'DOSRAM')
        idc.set_name(os_end, 'endos')
        idc.set_name(header.os_beg + 16, 'os_exec')
        idc.set_cmt(header.os_beg + 16, '-> default shell', 0)
        idc.set_name(header.os_beg + 20, 'os_magic')
        idc.set_cmt(header.os_beg + 20, '-> GEM magic (or NULL)', 0)
        idc.set_name(header.os_beg + 24, 'os_date')
        idc.create_dword(header.os_beg + 24)
        idc.set_cmt(header.os_beg + 24, 'date the system was built', 0)
        idc.set_name(header.os_beg + 28, 'os_conf')
        idc.create_word(header.os_beg + 28)
        idc.set_cmt(header.os_beg + 28, 'configuration bits', 0)
        idc.set_name(header.os_beg + 30, 'os_dosdate')
        idc.create_word(header.os_beg + 30)
        idc.set_cmt(header.os_beg + 30, 'DOS-format date the system was built',
                    0)
        addr = header.os_beg + 32
        while addr < reseth:
            if addr == header.os_beg + 0x20:
                idc.set_cmt(addr, 'base of GEMDOS pool', 0)
                idc.set_name(ida_bytes.get_dword(addr), '_root')
            elif addr == header.os_beg + 0x24:
                idc.set_cmt(addr, '-> keyboard shift-state byte', 0)
                idc.set_name(ida_bytes.get_dword(addr), 'kbshift')
            elif addr == header.os_beg + 0x28:
                idc.set_cmt(addr, '-> current process', 0)
                idc.set_name(ida_bytes.get_dword(addr), '_run')
            elif addr == header.os_beg + 0x2c:
                idc.set_cmt(addr, 'reserved for future use', 0)
            idc.create_dword(addr)
            addr += 4

        the_magic = ida_bytes.get_dword(header.os_beg + 20)
        gem_end = ida_bytes.get_dword(the_magic + 4)
        aes_init = ida_bytes.get_dword(the_magic + 8)
        idc.add_segm_ex(os_end, gem_end + 1, 0, 1, idaapi.saRelPara,
                        idaapi.scPub, idc.ADDSEG_NOSREG)
        idc.set_segm_name(os_end, 'GEMRAM')

        idc.set_name(the_magic, 'the_magic')
        idc.create_dword(the_magic)
        idc.set_cmt(the_magic, '$87654321 if GEM present', 0)
        idc.create_dword(the_magic + 4)
        idc.set_cmt(the_magic + 4, 'End address of OS RAM usage', 0)
        idc.create_dword(the_magic + 8)
        idc.set_cmt(the_magic + 8, 'Execution address of GEM', 0)
        idaapi.add_entry(aes_init, aes_init, "gem_entry", 1)
        idc.set_name(gem_end, 'gem_end')

        idaapi.auto_wait()
        return 1

    elif format == AtariSTProgramName:
        idaapi.set_processor_type('68K', ida_idp.SETPROC_LOADER)

        li.seek(0)
        header = read_struct(li, gemdos_executable_header)

        base_addr = AtariSTBaseAddress

        text_addr = base_addr
        data_addr = text_addr + header.PRG_tsize
        bss_addr = data_addr + header.PRG_dsize
        idc.add_segm_ex(text_addr, text_addr + header.PRG_tsize, 0, 1,
                        idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG)
        idc.set_segm_name(text_addr, 'tseg')
        idc.add_segm_ex(data_addr, data_addr + header.PRG_dsize, 0, 1,
                        idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG)
        idc.set_segm_name(data_addr, 'dseg')
        idc.add_segm_ex(bss_addr, bss_addr + header.PRG_bsize, 0, 1,
                        idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_SPARSE)
        idc.set_segm_name(bss_addr, 'bseg')
        li.file2base(ctypes.sizeof(gemdos_executable_header), text_addr,
                     text_addr + header.PRG_tsize + header.PRG_dsize, 0)

        # relocate the application
        li.seek(0, idaapi.SEEK_END)
        filesize = li.tell()
        li.seek(0, idaapi.SEEK_SET)
        relocDataOffset = ctypes.sizeof(
            gemdos_executable_header
        ) + header.PRG_tsize + header.PRG_dsize + header.PRG_ssize
        li.seek(relocDataOffset)
        relocData = li.read(filesize - relocDataOffset)
        roffset = 4
        rea = struct.unpack('>I', relocData[:roffset])[0]
        if rea != 0:
            rea = rea + base_addr
            idc.patch_dword(rea, ida_bytes.get_dword(rea) + base_addr)
            if rea >= data_addr:  # in the DATA segment, make sure it is an actual pointer
                idc.create_dword(rea)
            while True:
                offset = ord(relocData[roffset])
                roffset += 1
                if offset == 0:  # end of the relocation table
                    break
                if offset == 1:  # odd numbers are not valid, 1 is a special case to skip 254 bytes without relocating
                    rea += 254
                    continue
                rea += offset
                idc.patch_dword(rea, ida_bytes.get_dword(rea) + base_addr)
                if rea >= data_addr:  # in the DATA segment, make sure it is an actual pointer
                    idc.create_dword(rea)

        # apply a symbol table, if part of the file
        if header.PRG_ssize:
            symboltableDataOffset = ctypes.sizeof(
                gemdos_executable_header) + header.PRG_tsize + header.PRG_dsize
            li.seek(symboltableDataOffset)
            symboltableData = li.read(header.PRG_ssize)
            soffset = 0
            while soffset < header.PRG_ssize:
                entry = symboltableData[soffset:soffset + 14]
                soffset += 14
                name = entry[:8]
                flags, value = struct.unpack('>HL', entry[8:])
                if (
                        flags & 0x0048
                ) and soffset + 14 < header.PRG_ssize:  # GST extended DRI symbol format?
                    entry = symboltableData[soffset:soffset + 14]
                    soffset += 14
                    name += entry[:8]
                if (
                        flags & 0xf000
                ) == 0xa000:  # global defined symbol? (registers, etc are not supported)
                    value += text_addr  # relocate the value
                    if (flags & 0xf00) == 0x0100:  # BSS
                        idc.set_name(value, name)
                    elif (flags & 0xf00) == 0x0200:  # TEXT
                        idaapi.add_entry(value, value, name, 1)
                    elif (flags & 0xf00) == 0x0400:  # DATA
                        idc.set_name(value, name)

        idaapi.add_entry(text_addr, text_addr, "start", 1)
        idaapi.plan_and_wait(text_addr, text_addr + header.PRG_tsize)
        idaapi.auto_wait()
        return 1

    return 0
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