def _read_message(self, buf): """Reads a message.""" bytes_read = c_uint() ret = "" while True: success = KERNEL32.ReadFile(self.pipe_handle, byref(buf), sizeof(buf), byref(bytes_read), None) if KERNEL32.GetLastError() == ERROR_MORE_DATA: ret += buf.raw[:bytes_read.value] elif success: return ret + buf.raw[:bytes_read.value] else: return
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