mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Some more py3 compat fix + few feature in POC
This commit is contained in:
+3
-2
@@ -19,8 +19,9 @@ if sys.platform != "win32":
|
||||
from windows import winproxy
|
||||
from windows import winobject
|
||||
|
||||
from winobject.system import System
|
||||
from winobject.process import CurrentProcess, CurrentThread, WinProcess, WinThread
|
||||
from .winobject.system import System
|
||||
from .winobject.process import CurrentProcess, CurrentThread, WinProcess, WinThread
|
||||
from .winobject.file import WinFile
|
||||
|
||||
|
||||
system = System()
|
||||
|
||||
+7
-8
@@ -51,7 +51,6 @@ for func in windows.generated_def.meta.functions:
|
||||
|
||||
class IATHook(object):
|
||||
"""Look at my hook <3"""
|
||||
yolo = []
|
||||
|
||||
def __init__(self, IAT_entry, callback, types=None):
|
||||
if types is None:
|
||||
@@ -62,11 +61,14 @@ class IATHook(object):
|
||||
self.callback_types = self.transform_arguments(self.original_types)
|
||||
self.entry = IAT_entry
|
||||
self.callback = callback
|
||||
## No more circular ref -> but stub is destroyed -> segv :(
|
||||
self.stub = ctypes.WINFUNCTYPE(*self.callback_types)(self.hook_callback)
|
||||
self.stub_addr = ctypes.cast(self.stub, PVOID).value
|
||||
# stub = ctypes.WINFUNCTYPE(*self.callback_types)(self.hook_callback)
|
||||
# self.stub_addr = ctypes.cast(stub, PVOID) # Same problem as keep stub... (GC..)
|
||||
self.stub_addr = ctypes.cast(self.stub, PVOID).value # Same problem as keep stub... (GC..)
|
||||
# IAT_entry.stub = stub
|
||||
self.realfunction = ctypes.WINFUNCTYPE(*types)(IAT_entry.nonhookvalue)
|
||||
self.is_enable = False
|
||||
#IATHook.yolo.append(self)
|
||||
|
||||
def transform_arguments(self, types):
|
||||
res = []
|
||||
@@ -82,12 +84,14 @@ class IATHook(object):
|
||||
with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), PAGE_EXECUTE_READWRITE):
|
||||
self.entry.value = self.stub_addr
|
||||
self.is_enable = True
|
||||
self.entry.enabled = True
|
||||
|
||||
def disable(self):
|
||||
"""Disable the IAT hook"""
|
||||
with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), PAGE_EXECUTE_READWRITE):
|
||||
self.entry.value = self.entry.nonhookvalue
|
||||
self.is_enable = False
|
||||
self.entry.enabled = True
|
||||
|
||||
def hook_callback(self, *args):
|
||||
adapted_args = []
|
||||
@@ -105,11 +109,6 @@ class IATHook(object):
|
||||
return self.realfunction(*args)
|
||||
return self.callback(*adapted_args, real_function=real_function)
|
||||
|
||||
# Use this tricks to prevent garbage collection of hook ?
|
||||
#def __del__(self):
|
||||
# pass
|
||||
|
||||
|
||||
## New simple hook API based on winproxy
|
||||
def setup_hook(target, hook, dll_to_hook):
|
||||
"TODO: Test and doc :D"
|
||||
|
||||
@@ -6,6 +6,7 @@ from contextlib import contextmanager
|
||||
import windows
|
||||
import windows.generated_def as gdef
|
||||
from windows import winproxy
|
||||
from windows.pycompat import int_types
|
||||
|
||||
|
||||
# Helpers
|
||||
@@ -244,7 +245,8 @@ class EvtEvent(EvtHandle):
|
||||
# What about classic channels where there is no event_metadata ?
|
||||
# Return a dict with [0-1-2-3-4] as key ? raise ?
|
||||
# Juste use the render_xml ?
|
||||
return {k:v for k,v in zip(self.metadata.event_data, self.event_values())}
|
||||
event_data_name = (i["name"] for i in self.metadata.event_data if i["type"] == "data")
|
||||
return {k:v for k,v in zip(event_data_name, self.event_values())}
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
@@ -305,6 +307,27 @@ class ImprovedEVT_VARIANT(gdef.EVT_VARIANT):
|
||||
v = v[:self.Count]
|
||||
return v
|
||||
|
||||
@classmethod
|
||||
def from_value(cls, value, vtype=None):
|
||||
if vtype is None:
|
||||
# Guess type
|
||||
if isinstance(value, int_types):
|
||||
vtype = gdef.EvtVarTypeUInt64
|
||||
elif isinstance(value, basestring):
|
||||
vtype = gdef.EvtVarTypeString
|
||||
else:
|
||||
raise NotImplementedError("LATER")
|
||||
self = cls()
|
||||
# import pdb;pdb.set_trace()
|
||||
# Yolo test :)
|
||||
super(ImprovedEVT_VARIANT, ImprovedEVT_VARIANT).Type.__set__(self, vtype)
|
||||
# super(ImprovedEVT_VARIANT, self).Type = vtype
|
||||
attrname = self.VALUE_MAPPER[self.Type]
|
||||
setattr(self, attrname, value)
|
||||
if self.Type in (gdef.EvtVarTypeBinary, gdef.EvtVarTypeString):
|
||||
self.Count = len(value)
|
||||
return self
|
||||
|
||||
def __repr__(self):
|
||||
return "<{0} of type={1}>".format(type(self).__name__, self.Type)
|
||||
|
||||
@@ -360,7 +383,7 @@ class EvtChannel(object):
|
||||
if ids and filter:
|
||||
raise ValueError("<ids> and <filter> are mutually exclusive")
|
||||
if ids is not None:
|
||||
if isinstance(ids, (long, int)):
|
||||
if isinstance(ids, int_types):
|
||||
ids = (ids,)
|
||||
ids_filter = " or ".join("EventID={0}".format(id) for id in ids)
|
||||
filter = "Event/System[{0}]".format(ids_filter)
|
||||
@@ -854,19 +877,45 @@ class EventMetadata(EvtHandle):
|
||||
"""Identifies the template attribute of the event definition which is an XML string"""
|
||||
return eventinfo(self, gdef.EventMetadataEventTemplate).value
|
||||
|
||||
def _parse_event_template_data_element(self, element):
|
||||
res = {"type": "data"}
|
||||
res["name"] = element.attributes["name"].value
|
||||
res["inType"] = element.attributes["inType"].value
|
||||
res["outType"] = element.attributes["outType"].value
|
||||
count = element.attributes.get("count", None)
|
||||
if count:
|
||||
res["count"] = count.value
|
||||
length = element.attributes.get("length", None)
|
||||
if length:
|
||||
res["length"] = length.value
|
||||
return res
|
||||
|
||||
def _parse_event_template_struct_element(self, element):
|
||||
res = {"type": "struct"}
|
||||
res["name"] = element.attributes["name"].value
|
||||
res["fields"] = [self._parse_event_template_data_element(elt) for elt in element.childNodes if elt.nodeType == elt.ELEMENT_NODE]
|
||||
return res
|
||||
|
||||
def _event_data_generator(self, template):
|
||||
xmldoc = xml.dom.minidom.parseString(template)
|
||||
xmltemplate = xmldoc.getElementsByTagName("template")[0]
|
||||
for element in (n for n in xmltemplate.childNodes if n.nodeType == n.ELEMENT_NODE):
|
||||
if element.tagName == "data":
|
||||
yield self._parse_event_template_data_element(element)
|
||||
elif element.tagName == "struct":
|
||||
yield self._parse_event_template_struct_element(element)
|
||||
else:
|
||||
raise ValueError("Unexpected XML element <{0}> in event template".format(element.tagName))
|
||||
|
||||
@property
|
||||
def event_data(self):
|
||||
"""The list of attribute specifique for this event.
|
||||
Retrieved by parsing :data:`EventMetadata.template`
|
||||
"""
|
||||
result = []
|
||||
template = self.template
|
||||
if not template:
|
||||
return {}
|
||||
xmltemplate = xml.dom.minidom.parseString(template)
|
||||
for data in xmltemplate.getElementsByTagName("data"):
|
||||
result.append(data.attributes["name"].value)
|
||||
return result
|
||||
return []
|
||||
return list(self._event_data_generator(template))
|
||||
|
||||
def yolo(self):
|
||||
template = self.template
|
||||
|
||||
@@ -66,7 +66,7 @@ class EventRecord(gdef.EVENT_RECORD):
|
||||
# def match(self, provider=None, id=None, opcode=None):
|
||||
|
||||
def __repr__(self):
|
||||
guid = self.EventHeader.ProviderId.to_string()
|
||||
guid = self.EventHeader.ProviderId
|
||||
return """<{0} provider="{1}" id={2}>""".format(type(self).__name__, guid, self.id)
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ class EtwTrace(object):
|
||||
# TODO : maybe raise an Exception instead of silently masking the value ?
|
||||
level = gdef.UCHAR(chr(level & 0xff))
|
||||
|
||||
return windows.winproxy.EnableTraceEx2(self.handle, guid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, level , any_keyword, all_keyword, 0, None)
|
||||
return windows.winproxy.EnableTraceEx2(self.handle, guid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, level , any_keyword, all_keyword, 0, None)
|
||||
|
||||
|
||||
def process(self, callback, begin=None, end=None, context = None):
|
||||
@@ -295,7 +295,7 @@ class TraceProvider(object):
|
||||
return self.infos.instances
|
||||
|
||||
def __repr__(self):
|
||||
return """<{0} for "{1}">""".format(type(self).__name__, self.guid.to_string())
|
||||
return """<{0} for "{1}">""".format(type(self).__name__, self.guid)
|
||||
|
||||
|
||||
class TraceGuidInfo(gdef.TRACE_GUID_INFO):
|
||||
|
||||
@@ -203,6 +203,11 @@ class Task(gdef.IRegisteredTask):
|
||||
self.RunEx(params, flags, sessionid, user, result)
|
||||
return result
|
||||
|
||||
def get_security_descriptor(self, secinfo):
|
||||
res = gdef.BSTR()
|
||||
self.GetSecurityDescriptor(secinfo, res)
|
||||
return res.value
|
||||
|
||||
def __repr__(self):
|
||||
return """<{0} "{1}" at {2:#x}>""".format(type(self).__name__, self.name, id(self))
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import windows
|
||||
import ctypes
|
||||
import struct
|
||||
import functools
|
||||
from functools import partial
|
||||
from collections import namedtuple
|
||||
|
||||
from ctypes.wintypes import *
|
||||
@@ -9,7 +10,8 @@ from ctypes.wintypes import *
|
||||
import windows.com
|
||||
import windows.generated_def as gdef
|
||||
from windows.generated_def.winstructs import *
|
||||
from functools import partial
|
||||
|
||||
from windows.pycompat import basestring
|
||||
|
||||
# Common error check for all WMI COM interfaces
|
||||
# This 'just' add the corresponding 'WBEMSTATUS' to the hresult error code
|
||||
@@ -18,9 +20,44 @@ class WmiComInterface(object):
|
||||
def errcheck(self, result, func, args):
|
||||
if result < 0:
|
||||
wmitag = gdef.WBEMSTATUS.mapper[result & 0xffffffff]
|
||||
raise WindowsError(result, wmitag)
|
||||
raise ctypes.WinError(result, wmitag)
|
||||
return args
|
||||
|
||||
sentinel = object()
|
||||
# POC
|
||||
class QualifierSet(gdef.IWbemQualifierSet):
|
||||
def get_variant(self, name):
|
||||
"""Retrieve the value of property ``name`` as a :class:`~windows.com.Variant`
|
||||
|
||||
:return: :class:`~windows.com.Variant`
|
||||
"""
|
||||
if not isinstance(name, basestring):
|
||||
nametype = type(name).__name__
|
||||
raise TypeError("WmiObject attributes name must be str, not <{0}>".format(nametype))
|
||||
variant_res = windows.com.Variant()
|
||||
self.Get(name, 0, variant_res, None)
|
||||
return variant_res
|
||||
|
||||
def get(self, name, default=sentinel):
|
||||
"""Return the value of the property ``name``. The return value depends of the type of the property and can vary"""
|
||||
try:
|
||||
return self.get_variant(name).value
|
||||
except WindowsError as e:
|
||||
if (e.winerror & 0xffffffff) != gdef.WBEM_E_NOT_FOUND:
|
||||
raise
|
||||
if default is sentinel:
|
||||
raise
|
||||
return default
|
||||
|
||||
def names(self):
|
||||
res = POINTER(windows.com.SafeArray)()
|
||||
x = ctypes.pointer(res)
|
||||
self.GetNames(0, cast(x, POINTER(POINTER(gdef.SAFEARRAY))))
|
||||
# need to free the safearray / unlock ?
|
||||
properties = [p for p in res[0].to_list(BSTR)]
|
||||
return properties
|
||||
|
||||
|
||||
# https://docs.microsoft.com/en-us/windows/desktop/api/wbemcli/nn-wbemcli-iwbemclassobject
|
||||
|
||||
WmiMethod = namedtuple("WmiMethod", ["inparam", "outparam"])
|
||||
@@ -88,7 +125,6 @@ class WmiObject(gdef.IWbemClassObject, WmiComInterface):
|
||||
return gdef.tag_WBEM_GENUS_TYPE.mapper[self.get("__GENUS")]
|
||||
|
||||
## Higher level API
|
||||
|
||||
def get_properties(self, system_properties=False):
|
||||
"""Return the list of properties names available for the current object.
|
||||
If ``system_properties`` is ``False`` property names begining with ``_`` are ignored.
|
||||
@@ -108,6 +144,17 @@ class WmiObject(gdef.IWbemClassObject, WmiComInterface):
|
||||
|
||||
properties = property(get_properties) #: The properties of the object (exclude system properties)
|
||||
|
||||
@property
|
||||
def qualifier_set(self): # changer de nom ?
|
||||
res = QualifierSet()
|
||||
self.GetQualifierSet(res)
|
||||
return res
|
||||
|
||||
def get_p_set(self, name): # Changer de nom ?
|
||||
res = QualifierSet()
|
||||
self.GetPropertyQualifierSet(name, res)
|
||||
return res
|
||||
|
||||
# Make WmiObject a mapping object
|
||||
|
||||
def keys(self):
|
||||
@@ -133,6 +180,11 @@ class WmiObject(gdef.IWbemClassObject, WmiComInterface):
|
||||
return """<{0} class "{1}">""".format(type(self).__name__, self.get("__Class"))
|
||||
return """<{0} instance of "{1}">""".format(type(self).__name__, self.get("__Class"))
|
||||
|
||||
def __sprint__(self):
|
||||
return """ {0}\n
|
||||
{1}
|
||||
""".format(repr(self), "\n".join(": ".join([x[0], str(x[1])]) for x in sorted(self.items())))
|
||||
|
||||
|
||||
class WmiEnumeration(gdef.IEnumWbemClassObject, WmiComInterface):
|
||||
"""Represent an enumeration of object that can be itered"""
|
||||
@@ -150,7 +202,7 @@ class WmiEnumeration(gdef.IEnumWbemClassObject, WmiComInterface):
|
||||
return_count = gdef.ULONG(0)
|
||||
error = self.Next(timeout, 1, obj, return_count)
|
||||
if error == gdef.WBEM_S_TIMEDOUT:
|
||||
raise WindowsError(gdef.WBEM_S_TIMEDOUT, "Wmi timeout")
|
||||
raise ctypes.WinError(gdef.WBEM_S_TIMEDOUT, "Wmi timeout")
|
||||
elif error == WBEM_S_FALSE:
|
||||
return None
|
||||
else:
|
||||
@@ -337,6 +389,12 @@ class WmiNamespace(gdef.IWbemServices, WmiComInterface):
|
||||
self.PutInstance(instance, flags, None, res)
|
||||
return res
|
||||
|
||||
def delete_instance(self, instance, flags=0):
|
||||
"""TODO: Document"""
|
||||
if isinstance(instance, gdef.IWbemClassObject):
|
||||
instance = instance["__Path"]
|
||||
return self.DeleteInstance(instance, flags, None, None)
|
||||
|
||||
def exec_method(self, obj, method, inparam, flags=0):
|
||||
"""Exec method named on ``object`` with ``inparam``.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user