mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
POC of new Improved buffer utilities + sprint use dunder method __sprint__ if available in objects
This commit is contained in:
@@ -6,6 +6,14 @@ TODO:
|
||||
- Document / fix / release:
|
||||
- windows.bits
|
||||
- window
|
||||
- WMI
|
||||
- verif samples
|
||||
- add create_process sample to doc
|
||||
- rewrite / check doc + samples
|
||||
- Token
|
||||
- Finish code
|
||||
- samples
|
||||
- doc :)
|
||||
|
||||
======
|
||||
|
||||
@@ -42,9 +50,8 @@ TODO:
|
||||
- winobject\exception.py
|
||||
- large part could be rewritten with ctypes-generation extended-def
|
||||
|
||||
- add winobject/window.py + winobject/kernobj.py to System()
|
||||
- Some test/doc on both
|
||||
|
||||
- add winobject/window.py
|
||||
- Some test/doc
|
||||
|
||||
- wintrust doc:
|
||||
add : https://blogs.msdn.microsoft.com/winsdk/2016/01/05/why-cryptcatadmincalchashfromfilehandle-fails-with-a-seemingly-unexpected-error-code/
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from pythonutils import *
|
||||
from winutils import *
|
||||
from improved_buffer import *
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import ctypes
|
||||
import _ctypes
|
||||
import windows.generated_def as gdef
|
||||
|
||||
## TESTING Improved Buffer code ###
|
||||
## This code is not stable and WILL CHANGE ##
|
||||
## Do not use for now :) ##
|
||||
|
||||
# Uses cases:
|
||||
# Simple buffer
|
||||
# String / Wstring / Bytes
|
||||
# Resize array in struct
|
||||
# Typed buffer : filed call & contains X struct S
|
||||
# Having a ptr on struct with a buffer > sizeof(struct)
|
||||
# Autocreate a good-typed buffer from a tuple of ctypes objects
|
||||
|
||||
# On peut vouloir creer un buffer avec 12 elts de type X
|
||||
# Ou creer un buffer avec 12 elt de type X mais une sub-size de 1000
|
||||
|
||||
class ImprovedCtypesBufferBase(object):
|
||||
def cast(self, type):
|
||||
return ctypes.cast(self, type)
|
||||
|
||||
def as_string(self):
|
||||
return ctypes.cast(self, gdef.LPCSTR).value
|
||||
|
||||
def as_wstring(self):
|
||||
return ctypes.cast(self, gdef.LPWSTR).value
|
||||
|
||||
def as_pvoid(self):
|
||||
return self.cast(gdef.PVOID)
|
||||
|
||||
# Constructor
|
||||
@classmethod
|
||||
def from_size(cls, size):
|
||||
raw_buffer = ctypes.c_buffer(size)
|
||||
buffer = cls.from_buffer(raw_buffer)
|
||||
buffer._raw_buffer_ = raw_buffer
|
||||
return buffer
|
||||
|
||||
@property
|
||||
def real_size(self):
|
||||
real_buffer = getattr(self, "_raw_buffer_", self)
|
||||
return ctypes.sizeof(real_buffer)
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if "size" in kwargs:
|
||||
buff = ctypes.create_string_buffer(kwargs["size"])
|
||||
self = cls.from_buffer(buff)
|
||||
self._raw_buffer_ = buff
|
||||
return self
|
||||
# Add a '_raw_buffer_' even when no explicit size ?
|
||||
return super(ImprovedCtypesBufferBase, cls).__new__(cls, *args, **kwargs)
|
||||
|
||||
|
||||
# Used in windows.crypto.sign_verify for test
|
||||
class PartialBufferType(object):
|
||||
def __init__(self, type, nbelt=None):
|
||||
self.type = type
|
||||
self.nbelt = None
|
||||
|
||||
@staticmethod
|
||||
def create_real_implem(item_type, nbelt):
|
||||
if isinstance(nbelt, long):
|
||||
nbelt = int(nbelt)
|
||||
assert isinstance(nbelt, int)
|
||||
cls_name = "TypedBuffer<{0}><{1}>".format(item_type.__name__, nbelt)
|
||||
|
||||
class TmpImplemArrayName(ImprovedCtypesBufferBase, ctypes.Array):
|
||||
_type_ = item_type
|
||||
_length_ = nbelt
|
||||
|
||||
TmpImplemArrayName.__name__ = cls_name
|
||||
return TmpImplemArrayName
|
||||
|
||||
def from_buffer(self, buffer): # size as kwargs ?
|
||||
if len(buffer) % ctypes.sizeof(self.type):
|
||||
raise NotImplementedError("Buffer size of not a multiple of sizeof({0})".format(self.type.__name__))
|
||||
nbelt = len(buffer) / ctypes.sizeof(self.type)
|
||||
return self.create_real_implem(self.type, nbelt).from_buffer(buffer)
|
||||
|
||||
def from_buffer_copy(self, buffer): # size as kwargs ?
|
||||
if len(buffer) % ctypes.sizeof(self.type):
|
||||
raise NotImplementedError("Buffer size of not a multiple of sizeof({0})".format(self.type.__name__))
|
||||
nbelt = len(buffer) / ctypes.sizeof(self.type)
|
||||
return self.create_real_implem(self.type, nbelt).from_buffer_copy(buffer)
|
||||
|
||||
def create(self, nbelt):
|
||||
return self.create_real_implem(self.type, nbelt)
|
||||
|
||||
def __mul__(self, nbelt):
|
||||
return self.create_real_implem(self.type, nbelt)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
if len(args) == 1: # String magic: explode string as arg
|
||||
if isinstance(args[0], basestring):
|
||||
args = args[0]
|
||||
nbelt = kwargs.get("nbelt", max(len(args), 1))
|
||||
return self.create_real_implem(self.type, nbelt)(*args, **kwargs)
|
||||
|
||||
# # Expose these predefined types ?
|
||||
# CharBuffer = PartialBufferType(gdef.CHAR)
|
||||
# WCharBuffer = PartialBufferType(gdef.WCHAR)
|
||||
# ByteBuffer = PartialBufferType(gdef.BYTE)
|
||||
|
||||
|
||||
def BUFFER(type, nbelt=None):
|
||||
if nbelt is None:
|
||||
return PartialBufferType(type) # Allow user to create custom sized buffer
|
||||
return PartialBufferType.create_real_implem(type, int(nbelt))
|
||||
|
||||
def buffer(obj, eltclass=None):
|
||||
if eltclass is None: # Guess
|
||||
obj = list(obj)
|
||||
item = obj[0]
|
||||
eltclass = type(item) # All object must have the same type
|
||||
dlen = len(obj)
|
||||
return BUFFER(eltclass, dlen)(*obj)
|
||||
|
||||
def resized_array(array, newnbelt):
|
||||
btype = buffer_type(array._type_, newnbelt)
|
||||
new_array = btype.from_address(ctypes.addressof(array))
|
||||
new_array._base_array_ = array # Keep a ref to prevent some gc
|
||||
return new_array
|
||||
|
||||
|
||||
|
||||
@@ -8,86 +8,6 @@ from windows.dbgprint import dbgprint
|
||||
from windows import winproxy
|
||||
|
||||
|
||||
## TESTING Improved Buffer code ###
|
||||
|
||||
class ImprovedCtypesBufferBase(object):
|
||||
def cast(self, type):
|
||||
return ctypes.cast(self, type)
|
||||
|
||||
def as_string(self):
|
||||
return ctypes.cast(self, LPCSTR).value
|
||||
|
||||
def as_wstring(self):
|
||||
return ctypes.cast(self, LPWSTR).value
|
||||
|
||||
def as_pvoid(self):
|
||||
return self.cast(gdef.PVOID)
|
||||
|
||||
def buffer(size): # Test: DONT USE
|
||||
raise NotImplementedError("utils.buffer")
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
buf.size = size
|
||||
buf.address = ctypes.addressof(buf)
|
||||
|
||||
class ImprovedCtypesBufferImpl(ctypes.Array):
|
||||
_length_ = size
|
||||
_type_ = ctypes.c_char
|
||||
def lol(self):
|
||||
return "lol"
|
||||
|
||||
return ImprovedCtypesBufferImpl()
|
||||
|
||||
|
||||
def wbuffer(size): # Test: DONT USE
|
||||
raise NotImplementedError("utils.buffer")
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
buf.size = size
|
||||
buf.address = ctypes.addressof(buf)
|
||||
|
||||
class ImprovedCtypesBufferImpl(ctypes.Array):
|
||||
_length_ = size
|
||||
_type_ = ctypes.c_wchar
|
||||
def lol(self):
|
||||
return "lol"
|
||||
|
||||
return ImprovedCtypesBufferImpl()
|
||||
|
||||
# Used in windows.crypto.sign_verify for test
|
||||
class PartialBufferType(object):
|
||||
def __init__(self, type, size=None):
|
||||
self.type = type
|
||||
self.size = None
|
||||
|
||||
@staticmethod
|
||||
def create_real_implem(item_type, size):
|
||||
cls_name = "YOLO<IMPLE><{0}><{1}>".format(item_type.__name__, size)
|
||||
|
||||
class TmpImplemArrayName(ctypes.Array, ImprovedCtypesBufferBase):
|
||||
_type_ = item_type
|
||||
_length_ = size
|
||||
|
||||
TmpImplemArrayName.__name__ = cls_name
|
||||
return TmpImplemArrayName
|
||||
|
||||
def from_buffer(self, buffer):
|
||||
return self.create_real_implem(self.type, len(buffer)).from_buffer(buffer)
|
||||
|
||||
def from_buffer_copy(self, buffer):
|
||||
return self.create_real_implem(self.type, len(buffer)).from_buffer_copy(buffer)
|
||||
|
||||
def __call__(self, *args):
|
||||
return self.create_real_implem(self.type, len(args))(*args)
|
||||
|
||||
CharBuffer = PartialBufferType(gdef.CHAR)
|
||||
# CharBuffer vs CharString that append the +1 ?
|
||||
|
||||
def buffer(type, size=None):
|
||||
if size is None:
|
||||
return PartialBufferType(type)
|
||||
return PartialBufferType.create_real_implem(type, size)
|
||||
|
||||
|
||||
### Other utils ###
|
||||
|
||||
def fixedpropety(f):
|
||||
cache_name = "_" + f.__name__
|
||||
@@ -106,7 +26,15 @@ def transform_ctypes_fields(struct, replacement):
|
||||
return [(name, replacement.get(name, type)) for name, type in struct._fields_]
|
||||
|
||||
|
||||
def print_ctypes_struct(struct, name="", ident=0, hexa=False):
|
||||
def print_ctypes_struct(struct, name="", hexa=False):
|
||||
sprint_method = getattr(struct, "__sprint__", None)
|
||||
if sprint_method is not None:
|
||||
# Allow function to accept 'hexa' param
|
||||
# But handle function that don't, So we can just do:
|
||||
# __sprint__ = __repr__
|
||||
print("{0} -> {1}".format(name, sprint_method()))
|
||||
return
|
||||
|
||||
if isinstance(struct, _ctypes._Pointer):
|
||||
if ctypes.cast(struct, ctypes.c_void_p).value is None:
|
||||
print("{0} -> NULL".format(name))
|
||||
|
||||
Reference in New Issue
Block a user