def __handle_host_version(self, cpu_index, cpu): """ Handle the host_version interface call. Returns the interface version. """ # self.__printer("GuestAgentPlugin: host_version() called") if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", GuestAgentPlugin.__INTERFACE_VERSION) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", GuestAgentPlugin.__INTERFACE_VERSION)
def __handle_host_close(self, cpu_index, cpu): """ Handle the host_close interface call. Argument in EAX: The file descriptor. Returns 0 on success in EAX, or -1 on error. """ if isinstance(cpu, X86CPU): fd = cpu.EAX elif isinstance(cpu, X64CPU): fd = cpu.RAX if fd not in self.__file_descriptors: self.__printer( "HostFilesPlugin: host_close tried to access invalid file descriptor %d" % fd) return try: self.__file_descriptors[fd].close() del self.__file_descriptors[fd] if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", 0) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", 0) # self.__printer("GuestAgentPlugin: host_close(%d) called" % (fd)) except Exception as ex: self.__printer( "HostFilesPlugin: Exception %s while trying to close file descriptor %d" % (str(ex), fd)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1)
def __handle_host_get_command(self, cpu_index, cpu): """ Handle the host_get_command interface call. """ do_exit = False if len(self.__commands) > 0: # Fetch the first command command = self.__commands[0]["command"] meta = self.__commands[0]["meta"] # Remove the first command of the queue self.__commands = self.__commands[1:] else: command = GuestAgentPlugin.__CMD_WAIT meta = {} # if the command was an exit command, then clean up opcode callback if command == GuestAgentPlugin.__CMD_EXIT: self.__clean_opcode_callback() elif command == GuestAgentPlugin.__CMD_STOP: self.__clean() # Set it to EXIT, so that the agent understands # it has to exit. command = GuestAgentPlugin.__CMD_EXIT elif command == GuestAgentPlugin.__CMD_EXEC: self.__file_to_execute = meta if "callback" in meta and meta["callback"] is not None: meta["callback"]() elif command == GuestAgentPlugin.__CMD_COPY: self.__file_to_copy = meta if "callback" in meta and meta["callback"] is not None: meta["callback"]() elif command == GuestAgentPlugin.__CMD_EXEC_EXIT: command = GuestAgentPlugin.__CMD_EXEC self.__file_to_execute = meta if "callback" in meta["callback"] is not None: meta["callback"]() do_exit = True if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", command) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", command) # A command asks to exit afterwards if do_exit: self.__commands.append( {"command": GuestAgentPlugin.__CMD_EXIT, "meta": {}})
def rdtsc_opcode_call(cpu_index, cpu, pc, next_pc): global pyrebox_print global target_pgd global rdtsc_val_lo global rdtsc_val_hi if api.is_kernel_running(cpu_index) == False: pgd = api.get_running_process(cpu_index) if pgd == target_pgd and pc < 0x500000: if rdtsc_val_lo == 0: pyrebox_print("[*] first rdtsc call %x" % pc) rdtsc_val_lo = cpu.EAX rdtsc_val_hi = cpu.EDX else: pyrebox_print("[*] new rdtsc check! %x" % pc) rdtsc_val_lo = rdtsc_val_lo + 500 # this just works for pafish ~cos it has a sleep(500), need to find a more general aproach api.w_r(0, "EAX", rdtsc_val_lo) api.w_r(0, "EDX", rdtsc_val_hi)
def __opcode_range_callback(self, params): """ Called by the callback manager when the desired opcode is hit. """ cpu_index = params["cpu_index"] cpu = params["cpu"] cur_pc = params["cur_pc"] next_pc = params["next_pc"] try: if self.__status == GuestAgentPlugin.__AGENT_READY: function = api.r_va(api.get_running_process(cpu_index), cur_pc + 3, 2) try: handler = { "\x00\x00": self.__handle_host_version, "\x00\x01": self.__handle_host_message, "\x00\x02": self.__handle_host_get_command, "\x10\x00": self.__handle_host_open, "\x10\x01": self.__handle_host_read, "\x10\x02": self.__handle_host_close, "\x10\x03": self.__handle_host_get_file_name, "\x20\x00": self.__handle_host_request_exec_path, "\x20\x01": self.__handle_host_request_exec_args, "\x20\x02": self.__handle_host_request_exec_env, "\x20\x03": self.__handle_host_request_exec_args_linux, "\x20\x04": self.__handle_host_request_exec_env_linux }[function] handler(cpu_index, cpu) except KeyError: self.__printer( "HostFilePlugin: Unknown host opcode %x at 0x%08x" % (function, cur_pc)) # Advance the program counter. # Needs to be done explicitly, as Qemu doesn't know the instruction # length. if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EIP", cpu.EIP + 10) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RIP", cpu.RIP + 10) elif self.__status == GuestAgentPlugin.__AGENT_RUNNING: # Agent already running but not ready yet (the base # address was not correctly determined yet. # Advance the program counter. # Needs to be done explicitly, as Qemu doesn't know the instruction # length. if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EIP", cpu.EIP + 10) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RIP", cpu.RIP + 10) except Exception as e: self.__printer("Exception occurred on opcode callback: %s" % str(e))
def __handle_host_get_command(self, cpu_index, cpu): """ Handle the host_get_command interface call. """ do_exit = False if len(self.__commands) > 0: # Fetch the first command command = self.__commands[0]["command"] meta = self.__commands[0]["meta"] # Remove the first command of the queue self.__commands = self.__commands[1:] else: command = GuestAgentPlugin.__CMD_WAIT meta = {} # if the command was an exit command, then clean up opcode callback if command == GuestAgentPlugin.__CMD_EXIT: self.__clean_opcode_callback() elif command == GuestAgentPlugin.__CMD_STOP: self.__clean() # Set it to EXIT, so that the agent understands # it has to exit. command = GuestAgentPlugin.__CMD_EXIT elif command == GuestAgentPlugin.__CMD_EXEC: self.__file_to_execute = meta elif command == GuestAgentPlugin.__CMD_COPY: self.__file_to_copy = meta elif command == GuestAgentPlugin.__CMD_EXEC_EXIT: command = GuestAgentPlugin.__CMD_EXEC self.__file_to_execute = meta do_exit = True if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", command) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", command) # A command asks to exit afterwards if do_exit: self.__commands.append( {"command": GuestAgentPlugin.__CMD_EXIT, "meta": {}})
def opcodes(cpu_index, cpu, pc, next_pc): global pyrebox_print global target_pgd if api.is_kernel_running(cpu_index) == False: pgd = api.get_running_process(cpu_index) if pgd == target_pgd and pc < 0x500000: if cpu.EBX == 0x54474354: api.w_r(0, "EBX", 0x72657661) api.w_r(0, "ECX", 0x33333179) api.w_r(0, "EDX", 0x70796837) pyrebox_print("[*] Hypervisor name check %x" % pc) #start_shell() elif cpu.EBX == 0x756e6547: pyrebox_print("[*] GenuineIntel check %x" % pc) elif cpu.EBX == 0x72695620: api.w_r(0, "EAX", 0x65746e49) api.w_r(0, "EBX", 0x6f63206c) api.w_r(0, "ECX", 0x49206572) api.w_r(0, "EDX", 0x00003936) pyrebox_print("[*] CPU Name check %x" % pc) #start_shell() elif cpu.ECX == 0x80000001: #Not pretty elegant api.w_r(0, "ECX", 0x00000000) pyrebox_print("[*] Hypervisor bit check %x" % pc) else: pyrebox_print("[*] Unknown Check (TODO) %x" % pc)
def __handle_host_request_exec_args_linux(self, cpu_index, cpu): """ Handle the host_request_exec_args interface call. Argument in EAX: the buffer to write to Argument in EBX: the max size of the buffer to write to Returns number of bytes written in EAX, or -1 if the call failed. """ if isinstance(cpu, X86CPU): buf = cpu.EAX size = cpu.EBX elif isinstance(cpu, X64CPU): buf = cpu.RAX size = cpu.RBX TARGET_LONG_SIZE = api.get_os_bits() / 8 args = self.__file_to_execute["args"] argv_size = TARGET_LONG_SIZE * (len(args) + 1) + sum(len(x) + 1 for x in args) if argv_size > self.__agent_buffer_size: raise ValueError("The size of the args should not exceed %d bytes" % self.__agent_buffer_size) # self.__printer("GuestAgentPlugin: host_request_exec_args(0x%08x, %d) # called" % (buf, size)) pgd = api.get_running_process(cpu_index) try: # Security check: the buffer should be located on the allowed # boundaries if self.__check_buffer_validity(buf, size): self.__write_strings_array( pgd, buf, args) if isinstance(cpu, X86CPU): api.w_r( cpu_index, "EAX", argv_size) elif isinstance(cpu, X64CPU): api.w_r( cpu_index, "RAX", argv_size) else: self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" + "within the allowed boundaries %x (%x)" % (buf, size)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1) except Exception as ex: self.__printer( "HostFilesPlugin: Exception %s while trying to write file args to guest" % (str(ex))) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1)
def __handle_host_request_exec_path(self, cpu_index, cpu): """ Handle the host_request_exec_path interface call. Argument in EAX: the buffer to write to Argument in EBX: the max size of the buffer to write to Returns number of bytes written in EAX, or -1 if the call failed. """ if isinstance(cpu, X86CPU): buf = cpu.EAX size = cpu.EBX elif isinstance(cpu, X64CPU): buf = cpu.RAX size = cpu.RBX # self.__printer("GuestAgentPlugin: host_request_exec_path(0x%08x, %d) # called" % (buf, size)) pgd = api.get_running_process(cpu_index) try: # Security check: the buffer should be located on the allowed # boundaries if self.__check_buffer_validity(buf, size): api.w_va(pgd, buf, self.__file_to_execute[ "path"] + "\x00", len(self.__file_to_execute["path"]) + 1) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", len( self.__file_to_execute["path"]) + 1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", len( self.__file_to_execute["path"]) + 1) else: self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" + "within the allowed boundaries %x (%x)" % (buf, size)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1) except Exception as ex: self.__printer( "HostFilesPlugin: Exception %s while trying to write file path to guest" % (str(ex))) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1)
def __handle_host_read(self, cpu_index, cpu): """ Handle the host_read interface call. Argument in EAX: The file descriptor. Argument in EBX: Pointer to the buffer (VA) where bytes should be read into. Argument in ECX: Size of the buffer. Returns number of bytes read in EAX, or -1 if the call failed. """ if isinstance(cpu, X86CPU): fd = cpu.EAX buf = cpu.EBX size = cpu.ECX elif isinstance(cpu, X64CPU): fd = cpu.RAX buf = cpu.RBX size = cpu.RCX # self.__printer("GuestAgentPlugin: host_read(%d, 0x%08x, %d) called" % # (fd, buf, size)) if fd not in self.__file_descriptors: self.__printer( "HostFilesPlugin: host_read tried to access invalid file descriptor %d" % fd) return pgd = api.get_running_process(cpu_index) try: data = self.__file_descriptors[fd].read(size) # Security check: the buffer should be located on the allowed # boundaries if self.__check_buffer_validity(buf, size): api.w_va(pgd, buf, data, len(data)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", len(data)) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", len(data)) else: self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" + "within the allowed boundaries %x (%x)" % (buf, size)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1) except Exception as ex: self.__printer( "HostFilesPlugin: Exception %s while trying to read from file descriptor %d" % (str(ex), fd)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1)
def __handle_host_open(self, cpu_index, cpu): """ Handle the host_open interface call. Argument in EAX: Pointer (VA) to file name. Returns the file descriptor in EAX. """ if isinstance(cpu, X86CPU): fname = self.__read_string(cpu_index, cpu.EAX) elif isinstance(cpu, X64CPU): fname = self.__read_string(cpu_index, cpu.RAX) # self.__printer("GuestAgentPlugin: host_open(%s) called" % fname) try: # Check the program is requesting the file that we asked to copy if self.__file_to_copy["destiny"] == fname: fpath = self.__file_to_copy["source"] fd = open(fpath, "rb") self.__file_descriptors[self.__file_descriptor_counter] = fd if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", self.__file_descriptor_counter) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", self.__file_descriptor_counter) self.__file_descriptor_counter += 1 else: self.__printer( "HostFilesPlugin: The guest requested to open an invalid file %s" % fname) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1) except KeyError: self.__printer( "HostFilesPlugin: Guest tried to read unknown file %s" % fname) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1) except Exception as ex: self.__printer( "HostFilesPlugin: Exception %s while opening file %s" % (str(ex), fname)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1)
def __handle_host_request_exec_env_linux(self, cpu_index, cpu): """ Handle the host_request_exec_env interface call. Argument in EAX: the buffer to write to Argument in EBX: the max size of the buffer to write to Returns number of bytes written in EAX, or -1 if the call failed. """ if isinstance(cpu, X86CPU): buf = cpu.EAX size = cpu.EBX elif isinstance(cpu, X64CPU): buf = cpu.RAX size = cpu.RBX TARGET_LONG_SIZE = api.get_os_bits() / 8 env = self.__file_to_execute["env"] pgd = api.get_running_process(cpu_index) # self.__printer("GuestAgentPlugin: host_request_exec_env(0x%08x, %d) # called" % (buf, size)) if len(env) > 0: env = ["{:s}={:s}".format(k, v) for k, v in env.items()] env_size = sum(len(x) + 1 for x in env) + TARGET_LONG_SIZE * (len(env) + 1) try: # Security check: the buffer should be located on the allowed # boundaries if self.__check_buffer_validity(buf, size): self.__write_strings_array( pgd, buf, env) if isinstance(cpu, X86CPU): api.w_r( cpu_index, "EAX", env_size) elif isinstance(cpu, X64CPU): api.w_r( cpu_index, "RAX", env_size) else: self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" + "within the allowed boundaries %x (%x)" % (buf, size)) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1) except Exception as ex: self.__printer( "HostFilesPlugin: Exception %s while trying to write env vars to guest" % (str(ex))) if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", -1) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", -1) else: if isinstance(cpu, X86CPU): api.w_r(cpu_index, "EAX", 0) elif isinstance(cpu, X64CPU): api.w_r(cpu_index, "RAX", 0)
def set_full_regs(cpu_index, reg_name, value): import api reg_name = reg_name.upper() int_value = int(value.replace('L', ''), 16) pyrebox_print("Writing " + value + " to " + reg_name) api.w_r(cpu_index, reg_name, int_value)