def do_ioctl_init(arch): # Default config (x86, x86-64, ARM, AArch 64) with options for PPC global ioctl_initialized if ioctl_initialized: return ioctl_initialized = True TYPE_BITS = 8 CMD_BITS = 8 SIZE_BITS = 14 if arch != "ppc" else 13 DIR_BITS = 2 if arch != "ppc" else 3 ffi.cdef(""" struct IoctlCmdBits { uint8_t type_num:%d; uint8_t cmd_num:%d; uint16_t arg_size:%d; uint8_t direction:%d; }; union IoctlCmdUnion { struct IoctlCmdBits bits; uint32_t asUnsigned32; }; enum ioctl_direction { IO = 0, IOW = 1, IOR = 2, IOWR = 3 }; """ % (TYPE_BITS, CMD_BITS, SIZE_BITS, DIR_BITS), packed=True)
virt_addr = cpu.env_ptr.regs[7] phys_addr = panda.virt_to_phys(cpu, virt_addr) assert (panda.taint_check_ram(phys_addr) ), "Final result is not tainted" tq = panda.taint_get_ram(phys_addr) print("Result is tainted. " + str(tq) + " at " + hex(phys_addr)) panda.end_analysis() return None 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}));") info = None tainted = False @ffi.callback(f"void({cb_args})") def on_sys_read_return(cpustate, pc, fd, buf, count): global info, tainted if info and not tainted: cr3, fd1 = info if cr3 == cpustate.env_ptr.cr[3] and fd == fd1: returned = cpustate.env_ptr.regs[R_EAX] buf_read = panda.virtual_memory_read(cpustate, buf, returned) for idx in range(returned): taint_vaddr = buf + idx
ffi.cdef(""" struct syscall_ctx { int no; /**< number */ target_ptr_t asid; /**< calling process asid */ target_ptr_t retaddr; /**< return address */ uint8_t args[64] [64]; /**< arguments */ }; // syscalls2_info.h typedef struct { uint32_t max; uint32_t max_generic; uint32_t max_args; } syscall_meta_t; typedef enum { SYSCALL_ARG_U64 = 0x00, /**< unsigned 64bit value */ SYSCALL_ARG_U32, /**< unsigned 32bit value */ SYSCALL_ARG_U16, /**< unsigned 16bit value */ SYSCALL_ARG_S64 = 0x10, /**< signed 64bit value */ SYSCALL_ARG_S32, /**< signed 32bit value */ SYSCALL_ARG_S16, /**< signed 16bit value */ SYSCALL_ARG_PTR = 0x20, /**< pointer to buffer/struct */ SYSCALL_ARG_STR /**< C string */ } syscall_argtype_t; typedef struct { int no; const char *name; int nargs; syscall_argtype_t *argt; uint8_t *argsz; bool noreturn; } syscall_info_t; // Hand-crafted modeling python/include/syscalls_ext_typedefs_x86_64.h typedef struct syscall_ctx syscall_ctx_t; typedef void (*on_all_sys_enter2_t)(CPUState *cpu, target_ulong pc, const syscall_info_t *call, const syscall_ctx_t *ctx); void ppp_add_cb_on_all_sys_enter2(on_all_sys_enter2_t); """)
# Need to include at top-level for ppp decorator panda = Panda( arch='x86_64', mem='1G', qcow='/panda_resources/bionic-work.qcow2', expect_prompt=rb'root@ubuntu:.*# ', extra_args='-display none -net user,hostfwd=tcp::8080-:80 -net nic') # Hacky code to get on_branch2 PPP callback working in pypanda # CFFI Can't typedef structures with unions, like addrs # So here we replace `val` with a uint64_t 'addr_val' ffi.cdef(""" typedef struct { AddrType typ; uint64_t addr_val; uint16_t off; AddrFlag flag; } FakeAddr; """) ffi.cdef('typedef void (*on_branch2_t) (FakeAddr, uint64_t);', override=True) # XXX WIP ffi.cdef( 'void ppp_add_cb_on_branch2(on_branch2_t);' ) # Why don't we autogen this? Are we not translating the macros into fn defs? # End hacky-CFFI codev ffi.cdef(""" struct sockaddr { unsigned short sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };