Exemple #1
0
    def hook_intr(self, uc: Uc, intno, user_data):
        # self.debug_addr(uc.reg_read(UC_ARM_REG_PC) - 40, 40)
        if intno == 2:
            swi = from_bytes(uc.mem_read(uc.reg_read(UC_ARM_REG_PC) - 2, 1))
            r0 = uc.reg_read(UC_ARM_REG_R0)
            r1 = uc.reg_read(UC_ARM_REG_R1)
            r2 = uc.reg_read(UC_ARM_REG_R2)
            r3 = uc.reg_read(UC_ARM_REG_R3)

            if swi == 0:
                print("done?")
                print(intno, swi, ":", uc.reg_read(UC_ARM_REG_R0),
                      uc.reg_read(UC_ARM_REG_R1), uc.reg_read(UC_ARM_REG_R2),
                      uc.reg_read(UC_ARM_REG_R3))
                uc.reg_write(UC_ARM_REG_R0, 16)
                uc.reg_write(UC_ARM_REG_R1, 32)
                uc.reg_write(UC_ARM_REG_R2, 48)
                uc.reg_write(UC_ARM_REG_R3, 64)
            elif swi == 1:
                # TODO: address and size vaild required?
                buffer = uc.mem_read(r0, r1).decode('utf-8', 'replace')
                if self.state.write_to_stdout:
                    print("API_REQ", buffer)
                self.api_response("hello")
                self.uc.emu_stop()
            else:
                self.has_error = True

            self.uc.emu_stop()
Exemple #2
0
def hook_code(uc: unicorn.Uc, address, size, user_data):
    inst_code = uc.mem_read(address, size)
    for inst in cs.disasm(inst_code, size):
        # 判断是否保存有上次的指令,有的话,则先打印上次的指令,并且查询上次的第一个寄存器的新数值
        if globalData.has_pre and globalData.pre_regname:
            regindex = reg_names[globalData.pre_regname.upper()]
            regvalue = uc.reg_read(regindex)
            globalData.pre_codestr += "\t//%s=0x%x" % (globalData.pre_regname,
                                                       regvalue)
            print(globalData.pre_codestr)
            globalData.pre_codestr = ""
            globalData.has_pre = False

        # 监控我关心的内存空间,如果发生变动会再打印
        if len(globalData.watch_addrs) > 0:
            for i, v in globalData.watch_addrs.items():
                idata = uc.mem_read(i, 0x10)
                buf = binascii.b2a_hex(idata)
                hexstr = buf.decode(encoding="utf-8")
                if globalData.watch_addrs[i] == hexstr:
                    continue
                globalData.watch_addrs[i] = hexstr
                print("0x%x\t%s" % (i, hexstr))

        # 拼接当前行的汇编指令
        opstr = "0x%x:\t%s\t%s" % (address, inst.mnemonic, inst.op_str)
        # 从当前行指令中匹配出所有的寄存器
        res = re.findall(r'[^0]([wx][0-9]+)', " " + inst.op_str, re.I | re.M)
        # 如果有多个寄存器,取第一个为数值被改变的寄存器
        if len(res) > 0:
            globalData.pre_regname = res[0]
        res = list(set(res))
        # 如果有sp寄存器,则单独插入
        if "sp" in inst.op_str:
            res.append("sp")
        # 如果没有寄存器,则不需要记录为上次的,直接打印即可
        if len(res) <= 0:
            has_pre = False
            print(opstr)
            continue
        # 记录数据为上次的指令
        fenge = "\t\t------"
        curreg = ""
        for regname in res:
            regindex = reg_names[regname.upper()]
            regvalue = uc.reg_read(regindex)
            curreg += "%s=0x%x\t" % (regname, regvalue)
        globalData.pre_codestr = opstr + fenge + curreg
        globalData.has_pre = True
def main():
    mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
    mu.last_instr = ""

    setup_hooks(mu)

    load_mem(mu, 0x9FD6, 0x9FF8 - 0x9FD6)
    load_mem(mu, 0x35000, 0x4000)

    sram_addr = 0x20000000 & PAGE_MASK
    sram_size = ((0x40000) & PAGE_MASK) + PAGE_SIZE
    mu.mem_map(sram_addr, sram_size)

    setup_stack(mu)

    # mu.reg_write(UC_ARM_REG_R0, gps_cfg['addr'])

    print("[Starting Emulation]")
    mu.emu_start(0x0369E0 | 1, 0x369FE)

    with open("data_0x200000D8_7bc.bin", "wb") as fh:
        mem = mu.mem_read(0x200000D8, 0x7BC)
        fh.write(mem)
        fh.close()

    print("[Done]")
Exemple #4
0
    def speculate_instruction(emulator: Uc, address, size, model) -> None:
        # reached max spec. window? skip
        if len(model.checkpoints) >= model.nesting:
            return

        # decode the instruction
        code = emulator.mem_read(address, size)
        flags = emulator.reg_read(UC_X86_REG_EFLAGS)
        rcx = emulator.reg_read(UC_X86_REG_RCX)
        target, will_jump, is_loop = X86UnicornCond.decode(code, flags, rcx)

        # not a a cond. jump? ignore
        if not target:
            return

        # LOOP instructions must also decrement RCX
        if is_loop:
            emulator.reg_write(UC_X86_REG_RCX, rcx - 1)

        # Take a checkpoint
        next_instr = address + size + target if will_jump else address + size
        model.checkpoint(emulator, next_instr)

        # Simulate misprediction
        if will_jump:
            emulator.reg_write(UC_X86_REG_RIP, address + size)
        else:
            emulator.reg_write(UC_X86_REG_RIP, address + size + target)
def hook_instr(mu: Uc, address, size, user_data):
    #  BL   sha1sum
    # if address == 0x0369F6:
    #     mu.reg_write(UC_ARM_REG_PC, address + size)
    # if address == 0x369F8:
    #     d = input()
    #     if d:
    #         dump_hex_buf(mu, 0x200000D8, 128)
    if address >= 0x3642A and address <= 0x3658A:
        # input()
        pass
    if address >= 0x0369E0 and address <= 0x36A00:
        print(">>> Tracing instruction at 0x%X, instruction size = 0x%X" %
              (address, size))
        R0 = mu.reg_read(UC_ARM_REG_R0)
        R1 = mu.reg_read(UC_ARM_REG_R1)
        R2 = mu.reg_read(UC_ARM_REG_R2)
        R3 = mu.reg_read(UC_ARM_REG_R3)
        R4 = mu.reg_read(UC_ARM_REG_R4)
        PC = mu.reg_read(UC_ARM_REG_PC)
        print(f"R0: {R0:08X}  R1: {R1:08X}  R2: {R2:08X}  "
              f"R3: {R3:08X}  R4: {R4:08X}  PC: {PC:08X}")
        mem = mu.mem_read(address, size)
        for i in cs.disasm(mem, address):
            print(f"  0x{i.address:08X}:\t{i.mnemonic}\t{i.op_str}")
            # if i.mnemonic == "blx":
            #     print(f"[-] Skipping call to {R1:08X}")
            #     mu.reg_write(UC_ARM_REG_PC, address + size + 1)
        print()
        # dump_hex_buf(mu, R0, R1)

    mu.last_instr = (
        f">>> Tracing instruction at 0x{address:08X}, instruction size = 0x{size:X}\n"
    )
    R0 = mu.reg_read(UC_ARM_REG_R0)
    R1 = mu.reg_read(UC_ARM_REG_R1)
    R2 = mu.reg_read(UC_ARM_REG_R2)
    R3 = mu.reg_read(UC_ARM_REG_R3)
    R4 = mu.reg_read(UC_ARM_REG_R4)
    PC = mu.reg_read(UC_ARM_REG_PC)
    mu.last_instr += (f"R0: {R0:08X}  R1: {R1:08X}  R2: {R2:08X}  "
                      f"R3: {R3:08X}  R4: {R4:08X}  PC: {PC:08X}\n")

    # branch = False
    mem = mu.mem_read(address, size)
    for i in cs.disasm(mem, address):
        mu.last_instr += f"  0x{i.address:08X}:\t{i.mnemonic}\t{i.op_str}\n"
def dbg_hook_memory_access(uc: Uc, access, address, size, value, data):
    if access == UC_MEM_WRITE:
        print("Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(
            address, size, value))
    elif access == UC_HOOK_MEM_READ:
        print("Read: addr=0x{0:016x} size={1} data=0x{2:016x}".format(
            address, size,
            struct.unpack("B", uc.mem_read(address, size))[0]))
    print(access, address, size, value, data)
Exemple #7
0
def place_input(ucf: Unicorefuzz, uc: Uc, input: bytes) -> None:
    """
    Places the input in memory and alters the input.
    This is an example for sk_buff in openvsswitch
    """
    if len(input) < 1500:
        import os
        os._exit(0)
    rdx = uc.reg_read(UC_X86_REG_RDX)  # struct sk_buff* skb
    ucf.map_page(uc, rdx)  # ensure sk_buf is mapped
    data_ptr = struct.unpack("<Q", uc.mem_read(rdx + 0xD0, 8))[0]
    ucf.map_page(uc, data_ptr)  # ensure the buffer is mapped
    uc.mem_write(data_ptr, input)  # insert afl input
Exemple #8
0
 def angr_load_mapped_pages(
     self, uc: Uc, state: angr.SimState
 ) -> List[Tuple[int, int, int]]:
     """
     Loads all currently mapped unicorn mem regions into angr
     :param uc: The uc instance to load from
     :param state: the angr instance to load to
     :returns Lst of pages mapped
     """
     mapped = []
     for begin, end, perms in uc.mem_regions():
         mapped += (begin, end - begin + 1, perms)
         angr_store_mem(state, begin, bytes(uc.mem_read(begin, end - begin + 1)))
     return mapped
Exemple #9
0
def place_input_skb(ucf: Unicorefuzz, uc: Uc, input: bytes) -> None:
    """
    Places the input in memory and alters the input.
    This is an example for sk_buff in openvsswitch
    """

    if len(input) > 1500:
        import os

        os._exit(0)  # too big!

    # read input to the correct position at param rdx here:
    rdx = uc.reg_read(UC_X86_REG_RDX)
    rdi = uc.reg_read(UC_X86_REG_RDI)
    ucf.map_page(uc, rdx)  # ensure sk_buf is mapped
    bufferPtr = struct.unpack("<Q", uc.mem_read(rdx + 0xD8, 8))[0]
    ucf.map_page(uc, bufferPtr)  # ensure the buffer is mapped
    uc.mem_write(rdi, input)  # insert afl input
    uc.mem_write(rdx + 0xC4, b"\xdc\x05")  # fix tail
def hook_bss_access(uc: Uc, access, address, size, value, data):
    # check rwdata range
    if bss_section_start <= address < bss_section_end:
        if stage == 0:
            # entryBB
            if access == UC_MEM_READ and size == 4 and struct.unpack(
                    "<I", uc.mem_read(address, size))[0] == 0:
                decryptStatus.add(address)
                print("READ: address:0x{0:016x} is decryptStatus".format(
                    address))
        elif stage == 1:
            # decryptBB
            pass
        elif stage == 2:
            # originalBB
            if access == UC_MEM_WRITE and size == 4 and value == 1:
                print("WRITE: address:0x{0:016x} is decryptStatus".format(
                    address))
                if address in decryptStatus:
                    decryptStatus.remove(address)
                uc.emu_stop()
Exemple #11
0
stack_size = 0x10000 * 3
stack_top = stack_base + stack_size - 0x4
mu.mem_map(stack_base, stack_size)
mu.reg_write(UC_ARM_REG_SP, stack_top)

# 分配数据内存
data_base = 0xF0000
data_size = 0x10000 * 3
mu.mem_map(data_base, data_size)
mu.mem_write(data_base, a1)
mu.reg_write(UC_ARM_REG_R0, data_base)

# 修复 Got 表
mu.mem_write(image_base + 0x1EDB0, b"\xD9\x98\x00\x00")

# 设置 Hook
mu.hook_add(UC_HOOK_CODE, hook_code, None)
mu.hook_add(UC_HOOK_MEM_UNMAPPED, hook_memory, None)

# 设置需要 Run 的函数地址
func_start = image_base + 0x9B68 + 0x1
func_end = image_base + 0x9C2C

try:
    mu.emu_start(func_start, func_end)
    r2 = mu.reg_read(UC_ARM_REG_R2)
    result = mu.mem_read(r2, 16)
    print(result.hex())
except UcError as e:
    print(f"UC run error {e}")
class Emulator:
    """
    :type mu Uc
    :type modules Modules
    :type memory Memory
    """
    def __init__(self, vfs_root=None, vfp_inst_set=False):
        # Unicorn.
        self.mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)

        if vfp_inst_set:
            self._enable_vfp()

        # Android
        self.system_properties = {"libc.debug.malloc.options": ""}

        # Stack.
        self.mu.mem_map(config.STACK_ADDR, config.STACK_SIZE)
        self.mu.reg_write(UC_ARM_REG_SP, config.STACK_ADDR + config.STACK_SIZE)

        # Executable data.
        self.modules = Modules(self)
        self.memory = Memory(self)

        # CPU
        self.interrupt_handler = InterruptHandler(self.mu)
        self.syscall_handler = SyscallHandlers(self.interrupt_handler)
        self.syscall_hooks = SyscallHooks(self.mu, self.syscall_handler)

        # File System
        if vfs_root is not None:
            self.vfs = VirtualFileSystem(vfs_root, self.syscall_handler)
        else:
            self.vfs = None

        # Hooker
        self.mu.mem_map(config.HOOK_MEMORY_BASE, config.HOOK_MEMORY_SIZE)
        self.hooker = Hooker(self, config.HOOK_MEMORY_BASE,
                             config.HOOK_MEMORY_SIZE)

        # JavaVM
        self.java_classloader = JavaClassLoader()
        self.java_vm = JavaVM(self, self.java_classloader, self.hooker)

        # Native
        self.native_memory = NativeMemory(self.mu, config.HEAP_BASE,
                                          config.HEAP_SIZE,
                                          self.syscall_handler)
        self.native_hooks = NativeHooks(self, self.native_memory, self.modules,
                                        self.hooker)

        # Tracer
        self.tracer = Tracer(self.mu, self.modules)

    # https://github.com/unicorn-engine/unicorn/blob/8c6cbe3f3cabed57b23b721c29f937dd5baafc90/tests/regress/arm_fp_vfp_disabled.py#L15
    def _enable_vfp(self):
        # MRC p15, #0, r1, c1, c0, #2
        # ORR r1, r1, #(0xf << 20)
        # MCR p15, #0, r1, c1, c0, #2
        # MOV r1, #0
        # MCR p15, #0, r1, c7, c5, #4
        # MOV r0,#0x40000000
        # FMXR FPEXC, r0
        code = '11EE501F'
        code += '41F47001'
        code += '01EE501F'
        code += '4FF00001'
        code += '07EE951F'
        code += '4FF08040'
        code += 'E8EE100A'
        # vpush {d8}
        code += '2ded028b'

        address = 0x1000
        mem_size = 0x1000
        code_bytes = bytes.fromhex(code)

        try:
            self.mu.mem_map(address, mem_size)
            self.mu.mem_write(address, code_bytes)
            self.mu.reg_write(UC_ARM_REG_SP, address + mem_size)

            self.mu.emu_start(address | 1, address + len(code_bytes))
        finally:
            self.mu.mem_unmap(address, mem_size)

    def _call_init_array(self):
        pass

    def load_library(self, filename, do_init=True):
        libmod = self.modules.load_module(filename)
        if do_init:
            logger.debug("Calling Init for: %s " % filename)
            for fun_ptr in libmod.init_array:
                logger.debug("Calling Init function: %x " % fun_ptr)
                self.call_native(fun_ptr)
        return libmod

    def call_symbol(self, module, symbol_name, *argv):
        symbol = module.find_symbol(symbol_name)

        if symbol is None:
            logger.error('Unable to find symbol \'%s\' in module \'%s\'.' %
                         (symbol_name, module.filename))
            return

        self.call_native(symbol.address, *argv)

    def call_native(self, addr, *argv):
        # Detect JNI call
        is_jni = False

        if len(argv) >= 1:
            is_jni = argv[0] == self.java_vm.address_ptr or argv[
                0] == self.java_vm.jni_env.address_ptr

        # TODO: Write JNI args to local ref table if jni.

        try:
            # Execute native call.

            native_write_args(self, *argv)
            stop_pos = randint(HOOK_MEMORY_BASE,
                               HOOK_MEMORY_BASE + HOOK_MEMORY_SIZE) | 1
            self.mu.reg_write(UC_ARM_REG_LR, stop_pos)
            self.mu.emu_start(addr, stop_pos - 1)

            # Read result from locals if jni.
            if is_jni:
                result_idx = self.mu.reg_read(UC_ARM_REG_R0)
                result = self.java_vm.jni_env.get_local_reference(result_idx)

                if result is None:
                    return result

                return result.value
        finally:
            # Clear locals if jni.
            if is_jni:
                self.java_vm.jni_env.clear_locals()

    def dump(self, out_dir):
        os.makedirs(out_dir)

        for begin, end, prot in [reg for reg in self.mu.mem_regions()]:
            filename = "{:#010x}-{:#010x}.bin".format(begin, end)
            pathname = os.path.join(out_dir, filename)
            with open(pathname, "w") as f:
                f.write(
                    hexdump.hexdump(self.mu.mem_read(begin, end - begin),
                                    result='return'))
Exemple #13
0
class emu:
    """
    Loads ELF file to unicorn, sets watchpoints and stdin
    """
    def __init__(self, fname, stdin, watchpoints=[], drcov=True, emulator_base=None, fw_entry_symbol="cont"):
        self.stdin = stdin
        self.exception = ""
        self.uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
        self.fname = fname
        self.fd = open(fname, "rb")
        self.elf = elffile.ELFFile(self.fd) 

        self.symbols = {}
        self.symbols_reverse = {}
        for i in range(self.elf.num_sections()):
            sec = self.elf.get_section(i)
            if sec.name == ".symtab":
                for sym in sec.iter_symbols():
                    self.symbols[sym.name] = sym.entry["st_value"] 
                    self.symbols_reverse[sym.entry["st_value"]] = sym.name

        self.results = []
        self.result_id = 0
        self.coverage_pc = set()
        self.coverage_bb = set()
        self.read = set()
        self.write = set()

        self.trace_initialized = False
        self.coverage_activity = {}
        self.read_activity = {}
        self.write_activity = {}

        self.stdout = ""
        self.stderr = ""

        self.emulator_base_start = None
        self.emulator_base_stop = None
        if fw_entry_symbol in self.symbols:
            self.fw_entry = self.symbols[fw_entry_symbol] # ignore everything until that symbol
        else:
            self.fw_entry = None

        #loading prog headrs
        self.state = []
        self.segments = []
        for i in range(self.elf.num_sections()):
            section = self.elf.get_section(i)
            if section.header["sh_flags"] & SH_FLAGS.SHF_ALLOC != 0:
                addr = section.header["sh_addr"]
                size = section.header["sh_size"]
                name = section.name

                #NOBITS sections contains no data in file
                #Will be initialized with zero
                if section.header["sh_type"] == "SHT_NOBITS":
                    data = b"\x00" * size
                else:
                    data = section.data()

                print("Found %s @ 0x%x - 0x%x (%d bytes)" % (name, addr, addr+len(data), len(data)))
                if emulator_base == addr:
                    self.emulator_base_start = emulator_base
                    self.emulator_base_stop = emulator_base + size

                self.segments += [(name, addr, size)]
                self.state += [(addr, size, data)]



        #compute memory map from sections
        self.maps = []
        if self.emulator_base_start is not None:
            self.maps += [(self.emulator_base_start, self.emulator_base_stop)]
        self.segments = sorted(self.segments, key=lambda x:x[0])
        for name, addr, size in self.segments:
            size += addr & 0x3ff
            addr = addr & (~0x3ff)
            altered = False
            for i in range(len(self.maps)):
                map_addr, map_size = self.maps[i]
                offset = addr - map_addr
                if addr >= map_addr and addr <= map_addr + map_size:
                    self.maps[i] = (map_addr, self.pageresize(max(map_size, offset+size)))
                    altered = True

            if not altered:
                self.maps += [(addr, self.pageresize(size))]


        for addr, size in self.maps:
            print("Mapping 0x%x - 0x%x (%d bytes)" % (addr, addr+size, size))
            self.uc.mem_map(addr, size, UC_PROT_ALL)


            
        for addr,size,data in self.state:
            print("Loading 0x%x - 0x%x (%d bytes)" % (addr, addr+len(data), len(data)))
            self.uc.mem_write(addr, data)

        #stack
        stack = 0xdead0000
        stack_size = 16384
        print("Mapping Stack 0x%x - 0x%x (%d bytes)" % (stack, stack+stack_size, stack_size))
        self.uc.mem_map(stack, stack_size, UC_PROT_ALL)
        self.uc.reg_write(arm_const.UC_ARM_REG_SP, stack + stack_size)

        #syscalls
        self.uc.hook_add(UC_HOOK_INTR, self.hook_intr, self)

        #tracing
        self.watchpoints = watchpoints
        self.uc.hook_add(UC_HOOK_CODE, self.hook_code, self)
        self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_mem_access, self)

        #prepare drcov file
        self.drcov = drcov
        if drcov:
            self.uc.hook_add(UC_HOOK_BLOCK, self.hook_bb, self)

    def pageresize(self, s, pagesize=1024):
        if s % pagesize == 0:
            return s
        return (int(s / pagesize) + 1) * pagesize

    """
    We need to emulate read and write for emulation
    """
    @staticmethod
    def hook_intr(uc, size, self):
        #print hex(uc.reg_read(arm_const.UC_ARM_REG_PC))
        pc = uc.reg_read(arm_const.UC_ARM_REG_PC)
        for name in ["read","write"]:
            if self.symbols[name] <= pc and  self.symbols[name] + 8 >= pc:
                #print name
                if name == "read":
                    fd = uc.reg_read(arm_const.UC_ARM_REG_R0)
                    target = uc.reg_read(arm_const.UC_ARM_REG_R1)
                    size = uc.reg_read(arm_const.UC_ARM_REG_R2)

                    data = self.stdin[:size]
                    self.stdin = self.stdin[size:]

                    uc.mem_write(target, data)
                    self.uc.reg_write(arm_const.UC_ARM_REG_R0, len(data))

                elif name == "write":
                    fd = uc.reg_read(arm_const.UC_ARM_REG_R0)
                    target = uc.reg_read(arm_const.UC_ARM_REG_R1)
                    size = uc.reg_read(arm_const.UC_ARM_REG_R2)

                    data = uc.mem_read(target, size)
                    if fd == 1:
                        self.stdout += data.decode("utf-8")
                        sys.stdout.write(data.decode("utf-8"))
                    else:
                        self.stderr += data.decode("utf-8")
                        sys.stderr.write(data.decode("utf-8"))

                else:
                    print("unknown intr")

    """
    Implement memory and code watchpoints
    """
    @staticmethod
    def hook_bb(uc, address, size, self):
        if self.emulator_base_start is not None:
            if address >= self.emulator_base_start and address < self.emulator_base_stop:
                return
        #print(hex(address))
        self.coverage_bb.add((address, size))

    @staticmethod
    def hook_code(uc, address, size, self):
        # Unicorn will for some reason giv old register values after a crash
        # The last update seems to be on the entry of the bb
        self.regs = {}
        self.regs["r0"] = self.uc.reg_read(arm_const.UC_ARM_REG_R0)
        self.regs["r1"] = self.uc.reg_read(arm_const.UC_ARM_REG_R1)
        self.regs["r2"] = self.uc.reg_read(arm_const.UC_ARM_REG_R2)
        self.regs["r3"] = self.uc.reg_read(arm_const.UC_ARM_REG_R3)
        self.regs["r4"] = self.uc.reg_read(arm_const.UC_ARM_REG_R4)
        self.regs["r5"] = self.uc.reg_read(arm_const.UC_ARM_REG_R5)
        self.regs["r6"] = self.uc.reg_read(arm_const.UC_ARM_REG_R6)
        self.regs["r7"] = self.uc.reg_read(arm_const.UC_ARM_REG_R7)
        self.regs["r8"] = self.uc.reg_read(arm_const.UC_ARM_REG_R8)
        self.regs["r9"] = self.uc.reg_read(arm_const.UC_ARM_REG_R9)
        self.regs["r10"] = self.uc.reg_read(arm_const.UC_ARM_REG_R10)
        self.regs["r11"] = self.uc.reg_read(arm_const.UC_ARM_REG_R11)
        self.regs["r12"] = self.uc.reg_read(arm_const.UC_ARM_REG_R12)
        self.regs["sp"] = self.uc.reg_read(arm_const.UC_ARM_REG_R13)
        self.regs["lr"] = self.uc.reg_read(arm_const.UC_ARM_REG_R14)
        self.regs["pc"] = self.uc.reg_read(arm_const.UC_ARM_REG_R15)

        if self.fw_entry is not None and address & 0xfffffffe == self.fw_entry & 0xfffffffe:
            self.trace_init_state()
        if self.fw_entry is None and not self.trace_initialized:
            self.trace_init_state()

        if self.emulator_base_start is not None:
            if address >= self.emulator_base_start and address < self.emulator_base_stop:
                return

        self.coverage_pc.add(address)
        if address in self.coverage_activity:
            self.coverage_activity[address] += 1
        else:
            self.coverage_activity[address] = 1

        if address in self.watchpoints or address^1 in self.watchpoints:
            self.trace_state_change("Execute")

    @staticmethod
    def hook_mem_access(uc, access, address, size, value, self):
        pc = self.uc.reg_read(arm_const.UC_ARM_REG_R15)
        if self.emulator_base_start is not None:
            if pc >= self.emulator_base_start and pc < self.emulator_base_stop:
                return
        if access == UC_MEM_WRITE:
            self.write.add((pc, address, value))
            if address in self.write_activity:
                self.write_activity[address] += 1
            else:
                self.write_activity[address] = 1
        else:
            self.read.add((pc, address))
            if address in self.read_activity:
                self.read_activity[address] += 1
            else:
                self.read_activity[address] = 1
        if address in self.watchpoints:
            if access == UC_MEM_WRITE:
                self.trace_state_change("Write 0x%x" % address)
            else:
                self.trace_state_change("Read 0x%x" % address)


    """
    For each tracepoint that was hit
        Dump Registers
        Do Memory Dump
    """
    def trace_init_state(self):
        self.state = []
        self.trace_initialized = True
        for name, addr, size in self.segments:
            data = self.uc.mem_read(addr, size)
            #data = list(map(chr, data))
            self.state += [(addr, size, data)]
        

    """
    Called if a tracepoint is hit
    Will save registers and analyzes changes made im memory
    """
    def trace_state_change(self, reason):
        print(reason)
        new_state = []
        memdiff = []
        for addr, size, data in self.state:
            new_data = self.uc.mem_read(addr, size)
            #new_data = list(map(chr, new_data))
            if data != new_data:
                new = old = ""
                for i in range(len(data)):
                    if data[i] != new_data[i]:
                        old += "%02x" % data[i]
                        new += "%02x" % new_data[i]
                    elif new != "":
                        memdiff += [(i+addr-len(new), old, new)]
                        new = old = ""

            new_state += [(addr, size, new_data)]

        #XXX
        memdif_rendered = self.render_mem_diff()
        sys.stderr.write(self.stderr)
        sys.stderr.write("\n"+memdif_rendered+"\n")

        self.state = new_state

        # disassemble current instruction
        try:
            pc = self.regs["pc"]
            md = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)
            instr = list(md.disasm(self.uc.mem_read(pc, 4), pc))[0]
            instr = instr.mnemonic + "   " + instr.op_str 
        except:
            import traceback; traceback.print_exc()
            instr = hexlify(self.uc.mem_read(pc, 4))

        # Save tracepoint object
        tp = {}
        tp["reason"] = reason
        tp["regs"] = self.regs
        tp["instr"] = instr
        tp["memdiff"] = memdiff
        tp["memdif_rendered"] = memdif_rendered
        tp["stdout"] = self.stdout
        tp["stderr"] = self.stderr
        tp["resid"] = self.result_id
        self.results += [tp]
        self.stdout = ""
        self.stderr = ""
        self.result_id += 1

        return [{"regs": self.regs, "memdiff": sorted(memdiff)}]

    def render_mem_diff(self, block_size=32):
        ret  = "----------" + ("-"*(3*block_size+1)) + "\n"
        ret += "         |\n"
        print_dots = False
        for addr, size, data in self.state:
            new_data = self.uc.mem_read(addr, size)
            #new_data = list(map(chr, new_data))
            current_offset = 0
            #print(len(data), len(new_data), size)

            #for each hexdump row
            while current_offset <  size:
                old_row = data[current_offset: current_offset+block_size]
                new_row = new_data[current_offset: current_offset+block_size]
                #ugly equal comparison
                equal = True
                for x,y in zip(new_row, old_row):
                    equal = equal and (x==y)

                if not equal:
                    hex_new = "%8x |  " % (addr + current_offset)
                    hex_old = "         |  "
                    symbols = ""

                    #render diff
                    for i in range(min(block_size, len(new_row))):
                        if new_row[i] == old_row[i]:
                            hex_new += "%02x " % new_row[i]
                            hex_old += "   "
                        else:
                            hex_new += "\033[;32m%02x\033[;00m " % new_row[i]
                            hex_old += "\033[;31m%02x\033[;00m " % old_row[i]

                        if (addr + current_offset + i) in self.watchpoints:
                            symbols += "         |  "
                            if len("Watchpoint") < 3*i - 1:
                                symbols += " " * (3*i - len("Watchpoint") - 1)
                                symbols += "\033[;33mWatchpoint ^^\033[;00m\n"
                            else:
                                symbols += "   " * i
                                symbols += "\033[;33m^^ Watchpoint\033[;00m\n"
                        elif (addr + current_offset + i) in self.symbols_reverse:
                            name = self.symbols_reverse[addr + current_offset + i]
                            symbols += "         |  "
                            if len(name) < 3*i - 1:
                                symbols += " " * (3*i - len(name) - 1)
                                symbols += "%s ^^\n" % name
                            else:
                                symbols += "   " * i
                                symbols += "^^ %s\n" % name

                    ret += hex_new + "\n" + hex_old + "\n"
                    if len(symbols) > 1:
                        ret += symbols
                    print_dots = True

                else:
                    if print_dots:
                        print_dots = False
                        ret += "         |\n"
                        ret += "         |" + ("-"*(3*block_size+1)) + "\n"
                        ret += "         |\n"
                    


                current_offset += block_size

        #cleanup end
        split = ret.split("\n")
        if len(split) <= 3:
            return ""
        ret = "\n".join(split[:-3]) + "\n"
        ret += "----------" + ("-"*(3*block_size+1)) + "\n"
        return ret


    """
    Run the Emulation
    """
    def run(self, timeout=300):
        try:
            print("running until exit @ 0x%x" % self.symbols["exit"])
            self.uc.emu_start(self.elf.header.e_entry, self.symbols["exit"], timeout=timeout*UC_SECOND_SCALE)
            self.trace_state_change("Exit")
        except KeyboardInterrupt:
            sys.exit(1)
        except Exception as e:
            self.exception = str(e)
            print(e)
            import traceback; traceback.print_exc()
            print(hex(self.uc.reg_read(arm_const.UC_ARM_REG_PC)))
            self.trace_state_change(str(e))


    # Seems to be broken n lighthouse
    def get_drcov(self):
        drcov = b"DRCOV VERSION: 2\nDRCOV FLAVOR: drcov\n"

        drcov += b"Module Table: version 2, count %d\n" % len(self.state)
        drcov += b"Columns: id, base, end, entry, path\n"
        for i in range(len(self.state)):
            addr, size, _ = self.state[i]
            drcov += b"%d, 0x%x, 0x%x, 0x%x, %s\n" % (i, addr, addr+size+1, addr, os.path.basename(self.fname).encode())

        drcov += b"BB Table: %d bbs\n" % len(self.coverage_bb)
        bb_table = b""
        for address, size in self.coverage_bb:
            for module_id in range(len(self.state)):
                base_addr, module_size, _ = self.state[module_id]
                if address >= base_addr and address <= base_addr + module_size:
                    bb_table += struct.pack("<Ihh", address - base_addr, size, module_id)
                    break

        return drcov + bb_table

    def get_tracefile(self):
        trace = ""
        for address in self.coverage_pc:
            trace += "0x%x\n" % address
        return trace.encode()
def hook_rwdata_backup(uc: Uc, access, address, size, value, data):
    if data_section_start <= address < data_section_end and access == UC_MEM_WRITE:
        data_backup.append((address, uc.mem_read(address, size)))
Exemple #15
0
class Emulator:
    """
    :type mu Uc
    :type modules Modules
    """
    def __init__(self, vfs_root: str = None, vfp_inst_set: bool = False):
        # Unicorn.
        self.mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)

        if vfp_inst_set:
            self._enable_vfp()

        # Android
        self.system_properties = {"libc.debug.malloc.options": ""}

        # Stack.
        self.mu.mem_map(STACK_ADDR, STACK_SIZE)
        self.mu.reg_write(UC_ARM_REG_SP, STACK_ADDR + STACK_SIZE)

        # Executable data.
        self.modules = Modules(self)
        self.memory_manager = MemoryManager(self.mu)

        # CPU
        self.interrupt_handler = InterruptHandler(self.mu)
        self.syscall_handler = SyscallHandlers(self.interrupt_handler)
        self.syscall_hooks = SyscallHooks(self.mu, self.syscall_handler, self.modules)
        self.syscall_hooks_memory = SyscallHooksMemory(self.mu, self.memory_manager, self.syscall_handler)

        # File System
        if vfs_root is not None:
            self.vfs = VirtualFileSystem(vfs_root, self.syscall_handler)
        else:
            self.vfs = None

        # Hooker
        self.mu.mem_map(HOOK_MEMORY_BASE, HOOK_MEMORY_SIZE)
        self.hooker = Hooker(self, HOOK_MEMORY_BASE, HOOK_MEMORY_SIZE)

        # JavaVM
        self.java_classloader = JavaClassLoader()
        self.java_vm = JavaVM(self, self.java_classloader, self.hooker)

        # Native
        self.native_hooks = NativeHooks(self, self.memory_manager, self.modules, self.hooker)

        # Tracer
        self.tracer = Tracer(self.mu, self.modules)

        # Thread.
        self._setup_thread_register()

    # https://github.com/unicorn-engine/unicorn/blob/8c6cbe3f3cabed57b23b721c29f937dd5baafc90/tests/regress/arm_fp_vfp_disabled.py#L15
    def _enable_vfp(self):
        # MRC p15, #0, r1, c1, c0, #2
        # ORR r1, r1, #(0xf << 20)
        # MCR p15, #0, r1, c1, c0, #2
        # MOV r1, #0
        # MCR p15, #0, r1, c7, c5, #4
        # MOV r0,#0x40000000
        # FMXR FPEXC, r0
        code = '11EE501F'
        code += '41F47001'
        code += '01EE501F'
        code += '4FF00001'
        code += '07EE951F'
        code += '4FF08040'
        code += 'E8EE100A'
        # vpush {d8}
        code += '2ded028b'

        address = 0x1000
        mem_size = 0x1000
        code_bytes = bytes.fromhex(code)

        try:
            self.mu.mem_map(address, mem_size)
            self.mu.mem_write(address, code_bytes)
            self.mu.reg_write(UC_ARM_REG_SP, address + mem_size)

            self.mu.emu_start(address | 1, address + len(code_bytes))
        finally:
            self.mu.mem_unmap(address, mem_size)

    def _setup_thread_register(self):
        """
        Set up thread register.
        This is currently not accurate and just filled with garbage to ensure the emulator does not crash.

        https://developer.arm.com/documentation/ddi0211/k/system-control-coprocessor/system-control-coprocessor-register-descriptions/c13--thread-and-process-id-registers
        """
        thread_info_size = 64
        thread_info = self.memory_manager.allocate(thread_info_size * 5)

        thread_info_1 = thread_info + (thread_info_size * 0)
        thread_info_2 = thread_info + (thread_info_size * 1)
        thread_info_3 = thread_info + (thread_info_size * 2)
        thread_info_4 = thread_info + (thread_info_size * 3)
        thread_info_5 = thread_info + (thread_info_size * 4)

        # Thread name
        write_utf8(self.mu, thread_info_5, "AndroidNativeEmu")

        # R4
        self.mu.mem_write(thread_info_2 + 0x4, int(thread_info_5).to_bytes(4, byteorder='little'))
        self.mu.mem_write(thread_info_2 + 0xC, int(thread_info_3).to_bytes(4, byteorder='little'))

        # R1
        self.mu.mem_write(thread_info_1 + 0x4, int(thread_info_4).to_bytes(4, byteorder='little'))
        self.mu.mem_write(thread_info_1 + 0xC, int(thread_info_2).to_bytes(4, byteorder='little'))
        self.mu.reg_write(UC_ARM_REG_C13_C0_3, thread_info_1)

    def load_library(self, filename, do_init=True):
        libmod = self.modules.load_module(filename)
        if do_init:
            logger.debug("Calling init for: %s " % filename)
            for fun_ptr in libmod.init_array:
                logger.debug("Calling Init function: %x " % fun_ptr)
                self.call_native(fun_ptr, 0, 0, 0)
        return libmod

    def call_symbol(self, module, symbol_name, *argv, is_return_jobject=True):
        symbol = module.find_symbol(symbol_name)

        if symbol is None:
            logger.error('Unable to find symbol \'%s\' in module \'%s\'.' % (symbol_name, module.filename))
            return

        return self.call_native(symbol.address, *argv, is_return_jobject=is_return_jobject)

    def call_native(self, addr, *argv, is_return_jobject=True):
        # Detect JNI call
        is_jni = False

        if len(argv) >= 1:
            is_jni = argv[0] == self.java_vm.address_ptr or argv[0] == self.java_vm.jni_env.address_ptr

        # TODO: Write JNI args to local ref table if jni.

        try:
            # Execute native call.
            self.mu.reg_write(UC_ARM_REG_SP, STACK_ADDR + STACK_SIZE)
            native_write_args(self, *argv)
            stop_pos = randint(HOOK_MEMORY_BASE, HOOK_MEMORY_BASE + HOOK_MEMORY_SIZE) | 1
            self.mu.reg_write(UC_ARM_REG_LR, stop_pos)
            self.mu.emu_start(addr, stop_pos - 1)

            # Read result from locals if jni.
            if is_jni and is_return_jobject:
                result_idx = self.mu.reg_read(UC_ARM_REG_R0)
                result = self.java_vm.jni_env.get_local_reference(result_idx)

                if result is None:
                    return result

                return result.value
            else:
                return self.mu.reg_read(UC_ARM_REG_R0)
        finally:
            # Clear locals if jni.
            if is_jni:
                self.java_vm.jni_env.clear_locals()

    def dump(self, out_dir):
        os.makedirs(out_dir)

        for begin, end, prot in [reg for reg in self.mu.mem_regions()]:
            filename = "{:#010x}-{:#010x}.bin".format(begin, end)
            pathname = os.path.join(out_dir, filename)
            with open(pathname, "w") as f:
                f.write(hexdump.hexdump(self.mu.mem_read(begin, end - begin), result='return'))
Exemple #16
0
class CPU:
    def __init__(self,
                 firmware: Firmware = None,
                 state: CpuState = None,
                 verbose=0,
                 init=True):
        self.firmware = firmware
        self.uc = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
        self.cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
        self.cs.detail = True
        self.state = state
        self.has_error = None
        self.last_addr = None
        self.ready = False
        self.context = None
        self.verbose = verbose

        if init:
            self.init()

    def init(self):
        if self.firmware:
            self.firmware.refresh()
        self.state.verify()
        self.init_memory()
        self.init_hook()
        self.init_firmware()
        self.context = self.uc.context_save()
        self.reset()
        self.ready = True

    def init_firmware(self):
        if not self.firmware:
            raise Exception("firmware missing error")

        addr = MemoryMap.FLASH.address
        self.uc.mem_write(addr, self.firmware.buffer)

    def reset(self):
        addr = MemoryMap.FLASH.address
        self.uc.context_restore(self.context)
        self.uc.reg_write(UC_ARM_REG_PC,
                          from_bytes(self.uc.mem_read(addr + 4, 4)))

    def run(self):
        if not self.ready:
            raise Exception("init() does not called")

        INST_SIZE = 2

        if self.firmware:
            self.last_func = self.firmware.text_map[self.uc.reg_read(
                UC_ARM_REG_PC)]
            if self.verbose >= 2:
                print(self.last_func)

        try:
            while self.step():
                pass
        except UcError as e:
            print("ERROR:", e)
            addr = self.uc.reg_read(UC_ARM_REG_PC)
            self.debug_addr(addr - INST_SIZE * 8 - 2, count=7)
            print(">", end=" ")
            self.debug_addr(addr)
            self.debug_addr(addr + INST_SIZE, count=7)
            for reg in REGS:
                uc_value = self.uc.reg_read(reg)
                print(REGS_NAME[reg].ljust(5), hex32(uc_value), sep='\t')

            raise

    def step(self, count=None):
        addr = self.uc.reg_read(UC_ARM_REG_PC)
        cycle = self.state.cycle
        if count is not None:
            self.state.cycle = count

        try:
            self.uc.emu_start(addr | 1, MemoryMap.FLASH.address_until, 0,
                              self.state.cycle)
        finally:
            if count is not None:
                self.state.cycle = cycle

        if self.has_error:
            raise UcError(0)

        return True

    def init_memory(self):
        for region in MemoryMap:  # type: MemoryRegion
            self.uc.mem_map(region.address, region.size, region.uc_mode)

    def init_hook(self):
        peripheral = MemoryMap.PERIPHERAL

        self.uc.hook_add(
            UC_HOOK_MEM_READ,
            self.hook_peripheral_read,
            None,
            peripheral.address,
            peripheral.address_until,
        )

        self.uc.hook_add(UC_HOOK_MEM_WRITE, self.hook_peripheral_write, None,
                         peripheral.address, peripheral.address_until)

        self.uc.hook_add(
            UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED,
            self.hook_unmapped)

        self.uc.hook_add(
            UC_HOOK_INTR,
            self.hook_intr,
        )

        if self.verbose >= 2:
            self.uc.hook_add(UC_HOOK_CODE, self.hook_inst)

    def hook_intr(self, uc: Uc, intno, user_data):
        # self.debug_addr(uc.reg_read(UC_ARM_REG_PC) - 40, 40)
        if intno == 2:
            swi = from_bytes(uc.mem_read(uc.reg_read(UC_ARM_REG_PC) - 2, 1))
            r0 = uc.reg_read(UC_ARM_REG_R0)
            r1 = uc.reg_read(UC_ARM_REG_R1)
            r2 = uc.reg_read(UC_ARM_REG_R2)
            r3 = uc.reg_read(UC_ARM_REG_R3)

            if swi == 0:
                print("done?")
                print(intno, swi, ":", uc.reg_read(UC_ARM_REG_R0),
                      uc.reg_read(UC_ARM_REG_R1), uc.reg_read(UC_ARM_REG_R2),
                      uc.reg_read(UC_ARM_REG_R3))
                uc.reg_write(UC_ARM_REG_R0, 16)
                uc.reg_write(UC_ARM_REG_R1, 32)
                uc.reg_write(UC_ARM_REG_R2, 48)
                uc.reg_write(UC_ARM_REG_R3, 64)
            elif swi == 1:
                # TODO: address and size vaild required?
                buffer = uc.mem_read(r0, r1).decode('utf-8', 'replace')
                if self.state.write_to_stdout:
                    print("API_REQ", buffer)
                self.api_response("hello")
                self.uc.emu_stop()
            else:
                self.has_error = True

            self.uc.emu_stop()

    def api_response(self, *args):
        bufs = json.dumps(args)
        buf = bufs.encode("utf-8")
        if self.state.write_to_stdout:
            print("API_RES", buf)
        self.uc.mem_write(MemoryMap.SYSCALL_BUFFER.address, buf)
        self.uc.mem_write(MemoryMap.SYSCALL_BUFFER.address + len(buf), b'\0')
        self.uc.reg_write(UC_ARM_REG_R0, MemoryMap.SYSCALL_BUFFER.address)
        self.uc.reg_write(UC_ARM_REG_R1, len(buf))

    def hook_peripheral_read(self, uc: Uc, access, address, size, value, data):
        if address == PeripheralAddress.OP_CON_RAM_SIZE:
            uc.mem_write(address, to_bytes(self.state.ram_size))
        elif address == PeripheralAddress.OP_IO_RXR:
            if self.state.input_buffer:
                uc.mem_write(address, to_bytes(self.state.input_buffer.pop(0)))
            else:
                uc.mem_write(address, to_bytes(0))
        elif address == PeripheralAddress.OP_RTC_TICKS_MS:
            pass
            # uc.mem_write(address, to_bytes(int((time.time() - self.state.epoch) * 1000)))
        else:
            if self.verbose >= 1:
                print("read", access, hex(address), size, value, data)

    def hook_peripheral_write(self, uc: Uc, access, address, size, value,
                              data):
        if address == PeripheralAddress.OP_CON_PENDING:
            if self.verbose >= 1:
                print("OPENPYTHON_CONTROLLER_PENDING", value)
        elif address == PeripheralAddress.OP_CON_EXCEPTION:
            if self.verbose >= 1:
                print("OPENPYTHON_CONTROLLER_EXCEPTION", value)
        elif address == PeripheralAddress.OP_CON_INTR_CHAR:
            if self.verbose >= 1:
                print("OPENPYTHON_CONTROLLER_INTR_CHAR", value)
        elif address == PeripheralAddress.OP_IO_TXR:
            self.state.output_storage.append(value)
            if self.state.write_to_stdout:
                print(chr(value), end="")
            sys.stdout.flush()
        else:
            if self.verbose >= 1:
                print("write", access, hex(address), size, value, data)

    def hook_unmapped(self, uc: Uc, access, address, size, value, data):
        print("unmapped:", access, hex(address), size, value, data)
        uc.emu_stop()
        self.has_error = True

    def hook_inst(self, uc: Uc, address, size, data):
        func = None
        if self.firmware:
            func = self.firmware.text_map[address]
            if func in HELPER_FUNCTIONS:
                return

        if self.last_func != func:
            self.last_func = func
            print("#inst", hex(address), func)

        self.last_addr = address

    def report_memory(self):
        total_size = 0
        for mem_start, mem_end, perm in self.uc.mem_regions():
            total_size += mem_end - mem_start
            print("memory:", hex(mem_start), hex(mem_end - mem_start), perm)
        print("memory total:", total_size / 1024, "kb")

    INST_SIZE = 2

    def debug_addr(self, addr, count=1, *, end="\n"):
        INST_SIZE = 4
        try:
            for inst in self.cs.disasm(
                    self.uc.mem_read(addr, INST_SIZE * count), addr,
                    count):  # type: CsInsn
                if self.firmware:
                    print(self.firmware.text_map[inst.address], end=" ")

                print(hex(inst.address),
                      hex(from_bytes(inst.bytes)),
                      inst.mnemonic,
                      inst.op_str,
                      end=end)
        except UcError as exc:
            if exc.errno == UC_ERR_READ_UNMAPPED:
                print("fail to read memory", hex(addr))

    def debug_addr_bin(self, addr, count=1):
        INST_SIZE = 4
        try:
            for inst in self.cs.disasm(
                    self.uc.mem_read(addr, INST_SIZE * count), addr,
                    count):  # type: CsInsn
                if self.firmware:
                    print(self.firmware.text_map[inst.address], end=" ")

                if len(inst.bytes) != 2:
                    raise Exception(
                        f"len(inst) != 2; {inst.bytes} => {inst.mnemonic} {inst.op_str}"
                    )

                bcode = bin(from_bytes(inst.bytes))[2:].zfill(16)
                print(hex(inst.address), bcode[0:4], bcode[4:8], bcode[8:12],
                      bcode[12:16], inst.mnemonic, inst.op_str)
        except UcError as exc:
            if exc.errno == UC_ERR_READ_UNMAPPED:
                print("fail to read memory", hex(addr))
    emu.emu_start(originalBB, 0)
    if len(decryptStatus) == 0:
        print("Decrypt correctly!")
        # Patch decryptBB jump to original BB
        if decryptBB & 1 == 1:
            ks = ks_thumb
        else:
            ks = ks_arm
        fd.seek(decryptBB & 0xFFFFFFFE)
        if originalBB - decryptBB >= 0:
            bs = ks.asm("B.W $+" + str(originalBB - decryptBB))[0]
        else:
            bs = ks.asm("B.W $" + str(originalBB - decryptBB))[0]
        for _ in bs:
            fd.write(struct.pack("B", _))
    else:
        print("Current emulating seems incorrect, so restore patched data.")
        # 逆序恢复,防止由于读写顺序错乱引起的恢复失败
        for _a, data in data_backup[::-1]:
            emu.mem_write(_a, bytes(data))

# Patch data
print("Patch data")
new_data = emu.mem_read(data_section_header.sh_addr,
                        data_section_header.sh_size)
fd.seek(data_section_header.sh_offset)
fd.write(new_data)

fd.close()
print("done!")