def __init__(self, format, engine=CompressionEngine.Maximum): self.format = USHORT(format) self.format_engine = USHORT(format | engine) CompressBufferWorkSpaceSize = ULONG(0) CompressFragmentWorkSpaceSize = ULONG(0) Rtl.GetCompressionWorkSpaceSize( self.format_engine, byref(CompressBufferWorkSpaceSize), byref(CompressFragmentWorkSpaceSize)) self.ws = create_string_buffer(CompressBufferWorkSpaceSize.value)
def ConnectToLDAP(pConnectionInformation): dwRes = ULONG(LDAP_SUCCESS) version = ULONG(LDAP_VERSION3) size = ULONG(LDAP_NO_LIMIT) time = ULONG(LDAP_NO_LIMIT) hLDAPConnection = ldap_init(pConnectionInformation, LDAP_PORT) if hLDAPConnection == 0: print "Impossible to connect to LDAP\n" return 0 dwRes = ldap_set_option(hLDAPConnection, LDAP_OPT_PROTOCOL_VERSION, byref(version)) if dwRes != LDAP_SUCCESS: print "Unable to set LDAP protocol option (ErrorCode: %d).\r\n" % dwRes if hLDAPConnection != 0: ldap_unbind(hLDAPConnection) return 0 dwRes = ldap_set_option(hLDAPConnection, LDAP_OPT_SIZELIMIT, byref(size)) if dwRes != LDAP_SUCCESS: print "Unable to set LDAP size limit option (ErrorCode: %d).\r\n" % dwRes if hLDAPConnection != 0: ldap_unbind(hLDAPConnection) return 0 dwRes = ldap_set_option(hLDAPConnection, LDAP_OPT_TIMELIMIT, byref(time)) if dwRes != LDAP_SUCCESS: print "Unable to set LDAP time limit option (ErrorCode: %d).\r\n" % dwRes if hLDAPConnection != 0: ldap_unbind(hLDAPConnection) return 0 dwRes = ldap_connect(hLDAPConnection, 0) if dwRes != LDAP_SUCCESS: print "Unable to connect to LDAP server\n" if hLDAPConnection != 0: ldap_unbind(hLDAPConnection) return 0 dwRes = ldap_bind_s(hLDAPConnection, 0, 0, LDAP_AUTH_NEGOTIATE) if dwRes != LDAP_SUCCESS: print "Unable to bind to LDAP server\n" if hLDAPConnection != 0: ldap_unbind(hLDAPConnection) return 0 return cast(hLDAPConnection, PLDAP)
def vbusAttach(vbus, plugin): plugin.addr = vbusGetFreePort(vbus) unused = ULONG(0) if DeviceIoControl(vbus, IOCTL_USBVBUS_PLUGIN_HARDWARE, ctypes.byref(plugin), ctypes.sizeof(plugin), None, 0, ctypes.byref(unused), None): return plugin.addr else: raise VBUSException("Error attaching, error number = "+str(ctypes.GetLastError()))
def Decompress(self, input, output_buf=None): len_input, decomp_len = len(input), ULONG(0) output_buf = _get_buf(output_buf, len_input * 4) Rtl.DecompressBufferEx(self.format, _ptr(output_buf), len(output_buf), _ptr(input), len_input, byref(decomp_len), self.ws) return output_buf[:decomp_len.value]
def getPortInfo(self, screenOutput=False): """Get information and parameters of the port. Print to screen if screenOutput is Ture""" ftDev = ULONG() devID = DWORD() SN = c.c_buffer(16) desc = c.c_buffer(64) call_ft(dll.FT_GetDeviceInfo, self.handle, c.byref(ftDev), c.byref(devID), SN, desc, None) devs = [ 'BM', 'AM', '100AX', 'UNKNOWN', '2232C', '232R', '2232H', '4232H', '232H', 'X_SERIES', '4222H_0', '4222H_1_2', '4222H_3', '4222_PROG', '900', '930', 'UMFTPD3A' ] self._info.DeviceType = devs[ftDev.value] self._info.VIDPID = '0x%08X' % devID.value # '0x04036001' self._info.SerialNumber = SN.value.decode() # empty? self._info.Description = desc.value.decode() # 'USB <-> Serial' if os.sys.platform.startswith('win'): portNum = c.c_long() call_ft(dll.FT_GetComPortNumber, self.handle, c.byref(portNum)) self._info.ComPort = 'COM%i' % portNum.value if not screenOutput: class copy1(self._info): pass # changing the copy won't affect _info return copy1 for f in dir(self._info): if f.startswith('_') or f == 'mro': continue print('%20s: %s' % (f, getattr(self._info, f)))
def _query_handle(self, handle, klass, object_info_type): """Gets the object handle info. Parameters ---------- handle: HANDLE handle object klass: int the class of information to query object_info_type: Structure structure type which holds the handle info """ buff = malloc(self._object_buff_size) rlen = ULONG() status = nt_query_object(handle, klass, buff, self._object_buff_size, byref(rlen)) if status >= 0: info = cast(buff, POINTER(object_info_type)) self._buffers.append(buff) return info else: # reallocate the buffer size # and try again buff = realloc(buff, rlen.value) status = nt_query_object(handle, klass, buff, self._object_buff_size, None) if status >= 0: info = cast(buff, POINTER(object_info_type)) self._buffers.append(buff) return info else: free(buff) return None
def encrypt(self, data): global buf_size, buf l = len(data) block_size = len(self._iv_obj) if self._counter: remain_len = self._counter + l - block_size if remain_len > 0: result = b'\0' * self._counter + data[:block_size - self._counter] else: result = b'\0' * self._counter + data + b'\0' * -remain_len self._iv_obj.raw = xor(self._iv_obj.raw, result) result = self._iv_obj.raw[self._counter:self._counter + l] else: remain_len = l result = b'' if remain_len > 0: pad_len = -remain_len % block_size remain_data = data[-remain_len:] + b'\0' * pad_len cb_result = ULONG() if buf_size < remain_len + pad_len: buf_size = (remain_len + pad_len) * 2 buf = create_string_buffer(buf_size) res = bcrypt.BCryptEncrypt(self._key_handle, remain_data, remain_len + pad_len, None, byref(self._iv_obj), block_size, byref(buf), buf_size, byref(cb_result), 0) if res: self.clean() raise Exception('fail in BCryptEncrypt') result += buf.raw[:remain_len] self._counter = (self._counter + l) % block_size return result
def NtQueryObject(ObjectHandle, ObjectInformationClass): """ privilige_id: int """ _NtQueryObject = windll.ntdll.NtQueryObject _NtQueryObject.argtypes = [HANDLE, ULONG, PVOID, ULONG, PULONG] _NtQueryObject.restype = ULONG #if ObjectInformationClass not in [ObjectNameInformation, ObjectTypeInformation]: if ObjectInformationClass != ObjectTypeInformation: raise Exception('Unsupported ObjectInformationClass value %s.' % ObjectInformationClass) size = ULONG(0x10) oinfo_data = ctypes.create_string_buffer(size.value) while True: oinfo_data = ctypes.create_string_buffer(size.value) status = _NtQueryObject(ObjectHandle, ObjectInformationClass, oinfo_data, size, ctypes.byref(size)) if status == 0xc0000004: continue if status != 0: raise Exception('Failed call to NtDuplicateObject! Status: %s' % hex(status)) break if ObjectInformationClass == ObjectNameInformation: raise NotImplementedError('TODO: implement me when needed!') elif ObjectInformationClass == ObjectTypeInformation: oinfo = OBJECT_TYPE_INFORMATION.from_buffer( bytearray(oinfo_data.raw[:size.value])) return oinfo
def _cameras(): """ Get a list of ParamDicts for all cameras currently attached. """ cams = [] num = INT() if lib.is_GetNumberOfCameras(byref(num)) == IS_SUCCESS: if num >= 1: cam_list = create_camera_list(num)() cam_list.dwCount = ULONG(num.value) # This is stupid if lib.is_GetCameraList(pointer(cam_list)) == IS_SUCCESS: ids = [] repeated = [] for info in cam_list.ci: id = info.dwCameraID if id in ids: repeated.append(id) ids.append(id) if not repeated: for info in cam_list.ci: params = _ParamDict("<UC480_Camera '{}'>".format( info.SerNo)) params.module = 'cameras.uc480' params['cam_serial'] = info.SerNo params['cam_model'] = info.Model params['ueye_cam_id'] = int(info.dwCameraID) cams.append(params) else: log.info( "Some cameras have duplicate IDs. Uniquifying IDs now..." ) # Choose IDs that haven't been used yet potential_ids = [ i for i in range(1, len(ids) + 1) if i not in ids ] for id in repeated: new_id = potential_ids.pop(0) log.info("Trying to set id from {} to {}".format( id, new_id)) _id = HCAM(id) ret = lib.is_InitCamera(pointer(_id), NULL) if not ret == IS_SUCCESS: log.error( "Error connecting to camera {}".format(id)) return None # Avoid infinite recursion else: ret = lib.is_SetCameraID(_id, INT(new_id)) if not ret == IS_SUCCESS: log.error("Error setting the camera id") return None # Avoid infinite recursion # All IDs should be fixed now, let's retry cams = _cameras() else: raise Error("Error getting camera list") else: raise Error("Error getting number of attached cameras") return cams
def find_dolphin(self, skip_pids=[]): entry = PROCESSENTRY32() entry.dwSize = sizeof(PROCESSENTRY32) snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL) print(addressof(entry), hex(addressof(entry))) a = ULONG(addressof(entry)) self.pid = -1 if ctypes.windll.kernel32.Process32First(snapshot, pointer(entry)): if entry.th32ProcessID not in skip_pids and entry.szExeFile in ( b"Dolphin.exe", b"DolphinQt2.exe", b"DolphinWx.exe"): self.pid = entry.th32ProcessID else: while ctypes.windll.kernel32.Process32Next( snapshot, pointer(entry)): if entry.th32ProcessID in skip_pids: continue if entry.szExeFile in (b"Dolphin.exe", b"DolphinQt2.exe", b"DolphinWx.exe"): self.pid = entry.th32ProcessID ctypes.windll.kernel32.CloseHandle(snapshot) if self.pid == -1: return False return True
def Get_TGS(hLsaConnection, dwKerberosAuthenticationPackageId, SPNentry): LPTR = (0x0000 | 0x0040) list_of_target = SPNentry["serviceprincipalname"].split(";") for target in list_of_target: szSPN = create_unicode_buffer(target.lower()) dwSPNSize = USHORT((len(target)) * sizeof(wchar_t)) dwTicketPayloadSize = DWORD(sizeof(KERB_RETRIEVE_TKT_REQUEST) + dwSPNSize.value) KerbRetrieveEncodedTicketMessage = 8 KERB_ETYPE_RC4_HMAC_NT = 23 KERB_RETRIEVE_TICKET_DONT_USE_CACHE = (0x1) dwKerbRetrieveTicketRequestAddress = windll.kernel32.LocalAlloc(LPTR, dwTicketPayloadSize.value) pKerbRetrieveTicketRequest = cast(dwKerbRetrieveTicketRequestAddress, PKERB_RETRIEVE_TKT_REQUEST) pKerbRetrieveTicketRequest.contents.MessageType = KerbRetrieveEncodedTicketMessage # current logon session context pKerbRetrieveTicketRequest.contents.LogonID = 0 # TargetName pKerbRetrieveTicketRequest.contents.TargetName.Length = USHORT(dwSPNSize.value) pKerbRetrieveTicketRequest.contents.TargetName.MaximumLength = USHORT(dwSPNSize.value + sizeof(wchar_t)) dwKerbRetrieveTicketRequestBufferAddress = dwKerbRetrieveTicketRequestAddress + sizeof(KERB_RETRIEVE_TKT_REQUEST) memmove(dwKerbRetrieveTicketRequestBufferAddress, szSPN, pKerbRetrieveTicketRequest.contents.TargetName.Length) pKerbRetrieveTicketRequest.contents.TargetName.Buffer = cast(dwKerbRetrieveTicketRequestBufferAddress, PWSTR) pKerbRetrieveTicketRequest.contents.TicketFlags = ULONG(0) pKerbRetrieveTicketRequest.contents.CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE pKerbRetrieveTicketRequest.contents.EncryptionType = KERB_ETYPE_RC4_HMAC_NT pKerbRetrieveTicketRequest.contents.CredentialsHandle = SecHandle() pKerbRetrieveTicketResponse = PVOID() pKerbRetrieveTicketResponse = cast(pKerbRetrieveTicketResponse, PKERB_RETRIEVE_TKT_RESPONSE) dwProtocolStatus = DWORD(0) status = LsaCallAuthenticationPackage(hLsaConnection, dwKerberosAuthenticationPackageId, pKerbRetrieveTicketRequest, dwTicketPayloadSize, byref(pKerbRetrieveTicketResponse), byref(dwTicketPayloadSize), byref(dwProtocolStatus)) windll.kernel32.LocalFree(pKerbRetrieveTicketRequest) if status == STATUS_SUCCESS and dwProtocolStatus.value == STATUS_SUCCESS and dwTicketPayloadSize.value != 0: pKerbRetrieveTicketResponse = cast(pKerbRetrieveTicketResponse, PKERB_RETRIEVE_TKT_RESPONSE) pEncodedTicket = pKerbRetrieveTicketResponse.contents.Ticket.EncodedTicket dwEncodedTicketSize = pKerbRetrieveTicketResponse.contents.Ticket.EncodedTicketSize Ticket = "" for i in range(dwEncodedTicketSize): Ticket += hex(pEncodedTicket[i]).replace("0x",'').zfill(2) LsaFreeReturnBuffer(pKerbRetrieveTicketResponse) return Ticket else: print " [-] Cannot retrieve ticket for account '%s' and SPN '%s', status: %s ; protocolstatus: %s" % (SPNentry["samaccountname"], target, hex(status), hex(dwProtocolStatus.value)) print " [+] Trying the next one." print "[-] Could not retrieve any ticket for account '%s' and the list of SPN: '%s'" % (SPNentry["samaccountname"], SPNentry["serviceprincipalname"]) return 0
def Compress(self, input, output_buf=None): len_input, comp_len = len(input), ULONG(0) output_buf = _get_buf(output_buf, max(int(len_input * 1.5), len_input + 1024)) Rtl.CompressBuffer(self.format_engine, _ptr(input), len_input, _ptr(output_buf), len(output_buf), 4096, byref(comp_len), self.ws) return output_buf[:comp_len.value]
def SetFeature(self, buffer): if self.handle: bufferLength = ULONG(len(buffer)) result = ctypes.windll.hid.HidD_SetFeature( int(self.handle), ctypes.create_string_buffer(buffer), bufferLength) if not result: raise Exception("could not set feature")
def query_all_instances( self ): instances_len = ULONG(0) instances = pointer( IINST() ) if not BSCGetAllGlobalsArray( self.__bsc, enums.MBF.ALL, byref( instances ), byref( instances_len ) ): raise RuntimeError( "Unable to load all globals symbols" ) for i in range( instances_len.value ): self.__instances.append( instances[i] ) BSCDisposeArray( self.__bsc, instances )
def WinStationConnect(hServer, SessionID, TargetSessionID, Password="", Wait=False): if hServer is None: hServer = win32ts.WTS_CURRENT_SERVER_HANDLE if SessionID is None: SessionID = win32ts.WTS_CURRENT_SESSION if TargetSessionID is None: TargetSessionID = win32ts.WTS_CURRENT_SESSION res = winsta.WinStationConnectW(HANDLE(hServer), ULONG(SessionID), ULONG(TargetSessionID), LPWSTR(Password or ""), BOOL(Wait)) if res != 1: raise Win32Error(func="WinStationConnect")
def get_interface_by_index(index): table = MIB_IPADDRTABLE() size = ULONG(ctypes.sizeof(table)) table.dwNumEntries = 0 Iphlpapi.GetIpAddrTable(ctypes.byref(table), ctypes.byref(size), 0) for n in xrange(table.dwNumEntries): row = table.table[n] if row.dwIndex == index: return str(row.dwAddr) raise IndexError("interface index out of range")
def get_adapter_ips(): addressbuffersize = ULONG(15 * 1024) addressbuffer = (ctypes.create_string_buffer(addressbuffersize.value)) retval = iphlpapi.GetAdaptersAddresses(ULONG(AF_UNSPEC), ULONG(0), None, ctypes.byref(addressbuffer), ctypes.byref(addressbuffersize)) while retval == ERROR_BUFFER_OVERFLOW: addressbuffer = (ctypes.create_string_buffer( addressbuffersize.value)) retval = iphlpapi.GetAdaptersAddresses( ULONG(AF_UNSPEC), ULONG(0), None, ctypes.byref(addressbuffer), ctypes.byref(addressbuffersize)) if retval != NO_ERROR: raise ctypes.WinError() # Iterate through adapters fill array address_info = IP_ADAPTER_ADDRESSES.from_buffer(addressbuffer) while True: if address_info.FirstUnicastAddress: address = address_info.FirstUnicastAddress[0] while True: ip = sockaddr_to_ip(address.Address.lpSockaddr) if ip and ip != '127.0.0.1': logger.debug('adapter ip: ' + ip) yield ip if not address.Next: break address = address.Next[0] if not address_info.Next: break address_info = address_info.Next[0]
def instances( self ): instances_len = ULONG(0) instances_ids = pointer( IINST() ) if not BSCGetModuleContents( self.__bsc, self.mod_id, enums.MBF.ALL, byref( instances_ids ), byref( instances_len ) ): raise RuntimeError( "Unable to call BSCGetModuleContents" ) instances = map( lambda i: self.__bsc.create_instance( instances_ids[i] ) , range( instances_len.value ) ) BSCDisposeArray( self.__bsc, instances_ids ) return instances
def derived_classes(self): instances_len = ULONG(0) instances_ids = pointer( IINST() ) if not BSCGetDervArray( self.__bsc, self.inst_id, byref( instances_ids ), byref( instances_len ) ): raise RuntimeError( "Unable to call BSCGetDervArray" ) instances = map( lambda i: self.__bsc.create_instance( instances_ids[i] ) , range( instances_len.value ) ) BSCDisposeArray( self.__bsc, instances_ids ) return instances
def definitions( self ): definitions_len = ULONG(0) definitions_ids = pointer( IDEF() ) if not BSCGetDefArray( self.__bsc, self.inst_id, byref( definitions_ids ), byref( definitions_len ) ): raise RuntimeError( "Unable to call BSCGetDefArray" ) definitions = map( lambda i: definition_t( definitions_ids[i], self.__bsc ) , range( definitions_len.value ) ) BSCDisposeArray( self.__bsc, definitions_ids ) return definitions
def get_device_id(devinst, buf=None): if buf is None: buf = create_unicode_buffer(512) while True: ret = CM_Get_Device_ID(devinst, buf, len(buf), 0) if ret == CR_CODES['CR_BUFFER_SMALL']: devid_size = ULONG(0) CM_Get_Device_ID_Size(byref(devid_size), devinst, 0) buf = create_unicode_buffer(devid_size.value) continue if ret != CR_CODES['CR_SUCCESS']: raise WindowsError((ret, 'The cfgmgr32 function failed with err: %s' % CR_CODE_NAMES.get(ret, ret))) break return wstring_at(buf), buf
def files(self): module_ids = pointer( IMOD() ) module_len = ULONG() bs = BSC_STAT() if not BSCGetAllModulesArray( self.__bsc, module_ids, byref(module_len) ): raise RuntimeError( "Unable to load all modules" ) modules = map( lambda i: module_t( module_ids[i], self.__bsc ) , range( module_len.value ) ) BSCDisposeArray( self.__bsc, module_ids ) return modules
def run(self): InvariantAwareCommand.run(self) from tracer import rtl, RTL from ctypes import create_string_buffer, sizeof, byref from ctypes.wintypes import ULONG #self.rtl = RTL() self.rtl_size = ULONG() rtl_dll = rtl(self.conf.tracer_rtl_debug_dll_path) success = rtl_dll.InitializeRtl( 0, byref(self.rtl_size) ) self.rtl = create_string_buffer(self.rtl_size.value) import pdb pdb.set_trace() success = rtl_dll.InitializeRtl( byref(self.rtl), byref(self.rtl_size) ) if not success: if self.rtl_size.value != sizeof(self.rtl): msg = "Warning: RTL size mismatch: %d != %d\n" % ( self.rtl_size.value, sizeof(self.rtl) ) self._err(msg) self.rtl = create_string_buffer( self.rtl_size.value ) success = rtl_dll.InitializeRtl( byref(self.rtl), byref(self.rtl_size), ) if not success: raise RuntimeError("InitializeRtl() failed") self._out("Loaded Rtl successfully.") self.interactive = True return self
def decrypt(self, data): global buf_size, buf l = len(data) block_size = len(self._iv_obj) if self._counter % block_size: last_plain = buf.raw[self._counter // block_size * block_size:self._counter // block_size * block_size + block_size] remain_len = (self._counter % block_size) + l - block_size if remain_len > 0: self._iv_obj.raw = self._iv_obj.raw[:self._counter % block_size] + data[:block_size - (self. _counter % block_size )] else: self._iv_obj.raw = self._iv_obj.raw[:self._counter % block_size] + data + b'\0' * -remain_len result = xor(self._iv_obj.raw, last_plain)[self._counter % block_size:(self._counter % block_size) + l] else: remain_len = l result = b'' if remain_len > 0: pad_len = -remain_len % block_size remain_data = data[-remain_len:] + b'\0' * pad_len cb_result = ULONG() if buf_size < remain_len + pad_len: buf_size = (remain_len + pad_len) * 2 buf = create_string_buffer(buf_size) res = bcrypt.BCryptDecrypt(self._key_handle, remain_data, remain_len + pad_len, None, byref(self._iv_obj), block_size, byref(buf), buf_size, byref(cb_result), 0) if res: self.clean() raise Exception('fail in BCryptDecrypt') result += buf.raw[:remain_len] self._counter = remain_len if remain_len > 0 else self._counter + l return result
def NtQuerySystemInformation(info_type): _NtQuerySystemInformation = windll.ntdll.NtQuerySystemInformation _NtQuerySystemInformation.argtypes = [ULONG, PVOID, ULONG, PULONG] _NtQuerySystemInformation.restype = ULONG handleinfos = {} if info_type != 16: raise Exception('info_type only the value 16 is supported!') size = DWORD(0x10) data = ctypes.create_string_buffer(size.value) while True: #_NtQuerySystemInformation returns an incorrect expected size... size = DWORD(size.value * 2) data = ctypes.create_string_buffer(size.value) status = _NtQuerySystemInformation(info_type, ctypes.byref(data), size, ctypes.byref(size)) if status == 0: break if status != 0xC0000004: raise Exception('NtQuerySystemInformation returned %s' % hex(status)) status = _NtQuerySystemInformation(info_type, ctypes.byref(data), size, ctypes.byref(size)) data_bytes = bytearray(data.raw[:size.value]) hc = ULONG.from_buffer(data_bytes) class SYSTEM_HANDLE_INFORMATION(Structure): _fields_ = [ ("HandleCount", ULONG), ("Handles", SYSTEM_HANDLE * hc.value), #not just one handle ] syshandleinfo = SYSTEM_HANDLE_INFORMATION.from_buffer(data_bytes) for i in range(syshandleinfo.HandleCount): if not syshandleinfo.Handles[i].ProcessId in handleinfos: handleinfos[syshandleinfo.Handles[i].ProcessId] = [] handleinfos[syshandleinfo.Handles[i].ProcessId].append( syshandleinfo.Handles[i]) return handleinfos
def aead_encrypt(self, data): """ Encrypt data with authenticate tag :param data: plain text :return: cipher text with tag """ global buf_size, buf cb_result = ULONG() plen = len(data) if buf_size < plen: buf_size = plen * 2 buf = create_string_buffer(buf_size) self._auth_cipher_mode_info.pbTag = cast(byref(tag_buf), PUCHAR) res = bcrypt.BCryptEncrypt(self._key_handle, data, plen, byref(self._auth_cipher_mode_info), None, 0, byref(buf), buf_size, byref(cb_result), 0) if res: self.clean() raise Exception('fail in BCryptEncrypt') return buf.raw[:cb_result.value] + tag_buf[:self._tlen]
def comports(): """This generator scans the device registry for com ports and yields port, desc, hwid""" g_hdi = SetupDiGetClassDevs(ctypes.byref(GUID_CLASS_COMPORT), None, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); #~ for i in range(256): for dwIndex in range(256): did = SP_DEVICE_INTERFACE_DATA() did.cbSize = ctypes.sizeof(did) if not SetupDiEnumDeviceInterfaces(g_hdi, None, ctypes.byref(GUID_CLASS_COMPORT), dwIndex, ctypes.byref(did)): if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS: raise ctypes.WinError() break dwNeeded = DWORD() # get the size if not SetupDiGetDeviceInterfaceDetail(g_hdi, ctypes.byref(did), None, 0, ctypes.byref(dwNeeded), None): # Ignore ERROR_INSUFFICIENT_BUFFER if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: raise ctypes.WinError() # allocate buffer class SP_DEVICE_INTERFACE_DETAIL_DATA_A(ctypes.Structure): _fields_ = [ ('cbSize', DWORD), ('DevicePath', CHAR*(dwNeeded.value - ctypes.sizeof(DWORD))), ] def __str__(self): return "DevicePath:%s" % (self.DevicePath,) idd = SP_DEVICE_INTERFACE_DETAIL_DATA_A() if is_64bit(): idd.cbSize = 8 else: idd.cbSize = 5 devinfo = SP_DEVINFO_DATA() devinfo.cbSize = ctypes.sizeof(devinfo) if not SetupDiGetDeviceInterfaceDetail(g_hdi, ctypes.byref(did), ctypes.byref(idd), dwNeeded, None, ctypes.byref(devinfo)): raise ctypes.WinError() # hardware ID szHardwareID = byte_buffer(250) if not SetupDiGetDeviceRegistryProperty(g_hdi, ctypes.byref(devinfo), SPDRP_HARDWAREID, None, ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): # Ignore ERROR_INSUFFICIENT_BUFFER if GetLastError() != ERROR_INSUFFICIENT_BUFFER: raise ctypes.WinError() # friendly name szFriendlyName = byte_buffer(250) if not SetupDiGetDeviceRegistryProperty(g_hdi, ctypes.byref(devinfo), SPDRP_FRIENDLYNAME, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None): # Ignore ERROR_INSUFFICIENT_BUFFER if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) port_name = None else: # the real com port name has to read differently... hkey = SetupDiOpenDevRegKey(g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) port_name_buffer = byte_buffer(250) port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) RegQueryValueEx(hkey, PortName, None, None, ctypes.byref(port_name_buffer), ctypes.byref(port_name_length)) RegCloseKey(hkey) yield string(port_name_buffer), string(szFriendlyName), string(szHardwareID) SetupDiDestroyDeviceInfoList(g_hdi)
def iterate_comports(): """Return a generator that yields descriptions for serial ports""" PortsGUIDs = (GUID * 8)() # so far only seen one used, so hope 8 are enough... ports_guids_size = DWORD() if not SetupDiClassGuidsFromName("Ports", PortsGUIDs, ctypes.sizeof(PortsGUIDs), ctypes.byref(ports_guids_size)): raise ctypes.WinError() ModemsGUIDs = (GUID * 8)() # so far only seen one used, so hope 8 are enough... modems_guids_size = DWORD() if not SetupDiClassGuidsFromName("Modem", ModemsGUIDs, ctypes.sizeof(ModemsGUIDs), ctypes.byref(modems_guids_size)): raise ctypes.WinError() GUIDs = PortsGUIDs[:ports_guids_size. value] + ModemsGUIDs[:modems_guids_size.value] # repeat for all possible GUIDs for index in range(len(GUIDs)): bInterfaceNumber = None g_hdi = SetupDiGetClassDevs( ctypes.byref(GUIDs[index]), None, NULL, DIGCF_PRESENT ) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports devinfo = SP_DEVINFO_DATA() devinfo.cbSize = ctypes.sizeof(devinfo) index = 0 while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): index += 1 # get the real com port name hkey = SetupDiOpenDevRegKey( g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, # DIREG_DRV for SW info KEY_READ) port_name_buffer = ctypes.create_unicode_buffer(250) port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) RegQueryValueEx(hkey, "PortName", None, None, ctypes.byref(port_name_buffer), ctypes.byref(port_name_length)) RegCloseKey(hkey) # unfortunately does this method also include parallel ports. # we could check for names starting with COM or just exclude LPT # and hope that other "unknown" names are serial ports... if port_name_buffer.value.startswith('LPT'): continue # hardware ID szHardwareID = ctypes.create_unicode_buffer(250) # try to get ID that includes serial number if not SetupDiGetDeviceInstanceId( g_hdi, ctypes.byref(devinfo), #~ ctypes.byref(szHardwareID), szHardwareID, ctypes.sizeof(szHardwareID) - 1, None): # fall back to more generic hardware ID if that would fail if not SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_HARDWAREID, None, ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): # Ignore ERROR_INSUFFICIENT_BUFFER if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: raise ctypes.WinError() # stringify szHardwareID_str = szHardwareID.value info = list_ports_common.ListPortInfo(port_name_buffer.value, skip_link_detection=True) # in case of USB, make a more readable string, similar to that form # that we also generate on other platforms if szHardwareID_str.startswith('USB'): m = re.search( r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(.*))?', szHardwareID_str, re.I) if m: info.vid = int(m.group(1), 16) if m.group(3): info.pid = int(m.group(3), 16) if m.group(5): bInterfaceNumber = int(m.group(5)) # Check that the USB serial number only contains alpha-numeric characters. It # may be a windows device ID (ephemeral ID) for composite devices. if m.group(7) and re.match(r'^\w+$', m.group(7)): info.serial_number = m.group(7) else: info.serial_number = get_parent_serial_number( devinfo.DevInst, info.vid, info.pid) # calculate a location string loc_path_str = ctypes.create_unicode_buffer(250) if SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_LOCATION_PATHS, None, ctypes.byref(loc_path_str), ctypes.sizeof(loc_path_str) - 1, None): m = re.finditer(r'USBROOT\((\w+)\)|#USB\((\w+)\)', loc_path_str.value) location = [] for g in m: if g.group(1): location.append('{:d}'.format(int(g.group(1)) + 1)) else: if len(location) > 1: location.append('.') else: location.append('-') location.append(g.group(2)) if bInterfaceNumber is not None: location.append(':{}.{}'.format( 'x', # XXX how to determine correct bConfigurationValue? bInterfaceNumber)) if location: info.location = ''.join(location) info.hwid = info.usb_info() elif szHardwareID_str.startswith('FTDIBUS'): m = re.search( r'VID_([0-9a-f]{4})\+PID_([0-9a-f]{4})(\+(\w+))?', szHardwareID_str, re.I) if m: info.vid = int(m.group(1), 16) info.pid = int(m.group(2), 16) if m.group(4): info.serial_number = m.group(4) # USB location is hidden by FDTI driver :( info.hwid = info.usb_info() else: info.hwid = szHardwareID_str # friendly name szFriendlyName = ctypes.create_unicode_buffer(250) if SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_FRIENDLYNAME, #~ SPDRP_DEVICEDESC, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None): info.description = szFriendlyName.value #~ else: # Ignore ERROR_INSUFFICIENT_BUFFER #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) # ignore errors and still include the port in the list, friendly name will be same as port name # manufacturer szManufacturer = ctypes.create_unicode_buffer(250) if SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_MFG, #~ SPDRP_DEVICEDESC, None, ctypes.byref(szManufacturer), ctypes.sizeof(szManufacturer) - 1, None): info.manufacturer = szManufacturer.value yield info SetupDiDestroyDeviceInfoList(g_hdi)
def comports(): GUIDs = (GUID * 8)() # so far only seen one used, so hope 8 are enough... guids_size = DWORD() if not SetupDiClassGuidsFromName(Ports, GUIDs, ctypes.sizeof(GUIDs), ctypes.byref(guids_size)): raise ctypes.WinError() # repeat for all possible GUIDs for index in range(guids_size.value): g_hdi = SetupDiGetClassDevs( ctypes.byref(GUIDs[index]), None, NULL, DIGCF_PRESENT ) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports devinfo = SP_DEVINFO_DATA() devinfo.cbSize = ctypes.sizeof(devinfo) index = 0 while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): index += 1 # get the real com port name hkey = SetupDiOpenDevRegKey( g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, # DIREG_DRV for SW info KEY_READ) port_name_buffer = byte_buffer(250) port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) RegQueryValueEx(hkey, PortName, None, None, ctypes.byref(port_name_buffer), ctypes.byref(port_name_length)) RegCloseKey(hkey) # unfortunately does this method also include parallel ports. # we could check for names starting with COM or just exclude LPT # and hope that other "unknown" names are serial ports... if string(port_name_buffer).startswith('LPT'): continue # hardware ID szHardwareID = byte_buffer(250) # try to get ID that includes serial number if not SetupDiGetDeviceInstanceId( g_hdi, ctypes.byref(devinfo), ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): # fall back to more generic hardware ID if that would fail if not SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_HARDWAREID, None, ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): # Ignore ERROR_INSUFFICIENT_BUFFER if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: raise ctypes.WinError() # stringify szHardwareID_str = string(szHardwareID) # in case of USB, make a more readable string, similar to that form # that we also generate on other platforms if szHardwareID_str.startswith('USB'): m = re.search(r'VID_([0-9a-f]{4})&PID_([0-9a-f]{4})(\\(\w+))?', szHardwareID_str, re.I) if m: if m.group(4): szHardwareID_str = 'USB VID:PID=%s:%s SNR=%s' % ( m.group(1), m.group(2), m.group(4)) else: szHardwareID_str = 'USB VID:PID=%s:%s' % (m.group(1), m.group(2)) # friendly name szFriendlyName = byte_buffer(250) if not SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_FRIENDLYNAME, #~ SPDRP_DEVICEDESC, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None): # Ignore ERROR_INSUFFICIENT_BUFFER #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) # ignore errors and still include the port in the list, friendly name will be same as port name yield string(port_name_buffer), 'n/a', szHardwareID_str else: yield string(port_name_buffer), string( szFriendlyName), szHardwareID_str SetupDiDestroyDeviceInfoList(g_hdi)
def comports(): GUIDs = (GUID * 8)() # so far only seen one used, so hope 8 are enough... guids_size = DWORD() if not SetupDiClassGuidsFromName(Ports, GUIDs, ctypes.sizeof(GUIDs), ctypes.byref(guids_size)): raise ctypes.WinError() # repeat for all possible GUIDs for index in range(guids_size.value): g_hdi = SetupDiGetClassDevs( ctypes.byref(GUIDs[index]), None, NULL, DIGCF_PRESENT ) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports devinfo = SP_DEVINFO_DATA() devinfo.cbSize = ctypes.sizeof(devinfo) index = 0 while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): index += 1 # get the real com port name hkey = SetupDiOpenDevRegKey( g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, # DIREG_DRV for SW info KEY_READ) port_name_buffer = byte_buffer(250) port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) RegQueryValueEx(hkey, PortName, None, None, ctypes.byref(port_name_buffer), ctypes.byref(port_name_length)) RegCloseKey(hkey) # unfortunately does this method also include parallel ports. # we could check for names starting with COM or just exclude LPT # and hope that other "unknown" names are serial ports... if string(port_name_buffer).startswith('LPT'): continue # hardware ID szHardwareID = byte_buffer(250) # try to get ID that includes serial number if not SetupDiGetDeviceInstanceId( g_hdi, ctypes.byref(devinfo), ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): # fall back to more generic hardware ID if that would fail if not SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_HARDWAREID, None, ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): # Ignore ERROR_INSUFFICIENT_BUFFER if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: raise ctypes.WinError() # stringify szHardwareID_str = string(szHardwareID) info = list_ports_common.ListPortInfo(string(port_name_buffer)) # in case of USB, make a more readable string, similar to that form # that we also generate on other platforms if szHardwareID_str.startswith('USB'): m = re.search(r'VID_([0-9a-f]{4})&PID_([0-9a-f]{4})(\\(\w+))?', szHardwareID_str, re.I) if m: info.vid = int(m.group(1), 16) info.pid = int(m.group(2), 16) if m.group(4): info.serial_number = m.group(4) # calculate a location string # XXX was empty in tests with (internal) USB3 hub :( loc_path_str = byte_buffer(250) if SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_LOCATION_PATHS, None, ctypes.byref(loc_path_str), ctypes.sizeof(loc_path_str) - 1, None): #~ print (string(loc_path_str)) m = re.finditer(r'USBROOT\((\w+)\)|#USB\((\w+)\)', string(loc_path_str)) location = [] for g in m: if g.group(1): location.append('%d' % (int(g.group(1)) + 1)) else: if len(location) > 1: location.append('.') else: location.append('-') location.append(g.group(2)) if location: info.location = ''.join(location) info.hwid = info.usb_info() else: info.hwid = szHardwareID_str # friendly name szFriendlyName = byte_buffer(250) if SetupDiGetDeviceRegistryProperty( g_hdi, ctypes.byref(devinfo), SPDRP_FRIENDLYNAME, #~ SPDRP_DEVICEDESC, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None): info.description = string(szFriendlyName) #~ else: # Ignore ERROR_INSUFFICIENT_BUFFER #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) # ignore errors and still include the port in the list, friendly name will be same as port name yield info SetupDiDestroyDeviceInfoList(g_hdi)