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
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
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
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
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)")
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
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] ])))
# /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: db = args.db Recorder = State_Recorder(db, gdb, memories, args.elf)
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()