Esempio n. 1
0
def virt_mem_after_read(cpustate, pc, addr, size, buf):
	curbuf = ffi.cast("char*", buf)
	current = panda.get_current_process(cpustate)
	if current != ffi.NULL:
		if size >= 5:
			buf_addr = hex(int(ffi.cast("uint64_t", buf)))
			buf_str = ffi.string(ffi.cast("char*",buf)).decode(errors='ignore')
			print("Read buf: %s, size: %x, at pc: %x %s" %(buf_addr[2:], size, addr, buf_str))
Esempio n. 2
0
def on_sys_read_return(cpu, pc, fd, buf, count):
    asid = panda.current_asid(cpu)
    if is_hooked(fd, asid):
        # We need to make up a file. Grab our contents/fn
        f = file_descriptors[(fd, asid)]
        assert (f.is_fake), "Can't fake a non-faked FD"
        faker = files_faked[f.filename]
        logger.debug(
            f"Hooking return of read for FD={fd} corresponding to file {f.filename}"
        )
        """
        if faker.fake_contents: # Static file contents
                # index into it based on f.offset return up to count
            contents = faker.fake_contents+"\x00"
            if f.offset >= len(contents):  # No bytes left to read
                logger.debug(f"\t Returning EOF")
                cpu.env_ptr.regs[R_EAX] = 0
                return
            else: # Bytes to read
                file_contents = contents[f.offset:f.offset+count].encode("utf8")
                logger.debug(f"\t Set buffer at 0x{buf:x} to: {file_contents}")
                write_result = panda.virtual_memory_write(cpu, buf, file_contents) # Write buffer - May fail if page isn't mapped

                if write_result < 0: # Page not mapped. Make guest retry - Don't update our fake file's offset because this read will fail
                    logger.info(f"\t Failed to write data into guest memory")
                    cpu.env_ptr.regs[R_EAX] = ffi.cast("unsigned char", -11) # Return EAGAIN to make the guest retry (with page mapped, hopefully)
                    return
                cpu.env_ptr.regs[R_EAX] = len(file_contents) # Bytes written
                f.offset += len(file_contents)
                return

        else: # Function
        """

        # First try a junk write to see if memory write will fail (avoids calling class twice)
        try:
            panda.virtual_memory_write(cpu, buf, b'PANDA_TEST_DATA')
        except Exception:  # Page not mapped. Make guest retry
            cpu.env_ptr.regs[R_EAX] = ffi.cast("unsigned char",
                                               -11)  # Return EAGAIN
            return
        # Call fn and update guest memory
        (data, ret_val) = faker.get_data(f, count)
        if data and len(data):
            try:
                panda.virtual_memory_write(cpu, buf, data)
            except Exception:  # Page not mapped. Make guest retry. XXX: calls get_data twice
                logger.info(
                    f"\t Failed to write data into guest memory. XXX Duplicate call to get_data"
                )
                cpu.env_ptr.regs[R_EAX] = ffi.cast("unsigned char",
                                                   -11)  # Return EAGAIN
                return

        cpu.env_ptr.regs[R_EAX] = ret_val
Esempio n. 3
0
def syscall_enter(cpu, pc, call, ctx):
    for arg_idx in range(call.nargs):
        # Debug prints
        #type_str = ffi.string(ffi.cast("syscall_argtype_t", call.argt[arg_idx]))
        #print(f"\tArg{arg_idx}: size {call.argsz[arg_idx]}, type {type_str}")

        # Log all pointers passed to syscalls - strings or poitners to buffers
        if call.argt[arg_idx] in [
                argtypes['SYSCALL_ARG_PTR'], argtypes['SYSCALL_ARG_STR']
        ]:
            arg_ptr = int(
                ffi.cast('uint64_t*', ctx.args)[arg_idx]
            )  # Cast to uint64_t's _BEFORE_ we access (weird) TODO

            asid = panda.current_asid(cpu)
            proc = panda.plugins['osi'].get_current_process(cpu)
            syscall_name = ffi.string(call.name).decode(
                'utf8') if call.name != ffi.NULL else "unknown"
            if asid not in asid_to_procname:
                proc_name = ffi.string(proc.name).decode('utf8') if (
                    proc.name != ffi.NULL) else "unknown"
                asid_to_procname[asid] = proc_name
            proc_name = asid_to_procname[asid]
            if proc_name in procnames_of_interest:
                print(
                    f"Process: {proc_name} ({ctx.asid}) syscall {syscall_name} with buffer at 0x{arg_ptr:x}"
                )
                if arg_ptr not in identified_buffers.keys():
                    identified_buffers[arg_ptr] = []
                identified_buffers[arg_ptr].append(
                    (asid, proc_name, panda.rr_get_guest_instr_count(),
                     syscall_name))
Esempio n. 4
0
def on_sys_open_return(cpu, pc, fname_ptr, flags, mode):
    asid = panda.current_asid(cpu)
    fd = cpu.env_ptr.regs[R_EAX]
    global pending_hyperfile
    if not pending_hyperfile:
        # Return EAGAIN to make the guest retry (with page mapped, hopefully)
        cpu.env_ptr.regs[R_EAX] = ffi.cast("unsigned char", -11)
        return
    file_descriptors[(fd, asid)] = pending_hyperfile
    if pending_hyperfile.is_fake:
        logger.debug(
            f"Hook stored info for fake FD {fd} = {pending_hyperfile.filename}"
        )
    pending_hyperfile = None
Esempio n. 5
0
    def __str__(self):

        if self.osi:
            self_str = "\'{}\' using \'{}\' - ".format(self.proc_name, self.file_name)
        else:
            self_str = ""

        bits = self.cmd.bits
        direction = ffi.string(ffi.cast("enum ioctl_direction", bits.direction))
        ioctl_desc = f"dir={direction},arg_size={bits.arg_size:x},cmd={bits.cmd_num:x},type={bits.type_num:x}"
        if (self.guest_ptr == None):
            self_str += f"ioctl({ioctl_desc}) -> {self.original_ret_code}"
        else:
            self_str += f"ioctl({ioctl_desc},ptr={self.guest_ptr:08x},buf={self.guest_buf}) -> {self.original_ret_code}"
        return self_str
Esempio n. 6
0
def before_write(cpu, pc, start_addr, size, buf):
    for addr in range(start_addr, start_addr + size):
        if addr not in identified_buffers:
            continue

        buf_base = buf + (addr - start_addr)
        data = ffi.string(ffi.cast('char*', buf_base))

        # Find the last instruction (highest icount) that wrote to the buffer,
        # but before the syscall's icount
        write_icount = panda.rr_get_guest_instr_count()

        asid = panda.current_asid(cpu)
        for (old_asid, proc_name, icount_use, _) in identified_buffers[addr]:
            if old_asid != asid:
                continue
            if icount_use < write_icount:
                continue

            in_kernel = panda.in_kernel(cpu)

            # Identify what module we're currently in so we can get a relative offset
            for module in panda.get_mappings(cpu):
                mod_base = None
                mod_name = ffi.string(module.name).decode(
                    "utf8") if module.name != ffi.NULL else '(null)'

                if mod_name in procnames_of_interest:
                    if mod_name not in base_addresses or module.base < base_addresses[
                            mod_name]:
                        base_addresses[mod_name] = module.base

                # Debug: print memory map at each write we care about
                #print(f"0x{module.base:012x} - 0x{module.base+module.size:012x}: {mod_name}")

                if addr >= module.base and addr < module.base + module.size:  # Then it's in this module
                    mod_name = ffi.string(module.name).decode(
                        "utf8") if module.name != ffi.NULL else '(null)'
                    mod_base = module.base
                    break
            else:
                print(
                    f"Warning: No loaded module owns address 0x{addr:x}. Skipping"
                )
                continue

            # Identify where PC is at time of write
            '''
            for module in panda.get_mappings(cpu):
                if pc >= module.base and pc < module.base+module.size: # Then it's in this module
                    name = ffi.string(module.name).decode("utf8") if module.name != ffi.NULL else '(null)'
                    print(f"PC 0x{pc:x} is in {name} offset: 0x{pc-module.base:x}")
            '''

            if (asid, addr, icount_use) not in last_write_before.keys():
                last_write_before[(asid, addr,
                                   icount_use)] = (write_icount, pc, mod_name,
                                                   mod_base, in_kernel)
            else:
                last_write_icount = last_write_before[(asid, addr,
                                                       icount_use)][0]
                if write_icount > last_write_icount:  # Replace with new write
                    last_write_before[(asid, addr,
                                       icount_use)] = (write_icount, pc,
                                                       mod_name, mod_base,
                                                       in_kernel)
Esempio n. 7
0
def handle_packet(cpustate,buf,size,direction,old_buf_addr):
	buf_uint8 = ffi.cast("uint8_t*", buf)
	packets.append(Ether([buf_uint8[i] for i in range(size)]))
	return 0