def init(self, **kwargs): from pandare import Panda arch = self.avatar.arch.qemu_name args = self.assemble_cmd_line()[1:] self.avatar.save_config(file_name=self.qemu_config_file, config=self.generate_qemu_config()) self.pypanda = Panda(arch=arch, extra_args=args, **kwargs) # adjust panda's signal handler to avatar2-standard def SigHandler(SIG, a, b): if self.state == TargetStates.RUNNING: self.stop() self.wait() self.avatar.sigint_handler() self.pypanda._setup_internal_signal_handler(signal_handler=SigHandler) self._thread = Thread(target=self.pypanda.run, daemon=True) self._thread.start() self._connect_protocols()
It then replays the recording and uses virt mem callbacks to find strings written into memory. Run with: python3 extract_memstrings.py ''' from sys import argv from string import ascii_letters from os import remove, path from pandare import Panda # Single arg of arch, defaults to i386 arch = "i386" if len(argv) <= 1 else argv[1] panda = Panda(generic=arch) # Make sure we're always saving a new recording recording_name = "mem_test.recording" for f in [recording_name+"-rr-nondet.log", recording_name+"-rr-snp"]: if path.isfile(f): remove(f) @panda.queue_blocking def my_record_cmd(): # Run a non-deterministic command at the root snapshot, then end .run() panda.record_cmd("wget google.com", recording_name=recording_name) panda.stop_run() print("Take recording...") panda.run() print("Analyze replay...")
#!/usr/bin/env python3 # Demonstartion of using PANDA to run shellcode. Example modified from Unicorn Engine # https://github.com/unicorn-engine/unicorn/blob/master/bindings/python/sample_arm.py import capstone import os from pandare import Panda X86_CODE = b"\x40\x01\xC3\x41" # inc eax; add ebx, eax; inc ecx; ADDRESS = 0x1000 stop_addr = ADDRESS + len(X86_CODE) # Create a machine of type 'configurable' but with just a CPU specified (no peripherals or memory maps) panda = Panda("i386", extra_args=["-M", "configurable", "-nographic"]) @panda.cb_after_machine_init def setup(cpu): ''' After our CPU has been created, allocate memory and set starting state ''' # map 2MB memory for this emulation panda.map_memory("mymem", 2 * 1024 * 1024, ADDRESS) # Write code into memory panda.physical_memory_write(ADDRESS, X86_CODE) # Set up registers panda.arch.set_reg(cpu, "EAX", 0x1) panda.arch.set_reg(cpu, "EBX", 0x2)
#!/usr/bin/env python3 # Take a recording, then replay and analyze from os import remove, path from pandare import Panda, blocking arch = "i386" panda = Panda(generic=arch) # Make sure we're always saving a new recording recording_name = "test.recording" for f in [recording_name + "-rr-nondet.log", recording_name + "-rr-snp"]: if path.isfile(f): remove(f) @blocking def record_nondet( ): # Run a non-deterministic command at the root snapshot, then end .run() panda.record_cmd("date; cat /dev/urandom | head -n1 | md5sum", recording_name=recording_name) panda.stop_run() # Collect BBs during both recording and then replay validate that our replay is good in_replay = False orig_blocks = set() replay_blocks = set() @panda.cb_before_block_exec() def before_block_exec(env, tb): # At each BB's execution in 'find', ensure translation is cached and add to executed_pcs
print("Saw PASSWD - switch modes") self.set_mode("mode2") @self.panda.ppp("syscalls2", "on_sys_open_enter") @self.mode_filter("mode2") def on_open2(cpu, pc, fname_ptr, flags, mode): assert self.mode == "mode2" try: fname = self.panda.read_str(cpu, fname_ptr) except ValueError: return if fname == "/proc/cpuinfo": print("SAW CPUINFO - switch modes") self.set_mode("end") # End PANDA-decorated functions in init def run_guest(self): ''' Run guest ''' self.panda.run() if __name__ == "__main__": panda = Panda(generic="i386") test = Tester(panda) test.run_guest()
#!/usr/bin/env python3 from pandare import Panda, blocking, ffi panda = Panda(generic="x86_64") panda.load_plugin("syscalls2") panda.load_plugin("osi") @panda.ppp("syscalls2", "on_sys_read_return") def on_sys_read_return(cpu, pc, fd, buf, count): proc = panda.plugins['osi'].get_current_process(cpu) procname = ffi.string(proc.name) if proc != ffi.NULL else "error" fname_ptr = panda.plugins['osi_linux'].osi_linux_fd_to_filename(cpu, proc, fd) fname = ffi.string(fname_ptr) if fname_ptr != ffi.NULL else "error" rc = panda.plugins['syscalls2'].get_syscall_retval(cpu) print(f"[PANDA] {procname} read {rc} bytes from {fname}") @panda.ppp("syscalls2", "on_sys_execve_enter") def on_sys_execve_enter(cpu, pc, fname_ptr, argv_ptr, envp): # Log commands and arguments passed to execve unless in kernel if panda.in_kernel(cpu): return try: fname = panda.read_str(cpu, fname_ptr) argv_ptrlist = panda.virtual_memory_read(cpu, argv_ptr, 100, fmt='ptrlist') except ValueError: return argv = [] for ptr in argv_ptrlist: if ptr == 0: break try: argv.append(panda.read_str(cpu, ptr))
import capstone import angr import claripy import struct import logging from pandare import Panda, blocking from io import BytesIO from ipdb import set_trace as d logging.basicConfig( format='%(levelname)-7s | %(asctime)-23s | %(name)-8s | %(message)s') logger = logging.getLogger('angrypanda') logger.setLevel('DEBUG') panda = Panda(generic="i386") md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32) buffer_addr = None # Dynamically identified, address of buffer returned from malloc found_input = None # Dynamically computed during first run # Settings - It would be better do do these using line numbers but good enough for this PoC BUFFER_SET = 0x8048557 # After malloc (add esp, 0x10) START_ANGR = 0x804859e # After printf buffer contains (add esp, 0x10) FIND_ADDR = 0x80485e5 # Before print success (push eax=>s_success) AVOID = 0x80485f9 # Before print failure (push eax=>failure) END_MAIN = 0x8048611 # Main's ret (ret) def angr_insn_exec(state): """
# particular pc (0xc101dfec) which we only knew about bc we ran qemu -d # in_asm before. At this pc we take a snapshot. This callback actually # contains a little state machine. After we have taken the snapshot, we # are in state 3, where we increment a counter with each call, i.e. for # each new basic block we execute. After 10 blocks, we revert to the # snapshot at 0xc101dfec. # # Obviously there are more interesting uses for this kind of thing. Two # important things to notice. First, we can take a snapshot that will # in fact revert to a specific block's start pc. Second, when we # revert, we don't keep executing any code. We snap back to exactly # that bloc. # Single arg of arch, defaults to i386 arch = "i386" if len(argv) <= 1 else argv[1] panda = Panda(generic=arch) state = 0 # before snapshot load @blocking def init(): global state panda.delvm_sync("newroot") panda.revert_sync("root") state = 1 nt = 0 blocks = [] @panda.cb_before_block_exec() def before_block_exec(env,tb):
j .end nop .end: addiu $t1, 1 # t1++ """ ks = keystone.Ks(keystone.KS_ARCH_MIPS, keystone.KS_MODE_MIPS32) #ks = keystone.Ks(keystone.KS_ARCH_MIPS, keystone.KS_MODE_MIPS32 + KS_MODE_BIG_ENDIAN) ADDRESS = 0x1000 encoding, count = ks.asm(CODE, ADDRESS) stop_addr = ADDRESS + len(encoding) panda = Panda("mipsel", extra_args=["-M", "configurable", "-nographic"], raw_monitor=True) @panda.cb_after_machine_init def setup(cpu): ''' After our CPU has been created, allocate memory and set starting state ''' # map 2MB memory for this emulation panda.map_memory("mymem", 2 * 1024 * 1024, ADDRESS) # Write code into memory panda.physical_memory_write(ADDRESS, bytes(encoding)) # Set up registers
#!/usr/bin/env python3 from sys import argv from pandare import Panda, blocking # Record some programs running in the guest # for some programs, register python callbacks # Single arg of arch, defaults to i386 arch = "i386" if len(argv) <= 1 else argv[1] panda = Panda(generic=arch) # Python plugin- collect a set of unique basic blocks seen seen_bbs = set() @panda.cb_before_block_exec(enabled=False) def bbe(env, tb): pc = panda.current_pc(env) global seen_bbs seen_bbs.add(pc) # Run ls with c plugin loaded @blocking def record_ls(): print("Recording run of `ls` with C callback") # Load c plugin panda.require("coverage") panda.record_cmd("ls /", recording_name="ls") panda.unload_plugin("coverage") panda.stop_run() # Return control flow
#!/usr/bin/env python3 from sys import argv from pandare import Panda # Record some programs running in the guest # for some programs, register python callbacks # Single arg of arch, defaults to i386 arch = "x86_64" if len(argv) <= 1 else argv[1] extra = "-nographic -chardev socket,id=monitor,path=./monitor.sock,server,nowait -monitor chardev:monitor -serial telnet:127.0.0.1:4444,server,nowait -device e1000,netdev=net0 -netdev user,id=net0,hostfwd=tcp::5555-:22 -cdrom /home/luke/workspace/qcows/instance-1-cidata.iso" qcow = "/home/luke/workspace/qcows/instance-1.qcow2" panda = Panda(arch=arch,qcow=qcow,extra_args=extra,mem="1G") panda.set_os_name("linux-64-ubuntu") panda.require("syscalls2") cb_name = "on_sys_read_return" cb_args = "CPUState *, target_ulong, uint32_t, uint64_t, uint32_t" ffi.cdef(f"void ppp_add_cb_{cb_name}(void (*)({cb_args}));") @ffi.callback(f"void({cb_args})") def on_sys_read_return(cpustate, pc, fd, buf, count): vmlinux = panda.get_volatility_symbols() import pdb pdb.set_trace() panda.plugins["syscalls2"].__getattr__(f"ppp_add_cb_{cb_name}")(on_sys_read_return) cb_name = "on_sys_read_enter" cb_args = "CPUState *, target_ulong, uint32_t, uint64_t, uint32_t" ffi.cdef(f"void ppp_add_cb_{cb_name}(void (*)({cb_args}));")
#!/usr/bin/env python3 # Take a recording, then replay with analysis, then revert vm and run more commands from sys import argv from os import remove, path from pandare import Panda, blocking # Default arch is i386, but others can be used arch = argv[1] if len(argv) > 1 else "i386" panda = Panda(generic=arch) # Make sure we're always saving a new recording recording_name = "test.recording" for f in [recording_name + "-rr-nondet.log", recording_name + "-rr-snp"]: if path.isfile(f): remove(f) successes = [False, False] ####################### Recording #################### @blocking def record_nondet( ): # Run a non-deterministic command at the root snapshot, then end .run() panda.record_cmd("date; cat /dev/urandom | head -n30 | md5sum", recording_name=recording_name) global successes successes[0] = True panda.stop_run() # Collect BBs during both recording and then replay validate that our replay is good in_replay = False
from pandare import Panda from os import remove, path from sys import argv # Default arch is i386, but others can be used arch = argv[1] if len(argv) > 1 else "i386" panda = Panda(generic=arch) # Make sure we're always saving a new recording recording_name = f"filetaint-{arch}.recording" for f in [recording_name+"-rr-nondet.log", recording_name+"-rr-snp"]: if path.isfile(f): remove(f) success = False @panda.queue_blocking def driver(): panda.record_cmd("cat /etc/passwd | wc -l", recording_name=recording_name) panda.end_analysis() panda.run() # take recording @panda.ppp("taint2", "on_taint_change") def taint_change(*args): global success success = True panda.end_analysis() panda.load_plugin("file_taint", {"filename": "/etc/passwd"}) panda.run_replay(recording_name)
matches we taint the resulting data. Lastly, we use syscalls2 to monitor sys_sendto for network traffic. We must check each byte in the packet to check if it is tainted and we alert if it is tainted. ''' from sys import argv from os import path from pandare import Panda, blocking, ffi arch = "x86_64" if len(argv) <= 1 else argv[1] extra = "-nographic" #qcow = "/home/luke/workspace/qcows/instance-1.qcow2" #panda = Panda(arch=arch, qcow=qcow, extra_args=extra, mem="1G") panda = Panda(generic=arch) interesting_file_name = b"panda.panda2" panda.set_os_name("linux-64-ubuntu") panda.load_plugin("callstack_instr", args={"stack_type": "asid"}) panda.require("syscalls2") cb_name = "on_sys_read_return" cb_args = "CPUState *, target_ulong, uint32_t, uint64_t, uint32_t" ffi.cdef(f"void ppp_add_cb_{cb_name}(void (*)({cb_args}));") file_info = None @ffi.callback(f"void({cb_args})")
#!/usr/bin/env python3 # Take a recording, then replay with analysis, then revert vm and run more commands from sys import argv from os import remove, path from pandare import Panda # Default arch is i386, but others can be used arch = argv[1] if len(argv) > 1 else "i386" panda = Panda(generic=arch) # Make sure we're always saving a new recording recording_name = "test.recording" for f in [recording_name+"-rr-nondet.log", recording_name+"-rr-snp"]: if path.isfile(f): remove(f) successes = [False, False] ####################### Recording #################### @panda.queue_blocking def record_nondet(): # Run a non-deterministic command at the root snapshot, then end .run() panda.record_cmd("date; cat /dev/urandom | head -n30 | md5sum", recording_name=recording_name) global successes successes[0] = True panda.stop_run() # Collect BBs during both recording and then replay validate that our replay is good in_replay = False orig_blocks = set() replay_blocks = set() @panda.cb_before_block_exec() def before_block_exec(env, tb):
#!/usr/bin/env python3 from sys import argv from os import path, remove from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection from pandare import Panda # Single arg of arch, defaults to i386 arch = "i386_wheezy" if len(argv) <= 1 else argv[1] panda = Panda(generic=arch) bin_dir = "taint" bin_name = "taint" assert (path.isfile(path.join(bin_dir, bin_name))), "Missing file {}".format( path.join(bin_dir, bin_name)) # Take a recording of toy running in the guest if necessary recording_name = bin_dir + "_" + bin_name # Debug - delete recording each time if path.isfile(recording_name + "-rr-snp"): remove(recording_name + "-rr-snp") remove(recording_name + "-rr-nondet.log") if not path.isfile(recording_name + "-rr-snp"): @panda.queue_blocking def run_it(): panda.record_cmd(f"./taint/taint", copy_directory=bin_dir,
Retrieve ioctl that completed normally ''' return self._get_returns(self._unmodified_returns, with_buf_only) if __name__ == "__main__": ''' Bash will issue ioctls on /dev/ttys0 - this is just a simple test to make sure they're being captured ''' from pandare import blocking, Panda # No arguments, i386. Otherwise argument should be guest arch generic_type = sys.argv[1] if len(sys.argv) > 1 else "i386" panda = Panda(generic=generic_type) def print_list_elems(l): if not l: print("None") else: for e in l: print(e) @blocking def run_cmd(): # Setup faker ioctl_faker = IoctlFaker(panda, use_osi_linux=True)
''' volatility pslist two ways. By: Luke Craig ''' from pandare import Panda, blocking from sys import argv from time import time from volatility.framework.objects import utility arch = "x86_64" if len(argv) <= 1 else argv[1] extra = "-nographic -chardev socket,id=monitor,path=./monitor.sock,server,nowait -monitor chardev:monitor -serial telnet:127.0.0.1:4444,server,nowait" qcow = "/home/luke/workspace/qcows/instance-1.qcow2" panda = Panda(arch=arch, qcow=qcow, extra_args=extra, mem="1G") timechange = 5 oldtime, oldtime2 = time(), time() ''' In on_asid_change we use the fast method. It gives us back the volatility symbols and we "become" the volatility plugin. The reason this is fast is because we clear the cache between runs so we don't have to reconstruct the whole plugin again. This way we only have to run the 10+ second startup once. ''' @panda.cb_asid_changed() def on_asid_change(env, old_asid, new_asid): global oldtime if time() - oldtime > timechange: vmlinux = panda.get_volatility_symbols(debug=True) init_task = vmlinux.object_from_symbol(symbol_name="init_task")
#!/usr/bin/env python3 from pandare import Panda panda = Panda(generic='x86_64') @panda.queue_blocking def driver(): ''' Asynchronous function that drives guest behavior after PANDA starts Load a snapshot where we're logged in, then copy the contents of ./copy into the guest, ensure ls is executable, then load the trace plugin and run ls. When ls completes, end the analysis ''' panda.revert_sync("root") # Revert to snapshot panda.copy_to_guest("copy") # Copy directory into guest print(panda.run_serial_cmd("chmod +x ./copy/ls")) # Ensure executable panda.load_plugin("trace", { 'log': f'example_trace.txt', 'target': 'ls' }) # Trace program named ls print(panda.run_serial_cmd("./copy/ls")) # Run ls panda.end_analysis() # We're finished here @panda.ppp("proc_start_linux", "on_rec_auxv") def proc_start(cpu, tb, auxv): procname = panda.ffi.string(auxv.argv[0]).decode( errors='ignore') if auxv.argv[0] != panda.ffi.NULL else "(error)"
# Close all open hfds if len(self.hooked_fds): self.ff_logger.debug("Cleaning up open hyper file descriptors") for (fd, asid) in list(self.hooked_fds.keys()): self.hooked_fds[(fd, asid)].close() del self.hooked_fds[(fd, asid)] def __del__(self): # XXX: This isn't being called for some reason on destruction self.close() if __name__ == '__main__': from pandare import Panda panda = Panda(generic="x86_64") # Replace all syscalls that reference /foo with a custom string fake_str = "Hello world. This is data generated from python!" faker = FileFaker(panda) faker.replace_file("/foo", FakeFile(fake_str)) @panda.queue_blocking def driver(): new_str = "This is some new data" panda.revert_sync('root') data = panda.run_serial_cmd( "cat /foo" ) # note run_serial_cmd must end with a blank line and our fake file doesn't assert (fake_str in data), f"Failed to read fake file /foo: {data}"
def runner(generic_name): ''' Try to run a single generic image First run via CLI - load root snapshot, run a command and quit - check command output Then test via python to see if OSI works ''' from pandare import Panda data = SUPPORTED_IMAGES[generic_name] qcow_path = Qcows.get_qcow(generic_name) # Check 1 - can we load with CLI assert(os.path.isfile(qcow_path)), f"Can't find qcow for {generic_name}" # Start panda with a 10s timeout and background it # then sleep 1s, connect to the serial port via telnet, run a command and capture output # then shutdown panda via monitor and check if output matches expected value cmd = f"timeout 10s panda-system-{data.arch} -loadvm {data.snapshot} -m {data.default_mem} {qcow_path} \ {data.extra_args} -serial telnet:localhost:4321,server,nowait \ -monitor unix:/tmp/panda.monitor,server,nowait & \ sleep 2; RES=$(echo 'whoami' | nc localhost 4321) && (echo 'q' | nc -q1 -U /tmp/panda.monitor || true) && echo \"RESULT: $RES\" | grep -q 'root'" print(cmd) p = subprocess.run(cmd, shell=True) if p.returncode != 0: raise RuntimeError("Failed to run CLI panda") print("\tCLI: PASS") # Check 2 - load with python and test OSI profile if arch in osi_supported panda = Panda(generic=generic_name) assert(os.path.isdir(panda.build_dir)), f"Missing build dir {panda.build_dir}" osi_supported = ['i386', 'x86_64', 'arm'] if panda.arch in osi_supported: print(f"{panda.arch} supports OSI - loading") panda.load_plugin("osi") panda.load_plugin("osi_linux") seen = set() @panda.cb_asid_changed # Grab proc names at each asid change - AFTER we're at root (can't do OSI during boot, but asid will chage) def new_asid(cpu, oldasid, newasid): global reverted print("ASID", reverted, panda.arch) if reverted and panda.arch in osi_supported: # If osi unsupported, bail proc = panda.plugins['osi'].get_current_process(cpu) name = panda.ffi.string(proc.name) if name not in seen: seen.add(name) return 0 @panda.queue_blocking def start(): panda.revert_sync("root") global reverted reverted = True r = panda.run_serial_cmd("grep --color=no root /etc/passwd") assert("root:x" in r), "Failed to run grep command" panda.end_analysis() panda.run() if panda.arch in osi_supported: assert(len(seen)), "Didn't observe any processes" assert(b'grep' in seen), "Didn't see grep process run" print("\tPython: PASS" + (" (no OSI)" if panda.arch not in osi_supported else ""))
#!/usr/bin/env python3 # This test validates that run_serial_cmd works # both in terms of getting the correct response # but also for running multiple commands sequentially from pandare import Panda panda = Panda(generic="i386") @panda.queue_blocking def run_cmds(): panda.revert_sync("root") for cur_size in range(1, 300): buf = '1234567890'*(cur_size//10) + '1234567890'[:cur_size % 10] assert(len(buf) == cur_size), "Test is broken" resp = panda.run_serial_cmd(f"echo {buf}") # Check length assert(len(resp) == len(buf)), f"Test {cur_size}: Echo'd {len(buf)} characters but got {len(resp)} back" # Check contents for j in range(len(buf)): if resp[j] != buf[j]: raise ValueError(f"Test {cur_size}: Response character {j} was {repr(resp[j])} instead of an {buf[j]}") panda.end_analysis() panda.run()
from pandare import Panda panda = Panda(generic='x86_64') @panda.queue_blocking def driver(): panda.revert_sync('root') print(panda.run_serial_cmd("grep root /etc/passwd")) panda.end_analysis() panda.require("osi") panda.require("osi_linux") def fd_to_fname(cpu, fd): proc = panda.plugins['osi'].get_current_process(cpu) procname = panda.ffi.string( proc.name) if proc != panda.ffi.NULL else "error" fname_ptr = panda.plugins['osi_linux'].osi_linux_fd_to_filename( cpu, proc, fd) fname = panda.ffi.string( fname_ptr) if fname_ptr != panda.ffi.NULL else "error" return fname @panda.ppp("syscalls2", "on_sys_read_return") def read(cpu, tb, fd, buf, cnt): fname = fd_to_fname(cpu, fd) print(f"read {fname}")
#!/usr/bin/env python3 from sys import argv from pandare import Panda, blocking, ffi # Record the address of every function we call using callstack_instr generic_type = argv[1] if len(argv) > 1 else "mipsel" panda = Panda(generic=generic_type) if (generic_type == "i386") or (generic_type == "x86_64"): panda.load_plugin("callstack_instr") else: panda.load_plugin("callstack_instr", args = {"stack_type":"heuristic"}) @blocking def run_cmd(): panda.revert_sync("root") print(panda.run_serial_cmd("uname -a")) panda.end_analysis() @panda.ppp("callstack_instr", "on_call") def on_call(cpu, func): print(f"Call to 0x{func:x}") panda.queue_async(run_cmd) panda.run()
#!/usr/bin/env python3 import os from enum import Enum from sys import argv from pandare import Panda, ffi, blocking # Single arg of arch, defaults to i386 arch = "i386" if len(argv) <= 1 else argv[1] panda = Panda(generic=arch) monitor_lines = [] bb_count = 0 @blocking def my_runcmd(): panda.revert_sync('root') panda.run_serial_cmd("find . /proc/self") @blocking def info_reg(): global monitor_lines result = panda.run_monitor_cmd("info registers") monitor_lines = result.split("\n") panda.end_analysis() @panda.cb_before_block_exec def before_block_exec(env,tb): global bb_count bb_count += 1
#!/usr/bin/env python3 from pandare import Panda panda = Panda(generic="i386") panda.load_plugin("osi") bb_ctr = 0 @panda.cb_after_block_exec def bbe(cpu, tb, exit_code): global bb_ctr if (not panda.in_kernel(cpu)) and (exit_code <= 1): bb_ctr += 1 if (bb_ctr % 1000) == 0: proc = panda.plugins['osi'].get_current_process(cpu) if proc == ffi.NULL: return proc_name = ffi.string(proc.name).decode("utf-8") pc = panda.current_pc(cpu) in_dll = panda.plugins['osi'].in_shared_object(cpu, proc) print(f"{proc_name}@{pc:016x}, in SO? {in_dll}") @blocking def start(): panda.revert_sync("root")
#!/usr/bin/python3 import os from os import path from os import remove import sys import shutil from sys import argv from pandare import blocking, Panda thisdir = os.path.dirname(os.path.realpath(__file__)) if __name__ == "__main__": panda = Panda(arch="i386", qcow="/home/panda/regdir/qcows/wheezy_panda2.qcow2", extra_args="-nographic", expect_prompt=rb"root@debian-i386:.*") panda.load_plugin("taint2") panda.run_replay("taint2_tests")
#!/usr/bin/env python3 from sys import argv from os import path import capstone from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection from pandare import Panda # Single arg of arch, defaults to i386 arch = "i386" if len(argv) <= 1 else argv[1] panda = Panda(generic=arch) md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32) bin_dir = "taint" bin_name = "taint_asm" assert (path.isfile(path.join(bin_dir, bin_name))), "Missing file {}".format( path.join(bin_dir, bin_name)) # Take a recording of toy running in the guest if necessary recording_name = bin_dir + "_" + bin_name if not path.isfile(recording_name + "-rr-snp"): @panda.queue_blocking def run_it(): panda.record_cmd(path.join(bin_dir, bin_name), copy_directory=bin_dir, recording_name=recording_name) panda.stop_run() print("Generating " + recording_name + " replay")
''' proc_start.py Makes use of the proc_start_linux plugin to get output. Run with: python3 proc_start.py ''' from pandare import Panda from rich import print from sys import argv arch = argv[1] if len(argv) > 1 else "arm" panda = Panda(generic=arch) @panda.queue_blocking def do_stuff(): panda.revert_sync("root") for command in ["ls -la", "whoami", "sleep 1", "uname -r"]: print(panda.run_serial_cmd("LD_SHOW_AUXV=1 " + command)) panda.end_analysis() @panda.ppp("proc_start_linux", "on_rec_auxv") def rec_auxv(cpu, tb, av): print("[bold magenta][START PyPANDA on_recv_auxv][/bold magenta]") print("[bold red]Arguments: [/bold red]", end="") for i in range(av.argc): print(f'[bold red]{panda.ffi.string(av.argv[i])},[/bold red]', end="") print()
#!/usr/bin/env python3 from sys import argv from pandare import Panda, blocking, ffi panda = Panda(generic="x86_64" if len(argv) < 2 else argv[1]) @blocking def run_cmd(): panda.revert_sync("root") print(panda.run_serial_cmd("uname -a")) panda.end_analysis() @panda.cb_asid_changed() def asidchange(env, old_asid, new_asid): if old_asid != new_asid: print("Asid changed from %d to %d" % (old_asid, new_asid)) return 0 panda.queue_async(run_cmd) panda.run()