def get_parent_pid(self): """Get the Parent Process ID.""" class PROCESS_BASIC_INFORMATION(Structure): _fields_ = [ ("ExitStatus", c_void_p), ("PebBaseAddress", c_void_p), ("AffinityMask", c_void_p), ("BasePriority", c_void_p), ("UniqueProcessId", c_void_p), ("InheritedFromUniqueProcessId", c_void_p), ] NT_SUCCESS = lambda val: val >= 0 pbi = PROCESS_BASIC_INFORMATION() size = c_int() # Set return value to signed 32bit integer. NTDLL.NtQueryInformationProcess.restype = c_int process_handle = self.open_process() ret = NTDLL.NtQueryInformationProcess(process_handle, 0, byref(pbi), sizeof(pbi), byref(size)) KERNEL32.CloseHandle(process_handle) if NT_SUCCESS(ret) and size.value == sizeof(pbi): return pbi.InheritedFromUniqueProcessId
def run(self): while self.do_run: flags = FILE_FLAG_WRITE_THROUGH if self.message: pipe_handle = KERNEL32.CreateNamedPipeA( self.pipe_name, PIPE_ACCESS_DUPLEX | flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 0, None) else: pipe_handle = KERNEL32.CreateNamedPipeA( self.pipe_name, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, BUFSIZE, 0, None) if pipe_handle == INVALID_HANDLE_VALUE: log.warning("Error opening logging pipe server.") continue if KERNEL32.ConnectNamedPipe(pipe_handle, None) or \ KERNEL32.GetLastError() == ERROR_PIPE_CONNECTED: handler = self.pipe_handler(pipe_handle, **self.kwargs) handler.daemon = True handler.start() self.handlers.add(handler) else: KERNEL32.CloseHandle(pipe_handle)
def get_filepath(self): """Get process image file path. @return: decoded file path. """ process_handle = self.open_process() NT_SUCCESS = lambda val: val >= 0 pbi = create_string_buffer(200) size = c_int() # Set return value to signed 32bit integer. NTDLL.NtQueryInformationProcess.restype = c_int ret = NTDLL.NtQueryInformationProcess(process_handle, 27, byref(pbi), sizeof(pbi), byref(size)) KERNEL32.CloseHandle(process_handle) if NT_SUCCESS(ret) and size.value > 8: try: fbuf = pbi.raw[8:] fbuf = fbuf[:fbuf.find("\x00\x00") + 1] return fbuf.decode("utf16", errors="ignore") except: return "" return ""
def invoke(self, ctlcode, value, outlength=0x1000): device_handle = KERNEL32.CreateFileA( "\\\\.\\%s" % self.pipepath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None) % 2**32 if device_handle == 0xffffffff: # Only report an error if the error is not "name not found", # indicating that no kernel analysis is currently taking place. if KERNEL32.GetLastError() != 2: log.warning("Error opening handle to driver (%s): %d!", driver_name, KERNEL32.GetLastError()) return False out = ctypes.create_string_buffer(outlength) length = ctypes.c_uint() ret = KERNEL32.DeviceIoControl(device_handle, ctlcode, value, len(value), out, ctypes.sizeof(out), ctypes.byref(length), None) KERNEL32.CloseHandle(device_handle) if not ret: log.warning("Error performing ioctl (0x%08x): %d!", ctlcode, KERNEL32.GetLastError()) return False return out.raw[:length.value]
def grant_privilege(privilege): """Grant debug privileges. @param pid: PID. @return: operation status. """ ADVAPI32.OpenProcessToken.argtypes = (wintypes.HANDLE, wintypes.DWORD, POINTER(wintypes.HANDLE)) ADVAPI32.LookupPrivilegeValueW.argtypes = (wintypes.LPWSTR, wintypes.LPWSTR, POINTER(LUID)) ADVAPI32.AdjustTokenPrivileges.argtypes = (wintypes.HANDLE, wintypes.BOOL, POINTER(TOKEN_PRIVILEGES), wintypes.DWORD, POINTER(TOKEN_PRIVILEGES), POINTER(wintypes.DWORD)) h_process = KERNEL32.GetCurrentProcess() h_current_token = wintypes.HANDLE() if not ADVAPI32.OpenProcessToken(h_process, TOKEN_ALL_ACCESS, h_current_token): return False se_original_luid = LUID() if not ADVAPI32.LookupPrivilegeValueW(None, privilege, se_original_luid): return False luid_attributes = LUID_AND_ATTRIBUTES() luid_attributes.Luid = se_original_luid luid_attributes.Attributes = SE_PRIVILEGE_ENABLED token_privs = TOKEN_PRIVILEGES() token_privs.PrivilegeCount = 1 token_privs.Privileges = luid_attributes if not ADVAPI32.AdjustTokenPrivileges(h_current_token, False, token_privs, 0, None, None): return False KERNEL32.CloseHandle(h_current_token) KERNEL32.CloseHandle(h_process) return True
def exit_code(self): """Get process exit code. @return: exit code value. """ process_handle = self.open_process() exit_code = c_ulong(0) KERNEL32.GetExitCodeProcess(process_handle, byref(exit_code)) KERNEL32.CloseHandle(process_handle) return exit_code.value
def terminate(self): """Terminate process. @return: operation status. """ process_handle = self.open_process() ret = KERNEL32.TerminateProcess(process_handle, 1) KERNEL32.CloseHandle(process_handle) if ret: log.info("Successfully terminated process with pid %d.", self.pid) return True else: log.error("Failed to terminate process with pid %d.", self.pid) return False
def run(self): """Run the pipe dispatcher.""" buf = create_string_buffer(BUFSIZE) bytes_written = c_uint() while self.do_run: message = self._read_message(buf) if not message: break response = self.dispatcher.dispatch(message) or "OK" KERNEL32.WriteFile(self.pipe_handle, response, len(response), byref(bytes_written), None) KERNEL32.CloseHandle(self.pipe_handle)
def run(self): buf = create_string_buffer(BUFSIZE) bytes_read = c_uint() pid = c_uint() # The first four bytes indicate the process identifier. In case the # pipe handle is closed in an unknown way, reopening one and # specifying the same process identifier will reuse the same socket, # thus making it look like as if it was never closed in the first # place. success = KERNEL32.ReadFile(self.pipe_handle, byref(pid), sizeof(pid), byref(bytes_read), None) if not success or bytes_read.value != sizeof(pid): log.warning("Unable to read the process identifier of this " "log pipe instance.") KERNEL32.CloseHandle(self.pipe_handle) return if self.active.get(pid.value): log.warning("A second log pipe handler for an active process is " "being requested, denying request.") KERNEL32.CloseHandle(self.pipe_handle) return if pid.value: sock = self.sockets.get(pid.value) if not sock: sock = socket.create_connection(self.destination) self.sockets[pid.value] = sock self.active[pid.value] = True else: sock = socket.create_connection(self.destination) open_handles.add(sock) while self.do_run: success = KERNEL32.ReadFile(self.pipe_handle, byref(buf), sizeof(buf), byref(bytes_read), None) if success or KERNEL32.GetLastError() == ERROR_MORE_DATA: try: sock.sendall(buf.raw[:bytes_read.value]) except socket.error as e: if e.errno != errno.EBADF: log.warning("Failed socket operation: %s", e) break # If we get the broken pipe error then this pipe connection has # been terminated for one reason or another. So break from the # loop and make the socket "inactive", that is, another pipe # connection can in theory pick it up. (This will only happen in # cases where malware for some reason broke our pipe connection). elif KERNEL32.GetLastError() == ERROR_BROKEN_PIPE: break else: log.warning("The log pipe handler has failed, last error %d.", KERNEL32.GetLastError()) break if pid.value: self.active[pid.value] = False
def Close(self): KERNEL32.CloseHandle(self)