def publishers(self): h = windows.winproxy.EvtOpenPublisherEnum(None, 0) size = 0x1000 buffer = ctypes.create_unicode_buffer(size) ressize = gdef.DWORD() with ClosingEvtHandle(h): while True: try: windows.winproxy.EvtNextPublisherId(h, size, buffer, ressize) except WindowsError as e: if e.winerror != gdef.ERROR_NO_MORE_ITEMS: raise return assert buffer[ressize.value - 1] == "\x00" name = buffer[:ressize.value - 1] publisher = EvtPublisher(name) yield publisher
def _get_object_type(self): lh = self.local_handle xxx = gdef.PUBLIC_OBJECT_TYPE_INFORMATION() size_needed = gdef.DWORD() try: winproxy.NtQueryObject(lh, gdef.ObjectTypeInformation, ctypes.byref(xxx), ctypes.sizeof(xxx), ctypes.byref(size_needed)) except WindowsError as e: if e.code != gdef.STATUS_INFO_LENGTH_MISMATCH: raise size = size_needed.value buffer = ctypes.c_buffer(size) winproxy.NtQueryObject(lh, gdef.ObjectTypeInformation, buffer, size, ctypes.byref(size_needed)) xxx = gdef.PUBLIC_OBJECT_TYPE_INFORMATION.from_buffer_copy(buffer) return xxx.TypeName.str
def enumerate_kernel_modules(): if windows.current_process.is_wow_64: return enumerate_kernel_modules_syswow64() cbsize = gdef.DWORD() winproxy.NtQuerySystemInformation(gdef.SystemModuleInformation, None, 0, ctypes.byref(cbsize)) raw_buffer = (cbsize.value * gdef.BYTE)() buffer = gdef.SYSTEM_MODULE_INFORMATION.from_address( ctypes.addressof(raw_buffer)) winproxy.NtQuerySystemInformation(gdef.SystemModuleInformation, ctypes.byref(raw_buffer), ctypes.sizeof(raw_buffer), ctypes.byref(cbsize)) modules = (SystemModule * buffer.ModulesCount).from_address( ctypes.addressof(buffer) + gdef.SYSTEM_MODULE_INFORMATION.Modules.offset) return list(modules)
def get_name(self, nametype=gdef.CERT_NAME_SIMPLE_DISPLAY_TYPE, param_type=0, flags=0): """Retrieve the subject or issuer name of the certificate. See `CertGetNameStringA <https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086(v=vs.85).aspx>`_ :returns: :class:`str` """ if nametype == gdef.CERT_NAME_RDN_TYPE: param_type = gdef.DWORD(param_type) param_type = gdef.LPDWORD(param_type) size = winproxy.CertGetNameStringA(self, nametype, flags, param_type, None, 0) namebuff = ctypes.c_buffer(size) size = winproxy.CertGetNameStringA(self, nametype, flags, param_type, namebuff, size) return namebuff[:-1]
def verify_signature(cert, encoded_blob): # Verify parameters verif_param = gdef.CRYPT_KEY_VERIFY_MESSAGE_PARA() verif_param.cbSize = ctypes.sizeof(gdef.CRYPT_KEY_VERIFY_MESSAGE_PARA) verif_param.dwMsgEncodingType = windows.crypto.DEFAULT_ENCODING verif_param.hCryptProv = None # The public key used pubkey = cert.pCertInfo[0].SubjectPublicKeyInfo # Preparing in/out buffer/size signed_buffer = windows.utils.BUFFER( gdef.BYTE).from_buffer_copy(encoded_blob) decoded_buffer = windows.utils.BUFFER( gdef.BYTE).from_buffer_copy(encoded_blob) decoded_size = gdef.DWORD(len(decoded_buffer)) winproxy.CryptVerifyMessageSignatureWithKey(verif_param, pubkey, signed_buffer, len(encoded_blob), decoded_buffer, decoded_size) return bytearray(decoded_buffer[:decoded_size.value])
def DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize=None, lpOutBuffer=NeededParameter, nOutBufferSize=None, lpBytesReturned=None, lpOverlapped=None): if nInBufferSize is None: nInBufferSize = len(lpInBuffer) if nOutBufferSize is None: nOutBufferSize = len(lpOutBuffer) if lpBytesReturned is None: # Some windows check 0 / others does not lpBytesReturned = ctypes.byref(gdef.DWORD()) return DeviceIoControl.ctypes_function(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped)
def values(self): """The values of the registry key :type: [:class:`KeyValue`] - A list of values""" res = [] # Get max info keys max_name_size, max_data_size = self.get_key_size_info() # Null terminators max_name_size += 1 max_data_size += 2 with ExpectWindowsError(259): for i in itertools.count(): value_type = gdef.DWORD() namesize = gdef.DWORD(max_name_size) keyname = ctypes.create_unicode_buffer(namesize.value) datasize = gdef.DWORD(max_data_size) databuffer = windows.utils.BUFFER(gdef.BYTE, nbelt=datasize.value)() # A value can have been added in-between. # So recheck the size given by get_key_size_info :) # But check 10 times max as RegEnumValueW may bug (seen) and always return ERROR_MORE_DATA even with enought size for _ in range(10): try: winproxy.RegEnumValueW(self.phkey, i, keyname, namesize, None, value_type, databuffer, datasize) break except WindowsError as e: if e.winerror != gdef.ERROR_MORE_DATA: raise # I found some strange Windows where even with a big enought buffer: # - the data was filled # - ERROR_MORE_DATA was returned ## To prevent such bug to trigger and infinite loop, two things # - If the retuned namesize <= the passed keysize and keyname is not empty -> return the data` # - Max 10 test to prevent Infinite loop if ((namesize.value <= max_name_size) and (datasize.value <= max_data_size) and (keyname[:namesize.value].count("\x00") < namesize.value)): # Not just 0 Zero ? break # Update the sizes / buffers & try again :) max_name_size, max_data_size = self.get_key_size_info() max_name_size = max( max_name_size + 1, namesize.value + 1 ) # namesize.value may be > to max_name_size apparently (guessed) max_data_size = max( max_data_size + 2, datasize.value + 2 ) # datasize.value may be > to max_data_size apparently (seen) namesize = gdef.DWORD(max_name_size) keyname = ctypes.create_unicode_buffer(namesize.value) datasize = gdef.DWORD(max_data_size) databuffer = windows.utils.BUFFER( gdef.BYTE, nbelt=datasize.value)() else: # Probably a windows bug that prevent us from retrieving the data # Raise something (thus preventing getting the other values..) ? ignore it ? raise ValueError( "Could not extract registry key values, problably a Windows/hook bug" ) vobj = decode_registry_buffer(value_type.value, databuffer, datasize.value) res.append(KeyValue(keyname.value, vobj, value_type.value)) return res
def connect_to_port(self, port_name, connect_message=None, port_attr=None, port_attr_flags=0x10000, obj_attr=None, flags=gdef.ALPC_MSGFLG_SYNC_REQUEST, timeout=None): """Connect to the ALPC port ``port_name``. Most of the parameters have defauls value is ``None`` is passed. :param AlpcMessage connect_message: The message send with the connection request, if not ``None`` the function will return an :class:`AlpcMessage` :param ALPC_PORT_ATTRIBUTES port_attr: The port attributes, one with default value will be used if this parameter is ``None`` :param int port_attr_flags: ``ALPC_PORT_ATTRIBUTES.Flags`` used if ``port_attr`` is ``None`` (MUTUALY EXCLUSINVE WITH ``port_attr``) :param OBJECT_ATTRIBUTES obj_attr: The attributes of the port (can be None) :param int flags: The flags for :func:`NtAlpcConnectPort` :param int timeout: The timeout of the request """ # TODO raise on mutual exclusive parameter if self.handle is not None: raise ValueError("Client already connected") handle = gdef.HANDLE() port_name_unicode = self._alpc_port_to_unicode_string(port_name) if port_attr is None: port_attr = gdef.ALPC_PORT_ATTRIBUTES() port_attr.Flags = port_attr_flags # Flag qui fonctionne pour l'UAC port_attr.MaxMessageLength = DEFAULT_MESSAGE_SIZE port_attr.MemoryBandwidth = 0 port_attr.MaxPoolUsage = 0xffffffff port_attr.MaxSectionSize = 0xffffffff port_attr.MaxViewSize = 0xffffffff port_attr.MaxTotalSectionSize = 0xffffffff port_attr.DupObjectTypes = 0xffffffff port_attr.SecurityQos.Length = ctypes.sizeof(port_attr.SecurityQos) port_attr.SecurityQos.ImpersonationLevel = gdef.SecurityImpersonation port_attr.SecurityQos.ContextTrackingMode = 0 port_attr.SecurityQos.EffectiveOnly = 0 if connect_message is None: send_msg = None send_msg_attr = None buffersize = None elif isinstance(connect_message, windows.pycompat.anybuff): buffersize = gdef.DWORD(len(connect_message) + 0x1000) send_msg = AlpcMessagePort.from_buffer_size(buffersize.value) send_msg.data = connect_message send_msg_attr = MessageAttribute.with_all_attributes() elif isinstance(connect_message, AlpcMessage): send_msg = connect_message.port_message send_msg_attr = connect_message.attributes buffersize = gdef.DWORD(connect_message.port_message_buffer_size) else: raise ValueError( "Don't know how to send <{0!r}> as connect message".format( connect_message)) receive_attr = MessageAttribute.with_all_attributes() winproxy.NtAlpcConnectPort(handle, port_name_unicode, obj_attr, port_attr, flags, None, send_msg, buffersize, send_msg_attr, receive_attr, timeout) # If send_msg is not None, it contains the ClientId.UniqueProcess : PID of the server :) self.handle = handle.value self.port_name = port_name return AlpcMessage(send_msg, receive_attr) if send_msg is not None else None
def NtProtectVirtualMemory(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection=None): if OldAccessProtection is None: OldAccessProtection = gdef.DWORD() return NtProtectVirtualMemory.ctypes_function(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection)
def raw_hash(self): size = gdef.DWORD(100) buffer = ctypes.c_buffer(size.value) winproxy.CryptHashCertificate(None, 0, 0, self.pbCertEncoded, self.cbCertEncoded, ctypes.cast(buffer, gdef.LPBYTE), size) return buffer[:size.value]
def size(self): array_size = gdef.DWORD() windows.winproxy.EvtGetObjectArraySize(self, array_size) return array_size.value
def VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect=None): if lpflOldProtect is None: lpflOldProtect = ctypes.byref(gdef.DWORD()) return VirtualProtect.ctypes_function(lpAddress, dwSize, flNewProtect, lpflOldProtect)
from pfwtest import * @pytest.mark.parametrize("type, size", [ (gdef.BYTE, 10), (gdef.DWORD, 12), (gdef.GUID, 42)]) def test_improved_BUFFER_size(type, size): x = utils.BUFFER(type, 1)(size=size) assert len(x) == 1 assert x.real_size == size assert len(x._raw_buffer_) == size @pytest.mark.parametrize("params, expected_type, expected_size", [ (([gdef.DWORD(x) for x in range(10)],), gdef.DWORD, 10), # list (([gdef.GUID() for x in range(10)],), gdef.GUID, 10), # generator ((range(42), gdef.ULONGLONG), gdef.ULONGLONG, 42), # Explicite type ]) def test_improved_buffer(params, expected_type, expected_size): x = utils.buffer(*params) assert x._type_ == expected_type assert len(x) == expected_size @pytest.mark.parametrize("c_type, buffer, expected_size", [ (gdef.CHAR, "12345", 5), (gdef.WCHAR, "\x001\x002\x003\x004\x005", 5), (gdef.DWORD, "1111222233334444", 4), ]) def test_parial_buffer_size_guess(c_type, buffer, expected_size): buf = windows.utils.BUFFER(c_type).from_buffer_copy(buffer)
def WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite=None, lpNumberOfBytesWritten=None, lpOverlapped=None): if nNumberOfBytesToWrite is None: nNumberOfBytesToWrite = len(lpBuffer) if lpOverlapped is None and lpNumberOfBytesWritten is None: lpNumberOfBytesWritten = ctypes.byref(gdef.DWORD()) return WriteFile.ctypes_function(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped)
def ReadFile(hFile, lpBuffer, nNumberOfBytesToRead=None, lpNumberOfBytesRead=None, lpOverlapped=None): if nNumberOfBytesToRead is None: nNumberOfBytesToRead = len(lpBuffer) if lpOverlapped is None and lpNumberOfBytesRead is None: lpNumberOfBytesRead = ctypes.byref(gdef.DWORD()) return ReadFile.ctypes_function(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped)
def GetTokenInformation(TokenHandle=NeededParameter, TokenInformationClass=NeededParameter, TokenInformation=None, TokenInformationLength=0, ReturnLength=None): if ReturnLength is None: ReturnLength = ctypes.byref(gdef.DWORD()) return GetTokenInformation.ctypes_function(TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength, ReturnLength)
def _get_object_name(self): lh = self.local_handle size_needed = gdef.DWORD() yyy = ctypes.c_buffer(0x1000) winproxy.NtQueryObject(lh, gdef.ObjectNameInformation, ctypes.byref(yyy), ctypes.sizeof(yyy), ctypes.byref(size_needed)) return gdef.LSA_UNICODE_STRING.from_buffer_copy(yyy[:size_needed.value]).str
def _lookup_name(self, luid): size = gdef.DWORD(0x100) buff = ctypes.c_buffer(size.value) winproxy.LookupPrivilegeNameA(None, luid, buff, size) return buff[:size.value]
def device_io_control(handle, iocode, buffer): outbuffer = ctypes.c_buffer(0x1000) returned_size = gdef.DWORD() windows.winproxy.DeviceIoControl(handle, iocode, buffer, lpOutBuffer=outbuffer, lpBytesReturned=returned_size) return outbuffer[:returned_size.value]
def GetWindowsDirectoryW(lpBuffer, uSize=None): if uSize is None: uSize = gdef.DWORD(len(lpBuffer)) return GetWindowsDirectoryW.ctypes_function(lpBuffer, uSize)
def GetFileVersionInfoSizeW(lptstrFilename, lpdwHandle=None): if lpdwHandle is None: lpdwHandle = ctypes.byref(gdef.DWORD()) return GetFileVersionInfoSizeW.ctypes_function(lptstrFilename, lpdwHandle)
def PeekNamedPipe(hNamedPipe): lpTotalBytesAvail = gdef.DWORD() PeekNamedPipe.ctypes_function(hNamedPipe, None, 0, None, lpTotalBytesAvail, None) return lpTotalBytesAvail.value
def providers(self): buffer = windows.utils.BUFFER(gdef.GUID, 0x1000)() size = gdef.DWORD() windows.winproxy.EnumerateTraceGuidsEx(gdef.TraceGuidQueryList, None, 0, buffer, buffer.real_size, size) return [TraceProvider(g) for g in buffer[:size.value / ctypes.sizeof(gdef.GUID)]]