Ejemplo n.º 1
0
def main():
    for segstart, segend, segname in enum_segments():
        if segname not in ('.rdata', 'UPX1'):
            continue

        print(segname)
        for src, dst, size in find_pointers(segstart, segend):
            if idc.get_segm_name(dst) not in (".text", "UPX0"):
                continue

            if is_code(dst):
                continue

            print("new function pointer: 0x%x -> 0x%x" % (src, dst))

            ida_auto.auto_make_code(dst)
            ida_auto.auto_make_proc(dst)

            ida_bytes.del_items(src, size)
            ida_bytes.create_data(src,
                                  idc.FF_QWORD if size == 8 else idc.FF_DWORD,
                                  size, idc.BADADDR)
            # this doesn't seem to always work :-(
            idc.op_plain_offset(src, -1, 0)
            ida_name.set_name(src, "j_%s_%x" % (src, dst))
Ejemplo n.º 2
0
def resolvePointers(fileRange, pointerRange, verbose=True):
    """

    :param fileRange: tuple of (int, int) representing the file to resolve pointers in
    :param pointerRange: tuple of (int, int) representing range of pointers to resolve
    :param verbose: if True, all changes are printed
    :return:
    """
    if verbose:
        print("(%07X, %07X): expand unknown arrays" %
              (fileRange[0], fileRange[1]))
    expandUnkArrays(*fileRange, verbose=False)

    ea = fileRange[0]
    while ea < fileRange[1]:
        ea = next.unkptr(ea, fileRange[1], rom=True, ui=False, hexOut=False)
        if ea != idaapi.BADADDR:
            # get data at ea
            chars = idc.get_bytes(ea, 4)
            dword = 0
            for i in range(len(chars)):
                dword += ord(chars[i]) << 8 * i

            if pointerRange[0] <= dword < pointerRange[1]:
                if verbose: print('%07X: %07X' % (ea, dword))
                idc.op_plain_offset(ea, 0, 0)
Ejemplo n.º 3
0
    def req_patch(self, hash):
        addr, value, length = hash['addr'], hash['value'], hash['len']
        if length != 4 and length != 8:
            print("[x] unsupported length: %d" % length)
            return

        if length == 4:
            prev_value = Dword(addr)
            if MakeDword(addr) != 1:
                print('[x] MakeDword failed')
            if PatchDword(addr, value) != 1:
                print('[x] PatchDword failed')
            if not idc.op_plain_offset(addr, 0, 0):
                print('[x] op_plain_offset failed')

        elif length == 8:
            prev_value = Qword(addr)
            if MakeQword(addr) != 1:
                print('[x] MakeQword failed')
            if PatchQword(addr, value) != 1:
                print('[x] PatchQword failed')
            if not idc.op_plain_offset(addr, 0, 0):
                print('[x] op_plain_offset failed')

        print("[*] patched 0x%x = 0x%x (previous was 0x%x)" % (addr, value, prev_value))
Ejemplo n.º 4
0
    def req_patch(self, hash):
        addr, value, length = hash['addr'], hash['value'], hash['len']

        if length == 4:
            prev_value = idc.get_wide_dword(addr)
            if not ida_bytes.create_data(ea, FF_DWORD, 4, ida_idaapi.BADADDR):
                rs_log('[x] ida_bytes.create_data FF_DWORD failed')
            if not ida_bytes.patch_dword(addr, value):
                rs_log('[x] patch_dword failed')
            if not idc.op_plain_offset(addr, 0, 0):
                rs_log('[x] op_plain_offset failed')

        elif length == 8:
            prev_value = idc.get_qword(addr)
            if not ida_bytes.create_data(addr, FF_QWORD, 8,
                                         ida_idaapi.BADADDR):
                rs_log('[x] ida_bytes.create_data FF_QWORD failed')
            if not ida_bytes.patch_qword(addr, value):
                rs_log('[x] patch_qword failed')
            if not idc.op_plain_offset(addr, 0, 0):
                rs_log('[x] op_plain_offset failed')

        else:
            rs_log("[x] unsupported length: %d" % length)
            return

        rs_log("patched 0x%x = 0x%x (previous was 0x%x)" %
               (addr, value, prev_value))
Ejemplo n.º 5
0
    def set_offset(self, base=0):
        """
            Set this operand as being an offset.

            .. todo:: this should be a setter on a property ?

            .. todo:: doc base arg
        """
        idc.op_plain_offset(self.instr.ea, self.opnum, base)
Ejemplo n.º 6
0
def convert_pointer_to_offset(ea):
    # If this is code, skip it.
    flags = idc.get_full_flags(ea)
    if idc.is_code(flags):
        return
    # If the value at this address does not point into the kernelcache, skip it.
    value = idc.get_qword(ea)
    if not is_mapped(value, 8):
        return
    # Convert this value to a qword (in case it's unaligned) and then convert it into an
    # offset.
    idc.create_qword(ea)
    idc.op_plain_offset(ea, 0, 0)
Ejemplo n.º 7
0
def convert_vtable_to_offsets(vtable, length=None):
    """Convert a vtable into a sequence of offsets.

    Arguments:
        vtable: The address of the virtual method table.

    Options:
        length: The length of the vtable, if known.

    Returns:
        True if the data was successfully converted into offsets.
    """
    if length is None:
        length = vtable_length(vtable)
    if not length:
        _log(0, 'Address {:#x} is not a vtable', vtable)
        return False
    successful = True
    for address in idau.Addresses(vtable, length=length, step=idau.WORD_SIZE):
        # Handle addresses that are part of ALIGN directives
        if idaapi.is_align_insn(address) != 0:
            head = idaapi.get_item_head(address)
            idaapi.del_items(head)
        if not idc.op_plain_offset(address, 0, 0):
            _log(0, 'Could not change address {:#x} into an offset', address)
            successful = False
    return successful
Ejemplo n.º 8
0
def _process_offset(offset, ea, next_offset):
    """Process an offset in a __got section."""
    # Convert the address containing the offset into an offset in IDA, but continue if it fails.
    if not idc.op_plain_offset(ea, 0, 0):
        _log(1, 'Could not convert {:#x} into an offset', ea)
    # Get the name to which the offset refers.
    name = idau.get_ea_name(offset, user=True)
    if not name:
        _log(3, 'Offset at address {:#x} has target {:#x} without a name', ea,
             offset)
        return False
    # Make sure this isn't an offset to another stub or to a jump function to another stub. See the
    # comment in _symbolicate_stub.
    if stub.symbol_references_stub(name):
        _log(
            1,
            'Offset at address {:#x} has target {:#x} (name {}) that references a stub',
            ea, offset, name)
        return False
    # Set the new name for the offset.
    symbol = next_offset(name)
    if symbol is None:
        _log(0, 'Could not generate offset symbol for {}: names exhausted',
             name)
        return False
    if not idau.set_ea_name(ea, symbol, auto=True):
        _log(2, 'Could not set name {} for offset at {:#x}', symbol, ea)
        return False
    return True
def main():
    for segstart, segend, segname in enum_segments():
        if segname not in ('.rdata', 'UPX1' ):
            continue

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

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

            if b"\x00" in buf:
                continue

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

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

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

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

            # size
            ida_bytes.del_items(src + psize, psize)
            ida_bytes.create_data(src + psize, idc.FF_QWORD if size == 8 else idc.FF_DWORD, psize, idc.BADADDR)
Ejemplo n.º 10
0
def initialize_data_offsets():
    """Convert offsets in data segments into offsets in IDA.

    Segment names must be initialized with segments.initialize_segments() first.
    """
    # Normally, for user-space programs, this operation would be dangerous because there's a good
    # chance that a valid userspace address would happen to show up in regular program data that is
    # not actually an address. However, since kernel addresses are numerically much larger, the
    # chance of this happening is much less.
    for seg in idautils.Segments():
        name = idc.get_segm_name(seg)
        if not (name.endswith('__DATA_CONST.__const') or name.endswith('__got')
                or name.endswith('__DATA.__data') or name.endswith('__DATA_CONST.__auth_ptr')):
            continue
        for word, ea in idau.ReadWords(seg, idc.get_segm_end(seg), addresses=True):
            if idau.is_mapped(word, value=False):
                idc.op_plain_offset(ea, 0, 0)
Ejemplo n.º 11
0
    def init_vtable(self):
        my_start_idx = self.vtable_start_idx()

        # Fix: support 64bit work
        if idc.__EA64__:
            pointer_size = idaapi.DEF_ADDRSIZE
            pfn_make_ptr = lambda x: ida_bytes.create_data(x, idc.FF_QWORD, 8, idaapi.BADADDR) #MakeQword
            pfn_get_ptr_value = ida_bytes.get_qword
        else:
            pointer_size = idaapi.DEF_ADDRSIZE
            pfn_make_ptr =  lambda x: ida_bytes.create_data(x, idc.FF_DWORD, 4, idaapi.BADADDR) #ida_bytes.MakeDword
            pfn_get_ptr_value = ida_bytes.get_dword

        for idx, ea in enumerate(range(self.vtable_start, self.vtable_end, pointer_size)):
            pfn_make_ptr(ea)
            idc.op_plain_offset(ea, 0, 0)
            dst = pfn_get_ptr_value(ea)

            if idx < my_start_idx:
                base_method = self.base.vmethods[idx]
                if base_method.is_dst_equal(dst):                   # Method from base class
                    self.vmethods.append(self.base.vmethods[idx])
                elif Method.s_is_pure_virtual_dst(dst):             # New pure virtual override
                    opvm = PureVirtualOverrideMethod(self, base_method, idx)
                    opvm.refresh()
                    self.vmethods.append(opvm)
                elif Method.s_is_deleted_virtual_dst(dst):          # New deleted override
                    dom = DeletedOverrideMethod(self, base_method, idx)
                    dom.refresh()
                    self.vmethods.append(dom)
                else:                                               # New override
                    om = OverrideMethod(dst, self, base_method, idx)
                    om.refresh()
                    self.vmethods.append(om)
            elif Method.s_is_pure_virtual_dst(dst):                 # New pure virtual
                pvm = PureVirtualMethod(self, 'vf%X' % (idx*4), idx)
                pvm.refresh()
                self.vmethods.append(pvm)
            elif Method.s_is_deleted_virtual_dst(dst):              # New deleted virtual
                pvm = DeletedVirtualMethod(self, 'vf%X' % (idx*4), idx)
                pvm.refresh()
                self.vmethods.append(pvm)
            else:                                                   # New virtual
                vm = VirtualMethod(dst, self, 'vf%X' % (idx*4), idx)
                vm.refresh()
                self.vmethods.append(vm)
Ejemplo n.º 12
0
def make_date_ref():
    ea = 0x9561C
    max_ea = ida_ida.inf_get_max_ea()
    min_ea = ida_ida.inf_get_min_ea()

    while True:
        ea = ida_search.find_unknown(ea, idc.SEARCH_DOWN | idc.SEARCH_NEXT)
        if ea > max_ea:
            break
        size = idc.get_item_size(ea)
        print(hex(ea))

        val = idc.get_wide_dword(ea)
        # if 0xfff38 < val < 0x188544 or 0x1f000000 < val < 0x1ffa3fd9 or 0x20000000 < val < 0x2001ffff:
        #     idc.OpOff(ea, 0, 0)
        if min_ea < val < max_ea:
            idc.op_plain_offset(ea, 0, 0)
Ejemplo n.º 13
0
def main():
    for segstart, segend, segname in enum_segments():
        if segname not in ('.text', '.data'):
            continue

        for src, dst in find_pointers(segstart, segend):
            if is_code(src):
                # ignore instructions like:
                #
                #     call    ds:__vbaGenerateBoundsError
                #print('code pointer: 0x%x -> 0x%x' % (src, dst))
                continue

            if is_in_string(src):
                # for example, the following contains 0x444974 (a common valid offset):
                #
                #     text:004245B0 aRequestid    db 'requestID',
                #
                # enable or disable this behavior as you wish
                print('string pointer: 0x%x -> 0x%x' % (src, dst))
                pass
                #continue

            print('pointer from 0x%x to 0x%x' % (src, dst))

            if is_unknown(dst):
                print('destination unknown, making byte: 0x%x' % (dst))
                ida_bytes.create_data(dst, FF_BYTE, 1, ida_idaapi.BADADDR)

            elif is_head(dst):
                # things are good
                pass

            else:
                # need to undefine head, and make byte
                head_va = get_head(dst)
                print('destination overlaps with head: 0x%x' % (head_va))
                ida_bytes.del_items(head_va, dst - head_va)
                ida_bytes.create_data(head_va, FF_BYTE, 1, ida_idaapi.BADADDR)
                ida_bytes.create_data(dst, FF_BYTE, 1, ida_idaapi.BADADDR)

            ida_bytes.del_items(src, 4)
            ida_bytes.create_data(src, FF_DWORD, 4, ida_idaapi.BADADDR)
            # this doesn't seem to always work :-(
            idc.op_plain_offset(src, -1, 0)
Ejemplo n.º 14
0
    def load(infos):
        insn = ida_ua.insn_t()

        for info in infos:
            # Find or create struct.
            struct_id = ida_struct.get_struc_id(info['name'])
            if struct_id == BADADDR:
                print('[IDA-Sync] Creating new struct %s.' % info['name'])
                struct_id = ida_struct.add_struc(info['idx'], info['name'])
            struct = ida_struct.get_struc(struct_id)

            ida_struct.set_struc_idx(struct, info['idx'])

            # Create struct members.
            for member in info['members']:
                ida_struct.add_struc_member(
                    struct,
                    member['name'],
                    member['offset'],
                    # flag
                    0,
                    # opinfo_t instance... maybe it should sometimes be
                    # something?
                    None,
                    member['size'],
                )

            # Create xrefs to members of the struct as offsets.
            for xref in info['xrefs']:
                typ = xref['type']

                # Offset xref.
                if typ == 1:
                    # TODO figure out what second argument does.
                    idc.op_plain_offset(xref['from'], 1, xref['offset'])

                # Read/write xrefs.
                elif typ in [2, 3]:
                    ida_ua.create_insn(xref['from'], insn)
                    idc.op_stroff(insn, 1, struct.id, 0)

                # TODO do the other cases come up?
                else:
                    pass
Ejemplo n.º 15
0
def convert_vtable_to_offsets(vtable, length=None):
    """Convert a vtable into a sequence of offsets.

    Arguments:
        vtable: The address of the virtual method table.

    Options:
        length: The length of the vtable, if known.

    Returns:
        True if the data was successfully converted into offsets.
    """
    if length is None:
        length = vtable_length(vtable)
    if not length:
        _log(0, 'Address {:#x} is not a vtable', vtable)
        return False
    successful = True
    for address in idau.Addresses(vtable, length=length, step=idau.WORD_SIZE):
        if not idc.op_plain_offset(address, 0, 0):
            _log(0, 'Could not change address {:#x} into an offset', address)
            successful = False
    return successful
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
Ejemplo n.º 17
0
def OpOffset(ea, base):
    return idc.op_plain_offset(ea, -1, base)
Ejemplo n.º 18
0
 def ida_make_offset(f, ea):
     if f.armv7:
         idaapi.create_data(ea, idc.FF_DWORD, 4, idaapi.BADADDR)
     else:
         idaapi.create_data(ea, idc.FF_QWORD, 8, idaapi.BADADDR)
     idc.op_plain_offset(ea, 0, 0)
Ejemplo n.º 19
0
def untag_pointer(ea, tp):
    _log(4, 'Untagging pointer at {:x}', ea)
    idau.patch_word(ea, tagged_pointer_untag(tp))
    idc.op_plain_offset(ea, 0, 0)
Ejemplo n.º 20
0
def sync_data_definitions_in(source_units, address_space, ea):
    from edit_source.include.definitions import DATA_TYPES
    def create_array_of(ea, count, size, op, error=False, verbose=False):
        ops.delete_items(ea, size)
        status = op(ea)
        if count != 1:
            status = idc.make_array(ea, count)
        if verbose:
            if status is False:
                print('error: {:07X}: failed to perform operation'.format(ea))
        if error:
            if status is False:
                raise Exception('{:07X}: failed to perform operation'.format(ea))
        return status

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

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