Example #1
0
def relocate_bootblock():
	bootblk_start = 0xF000 << 4
	bootblk_end = 0x10000 << 4
	bootblk_baseparagraph = 0xF000
	bootblk_size = 0x10000 # 64 Kbyte

	idaapi.add_segm(bootblk_baseparagraph, bootblk_start, bootblk_end, "BOOTBLK", "CODE")
	bootblk = idaapi.get_segm_by_name("BOOTBLK")
	idaapi.set_segm_addressing(bootblk, 16)
	bootblk_addr = get_bootblock_start_address()
	print("Found bootblock at {0} addr!".format(hex(bootblk_addr)))
	relocate_segment(bootblk_addr, bootblk_start, bootblk_size)
def load_file(li, neflags, format):

	idaapi.set_processor_type("arm", SETPROC_ALL|SETPROC_FATAL)

	offs = 0

	for s in segments:
		start = s["start"]
		length = s["len"]
		name = s["name"]
		seg_type = s["type"]

		li.file2base(offs, start, start+length, True)
		idaapi.add_segm(0, start, start+length, name, seg_type)

		offs += length

	create_modem_hdr_struct()
	add_modem_hdr_struct(8*4 + segments[0]["start"]) #this might fail unless we carve out a DATA segment from the CODE segment for it.
	
	print "Samsung Shannon image loaded."
	return 1
Example #3
0
def load_cro(li, is_crs):
    if is_crs:
        base = 0
    else:
        base = 0x00100000  # arbitrary

    li.seek(0x80)
    (Magic, NameOffset, NextCRO, PreviousCRO, FileSize, BssSize, FixedSize,
     UnknownZero, UnkSegmentTag, OnLoadSegmentTag, OnExitSegmentTag,
     OnUnresolvedSegmentTag, CodeOffset, CodeSize, DataOffset, DataSize,
     ModuleNameOffset, ModuleNameSize, SegmentTableOffset, SegmentNum,
     ExportNamedSymbolTableOffset, ExportNamedSymbolNum,
     ExportIndexedSymbolTableOffset, ExportIndexedSymbolNum,
     ExportStringsOffset, ExportStringsSize, ExportTreeTableOffset,
     ExportTreeNum, ImportModuleTableOffset, ImportModuleNum,
     ExternalPatchTableOffset, ExternalPatchNum, ImportNamedSymbolTableOffset,
     ImportNamedSymbolNum, ImportIndexedSymbolTableOffset,
     ImportIndexedSymbolNum, ImportAnonymousSymbolTableOffset,
     ImportAnonymousSymbolNum, ImportStringsOffset, ImportStringsSize,
     StaticAnonymousSymbolTableOffset, StaticAnonymousSymbolNum,
     InternalPatchTableOffset, InternalPatchNum, StaticPatchTableOffset,
     StaticPatchNum) = struct.unpack(
         "<IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
         li.read(0x138 - 0x80))

    if not is_crs:
        li.file2base(0, base, base + FileSize, 0)
        idaapi.add_segm(0, base, base + 0x80, "header", "RODATA")
        idaapi.add_segm(0, base + SegmentTableOffset, base + DataOffset,
                        "tables", "RODATA")

    # set segments
    li.seek(SegmentTableOffset)
    segmentDic = [("CODE", ".text"), ("DATA", ".rodata"), ("DATA", ".data"),
                  ("BSS", ".bss")]
    segmentAddress = []
    for i in range(SegmentNum):
        SegmentOffset, SegmentSize, SegmentType = struct.unpack(
            "<III", li.read(12))
        if SegmentType == 3:
            SegmentOffset = 0x08000000
            idaapi.enable_flags(base + SegmentOffset,
                                base + SegmentOffset + SegmentSize,
                                idaapi.STT_VA)

        segmentAddress.append(base + SegmentOffset)
        if SegmentSize:
            idaapi.add_segm(0, segmentAddress[i],
                            segmentAddress[i] + SegmentSize,
                            segmentDic[SegmentType][1],
                            segmentDic[SegmentType][0])

    # do internal relocations
    li.seek(InternalPatchTableOffset)
    for i in range(InternalPatchNum):
        target, patch_type, source, _, _, shift = struct.unpack(
            "<IBBBBI", li.read(12))
        target_offset = DecodeTag(segmentAddress, target)
        source_offset = segmentAddress[source] + shift
        if patch_type == 2:
            value = source_offset
        elif patch_type == 3:
            rel = source_offset - target_offset
            if rel < 0:
                rel += 0x100000000
            value = rel
        idaapi.patch_long(target_offset, value)
        f = idaapi.fixup_data_t()
        f.type = idaapi.FIXUP_OFF32
        f.off = value
        idaapi.set_fixup(target_offset, f)

    # import
    li.seek(ImportNamedSymbolTableOffset)
    importNamedSymbolTable = []
    for i in range(ImportNamedSymbolNum):
        importNamedSymbolTable.append(struct.unpack('<II', li.read(8)))

    for importNamedSymbol in importNamedSymbolTable:
        nameOffset, batchOffset = importNamedSymbol
        li.seek(nameOffset)
        name = ""
        while True:
            c = li.read(1)
            if c == '\0':
                break
            name += c
        do_import_batch(li, segmentAddress, batchOffset, name)

    li.seek(ImportModuleTableOffset)
    module = []
    for i in range(ImportModuleNum):
        module.append(struct.unpack('<IIIII', li.read(20)))

    for m in module:
        moduleNameOffset, indexed, indexedNum, anonymous, anonymousNum = m
        li.seek(moduleNameOffset)
        mname = ""
        while True:
            c = li.read(1)
            if c == '\0':
                break
            mname += c

        indexeds = []
        li.seek(indexed)
        for i in range(indexedNum):
            indexeds.append(struct.unpack('<II', li.read(8)))

        anonymouses = []
        li.seek(anonymous)
        for i in range(anonymousNum):
            anonymouses.append(struct.unpack('<II', li.read(8)))

        for i in indexeds:
            index, batchOffset = i
            do_import_batch(li, segmentAddress, batchOffset,
                            "%s_%d" % (mname, index))

        for i in anonymouses:
            tag, batchOffset = i
            do_import_batch(li, segmentAddress, batchOffset,
                            "%s_%08X" % (mname, tag))

    # export
    li.seek(ExportNamedSymbolTableOffset)
    exportNamedSymbolTable = []
    for i in range(ExportNamedSymbolNum):
        exportNamedSymbolTable.append(struct.unpack('<II', li.read(8)))

    for exportNamedSymbol in exportNamedSymbolTable:
        nameOffset, target = exportNamedSymbol
        target_offset = DecodeTag(segmentAddress, target)
        li.seek(nameOffset)
        name = ""
        while True:
            c = li.read(1)
            if c == '\0':
                break
            name += c
        if idaapi.segtype(target_offset) == idaapi.SEG_CODE:
            target_offset &= ~1
        idaapi.add_entry(target_offset, target_offset, name,
                         idaapi.segtype(target_offset) == idaapi.SEG_CODE)
        idaapi.make_name_public(target_offset)

    li.seek(ExportIndexedSymbolTableOffset)
    for i in range(ExportIndexedSymbolNum):
        target, = struct.unpack('<I', li.read(4))
        target_offset = DecodeTag(segmentAddress, target)
        if idaapi.segtype(target_offset) == idaapi.SEG_CODE:
            target_offset &= ~1
        idaapi.add_entry(i, target_offset, "indexedExport_%d" % i,
                         idaapi.segtype(target_offset) == idaapi.SEG_CODE)
        idaapi.make_name_public(target_offset)
Example #4
0
    def load_file(li, neflags, fmt):
        idaapi.set_processor_type(
            "arm", idaapi.SETPROC_LOADER_NON_FATAL | idaapi.SETPROC_LOADER)
        idc.set_inf_attr(idc.INF_LFLAGS,
                         idc.get_inf_attr(idc.INF_LFLAGS) | idc.LFLG_64BIT)
        idc.set_inf_attr(idc.INF_DEMNAMES, idaapi.DEMNAM_GCC3)
        idaapi.set_compiler_id(idaapi.COMP_GNU)
        idaapi.add_til('gnulnx_arm64', 1)

        # Get the meta offset
        meta_ofs = find_kernel_meta(li)
        assert meta_ofs != -1

        # Read important offsets.
        li.seek(meta_ofs + 0x40)
        text_base, init_base, init_base2, kernel_end = struct.unpack(
            '<QQQQ', li.read(0x20))

        # Load the init segment.
        li.seek(0)
        init_data = li.read(KERNEL_INIT_SIZE)

        idaapi.mem2base(init_data, init_base)

        # Emulate the kernel init segment to determine interesting extents
        emu = Emulator()
        emu.run_emulator(init_base, init_data)

        builder = SegmentBuilder()
        builder.add_segment(init_base, KERNEL_INIT_SIZE, '.init', 'RWX')
        text_phys = 0
        text_size = 0
        ro_size = 0
        rw_size = 0
        core_dram_mappings = []
        for (virt_addr, size, phys_addr, attr) in emu.mappings:
            print('%x, %x, %x, %x' % (virt_addr, size, phys_addr, attr))
            assert attr in [
                0x4000000000078B, 0x78B, 0x6000000000078B, 0x6000000000070B,
                0x60000000000607, 0x60000000000709
            ]
            if attr == 0x78B or attr == 0x4000000000078B:
                # .text
                assert virt_addr == text_base
                builder.add_segment(virt_addr, size, '.text', 'CODE')
                li.seek(phys_addr - init_base)
                idaapi.mem2base(li.read(size), virt_addr)
                text_phys = phys_addr
                text_size = size
            elif attr == 0x6000000000078B:
                # .rodata
                assert text_size != 0
                assert virt_addr == text_base + text_size
                builder.add_segment(virt_addr, size, '.rodata', 'CONST')
                li.seek(phys_addr - init_base)
                idaapi.mem2base(li.read(size), virt_addr)
                ro_size = size
            elif attr == 0x6000000000070B and virt_addr == text_base + text_size + ro_size:
                assert text_size != 0
                assert ro_size != 0
                # .rwdata
                builder.add_segment(virt_addr, size, '.rwdata', 'DATA')
                li.seek(phys_addr - init_base)
                idaapi.mem2base(li.read(size), virt_addr)
                rw_size = size
            elif attr == 0x60000000000607:
                # IO
                DEVICES = {
                    (0x40000000, 0x40000): '.iram',
                    (0x50041000, 0x01000): '.gicd',
                    (0x50042000, 0x01000): '.gicc',
                    (0x60001000, 0x01000): '.semaphore',
                    (0x60004000, 0x01000): '.primary_ictlr',
                    (0x60006000, 0x01000): '.clkrst',
                    (0x60007000, 0x01000): '.flow_ctlr',
                    (0x6000F000, 0x01000): '.evp',
                    (0x70006000, 0x01000): '.uart',
                    (0x7000E000, 0x01000): '.rtc_pmc',
                    (0x70016000, 0x02000): '.atomics',
                    (0x70019000, 0x01000): '.mc',
                    (0x7001C000, 0x01000): '.mc0',
                    (0x7001D000, 0x01000): '.mc1',
                }
                assert (phys_addr, size) in DEVICES.keys()
                name = DEVICES[(phys_addr, size)]
                builder.add_segment(virt_addr, size, name, 'IO')
            elif attr == 0x6000000000070B:
                # Kernel DRAM
                if phys_addr == (emu.ttbr & ~0xFFF) and size == 0x1000:
                    builder.add_segment(virt_addr, size, '.ttbr1', 'DATA')
                else:
                    core_dram_mappings.append(
                        (virt_addr, size, phys_addr, attr))
            else:
                # Linear DRAM
                assert attr == 0x60000000000709
                idaapi.add_segm(0, virt_addr, virt_addr + size, '.linear_dram',
                                'DATA', idaapi.ADDSEG_SPARSE)
                segm = idaapi.get_segm_by_name('.linear_dram')
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
                idaapi.update_segm(segm)
                idaapi.set_segm_addressing(segm, 2)

        assert len(core_dram_mappings) % 5 == 0
        if len(core_dram_mappings) // 5 == 3:
            # 1.0.0-style core local mappings
            assert core_dram_mappings[
                0 + 0][2] == core_dram_mappings[0 + 3][2] - 0x2000
            assert core_dram_mappings[
                0 + 3][2] == core_dram_mappings[0 + 6][2] - 0x2000
            assert core_dram_mappings[
                0 + 6][2] == core_dram_mappings[0 + 9][2] - 0x2000
            assert core_dram_mappings[0 + 0][2] == core_dram_mappings[0 +
                                                                      12][2]

            assert core_dram_mappings[
                1 + 0][2] == core_dram_mappings[1 + 3][2] - 0x2000
            assert core_dram_mappings[
                1 + 3][2] == core_dram_mappings[1 + 6][2] - 0x2000
            assert core_dram_mappings[
                1 + 6][2] == core_dram_mappings[1 + 9][2] - 0x2000
            assert core_dram_mappings[1 + 0][2] == core_dram_mappings[1 +
                                                                      12][2]

            assert core_dram_mappings[
                2 + 0][2] == core_dram_mappings[2 + 3][2] - 0x1000
            assert core_dram_mappings[
                2 + 3][2] == core_dram_mappings[2 + 6][2] - 0x1000
            assert core_dram_mappings[
                2 + 6][2] == core_dram_mappings[2 + 9][2] - 0x1000
            assert core_dram_mappings[2 + 0][2] == core_dram_mappings[2 +
                                                                      12][2]

            builder.add_segment(core_dram_mappings[0][0], 0xA000 * 4,
                                '.core_local_regions', 'DATA')
            builder.add_segment(core_dram_mappings[3 * 4 + 0][0],
                                core_dram_mappings[3 * 4 + 0][1],
                                '.current_common_stack', 'DATA')
            builder.add_segment(core_dram_mappings[3 * 4 + 1][0],
                                core_dram_mappings[3 * 4 + 1][1],
                                '.current_main_stack', 'DATA')
            builder.add_segment(core_dram_mappings[3 * 4 + 2][0],
                                core_dram_mappings[3 * 4 + 2][1],
                                '.current_context', 'DATA')
        elif len(core_dram_mappings) // 5 == 4:
            # 3.0.0-style core local mappings
            assert core_dram_mappings[
                0 + 0][2] == core_dram_mappings[0 + 4][2] - 0x2000
            assert core_dram_mappings[
                0 + 4][2] == core_dram_mappings[0 + 8][2] - 0x2000
            assert core_dram_mappings[
                0 + 8][2] == core_dram_mappings[0 + 12][2] - 0x2000
            assert core_dram_mappings[0 + 0][2] == core_dram_mappings[0 +
                                                                      16][2]

            assert core_dram_mappings[
                1 + 0][2] == core_dram_mappings[1 + 4][2] - 0x2000
            assert core_dram_mappings[
                1 + 4][2] == core_dram_mappings[1 + 8][2] - 0x2000
            assert core_dram_mappings[
                1 + 8][2] == core_dram_mappings[1 + 12][2] - 0x2000
            assert core_dram_mappings[1 + 0][2] == core_dram_mappings[1 +
                                                                      16][2]

            assert core_dram_mappings[
                2 + 0][2] == core_dram_mappings[2 + 4][2] - 0x2000
            assert core_dram_mappings[
                2 + 4][2] == core_dram_mappings[2 + 8][2] - 0x2000
            assert core_dram_mappings[
                2 + 8][2] == core_dram_mappings[2 + 12][2] - 0x2000
            assert core_dram_mappings[2 + 0][2] == core_dram_mappings[2 +
                                                                      16][2]

            assert core_dram_mappings[
                3 + 0][2] == core_dram_mappings[3 + 4][2] - 0x1000
            assert core_dram_mappings[
                3 + 4][2] == core_dram_mappings[3 + 8][2] - 0x1000
            assert core_dram_mappings[
                3 + 8][2] == core_dram_mappings[3 + 12][2] - 0x1000
            assert core_dram_mappings[3 + 0][2] == core_dram_mappings[3 +
                                                                      16][2]

            builder.add_segment(core_dram_mappings[0][0], 0xE000 * 4,
                                '.core_local_regions', 'DATA')
            builder.add_segment(core_dram_mappings[4 * 4 + 0][0],
                                core_dram_mappings[4 * 4 + 0][1],
                                '.current_common_stack', 'DATA')
            builder.add_segment(core_dram_mappings[4 * 4 + 1][0],
                                core_dram_mappings[4 * 4 + 1][1],
                                '.current_main_stack', 'DATA')
            builder.add_segment(core_dram_mappings[4 * 4 + 2][0],
                                core_dram_mappings[4 * 4 + 2][1],
                                '.current_idle_stack', 'DATA')
            builder.add_segment(core_dram_mappings[4 * 4 + 3][0],
                                core_dram_mappings[4 * 4 + 3][1],
                                '.current_context', 'DATA')

        seg_prefix = ''
        for start, end, name, kind in builder.flatten():
            idaapi.add_segm(0, start, end, seg_prefix + name, kind)
            segm = idaapi.get_segm_by_name(seg_prefix + name)
            if kind == 'CONST':
                segm.perm = idaapi.SEGPERM_READ
            elif kind == 'CODE':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC
            elif kind == 'DATA':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
            elif kind == 'BSS':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
            elif kind == 'RWX':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE | idaapi.SEGPERM_EXEC
            elif kind == 'IO':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
            idaapi.update_segm(segm)
            idaapi.set_segm_addressing(segm, 2)

        # Set vector types as code.
        for i, ctx in enumerate(['sp0', 'spx', 'a64', 'a32']):
            for j, kind in enumerate(['synch', 'irq', 'fiq', 'serror']):
                addr = emu.vbar + 0x200 * i + 0x80 * j
                name = '%s_%s_exception' % (kind, ctx)
                idc.create_insn(addr)
                idc.set_name(addr, name)

        # Set .init as code.
        idc.create_insn(init_base)
        idc.set_name(init_base, 'crt0')

        # Set text start as code.
        idc.create_insn(text_base)
        idc.set_name(text_base, 'HorizonKernelMain')

        # Patch movk instructions to be better understandable by ida.
        li.seek(text_phys - init_base)
        text = li.read(text_size)
        ro_rw = li.read(ro_size + rw_size)
        patch_movk_to_adrp(text_base, text, ro_rw, emu.mappings)

        return 1
Example #5
0
def load_cro(li, is_crs):
    if is_crs:
        base = 0
    else:
        base = 0x00100000 # arbitrary

    li.seek(0x80)
    (Magic,
    NameOffset,
    NextCRO,
    PreviousCRO,
    FileSize,
    BssSize,
    FixedSize,
    UnknownZero,
    UnkSegmentTag,
    OnLoadSegmentTag,
    OnExitSegmentTag,
    OnUnresolvedSegmentTag,

    CodeOffset,
    CodeSize,
    DataOffset,
    DataSize,
    ModuleNameOffset,
    ModuleNameSize,
    SegmentTableOffset,
    SegmentNum,

    ExportNamedSymbolTableOffset,
    ExportNamedSymbolNum,
    ExportIndexedSymbolTableOffset,
    ExportIndexedSymbolNum,
    ExportStringsOffset,
    ExportStringsSize,
    ExportTreeTableOffset,
    ExportTreeNum,

    ImportModuleTableOffset,
    ImportModuleNum,
    ExternalPatchTableOffset,
    ExternalPatchNum,
    ImportNamedSymbolTableOffset,
    ImportNamedSymbolNum,
    ImportIndexedSymbolTableOffset,
    ImportIndexedSymbolNum,
    ImportAnonymousSymbolTableOffset,
    ImportAnonymousSymbolNum,
    ImportStringsOffset,
    ImportStringsSize,

    StaticAnonymousSymbolTableOffset,
    StaticAnonymousSymbolNum,
    InternalPatchTableOffset,
    InternalPatchNum,
    StaticPatchTableOffset,
    StaticPatchNum) = struct.unpack("<IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII", li.read(0x138 - 0x80))

    if not is_crs:
        li.file2base(0, base, base + FileSize, 0)

    # set segments
    li.seek(SegmentTableOffset)
    segmentDic = [
        ("CODE", ".text"),
        ("DATA", ".rodata"),
        ("DATA", ".data"),
        ("BSS", ".bss")
    ]
    segmentAddress = []
    for i in range(SegmentNum):
        SegmentOffset, SegmentSize, SegmentType = struct.unpack("<III", li.read(12))
        if SegmentType == 3:
            SegmentOffset = 0x08000000
            idaapi.enable_flags(base + SegmentOffset, base + SegmentOffset + SegmentSize, idaapi.STT_VA)

        segmentAddress.append(base + SegmentOffset)
        if SegmentSize :
            idaapi.add_segm(0, segmentAddress[i], segmentAddress[i] + SegmentSize, segmentDic[SegmentType][1], segmentDic[SegmentType][0])

    # do internal relocations
    li.seek(InternalPatchTableOffset)
    for i in range(InternalPatchNum):
        target, patch_type, source, _, _, shift = struct.unpack("<IBBBBI", li.read(12))
        target_offset = DecodeTag(segmentAddress, target)
        source_offset = segmentAddress[source] + shift
        if patch_type == 2:
            value = source_offset
        elif patch_type == 3:
            rel = source_offset - target_offset
            if rel < 0:
                rel += 0x100000000
            value = rel
        idaapi.patch_long(target_offset, value)
        f = idaapi.fixup_data_t()
        f.type = idaapi.FIXUP_OFF32
        f.off = value
        idaapi.set_fixup(target_offset, f)

    # import
    li.seek(ImportNamedSymbolTableOffset)
    importNamedSymbolTable = []
    for i in range(ImportNamedSymbolNum):
        importNamedSymbolTable.append(struct.unpack('<II', li.read(8)))

    for importNamedSymbol in importNamedSymbolTable:
        nameOffset, batchOffset = importNamedSymbol
        li.seek(nameOffset)
        name = ""
        while True:
            c = li.read(1)
            if c == '\0':
                break
            name += c
        do_import_batch(li, segmentAddress, batchOffset, name)

    li.seek(ImportModuleTableOffset)
    module = []
    for i in range(ImportModuleNum):
        module.append(struct.unpack('<IIIII', li.read(20)))

    for m in module:
        moduleNameOffset, indexed, indexedNum, anonymous, anonymousNum = m
        li.seek(moduleNameOffset)
        mname = ""
        while True:
            c = li.read(1)
            if c == '\0':
                break
            mname += c

        indexeds = []
        li.seek(indexed)
        for i in range(indexedNum):
            indexeds.append(struct.unpack('<II', li.read(8)))

        anonymouses = []
        li.seek(anonymous)
        for i in range(anonymousNum):
            anonymouses.append(struct.unpack('<II', li.read(8)))

        for i in indexeds:
            index, batchOffset = i
            do_import_batch(li, segmentAddress, batchOffset, "%s_%d"%(mname, index))

        for i in anonymouses:
            tag, batchOffset = i
            do_import_batch(li, segmentAddress, batchOffset, "%s_%08X"%(mname, tag))

    # export
    li.seek(ExportNamedSymbolTableOffset)
    exportNamedSymbolTable = []
    for i in range(ExportNamedSymbolNum):
        exportNamedSymbolTable.append(struct.unpack('<II', li.read(8)))

    for exportNamedSymbol in exportNamedSymbolTable:
        nameOffset, target = exportNamedSymbol
        target_offset = DecodeTag(segmentAddress, target)
        li.seek(nameOffset)
        name = ""
        while True:
            c = li.read(1)
            if c == '\0':
                break
            name += c
        idaapi.add_entry(target_offset, target_offset, name, idaapi.segtype(target_offset) == idaapi.SEG_CODE)
        idaapi.make_name_public(target_offset)

    li.seek(ExportIndexedSymbolTableOffset)
    for i in range(ExportIndexedSymbolNum):
        target, = struct.unpack('<I', li.read(4))
        target_offset = DecodeTag(segmentAddress, target)
        idaapi.add_entry(i, target_offset, "indexedExport_%d" % i, idaapi.segtype(target_offset) == idaapi.SEG_CODE)
        idaapi.make_name_public(target_offset)
Example #6
0
def load_file(f, neflags, format):

    print('# PS4 Kernel Loader')
    ps4 = Binary(f)

    # PS4 Processor, Compiler, Library
    bitness = ps4.procomp('metapc', CM_N64 | CM_M_NN | CM_CC_FASTCALL,
                          'gnulnx_x64')

    # Segment Loading...
    for segm in ps4.E_SEGMENTS:

        # Process Loadable Segments...
        if segm.name() in ['CODE', 'DATA', 'SCE_RELRO']:
            address = segm.MEM_ADDR
            size = segm.MEM_SIZE

            # Dumped Kernel Fix-ups
            if segm.name() in ['DATA', 'SCE_RELRO'
                               ] and idaapi.get_segm_by_name(
                                   'CODE').start_ea != 0xFFFFFFFF82200000:
                offset = address - idaapi.get_segm_by_name('CODE').start_ea
                dumped = segm.MEM_SIZE
            else:
                offset = segm.OFFSET
                dumped = segm.FILE_SIZE

            print('# Creating %s Segment...' % segm.name())
            f.file2base(offset, address, address + dumped, FILEREG_PATCHABLE)

            idaapi.add_segm(0, address, address + size, segm.name(),
                            segm.type(), ADDSEG_NOTRUNC | ADDSEG_FILLGAP)

            # Processor Specific Segment Details
            idc.set_segm_addressing(address, bitness)
            idc.set_segm_alignment(address, segm.alignment())
            idc.set_segm_attr(address, SEGATTR_PERM, segm.flags())

        # Process Dynamic Segment...
        elif segm.name() == 'DYNAMIC':
            code = idaapi.get_segm_by_name('CODE')
            data = idaapi.get_segm_by_name('DATA')
            relro = idaapi.get_segm_by_name('SCE_RELRO')

            # ------------------------------------------------------------------------------------------------------------
            # Dynamic Tag Entry Structure
            members = [('tag', 'Tag', 0x8), ('value', 'Value', 0x8)]
            struct = segm.struct('Tag', members)

            # Dynamic Tag Table
            stubs = {}
            modules = {}
            location = segm.MEM_ADDR

            # Dumps are offset by a small amount
            if code.start_ea != 0xFFFFFFFF82200000:
                dumped = code.start_ea - 0xFFFFFFFF82200000
            else:
                dumped = 0

            f.seek(location - code.start_ea)
            for entry in xrange(segm.MEM_SIZE / 0x10):
                idaapi.create_struct(location + (entry * 0x10), 0x10, struct)
                idc.set_cmt(location + (entry * 0x10),
                            Dynamic(f).process(dumped, stubs, modules), False)

            # ------------------------------------------------------------------------------------------------------------
            # Hash Entry Structure
            members = [('bucket', 'Bucket', 0x2), ('chain', 'Chain', 0x2),
                       ('buckets', 'Buckets', 0x2), ('chains', 'Chains', 0x2)]
            struct = segm.struct('Hash', members)

            # Hash Table
            try:
                location = Dynamic.HASHTAB
                size = Dynamic.HASHTABSZ

            except:
                location = Dynamic.HASH
                size = Dynamic.SYMTAB - location

            f.seek(location - code.start_ea)
            for entry in xrange(size / 0x8):
                idaapi.create_struct(location + (entry * 0x8), 0x8, struct)

            # --------------------------------------------------------------------------------------------------------
            # Relocation Entry Structure (with specific addends)
            members = [('offset', 'Offset (String Index)', 0x8),
                       ('info', 'Info (Symbol Index : Relocation Code)', 0x8),
                       ('addend', 'AddEnd', 0x8)]
            struct = segm.struct('Relocation', members)

            # Relocation Table (with specific addends)
            location = Dynamic.RELATAB

            f.seek(location - code.start_ea)
            for entry in xrange(Dynamic.RELATABSZ / 0x18):
                idaapi.create_struct(location + (entry * 0x18), 0x18, struct)
                idc.set_cmt(location + (entry * 0x18),
                            Relocation(f).process(dumped, code.end_ea), False)

            # Initialization Function
            idc.add_entry(Dynamic.INIT, Dynamic.INIT, '.init', True)

    address = code.start_ea

    # ELF Header Structure
    members = [('File format', 0x4), ('File class', 0x1),
               ('Data encoding', 0x1), ('File version', 0x1), ('OS/ABI', 0x1),
               ('ABI version', 0x1), ('Padding', 0x7), ('File type', 0x2),
               ('Machine', 0x2), ('File version', 0x4), ('Entry point', 0x8),
               ('PHT file offset', 0x8), ('SHT file offset', 0x8),
               ('Processor-specific flags', 0x4), ('ELF header size', 0x2),
               ('PHT entry size', 0x2), ('Number of entries in PHT', 0x2),
               ('SHT entry size', 0x2), ('Number of entries in SHT', 0x2),
               ('SHT entry index for string table\n', 0x2)]

    for (comment, size) in members:
        flags = idaapi.get_flags_by_size(size)
        idc.create_data(address, flags if flags != 0 else FF_STRLIT, size,
                        BADNODE)
        idc.set_cmt(address, comment, False)
        address += size

    for index, entry in enumerate(ps4.E_SEGMENTS):
        # ELF Program Header Structure
        members = [('Type: %s' % entry.name(), 0x4), ('Flags', 0x4),
                   ('File offset', 0x8), ('Virtual address', 0x8),
                   ('Physical address', 0x8), ('Size in file image', 0x8),
                   ('Size in memory image', 0x8), ('Alignment\n', 0x8)]

        for (comment, size) in members:
            flags = idaapi.get_flags_by_size(size)

            idc.create_data(address, flags if flags != 0 else FF_STRLIT, size,
                            BADNODE)
            idc.set_cmt(address, comment, False)
            address += size

    # Start Function
    idc.add_entry(ps4.E_START_ADDR, ps4.E_START_ADDR, 'start', True)

    # Xfast_syscall
    address = idaapi.find_binary(
        code.start_ea, code.end_ea,
        '0F 01 F8 65 48 89 24 25 A8 02 00 00 65 48 8B 24', 0x10, SEARCH_DOWN)
    idaapi.do_unknown(address, 0)
    idaapi.create_insn(address)
    idaapi.add_func(address, BADADDR)
    idaapi.set_name(address, 'Xfast_syscall',
                    SN_NOCHECK | SN_NOWARN | SN_FORCE)

    # --------------------------------------------------------------------------------------------------------
    # Znullptr's syscalls
    print('# Processing Znullptr\'s Syscalls...')

    # Syscall Entry Structure
    members = [('narg', 'Number of Arguments', 0x4), ('_pad', 'Padding', 0x4),
               ('function', 'Function', 0x8),
               ('auevent', 'Augmented Event?', 0x2), ('_pad1', 'Padding', 0x2),
               ('_pad2', 'Padding', 0x4),
               ('trace_args_func', 'Trace Arguments Function', 0x8),
               ('entry', 'Entry', 0x4), ('return', 'Return', 0x4),
               ('flags', 'Flags', 0x4), ('thrcnt', 'Thread Count?', 0x4)]
    struct = segm.struct('Syscall', members)

    znullptr(code.start_ea, code.end_ea,
             '4F 52 42 49 53 20 6B 65 72 6E 65 6C 20 53 45 4C 46', struct)

    # --------------------------------------------------------------------------------------------------------
    # Chendo's cdevsw con-struct-or
    print('# Processing Chendo\'s Structures...')

    # cdevsw Entry Structure
    members = [('d_version', 'Version', 0x4), ('d_flags', 'Flags', 0x4),
               ('d_name', 'Name', 0x8), ('d_open', 'Open', 0x8),
               ('d_fdopen', 'File Descriptor Open', 0x8),
               ('d_close', 'Close', 0x8), ('d_read', 'Read', 0x8),
               ('d_write', 'Write', 0x8),
               ('d_ioctl', 'Input/Ouput Control', 0x8),
               ('d_poll', 'Poll', 0x8), ('d_mmap', 'Memory Mapping', 0x8),
               ('d_strategy', 'Strategy', 0x8), ('d_dump', 'Dump', 0x8),
               ('d_kqfilter', 'KQFilter', 0x8), ('d_purge', 'Purge', 0x8),
               ('d_mmap_single', 'Single Memory Mapping', 0x8),
               ('d_spare0', 'Spare0', 0x8), ('d_spare1', 'Spare1', 0x8),
               ('d_spare2', 'Spare2', 0x8), ('d_spare3', 'Spare3', 0x8),
               ('d_spare4', 'Spare4', 0x8), ('d_spare5', 'Spare5', 0x8),
               ('d_spare6', 'Spare6', 0x4), ('d_spare7', 'Spare7', 0x4)]
    struct = segm.struct('cdevsw', members)

    chendo(data.start_ea, data.end_ea, '09 20 12 17', struct)

    # --------------------------------------------------------------------------------------------------------
    # Pablo's IDC
    try:
        print('# Processing Pablo\'s Push IDC...')

        # Script 1) Push it real good...
        # Default patterns set
        pablo(0, code.start_ea, 0x10, '55 48 89')
        pablo(2, code.start_ea, code.end_ea, '90 90 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, 'C3 90 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, '66 90 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, 'C9 C3 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, '0F 0B 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, 'EB ?? 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, '5D C3 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, '5B C3 55 48 ??')
        pablo(2, code.start_ea, code.end_ea, '90 90 55 41 ?? 41 ??')
        pablo(2, code.start_ea, code.end_ea, '66 90 48 81 EC ?? 00 00 00')
        pablo(2, code.start_ea, code.end_ea,
              '0F 0B 48 89 9D ?? ?? FF FF 49 89')
        pablo(2, code.start_ea, code.end_ea, '90 90 53 4C 8B 54 24 20')
        pablo(2, code.start_ea, code.end_ea, '90 90 55 41 56 53')
        pablo(2, code.start_ea, code.end_ea, '90 90 53 48 89')
        pablo(2, code.start_ea, code.end_ea, '90 90 41 ?? 41 ??')
        pablo(3, code.start_ea, code.end_ea, '0F 0B 90 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, 'EB ?? 90 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '41 5F C3 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '41 5C C3 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '31 C0 C3 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '41 5D C3 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '41 5E C3 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '66 66 90 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '0F 1F 00 55 48 ??')
        pablo(3, code.start_ea, code.end_ea, '41 ?? C3 53 48')
        pablo(3, code.start_ea, code.end_ea, '0F 1F 00 48 81 EC ?? 00 00 00')
        pablo(4, code.start_ea, code.end_ea, '0F 1F 40 00 55 48 ??')
        pablo(4, code.start_ea, code.end_ea,
              '0F 1F 40 00 48 81 EC ?? 00 00 00')
        pablo(5, code.start_ea, code.end_ea, 'E9 ?? ?? ?? ?? 55 48 ??')
        pablo(5, code.start_ea, code.end_ea, 'E8 ?? ?? ?? ?? 55 48 ??')
        pablo(5, code.start_ea, code.end_ea, '48 83 C4 ?? C3 55 48 ??')
        pablo(5, code.start_ea, code.end_ea, '0F 1F 44 00 00 55 48 ??')
        pablo(5, code.start_ea, code.end_ea,
              '0F 1F 44 00 00 48 81 EC ?? 00 00 00')
        pablo(6, code.start_ea, code.end_ea, 'E9 ?? ?? ?? ?? 90 55 48 ??')
        pablo(6, code.start_ea, code.end_ea, 'E8 ?? ?? ?? ?? 90 55 48 ??')
        pablo(6, code.start_ea, code.end_ea, '66 0F 1F 44 00 00 55 48 ??')
        pablo(7, code.start_ea, code.end_ea, '0F 1F 80 00 00 00 00 55 48 ??')
        pablo(8, code.start_ea, code.end_ea,
              '0F 1F 84 00 00 00 00 00 55 48 ??')
        pablo(8, code.start_ea, code.end_ea, 'C3 0F 1F 80 00 00 00 00 48')
        pablo(8, code.start_ea, code.end_ea,
              '0F 1F 84 00 00 00 00 00 53 48 83 EC')

        # Special cases patterns set
        pablo(13, code.start_ea, code.end_ea,
              'C3 90 90 90 90 90 90 90 90 90 90 90 90 48')
        pablo(13, code.start_ea, code.end_ea,
              'C3 90 90 90 90 90 90 90 90 90 90 90 90 55')
        pablo(17, code.start_ea, code.end_ea,
              'E9 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 48')
        pablo(19, code.start_ea, code.end_ea,
              'E9 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 48')
        pablo(19, code.start_ea, code.end_ea,
              'E8 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 48')
        pablo(
            20, code.start_ea, code.end_ea,
            'E9 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 48')
        pablo(
            20, code.start_ea, code.end_ea,
            'E9 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 48')

        # Script 2) Fix-up Dumped Data Pointers...
        if dumped:
            print('# Processing Pablo\'s Dumped Data Pointers IDC...')
            pablo(0, data.start_ea, data.end_ea, '?? FF FF FF FF')

    except:
        pass

    # --------------------------------------------------------------------------------------------------------
    # Kiwidog's __stack_chk_fail
    print('# Processing Kiwidog\'s Stack Functions...')

    kiwidog(
        code.start_ea, code.end_ea,
        '73 74 61 63 6B 20 6F 76 65 72 66 6C 6F 77 20 64 65 74 65 63 74 65 64 3B'
    )

    print('# Done!')
    return 1
Example #7
0
import os

SEG_PROT_R = 4
SEG_PROT_W = 2
SEG_PROT_X = 1

cmd = 'vmmap'
try:
    mappings = json.loads(idc.send_dbg_command("vmmap"))
    for start, end, prot, pathname in mappings:
        # if pathname == "<no name>": continue # Why we should ignore mmapped mapges & co.?
        perms = 0
        if prot & SEG_PROT_R: perms |= idaapi.SEGPERM_READ
        if prot & SEG_PROT_W: perms |= idaapi.SEGPERM_WRITE
        if prot & SEG_PROT_X: perms |= idaapi.SEGPERM_EXEC
        name = os.path.basename(pathname)
        sclass = "DATA"  # TODO recognize automatically sclass
        idaapi.add_segm(0, start, end, name, sclass)
        idc.set_segm_attr(start, SEGATTR_PERM, perms)
        idc.set_segm_attr(start, SEGATTR_ES, 0)
        idc.set_segm_attr(start, SEGATTR_CS, 0)
        idc.set_segm_attr(start, SEGATTR_SS, 0)
        idc.set_segm_attr(start, SEGATTR_DS, 0)
        idc.set_segm_attr(start, SEGATTR_FS, 0)
        idc.set_segm_attr(start, SEGATTR_GS, 0)
except:
    #self.AddLine(idaapi.COLSTR("Debugger is not active or does not export send_dbg_command()", idaapi.SCOLOR_ERROR))
    import traceback
    traceback.print_exc()
    print("\nDebugger is not active or does not export send_dbg_command()")
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
Example #9
0
def load_file(li, neflags, format):
    if format != "NeoGeo 68k loader":
        return 0

    idaapi.set_processor_type("68000", SETPROC_ALL | SETPROC_FATAL)

    idaapi.add_segm(0, 0x000000, 0x0FFFFF, "ROM", "CODE")
    idaapi.add_segm(0, 0x100000, 0x10F2FF, "WRAM", "DATA")
    idaapi.add_segm(0, 0x10F300, 0x10FFFF, "BIOSRAM", "DATA")
    idaapi.add_segm(0, 0x200000, 0x2FFFFF, "PORT", "DATA")
    idaapi.add_segm(0, 0x300000, 0x3FFFFF, "IO", "DATA")
    idaapi.add_segm(0, 0x400000, 0x401FFF, "PALETTES", "DATA")
    idaapi.add_segm(0, 0x800000, 0xBFFFFF, "MEMCARD", "DATA")
    idaapi.add_segm(0, 0xC00000, 0xC1FFFF, "SYSROM", "DATA")
    idaapi.add_segm(0, 0xD00000, 0xD0FFFF, "BRAM", "DATA")

    map_io_registers()

    li.seek(0, 2)
    file_size = li.tell()
    li.seek(0)

    # read p1 rom
    file_data = li.read(0x100000)
    file_remain = file_size - 0x100000

    idaapi.mem2base(file_data, 0, 0x100000)

    # read p2 rom
    bank2_seg_offset = 0x01000000
    bank2_seg_index = 0

    while file_remain > 0:
        bank2_seg_start = bank2_seg_offset + 0x200000
        bank2_seg_end = bank2_seg_start + 0x2FFFFF

        idaapi.add_segm(0, bank2_seg_start, bank2_seg_end,
                        "BANK2_%d" % bank2_seg_index, "DATA")

        bytes_to_read = file_remain
        if bytes_to_read > 0x100000:
            bytes_to_read = 0x100000

        file_data = li.read(bytes_to_read)
        idaapi.mem2base(file_data, bank2_seg_start,
                        bank2_seg_start + len(file_data))

        bank2_seg_offset += 0x01000000
        bank2_seg_index += 1
        file_remain -= bytes_to_read

    # http://ajworld.net/neogeodev/beginner/
    name_long(0x000000, "InitSP")
    name_long(0x000004, "InitPC")
    name_long(0x000008, "BusError")
    name_long(0x00000C, "AddressError")
    name_long(0x000010, "IllegalInstruction")
    name_long(0x000014, "DivByZero")
    name_long(0x000018, "CHK")
    name_long(0x00001C, "TRAPV")
    name_long(0x000020, "PrivilegeViolation")
    name_long(0x000024, "Trace")
    name_long(0x000028, "Line1010Emu")
    name_long(0x00002C, "Line1111Emu")
    name_array(0x000030, "Reserved0", 0xC)
    name_long(0x000003C, "UnintializedInterruptVec")
    name_array(0x000040, "Reserved1", 0x20)
    name_long(0x000060, "VirtualInterrupt")
    name_long(0x000064, "Interrupt1")
    name_long(0x000068, "Interrupt2")
    name_long(0x00006C, "Interrupt3")
    name_long(0x000070, "Interrupt4")
    name_long(0x000074, "Interrupt5")
    name_long(0x000078, "Interrupt6")
    name_long(0x00007C, "Interrupt7")
    name_dword_array(0x000080, "Traps", 0x10)
    name_array(0x0000C0, "Reserved2", 0x40)

    # Neo-Geo header
    # https://wiki.neogeodev.org/index.php?title=68k_program_header
    idc.create_strlit(0x000100, 0x000107)
    idaapi.set_name(0x000100, "Magic")
    name_byte(0x000107, "SysVersion")
    name_word(0x000108, "GameID")
    name_long(0x00010A, "ProgramSize")
    name_long(0x00010E, "BackupRAMPtr")
    name_word(0x000112, "BackupRAMSize")
    name_byte(0x000114, "EyecatchFlag")
    name_byte(0x000115, "EyecatchSpriteBank")
    name_long(0x000116, "MenuJP")
    name_long(0x00011A, "MenuUS")
    name_long(0x00011E, "MenuEU")
    name_code(0x000122, "Routine_USER", 6)
    name_code(0x000128, "Routine_PLAYER_START", 6)
    name_code(0x00012E, "Routine_DEMO_END", 6)
    name_code(0x000134, "Routine_COIN_SOUND", 6)
    name_array(0x00013A, "Unknown0", 0x48)
    name_long(0x000182, "CartridgeRecognitionCodePtr")
    name_long(0x000186, "Unknown1")
    name_long(0x00018A, "Unknown2")
    name_long(0x00018E, "MenuES")  # Spanish

    # BIOS RAM
    set_name_with_comment(0x10FD80, "BIOS_SYSTEM_MODE", "0x00 : System"
                          "0x80 : Game")

    set_name_with_comment(0x10FD82, "BIOS_MVS_FLAG", "0 : HOME/AES\n"
                          "1 : MVS")

    set_name_with_comment(
        0x10FDAE, "BIOS_USER_REQUEST", "0 : Startup initialization\n"
        "1 : Eye-catcher\n"
        "2 : Demo Game / Game\n"
        "3 : Title Display")

    set_name_with_comment(
        0x10FDAF, "BIOS_USER_MODE", "Current game status.\n"
        "0 : init/boot\n"
        "1 : title/demo\n"
        "2 : game")

    set_name_with_comment(
        0x10FEC5, "BIOS_TITLE_MODE",
        "Newer games set this to 1 in their command 3 USER subroutine.\n"
        "It prevents the system ROM from calling command 3 twice after game over if credits are already in the system.\n"
    )

    #idaapi.del_items(0x3C0000)
    # VRAM

    set_name_with_comment(
        0x3C0000, "REG_VRAMADDR",
        "sets the VRAM address for the next read/write operation.")
    set_name_with_comment(0x3C0002, "REG_VRAMRW", "the data read or to write.")
    set_name_with_comment(
        0x3C0004, "REG_VRAMMOD",
        "the signed value automatically added to the VRAM address after a write."
    )

    set_name_with_comment(
        0x3C000C, "LSPC_IRQ_ACK",
        "IRQ acknowledgement register.\nbit2 : Ack.VBlank | bit 1 : Ack.HBlank | bit 0 : IRQ3"
    )

    idaapi.set_name(0xC00444, "SYSTEM_RETURN")
    idaapi.set_name(0xC0044A, "SYSTEM_IO")

    idaapi.set_name(0xD00100, "BOARD_CORRUPTED")

    #idaapi.set_cmt(0x3C0000, "Pouet.", 1)
    return 1
Example #10
0
    def add_mdec_regs(cls):
        idaapi.add_segm(0, 0x1F801820, 0x1F801828, 'MDEC_REGS', 'XTRN')

        cls.add_port_4(0x1F801820, 'MDEC_REG0')
        cls.add_port_4(0x1F801824, 'MDEC_REG1')
Example #11
0
 def create_got_fix(cls):
     idaapi.add_segm(0, 0x90000000, 0x90000001, '.got', 'DATA')
     seg = idaapi.getseg(0x90000000)
     idaapi.set_visible_segm(seg, False)
Example #12
0
    def add_dma(cls):
        idaapi.add_segm(0, 0x1F801080, 0x1F80108C, 'DMA_MDEC_IN', 'XTRN')
        idaapi.add_segm(0, 0x1F801090, 0x1F80109C, 'DMA_MDEC_OUT', 'XTRN')
        idaapi.add_segm(0, 0x1F8010A0, 0x1F8010AC, 'DMA_GPU', 'XTRN')
        idaapi.add_segm(0, 0x1F8010B0, 0x1F8010BC, 'DMA_CDROM', 'XTRN')
        idaapi.add_segm(0, 0x1F8010C0, 0x1F8010CC, 'DMA_SPU', 'XTRN')
        idaapi.add_segm(0, 0x1F8010D0, 0x1F8010DC, 'DMA_PIO', 'XTRN')
        idaapi.add_segm(0, 0x1F8010E0, 0x1F8010EC, 'DMA_OTC', 'XTRN')
        idaapi.add_segm(0, 0x1F8010F0, 0x1F8010F8, 'DMA_CTRL_INT', 'XTRN')

        cls.add_port_4(0x1F801080, 'DMA_MDEC_IN_MADR')
        cls.add_port_4(0x1F801084, 'DMA_MDEC_IN_BCR')
        cls.add_port_4(0x1F801088, 'DMA_MDEC_IN_CHCR')

        cls.add_port_4(0x1F801090, 'DMA_MDEC_OUT_MADR')
        cls.add_port_4(0x1F801094, 'DMA_MDEC_OUT_BCR')
        cls.add_port_4(0x1F801098, 'DMA_MDEC_OUT_CHCR')

        cls.add_port_4(0x1F8010A0, 'DMA_GPU_MADR')
        cls.add_port_4(0x1F8010A4, 'DMA_GPU_BCR')
        cls.add_port_4(0x1F8010A8, 'DMA_GPU_CHCR')

        cls.add_port_4(0x1F8010B0, 'DMA_CDROM_MADR')
        cls.add_port_4(0x1F8010B4, 'DMA_CDROM_BCR')
        cls.add_port_4(0x1F8010B8, 'DMA_CDROM_CHCR')

        cls.add_port_4(0x1F8010C0, 'DMA_SPU_MADR')
        cls.add_port_4(0x1F8010C4, 'DMA_SPU_BCR')
        cls.add_port_4(0x1F8010C8, 'DMA_SPU_CHCR')

        cls.add_port_4(0x1F8010D0, 'DMA_PIO_MADR')
        cls.add_port_4(0x1F8010D4, 'DMA_PIO_BCR')
        cls.add_port_4(0x1F8010D8, 'DMA_PIO_CHCR')

        cls.add_port_4(0x1F8010E0, 'DMA_OTC_MADR')
        cls.add_port_4(0x1F8010E4, 'DMA_OTC_BCR')
        cls.add_port_4(0x1F8010E8, 'DMA_OTC_CHCR')

        cls.add_port_4(0x1F8010F0, 'DMA_DPCR')
        cls.add_port_4(0x1F8010F4, 'DMA_DICR')
Example #13
0
    def add_gpu_regs(cls):
        idaapi.add_segm(0, 0x1F801810, 0x1F801818, 'GPU_REGS', 'XTRN')

        cls.add_port_4(0x1F801810, 'GPU_REG0')
        cls.add_port_4(0x1F801814, 'GPU_REG1')
Example #14
0
    def add_int_ctrl(cls):
        idaapi.add_segm(0, 0x1F801070, 0x1F801076, 'INT_CTRL', 'XTRN')

        cls.add_port_2(0x1F801070, 'I_STAT')
        cls.add_port_2(0x1F801074, 'I_MASK')
Example #15
0
    def add_mem_ctrl2(cls):
        idaapi.add_segm(0, 0x1F801060, 0x1F801064, 'MCTRL2', 'XTRN')

        cls.add_port_4(0x1F801060, 'RAM_SIZE')
Example #16
0
def load_file(li, neflags, format):
    # Check the format we've been asked to load
    if format != FORMAT_NAME:
        return 0

    # Datatrak 68K - set processor type
    idaapi.set_processor_type("68000", SETPROC_ALL | SETPROC_FATAL)

    # Add segments
    idaapi.add_segm(0, 0x000000, 0x03FFFF, "ROM",
                    "CODE")  # TODO validate ROM area
    idaapi.add_segm(0, 0x200000, 0x21FFFF, "RAM",
                    "DATA")  # TODO validate RAM area
    idaapi.add_segm(0, 0x220000, 0x23FFFF, "RAM2",
                    "DATA")  # TODO validate this, it's here just to fill space
    idaapi.add_segm(0, 0x240000, 0x2400FF, "IO_ADC", "DATA")  # A/D converter
    idaapi.add_segm(0, 0x240100, 0x2401FF, "IO_UNK_01", "DATA")  #
    idaapi.add_segm(0, 0x240200, 0x2402FF, "IO_RFPHA",
                    "DATA")  # RF phase detector
    idaapi.add_segm(0, 0x240300, 0x2403FF, "IO_UART", "DATA")  # Dual UART
    idaapi.add_segm(0, 0x240400, 0x2404FF, "IO_UNK_04", "DATA")  #
    idaapi.add_segm(0, 0x240500, 0x2405FF, "IO_UNK_05", "DATA")  #
    idaapi.add_segm(0, 0x240600, 0x2406FF, "IO_UNK_06", "DATA")  #
    idaapi.add_segm(0, 0x240700, 0x2407FF, "IO_UNK_07", "DATA")  #
    idaapi.add_segm(0, 0x240800, 0x2408FF, "IO_UNK_08", "DATA")  #
    idaapi.add_segm(0, 0x240900, 0x24FFFF, "IO_UNKNOWN", "DATA")  #

    # Seek to EOF and get filesize
    li.seek(0, 2)
    size = li.tell()

    # Seek back to start of file, read the file into memory
    li.seek(0)
    file_data = li.read(size)
    idaapi.mem2base(file_data, 0, size)  # data,start,end

    do_68k_vectors()

    # Get the initial program counter
    initPC = struct.unpack('>L', bytearray(file_data[4:8]))[0]

    # Hunt down the DATA segment initialiser, starting at the reset vector
    pattern = [
        0x41,
        0xF9,
        0x00,
        0x20,
        0x00,
        0x00,  # LEA    (0x200000).L, A0     ; start of dseg in RAM
        0x20,
        0x3C,
        0x00,
        None,
        None,
        None,  # MOVE.L #EndOfDataSeg, D0    ; end of dseg in RAM
        0x90,
        0x88,  # SUB.L  A0, D0               ; D0 = D0 - A0
        0x43,
        0xF9,
        0x00,
        None,
        None,
        None,  # LEA    (StartOfData), A1    ; start of dseg initialisation data
        0x53,
        0x80,  # SUBQ.L #1, D0               ; D0 --
        0x10,
        0xD9,  # MOVE.B (A1)+, (A0)+         ; *a0++ = *a1++
        0x51,
        0xC8,
        0xFF,
        0xFC  # DBF    D0, $-2              ; decrement d0, branch if >= 0
    ]
    sh_reg = [0x00] * len(pattern)

    # TODO: Refactor this to use IDA's internal buffer instead of the file_data array?

    for addr in range(initPC, initPC + 0x100):
        # shift in next byte
        sh_reg = sh_reg[1:]
        sh_reg.append(ord(file_data[addr]))

        # check if we've found a match
        match = True
        for i in range(len(pattern)):
            if pattern[i] is not None and pattern[i] != sh_reg[i]:
                match = False
                break

        # exit the search loop if we found a match
        if match:
            break

    if match:
        # If we've exited the loop and have a match, fish the DSEG addresses
        # out of the instruction parameters.
        dsegRamStart = struct.unpack(">L", bytearray(sh_reg[2:6]))[0]
        dsegRamEnd = struct.unpack(">L", bytearray(sh_reg[8:12]))[0]
        dsegRomStart = struct.unpack(">L", bytearray(sh_reg[16:20]))[0]

        print("DSEG RAM Start %08X" % dsegRamStart)
        print("DSEG RAM End   %08X" % dsegRamEnd)
        print("DSEG ROM Start %08X" % dsegRomStart)

        # Calculate initialised data segment end and end of the idata in ROM
        dsegLen = dsegRamEnd - dsegRamStart
        dsegRomEnd = dsegRomStart + dsegLen

        # Load the idata into RAM from the appropriate part of the ROM file
        idaapi.mem2base(file_data[dsegRomStart:dsegRomEnd], dsegRamStart,
                        dsegRamEnd)

        # TODO: Designate the source idata as ROM DATA
        idaapi.add_segm(0, dsegRomStart, dsegRomEnd, "DATAINIT", "DATA")
    else:
        print("No Match")

    # TODO: Try to identify the boundary between CODE and ROMDATA and move that into a segment

    # Wait for autoanalysis to finish
    autoWait()

    # Convert all MOVEA source parameters into address references
    doMoveaAddrRefs()

    # TODO: Search for switch-case jump tables
    oper_re = re.compile(r'\(pc,([ad][0-9]).([bwl])\)')
    insnStack = []
    for ea in Heads(0x33B0, 0x33D0):
        # Decode the instruction and operands
        insn = {
            'ea': ea,
            'disasm': GetDisasm(ea),
            'mnem': GetMnem(ea),
        }
        opnds = []
        for i in range(3):
            opnd = {
                'type': get_operand_type(ea, i),
                'opnd': GetOpnd(ea, i),
                'value': GetOperandValue(ea, i)
            }
            # store non-empty operands only
            if opnd['type'] != 0:  # FIXME use operand type constants
                opnds.append(opnd)
        insn['operands'] = opnds

        # push the instruction onto the stack, limiting the stack size
        insnStack.append(insn)
        insnStack = insnStack[-10:]

        # Look for this sequence at the end of the stack:
        #   ADD.W    d0,d0
        #   MOVE.W   <table>(pc,d0.w)
        #   JMP      <table>(pc,d0.w)
        #
        if insnStack[-1]['mnem'] == 'jmp' and insnStack[-2]['mnem'].startswith(
                'move.') and insnStack[-3]['mnem'].startswith('add.'):
            print("*** Potential jumptable sequence found at EOS")
            pprint(insnStack[-3])
            pprint(insnStack[-2])
            pprint(insnStack[-1])

            # Check the argtypes
            # Jump and move should have identical first argument types
            if insnStack[-1]['operands'][0]['type'] != 4 or insnStack[-2][
                    'operands'][0]['type'] != 4:
                continue

            # Add should be rigged to double the value of a register
            if insnStack[-3]['operands'][0]['type'] != 1 or insnStack[-3][
                    'operands'][1]['type'] != 1:
                continue
            if insnStack[-3]['operands'][0]['opnd'] != insnStack[-3][
                    'operands'][1]['opnd']:
                continue

            # Jumptable address is the offset in the jump instruction's first operand
            jumptableAddr = insnStack[-1]['operands'][0]['value']
            # Jump instruction EA
            jumpinstrAddr = insnStack[-1]['ea']
            # Jump register
            jumpReg = insnStack[-3]['operands'][0]['opnd']

            # Is there a subtract instruction above the 'add R,R'?
            if insnStack[-4]['mnem'].startswith('subi.'):
                jumpOffset = insnStack[-4]['operands'][0]['value']
            else:
                jumpOffset = 0

            print(
                "Jumptable Debug: TADDR %08X, JADDR %08X, OFFSET %d, REGISTER '%s'"
                % (jumptableAddr, jumpinstrAddr, jumpOffset, jumpReg))

            jtLowerBound = None
            jtUpperBound = None

            # Hunt backwards for the compare operations (to get the JT bounds)
            for i in reversed(range(3, 8)):  # 10 - 2
                curi = insnStack[-i]
                previ = insnStack[-(i + 1)]
                if previ['mnem'].startswith('cmpi.'):
                    print("COMPARE value %d" % previ['operands'][0]['value'])
                    if curi['mnem'].startswith('blt.'):
                        jtLowerBound = previ['operands'][0]['value']
                    elif curi['mnem'].startswith('bgt.'):
                        jtUpperBound = previ['operands'][0]['value']

            print("Jumptable Debug: upperbound %s lowerbound %s" %
                  (jtUpperBound, jtLowerBound))

            # TODO: figure out the register size

            # Set jumptable data
            swInf = switch_info_t()
            swInf.set_jtable_element_size

    # TODO: use AddCodeXref(?) to link calls where a function address has been copied into an address register

    # TODO: Search for the task table?
    """
	# ???
	idaapi.do_unknown(0x3C0000, 1)
	idaapi.doByte(0x3C0000, 1)
	idaapi.set_name(0x3C0000, "REG_VRAMADDR")
	#idaapi.set_cmt(0x3C0000, "Pouet.", 1)
	"""

    return 1
def fix_callgraph(msgsend, segname, class_param, sel_param):
    '''
    fix_callgraph: msgsend, segname, class_param, sel_param

    Given the msgsend flavour address as a parameter, looks
    for the parameters (class and selector, identified by
    class_param and sel_param) and creates a new segment where
    it places a set of dummy calls named as classname_methodname
    (we use method instead of selector most of the time).
    '''

    t1 = time.time()
    if not msgsend:
        print 'ERROR: msgSend not found'
        return

    total = 0
    resolved = 0
    call_table = dict()

    for xref in idautils.XrefsTo(msgsend, idaapi.XREF_ALL):
        total += 1
        ea_call = xref.frm
        func_start = idc.GetFunctionAttr(ea_call, idc.FUNCATTR_START)
        if not func_start or func_start == idc.BADADDR:
            continue
        ea = ea_call
        method_name_ea = trace_param(ea, func_start, idc.o_reg, sel_param)
        if method_name_ea and idc.isASCII(idc.GetFlags(method_name_ea)):
            method_name = idc.GetString(method_name_ea, -1, idc.ASCSTR_C)
            if not method_name:
                method_name = '_unk_method'
        else:
            method_name = '_unk_method'

        class_name_ea = trace_param(ea, func_start, idc.o_reg, class_param)
        if class_name_ea:
            class_name = idc.Name(class_name_ea)
            if not class_name:
                class_name = '_unk_class'
        else:
            class_name = '_unk_class'

        if method_name == '_unk_method' and class_name == '_unk_class':
            continue

        # Using this name convention, if the class and method
        # are identified by IDA, the patched call will point to
        # the REAL call and not one of our dummy functions
        #
        class_name = class_name.replace('_OBJC_CLASS_$_', '')
        class_name = class_name.replace('_OBJC_METACLASS_$_', '')
        new_name = '_[' + class_name + '_' + method_name + ']'
        print '%08x: %s' % (ea_call, new_name)
        call_table[ea_call] = new_name
        resolved += 1

    print '\nFinal stats:\n\t%d total calls, %d resolved' % (total, resolved)
    print '\tAnalysis took %.2f seconds' % (time.time() - t1)

    if resolved == 0:
        print 'Nothing to patch.'
        return

    print 'Adding new segment to store new nullsubs'

    # segment size = opcode ret (4 bytes) * num_calls
    seg_size = resolved * 4
    seg_start = idc.MaxEA() + 4
    idaapi.add_segm(0, seg_start, seg_start + seg_size, segname, 'CODE')

    print 'Patching database...'
    seg_ptr = seg_start
    for ea, new_name in call_table.items():
        if idc.LocByName(new_name) != idc.BADADDR:
            offset = idc.LocByName(new_name) - ea
        else:
            # create code and name it
            idc.PatchDword(seg_ptr, 0xE12FFF1E) # BX LR
            idc.MakeName(seg_ptr, new_name)
            idc.MakeCode(seg_ptr)
            idc.MakeFunction(seg_ptr, seg_ptr + 4)
            idc.MakeRptCmt(seg_ptr, new_name)
            offset = seg_ptr - ea
            seg_ptr += 4

        # patch the msgsend call
        if idc.GetReg(ea, "T") == 1:
            if offset > 0 and offset & 0xFF800000:
                print 'Offset too far for Thumb (%08x) Stopping [%08x]' % (offset, ea)
                return

            off1 = (offset & 0x7FF000) >> 12
            off2 = (offset & 0xFFF) / 2
            w1 = (0xF000 | off1)
            w2 = (0xE800 | off2) - 1
            idc.PatchWord(ea, w1)
            idc.PatchWord(ea + 2, w2)
        else:
            if offset > 0 and offset & 0xFF000000:
                print 'Offset too far (%08x) Stopping [%08x]' % (offset, ea)
            dw = (0xFA000000 | (offset - 8 >> 2))
            if dw < 0:
                dw = dw & 0xFAFFFFFF
            idc.PatchDword(ea, dw)
Example #18
0
    def load_one_file(li, options, idx, basename=None):
        bypass_plt = OPT_BYPASS_PLT in options

        f = load_nxo(li)

        if idx == 0:
            if f.armv7:
                idc.SetShortPrm(idc.INF_LFLAGS, idc.GetShortPrm(idc.INF_LFLAGS) | idc.LFLG_PC_FLAT)
            else:
                idc.SetShortPrm(idc.INF_LFLAGS, idc.GetShortPrm(idc.INF_LFLAGS) | idc.LFLG_64BIT)

            idc.SetCharPrm(idc.INF_DEMNAMES, idaapi.DEMNAM_GCC3)
            idaapi.set_compiler_id(idaapi.COMP_GNU)
            idaapi.add_til2('gnulnx_arm' if f.armv7 else 'gnulnx_arm64', 1)
            # don't create tails
            idc.set_inf_attr(idc.INF_AF, idc.get_inf_attr(idc.INF_AF) & ~idc.AF_FTAIL)

        if OPT_LOAD_31_BIT in options:
            loadbase = 0x8000000
            step = 0x1000000
        elif f.armv7:
            loadbase = 0x60000000
            step = 0x10000000
        else:
            loadbase = 0x7100000000
            step = 0x100000000
        loadbase += idx * step

        f.binfile.seek(0)
        as_string = f.binfile.read(f.bssoff)
        idaapi.mem2base(as_string, loadbase)

        seg_prefix = basename if basename is not None else ''
        for start, end, name, kind in f.sections:
            if name.startswith('.got'):
                kind = 'CONST'
            idaapi.add_segm(0, loadbase+start, loadbase+end, seg_prefix+name, kind)
            segm = idaapi.get_segm_by_name(seg_prefix+name)
            if kind == 'CONST':
                segm.perm = idaapi.SEGPERM_READ
            elif kind == 'CODE':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC
            elif kind == 'DATA':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
            elif kind == 'BSS':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
            idaapi.update_segm(segm)
            idaapi.set_segm_addressing(segm, 1 if f.armv7 else 2)

        # do imports
        # TODO: can we make imports show up in "Imports" window?
        undef_count = 0
        for s in f.symbols:
            if not s.shndx and s.name:
                undef_count += 1
        last_ea = max(loadbase + end for start, end, name, kind in f.sections)
        undef_entry_size = 8
        undef_ea = ((last_ea + 0xFFF) & ~0xFFF) + undef_entry_size # plus 8 so we don't end up on the "end" symbol

        undef_seg = basename + '.UNDEF' if basename is not None else 'UNDEF'
        idaapi.add_segm(0, undef_ea, undef_ea+undef_count*undef_entry_size, undef_seg, 'XTRN')
        segm = idaapi.get_segm_by_name(undef_seg)
        segm.type = idaapi.SEG_XTRN
        idaapi.update_segm(segm)
        for i,s in enumerate(f.symbols):
            if not s.shndx and s.name:
                idc.MakeQword(undef_ea)
                idaapi.do_name_anyway(undef_ea, s.name)
                s.resolved = undef_ea
                undef_ea += undef_entry_size
            elif i != 0:
                assert s.shndx
                s.resolved = loadbase + s.value
                if s.name:
                    if s.type == STT_FUNC:
                        idaapi.add_entry(s.resolved, s.resolved, s.name, 0)
                    else:
                        idaapi.do_name_anyway(s.resolved, s.name)

            else:
                # NULL symbol
                s.resolved = 0

        funcs = set()
        for s in f.symbols:
            if s.name and s.shndx and s.value:
                if s.type == STT_FUNC:
                    funcs.add(loadbase+s.value)
                    symend = loadbase+s.value+s.size
                    if Dword(symend) != 0:
                        funcs.add(symend)

        got_name_lookup = {}
        for offset, r_type, sym, addend in f.relocations:
            target = offset + loadbase
            if r_type in (R_ARM_GLOB_DAT, R_ARM_JUMP_SLOT, R_ARM_ABS32):
                if not sym:
                    print 'error: relocation at %X failed' % target
                else:
                    idaapi.put_long(target, sym.resolved)
            elif r_type == R_ARM_RELATIVE:
                idaapi.put_long(target, idaapi.get_long(target) + loadbase)
            elif r_type in (R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT, R_AARCH64_ABS64):
                idaapi.put_qword(target, sym.resolved + addend)
                if addend == 0:
                    got_name_lookup[offset] = sym.name
            elif r_type == R_AARCH64_RELATIVE:
                idaapi.put_qword(target, loadbase + addend)
                if addend < f.textsize:
                    funcs.add(loadbase + addend)
            else:
                print 'TODO r_type %d' % (r_type,)
            ida_make_offset(f, target)

        for func, target in f.plt_entries:
            if target in got_name_lookup:
                addr = loadbase + func
                funcs.add(addr)
                idaapi.do_name_anyway(addr, got_name_lookup[target])

        if not f.armv7:
            funcs |= find_bl_targets(loadbase, loadbase+f.textsize)

            if bypass_plt:
                plt_lookup = f.plt_lookup
                for pco in xrange(0, f.textsize, 4):
                    pc = loadbase + pco
                    d = Dword(pc)
                    if (d & 0x7c000000) == (0x94000000 & 0x7c000000):
                        imm = d & 0x3ffffff
                        if imm & 0x2000000:
                            imm |= ~0x1ffffff
                        if 0 <= imm <= 2:
                            continue
                        target = (pc + imm * 4) - loadbase
                        if target in plt_lookup:
                            new_target = plt_lookup[target] + loadbase
                            new_instr = (d & ~0x3ffffff) | (((new_target - pc) / 4) & 0x3ffffff)
                            idaapi.put_long(pc, new_instr)

            for pco in xrange(0, f.textsize, 4):
                pc = loadbase + pco
                d = Dword(pc)
                if d == 0x14000001:
                    funcs.add(pc + 4)

        for pc, _ in f.eh_table:
            funcs.add(loadbase + pc)

        for addr in sorted(funcs, reverse=True):
            idaapi.auto_make_proc(addr)

        return 1
Example #19
0
    def go(self):
        print "0) Building cache..."
        self.load_nids()

        # Vita is ARM
        idaapi.set_processor_type("arm", idaapi.SETPROC_ALL | idaapi.SETPROC_FATAL)
        
        # Set compiler info
        cinfo = idaapi.compiler_info_t()
        cinfo.id = idaapi.COMP_GNU
        cinfo.cm = idaapi.CM_CC_CDECL | idaapi.CM_N32_F48
        cinfo.size_s = 2
        cinfo.size_i = cinfo.size_b = cinfo.size_e = cinfo.size_l = cinfo.defalign = 4
        cinfo.size_ll = cinfo.size_ldbl = 8
        idaapi.set_compiler(cinfo, 0)

        # Import types
        self.import_types()
        self.load_proto()

        print "1) Loading ELF segments"
        self.fin.seek(0)
        header = Ehdr(self.fin.read(Ehdr.SIZE))

        self.fin.seek(header.e_phoff)
        phdrs = [Phdr(self.fin.read(header.e_phentsize)) for _ in xrange(header.e_phnum)]
        phdr_text = phdrs[0]

        for phdr in phdrs:
            if phdr.p_type == Phdr.PT_LOAD:
                idaapi.add_segm(0, phdr.p_vaddr, phdr.p_vaddr + phdr.p_memsz,
                                ".text" if phdr.x else ".data",
                                "CODE" if phdr.x else "DATA")
                seg = idaapi.getseg(phdr.p_vaddr)
                if phdr.x:
                    seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ
                    phdr_text = phdr
                else:
                    seg.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
                self.fin.file2base(phdr.p_offset, phdr.p_vaddr, phdr.p_vaddr + phdr.p_filesz, 1)

        if header.e_type == Ehdr.ET_SCE_EXEC:
            self.phdr_modinfo = phdr_text
            modinfo_off = phdr_text.p_offset + header.e_entry
        else:
            self.phdr_modinfo = phdrs[(header.e_entry & (0b11 << 30)) >> 30]
            modinfo_off = self.phdr_modinfo.p_offset + (header.e_entry & 0x3FFFFFFF)

        self.fin.seek(modinfo_off)
        modinfo = SceModuleInfo(self.fin.read(SceModuleInfo.SIZE))
        modinfo_ea = idaapi.get_fileregion_ea(modinfo_off)
        apply_struct(modinfo_ea, SceModuleInfo._find_or_create_struct())
        
        print ""
        print "   Module:  " + str(modinfo.name)
        print "   NID:     0x{:08X}".format(modinfo.nid)
        print ""

        print "2) Parsing export tables"
        self.parse_impexp(modinfo.export_top, modinfo.export_end, SceModuleExports, self.cb_exp)

        print "3) Parsing import tables"
        self.parse_impexp(modinfo.import_top, modinfo.import_end, SceModuleImports, self.cb_imp)

        print "4) Waiting for IDA to analyze the program"
        idc.Wait()

        print "5) Analyzing system instructions"
        from highlight_arm_system_insn import run_script
        run_script()

        print "6) Adding MOVT/MOVW pair xrefs"
        add_xrefs()
Example #20
0
    def load_file(li, neflags, format):
        idaapi.set_processor_type("arm",
                                  idaapi.SETPROC_ALL | idaapi.SETPROC_FATAL)
        f = load_nxo(li)
        if f.armv7:
            SetShortPrm(INF_LFLAGS, GetShortPrm(INF_LFLAGS) | LFLG_PC_FLAT)
        else:
            SetShortPrm(INF_LFLAGS, GetShortPrm(INF_LFLAGS) | LFLG_64BIT)

        SetCharPrm(INF_DEMNAMES, idaapi.DEMNAM_GCC3)
        idaapi.set_compiler_id(idaapi.COMP_GNU)
        idaapi.add_til2('gnulnx_arm' if f.armv7 else 'gnulnx_arm64', 1)

        loadbase = 0x60000000 if f.armv7 else 0x7100000000

        f.binfile.seek(0)
        as_string = f.binfile.read(f.bssoff)
        idaapi.mem2base(as_string, loadbase)
        if f.text[1] != None:
            li.file2base(f.text[1], loadbase + f.text[2],
                         loadbase + f.text[2] + f.text[3], True)
        if f.ro[1] != None:
            li.file2base(f.ro[1], loadbase + f.ro[2],
                         loadbase + f.ro[2] + f.ro[3], True)
        if f.data[1] != None:
            li.file2base(f.data[1], loadbase + f.data[2],
                         loadbase + f.data[2] + f.data[3], True)

        for start, end, name, kind in f.sections:
            if name.startswith('.got'):
                kind = 'CONST'
            idaapi.add_segm(0, loadbase + start, loadbase + end, name, kind)
            segm = idaapi.get_segm_by_name(name)
            if kind == 'CONST':
                segm.perm = idaapi.SEGPERM_READ
            elif kind == 'CODE':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC
            elif kind == 'DATA':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
            elif kind == 'BSS':
                segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
            idaapi.update_segm(segm)
            idaapi.set_segm_addressing(segm, 1 if f.armv7 else 2)

        # do imports
        # TODO: can we make imports show up in "Imports" window?
        undef_count = 0
        for s in f.symbols:
            if not s.shndx and s.name:
                undef_count += 1
        last_ea = max(loadbase + end for start, end, name, kind in f.sections)
        undef_entry_size = 8
        undef_ea = (
            (last_ea + 0xFFF) & ~0xFFF
        ) + undef_entry_size  # plus 8 so we don't end up on the "end" symbol
        idaapi.add_segm(0, undef_ea, undef_ea + undef_count * undef_entry_size,
                        "UNDEF", "XTRN")
        segm = idaapi.get_segm_by_name("UNDEF")
        segm.type = idaapi.SEG_XTRN
        idaapi.update_segm(segm)
        for i, s in enumerate(f.symbols):
            if not s.shndx and s.name:
                MakeQword(undef_ea)
                idaapi.do_name_anyway(undef_ea, s.name)
                s.resolved = undef_ea
                undef_ea += undef_entry_size
            elif i != 0:
                assert s.shndx
                s.resolved = loadbase + s.value
                if s.name:
                    if s.type == STT_FUNC:
                        print hex(s.resolved), s.name
                        idaapi.add_entry(s.resolved, s.resolved, s.name, 0)
                    else:
                        idaapi.do_name_anyway(s.resolved, s.name)

            else:
                # NULL symbol
                s.resolved = 0

        funcs = set()
        for s in f.symbols:
            if s.name and s.shndx and s.value:
                if s.type == STT_FUNC:
                    funcs.add(loadbase + s.value)

        got_name_lookup = {}
        for offset, r_type, sym, addend in f.relocations:
            target = offset + loadbase
            if r_type in (R_ARM_GLOB_DAT, R_ARM_JUMP_SLOT, R_ARM_ABS32):
                if not sym:
                    print 'error: relocation at %X failed' % target
                else:
                    idaapi.put_long(target, sym.resolved)
            elif r_type == R_ARM_RELATIVE:
                idaapi.put_long(target, idaapi.get_long(target) + loadbase)
            elif r_type in (R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT,
                            R_AARCH64_ABS64):
                idaapi.put_qword(target, sym.resolved + addend)
                if addend == 0:
                    got_name_lookup[offset] = sym.name
            elif r_type == R_AARCH64_RELATIVE:
                idaapi.put_qword(target, loadbase + addend)
                if addend < f.textsize:
                    funcs.add(loadbase + addend)
            else:
                print 'TODO r_type %d' % (r_type, )
            ida_make_offset(f, target)

        for func, target in f.plt_entries:
            if target in got_name_lookup:
                addr = loadbase + func
                funcs.add(addr)
                idaapi.do_name_anyway(addr, got_name_lookup[target])

        funcs |= find_bl_targets(loadbase, loadbase + f.textsize)

        for addr in sorted(funcs, reverse=True):
            AutoMark(addr, AU_CODE)
            AutoMark(addr, AU_PROC)

        return 1
Example #21
0
    def create_segments(self, li):
        li.seek(0x800)

        code = li.read(self.rom_size)

        idaapi.add_segm(0, 0x80000000, self.rom_addr, 'RAM', 'DATA')
        idc.set_default_sreg_value(0x80000000, 'ds', 0)
        seg = idaapi.getseg(0x80000000)
        seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE

        idaapi.mem2base(code, self.rom_addr, 0x800)
        idaapi.add_segm(0, self.rom_addr, self.rom_addr + self.rom_size, 'CODE', 'CODE')
        idc.set_default_sreg_value(self.rom_addr, 'ds', 0)
        seg = idaapi.getseg(self.rom_addr)
        seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE

        if self.data_addr != 0:
            idaapi.add_segm(0, self.data_addr, self.data_addr + self.data_size, '.data', 'DATA')
            idc.set_default_sreg_value(self.data_addr, 'ds', 0)
            seg = idaapi.getseg(self.data_addr)
            seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE

        if self.bss_addr != 0:
            idaapi.add_segm(0, self.bss_addr, self.bss_addr + self.bss_size, '.bss', 'BSS')
            idc.set_default_sreg_value(self.bss_addr, 'ds', 0)
            seg = idaapi.getseg(self.bss_addr)
            seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE

        idaapi.add_segm(0, self.rom_addr + self.rom_size, 0x80200000, 'RAM', 'DATA')
        idc.set_default_sreg_value(self.rom_addr + self.rom_size, 'ds', 0)
        seg = idaapi.getseg(self.rom_addr + self.rom_size)
        seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE

        idaapi.add_segm(0, 0x1F800000, 0x1F800400, 'CACHE', 'DATA')
        idaapi.add_segm(0, 0x1F800400, 0x1F801000, 'UNK1', 'XTRN')

        self.add_mem_ctrl1()
        self.add_mem_ctrl2()
        self.add_periph_io()
        self.add_int_ctrl()
        self.add_dma()
        self.add_timers()
        self.add_cdrom_regs()
        self.add_gpu_regs()
        self.add_mdec_regs()
        self.add_spu_voices()
        self.add_spu_ctrl_regs()
        self.create_got_fix()

        idaapi.cvar.inf.start_ss = idaapi.cvar.inf.start_cs = 0
        idaapi.cvar.inf.start_ip = idaapi.cvar.inf.start_ea = self.init_pc
        idaapi.cvar.inf.start_sp = self.sp_base + self.sp_offset
Example #22
0
def load_file(f, neflags, format):
    '''
    load the given file into the current IDA Pro database.

    Args:
      f (file): the file-like object to load.
      neflags (Any): unused
      format (Any): unused

    Returns:
      int: 1 on success, 0 on failure
    '''

    # compute file size, then read the entire contents
    f.seek(0x0, os.SEEK_END)
    flen = f.tell()
    f.seek(0x0)
    buf = f.read(flen)

    # mark the proc type, so IDA can invoke the correct disassembler/processor.
    # this must match `processor.wasm_processor_t.psnames`
    idaapi.set_processor_type('wasm', idaapi.SETPROC_ALL)

    f.seek(0x0)
    # load the entire file directly at address zero.
    f.file2base(0, 0, len(buf), True)

    p = 0
    sections = wasm.decode.decode_module(buf)
    for i, section in enumerate(sections):
        if i == 0:
            sname = 'header'
        else:
            if section.data.id == 0:
                # fetch custom name
                sname = ''
            else:
                sname = idawasm.const.WASM_SECTION_NAMES.get(
                    section.data.id, 'unknown')

        if sname != 'header' and section.data.id in (
                wasm.wasmtypes.SEC_CODE, wasm.wasmtypes.SEC_GLOBAL):
            stype = 'CODE'
        else:
            stype = 'DATA'

        # add IDA segment with type, name, size as appropriate
        slen = sum(section.data.get_decoder_meta()['lengths'].values())
        idaapi.add_segm(0, p, p + slen, sname, stype)

        if sname != 'header':
            loader = SECTION_LOADERS.get(section.data.id)
            if loader is not None:
                loader(section, p)

            load_section(section, p)

        p += slen

    # magic
    idc.MakeDword(0x0)
    idc.MakeName(0x0, 'WASM_MAGIC')
    # version
    idc.MakeDword(0x4)
    idc.MakeName(0x4, 'WASM_VERSION')

    return 1
def load_file(f, neflags, format):
    
    print('# PS4 Kernel Loader')
    ps = Binary(f)
    
    # PS4 Processor, Compiler, Library
    bitness = ps.procomp('metapc', CM_N64 | CM_M_NN | CM_CC_FASTCALL, 'gnulnx_x64')
    
    # Segment Loading...
    for segm in ps.E_SEGMENTS:
        if segm.name() == 'PHDR':
            kASLR = False if segm.FILE_SIZE == 0x118 else True
        
        # Process Loadable Segments...
        if segm.name() in ['CODE', 'DATA', 'SCE_RELRO']:
            address = segm.MEM_ADDR
            size = segm.MEM_SIZE
            
            # Dumped Kernel Fix-ups
            if segm.name() in ['DATA', 'SCE_RELRO'] and (idaapi.get_segm_by_name('CODE').start_ea != 0xFFFFFFFF82200000 or not kASLR):
                offset = address - idaapi.get_segm_by_name('CODE').start_ea
                dumped = segm.MEM_SIZE
            else:
                offset = segm.OFFSET
                dumped = segm.FILE_SIZE
            
            print('# Creating %s Segment...' % segm.name())
            f.file2base(offset, address, address + dumped, FILEREG_PATCHABLE)
            
            idaapi.add_segm(0, address, address + size, segm.name(), segm.type(), ADDSEG_NOTRUNC | ADDSEG_FILLGAP)
            
            # Processor Specific Segment Details
            idc.set_segm_addressing(address, bitness)
            idc.set_segm_alignment(address, segm.alignment())
            idc.set_segm_attr(address, SEGATTR_PERM, segm.flags())
        
        # Process Dynamic Segment...
        elif segm.name() == 'DYNAMIC':
            code = idaapi.get_segm_by_name('CODE')
            data = idaapi.get_segm_by_name('DATA')
            relro = idaapi.get_segm_by_name('SCE_RELRO')
            
            # ------------------------------------------------------------------------------------------------------------
            # Dynamic Tag Entry Structure
            members = [('tag', 'Tag', 0x8),
                       ('value', 'Value', 0x8)]
            struct = segm.struct('Tag', members)
            
            # Dynamic Tag Table
            stubs = {}
            modules = {}
            location = segm.MEM_ADDR
            
            # Dumps are offset by a small amount
            if code.start_ea != 0xFFFFFFFF82200000:
                dumped = code.start_ea - 0xFFFFFFFF82200000
            else:
                dumped = 0
            
            f.seek(location - code.start_ea)
            for entry in xrange(segm.MEM_SIZE / 0x10):
                idaapi.create_struct(location + (entry * 0x10), 0x10, struct)
                idc.set_cmt(location + (entry * 0x10), Dynamic(f).process(dumped, stubs, modules), False)
            
            # ------------------------------------------------------------------------------------------------------------
            # Hash Entry Structure
            members = [('bucket', 'Bucket', 0x2),
                       ('chain', 'Chain', 0x2),
                       ('buckets', 'Buckets', 0x2),
                       ('chains', 'Chains', 0x2)]
            struct = segm.struct('Hash', members)
            
            # Hash Table
            try:
                location = Dynamic.HASHTAB
                size = Dynamic.HASHTABSZ
            
            except:
                location = Dynamic.HASH
                size = Dynamic.SYMTAB - location
            
            f.seek(location - code.start_ea)
            for entry in xrange(size / 0x8):
                idaapi.create_struct(location + (entry * 0x8), 0x8, struct)
            
            if kASLR:
                # --------------------------------------------------------------------------------------------------------
                # Relocation Entry Structure (with specific addends)
                members = [('offset', 'Offset (String Index)', 0x8),
                           ('info', 'Info (Symbol Index : Relocation Code)', 0x8),
                           ('addend', 'AddEnd', 0x8)]
                struct = segm.struct('Relocation', members)
                
                # Relocation Table (with specific addends)
                location = Dynamic.RELATAB
                
                f.seek(location - code.start_ea)
                for entry in xrange(Dynamic.RELATABSZ / 0x18):
                    idaapi.create_struct(location + (entry * 0x18), 0x18, struct)
                    idc.set_cmt(location + (entry * 0x18), Relocation(f).process(dumped, code.end_ea), False)
                
                # Initialization Function
                idc.add_entry(Dynamic.INIT, Dynamic.INIT, '.init', True)
            
            else:
                # --------------------------------------------------------------------------------------------------------
                # Symbol Entry Structure
                members = [('name', 'Name (String Index)', 0x4),
                           ('info', 'Info (Binding : Type)', 0x1),
                           ('other', 'Other', 0x1),
                           ('shtndx', 'Section Index', 0x2),
                           ('offset', 'Value', 0x8),
                           ('size', 'Size', 0x8)]
                struct = segm.struct('Symbol', members)
                
                # Symbol Table
                location = Dynamic.SYMTAB
                f.seek(location - code.start_ea)
                functions = {}
                
                # .symtab
                idc.add_entry(location, location, '.symtab', False)
                
                for entry in xrange((Dynamic.STRTAB - location) / 0x18):
                    idaapi.create_struct(location + (entry * 0x18), 0x18, struct)
                    idc.set_cmt(location + (entry * 0x18), Symbol(f).process(functions), False)
                
                # --------------------------------------------------------------------------------------------------------
                # Dynamic String Table
                location = Dynamic.STRTAB
                
                # .strtab
                idc.add_entry(location, location, '.strtab', False)
                
                # Functions
                for key in functions:
                    idc.create_strlit(location + key, BADADDR)
                    functions[key] = idc.get_strlit_contents(location + key, BADADDR)
                    idc.set_cmt(location + key, 'Function', False)
                
                functions = sorted(functions.iteritems(), key = operator.itemgetter(0))
                #print('Functions: %s' % functions)
                
                # Resolve Functions
                location = Dynamic.SYMTAB
                f.seek(location - code.start_ea + 0x18)
                
                for entry in xrange((Dynamic.STRTAB - location - 0x18) / 0x18):
                    Symbol(f).resolve(functions[entry][1])
    
    # Fix-up
    if kASLR:
        address = relro.start_ea
        del_items(address, DELIT_SIMPLE, relro.end_ea - address)
        
        while address < relro.end_ea:
            create_data(address, FF_QWORD, 0x8, BADNODE)
            address += 0x8
    
    address = code.start_ea
    
    # ELF Header Structure
    members = [('File format', 0x4),
               ('File class', 0x1),
               ('Data encoding', 0x1),
               ('File version', 0x1),
               ('OS/ABI', 0x1),
               ('ABI version', 0x1),
               ('Padding', 0x7),
               ('File type', 0x2),
               ('Machine', 0x2),
               ('File version', 0x4),
               ('Entry point', 0x8),
               ('PHT file offset', 0x8),
               ('SHT file offset', 0x8),
               ('Processor-specific flags', 0x4),
               ('ELF header size', 0x2),
               ('PHT entry size', 0x2),
               ('Number of entries in PHT', 0x2),
               ('SHT entry size', 0x2),
               ('Number of entries in SHT', 0x2),
               ('SHT entry index for string table\n', 0x2)]
    
    for (comment, size) in members:
        flags = idaapi.get_flags_by_size(size)
        idc.create_data(address, flags if flags != 0 else FF_STRLIT, size, BADNODE)
        idc.set_cmt(address, comment, False)
        address += size
    
    for index, entry in enumerate(ps.E_SEGMENTS):
        # ELF Program Header Structure
        members = [('Type: %s' % entry.name(), 0x4),
                   ('Flags', 0x4),
                   ('File offset', 0x8),
                   ('Virtual address', 0x8),
                   ('Physical address', 0x8),
                   ('Size in file image', 0x8),
                   ('Size in memory image', 0x8),
                   ('Alignment\n', 0x8)]
        
        for (comment, size) in members:
            flags = idaapi.get_flags_by_size(size)
            
            idc.create_data(address, flags if flags != 0 else FF_STRLIT, size, BADNODE)
            idc.set_cmt(address, comment, False)
            address += size
    
    # Wait for the AutoAnalyzer to Complete...
    print('# Waiting for the AutoAnalyzer to Complete...')
    idaapi.auto_wait()
    
    if kASLR:
        # Start Function
        idc.add_entry(ps.E_START_ADDR, ps.E_START_ADDR, 'start', True)
        
        # Xfast_syscall
        address = idaapi.find_binary(code.start_ea, code.end_ea, '0F 01 F8 65 48 89 24 25 A8 02 00 00 65 48 8B 24', 0x10, SEARCH_DOWN)
        idaapi.do_unknown(address, 0)
        idaapi.create_insn(address)
        idaapi.add_func(address, BADADDR)
        idaapi.set_name(address, 'Xfast_syscall', SN_NOCHECK | SN_NOWARN)
        
        # --------------------------------------------------------------------------------------------------------
        # Znullptr's syscalls
        print('# Processing Znullptr\'s Syscalls...')
        
        # Syscall Entry Structure
        members = [('narg', 'Number of Arguments', 0x4),
                   ('_pad', 'Padding', 0x4),
                   ('function', 'Function', 0x8),
                   ('auevent', 'Augmented Event?', 0x2),
                   ('_pad1', 'Padding', 0x2),
                   ('_pad2', 'Padding', 0x4),
                   ('trace_args_func', 'Trace Arguments Function', 0x8),
                   ('entry', 'Entry', 0x4),
                   ('return', 'Return', 0x4),
                   ('flags', 'Flags', 0x4),
                   ('thrcnt', 'Thread Count?', 0x4)]
        struct = segm.struct('Syscall', members)
        
        znullptr(code.start_ea, code.end_ea, '4F 52 42 49 53 20 6B 65 72 6E 65 6C 20 53 45 4C 46', struct)
        
        # --------------------------------------------------------------------------------------------------------
        # Chendo's cdevsw con-struct-or
        print('# Processing Chendo\'s cdevsw structs...')
        
        # cdevsw Entry Structure
        members = [('d_version', 'Version', 0x4),
                   ('d_flags', 'Flags', 0x4),
                   ('d_name', 'Name', 0x8),
                   ('d_open', 'Open', 0x8),
                   ('d_fdopen', 'File Descriptor Open', 0x8),
                   ('d_close', 'Close', 0x8),
                   ('d_read', 'Read', 0x8),
                   ('d_write', 'Write', 0x8),
                   ('d_ioctl', 'Input/Ouput Control', 0x8),
                   ('d_poll', 'Poll', 0x8),
                   ('d_mmap', 'Memory Mapping', 0x8),
                   ('d_strategy', 'Strategy', 0x8),
                   ('d_dump', 'Dump', 0x8),
                   ('d_kqfilter', 'KQFilter', 0x8),
                   ('d_purge', 'Purge', 0x8),
                   ('d_mmap_single', 'Single Memory Mapping', 0x8),
                   ('d_spare0', 'Spare0', 0x8),
                   ('d_spare1', 'Spare1', 0x8),
                   ('d_spare2', 'Spare2', 0x8),
                   ('d_spare3', 'Spare3', 0x8),
                   ('d_spare4', 'Spare4', 0x8),
                   ('d_spare5', 'Spare5', 0x8),
                   ('d_spare6', 'Spare6', 0x4),
                   ('d_spare7', 'Spare7', 0x4)]
        struct = segm.struct('cdevsw', members)
        
        chendo(data.start_ea, data.end_ea, '09 20 12 17', struct)
    
    # --------------------------------------------------------------------------------------------------------
    # Pablo's IDC
    try:
        print('# Processing Pablo\'s Push IDC...')
        
        # Script 1) Push it real good...
        pablo(code.start_ea, code.end_ea, 'C5 FA 5A C0 C5 F2 5A C9 C5 EA 5A D2 C5 FB 59 C1')
        pablo(code.start_ea, code.end_ea, 'C5 F9 7E C0 31 C9')
        pablo(code.start_ea, code.end_ea, '48 89 E0 55 53')
        pablo(code.start_ea, code.end_ea, 'B8 2D 00 00 00 C3')
        pablo(code.start_ea, code.end_ea, '31 C0 C3')
        pablo(code.start_ea, code.end_ea, '55 48 89')
        pablo(code.start_ea, code.end_ea, '48 81 EC A0 00 00 00 C7')
        pablo(code.start_ea, code.end_ea, '48 81 EC A8 00 00 00')
        
        # Script 2) Fix-up Dumped Data Pointers...
        if dumped or not kASLR:
            print('# Processing Pablo\'s Dumped Data Pointers IDC...')
            pablo(data.start_ea, data.end_ea, '?? FF FF FF FF')
    
    except:
        pass
    
    # --------------------------------------------------------------------------------------------------------
    # Kiwidog's __stack_chk_fail
    if kASLR:
        print('# Processing Kiwidog\'s Stack Functions...')
        
        kiwidog(code.start_ea, code.end_ea, '73 74 61 63 6B 20 6F 76 65 72 66 6C 6F 77 20 64 65 74 65 63 74 65 64 3B')
    
    # --------------------------------------------------------------------------------------------------------
    # Final Pass
    print('# Performing Final Pass...')
    address = code.start_ea
    while address < code.end_ea:
        address = idaapi.find_not_func(address, SEARCH_DOWN)
        
        if idaapi.isUnknown(idaapi.getFlags(address)):
            idaapi.create_insn(address)
        else:
            idc.add_func(address)
        
        address += 4
    
    print('# Done!')
    return 1
Example #24
0
def load_file(li, neflags, format):

    # Read in the bFLT header fields
    li.seek(0)
    (magic, version, entry, data_start, data_end, bss_end, stack_size,
     reloc_start, reloc_count, flags) = struct.unpack(">IIIIIIIIII",
                                                      li.read(4 * 10))

    # Check for the GZIP flag.
    # The loader doesn't de-compress GZIP'd files, as these can be easily decompressed with external tools prior to loading the file into IDA
    if (flags & FLAGS_GZIP) == FLAGS_GZIP:
        Warning(
            "Code/data is GZIP compressed. You probably want to decompress the bFLT file with the flthdr or gunzip_bflt utilities before loading it into IDA."
        )

    # Load the file data into IDA
    li.file2base(BFLT_HEADER_SIZE, BFLT_HEADER_SIZE, data_end, True)

    # Add the .text .data and .bss segments
    idaapi.add_segm(0, BFLT_HEADER_SIZE, data_start, ".text", "CODE")
    idaapi.add_segm(0, data_start, data_end, ".data", "DATA")
    idaapi.add_segm(0, data_end, bss_end, ".bss", "BSS")

    if DEBUG:
        print "Created File Segments: "
        print "\t.text   0x%.8X - 0x%.8X" % (BFLT_HEADER_SIZE, data_start)
        print "\t.data   0x%.8X - 0x%.8X" % (data_start, data_end)
        print "\t.bss    0x%.8X - 0x%.8X" % (data_end, bss_end)

    # Entry point is at the beginning of the .text section
    idaapi.add_entry(entry, entry, "_start", 1)

    # Set default processor
    idaapi.set_processor_type(DEFAULT_CPU, SETPROC_ALL)

    # Explicitly set 32 bit addressing on .text segment
    idaapi.set_segm_addressing(idaapi.getseg(entry), 1)

    # prepare structure for set_fixup()
    fd = idaapi.fixup_data_t()
    fd.type = idaapi.FIXUP_OFF32

    # Is there a global offset table?
    if (flags & FLAGS_GOTPIC) == FLAGS_GOTPIC:

        # Add a reptable comment and name the offset so that all references to GOT are obvious
        MakeRptCmt(data_start, "GLOBAL_OFFSET_TABLE")
        MakeName(data_start, "GOT")

        if DEBUG:
            print "Global Offset Table detected, patching..."

        # GOT starts at the beginning of the data section; loop through the data section, patching up valid GOT entries.
        i = data_start
        while i < data_end:

            # Get the next GOT entry
            li.seek(i)
            got_entry = struct.unpack("<I", li.read(4))[0]

            # The last GOT entry is -1
            if got_entry == 0xFFFFFFFF:
                if DEBUG:
                    print "Finished processing Global Offset Table."
                break

            # All other non-zero entries are valid GOT entries
            elif got_entry > 0:

                # The actual data is located at <original GOT entry> + <BFLT_HEADER_SIZE>
                new_entry = got_entry + BFLT_HEADER_SIZE

                if DEBUG:
                    print "Replacing GOT entry value 0x%.8X with 0x%.8X at offset 0x%.8X" % (
                        got_entry, new_entry, i)

                # Replace the GOT entry with the correct pointer
                idaapi.put_long(i, new_entry)
                # add info about relocation to help analyzer
                fd.off = new_entry
                idaapi.set_fixup(i, fd)

            # Make each GOT entry a DWORD
            MakeDword(i)

            # Point i at the next GOT entry address
            i = i + 4

    # Patch relocation addresses
    for i in range(0, reloc_count):
        try:
            # Get the next relocation entry.
            # Relocation entry = <address of bytes to be patched> - <BFLT_HEADER_SIZE>
            li.seek(reloc_start + (i * 4))
            reloc_offset = struct.unpack(">I",
                                         li.read(4))[0] + BFLT_HEADER_SIZE

            # Sanity check, make sure the relocation offset is in a defined segment
            if reloc_offset < bss_end:
                try:
                    # reloc_offset + base_offset == <pointer to actual data> - <BFLT_HEADER_SIZE>
                    li.seek(reloc_offset)
                    reloc_val = struct.unpack(">I", li.read(4))[0]
                    if reloc_val == 0:
                        # skip zero relocs
                        # see fs/binfmt_flat.c
                        if DEBUG:
                            print "Skipping zero reloc at (0x%.8X)" % reloc_offset
                        continue

                    reloc_data_offset = reloc_val + BFLT_HEADER_SIZE

                    if DEBUG:
                        print "Patching reloc: (0x%.8X) == 0x%.8X" % (
                            reloc_offset, reloc_data_offset)

                    # Replace pointer at reloc_offset with the address of the actual data
                    idaapi.put_long(reloc_offset, reloc_data_offset)
                    # add info about relocation to help analyzer
                    fd.off = reloc_data_offset
                    idaapi.set_fixup(reloc_offset, fd)
                except Exception, e:
                    print "Error patching relocation entry #%d: %s" % (i,
                                                                       str(e))
            elif DEBUG:
                print "Relocation entry #%d outside of defined file sections, skipping..." % i
Example #25
0
def load_file(li, neflags, format):
    if format != "NeoGeo 68k loader":
        return 0

    idaapi.set_processor_type("68000", SETPROC_ALL | SETPROC_FATAL)

    idaapi.add_segm(0, 0x000000, 0x0FFFFF, "ROM", "CODE")
    idaapi.add_segm(0, 0x100000, 0x10F2FF, "WRAM", "DATA")
    idaapi.add_segm(0, 0x10F300, 0x10FFFF, "BIOSRAM", "DATA")
    idaapi.add_segm(0, 0x200000, 0x2FFFFF, "PORT", "DATA")
    idaapi.add_segm(0, 0x300000, 0x3FFFFF, "IO", "DATA")
    idaapi.add_segm(0, 0x400000, 0x401FFF, "PALETTES", "DATA")
    idaapi.add_segm(0, 0x800000, 0xBFFFFF, "MEMCARD", "DATA")
    idaapi.add_segm(0, 0xC00000, 0xC1FFFF, "SYSROM", "DATA")
    idaapi.add_segm(0, 0xD00000, 0xD0FFFF, "BRAM", "DATA")

    li.seek(0, 2)
    size = li.tell()
    li.seek(0)
    file_data = li.read(size)
    idaapi.mem2base(file_data, 0, 0x100000)

    name_long(0x000000, "InitSP")
    name_long(0x000004, "InitPC")

    idaapi.do_unknown(0x3C0000, 1)
    idaapi.doByte(0x3C0000, 1)
    idaapi.set_name(0x3C0000, "REG_VRAMADDR")
    #idaapi.set_cmt(0x3C0000, "Pouet.", 1)

    return 1
Example #26
0
def fix_callgraph(msgsend, segname, class_param, sel_param):
  '''
  fix_callgraph: msgsend, segname, class_param, sel_param

  Given the msgsend flavour address as a parameter, looks
  for the parameters (class and selector, identified by
  class_param and sel_param) and creates a new segment where
  it places a set of dummy calls named as classname_methodname
  (we use method instead of selector most of the time).
  '''

  t1 = time.time()
  if not msgsend:
    print 'ERROR: msgSend not found'
    return

  total = 0
  resolved = 0
  call_table = dict()


  for xref in idautils.XrefsTo(msgsend, idaapi.XREF_ALL):
    total += 1
    ea_call = xref.frm
    func_start = idc.GetFunctionAttr(ea_call, idc.FUNCATTR_START)
    if not func_start or func_start == idc.BADADDR:
      continue
    ea = ea_call

    method_name_ea = track_param(ea, func_start, idc.o_displ, sel_param)
    if method_name_ea:
      method_name = idc.GetString(method_name_ea, -1, idc.ASCSTR_C)
      if not method_name:
        method_name = ''
    else:
      method_name = ''

    class_name_ea = track_param(ea, func_start, idc.o_phrase, class_param)
    if class_name_ea:
      class_name = idc.GetString(class_name_ea, -1, idc.ASCSTR_C)
      if not class_name:
        class_name = ''
    else:
      class_name = ''

    if not method_name and not class_name:
      continue

    # Using this name convention, if the class and method
    # are identified by IDA, the patched call will point to
    # the REAL call and not one of our dummy functions
    #
    class_name = class_name.replace('_objc_class_name_', '')

    new_name = '_[' + class_name + '_' + method_name + ']'
    call_table[ea_call] = new_name
    resolved += 1

  print '\nFinal stats:\n\t%d total calls, %d resolved' % (total, resolved)
  print '\tAnalysis took %.2f seconds' % (time.time() - t1)

  if resolved == 0:
    print 'Nothing to patch.'
    return

  print 'Adding new segment to store new nullsubs'

  # segment size = opcode ret (4 bytes) * num_calls
  seg_size = resolved * 4
  seg_start = idc.MaxEA() + 4
  idaapi.add_segm(0, seg_start, seg_start + seg_size, segname, 'CODE')

  print 'Patching database...'
  seg_ptr = seg_start
  for ea, new_name in call_table.items():
    if idc.LocByName(new_name) != idc.BADADDR:
      offset = (idc.LocByName(new_name) - ea) & idc.BADADDR
    else:
      # create code and name it
      idc.PatchDword(seg_ptr, 0x90) # nop
      idc.MakeName(seg_ptr, new_name)
      idc.MakeCode(seg_ptr)
      idc.MakeFunction(seg_ptr, seg_ptr + 4)
      idc.MakeRptCmt(seg_ptr, new_name)
      offset = seg_ptr - ea
      seg_ptr += 4

    dw = offset - 5
    idc.PatchByte(ea, 0xE8)
    idc.PatchDword(ea + 1, dw)