예제 #1
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]
                   ])))
예제 #2
0
                            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:
        db = args.db

    Recorder = State_Recorder(db, gdb, memories, args.elf)

    with open(args.functions, 'rb') as infile:
        functions = yaml.safe_load(infile)

    for f in functions:
        print "Setting Breakpoint: ", f
        Recorder.add_function(f)
    gdb.protocols.execution.console_command('load')
    gdb.protocols.execution.console_command('monitor reset')
    gdb.cont()
    embed()
    gdb.stop()
    avatar.shutdown()