import struct from struct import pack, calcsize def patch_impacket_wmi(): """对 impacket WMI 模块进行运行时补丁: 1. ENCODED_VALUE.getValue: 加速 uint8 数组 (CIM_TYPE 0x2011) 处理 2. addNewAttribute: 支持 qualifiers 参数 (list), 标记属性 qualifier 3. __createCimTypeQualifierSet -> __buildPropertyQualifierSet: 支持多 qualifier 构建 4. marshalMe: 解包 4 元素 tuple 并传递 qualifiers 5. callMethod: kwargs 形式的 WMI method 呼叫, 未提供的 InParams 以 NdTable=null 标记 (等价 wmic 行为), 避免 singleton class 大 Set 方法被迫全参数覆写。 以 `cls.callMethod("Set", Foo=1, Bar=2)` 呼叫。 6. createMethods-bound dispatcher: 对 class object 自动绑定的方法加一层分派: - 纯 kwargs → callMethod - 其它 → impacket 原 positional 路径 (保持 StdRegProv.SetDWORDValue 等相容) """ from impacket.dcerpc.v5.dcom.wmi import ( ENCODED_VALUE, IWbemClassObject, QUALIFIER, QUALIFIER_SET, DICTIONARY_REFERENCE_TO_VALUE, CIM_TYPE_ENUM, CIM_TYPES_REF, CIM_ARRAY_FLAG, ENCODED_STRING, CIM_TYPE_TO_NAME, ) # === 补丁 1: 加速 uint8 数组读取 === _original_getValue = ENCODED_VALUE.getValue @staticmethod def _fast_getValue(cimType, entry, heap): if cimType == 0x2011: # CIM_UINT8 | CIM_ARRAY_FLAG try: if isinstance(entry, int): heapOffset = entry else: heapOffset = struct.unpack('>= 8 instance_type = INSTANCE_TYPE() instance_type['CurrentClass'] = b'' instance_type['InstanceQualifierSet'] = b'\x04\x00\x00\x00\x01' instance_type['NdTable_ValueTable'] = packed_nd + value_table heap_rec = HEAP() heap_rec['HeapLength'] = len(instance_heap) | 0x80000000 heap_rec['HeapItem'] = instance_heap instance_type['InstanceHeap'] = heap_rec # Match createMethods ordering: compute EncodingLength BEFORE assigning the # real CurrentClass; CurrentClass bytes are appended trailing. instance_type['EncodingLength'] = len(instance_type) class_part = method_def['InParamsRaw']['ClassType']['CurrentClass']['ClassPart'] class_part['ClassHeader']['EncodingLength'] = len(class_part.getData()) instance_type['CurrentClass'] = class_part obj_block = OBJECT_BLOCK() obj_block.structure += OBJECT_BLOCK.instanceType obj_block['ObjectFlags'] = CIM_INSTANCE obj_block['Decoration'] = b'' obj_block['InstanceType'] = instance_type.getData() enc = ENCODING_UNIT() enc['ObjectBlock'] = obj_block enc['ObjectEncodingLength'] = len(obj_block) objref = OBJREF_CUSTOM() objref['iid'] = self._iid objref['clsid'] = CLSID_WbemClassObject objref['cbExtension'] = 0 objref['ObjectReferenceSize'] = len(enc) objref['pObjectData'] = enc ws = self._IWbemClassObject__iWbemServices try: return ws.ExecMethod(self.getClassName(), methodName, pInParams=objref) except TypeError as e: # impacket ExecMethod fails to parse OutParams for certain methods whose # response payload is a flat byte blob (e.g. methods returning only # uint32 ReturnValue). The RPC itself succeeded — swallow the parsing # error and return None; caller verifies via subsequent query. if "byte indices must be integers" in str(e): return None raise IWbemClassObject.callMethod = _callMethod # === 补丁 6: createMethods 绑定的方法支援 kwargs 语法 === # # impacket 的 createMethods 为 class object 自动绑定方法, # 只接受全部 InParams 的 positional。这里 post-wrap 成 dispatcher, # 支援两种呼叫形式: # (a) cls.Set(Foo=1, Bar=2) — Python kwargs, 路由到 patch 5 callMethod, # 未指定 InParam 自动 NdTable=null # (b) cls.Method(a, b, c, ...) — 原有 positional 不变 (StdRegProv 等沿用) _orig_createMethods = IWbemClassObject.createMethods def _wrapped_createMethods(self, classOrInstance, methods): _orig_createMethods(self, classOrInstance, methods) for methodName in methods: original = getattr(self, methodName) def _make_dispatcher(mname, orig): def dispatcher(*args, **kwargs): if kwargs and not args: return self.callMethod(mname, **kwargs) return orig(*args) dispatcher.__name__ = mname return dispatcher setattr(self, methodName, _make_dispatcher(methodName, original)) IWbemClassObject.createMethods = _wrapped_createMethods