diff --git a/samples/device/device_manager.py b/samples/device/device_manager.py deleted file mode 100644 index ee30497..0000000 --- a/samples/device/device_manager.py +++ /dev/null @@ -1,40 +0,0 @@ -import windows -import windows.generated_def as gdef - -manager = windows.system.device_manager -print(manager) -for devcls in manager.classes: - print("- {0!r}".format(devcls)) - for device in devcls.devices: - print(u" - [{dev.name}] <{dev.description}> ({dev.device_object_name})".format(dev=device)) - # Je sais pas trop quoi faire comme API sur ce truc - # Apparement on peut avoir plusieurs logical_configuration par type - # - Je sais meme pas si c'est possible en vrai meme si existe - # Idées: - # * get_allocated_conf + get_boot_conf & co - # * logical_configurations() qui retourne la liste complete - # * Je sais pas trop - # - devconf = device.get_first_logical_configuration(gdef.ALLOC_LOG_CONF) - if devconf: - # import pdb;pdb.set_trace() - # print(devconf) - print(" ") - for resource in devconf.resources: - print(" - {0}".format(resource)) - - # print(dev.description) - # print(dev.device_object_name) - # # x = dev.get_first_logical_configuration(gdef.ALLOC_LOG_CONF) - # x = dev.get_first_logical_configuration(gdef.BOOT_LOG_CONF) - # if x: - # print(x) - # for res in x.resources: - # print(res) - # # print(repr(res.rawdata)) - # print(res.header) - # assert not res.data - # # import pdb;pdb.set_trace() - # import pdb;pdb.set_trace() - # print("BYE") - diff --git a/samples/device_manager/device_manager.py b/samples/device_manager/device_manager.py new file mode 100644 index 0000000..8a3cc60 --- /dev/null +++ b/samples/device_manager/device_manager.py @@ -0,0 +1,51 @@ +import sys +import os.path +sys.path.append(os.path.abspath(__file__ + "\..\..")) + +import windows +import windows.generated_def as gdef + +devmgr = windows.system.device_manager +print("Device manager is {0}".format(devmgr)) + +print("Enumerating the first 3 device classes") +for cls in devmgr.classes[:3]: + print(" * {0}".format(cls)) + +print("Finding device class 'System'") +# Allow devmgr.classes["name"] ? +system_cls = [cls for cls in devmgr.classes if cls.name == "System"][0] +print(" * {0}".format(system_cls)) +print(" Enumerating some devices of 'System'") +devices = system_cls.devices.all() + +for devinst in (devices[0], devices[25], devices[35]): # Some "random" devices to have interesting ones + print(" * {0}".format(devinst)) + devconf = devinst.allocated_configuration + if not devconf: + continue + print(" Enumerating allocated resources:") + for resource in devconf.resources: + print(" * {0}".format(resource)) + + +# python64 samples\device\device_manager.py + +# Device manager is +# Enumerating the first 3 device classes +# * +# * +# * +# Finding device class 'System' +# * +# Enumerating some devices of 'System' +# * +# * +# Enumerating allocated resources: +# * +# * +# * +# Enumerating allocated resources: +# * +# * +# * diff --git a/samples/device_manager/enum_devices.py b/samples/device_manager/enum_devices.py new file mode 100644 index 0000000..19b7f0b --- /dev/null +++ b/samples/device_manager/enum_devices.py @@ -0,0 +1,48 @@ +import argparse + +import windows +import windows.generated_def as gdef + +devmgr = windows.system.device_manager + +def class_generator(filter=None): + for cls in devmgr.classes: + if filter and cls.name != filter: + continue + yield cls + + +def main(clsfilter, enumerate_devices, print_devinst_resources): + for devcls in class_generator(clsfilter): + print(devcls) + if not enumerate_devices: + continue + # Enumerate devices + for devinst in devcls.devices: + print(" * {0}".format(devinst)) + if not print_devinst_resources: + continue + # Device resources + devconf = devinst.allocated_configuration + if not devconf: + # No allocated configuration + # Check boot conf ? + continue + for resource in devconf.resources: + print(" * {0}".format(resource)) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(prog=__file__, formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument("--class", dest="clsfilter", default=None, help="The classe to list: default all") + parser.add_argument("--no-print-devices", action="store_true", help="Prevent the listing of devices in the matching classes") + parser.add_argument("--print-resources", action="store_true", help="Print the resources allocated to the device instance") + + args = parser.parse_args() + print(args) + main(args.clsfilter, + enumerate_devices=not args.no_print_devices, + print_devinst_resources=args.print_resources) + + + diff --git a/windows/winobject/device_manager.py b/windows/winobject/device_manager.py index 3144f23..d86ccc9 100644 --- a/windows/winobject/device_manager.py +++ b/windows/winobject/device_manager.py @@ -11,6 +11,9 @@ from windows.utils import fixedproperty class DeviceManager(object): @property def classes(self): + return list(self._classes_generator()) + + def _classes_generator(self): for index in itertools.count(): try: yield self._enumerate_classes(index, 0) @@ -55,7 +58,7 @@ class DeviceClass(gdef.GUID): def __repr__(self): guid_cls = self.to_string() - return """<{0} {2} name="{1}">""".format(type(self).__name__, self.name, guid_cls) + return """<{0} name="{1}" guid={2}>""".format(type(self).__name__, self.name, guid_cls) __str__ = __repr__ # Overwrite default GUID str @@ -80,6 +83,9 @@ class DeviceInformationSet(gdef.HDEVINFO): def enum_device_interface(self, index): raise NotImplementedError("enum_device_interface") + def all(self): + return list(self) + class DeviceInstance(gdef.SP_DEVINFO_DATA): def __init__(self, information_set=None): @@ -148,6 +154,9 @@ class DeviceInstance(gdef.SP_DEVINFO_DATA): raise + # https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/hardware-resources + # Explanation of types: + # - https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/hardware-resources#logical-configuration-types-for-resource-requirements-lists def get_first_logical_configuration(self, type): res = LogicalConfiguration() try: @@ -163,6 +172,49 @@ class DeviceInstance(gdef.SP_DEVINFO_DATA): winproxy.CM_Get_Next_Log_Conf(res, logconf) return res + def _logical_configuration_generator(self, type): + x = self.get_first_logical_configuration(type) + while x: + yield x + try: + x = self.get_next_logical_configuration(x) + except WindowsError as e: + if e.winerror == gdef.CR_NO_MORE_LOG_CONF: + return + raise + + def get_logical_configuration(self, type): + return list(self._logical_configuration_generator(type)) + + + # Allocated Configuration + # From https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/hardware-resources#logical-configuration-types-for-resource-lists + # A resource list identifying resources currently in use by a device instance. + # !!! Only one allocated configuration can exist for each device instance. + @property + def allocated_configuration(self): + allocconfs = self.get_logical_configuration(gdef.ALLOC_LOG_CONF) + if not allocconfs: + return allocconfs + assert len(allocconfs) == 1 # Only one allocated configuration can exist for each device instance. + return allocconfs[0] + + # Boot Configuration + # From https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/hardware-resources#logical-configuration-types-for-resource-lists + # A resource list identifying the resources assigned to a device instance when the system is booted + # Only one boot configuration can exist for each device instance. + + @property + def boot_configuration(self): + bootconfs = self.get_logical_configuration(gdef.BOOT_LOG_CONF) + if not bootconfs: + return bootconfs + assert len(bootconfs) == 1 # Only one boot configuration can exist for each device instance. + return bootconfs[0] + + + + # Make properties for Each type of logical configuration ? # 'advanced' attributes extrapolated from properties @property @@ -170,7 +222,7 @@ class DeviceInstance(gdef.SP_DEVINFO_DATA): return SecurityDescriptor.from_binary(self.raw_security_descriptor) def __repr__(self): - return """<{0} {1}>""".format(type(self).__name__, self.DevInst) + return """<{0} "{1}" (id={2})>""".format(type(self).__name__, self.description, self.DevInst) class LogicalConfiguration(gdef.HANDLE): @@ -305,7 +357,6 @@ class DmaResource(ResourceDescriptorWithHeaderAndRanges): DATA_TYPE = gdef.DMA_RESOURCE def __str__(self): - import pdb;pdb.set_trace() return "<{0} : [{1:#016x}]>".format(type(self).__name__, self.header.DD_Alloc_Chan) diff --git a/windows/winproxy/apis/cfgmgr32.py b/windows/winproxy/apis/cfgmgr32.py index 662ce3e..61c2f75 100644 --- a/windows/winproxy/apis/cfgmgr32.py +++ b/windows/winproxy/apis/cfgmgr32.py @@ -136,3 +136,7 @@ def CM_Get_Res_Des_Data_Size(pulSize, rdResDes, ulFlags=0): def CM_Get_Res_Des_Data(rdResDes, Buffer, BufferLen, ulFlags=0): return CM_Get_Res_Des_Data.ctypes_function(rdResDes, Buffer, BufferLen, ulFlags) + +@CfgMgr32Proxy() +def CM_Get_Parent(pdnDevInst, dnDevInst, ulFlags=0): + return CM_Get_Parent.ctypes_function(pdnDevInst, dnDevInst, ulFlags) \ No newline at end of file