mirror of
https://github.com/lgandx/Responder.git
synced 2024-10-18 13:10:21 -07:00
1091 lines
32 KiB
Python
1091 lines
32 KiB
Python
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
|
|
#
|
|
# This software is provided under under a slightly modified version
|
|
# of the Apache Software License. See the accompanying LICENSE file
|
|
# for more information.
|
|
#
|
|
# Author: Alberto Solino (@agsolino)
|
|
#
|
|
# Description:
|
|
# [MS-OAUT]: OLE Automation Protocol Implementation
|
|
# This was used as a way to test the DCOM runtime. Further
|
|
# testing is needed to verify it is working as expected
|
|
#
|
|
# Best way to learn how to use these calls is to grab the protocol standard
|
|
# so you understand what the call does, and then read the test case located
|
|
# at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC
|
|
#
|
|
# Since DCOM is like an OO RPC, instead of helper functions you will see the
|
|
# classes described in the standards developed.
|
|
# There are test cases for them too.
|
|
#
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
import random
|
|
from struct import pack, unpack
|
|
|
|
from impacket import LOG
|
|
from impacket import hresult_errors
|
|
from impacket.dcerpc.v5.dcomrt import DCOMCALL, DCOMANSWER, IRemUnknown2, PMInterfacePointer, INTERFACE, \
|
|
MInterfacePointer, MInterfacePointer_ARRAY, BYTE_ARRAY, PPMInterfacePointer
|
|
from impacket.dcerpc.v5.dtypes import LPWSTR, ULONG, DWORD, SHORT, GUID, USHORT, LONG, WSTR, BYTE, LONGLONG, FLOAT, \
|
|
DOUBLE, HRESULT, PSHORT, PLONG, PLONGLONG, PFLOAT, PDOUBLE, PHRESULT, CHAR, ULONGLONG, INT, UINT, PCHAR, PUSHORT, \
|
|
PULONG, PULONGLONG, PINT, PUINT, NULL
|
|
from impacket.dcerpc.v5.enum import Enum
|
|
from impacket.dcerpc.v5.ndr import NDRSTRUCT, NDRUniConformantArray, NDRPOINTER, NDRENUM, NDRUSHORT, NDRUNION, \
|
|
NDRUniConformantVaryingArray, NDR
|
|
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
|
from impacket.uuid import string_to_bin
|
|
|
|
class DCERPCSessionError(DCERPCException):
|
|
def __init__(self, error_string=None, error_code=None, packet=None):
|
|
DCERPCException.__init__(self, error_string, error_code, packet)
|
|
|
|
def __str__( self ):
|
|
if self.error_code in hresult_errors.ERROR_MESSAGES:
|
|
error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0]
|
|
error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1]
|
|
return 'OAUT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
|
|
else:
|
|
return 'OAUT SessionError: unknown error code: 0x%x' % (self.error_code)
|
|
|
|
################################################################################
|
|
# CONSTANTS
|
|
################################################################################
|
|
# 1.9 Standards Assignments
|
|
IID_IDispatch = string_to_bin('00020400-0000-0000-C000-000000000046')
|
|
IID_ITypeInfo = string_to_bin('00020401-0000-0000-C000-000000000046')
|
|
IID_ITypeComp = string_to_bin('00020403-0000-0000-C000-000000000046')
|
|
IID_NULL = string_to_bin('00000000-0000-0000-0000-000000000000')
|
|
|
|
error_status_t = ULONG
|
|
|
|
LCID = DWORD
|
|
WORD = NDRUSHORT
|
|
|
|
# 2.2.2 IID
|
|
IID = GUID
|
|
|
|
# 2.2.3 LPOLESTR
|
|
LPOLESTR = LPWSTR
|
|
OLESTR = WSTR
|
|
|
|
# 2.2.4 REFIID
|
|
REFIID = IID
|
|
|
|
# 2.2.25 DATE
|
|
DATE = DOUBLE
|
|
class PDATE(NDRPOINTER):
|
|
referent = (
|
|
('Data', DATE),
|
|
)
|
|
|
|
# 2.2.27 VARIANT_BOOL
|
|
VARIANT_BOOL = USHORT
|
|
|
|
class PVARIANT_BOOL(NDRPOINTER):
|
|
referent = (
|
|
('Data', VARIANT_BOOL),
|
|
)
|
|
|
|
# 3.1.4.4 IDispatch::Invoke (Opnum 6)
|
|
# dwFlags
|
|
DISPATCH_METHOD = 0x00000001
|
|
DISPATCH_PROPERTYGET = 0x00000002
|
|
DISPATCH_PROPERTYPUT = 0x00000004
|
|
DISPATCH_PROPERTYPUTREF = 0x00000008
|
|
DISPATCH_zeroVarResult = 0x00020000
|
|
DISPATCH_zeroExcepInfo = 0x00040000
|
|
DISPATCH_zeroArgErr = 0x00080000
|
|
|
|
################################################################################
|
|
# STRUCTURES
|
|
################################################################################
|
|
# 2.2.26 DECIMAL
|
|
class DECIMAL(NDRSTRUCT):
|
|
structure = (
|
|
('wReserved',WORD),
|
|
('scale',BYTE),
|
|
('sign',BYTE),
|
|
('Hi32',ULONG),
|
|
('Lo64',ULONGLONG),
|
|
)
|
|
|
|
class PDECIMAL(NDRPOINTER):
|
|
referent = (
|
|
('Data', DECIMAL),
|
|
)
|
|
|
|
# 2.2.7 VARIANT Type Constants
|
|
class VARENUM(NDRENUM):
|
|
class enumItems(Enum):
|
|
VT_EMPTY = 0
|
|
VT_NULL = 1
|
|
VT_I2 = 2
|
|
VT_I4 = 3
|
|
VT_R4 = 4
|
|
VT_R8 = 5
|
|
VT_CY = 6
|
|
VT_DATE = 7
|
|
VT_BSTR = 8
|
|
VT_DISPATCH = 9
|
|
VT_ERROR = 0xa
|
|
VT_BOOL = 0xb
|
|
VT_VARIANT = 0xc
|
|
VT_UNKNOWN = 0xd
|
|
VT_DECIMAL = 0xe
|
|
VT_I1 = 0x10
|
|
VT_UI1 = 0x11
|
|
VT_UI2 = 0x12
|
|
VT_UI4 = 0x13
|
|
VT_I8 = 0x14
|
|
VT_UI8 = 0x15
|
|
VT_INT = 0x16
|
|
VT_UINT = 0x17
|
|
VT_VOID = 0x18
|
|
VT_HRESULT = 0x19
|
|
VT_PTR = 0x1a
|
|
VT_SAFEARRAY = 0x1b
|
|
VT_CARRAY = 0x1c
|
|
VT_USERDEFINED = 0x1d
|
|
VT_LPSTR = 0x1e
|
|
VT_LPWSTR = 0x1f
|
|
VT_RECORD = 0x24
|
|
VT_INT_PTR = 0x25
|
|
VT_UINT_PTR = 0x26
|
|
VT_ARRAY = 0x2000
|
|
VT_BYREF = 0x4000
|
|
VT_RECORD_OR_VT_BYREF = VT_RECORD | VT_BYREF
|
|
VT_UI1_OR_VT_BYREF = VT_UI1 | VT_BYREF
|
|
VT_I2_OR_VT_BYREF = VT_I2 | VT_BYREF
|
|
VT_I4_OR_VT_BYREF = VT_I4 | VT_BYREF
|
|
VT_I8_OR_VT_BYREF = VT_I8 | VT_BYREF
|
|
VT_R4_OR_VT_BYREF = VT_R4 | VT_BYREF
|
|
VT_R8_OR_VT_BYREF = VT_R8 | VT_BYREF
|
|
VT_BOOL_OR_VT_BYREF = VT_BOOL | VT_BYREF
|
|
VT_ERROR_OR_VT_BYREF = VT_ERROR | VT_BYREF
|
|
VT_CY_OR_VT_BYREF = VT_CY | VT_BYREF
|
|
VT_DATE_OR_VT_BYREF = VT_DATE | VT_BYREF
|
|
VT_BSTR_OR_VT_BYREF = VT_BSTR | VT_BYREF
|
|
VT_UNKNOWN_OR_VT_BYREF = VT_UNKNOWN | VT_BYREF
|
|
VT_DISPATCH_OR_VT_BYREF = VT_DISPATCH | VT_BYREF
|
|
VT_ARRAY_OR_VT_BYREF = VT_ARRAY | VT_BYREF
|
|
VT_VARIANT_OR_VT_BYREF = VT_VARIANT| VT_BYREF
|
|
VT_I1_OR_VT_BYREF = VT_I1 | VT_BYREF
|
|
VT_UI2_OR_VT_BYREF = VT_UI2 | VT_BYREF
|
|
VT_UI4_OR_VT_BYREF = VT_UI4 | VT_BYREF
|
|
VT_UI8_OR_VT_BYREF = VT_UI8 | VT_BYREF
|
|
VT_INT_OR_VT_BYREF = VT_INT | VT_BYREF
|
|
VT_UINT_OR_VT_BYREF = VT_UINT | VT_BYREF
|
|
VT_DECIMAL_OR_VT_BYREF = VT_DECIMAL | VT_BYREF
|
|
|
|
# 2.2.8 SAFEARRAY Feature Constants
|
|
class SF_TYPE(NDRENUM):
|
|
# [v1_enum] type
|
|
structure = (
|
|
('Data', '<L'),
|
|
)
|
|
class enumItems(Enum):
|
|
SF_ERROR = VARENUM.VT_ERROR
|
|
SF_I1 = VARENUM.VT_I1
|
|
SF_I2 = VARENUM.VT_I2
|
|
SF_I4 = VARENUM.VT_I4
|
|
SF_I8 = VARENUM.VT_I8
|
|
SF_BSTR = VARENUM.VT_BSTR
|
|
SF_UNKNOWN = VARENUM.VT_UNKNOWN
|
|
SF_DISPATCH = VARENUM.VT_DISPATCH
|
|
SF_VARIANT = VARENUM.VT_VARIANT
|
|
SF_RECORD = VARENUM.VT_RECORD
|
|
SF_HAVEIID = VARENUM.VT_UNKNOWN | 0x8000
|
|
|
|
# 2.2.10 CALLCONV Calling Convention Constants
|
|
class CALLCONV(NDRENUM):
|
|
# [v1_enum] type
|
|
structure = (
|
|
('Data', '<L'),
|
|
)
|
|
class enumItems(Enum):
|
|
CC_CDECL = 1
|
|
CC_PASCAL = 2
|
|
CC_STDCALL = 4
|
|
|
|
|
|
# 2.2.12 FUNCKIND Function Access Constants
|
|
class FUNCKIND(NDRENUM):
|
|
# [v1_enum] type
|
|
structure = (
|
|
('Data', '<L'),
|
|
)
|
|
class enumItems(Enum):
|
|
FUNC_PUREVIRTUAL = 1
|
|
FUNC_STATIC = 3
|
|
FUNC_DISPATCH = 4
|
|
|
|
# 2.2.14 INVOKEKIND Function Invocation Constants
|
|
class INVOKEKIND(NDRENUM):
|
|
# [v1_enum] type
|
|
structure = (
|
|
('Data', '<L'),
|
|
)
|
|
class enumItems(Enum):
|
|
INVOKE_FUNC = 1
|
|
INVOKE_PROPERTYGET = 2
|
|
INVOKE_PROPERTYPUT = 4
|
|
INVOKE_PROPERTYPUTREF = 8
|
|
|
|
# 2.2.17 TYPEKIND Type Kind Constants
|
|
class TYPEKIND(NDRENUM):
|
|
# [v1_enum] type
|
|
structure = (
|
|
('Data', '<L'),
|
|
)
|
|
class enumItems(Enum):
|
|
TKIND_ENUM = 0
|
|
TKIND_RECORD = 1
|
|
TKIND_MODULE = 2
|
|
TKIND_INTERFACE = 3
|
|
TKIND_DISPATCH = 4
|
|
TKIND_COCLASS = 5
|
|
TKIND_ALIAS = 6
|
|
TKIND_UNION = 7
|
|
|
|
# 2.2.23 BSTR
|
|
# 2.2.23.1 FLAGGED_WORD_BLOB
|
|
class USHORT_ARRAY(NDRUniConformantArray):
|
|
item = '<H'
|
|
|
|
class FLAGGED_WORD_BLOB(NDRSTRUCT):
|
|
structure = (
|
|
('cBytes',ULONG),
|
|
('clSize',ULONG),
|
|
('asData',USHORT_ARRAY),
|
|
)
|
|
def __setitem__(self, key, value):
|
|
if key == 'asData':
|
|
value = value #+ '\x00'
|
|
array = list()
|
|
for letter in value:
|
|
encoded = letter.encode('utf-16le')
|
|
array.append(unpack('<H', encoded)[0])
|
|
self.fields[key]['Data'] = array
|
|
self['cBytes'] = len(value)*2
|
|
self['clSize'] = len(value)
|
|
self.data = None # force recompute
|
|
else:
|
|
return NDRSTRUCT.__setitem__(self, key, value)
|
|
|
|
def __getitem__(self, key):
|
|
if key == 'asData':
|
|
value = ''
|
|
for letter in self.fields['asData']['Data']:
|
|
value += pack('<H', letter).decode('utf-16le')
|
|
return value
|
|
else:
|
|
return NDRSTRUCT.__getitem__(self,key)
|
|
|
|
def dump(self, msg = None, indent = 0):
|
|
if msg is None: msg = self.__class__.__name__
|
|
ind = ' '*indent
|
|
if msg != '':
|
|
print("%s" % (msg))
|
|
value = ''
|
|
print('%sasData: %s' % (ind,self['asData']), end=' ')
|
|
|
|
# 2.2.23.2 BSTR Type Definition
|
|
class BSTR(NDRPOINTER):
|
|
referent = (
|
|
('Data', FLAGGED_WORD_BLOB),
|
|
)
|
|
|
|
class PBSTR(NDRPOINTER):
|
|
referent = (
|
|
('Data', BSTR),
|
|
)
|
|
|
|
# 2.2.24 CURRENCY
|
|
class CURRENCY(NDRSTRUCT):
|
|
structure = (
|
|
('int64', LONGLONG),
|
|
)
|
|
|
|
class PCURRENCY(NDRPOINTER):
|
|
referent = (
|
|
('Data', CURRENCY),
|
|
)
|
|
|
|
# 2.2.28.2 BRECORD
|
|
# 2.2.28.2.1 _wireBRECORD
|
|
class _wireBRECORD(NDRSTRUCT):
|
|
structure = (
|
|
('fFlags', LONGLONG),
|
|
('clSize', LONGLONG),
|
|
('pRecInfo', MInterfacePointer),
|
|
('pRecord', BYTE_ARRAY),
|
|
)
|
|
|
|
class BRECORD(NDRPOINTER):
|
|
referent = (
|
|
('Data', _wireBRECORD),
|
|
)
|
|
|
|
# 2.2.30 SAFEARRAY
|
|
# 2.2.30.1 SAFEARRAYBOUND
|
|
class SAFEARRAYBOUND(NDRSTRUCT):
|
|
structure = (
|
|
('cElements', ULONG),
|
|
('lLbound', LONG),
|
|
)
|
|
|
|
class PSAFEARRAYBOUND(NDRPOINTER):
|
|
referent = (
|
|
('Data', SAFEARRAYBOUND),
|
|
)
|
|
|
|
# 2.2.30.2 SAFEARR_BSTR
|
|
class BSTR_ARRAY(NDRUniConformantArray):
|
|
item = BSTR
|
|
|
|
class PBSTR_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', BSTR_ARRAY),
|
|
)
|
|
|
|
class SAFEARR_BSTR(NDRSTRUCT):
|
|
structure = (
|
|
('Size', ULONG),
|
|
('aBstr', PBSTR_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.3 SAFEARR_UNKNOWN
|
|
class SAFEARR_UNKNOWN(NDRSTRUCT):
|
|
structure = (
|
|
('Size', ULONG),
|
|
('apUnknown', MInterfacePointer_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.4 SAFEARR_DISPATCH
|
|
class SAFEARR_DISPATCH(NDRSTRUCT):
|
|
structure = (
|
|
('Size', ULONG),
|
|
('apDispatch', MInterfacePointer_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.6 SAFEARR_BRECORD
|
|
class BRECORD_ARRAY(NDRUniConformantArray):
|
|
item = BRECORD
|
|
|
|
class SAFEARR_BRECORD(NDRSTRUCT):
|
|
structure = (
|
|
('Size', ULONG),
|
|
('aRecord', BRECORD_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.7 SAFEARR_HAVEIID
|
|
class SAFEARR_HAVEIID(NDRSTRUCT):
|
|
structure = (
|
|
('Size', ULONG),
|
|
('apUnknown', MInterfacePointer_ARRAY),
|
|
('iid', IID),
|
|
)
|
|
|
|
# 2.2.30.8 Scalar-Sized Arrays
|
|
# 2.2.30.8.1 BYTE_SIZEDARR
|
|
class BYTE_SIZEDARR(NDRSTRUCT):
|
|
structure = (
|
|
('clSize', ULONG),
|
|
('pData', BYTE_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.8.2 WORD_SIZEDARR
|
|
class WORD_ARRAY(NDRUniConformantArray):
|
|
item = '<H'
|
|
|
|
class WORD_SIZEDARR(NDRSTRUCT):
|
|
structure = (
|
|
('clSize', ULONG),
|
|
('pData', WORD_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.8.3 DWORD_SIZEDARR
|
|
class DWORD_ARRAY(NDRUniConformantArray):
|
|
item = '<L'
|
|
|
|
class DWORD_SIZEDARR(NDRSTRUCT):
|
|
structure = (
|
|
('clSize', ULONG),
|
|
('pData', DWORD_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.8.4 HYPER_SIZEDARR
|
|
class HYPER_ARRAY(NDRUniConformantArray):
|
|
item = '<Q'
|
|
|
|
class HYPER_SIZEDARR(NDRSTRUCT):
|
|
structure = (
|
|
('clSize', ULONG),
|
|
('pData', HYPER_ARRAY),
|
|
)
|
|
|
|
|
|
# 2.2.36 HREFTYPE
|
|
HREFTYPE = DWORD
|
|
|
|
# 2.2.30.5 SAFEARR_VARIANT
|
|
class VARIANT_ARRAY(NDRUniConformantArray):
|
|
# In order to avoid the lack of forward declarations in Python
|
|
# I declare the item in the constructor
|
|
#item = VARIANT
|
|
def __init__(self, data = None, isNDR64 = False):
|
|
NDRUniConformantArray.__init__(self, data, isNDR64)
|
|
self.item = VARIANT
|
|
|
|
class PVARIANT_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', VARIANT_ARRAY),
|
|
)
|
|
|
|
class PVARIANT(NDRPOINTER):
|
|
# In order to avoid the lack of forward declarations in Python
|
|
# I declare the item in the constructor
|
|
#referent = (
|
|
# ('Data', VARIANT),
|
|
#)
|
|
def __init__(self, data = None, isNDR64 = False):
|
|
NDRPOINTER.__init__(self, data, isNDR64)
|
|
self.referent = ( ('Data', VARIANT),)
|
|
|
|
|
|
class SAFEARR_VARIANT(NDRSTRUCT):
|
|
structure = (
|
|
('Size', ULONG),
|
|
('aVariant', VARIANT_ARRAY),
|
|
)
|
|
|
|
# 2.2.30.9 SAFEARRAYUNION
|
|
class SAFEARRAYUNION(NDRUNION):
|
|
commonHdr = (
|
|
('tag', ULONG),
|
|
)
|
|
union = {
|
|
SF_TYPE.SF_BSTR : ('BstrStr', SAFEARR_BSTR),
|
|
SF_TYPE.SF_UNKNOWN : ('UnknownStr', SAFEARR_UNKNOWN),
|
|
SF_TYPE.SF_DISPATCH : ('DispatchStr', SAFEARR_DISPATCH),
|
|
SF_TYPE.SF_VARIANT : ('VariantStr', SAFEARR_VARIANT),
|
|
SF_TYPE.SF_RECORD : ('RecordStr', SAFEARR_BRECORD),
|
|
SF_TYPE.SF_HAVEIID : ('HaveIidStr', SAFEARR_HAVEIID),
|
|
SF_TYPE.SF_I1 : ('ByteStr', BYTE_SIZEDARR),
|
|
SF_TYPE.SF_I2 : ('WordStr', WORD_SIZEDARR),
|
|
SF_TYPE.SF_I4 : ('LongStr', DWORD_SIZEDARR),
|
|
SF_TYPE.SF_I8 : ('HyperStr', HYPER_SIZEDARR),
|
|
}
|
|
|
|
# 2.2.30.10 SAFEARRAY
|
|
class SAFEARRAYBOUND_ARRAY(NDRUniConformantArray):
|
|
item = SAFEARRAYBOUND
|
|
|
|
class PSAFEARRAYBOUND_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', SAFEARRAYBOUND_ARRAY),
|
|
)
|
|
|
|
class SAFEARRAY(NDRSTRUCT):
|
|
structure = (
|
|
('cDims', USHORT),
|
|
('fFeatures', USHORT),
|
|
('cbElements', ULONG),
|
|
('cLocks', ULONG),
|
|
('uArrayStructs', SAFEARRAYUNION),
|
|
('rgsabound', SAFEARRAYBOUND_ARRAY),
|
|
)
|
|
|
|
class PSAFEARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', SAFEARRAY),
|
|
)
|
|
|
|
# 2.2.29 VARIANT
|
|
# 2.2.29.1 _wireVARIANT
|
|
class EMPTY(NDR):
|
|
align = 0
|
|
structure = (
|
|
)
|
|
|
|
class varUnion(NDRUNION):
|
|
commonHdr = (
|
|
('tag', ULONG),
|
|
)
|
|
union = {
|
|
VARENUM.VT_I8 : ('llVal', LONGLONG),
|
|
VARENUM.VT_I4 : ('lVal', LONG),
|
|
VARENUM.VT_UI1 : ('bVal', BYTE),
|
|
VARENUM.VT_I2 : ('iVal', SHORT),
|
|
VARENUM.VT_R4 : ('fltVal', FLOAT),
|
|
VARENUM.VT_R8 : ('dblVal', DOUBLE),
|
|
VARENUM.VT_BOOL : ('boolVal', VARIANT_BOOL),
|
|
VARENUM.VT_ERROR : ('scode', HRESULT),
|
|
VARENUM.VT_CY : ('cyVal', CURRENCY),
|
|
VARENUM.VT_DATE : ('date', DATE),
|
|
VARENUM.VT_BSTR : ('bstrVal', BSTR),
|
|
VARENUM.VT_UNKNOWN : ('punkVal', PMInterfacePointer),
|
|
VARENUM.VT_DISPATCH : ('pdispVal', PMInterfacePointer),
|
|
VARENUM.VT_ARRAY : ('parray', SAFEARRAY),
|
|
VARENUM.VT_RECORD : ('brecVal', BRECORD),
|
|
VARENUM.VT_RECORD_OR_VT_BYREF : ('brecVal', BRECORD),
|
|
VARENUM.VT_UI1_OR_VT_BYREF : ('pbVal', BYTE),
|
|
VARENUM.VT_I2_OR_VT_BYREF : ('piVal', PSHORT),
|
|
VARENUM.VT_I4_OR_VT_BYREF : ('plVal', PLONG),
|
|
VARENUM.VT_I8_OR_VT_BYREF : ('pllVal', PLONGLONG),
|
|
VARENUM.VT_R4_OR_VT_BYREF : ('pfltVal', PFLOAT),
|
|
VARENUM.VT_R8_OR_VT_BYREF : ('pdblVal', PDOUBLE),
|
|
VARENUM.VT_BOOL_OR_VT_BYREF : ('pboolVal', PVARIANT_BOOL),
|
|
VARENUM.VT_ERROR_OR_VT_BYREF : ('pscode', PHRESULT),
|
|
VARENUM.VT_CY_OR_VT_BYREF : ('pcyVal', PCURRENCY),
|
|
VARENUM.VT_DATE_OR_VT_BYREF : ('pdate', PDATE),
|
|
VARENUM.VT_BSTR_OR_VT_BYREF : ('pbstrVal', PBSTR),
|
|
VARENUM.VT_UNKNOWN_OR_VT_BYREF : ('ppunkVal', PPMInterfacePointer),
|
|
VARENUM.VT_DISPATCH_OR_VT_BYREF: ('ppdispVal', PPMInterfacePointer),
|
|
VARENUM.VT_ARRAY_OR_VT_BYREF : ('pparray', PSAFEARRAY),
|
|
VARENUM.VT_VARIANT_OR_VT_BYREF : ('pvarVal', PVARIANT),
|
|
VARENUM.VT_I1 : ('cVal', CHAR),
|
|
VARENUM.VT_UI2 : ('uiVal', USHORT),
|
|
VARENUM.VT_UI4 : ('ulVal', ULONG),
|
|
VARENUM.VT_UI8 : ('ullVal', ULONGLONG),
|
|
VARENUM.VT_INT : ('intVal', INT),
|
|
VARENUM.VT_UINT : ('uintVal', UINT),
|
|
VARENUM.VT_DECIMAL : ('decVal', DECIMAL),
|
|
VARENUM.VT_I1_OR_VT_BYREF : ('pcVal', PCHAR),
|
|
VARENUM.VT_UI2_OR_VT_BYREF : ('puiVal', PUSHORT),
|
|
VARENUM.VT_UI4_OR_VT_BYREF : ('pulVal', PULONG),
|
|
VARENUM.VT_UI8_OR_VT_BYREF : ('pullVal', PULONGLONG),
|
|
VARENUM.VT_INT_OR_VT_BYREF : ('pintVal', PINT),
|
|
VARENUM.VT_UINT_OR_VT_BYREF : ('puintVal', PUINT),
|
|
VARENUM.VT_DECIMAL_OR_VT_BYREF : ('pdecVal', PDECIMAL),
|
|
VARENUM.VT_EMPTY : ('empty', EMPTY),
|
|
VARENUM.VT_NULL : ('null', EMPTY),
|
|
}
|
|
|
|
class wireVARIANTStr(NDRSTRUCT):
|
|
structure = (
|
|
('clSize',DWORD),
|
|
('rpcReserved',DWORD),
|
|
('vt',USHORT),
|
|
('wReserved1',USHORT),
|
|
('wReserved2',USHORT),
|
|
('wReserved3',USHORT),
|
|
('_varUnion',varUnion),
|
|
)
|
|
|
|
def getAlignment(self):
|
|
return 8
|
|
|
|
class VARIANT(NDRPOINTER):
|
|
referent = (
|
|
('Data', wireVARIANTStr),
|
|
)
|
|
|
|
class PVARIANT(NDRPOINTER):
|
|
referent = (
|
|
('Data', VARIANT),
|
|
)
|
|
|
|
# 2.2.32 DISPID
|
|
DISPID = LONG
|
|
|
|
# 2.2.33 DISPPARAMS
|
|
class DISPID_ARRAY(NDRUniConformantArray):
|
|
item = '<L'
|
|
|
|
class PDISPID_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', DISPID_ARRAY),
|
|
)
|
|
|
|
class DISPPARAMS(NDRSTRUCT):
|
|
structure = (
|
|
('rgvarg',PVARIANT_ARRAY),
|
|
('rgdispidNamedArgs', PDISPID_ARRAY),
|
|
('cArgs', UINT),
|
|
('cNamedArgs', UINT),
|
|
)
|
|
|
|
# 2.2.34 EXCEPINFO
|
|
class EXCEPINFO(NDRSTRUCT):
|
|
structure = (
|
|
('wCode',WORD),
|
|
('wReserved', WORD),
|
|
('bstrSource', BSTR),
|
|
('bstrDescription', BSTR),
|
|
('bstrHelpFile', BSTR),
|
|
('dwHelpContext', DWORD),
|
|
('pvReserved', ULONG),
|
|
('pfnDeferredFillIn', ULONG),
|
|
('scode', HRESULT),
|
|
)
|
|
|
|
# 2.2.35 MEMBERID
|
|
MEMBERID = DISPID
|
|
|
|
# 2.2.38 ARRAYDESC
|
|
class ARRAYDESC(NDRSTRUCT):
|
|
# In order to avoid the lack of forward declarations in Python
|
|
# I declare the item in the constructor
|
|
#structure = (
|
|
# ('tdescElem',TYPEDESC),
|
|
# ('cDims',USHORT),
|
|
# ('rgbounds',SAFEARRAYBOUND_ARRAY),
|
|
#)
|
|
def __init__(self, data = None, isNDR64 = False):
|
|
NDRSTRUCT.__init__(self, data, isNDR64)
|
|
self.structure = (
|
|
('tdescElem',TYPEDESC),
|
|
('cDims',USHORT),
|
|
('rgbounds',SAFEARRAYBOUND_ARRAY),
|
|
)
|
|
|
|
# 2.2.37 TYPEDESC
|
|
class tdUnion(NDRUNION):
|
|
notAlign = True
|
|
commonHdr = (
|
|
('tag', USHORT),
|
|
)
|
|
# In order to avoid the lack of forward declarations in Python
|
|
# I declare the item in the constructor
|
|
#union = {
|
|
# VARENUM.VT_PTR: ('lptdesc', tdUnion),
|
|
# VARENUM.VT_SAFEARRAY: ('lptdesc', tdUnion),
|
|
# VARENUM.VT_CARRAY: ('lpadesc', ARRAYDESC),
|
|
# VARENUM.VT_USERDEFINED: ('hreftype', HREFTYPE),
|
|
#}
|
|
def __init__(self, data = None, isNDR64=False, topLevel = False):
|
|
NDRUNION.__init__(self,None, isNDR64=isNDR64, topLevel=topLevel)
|
|
self.union = {
|
|
VARENUM.VT_PTR: ('lptdesc', PTYPEDESC),
|
|
VARENUM.VT_SAFEARRAY: ('lptdesc', PTYPEDESC),
|
|
VARENUM.VT_CARRAY: ('lpadesc', ARRAYDESC),
|
|
VARENUM.VT_USERDEFINED: ('hreftype', HREFTYPE),
|
|
'default': None,
|
|
}
|
|
|
|
class TYPEDESC(NDRSTRUCT):
|
|
structure = (
|
|
('vtType',tdUnion),
|
|
('vt', VARENUM),
|
|
)
|
|
|
|
def getAlignment(self):
|
|
return 4
|
|
|
|
class PTYPEDESC(NDRPOINTER):
|
|
referent = (
|
|
('Data', TYPEDESC),
|
|
)
|
|
def __init__(self, data = None, isNDR64=False, topLevel = False):
|
|
ret = NDRPOINTER.__init__(self,None, isNDR64=isNDR64, topLevel = False)
|
|
# We're forcing the pointer not to be topLevel
|
|
if data is None:
|
|
self.fields['ReferentID'] = random.randint(1,65535)
|
|
else:
|
|
self.fromString(data)
|
|
|
|
|
|
# 2.2.48 SCODE
|
|
SCODE = LONG
|
|
|
|
class SCODE_ARRAY(NDRUniConformantArray):
|
|
item = SCODE
|
|
|
|
class PSCODE_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', SCODE_ARRAY),
|
|
)
|
|
|
|
# 2.2.39 PARAMDESCEX
|
|
class PARAMDESCEX(NDRSTRUCT):
|
|
structure = (
|
|
('cBytes',ULONG),
|
|
('varDefaultValue',VARIANT),
|
|
)
|
|
|
|
class PPARAMDESCEX(NDRPOINTER):
|
|
referent = (
|
|
('Data', PARAMDESCEX),
|
|
)
|
|
|
|
|
|
# 2.2.40 PARAMDESC
|
|
class PARAMDESC(NDRSTRUCT):
|
|
structure = (
|
|
('pparamdescex',PPARAMDESCEX),
|
|
('wParamFlags',USHORT),
|
|
)
|
|
|
|
# 2.2.41 ELEMDESC
|
|
class ELEMDESC(NDRSTRUCT):
|
|
structure = (
|
|
('tdesc',TYPEDESC),
|
|
('paramdesc',PARAMDESC),
|
|
)
|
|
|
|
class ELEMDESC_ARRAY(NDRUniConformantArray):
|
|
item = ELEMDESC
|
|
|
|
class PELEMDESC_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', ELEMDESC_ARRAY),
|
|
)
|
|
|
|
# 2.2.42 FUNCDESC
|
|
class FUNCDESC(NDRSTRUCT):
|
|
structure = (
|
|
('memid',MEMBERID),
|
|
('lReserved1',PSCODE_ARRAY),
|
|
('lprgelemdescParam',PELEMDESC_ARRAY),
|
|
('funckind',FUNCKIND),
|
|
('invkind',INVOKEKIND),
|
|
('callconv',CALLCONV),
|
|
('cParams',SHORT),
|
|
('cParamsOpt',SHORT),
|
|
('oVft',SHORT),
|
|
('cReserved2',SHORT),
|
|
('elemdescFunc',ELEMDESC),
|
|
('wFuncFlags',WORD),
|
|
)
|
|
|
|
class LPFUNCDESC(NDRPOINTER):
|
|
referent = (
|
|
('Data', FUNCDESC),
|
|
)
|
|
# 2.2.44 TYPEATTR
|
|
class TYPEATTR(NDRSTRUCT):
|
|
structure = (
|
|
('guid',GUID),
|
|
('lcid',LCID),
|
|
('dwReserved1',DWORD),
|
|
('dwReserved2',DWORD),
|
|
('dwReserved3',DWORD),
|
|
('lpstrReserved4',LPOLESTR),
|
|
('cbSizeInstance',ULONG),
|
|
('typeKind',TYPEKIND),
|
|
('cFuncs',WORD),
|
|
('cVars',WORD),
|
|
('cImplTypes',WORD),
|
|
('cbSizeVft',WORD),
|
|
('cbAlignment',WORD),
|
|
('wTypeFlags',WORD),
|
|
('wMajorVerNum',WORD),
|
|
('wMinorVerNum',WORD),
|
|
('tdescAlias',TYPEDESC),
|
|
('dwReserved5',DWORD),
|
|
('dwReserved6',WORD),
|
|
)
|
|
|
|
class PTYPEATTR(NDRPOINTER):
|
|
referent = (
|
|
('Data', TYPEATTR),
|
|
)
|
|
|
|
class BSTR_ARRAY_CV(NDRUniConformantVaryingArray):
|
|
item = BSTR
|
|
|
|
class UINT_ARRAY(NDRUniConformantArray):
|
|
item = '<L'
|
|
|
|
class OLESTR_ARRAY(NDRUniConformantArray):
|
|
item = LPOLESTR
|
|
|
|
|
|
################################################################################
|
|
# RPC CALLS
|
|
################################################################################
|
|
# 3.1.4.1 IDispatch::GetTypeInfoCount (Opnum 3)
|
|
class IDispatch_GetTypeInfoCount(DCOMCALL):
|
|
opnum = 3
|
|
structure = (
|
|
('pwszMachineName', LPWSTR),
|
|
)
|
|
|
|
class IDispatch_GetTypeInfoCountResponse(DCOMANSWER):
|
|
structure = (
|
|
('pctinfo', ULONG),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.4.2 IDispatch::GetTypeInfo (Opnum 4)
|
|
class IDispatch_GetTypeInfo(DCOMCALL):
|
|
opnum = 4
|
|
structure = (
|
|
('iTInfo', ULONG),
|
|
('lcid', DWORD),
|
|
)
|
|
|
|
class IDispatch_GetTypeInfoResponse(DCOMANSWER):
|
|
structure = (
|
|
('ppTInfo', PMInterfacePointer),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.4.3 IDispatch::GetIDsOfNames (Opnum 5)
|
|
class IDispatch_GetIDsOfNames(DCOMCALL):
|
|
opnum = 5
|
|
structure = (
|
|
('riid', REFIID),
|
|
('rgszNames', OLESTR_ARRAY),
|
|
('cNames', UINT),
|
|
('lcid', LCID),
|
|
)
|
|
|
|
class IDispatch_GetIDsOfNamesResponse(DCOMANSWER):
|
|
structure = (
|
|
('rgDispId', DISPID_ARRAY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.4.4 IDispatch::Invoke (Opnum 6)
|
|
class IDispatch_Invoke(DCOMCALL):
|
|
opnum = 6
|
|
structure = (
|
|
('dispIdMember', DISPID),
|
|
('riid', REFIID),
|
|
('lcid', LCID),
|
|
('dwFlags', DWORD),
|
|
('pDispParams', DISPPARAMS),
|
|
('cVarRef', UINT),
|
|
('rgVarRefIdx', UINT_ARRAY),
|
|
('rgVarRef', VARIANT_ARRAY),
|
|
)
|
|
|
|
class IDispatch_InvokeResponse(DCOMANSWER):
|
|
structure = (
|
|
('pVarResult', VARIANT),
|
|
('pExcepInfo', EXCEPINFO),
|
|
('pArgErr', UINT),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.7.4.1 ITypeInfo::GetTypeAttr (Opnum 3)
|
|
class ITypeInfo_GetTypeAttr(DCOMCALL):
|
|
opnum = 3
|
|
structure = (
|
|
)
|
|
|
|
class ITypeInfo_GetTypeAttrResponse(DCOMANSWER):
|
|
structure = (
|
|
('ppTypeAttr', PTYPEATTR),
|
|
('pReserved', DWORD),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.7.4.2 ITypeInfo::GetTypeComp (Opnum 4)
|
|
class ITypeInfo_GetTypeComp(DCOMCALL):
|
|
opnum = 4
|
|
structure = (
|
|
)
|
|
|
|
class ITypeInfo_GetTypeCompResponse(DCOMANSWER):
|
|
structure = (
|
|
('ppTComp', PMInterfacePointer),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.7.4.3 ITypeInfo::GetFuncDesc (Opnum 5)
|
|
class ITypeInfo_GetFuncDesc(DCOMCALL):
|
|
opnum = 5
|
|
structure = (
|
|
('index', UINT),
|
|
)
|
|
|
|
class ITypeInfo_GetFuncDescResponse(DCOMANSWER):
|
|
structure = (
|
|
('ppFuncDesc', LPFUNCDESC),
|
|
('pReserved', DWORD),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.7.4.5 ITypeInfo::GetNames (Opnum 7)
|
|
class ITypeInfo_GetNames(DCOMCALL):
|
|
opnum = 7
|
|
structure = (
|
|
('memid', MEMBERID),
|
|
('cMaxNames', UINT),
|
|
)
|
|
|
|
class ITypeInfo_GetNamesResponse(DCOMANSWER):
|
|
structure = (
|
|
('rgBstrNames', BSTR_ARRAY_CV),
|
|
('pcNames', UINT),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.7.4.8 ITypeInfo::GetDocumentation (Opnum 12)
|
|
class ITypeInfo_GetDocumentation(DCOMCALL):
|
|
opnum = 12
|
|
structure = (
|
|
('memid', MEMBERID),
|
|
('refPtrFlags', DWORD),
|
|
)
|
|
|
|
class ITypeInfo_GetDocumentationResponse(DCOMANSWER):
|
|
structure = (
|
|
('pBstrName', BSTR),
|
|
('pBstrDocString', BSTR),
|
|
('pdwHelpContext', DWORD),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
|
|
################################################################################
|
|
# OPNUMs and their corresponding structures
|
|
################################################################################
|
|
OPNUMS = {
|
|
}
|
|
|
|
################################################################################
|
|
# HELPER FUNCTIONS AND INTERFACES
|
|
################################################################################
|
|
# 4.8.5 Enumerating All Methods in an Interface
|
|
# INPUT: IDispatch pointer from the automation server
|
|
# CALL IDispatch::GetTypeInfoCount and OBTAIN pcTInfo
|
|
# COMMENT see Section 3.1.4.1 for information on pcTInfo i
|
|
# IF pcTInfo = 0 THEN
|
|
# PRINT Automation Server does not support type information for this object
|
|
# ELSE
|
|
# CALL IDispatch::GetTypeInfo with correct LocaleID and OBTAIN ITypeInfo pointer
|
|
# CALL ITypeInfo::GetDocumentation(MEMBERID_NIL, 1, &BstrName, NULL, NULL, NULL)
|
|
# PRINT Name of the Interface is BstrName
|
|
# CALL ITypeInfo::GetTypeAttr and OBTAIN TYPEATTR pointer
|
|
#
|
|
# FOR X = 0 to TYPEATTR:: cFuncs -1
|
|
# CALL ITypeInfo::GetFuncDesc with X and OBTAIN FUNCDESC pointer
|
|
# CALL ITypeInfo::GetNames with FUNCDESC::memid and appropriate values for
|
|
# rgBstrNames, cMaxNames and pcNames
|
|
# COMMENT see Section 3.7.4.5 for more information regarding the parameters
|
|
# to ITypeinfo::GetNames
|
|
# IF pcNames > 0 THEN
|
|
# PRINT Name of the method is rgBstrNames[0]
|
|
# PRINT Parameters to above method are following
|
|
# FOR Y = 1 to pcNames -1
|
|
# PRINT rgBstrNames[Y]
|
|
# END FOR
|
|
# END IF
|
|
# END FOR i
|
|
# ENDIF
|
|
def enumerateMethods(iInterface):
|
|
methods = dict()
|
|
typeInfoCount = iInterface.GetTypeInfoCount()
|
|
if typeInfoCount['pctinfo'] == 0:
|
|
LOG.error('Automation Server does not support type information for this object')
|
|
return {}
|
|
iTypeInfo = iInterface.GetTypeInfo()
|
|
iTypeAttr = iTypeInfo.GetTypeAttr()
|
|
for x in range(iTypeAttr['ppTypeAttr']['cFuncs']):
|
|
funcDesc = iTypeInfo.GetFuncDesc(x)
|
|
names = iTypeInfo.GetNames(funcDesc['ppFuncDesc']['memid'], 255)
|
|
print(names['rgBstrNames'][0]['asData'])
|
|
funcDesc.dump()
|
|
print('='*80)
|
|
if names['pcNames'] > 0:
|
|
name = names['rgBstrNames'][0]['asData']
|
|
methods[name] = {}
|
|
for param in range(1, names['pcNames']):
|
|
methods[name][names['rgBstrNames'][param]['asData']] = ''
|
|
if funcDesc['ppFuncDesc']['elemdescFunc'] != NULL:
|
|
methods[name]['ret'] = funcDesc['ppFuncDesc']['elemdescFunc']['tdesc']['vt']
|
|
|
|
return methods
|
|
|
|
def checkNullString(string):
|
|
if string == NULL:
|
|
return string
|
|
|
|
if string[-1:] != '\x00':
|
|
return string + '\x00'
|
|
else:
|
|
return string
|
|
|
|
class ITypeComp(IRemUnknown2):
|
|
def __init__(self, interface):
|
|
IRemUnknown2.__init__(self,interface)
|
|
self._iid = IID_ITypeComp
|
|
|
|
class ITypeInfo(IRemUnknown2):
|
|
def __init__(self, interface):
|
|
IRemUnknown2.__init__(self,interface)
|
|
self._iid = IID_ITypeInfo
|
|
|
|
def GetTypeAttr(self):
|
|
request = ITypeInfo_GetTypeAttr()
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return resp
|
|
|
|
def GetTypeComp(self):
|
|
request = ITypeInfo_GetTypeComp()
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return ITypeComp(INTERFACE(self.get_cinstance(), ''.join(resp['ppTComp']['abData']), self.get_ipidRemUnknown(), target = self.get_target()))
|
|
|
|
def GetFuncDesc(self, index):
|
|
request = ITypeInfo_GetFuncDesc()
|
|
request['index'] = index
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return resp
|
|
|
|
def GetNames(self, memid, cMaxNames=10):
|
|
request = ITypeInfo_GetNames()
|
|
request['memid'] = memid
|
|
request['cMaxNames'] = cMaxNames
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return resp
|
|
|
|
def GetDocumentation(self, memid, refPtrFlags=15):
|
|
request = ITypeInfo_GetDocumentation()
|
|
request['memid'] = memid
|
|
request['refPtrFlags'] = refPtrFlags
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return resp
|
|
|
|
|
|
class IDispatch(IRemUnknown2):
|
|
def __init__(self, interface):
|
|
IRemUnknown2.__init__(self,interface)
|
|
self._iid = IID_IDispatch
|
|
|
|
def GetTypeInfoCount(self):
|
|
request = IDispatch_GetTypeInfoCount()
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return resp
|
|
|
|
def GetTypeInfo(self):
|
|
request = IDispatch_GetTypeInfo()
|
|
request['iTInfo'] = 0
|
|
request['lcid'] = 0
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return ITypeInfo(INTERFACE(self.get_cinstance(), ''.join(resp['ppTInfo']['abData']), self.get_ipidRemUnknown(), target = self.get_target()))
|
|
|
|
def GetIDsOfNames(self, rgszNames, lcid = 0):
|
|
request = IDispatch_GetIDsOfNames()
|
|
request['riid'] = IID_NULL
|
|
for name in rgszNames:
|
|
tmpName = LPOLESTR()
|
|
tmpName['Data'] = checkNullString(name)
|
|
request['rgszNames'].append(tmpName)
|
|
request['cNames'] = len(rgszNames)
|
|
request['lcid'] = lcid
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
IDs = list()
|
|
for id in resp['rgDispId']:
|
|
IDs.append(id)
|
|
|
|
return IDs
|
|
|
|
def Invoke(self, dispIdMember, lcid, dwFlags, pDispParams, cVarRef, rgVarRefIdx, rgVarRef):
|
|
request = IDispatch_Invoke()
|
|
request['dispIdMember'] = dispIdMember
|
|
request['riid'] = IID_NULL
|
|
request['lcid'] = lcid
|
|
request['dwFlags'] = dwFlags
|
|
request['pDispParams'] = pDispParams
|
|
request['cVarRef'] = cVarRef
|
|
request['rgVarRefIdx'] = rgVarRefIdx
|
|
request['rgVarRef'] = rgVarRefIdx
|
|
resp = self.request(request, iid = self._iid, uuid = self.get_iPid())
|
|
return resp
|