Esempio n. 1
0
    def setup_env(self, gdb_unix_socket_path=None):
        self.rom_addr = None
        self.arch = None
        self.setup_arch()

        self.avatar = Avatar(arch=self.arch,
                             output_directory=TEST_DIR,
                             configure_logging=False)
        self.qemu = QemuTarget(
            self.avatar,
            name='qemu_test',
            #firmware="./tests/binaries/qemu_arm_test",
            firmware='%s/firmware' % TEST_DIR,
            gdb_unix_socket_path=gdb_unix_socket_path,
        )
        self.fake_target = FakeTarget()

        dev1 = self.avatar.add_memory_range(0x101f2000,
                                            0x1000,
                                            'dev1',
                                            forwarded=True,
                                            forwarded_to=self.fake_target,
                                            qemu_name='avatar-rmemory')

        mem1 = self.avatar.add_memory_range(
            self.rom_addr,
            0x1000,
            'mem1',
            #file='%s/tests/binaries/qemu_arm_test' %
            #   os.getcwd())
            file='%s/firmware' % TEST_DIR)
Esempio n. 2
0
def setup():
    global qemu
    global avatar
    global fake_target

    arch = setup_ARCH()

    avatar = Avatar(arch=arch, output_directory=test_dir)
    qemu = QemuTarget(
        avatar,
        name='qemu_test',
        #firmware="./tests/binaries/qemu_arm_test",
        firmware='%s/firmware' % test_dir,
    )
    fake_target = FakeTarget()

    dev1 = avatar.add_memory_range(0x101f2000,
                                   0x1000,
                                   'dev1',
                                   forwarded=True,
                                   forwarded_to=fake_target,
                                   qemu_name='avatar-rmemory')

    mem1 = avatar.add_memory_range(
        rom_addr,
        0x1000,
        'mem1',
        #file='%s/tests/binaries/qemu_arm_test' %
        #   os.getcwd())
        file='%s/firmware' % test_dir)
Esempio n. 3
0
def get_qemu_target(name,
                    entry_addr,
                    firmware=None,
                    log_basic_blocks=False,
                    output_base_dir='',
                    gdb_port=1234):
    qemu_path = find_qemu()
    outdir = os.path.join(output_base_dir, 'tmp', name)
    hal_stats.set_filename(outdir + "/stats.yaml")
    avatar = Avatar(arch=ARM_CORTEX_M3, output_directory=outdir)
    print "GDB_PORT", gdb_port
    log.critical("Using qemu in %s" % qemu_path)
    qemu = avatar.add_target(QemuTarget,
                             gdb_executable="arm-none-eabi-gdb",
                             gdb_port=gdb_port,
                             qmp_port=gdb_port + 1,
                             firmware=firmware,
                             executable=qemu_path,
                             entry_address=entry_addr,
                             name=name)
    #qemu.log.setLevel(logging.DEBUG)

    if log_basic_blocks == 'irq':
        qemu.additional_args = [
            '-d', 'in_asm,exec,int,cpu,guest_errors,avatar,trace:nvic*', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]
    elif log_basic_blocks:
        qemu.additional_args = [
            '-d', 'in_asm', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]
    return avatar, qemu
Esempio n. 4
0
    def init(self,
             entry_addr,
             qemu_bin,
             qemu_args,
             verbose=False,
             interactive=False):
        self.avatar = Avatar(output_directory=AVATAR_DIR)
        self.avatar.log.setLevel('DEBUG')

        PSPEmulator.verbose = verbose
        PSPEmulator.interactive = interactive

        PSPEmulator.qemu = self.avatar.add_target(
            QemuTarget,
            name='qemu1',
            executable=qemu_bin,
            gdb_executable="arm-eabi-gdb",
            additional_args=qemu_args)
        PSPEmulator.qemu.cpu_model = 'cortex-a8'

        self.avatar.watchmen.add_watchman('RemoteMemoryRead',
                                          'before',
                                          self.before_remote_memory_access,
                                          is_async=False)
        self.avatar.watchmen.add_watchman('RemoteMemoryWrite',
                                          'before',
                                          self.before_remote_memory_access,
                                          is_async=False)

        PSPEmulator.qemu.entry_address = entry_addr
Esempio n. 5
0
def get_qemu_target(name,
                    config,
                    firmware=None,
                    log_basic_blocks=False,
                    gdb_port=1234):
    qemu_path = find_qemu()
    outdir = os.path.join('tmp', name)
    hal_stats.set_filename(outdir + "/stats.yaml")

    # Get info from config
    arch = ARCH_LUT[config.machine.arch]

    avatar = Avatar(arch=arch, output_directory=outdir)
    log.info("GDB_PORT: %s" % gdb_port)
    log.info("QEMU Path: %s" % qemu_path)

    qemu_target = QEMU_ARCH_LUT[config.machine.arch]
    qemu = avatar.add_target(qemu_target,
                             cpu_model=config.machine.cpu_model,
                             gdb_executable=config.machine.gdb_exe,
                             gdb_port=gdb_port,
                             qmp_port=gdb_port + 1,
                             firmware=firmware,
                             executable=qemu_path,
                             entry_address=config.machine.entry_addr,
                             name=name)

    if log_basic_blocks == 'irq':
        qemu.additional_args = [
            '-d', 'in_asm,exec,int,cpu,guest_errors,avatar,trace:nvic*', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]
    elif log_basic_blocks == 'regs':
        qemu.additional_args = [
            '-d', 'in_asm,exec,cpu', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]
    elif log_basic_blocks == 'exec':
        qemu.additional_args = [
            '-d', 'exec', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]
    elif log_basic_blocks == 'trace-nochain':
        qemu.additional_args = [
            '-d', 'in_asm,exec,nochain', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]
    elif log_basic_blocks == 'trace':
        qemu.additional_args = [
            '-d', 'in_asm,exec', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]

    elif log_basic_blocks:
        qemu.additional_args = [
            '-d', 'in_asm', '-D',
            os.path.join(outdir, 'qemu_asm.log')
        ]
    return avatar, qemu
Esempio n. 6
0
def init_avatar_target(ucf: Unicorefuzz, avatar: Avatar) -> Target:
    """
        初始化probe wrapper使用的target
    Init the target used by the probe wrapper.
        probe_wrapper会设置断点,导向寄存器和内存
    The probe_wrapper will set the breakpoint and forward regs and mem using this target.

    :param ucf: Unicorefuzz instance, access config using ucf.config.
    :param avatar: Initialized Avatar to add target to.
        返回一个初始化后的target
    :return: An initialized target, added to Avatar.
    """
    from avatar2 import GDBTarget

    # 调用avatar的add_target方法
    target = avatar.add_target(
        GDBTarget,
        gdb_ip=ucf.config.GDB_HOST, # gdb ip
        gdb_port=ucf.config.GDB_PORT, # gdb 端口
        gdb_executable=ucf.config.GDB_PATH, # gdb执行路径
    )

    # 初始化
    target.init()

    # 返回
    return target
Esempio n. 7
0
def setup():
    global qemu
    global avatar
    avatar = Avatar()
    qemu = QemuTarget(avatar,
                      name='qemu_test',
                      firmware="./tests/binaries/qemu_arm_test",
                      gdb_executable=GDB_EXECUTABLE,
                      executable=QEMU_EXECUTABLE)
    fake_target = FakeTarget()

    dev1 = avatar.add_memory_range(0x101f2000,
                                   0x1000,
                                   'dev1',
                                   forwarded=True,
                                   forwarded_to=fake_target,
                                   qemu_name='avatar-rmemory')

    mem1 = avatar.add_memory_range(0x8000000,
                                   0x1000,
                                   'mem1',
                                   file='%s/tests/binaries/qemu_arm_test' %
                                   os.getcwd())
Esempio n. 8
0
def setup():
    global qemu
    global avatar
    global fake_target
    avatar = Avatar(output_directory='/tmp/testava')
    qemu = QemuTarget(
        avatar,
        name='qemu_test',
        firmware="./tests/binaries/qemu_arm_test",
    )
    fake_target = FakeTarget()

    dev1 = avatar.add_memory_range(0x101f2000,
                                   0x1000,
                                   'dev1',
                                   forwarded=True,
                                   forwarded_to=fake_target,
                                   qemu_name='avatar-rmemory')

    mem1 = avatar.add_memory_range(0x8000000,
                                   0x1000,
                                   'mem1',
                                   file='%s/tests/binaries/qemu_arm_test' %
                                   os.getcwd())
Esempio n. 9
0
def init_avatar_target(ucf: Unicorefuzz, avatar: Avatar) -> Target:
    """
    Init the target used by the probe wrapper.
    The probe_wrapper will set the breakpoint and forward regs and mem using this target.
    :param ucf: Unicorefuzz instance, access config using ucf.config.
    :param avatar: Initialized Avatar to add target to.
    :return: An initialized target, added to Avatar.
    """
    from avatar2 import GDBTarget

    target = avatar.add_target(
        GDBTarget,
        gdb_ip=ucf.config.GDB_HOST,
        gdb_port=ucf.config.GDB_PORT,
        gdb_executable=ucf.config.GDB_PATH,
    )
    target.init()
    return target
Esempio n. 10
0
    def start_target(self):
        if not self.no_ykush:
            system("ykushcmd -u %d" % self.ykush_port)
            sleep(2)

        #These modes require avatar
        if self.mode > 0:
            self.avatar = Avatar(arch=ARMV7M, output_directory=self.output_dir)
            start_avatar(self.avatar, self.mode, self.binary, self.elf_file,
                         self.output_dir, self.callstack, self.callframe,
                         self.segment, self.heap_object, self.format,
                         self.stack_object, self.record, self.port)
            self.panda_log = open(self.avatar.output_directory+\
                                  '/panda_out.txt', 'r')
        if self.mode == 1:
            self.avatar.watchmen.add_watchman('RemoteMemoryRead',
                                              when='after',
                                              callback=wait_for_serial_read)
        return True
Esempio n. 11
0
def main(workdir, module=None, breakoffset=None, breakaddress=None, reset_state=True, arch="x64", gdb_port=1234):
    request_path = os.path.join(workdir, REQUEST_FOLDER)
    output_path = os.path.join(workdir, STATE_FOLDER)

    if arch != "x64":
        raise("Unsupported arch")
    if reset_state:
        try:
            shutil.rmtree(output_path)
        except:
            pass
    try:
        os.makedirs(output_path, exist_ok=True)
    except:
        pass

    if module:
        if breakaddress is not None:
            raise("Breakaddress and module supplied. They are not compatible.")
        if breakoffset is None:
            raise("Module but no breakoffset specified. Don't know where to break.")

        mem_addr = os.popen("./get_mod_addr.sh " + module).readlines()
        try:
            mem_addr = int(mem_addr[0], 16)
        except ValueError as ex:
            print("Error decoding module addr. Either module {} has not been loaded or something went wrong with ssh ({})".format(module, ex))
            exit(-1)
        print("Module " + module + " is at memory address " + hex(mem_addr))
        breakaddress = hex(mem_addr + breakoffset)
    else:
        breakaddress = hex(breakaddress)

    avatar = Avatar(arch=get_arch(arch),
                    output_directory=os.path.join(workdir, "avatar"))
    target = avatar.add_target(
        GDBTarget, gdb_port=gdb_port, gdb_executable=GDB_PATH)
    target.init()

    target.set_breakpoint("*{}".format(breakaddress))
    print("[*] Breakpoint set at {}".format(breakaddress))
    print("[+] waiting for bp hit...")
    target.cont()
    target.wait()

    print("[+] hit! dumping registers and memory")

    # dump registers
    for reg in all_regs(get_arch(arch)):
        written = True
        reg_file = os.path.join(output_path, reg)
        with open(reg_file, "w") as f:
            try:
                val = target.read_register(reg)
                if isinstance(val, list):
                    # Avatar special registers (xmm, ...)
                    i32list = val
                    val = 0
                    for shift, i32 in enumerate(i32list):
                        val += (i32 << (shift * 32))
                f.write(str(val))
            except Exception as ex:
                #print("Ignoring {}: {}".format(reg, ex))
                written = False
        if not written:
            os.unlink(reg_file)

    try:
        os.mkdir(request_path)
    except:
        pass

    forward_requests(target, workdir, request_path, output_path)
    print("[*] Initial dump complete. Listening for requests from ./harness.py.")

    i = inotify.adapters.Inotify()
    # only readily written files
    i.add_watch(request_path, mask=inotify.constants.IN_CLOSE_WRITE)
    for event in i.event_gen(yield_nones=False):
        #print("Request: ", event)
        forward_requests(target, workdir, request_path, output_path)

    print("[*] Exiting probe_wrapper (keyboard interrupt)")
Esempio n. 12
0
    def wrap_gdb_target(self, clear_state: bool = True) -> None:
        """
        Attach to a GDB target, set breakpoint, forward Memory
        :param clear_state: If the state folder should be cleared
        """
        request_path = self.requestdir
        output_path = self.statedir
        workdir = self.config.WORKDIR
        module = self.config.MODULE
        breakoffset = self.config.BREAK_OFFSET
        breakaddress = self.config.BREAK_ADDR
        arch = self.arch

        # 如果状态目录应该被清除,调用shutil.rmtree,shutil应该是一个对文件进行操作的库
        if clear_state:
            try:
                shutil.rmtree(output_path)
            except Exception:
                pass

        # 创建一个输出目录
        try:
            os.makedirs(output_path, exist_ok=True)
        except Exception:
            pass

        # 如果有模块,和断点(breakaddrss)是对立的,提供两个参数:module的基地址和断点偏移breakoffset
        # 然后在那个位置下一个断点
        if module:
            if breakaddress is not None:
                raise ValueError(
                    "Breakaddress and module supplied. They are not compatible."
                )
            if breakoffset is None:
                raise ValueError(
                    "Module but no breakoffset specified. Don't know where to break."
                )

            # 运行get_mod_addr.sh获取内存地址
            mem_addr = os.popen(
                os.path.join(self.config.UNICORE_PATH, "get_mod_addr.sh ") +
                module).readlines()
            try:
                mem_addr = int(mem_addr[0], 16)
            except ValueError as ex:
                print(
                    "Error decoding module addr. Either module {} has not been loaded or ssh is not configured ({})"
                    .format(module, ex))
                exit(-1)

            # 计算断点地址 算法:内存地址(根据get_mod_addr.sh运行的来的)+断点偏移
            print("Module " + module + " is at memory address " +
                  hex(mem_addr))
            breakaddress = hex(mem_addr + breakoffset)
        else:
            if breakaddress is None:
                raise ValueError(
                    "Neither BREAK_ADDR nor MODULE + BREAK_OFFSET specified in config.py"
                )
            # 直接由breakaddress指定的地址
            breakaddress = hex(breakaddress)

        # avatar指定实例
        avatar = Avatar(arch=arch,
                        output_directory=os.path.join(workdir, "avatar"))

        print("[*] Initializing Avatar2")
        target = self.config.init_avatar_target(self, avatar)  # type: Target

        # 设置断点
        target.set_breakpoint("*{}".format(breakaddress))
        print("[+] Breakpoint set at {}".format(breakaddress))
        print("[*] Waiting for bp hit...")

        # 两个方法,wait就是等待喽,cont不知道干什么的,需要看avatar
        target.cont()
        target.wait()

        print("[+] Breakpoint hit! dumping registers and memory")

        # dump registers

        # 大循环,读取每一个寄存器的值
        for reg in arch.reg_names:
            written = True
            reg_file = os.path.join(output_path, reg)
            with open(reg_file, "w") as f:
                try:
                    val = target.read_register(reg)
                    if isinstance(val, list):
                        # Avatar special registers (xmm, ...)
                        i32list = val
                        val = 0
                        for shift, i32 in enumerate(i32list):
                            val += i32 << (shift * 32)
                    f.write(str(val))
                except Exception as ex:
                    # print("Ignoring {}: {}".format(reg, ex))
                    written = False
            if not written:
                os.unlink(reg_file)

        # 如果请求路径不存在就创建
        if not os.path.isdir(request_path):
            print("[+] Creating request folder")
            os.mkdir(request_path)

        # 调用forward_requests 作用未知
        self.forward_requests(target, request_path, output_path)
        print(
            "[*] Initial dump complete. Listening for requests from ucf emu.")

        # inotify 作用未知(可能是监控文件行为的?)
        '''
            inotify是一种文件变化通知机制,Linux内核从2.6.13开始引入,是一种跨平台的机制,
        在Linux、BSD、windows和Mac OS系统中各有支持的组件。

        '''
        i = inotify.adapters.Inotify()
        # noinspection PyUnresolvedReferences
        # add_watch()方法  IN_CLOSE_WRITE:可写文件被关闭
        i.add_watch(request_path, mask=inotify.constants.IN_CLOSE_WRITE)
        for event in i.event_gen(yield_nones=False):
            # print("Request: ", event)
            # 又一次调用forword_requests方法
            self.forward_requests(target, request_path, output_path)

        print("[*] Exiting probe wrapper (keyboard interrupt)")
Esempio n. 13
0
    def wrap_gdb_target(self, clear_state: bool = True) -> None:
        """
        Attach to a GDB target, set breakpoint, forward Memory
        :param clear_state: If the state folder should be cleared
        """
        request_path = self.requestdir
        output_path = self.statedir
        workdir = self.config.WORKDIR
        module = self.config.MODULE
        breakoffset = self.config.BREAK_OFFSET
        breakaddress = self.config.BREAK_ADDR
        arch = self.arch

        if clear_state:
            try:
                shutil.rmtree(output_path)
            except Exception:
                pass
        try:
            os.makedirs(output_path, exist_ok=True)
        except Exception:
            pass

        if module:
            if breakaddress is not None:
                raise ValueError(
                    "Breakaddress and module supplied. They are not compatible."
                )
            if breakoffset is None:
                raise ValueError(
                    "Module but no breakoffset specified. Don't know where to break."
                )

            mem_addr = os.popen(
                os.path.join(self.config.UNICORE_PATH, "get_mod_addr.sh ") +
                module).readlines()
            try:
                mem_addr = int(mem_addr[0], 16)
            except ValueError as ex:
                print(
                    "Error decoding module addr. Either module {} has not been loaded or ssh is not configured ({})"
                    .format(module, ex))
                exit(-1)
            print("Module " + module + " is at memory address " +
                  hex(mem_addr))
            breakaddress = hex(mem_addr + breakoffset)
        else:
            if breakaddress is None:
                raise ValueError(
                    "Neither BREAK_ADDR nor MODULE + BREAK_OFFSET specified in config.py"
                )
            breakaddress = hex(breakaddress)

        avatar = Avatar(arch=arch,
                        output_directory=os.path.join(workdir, "avatar"))

        print("[*] Initializing Avatar2")
        target = self.config.init_avatar_target(self, avatar)  # type: Target

        target.set_breakpoint("*{}".format(breakaddress))
        print("[+] Breakpoint set at {}".format(breakaddress))
        print("[*] Waiting for bp hit...")
        target.cont()
        target.wait()

        print("[+] Breakpoint hit! dumping registers and memory")

        # dump registers
        for reg in arch.reg_names:
            written = True
            reg_file = os.path.join(output_path, reg)
            with open(reg_file, "w") as f:
                try:
                    val = target.read_register(reg)
                    if isinstance(val, list):
                        # Avatar special registers (xmm, ...)
                        i32list = val
                        val = 0
                        for shift, i32 in enumerate(i32list):
                            val += i32 << (shift * 32)
                    f.write(str(val))
                except Exception as ex:
                    # print("Ignoring {}: {}".format(reg, ex))
                    written = False
            if not written:
                os.unlink(reg_file)

        if not os.path.isdir(request_path):
            print("[+] Creating request folder")
            os.mkdir(request_path)

        self.forward_requests(target, request_path, output_path)
        print(
            "[*] Initial dump complete. Listening for requests from ucf emu.")

        i = inotify.adapters.Inotify()
        # noinspection PyUnresolvedReferences
        i.add_watch(request_path, mask=inotify.constants.IN_CLOSE_WRITE)
        for event in i.event_gen(yield_nones=False):
            # print("Request: ", event)
            self.forward_requests(target, request_path, output_path)

        print("[*] Exiting probe wrapper (keyboard interrupt)")
Esempio n. 14
0
from time import sleep
from avatar2 import Avatar, ARMV7M, OpenOCDTarget, PandaTarget

avatar = Avatar(arch=ARMV7M, output_directory='/tmp/panda_rr')
avatar.load_plugin('orchestrator')

nucleo = avatar.add_target(OpenOCDTarget,
                           openocd_script='nucleo-l152re.cfg',
                           gdb_executable="arm-none-eabi-gdb",
                           gdb_port=1234)

panda = avatar.add_target(PandaTarget,
                          executable='panda/qemu-system-arm',
                          gdb_executable="arm-none-eabi-gdb",
                          gdb_port=1235)

rom = avatar.add_memory_range(0x08000000,
                              0x1000000,
                              'rom',
                              file='firmware.bin')

ram = avatar.add_memory_range(0x20000000, 0x14000, 'ram')
mmio = avatar.add_memory_range(0x40000000,
                               0x1000000,
                               'mmio',
                               forwarded=True,
                               forwarded_to=nucleo)

avatar.init_targets()

avatar.start_target = nucleo
Esempio n. 15
0
from avatar2 import Avatar, ARMV7M, OpenOCDTarget
from IPython import embed

main_addr = 0xD270

avatar = Avatar(output_directory='/tmp/harvey', arch=ARMV7M)
avatar.load_plugin('assembler')

t = avatar.add_target(OpenOCDTarget,
                      openocd_script='plc.cfg',
                      gdb_executable='arm-none-eabi-gdb')

t.init()

t.set_breakpoint(main_addr)
t.cont()
t.wait()

t.inject_asm('b 0x2000250E', addr=0x20001E2E)
t.inject_asm('mov r5,0xfffffffc\n b 0x20001E30', addr=0x2000250E)

t.inject_asm('b 0x20002514', addr=0x20002338)
t.inject_asm('mov r5,0xfffffffd\n mov r4, r5 \n mov r5, 0\nb 0x2000233E',
             addr=0x20002514)

t.cont()
embed()
Esempio n. 16
0
class QemuTargetTestCase(unittest.TestCase):
    def setUp(self):
        self.setup_env()

    def setup_env(self, gdb_unix_socket_path=None):
        self.rom_addr = None
        self.arch = None
        self.setup_arch()

        self.avatar = Avatar(arch=self.arch,
                             output_directory=TEST_DIR,
                             configure_logging=False)
        self.qemu = QemuTarget(
            self.avatar,
            name='qemu_test',
            #firmware="./tests/binaries/qemu_arm_test",
            firmware='%s/firmware' % TEST_DIR,
            gdb_unix_socket_path=gdb_unix_socket_path,
        )
        self.fake_target = FakeTarget()

        dev1 = self.avatar.add_memory_range(0x101f2000,
                                            0x1000,
                                            'dev1',
                                            forwarded=True,
                                            forwarded_to=self.fake_target,
                                            qemu_name='avatar-rmemory')

        mem1 = self.avatar.add_memory_range(
            self.rom_addr,
            0x1000,
            'mem1',
            #file='%s/tests/binaries/qemu_arm_test' %
            #   os.getcwd())
            file='%s/firmware' % TEST_DIR)

    def setup_arch(self):

        ARCH = os.getenv('AVATAR2_ARCH')

        if ARCH == 'ARM':
            self.arch = ARM
            self.rom_addr = ARM_BASE_ADDR
            firmware = ARM_BIN

        elif ARCH == 'MIPS':
            self.arch = MIPS_24KF
            self.rom_addr = MIPS_BASE_ADDR
            firmware = MIPS_BIN

        else:
            self.assertTrue(False, 'Invalid Achitecture')

        if not os.path.exists(TEST_DIR): os.makedirs(TEST_DIR)
        with open('%s/firmware' % TEST_DIR, 'wb') as f:
            f.write(firmware)

    def tearDown(self):
        self.qemu.shutdown()

    def test_initilization(self):
        self.qemu.init()
        self.qemu.wait()
        self.assertEqual(self.qemu.state, TargetStates.STOPPED,
                         self.qemu.state)

    def test_step(self):
        self.qemu.init()
        self.qemu.wait()

        self.qemu.regs.pc = self.rom_addr
        self.qemu.step()

        pc = self.qemu.regs.pc
        self.assertEqual(pc, self.rom_addr + 4, pc)

    def test_memory_read(self):
        self.qemu.init()
        self.qemu.wait()

        mem = self.qemu.read_memory(self.rom_addr, 4)

        if self.arch == ARM:
            self.assertEqual(mem, 0xe3a0101e, mem)

        elif self.arch == MIPS_24KF:
            #self.assertEqual(mem, 0x2409001e, mem)
            self.assertEqual(mem, 0x1e000924, mem)
        else:
            self.assertTrue(False, "Architecture not supported")

    def test_memory_write(self):
        self.qemu.init()
        self.qemu.wait()

        self.qemu.write_memory(self.rom_addr, 4, 0x41414141)
        mem = self.qemu.read_memory(self.rom_addr, 4)
        self.assertEqual(mem, 0x41414141, mem)

    def test_remote_memory_write(self):
        self.qemu.init()
        self.qemu.wait()
        remote_memory_write = self.qemu.write_memory(0x101f2000, 4, 0x41414141)
        self.assertEqual(remote_memory_write, True)

        addr = self.fake_target.fake_write_addr
        size = self.fake_target.fake_write_size
        val = self.fake_target.fake_write_val
        self.assertEqual(addr, 0x101f2000, addr)
        self.assertEqual(size, 4, size)
        self.assertEqual(val, 0x41414141, val)

    def test_remote_memory_read(self):
        self.qemu.init()
        self.qemu.wait()
        self.assertEqual(self.qemu.state, TargetStates.STOPPED,
                         self.qemu.state)

        remote_memory_read = self.qemu.read_memory(0x101f2000, 4)
        self.assertEqual(remote_memory_read, 0xdeadbeef, remote_memory_read)
Esempio n. 17
0
# Command to start jTrace
# /opt/SEGGER/JLink/JLinkGDBServer -endian little -localhostonly -device STM32F479NI -if SWD

if __name__ == '__main__':
    from argparse import ArgumentParser
    p = ArgumentParser()
    p.add_argument("-e", '--elf', required=True, help='Elf file to profile')
    p.add_argument("-f",
                   '--functions',
                   required=True,
                   help='YAML file listing functions')
    p.add_argument("-d", '--db', help='sqlite3 database filename')
    args = p.parse_args()

    avatar = Avatar(arch=ARM_CORTEX_M3, output_directory='/tmp/hal_profile')
    gdb = avatar.add_target(GDBTarget,
                            gdb_additional_args=[args.elf],
                            gdb_executable="arm-none-eabi-gdb",
                            gdb_port=2331)

    avatar.watchmen.add_watchman('BreakpointHit',
                                 'before',
                                 handle_bp,
                                 is_async=True)
    avatar.init_targets()

    memories = [(0x20000000, 0x50000)]
    if args.db == None:
        db = os.path.splitext(args.elf)[0] + ".sqlite"
    else:
Esempio n. 18
0
class PSPEmulator():

    custom_memory = bytearray(2**32)

    accessed_mem = {}

    verbose = True

    interactive = False

    ccp_cmd = {"process": False, "start": 0x0, "end": 0x0}
    qemu = None

    def __init__(self):
        self.avatar = None
        self.close = False
        self.trace_parse = None
        self.trace_file = None
        self.ignored_addresses = set()

    def init(self,
             entry_addr,
             qemu_bin,
             qemu_args,
             verbose=False,
             interactive=False):
        self.avatar = Avatar(output_directory=AVATAR_DIR)
        self.avatar.log.setLevel('DEBUG')

        PSPEmulator.verbose = verbose
        PSPEmulator.interactive = interactive

        PSPEmulator.qemu = self.avatar.add_target(
            QemuTarget,
            name='qemu1',
            executable=qemu_bin,
            gdb_executable="arm-eabi-gdb",
            additional_args=qemu_args)
        PSPEmulator.qemu.cpu_model = 'cortex-a8'

        self.avatar.watchmen.add_watchman('RemoteMemoryRead',
                                          'before',
                                          self.before_remote_memory_access,
                                          is_async=False)
        self.avatar.watchmen.add_watchman('RemoteMemoryWrite',
                                          'before',
                                          self.before_remote_memory_access,
                                          is_async=False)

        PSPEmulator.qemu.entry_address = entry_addr

    def load_file(self, address, mem_size, filename, offset, file_size):
        self.avatar.add_memory_range(address,
                                     mem_size,
                                     file=filename,
                                     file_offset=offset,
                                     file_bytes=file_size)

    def load_custom_mem(self, address, filename, offset=0, size=0):
        f = open(filename, 'rb')
        if offset != 0:
            f.seek(offset)

        if size != 0:
            data = f.read(size)
        else:
            data = f.read()

        self.custom_memory[address:address + len(data)] = data

    def add_memory_range(self, start, end, permissions='rw-'):
        if ((end - start) % 0x1000) != 0:
            print("[PSPEmulator] ERROR: memory ranges must be page aligned"
                  "(0x%.8x)" % start)
        self.avatar.add_memory_range(start,
                                     end - start,
                                     permission=permissions)

    def set_memory_value(self, address, value, size=4):
        if size != 1 and size != 4:
            print("[PSPEmulator] ERROR: Only 1 or 4 bytes are supported")
            return

        if size == 1:
            PSPEmulator.custom_memory[address] = value
        elif size == 4:
            bval = (value).to_bytes(4, byteorder='big')
            PSPEmulator.custom_memory[address] = bval[0]
            PSPEmulator.custom_memory[address + 1] = bval[1]
            PSPEmulator.custom_memory[address + 2] = bval[2]
            PSPEmulator.custom_memory[address + 3] = bval[3]

    def qemu_init(self):
        PSPEmulator.qemu.init()

    def set_breakpoint(self, address):
        PSPEmulator.qemu.set_breakpoint(address)

    def watch_memory_range(self, start, end, permissions='rw-'):
        if ((end - start) % 0x1000) != 0:
            print("[PSPEmulator] ERROR: watched memory ranges must be page"
                  "aligned (0x%.8x)" % start)
            return
        self.avatar.add_memory_range(start,
                                     end - start,
                                     emulate=CustomMemoryPeripheral,
                                     permission=permissions)

    def add_virtual_ccp(self, address):
        if not PSPEmulator.qemu:
            print("[PSPEmulator] ERROR: PSPEmulator not initialized yet. Call"
                  "init() first")
            return
        self.avatar.add_memory_range(address,
                                     0x1000,
                                     emulate=VirtualCCP,
                                     permission='rw-')
        # self.ignored_addresses.add(address)

    def add_misc_dev(self, address):
        if not PSPEmulator.qemu:
            print("[PSPEmulator] ERROR: PSPEmulator not initialized yet. Call"
                  "init() first")
            return
        self.avatar.add_memory_range(address,
                                     0x1000,
                                     emulate=VirtMisc,
                                     permission='rw-')

    def add_virtual_timer(self, address):
        if not PSPEmulator.qemu:
            print("[PSPEmulator] ERROR: PSPEmulator not initialized yet. Call"
                  "init() first")
            return
        self.avatar.add_memory_range(address,
                                     0x1000,
                                     name="VirtualTimer",
                                     emulate=VirtualTimer,
                                     permission='rw-')
        # self.ignored_addresses.add(address)

    def watch_memory(self, address=None, size=None):
        # TODO: Automatically configure "remaining", i.e. not yet configured
        #       memory ranges to be backed by our CustomMemoryPeripheral
        print(self.avatar.memory_ranges)
        for interval in self.avatar.memory_ranges:
            print("0x%x 0x%x" % (interval.begin, interval.end))

    def __del__(self):
        self.avatar.shutdown()
        if self.trace_file and self.trace_parse:
            command = 'python2.7 %s %s /tmp/trace > /tmp/parsed' % \
                      (self.trace_parse, self.trace_file)
            print("[PSPEmulator] Calling %s" % command)
            os.system(command)

    def exit(self):
        self.close = True
        self.__del__()

    def disconnect_gdb(self):
        PSPEmulator.qemu.gdb.remote_disconnect()

    def connect_gdb(self):
        PSPEmulator.qemu.gdb.remote_connect()

    def run(self):
        while not self.close:
            if PSPEmulator.qemu.state != TargetStates.EXITED:
                PSPEmulator.qemu.cont()
            PSPEmulator.qemu.wait(TargetStates.EXITED | TargetStates.STOPPED)
            if PSPEmulator.qemu.state == TargetStates.STOPPED:
                if PSPEmulator.ccp_cmd["process"] is True:
                    print("[ccp_dev] Parsing new cmd at pc=0x%.8x" %
                          PSPEmulator.qemu.read_register("pc"))
                    self.print_ccp_cmds(PSPEmulator.ccp_cmd["start"],
                                        PSPEmulator.ccp_cmd["end"])
                    PSPEmulator.ccp_cmd["process"] = False
                else:
                    embed(banner1="QEMU entered STOPPED state at pc=0x%.8x" %
                          PSPEmulator.qemu.read_register("pc"))
            else:
                print("[PSPEmulator] Qemu exited with state: %s" %
                      str(PSPEmulator.qemu.state))
                self.exit()

    def print_ccp_cmds(self, start, end):

        cmds = (end - start) // 0x20
        for e in range(0x0, cmds):
            dwords = [
                PSPEmulator.qemu.read_memory(i, 0x4)
                for i in range(start + (e * 0x20), start + (e * 0x20) +
                               0x20, 0x4)
            ]
            print("\n[ccp_dev] Processing ccp cmd %d" % e)
            cmt, engine = ccp_parse.parse_dword0(dwords[0])
            print("[ccp_dev]\t %s" % cmt)
            print("[ccp_dev]\t Length of src data 0x%x" % dwords[1])
            print("[ccp_dev]\t Src ptr 0x%x" % dwords[2])
            print("[ccp_dev]\t %s" % ccp_parse.parse_dword3(dwords[3]))
            print("[ccp_dev]\t %s" % ccp_parse.parse_dword4(engine, dwords[4]))
            print("[ccp_dev]\t %s" % ccp_parse.parse_dword5(engine, dwords[5]))
            print("[ccp_dev]\t Low 32bit key ptr: 0x%x" % dwords[6])
            print("[ccp_dev]\t High 16bit key ptr + mem type: 0x%x" %
                  dwords[7])
            print()

    def swap32(i):
        return struct.unpack("<I", struct.pack(">I", i))[0]

    def enable_tracing(self, trace_parse, trace_file):
        self.trace_file = trace_file
        self.trace_parse = trace_parse
        PSPEmulator.qemu.qmp.execute_command('trace-event-set-state', {
            'name': 'exec_tb',
            'enable': True
        })
        PSPEmulator.qemu.qmp.execute_command('trace-event-set-state', {
            'name': 'guest_mem_before_exec',
            'enable': True
        })

    def before_remote_memory_access(self, avatar, remote_memory_msg, **kwargs):
        address = remote_memory_msg.address
        pc = remote_memory_msg.pc

        # Ignore pages belonging to emulated devices
        if (address & 0xFFFFF000) in self.ignored_addresses:
            return

        read_or_write = ''
        if isinstance(remote_memory_msg, RemoteMemoryReadMessage):
            read_or_write = 'read'
        else:  # if isinstance(remote_memory_msg, RemoteMemoryWriteMessage):
            read_or_write = 'write'

        # if not PSPEmulator.ccp_cmd["process"]:
        #     print('[custom_memory] New %s at 0x%.8x from PC: 0x%.8x' % (read_or_write, address, pc))

        if address not in PSPEmulator.accessed_mem:
            PSPEmulator.accessed_mem[address] = set()

        # print("BeforeMemaccess: pc 0x%.8x addr 0x%.8x" % (pc, address))

        PSPEmulator.accessed_mem[address].add((pc, read_or_write))

    def print_custom_memory(self):
        for i in PSPEmulator.accessed_mem:
            val = int.from_bytes(PSPEmulator.custom_memory[i:i + 4], 'little')
            print('\t0x%.8x: \t0x%.8x \taccessed_by: %s' %
                  (i, val,
                   repr([
                       v[1] + ':' + hex(v[0])
                       for v in PSPEmulator.accessed_mem[i]
                   ])))