예제 #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)
예제 #2
0
def add_segment(start, size, name, kind):
    end = start + size
    idaapi.add_segm(0, start, 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
    elif kind == 'IO':
        segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE
    elif kind == 'RWX':
        segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC | idaapi.SEGPERM_WRITE
    idaapi.update_segm(segm)
    idaapi.set_segm_addressing(segm, 2)
예제 #3
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
예제 #4
0
파일: nxo64.py 프로젝트: Thog/swipc-gen
    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
예제 #5
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
예제 #6
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