From 4d3b3e18add0ce77769cd4a06ff68e36e1984717 Mon Sep 17 00:00:00 2001 From: hakril Date: Thu, 13 Feb 2020 22:23:20 +0100 Subject: [PATCH] Lot of small py3 compat fix --- windows/alpc.py | 15 ++++--- windows/com.py | 9 +++-- windows/crypto/certificate.py | 10 ++++- windows/crypto/cryptmsg.py | 3 ++ windows/crypto/encrypt_decrypt.py | 6 +-- windows/injection.py | 4 +- windows/pipe.py | 17 +++++--- windows/pycompat.py | 19 +++++++++ windows/remotectypes.py | 10 ++++- windows/rpc/__init__.py | 7 ++-- windows/rpc/client.py | 56 +++++++++++++++++++------ windows/rpc/epmapper.py | 20 ++++----- windows/rpc/ndr.py | 63 ++++++++++++++++++++++++----- windows/test.py | 8 ++-- windows/utils/improved_buffer.py | 4 +- windows/utils/winutils.py | 55 ++++++++++++++++--------- windows/winobject/bits.py | 2 +- windows/winobject/object_manager.py | 2 +- windows/winobject/process.py | 2 +- windows/winobject/registry.py | 24 ++++++----- windows/winobject/system.py | 39 ++++++++++++++---- windows/winobject/token.py | 5 ++- windows/winobject/volume.py | 4 +- windows/winproxy/apis/crypt32.py | 9 +++-- 24 files changed, 283 insertions(+), 110 deletions(-) diff --git a/windows/alpc.py b/windows/alpc.py index 15cd2ed..9dead06 100644 --- a/windows/alpc.py +++ b/windows/alpc.py @@ -5,6 +5,7 @@ from collections import namedtuple import windows from windows import winproxy from windows import generated_def as gdef +import windows.pycompat ## For 64b python @@ -21,7 +22,7 @@ class AlpcMessage(object): # PORT_MESSAGE + MessageAttribute def __init__(self, msg_or_size=0x1000, attributes=None): # Init the PORT_MESSAGE - if isinstance(msg_or_size, (long, int)): + if isinstance(msg_or_size, windows.pycompat.int_types): self.port_message_buffer_size = msg_or_size self.port_message_raw_buffer = ctypes.c_buffer(msg_or_size) self.port_message = AlpcMessagePort.from_buffer(self.port_message_raw_buffer) @@ -301,9 +302,11 @@ class AlpcTransportBase(object): :type receive_msg: AlpcMessage or None :param int flags: The flags for :func:`NtAlpcSendWaitReceivePort` """ - if isinstance(alpc_message, basestring): + if isinstance(alpc_message, windows.pycompat.anybuff): raw_alpc_message = alpc_message - alpc_message = AlpcMessage(max(0x1000, len(alpc_message))) + if len(alpc_message) > 0x1000: + import pdb;pdb.set_trace() + alpc_message = AlpcMessage(max(0x1000, len(alpc_message) + 0x200)) alpc_message.port_message.data = raw_alpc_message if receive_msg is None: @@ -319,7 +322,7 @@ class AlpcTransportBase(object): :type alpc_message: AlpcMessage or str :param int flags: The flags for :func:`NtAlpcSendWaitReceivePort` """ - if isinstance(alpc_message, basestring): + if isinstance(alpc_message, windows.pycompat.anybuff): raw_alpc_message = alpc_message alpc_message = AlpcMessage(max(0x1000, len(alpc_message))) alpc_message.port_message.data = raw_alpc_message @@ -346,7 +349,7 @@ class AlpcTransportBase(object): class AlpcClient(AlpcTransportBase): "An ALPC client able to connect to a port and send/receive messages" - DEFAULT_MAX_MESSAGE_LENGTH = 0x1000 + DEFAULT_MAX_MESSAGE_LENGTH = 0x9000 def __init__(self, port_name=None): """Init the :class:`AlpcClient` automatically connect to ``port_name`` using default values if given""" @@ -396,7 +399,7 @@ class AlpcClient(AlpcTransportBase): send_msg = None send_msg_attr = None buffersize = None - elif isinstance(connect_message, basestring): + elif isinstance(connect_message, windows.pycompat.anybuff): buffersize = gdef.DWORD(len(connect_message) + 0x1000) send_msg = AlpcMessagePort.from_buffer_size(buffersize.value) send_msg.data = connect_message diff --git a/windows/com.py b/windows/com.py index ba67de7..4d72c67 100644 --- a/windows/com.py +++ b/windows/com.py @@ -1,3 +1,4 @@ +import sys import struct import ctypes import functools @@ -12,6 +13,8 @@ from windows.generated_def import RPC_C_IMP_LEVEL_IMPERSONATE, CLSCTX_INPROC_SER from windows.generated_def import interfaces from windows.generated_def.interfaces import generate_IID, IID +from windows.pycompat import int_types, basestring + # We have windows.com.COMImplementation # So we need windows.com.COMInterface COMInterface = interfaces.COMInterface @@ -109,11 +112,11 @@ def check_type_null(value): def check_type_i4(value): # 31 ? as we may want to keep sign :) - return isinstance(value, (int, long)) and (value).bit_length() <= 32 + return isinstance(value, int_types) and (value).bit_length() <= 32 def check_type_i8(value): # 63 ? as we may want to keep sign :) - return isinstance(value, (int, long)) and (value).bit_length() <= 64 + return isinstance(value, int_types) and (value).bit_length() <= 64 def check_type_bstr(value): return isinstance(value, basestring) @@ -299,7 +302,7 @@ class COMImplementation(object): def QueryInterface(self, this, piid, result): """Default ``QueryInterface`` implementation that returns ``self`` if piid is the implemented interface""" - if piid[0] in (IUnknown.IID, self.IMPLEMENT.IID): + if piid[0] in (gdef.IUnknown.IID, self.IMPLEMENT.IID): result[0] = this return 1 return E_NOINTERFACE diff --git a/windows/crypto/certificate.py b/windows/crypto/certificate.py index 49a756b..f627751 100644 --- a/windows/crypto/certificate.py +++ b/windows/crypto/certificate.py @@ -98,7 +98,7 @@ class CryptObject(object): return list(self._signers_and_certs_generator()) def __repr__(self): - return '<{0} "{1}" content_type={2}>'.format(type(self).__name__, self.filename, self.content_type) + return '<{0} "{1}" content_type={2!r}>'.format(type(self).__name__, self.filename, self.content_type) # https://msdn.microsoft.com/en-us/library/windows/desktop/aa382037(v=vs.85).aspx @@ -176,6 +176,9 @@ class CertificateStore(gdef.HCERTSTORE): return None return Certificate.from_pointer(rawcertcontext) + def __del__(self): + return winproxy.CertCloseStore(self, 0) + # PKCS12_NO_PERSIST_KEY -> do not save it in a key container on disk # Without it, a key container is created at 'C:\Users\USERNAME\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-3241049326-165485355-1070449050-1001' @@ -189,6 +192,7 @@ class CertificateStore(gdef.HCERTSTORE): # By forcing PKCS12_ALWAYS_CNG_KSP we remove this as the key are directly linked to the correct CNG_KSP in the CertStore # Look like it's based on this part of the PFX: # Microsoft CSP Name: Microsoft Enhanced Cryptographic Provider v1.0 +# BUT this will not allow to decrypt RSA_RC4 ? def import_pfx(pfx, password=None, flags=gdef.CRYPT_USER_KEYSET | gdef.PKCS12_NO_PERSIST_KEY | gdef.PKCS12_ALWAYS_CNG_KSP): """Import the file ``pfx`` with the ``password``. @@ -199,7 +203,7 @@ def import_pfx(pfx, password=None, flags=gdef.CRYPT_USER_KEYSET | gdef.PKCS12_NO :return: :class:`CertificateStore` """ - if isinstance(pfx, (basestring, bytearray)): + if isinstance(pfx, windows.pycompat.anybuff) or isinstance(pfx, bytearray): pfx = gdef.CRYPT_DATA_BLOB.from_string(pfx) cert_store = winproxy.PFXImportCertStore(pfx, password, flags) return CertificateStore(cert_store) @@ -483,6 +487,8 @@ class Certificate(gdef.CERT_CONTEXT): + + # class CertficateChain(object): # def __init__(self, pc_chain_context): # self.chain = pc_chain_context[0] diff --git a/windows/crypto/cryptmsg.py b/windows/crypto/cryptmsg.py index 825866c..be2d851 100644 --- a/windows/crypto/cryptmsg.py +++ b/windows/crypto/cryptmsg.py @@ -127,3 +127,6 @@ class CryptMessage(gdef.HCRYPTMSG): newmsg = CryptMessage(hmsg) newmsg.update(data, final=True) return newmsg + + def __del__(self): + return winproxy.CryptMsgClose(self) diff --git a/windows/crypto/encrypt_decrypt.py b/windows/crypto/encrypt_decrypt.py index 36d136c..d94e34b 100644 --- a/windows/crypto/encrypt_decrypt.py +++ b/windows/crypto/encrypt_decrypt.py @@ -48,7 +48,7 @@ def encrypt(cert_or_certlist, msg, algo=szOID_NIST_AES256_CBC, initvector=genini :return: :class:`bytearray`: The encrypted message """ alg_ident = CRYPT_ALGORITHM_IDENTIFIER() - alg_ident.pszObjId = algo + alg_ident.pszObjId = algo.encode("ascii") # We want to have automatique translation of Certificate -> PCERT_CONTEXT # In order to simple create the 'PCERT_CONTEXT[] certs' # For that we need a tuple of X * 1-item-tuple @@ -114,6 +114,6 @@ def decrypt(cert_store, encrypted): dcryptsize = DWORD() winproxy.CryptDecryptMessage(dparam, buf, ctypes.sizeof(buf), None, dcryptsize, None) #Decrypt the msg - dcryptbuff = (BYTE * dcryptsize.value)() + dcryptbuff = (BYTE * (dcryptsize.value + 0x1000))() winproxy.CryptDecryptMessage(dparam, buf, ctypes.sizeof(buf), dcryptbuff, dcryptsize, None) - return str(bytearray(dcryptbuff[:dcryptsize.value])) \ No newline at end of file + return bytes(bytearray(dcryptbuff[:dcryptsize.value])) diff --git a/windows/injection.py b/windows/injection.py index fab0857..23e1e7e 100644 --- a/windows/injection.py +++ b/windows/injection.py @@ -208,6 +208,7 @@ def generate_python_exec_shellcode_32(target, PyDll): code += x86.Jnz(":DO_ENSURE") code += x86.Mov('EAX', Py_Initialize) code += x86.Call('EAX') + # https://docs.python.org/3/c-api/init.html#c.PyEval_InitThreads code += x86.Mov('EAX', PyEval_InitThreads) code += x86.Call('EAX') code += x86.Label(":DO_ENSURE") @@ -272,6 +273,7 @@ def generate_python_exec_shellcode_64(target, PyDll): code += x64.Jnz(":DO_ENSURE") code += x64.Mov('RAX', Py_Initialize) code += x64.Call('RAX') + # https://docs.python.org/3/c-api/init.html#c.PyEval_InitThreads code += x64.Mov('RAX', PyEval_InitThreads) code += x64.Call('RAX') code += x64.Label(":DO_ENSURE") @@ -398,7 +400,7 @@ import ctypes size = ctypes.c_uint.from_address(addr) size.value = len(txt) buff = (ctypes.c_char * len(txt)).from_address(addr + ctypes.sizeof(ctypes.c_uint)) -buff[:] = txt +buff[:] = txt.encode() """ def retrieve_last_exception_data(process): diff --git a/windows/pipe.py b/windows/pipe.py index 62f9677..424fd52 100644 --- a/windows/pipe.py +++ b/windows/pipe.py @@ -1,17 +1,24 @@ import windows from windows import winproxy import windows.generated_def as gdef - -import _multiprocessing import ctypes +from windows.pycompat import is_py3 + +if is_py3: + from multiprocessing.connection import PipeConnection as native_PipeConnection +else: + from _multiprocessing import PipeConnection as native_PipeConnection + # Inspired from 'multiprocessing\connection.py' def full_pipe_address(addr): """Return the full address of the pipe `addr`""" - if addr.startswith("\\\\"): + if not isinstance(addr, bytes): + addr = addr.encode("ascii") + if addr.startswith(b"\\\\"): return addr - return r"\\.\pipe\{addr}".format(addr=addr) + return br"\\.\pipe" + "\\".encode() + addr class PipeConnection(object): # Cannot inherit: crash the interpreter """A wrapper arround :class:`_multiprocessing.PipeConnection` able to work as a ContextManager""" @@ -26,7 +33,7 @@ class PipeConnection(object): # Cannot inherit: crash the interpreter @classmethod def from_handle(cls, phandle, *args, **kwargs): """Create a :class:`PipeConnection` from pipe handle `phandle`""" - connection = _multiprocessing.PipeConnection(phandle) + connection = native_PipeConnection(phandle) return cls(connection, *args, **kwargs) @classmethod diff --git a/windows/pycompat.py b/windows/pycompat.py index ce8b132..c86e294 100644 --- a/windows/pycompat.py +++ b/windows/pycompat.py @@ -10,6 +10,16 @@ if is_py3: basestring = str anybuff = (str, bytes) + def raw_encode(s): + if isinstance(s, str): + return s.encode("latin1") + return s + + def raw_decode(s): + if isinstance(s, bytes): + return s.decode("latin1") + return s + else: # py2.7 def str_from_ascii_function(s): return s @@ -17,3 +27,12 @@ else: # py2.7 int_types = (int, long) basestring = basestring anybuff = basestring + + def raw_encode(s): + if isinstance(s, unicode): + return s.encode("latin1") + return s + + def raw_decode(s): + # No unicode for now on py2 + return s diff --git a/windows/remotectypes.py b/windows/remotectypes.py index decbe21..28886fa 100644 --- a/windows/remotectypes.py +++ b/windows/remotectypes.py @@ -7,6 +7,14 @@ import ctypes.wintypes import itertools from _ctypes import _SimpleCData +# No PFW deps in this file +import sys +is_py3 = (sys.version_info.major >= 3) +if is_py3: + int_types = int +else: + int_types = (int, long) + # ## Utils ### # def is_pointer(x): @@ -168,7 +176,7 @@ def create_remote_array(subtype, len): def __getitem__(self, slice): # import pdb;pdb.set_trace() - if not isinstance(slice, (int, long)): + if not isinstance(slice, int_types): raise NotImplementedError("RemoteArray slice __getitem__") if slice >= len: raise IndexError("Access to {0} for a RemoteArray of size {1}".format(slice, len)) diff --git a/windows/rpc/__init__.py b/windows/rpc/__init__.py index 6dbd6ec..383b79e 100644 --- a/windows/rpc/__init__.py +++ b/windows/rpc/__init__.py @@ -1,4 +1,3 @@ -import ndr -from client import RPCClient - -from epmapper import find_alpc_endpoint_and_connect, find_alpc_endpoints, construct_alpc_tower \ No newline at end of file +from . import ndr +from .client import RPCClient +from .epmapper import find_alpc_endpoint_and_connect, find_alpc_endpoints, construct_alpc_tower \ No newline at end of file diff --git a/windows/rpc/client.py b/windows/rpc/client.py index 2ba64ce..c1c5e9b 100644 --- a/windows/rpc/client.py +++ b/windows/rpc/client.py @@ -5,6 +5,9 @@ import windows.alpc as alpc import windows.com import windows.generated_def as gdef +if windows.pycompat.is_py3: + buffer = bytes + KNOW_REQUEST_TYPE = gdef.FlagMapper(gdef.RPC_REQUEST_TYPE_CALL, gdef.RPC_REQUEST_TYPE_BIND) KNOW_RESPONSE_TYPE = gdef.FlagMapper(gdef.RPC_RESPONSE_TYPE_FAIL, gdef.RPC_RESPONSE_TYPE_SUCCESS, gdef.RPC_RESPONSE_TYPE_BIND_OK) @@ -54,10 +57,7 @@ class ALPC_RPC_CALL(ctypes.Structure): ("UNK5", gdef.DWORD), ("UNK6", gdef.DWORD), ("UNK7", gdef.DWORD), - ("UNK8", gdef.DWORD), - ("UNK9", gdef.DWORD), - ("UNK10", gdef.DWORD), - ("UNK11", gdef.DWORD), + ("ORPC_IPID", gdef.GUID) ] class RPCClient(object): @@ -86,7 +86,20 @@ class RPCClient(object): #TODO: attach version information to IID return IID - def call(self, IID, method_offset, params): + def forge_alpc_request(self, IID, method_offset, params, ipid=None): + """Craft an ALPC message containing an RPC request to call ``method_offset`` of interface ``IID` + with ``params``. + Can be used to craft request without directly sending it + """ + iid_hash = hash(buffer(IID)[:]) + interface_nb = self.if_bind_number[iid_hash] # TODO: add __hash__ to IID + if len(params) > 0x900: # 0x1000 - size of meta-data + request = self._forge_call_request_in_view(interface_nb, method_offset, params, ipid=ipid) + else: + request = self._forge_call_request(interface_nb, method_offset, params, ipid=ipid) + return request + + def call(self, IID, method_offset, params, ipid=None): """Call method number ``method_offset`` of interface ``IID`` with mashalled ``params`` :param IID IID: An IID previously returned by :func:`bind` @@ -94,15 +107,14 @@ class RPCClient(object): :param str params: The mashalled parameters (NDR32) :returns: :class:`str` """ - iid_hash = hash(buffer(IID)[:]) - interface_nb = self.if_bind_number[iid_hash] # TODO: add __hash__ to IID - request = self._forge_call_request(interface_nb, method_offset, params) + request = self.forge_alpc_request(IID, method_offset, params, ipid=ipid) response = self._send_request(request) # Parse reponse request_type = self._get_request_type(response) if request_type != gdef.RPC_RESPONSE_TYPE_SUCCESS: raise ValueError("Unexpected reponse type. Expected RESPONSE_SUCCESS got {0}".format(KNOW_RESPONSE_TYPE[request_type])) + # windows.utils.sprint(ALPC_RPC_CALL.from_buffer_copy(response + "\x00" * 12)) data = struct.unpack("<6I", response[:6 * 4]) assert data[3] == self.REQUEST_IDENTIFIER return response[4 * 6:] # Should be the return value (not completly verified) @@ -111,7 +123,7 @@ class RPCClient(object): response = self.alpc_client.send_receive(request) return response.data - def _forge_call_request(self, interface_nb, method_offset, params): + def _forge_call_request(self, interface_nb, method_offset, params, ipid=None): # TODO: differents REQUEST_IDENTIFIER for each req ? # TODO: what is this '0' ? (1 is also accepted) (flags ?) # request = struct.pack("<16I", gdef.RPC_REQUEST_TYPE_CALL, NOT_USED, 1, self.REQUEST_IDENTIFIER, interface_nb, method_offset, *[NOT_USED] * 10) @@ -121,19 +133,39 @@ class RPCClient(object): req.request_id = self.REQUEST_IDENTIFIER req.if_nb = interface_nb req.method_offset = method_offset - + if ipid: + req.ORPC_IPID = ipid + this = gdef.ORPCTHIS() + this.version = (5,7) + this.flags = 1 + lthis = gdef.LOCALTHIS() + return buffer(req)[:] + buffer(this)[:] + buffer(lthis)[:] + params return buffer(req)[:] + params + def _forge_call_request_in_view(self, interface_nb, method_offset, params, ipid=None): + # import pdb;pdb.set_trace() + # Version crade qui clean rien pour POC. GROS DOUTES :D + raw_request = self._forge_call_request(interface_nb, method_offset, "") + p = windows.alpc.AlpcMessage(0x2000) + section = self.alpc_client.create_port_section(0x40000, 0, len(params)) + view = self.alpc_client.map_section(section[0], len(params)) + p.port_message.data = raw_request + windows.rpc.ndr.NdrLong.pack(len(params) + 0x200) + "\x00" * 40 + p.attributes.ValidAttributes |= gdef.ALPC_MESSAGE_VIEW_ATTRIBUTE + p.view_attribute.Flags = 0x40000 + p.view_attribute.ViewBase = view.ViewBase + p.view_attribute.SectionHandle = view.SectionHandle + p.view_attribute.ViewSize = len(params) + windows.current_process.write_memory(view.ViewBase, params) # Write NDR to view + return p + def _forge_bind_request(self, uuid, syntaxversion, requested_if_nb): version_major, version_minor = syntaxversion req = ALPC_RPC_BIND() req.request_type = gdef.RPC_REQUEST_TYPE_BIND req.target = gdef.RPC_IF_ID(uuid, *syntaxversion) req.flags = gdef.BIND_IF_SYNTAX_NDR32 - # req.flags = gdef.BIND_IF_SYNTAX_NDR64 req.if_nb_ndr32 = requested_if_nb req.if_nb_ndr64 = 0 - req.if_nb_ndr64 = requested_if_nb req.if_nb_unkn = 0 req.register_multiple_syntax = False req.some_context_id = 0xB00B00B diff --git a/windows/rpc/epmapper.py b/windows/rpc/epmapper.py index 398eb76..c2d9f98 100644 --- a/windows/rpc/epmapper.py +++ b/windows/rpc/epmapper.py @@ -5,6 +5,7 @@ import windows import windows.generated_def as gdef from windows.rpc import ndr from windows.dbgprint import dbgprint +from windows.pycompat import basestring @@ -85,14 +86,15 @@ def explode_alpc_tower(tower): lhs, rhs = parse_floor(stream) if not (rhs[-1] == 0): - raise ValueError("ALPC Port name doest not end by \\x00") - return UnpackTower("ncalrpc", rhs[:-1], None, object, syntax) + rhs = rhs[:rhs.find("\x00")] + # raise ValueError("ALPC Port name doest not end by \\x00") + return UnpackTower("ncalrpc", bytes(rhs[:-1]), None, object, syntax) # http://pubs.opengroup.org/onlinepubs/9629399/apdxi.htm#tagcjh_28 # Octet 0 contains the hexadecimal value 0d. This is a reserved protocol identifier prefix that indicates that the protocol ID is UUID derived -TOWER_PROTOCOL_IS_UUID = "\x0d" -TOWER_EMPTY_RHS = "\x00\x00" -TOWER_PROTOCOL_ID_ALPC = "\x0c" # From RE +TOWER_PROTOCOL_IS_UUID = b"\x0d" +TOWER_EMPTY_RHS = b"\x00\x00" +TOWER_PROTOCOL_ID_ALPC = b"\x0c" # From RE def construct_alpc_tower(object, syntax, protseq, endpoint, address): if address is not None: @@ -113,11 +115,11 @@ def construct_alpc_tower(object, syntax, protseq, endpoint, address): floor_2 = craft_floor(floor_2_lsh, floor_2_rsh) # Floor 3 if endpoint is None: - floor_3_lsh = "\xff" + floor_3_lsh = b"\xff" floor_3_rsh = TOWER_EMPTY_RHS floor_3 = craft_floor(floor_3_lsh, floor_3_rsh) else: - floor_3_lsh = "\x10" + floor_3_lsh = b"\x10" floor_3_rsh = endpoint floor_3 = craft_floor(floor_3_lsh, floor_3_rsh) towerarray = struct.pack("".format(alpctowers), "RPC") for tower in alpctowers: dbgprint("Trying to connect to endpoint <{0}>".format(tower.endpoint), "RPC") - alpc_port = r"\RPC Control\{0}".format(tower.endpoint) + alpc_port = r"\RPC Control\{0}".format(tower.endpoint.decode()) try: client = windows.rpc.RPCClient(alpc_port) except Exception as e: diff --git a/windows/rpc/ndr.py b/windows/rpc/ndr.py index 5c3ac11..382acff 100644 --- a/windows/rpc/ndr.py +++ b/windows/rpc/ndr.py @@ -24,7 +24,7 @@ def pack_dword(x): def dword_pad(s): if (len(s) % 4) == 0: return s - return s + ("P" * (4 - len(s) % 4)) + return s + (b"P" * (4 - len(s) % 4)) class NdrUniquePTR(object): @@ -55,7 +55,7 @@ class NdrUniquePTR(object): def unpack_in_struct(self, stream): ptr = NdrLong.unpack(stream) if not ptr: - return 0, None + return 0, NdrUnpackNone return ptr, self.subcls def parse(self, stream): @@ -64,6 +64,22 @@ class NdrUniquePTR(object): return None return self.subcls.parse(stream) +class NdrUnpackNone(object): + @classmethod + def unpack(cls, stream): + return None + +class NdrRef(object): + # TESTING + def __init__(self, subcls): + self.subcls = subcls + + def unpack(self, stream): + ptr = NdrLong.unpack(stream) + if not ptr: + raise ValueError("Ndr REF cannot be NULL") + return self.subcls.unpack(stream) + class NdrFixedArray(object): def __init__(self, subcls, size): self.subcls = subcls @@ -72,7 +88,7 @@ class NdrFixedArray(object): def pack(self, data): data = list(data) assert len(data) == self.size - return dword_pad("".join([self.subcls.pack(elt) for elt in data])) + return dword_pad(b"".join([self.subcls.pack(elt) for elt in data])) def unpack(self, stream): @@ -119,7 +135,7 @@ class NdrWString(object): if not data.endswith('\x00'): data += '\x00' data = data.encode("utf-16-le") - l = (len(data) / 2) + l = (len(data) // 2) result = struct.pack("<3I", l, 0, l) result += data return dword_pad(result) @@ -249,7 +265,7 @@ class NdrStructure(object): else: packed_member = member.pack(memberdata) res.append(packed_member) - return dword_pad("".join(conformant_size)) + dword_pad("".join(res)) + dword_pad("".join(pointed)) + return dword_pad(b"".join(conformant_size)) + dword_pad(b"".join(res)) + dword_pad(b"".join(pointed)) @classmethod def unpack(cls, stream): @@ -257,7 +273,6 @@ class NdrStructure(object): conformant_members = [hasattr(m, "pack_conformant") for m in cls.MEMBERS] is_conformant = any(conformant_members) assert(conformant_members.count(True) <= 1), "Unpack conformant struct with more that one conformant MEMBER not implem" - data = [] if is_conformant: conformant_size = NdrLong.unpack(stream) @@ -279,7 +294,11 @@ class NdrStructure(object): data.append(member.unpack(stream)) # print("Applying deref unpack") for i, entry in post_subcls: - data[i] = entry.unpack(stream) + new_data = entry.unpack(stream) + if getattr(entry, "post_unpack", None): + new_data = entry.post_unpack(new_data) + data[i] = new_data + return cls.post_unpack(data) @classmethod @@ -305,7 +324,7 @@ class NdrParameters(object): for (member, memberdata) in zip(cls.MEMBERS, data): packed_member = member.pack(memberdata) res.append(packed_member) - return "".join(dword_pad(elt) for elt in res) + return b"".join(dword_pad(elt) for elt in res) @classmethod def unpack(cls, stream): @@ -321,14 +340,24 @@ class NdrConformantArray(object): @classmethod def pack(cls, data): ndrsize = NdrLong.pack(len(data)) - return dword_pad(ndrsize + "".join([cls.MEMBER_TYPE.pack(memberdata) for memberdata in data])) + return dword_pad(ndrsize + b"".join([cls.MEMBER_TYPE.pack(memberdata) for memberdata in data])) @classmethod def pack_conformant(cls, data): ndrsize = NdrLong.pack(len(data)) - ndrdata = dword_pad("".join([cls.MEMBER_TYPE.pack(memberdata) for memberdata in data])) + ndrdata = dword_pad(b"".join([cls.MEMBER_TYPE.pack(memberdata) for memberdata in data])) return ndrsize, ndrdata + @classmethod + def unpack(cls, stream): + nbelt = NdrLong.unpack(stream) + result = cls.unpack_conformant(stream, nbelt) + return cls._post_unpack(result) + + @classmethod + def _post_unpack(cls, result): + return result + @classmethod def unpack_conformant(cls, stream, size): res = [cls.MEMBER_TYPE.unpack(stream) for i in range(size)] @@ -342,7 +371,7 @@ class NdrConformantVaryingArrays(object): def pack(cls, data): ndrsize = NdrLong.pack(len(data)) offset = NdrLong.pack(0) - return dword_pad(ndrsize + offset + ndrsize + "".join([cls.MEMBER_TYPE.pack(memberdata) for memberdata in data])) + return dword_pad(ndrsize + offset + ndrsize + b"".join([cls.MEMBER_TYPE.pack(memberdata) for memberdata in data])) @classmethod def unpack(cls, stream): @@ -385,6 +414,8 @@ class NdrWcharConformantVaryingArrays(NdrConformantVaryingArrays): def _post_unpack(self, result): return u"".join(unichr(c) for c in result) +class NdrCharConformantVaryingArrays(NdrConformantVaryingArrays): + MEMBER_TYPE = NdrByte class NdrHyperConformantVaryingArrays(NdrConformantVaryingArrays): MEMBER_TYPE = NdrHyper @@ -405,6 +436,13 @@ class NdrByteConformantArray(NdrConformantArray): def _post_unpack(self, result): return bytearray(result) +class NdrWcharConformantArray(NdrConformantArray): + MEMBER_TYPE = NdrShort + + @classmethod + def _post_unpack(self, result): + return bytearray(result) + class NdrGuidConformantArray(NdrConformantArray): MEMBER_TYPE = NdrGuid @@ -438,12 +476,15 @@ class NdrStream(object): def align(self, size): """Discard some bytes to align the remaining stream on ``size``""" + already_read = len(self.fulldata) - len(self.data) if already_read % size: # Realign size_to_align = (size - (already_read % size)) self.data = self.data[size_to_align:] + # print("align {0}: {1}".format(size, size_to_align)) return size_to_align + # print("align {0}: 0".format(size)) return 0 diff --git a/windows/test.py b/windows/test.py index f3ad100..f080ca6 100644 --- a/windows/test.py +++ b/windows/test.py @@ -8,18 +8,18 @@ DEFAULT_CREATION_FLAGS = gdef.CREATE_NEW_CONSOLE if windows.system.bitness == 32: def pop_proc_32(dwCreationFlags=DEFAULT_CREATION_FLAGS): - return create_process(r"C:\Windows\system32\{0}".format(test_binary_name), dwCreationFlags=dwCreationFlags, show_windows=True) + return create_process(r"C:\Windows\system32\{0}".format(test_binary_name).encode(), dwCreationFlags=dwCreationFlags, show_windows=True) def pop_proc_64(dwCreationFlags=DEFAULT_CREATION_FLAGS): raise WindowsError("Cannot create calc64 in 32bits system") else: def pop_proc_32(dwCreationFlags=DEFAULT_CREATION_FLAGS): - return create_process(r"C:\Windows\syswow64\{0}".format(test_binary_name), dwCreationFlags=dwCreationFlags, show_windows=True) + return create_process(r"C:\Windows\syswow64\{0}".format(test_binary_name).encode(), dwCreationFlags=dwCreationFlags, show_windows=True) if windows.current_process.bitness == 32: def pop_proc_64(dwCreationFlags=DEFAULT_CREATION_FLAGS): with DisableWow64FsRedirection(): - return create_process(r"C:\Windows\system32\{0}".format(test_binary_name), dwCreationFlags=dwCreationFlags, show_windows=True) + return create_process(r"C:\Windows\system32\{0}".format(test_binary_name).encode(), dwCreationFlags=dwCreationFlags, show_windows=True) else: def pop_proc_64(dwCreationFlags=DEFAULT_CREATION_FLAGS): - return create_process(r"C:\Windows\system32\{0}".format(test_binary_name), dwCreationFlags=dwCreationFlags, show_windows=True) \ No newline at end of file + return create_process(r"C:\Windows\system32\{0}".format(test_binary_name).encode(), dwCreationFlags=dwCreationFlags, show_windows=True) \ No newline at end of file diff --git a/windows/utils/improved_buffer.py b/windows/utils/improved_buffer.py index fb346f8..99eba0e 100644 --- a/windows/utils/improved_buffer.py +++ b/windows/utils/improved_buffer.py @@ -80,13 +80,13 @@ class PartialBufferType(object): 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) + nbelt = int(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) + nbelt = int(len(buffer) / ctypes.sizeof(self.type)) return self.create_real_implem(self.type, nbelt).from_buffer_copy(buffer) def create(self, nbelt): diff --git a/windows/utils/winutils.py b/windows/utils/winutils.py index fc21b74..262546f 100644 --- a/windows/utils/winutils.py +++ b/windows/utils/winutils.py @@ -51,7 +51,15 @@ def create_file_from_handle(handle, mode="r"): """Return a Python :class:`file` around a ``Windows`` HANDLE""" flags = os.O_BINARY if "b" in mode else os.O_TEXT fd = msvcrt.open_osfhandle(handle, flags) - return os.fdopen(fd, mode, 0) + kwargs = {} + if windows.pycompat.is_py3 and flags == os.O_TEXT: + # Buffering, encoding + args = (100, "ascii") + else: + # Buffering + args = (0,) + # In py2 os.fdopen do not accept kwargs + return os.fdopen(fd, mode, *args) def get_handle_from_file(f): @@ -68,7 +76,7 @@ def create_console(): sys.stdout = console_stdout stdin_handle = winproxy.GetStdHandle(gdef.STD_INPUT_HANDLE) - console_stdin = create_file_from_handle(stdin_handle, "r+") + console_stdin = create_file_from_handle(stdin_handle, "r") sys.stdin = console_stdin stderr_handle = winproxy.GetStdHandle(gdef.STD_ERROR_HANDLE) @@ -87,7 +95,7 @@ def create_process(path, args=None, dwCreationFlags=0, show_windows=True): lpStartupInfo = ctypes.byref(StartupInfo) lpCommandLine = None if args: - lpCommandLine = (" ".join([str(a) for a in args])) + lpCommandLine = (b" ".join([a for a in args])) windows.winproxy.CreateProcessA(path, lpCommandLine=lpCommandLine, dwCreationFlags=dwCreationFlags, lpProcessInformation=ctypes.byref(proc_info), lpStartupInfo=lpStartupInfo) dbgprint("CreateProcessA new process handle {:#x}".format(proc_info.hProcess), "HANDLE") dbgprint("CreateProcessA new thread handle {:#x}".format(proc_info.hThread), "HANDLE") @@ -213,13 +221,29 @@ WIN_TO_UNIX_EPOCH_WIN_TICKS = WIN_TO_UNIX_EPOCH_SECOND * WIN_TICK_PER_SECOND_INT def unix_timestamp_from_filetime(filetime): # Round the filetime - round_win_ticks = ((filetime / 10) + int(round((filetime % 10) / 10.0))) * 10 + last_number = (filetime % 10) + # We do some sort of "manual rounding cause of py2 vs py3 + # PY2: round(0.5) == 1 + # PY3: round(0.5) == 0 + if last_number == 5: + rounding = 1 + else: + rounding = round(last_number / 10.0) + round_win_ticks = ((filetime // 10) + int(rounding)) * 10 return round((round_win_ticks - WIN_TO_UNIX_EPOCH_WIN_TICKS) / WIN_TICK_PER_SECOND_FLOAT, 7) def datetime_from_filetime(filetime): """return a :class:`datetime.datetime` from a ``windows`` FILETIME int""" # Manual non-approx rounding as filetime will not have a perfect representation as Python float - round_microsecond = (filetime / 10) + int(round((filetime % 10) / 10.0)) + # We do some sort of "manual rounding cause of py2 vs py3 + # PY2: round(0.5) == 1 + # PY3: round(0.5) == 0 + last_number = (filetime % 10) + if last_number == 5: + rounding = 1 + else: + rounding = round(last_number / 10.0) + round_microsecond = (filetime // 10) + int(rounding) return WINDOWS_EPOCH + datetime.timedelta(microseconds=round_microsecond) def filetime_from_datetime(dtime): @@ -303,7 +327,7 @@ ntqueryinformationfile_info_structs = { } def query_file_information(file_or_handle, file_info_class): - if isinstance(file_or_handle, file): + if not isinstance(file_or_handle, windows.pycompat.int_types): file_or_handle = windows.utils.get_handle_from_file(file_or_handle) handle = file_or_handle io_status = gdef.IO_STATUS_BLOCK() @@ -313,7 +337,6 @@ def query_file_information(file_or_handle, file_info_class): try: windows.winproxy.NtQueryInformationFile(handle, io_status, pinfo, ctypes.sizeof(info), FileInformationClass=file_info_class) except Exception as e: - # import pdb;pdb.set_trace() if not (e.winerror & 0xffffffff) == gdef.STATUS_BUFFER_OVERFLOW: raise # STATUS_BUFFER_OVERFLOW -> Guess we have a FILE_NAME_INFORMATION somewhere that need a bigger buffer @@ -407,7 +430,7 @@ ntqueryvolumeinformationfile_info_structs = { # TODO: FileFsDriverPathInformation # TODO: Extended FILE_FS_VOLUME_INFORMATION that can read the real value of 'VolumeLabel' def query_volume_information(file_or_handle, volume_info_class): - if isinstance(file_or_handle, file): + if not isinstance(file_or_handle, windows.pycompat.int_types): file_or_handle = get_handle_from_file(file_or_handle) handle = file_or_handle io_status = gdef.IO_STATUS_BLOCK() @@ -460,12 +483,8 @@ def get_long_path(path): :returns: :class:`str` | :obj:`unicode` -- same type as ``path`` parameter """ size = 0x1000 - if isinstance(path, unicode): - buffer = ctypes.create_unicode_buffer(size) - rsize = winproxy.GetLongPathNameW(path, buffer, size) - else: - buffer = ctypes.c_buffer(size) - rsize = winproxy.GetLongPathNameA(path, buffer, size) + buffer = ctypes.create_unicode_buffer(size) + rsize = winproxy.GetLongPathNameW(path, buffer, size) return buffer[:rsize] @@ -478,12 +497,8 @@ def get_short_path(path): :returns: :class:`str` | :obj:`unicode` -- same type as ``path`` parameter """ size = 0x1000 - if isinstance(path, unicode): - buffer = ctypes.create_unicode_buffer(size) - rsize = winproxy.GetShortPathNameW(path, buffer, size) - else: - buffer = ctypes.c_buffer(size) - rsize = winproxy.GetShortPathNameA(path, buffer, size) + buffer = ctypes.create_unicode_buffer(size) + rsize = winproxy.GetShortPathNameW(path, buffer, size) return buffer[:rsize] def dospath_to_ntpath(dospath): diff --git a/windows/winobject/bits.py b/windows/winobject/bits.py index 9f77ac4..286c129 100644 --- a/windows/winobject/bits.py +++ b/windows/winobject/bits.py @@ -191,7 +191,7 @@ class BitsCopyJob(IBackgroundCopyJob): def __repr__(self): - return '<{0} iid="{1}" at {2:#08x}>'.format(type(self).__name__, self.iid.to_string(), id(self)) + return '<{0} iid="{1}" at {2:#08x}>'.format(type(self).__name__, self.iid, id(self)) class BitsCopyJob2(gdef.IBackgroundCopyJob2, BitsCopyJob): diff --git a/windows/winobject/object_manager.py b/windows/winobject/object_manager.py index a9161c9..7eeae9f 100644 --- a/windows/winobject/object_manager.py +++ b/windows/winobject/object_manager.py @@ -18,7 +18,7 @@ def query_link(linkpath): obj_attr.SecurityQualityOfService = 0 res = gdef.HANDLE() x = winproxy.NtOpenSymbolicLinkObject(res, gdef.DIRECTORY_QUERY | gdef.READ_CONTROL , obj_attr) - v = gdef.LSA_UNICODE_STRING.from_string("\x00" * 1000) + v = gdef.LSA_UNICODE_STRING.from_size(1000) s = gdef.ULONG() winproxy.NtQuerySymbolicLinkObject(res, v, s) # Handle Buffer-too-small ? return v.str diff --git a/windows/winobject/process.py b/windows/winobject/process.py index 7c97fb6..ed0b202 100644 --- a/windows/winobject/process.py +++ b/windows/winobject/process.py @@ -378,7 +378,7 @@ class Process(utils.AutoHandle): # handle read_wstring at end of page # Of read failed: read only the half of size # read_size must remain a multiple of 2 - read_size = read_size / 2 + read_size = int(read_size / 2) continue readden += read_size # Bytearray will work on py2 & py3 diff --git a/windows/winobject/registry.py b/windows/winobject/registry.py index f922665..39edc15 100644 --- a/windows/winobject/registry.py +++ b/windows/winobject/registry.py @@ -8,6 +8,7 @@ import windows from windows.dbgprint import dbgprint import windows.generated_def as gdef from windows import winproxy +from windows.pycompat import basestring, int_types, is_py3 WENCODING = "utf-16-le" @@ -61,9 +62,10 @@ def Py2Reg_DWORD_BIG_ENDIAN(obj): def Reg2Py_BINARY(buffer, size): - return str(bytearray(buffer[:size])) + return bytes(bytearray(buffer[:size])) def Py2Reg_BINARY(obj): + # latin-1 encoding if py3 & type is str ? return obj @@ -75,7 +77,8 @@ def Reg2Py_SZ(buffer, size): # NULL TERMINATED: EASY return buffer.as_wstring() # Not null terminated: keep last byte - return (gdef.WCHAR * (size / 2)).from_buffer(buffer)[:] + assert not size % 2 + return (gdef.WCHAR * (size // 2)).from_buffer(buffer)[:] def Py2Reg_SZ(obj): return obj.encode(WENCODING) @@ -84,7 +87,10 @@ def Reg2Py_Multi_SZ(buffer, size): if not size: return [] # Simple path - rawstr = "".join([chr(c) for c in buffer[:size]]) + if is_py3: + rawstr = bytes(buffer) + else: + rawstr = "".join([chr(c) for c in buffer[:size]]) try: unistr = rawstr.decode(WENCODING) return unistr.rstrip(u"\x00").split(u"\x00") @@ -93,16 +99,16 @@ def Reg2Py_Multi_SZ(buffer, size): # Complexe-path # This is not some valide UTF-16 # Try our best to extract some stuff from raw - return rawstr.rstrip("\x00").split("\x00") + return rawstr.rstrip(b"\x00").split(b"\x00") def Py2Reg_Multi_SZ(obj): # Work on encoded values (to prevent str/unicode errors) uni_list = [s.encode(WENCODING) for s in obj] # Separate by UTF-16 NULL BYTE (2 \x00) - uni_str = "\x00\x00".join(uni_list) + uni_str = b"\x00\x00".join(uni_list) # Add UTF-16 NULL byte for final string + final UTF-16 \x00 (4 \x00) - return uni_str + "\x00\x00\x00\x00" + return uni_str + b"\x00\x00\x00\x00" DECODE_METHOD = 0 ENCODE_METHOD = 1 @@ -293,7 +299,7 @@ class PyHKey(object): def _guess_value_type(self, value): if isinstance(value, basestring): return gdef.REG_SZ - elif isinstance(value, (int, long)): + elif isinstance(value, int_types): return gdef.REG_DWORD # elif isinstance(value, (list, tuple)): # if all(isinstance(v, basestring) in value): @@ -308,7 +314,7 @@ class PyHKey(object): buffer = ENCODE_DECODE_METHODS[type][ENCODE_METHOD](value) - if isinstance(buffer, str): # Should not be unicode at this point + if isinstance(buffer, bytes): # Should not be unicode at this point buffer = windows.utils.BUFFER(gdef.BYTE).from_buffer_copy(buffer) return winproxy.RegSetValueExW(self.phkey, name, 0, type, buffer, len(buffer)) @@ -357,7 +363,7 @@ class PyHKey(object): def __setitem__(self, name, value): rtype = None - if not isinstance(value, (int, long, basestring)): + if not (isinstance(value, basestring) or isinstance(value, int_types)): value, rtype = value return self.set(name, value, rtype) diff --git a/windows/winobject/system.py b/windows/winobject/system.py index dbf87ea..bc8db6b 100644 --- a/windows/winobject/system.py +++ b/windows/winobject/system.py @@ -147,8 +147,13 @@ class System(object): :type: :class:`str` """ size = gdef.DWORD(0x1000) - buf = ctypes.c_buffer(size.value) - winproxy.GetComputerNameA(buf, ctypes.byref(size)) + # For now I don't know what is best as A vs W APIs... + if windows.pycompat.is_py3: + buf = ctypes.create_unicode_buffer(size.value) + winproxy.GetComputerNameW(buf, ctypes.byref(size)) + else: + buf = ctypes.create_string_buffer(size.value) + winproxy.GetComputerNameA(buf, ctypes.byref(size)) return buf[:size.value] @utils.fixedpropety @@ -372,12 +377,30 @@ class System(object): @utils.fixedpropety def build_number(self): - # This returns the last version where ntdll was updated - # Should look at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion - # values: CurrentBuild + UBR - # windows.system.registry(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion")["CurrentBuild"].value - # windows.system.registry(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion")["UBR"].value - return self.get_file_version("comctl32") + # Best effort. use get_file_version if registry code fails + try: + # Does not works on Win7.. + # Missing CurrentMajorVersionNumber/CurrentMinorVersionNumber/UBR + # We have CurrentVersion instead + # Use this code and get_file_version as a backup ? + curver_key = windows.system.registry(r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion") + try: + major = curver_key["CurrentMajorVersionNumber"].value + minor = curver_key["CurrentMinorVersionNumber"].value + except WindowsError as e: + version = curver_key["CurrentVersion"].value + # May raise ValueError if no "." + major, minor = version.split(".") + build = curver_key["CurrentBuildNumber"].value + # Update Build Revision + try: + ubr = curver_key["UBR"].value + except WindowsError as e: + ubr = 0 # Not present on Win7 + return "{0}.{1}.{2}.{3}".format(major, minor, build, ubr) + except (WindowsError, ValueError): + return self.get_file_version("ntdll") + @staticmethod def enumerate_processes(): diff --git a/windows/winobject/token.py b/windows/winobject/token.py index 03ed7d0..aedb7e7 100644 --- a/windows/winobject/token.py +++ b/windows/winobject/token.py @@ -1,12 +1,12 @@ import ctypes import functools -from __builtin__ import type as bltn_type import windows from windows import utils from windows import winproxy import windows.generated_def as gdef +bltn_type = type KNOW_INTEGRITY_LEVEL = gdef.FlagMapper( gdef.SECURITY_MANDATORY_UNTRUSTED_RID, @@ -465,7 +465,8 @@ class Token(utils.AutoHandle): """ mandatory_label = gdef.TOKEN_MANDATORY_LABEL() mandatory_label.Label.Attributes = 0x60 - mandatory_label.Label.Sid = gdef.PSID.from_string("S-1-16-{0}".format(integrity)) + # cast integrity to int to accept SECURITY_MANDATORY_LOW_RID & other Flags + mandatory_label.Label.Sid = gdef.PSID.from_string("S-1-16-{0}".format(int(integrity))) return self.set_informations(gdef.TokenIntegrityLevel, mandatory_label) _INTEGRITY_PROPERTY_DOC = """The integrity of the token as an int (extracted from integrity PSID) diff --git a/windows/winobject/volume.py b/windows/winobject/volume.py index 7b9438a..5d7c05a 100644 --- a/windows/winobject/volume.py +++ b/windows/winobject/volume.py @@ -71,7 +71,7 @@ def get_logical_drive_names(): size = 0x100 buffer = ctypes.c_buffer(size) rsize = winproxy.GetLogicalDriveStringsA(0x1000, buffer) - return buffer[:rsize].rstrip("\x00").split("\x00") + return buffer[:rsize].rstrip(b"\x00").split(b"\x00") def get_info(drivename): size = 0x1000 @@ -85,4 +85,4 @@ def query_dos_device(name): size = 0x1000 buffer = ctypes.c_buffer(size) rsize = winproxy.QueryDosDeviceA(name, buffer, size) - return buffer[:rsize].rstrip("\x00").split("\x00") \ No newline at end of file + return buffer[:rsize].rstrip(b"\x00").split(b"\x00") \ No newline at end of file diff --git a/windows/winproxy/apis/crypt32.py b/windows/winproxy/apis/crypt32.py index 77cd3d3..2b5c85f 100644 --- a/windows/winproxy/apis/crypt32.py +++ b/windows/winproxy/apis/crypt32.py @@ -4,6 +4,9 @@ import windows.generated_def as gdef from ..apiproxy import ApiProxy, NeededParameter from ..error import no_error_check, fail_on_zero +import windows.pycompat +from windows.pycompat import int_types + class Crypt32Proxy(ApiProxy): APIDLL = "crypt32" default_error_check = staticmethod(fail_on_zero) @@ -74,7 +77,7 @@ def CryptHashCertificate(hCryptProv, Algid, dwFlags, pbEncoded, cbEncoded, pbCom @Crypt32Proxy() def CertOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara): - if isinstance(lpszStoreProvider, (long, int)): + if isinstance(lpszStoreProvider, int_types): lpszStoreProvider = gdef.LPCSTR(lpszStoreProvider) return CertOpenStore.ctypes_function(lpszStoreProvider, dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara) @@ -119,7 +122,7 @@ def CryptAcquireCertificatePrivateKey(pCert, dwFlags, pvParameters, phCryptProvO @Crypt32Proxy() def CryptEncryptMessage(pEncryptPara, cRecipientCert, rgpRecipientCert, pbToBeEncrypted, cbToBeEncrypted, pbEncryptedBlob, pcbEncryptedBlob): - if isinstance(pbToBeEncrypted, basestring): + if isinstance(pbToBeEncrypted, windows.pycompat.anybuff): # Transform string to array of byte pbToBeEncrypted = (gdef.BYTE * len(pbToBeEncrypted))(*bytearray(pbToBeEncrypted)) if cbToBeEncrypted is None and pbToBeEncrypted is not None: @@ -161,7 +164,7 @@ def CryptVerifyMessageHash(pHashPara, pbHashedBlob, cbHashedBlob, pbToBeHashed, @Crypt32Proxy() def CryptEncodeObjectEx(dwCertEncodingType, lpszStructType, pvStructInfo, dwFlags, pEncodePara, pvEncoded, pcbEncoded): - lpszStructType = gdef.LPCSTR(lpszStructType) if isinstance(lpszStructType, (int, long)) else lpszStructType + lpszStructType = gdef.LPCSTR(lpszStructType) if isinstance(lpszStructType, int_types) else lpszStructType return CryptEncodeObjectEx.ctypes_function(dwCertEncodingType, lpszStructType, pvStructInfo, dwFlags, pEncodePara, pvEncoded, pcbEncoded) @Crypt32Proxy()