mirror of
https://github.com/lgandx/Responder.git
synced 2024-10-18 05:00:39 -07:00
1007 lines
30 KiB
Python
1007 lines
30 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-RRP] Interface implementation
|
|
#
|
|
# 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
|
|
#
|
|
# Some calls have helper functions, which makes it even easier to use.
|
|
# They are located at the end of this file.
|
|
# Helper functions start with "h"<name of the call>.
|
|
# There are test cases for them too.
|
|
#
|
|
|
|
|
|
from struct import unpack, pack
|
|
|
|
from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantVaryingArray, NDRUniConformantArray
|
|
from impacket.dcerpc.v5.dtypes import DWORD, UUID, ULONG, LPULONG, BOOLEAN, SECURITY_INFORMATION, PFILETIME, \
|
|
RPC_UNICODE_STRING, FILETIME, NULL, MAXIMUM_ALLOWED, OWNER_SECURITY_INFORMATION, PWCHAR, PRPC_UNICODE_STRING
|
|
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
|
from impacket import system_errors, LOG
|
|
from impacket.uuid import uuidtup_to_bin
|
|
|
|
MSRPC_UUID_RRP = uuidtup_to_bin(('338CD001-2244-31F1-AAAA-900038001003', '1.0'))
|
|
|
|
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 ):
|
|
key = self.error_code
|
|
if key in system_errors.ERROR_MESSAGES:
|
|
error_msg_short = system_errors.ERROR_MESSAGES[key][0]
|
|
error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
|
|
return 'RRP SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
|
|
else:
|
|
return 'RRP SessionError: unknown error code: 0x%x' % self.error_code
|
|
|
|
################################################################################
|
|
# CONSTANTS
|
|
################################################################################
|
|
# 2.2.2 PREGISTRY_SERVER_NAME
|
|
PREGISTRY_SERVER_NAME = PWCHAR
|
|
|
|
# 2.2.3 error_status_t
|
|
error_status_t = ULONG
|
|
|
|
# 2.2.5 RRP_UNICODE_STRING
|
|
RRP_UNICODE_STRING = RPC_UNICODE_STRING
|
|
PRRP_UNICODE_STRING = PRPC_UNICODE_STRING
|
|
|
|
# 2.2.4 REGSAM
|
|
REGSAM = ULONG
|
|
|
|
KEY_QUERY_VALUE = 0x00000001
|
|
KEY_SET_VALUE = 0x00000002
|
|
KEY_CREATE_SUB_KEY = 0x00000004
|
|
KEY_ENUMERATE_SUB_KEYS = 0x00000008
|
|
KEY_CREATE_LINK = 0x00000020
|
|
KEY_WOW64_64KEY = 0x00000100
|
|
KEY_WOW64_32KEY = 0x00000200
|
|
|
|
REG_BINARY = 3
|
|
REG_DWORD = 4
|
|
REG_DWORD_LITTLE_ENDIAN = 4
|
|
REG_DWORD_BIG_ENDIAN = 5
|
|
REG_EXPAND_SZ = 2
|
|
REG_LINK = 6
|
|
REG_MULTI_SZ = 7
|
|
REG_NONE = 0
|
|
REG_QWORD = 11
|
|
REG_QWORD_LITTLE_ENDIAN = 11
|
|
REG_SZ = 1
|
|
|
|
# 3.1.5.7 BaseRegCreateKey (Opnum 6)
|
|
REG_CREATED_NEW_KEY = 0x00000001
|
|
REG_OPENED_EXISTING_KEY = 0x00000002
|
|
|
|
# 3.1.5.19 BaseRegRestoreKey (Opnum 19)
|
|
# Flags
|
|
REG_WHOLE_HIVE_VOLATILE = 0x00000001
|
|
REG_REFRESH_HIVE = 0x00000002
|
|
REG_NO_LAZY_FLUSH = 0x00000004
|
|
REG_FORCE_RESTORE = 0x00000008
|
|
|
|
################################################################################
|
|
# STRUCTURES
|
|
################################################################################
|
|
# 2.2.1 RPC_HKEY
|
|
class RPC_HKEY(NDRSTRUCT):
|
|
structure = (
|
|
('context_handle_attributes',ULONG),
|
|
('context_handle_uuid',UUID),
|
|
)
|
|
|
|
def __init__(self, data=None, isNDR64=False):
|
|
NDRSTRUCT.__init__(self, data, isNDR64)
|
|
self['context_handle_uuid'] = b'\x00'*16
|
|
|
|
def isNull(self):
|
|
return self['context_handle_uuid'] == b'\x00'*16
|
|
|
|
# 2.2.6 RVALENT
|
|
class RVALENT(NDRSTRUCT):
|
|
structure = (
|
|
('ve_valuename',PRRP_UNICODE_STRING),
|
|
('ve_valuelen',DWORD),
|
|
('ve_valueptr',DWORD),
|
|
('ve_type',DWORD),
|
|
)
|
|
|
|
class RVALENT_ARRAY(NDRUniConformantVaryingArray):
|
|
item = RVALENT
|
|
|
|
# 2.2.9 RPC_SECURITY_DESCRIPTOR
|
|
class BYTE_ARRAY(NDRUniConformantVaryingArray):
|
|
pass
|
|
|
|
class PBYTE_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
('Data', BYTE_ARRAY),
|
|
)
|
|
|
|
class RPC_SECURITY_DESCRIPTOR(NDRSTRUCT):
|
|
structure = (
|
|
('lpSecurityDescriptor',PBYTE_ARRAY),
|
|
('cbInSecurityDescriptor',DWORD),
|
|
('cbOutSecurityDescriptor',DWORD),
|
|
)
|
|
|
|
# 2.2.8 RPC_SECURITY_ATTRIBUTES
|
|
class RPC_SECURITY_ATTRIBUTES(NDRSTRUCT):
|
|
structure = (
|
|
('nLength',DWORD),
|
|
('RpcSecurityDescriptor',RPC_SECURITY_DESCRIPTOR),
|
|
('bInheritHandle',BOOLEAN),
|
|
)
|
|
|
|
class PRPC_SECURITY_ATTRIBUTES(NDRPOINTER):
|
|
referent = (
|
|
('Data', RPC_SECURITY_ATTRIBUTES),
|
|
)
|
|
|
|
################################################################################
|
|
# RPC CALLS
|
|
################################################################################
|
|
# 3.1.5.1 OpenClassesRoot (Opnum 0)
|
|
class OpenClassesRoot(NDRCALL):
|
|
opnum = 0
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenClassesRootResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.2 OpenCurrentUser (Opnum 1)
|
|
class OpenCurrentUser(NDRCALL):
|
|
opnum = 1
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenCurrentUserResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.3 OpenLocalMachine (Opnum 2)
|
|
class OpenLocalMachine(NDRCALL):
|
|
opnum = 2
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenLocalMachineResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.4 OpenPerformanceData (Opnum 3)
|
|
class OpenPerformanceData(NDRCALL):
|
|
opnum = 3
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenPerformanceDataResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.5 OpenUsers (Opnum 4)
|
|
class OpenUsers(NDRCALL):
|
|
opnum = 4
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenUsersResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.6 BaseRegCloseKey (Opnum 5)
|
|
class BaseRegCloseKey(NDRCALL):
|
|
opnum = 5
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
)
|
|
|
|
class BaseRegCloseKeyResponse(NDRCALL):
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.7 BaseRegCreateKey (Opnum 6)
|
|
class BaseRegCreateKey(NDRCALL):
|
|
opnum = 6
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpSubKey', RRP_UNICODE_STRING),
|
|
('lpClass', RRP_UNICODE_STRING),
|
|
('dwOptions', DWORD),
|
|
('samDesired', REGSAM),
|
|
('lpSecurityAttributes', PRPC_SECURITY_ATTRIBUTES),
|
|
('lpdwDisposition', LPULONG),
|
|
)
|
|
|
|
class BaseRegCreateKeyResponse(NDRCALL):
|
|
structure = (
|
|
('phkResult', RPC_HKEY),
|
|
('lpdwDisposition', LPULONG),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.8 BaseRegDeleteKey (Opnum 7)
|
|
class BaseRegDeleteKey(NDRCALL):
|
|
opnum = 7
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpSubKey', RRP_UNICODE_STRING),
|
|
)
|
|
|
|
class BaseRegDeleteKeyResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.9 BaseRegDeleteValue (Opnum 8)
|
|
class BaseRegDeleteValue(NDRCALL):
|
|
opnum = 8
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpValueName', RRP_UNICODE_STRING),
|
|
)
|
|
|
|
class BaseRegDeleteValueResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.10 BaseRegEnumKey (Opnum 9)
|
|
class BaseRegEnumKey(NDRCALL):
|
|
opnum = 9
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('dwIndex', DWORD),
|
|
('lpNameIn', RRP_UNICODE_STRING),
|
|
('lpClassIn', PRRP_UNICODE_STRING),
|
|
('lpftLastWriteTime', PFILETIME),
|
|
)
|
|
|
|
class BaseRegEnumKeyResponse(NDRCALL):
|
|
structure = (
|
|
('lpNameOut', RRP_UNICODE_STRING),
|
|
('lplpClassOut', PRRP_UNICODE_STRING),
|
|
('lpftLastWriteTime', PFILETIME),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.11 BaseRegEnumValue (Opnum 10)
|
|
class BaseRegEnumValue(NDRCALL):
|
|
opnum = 10
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('dwIndex', DWORD),
|
|
('lpValueNameIn', RRP_UNICODE_STRING),
|
|
('lpType', LPULONG),
|
|
('lpData', PBYTE_ARRAY),
|
|
('lpcbData', LPULONG),
|
|
('lpcbLen', LPULONG),
|
|
)
|
|
|
|
class BaseRegEnumValueResponse(NDRCALL):
|
|
structure = (
|
|
('lpValueNameOut', RRP_UNICODE_STRING),
|
|
('lpType', LPULONG),
|
|
('lpData', PBYTE_ARRAY),
|
|
('lpcbData', LPULONG),
|
|
('lpcbLen', LPULONG),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.12 BaseRegFlushKey (Opnum 11)
|
|
class BaseRegFlushKey(NDRCALL):
|
|
opnum = 11
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
)
|
|
|
|
class BaseRegFlushKeyResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.13 BaseRegGetKeySecurity (Opnum 12)
|
|
class BaseRegGetKeySecurity(NDRCALL):
|
|
opnum = 12
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('SecurityInformation', SECURITY_INFORMATION),
|
|
('pRpcSecurityDescriptorIn', RPC_SECURITY_DESCRIPTOR),
|
|
)
|
|
|
|
class BaseRegGetKeySecurityResponse(NDRCALL):
|
|
structure = (
|
|
('pRpcSecurityDescriptorOut', RPC_SECURITY_DESCRIPTOR),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.14 BaseRegLoadKey (Opnum 13)
|
|
class BaseRegLoadKey(NDRCALL):
|
|
opnum = 13
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpSubKey', RRP_UNICODE_STRING),
|
|
('lpFile', RRP_UNICODE_STRING),
|
|
)
|
|
|
|
class BaseRegLoadKeyResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.15 BaseRegOpenKey (Opnum 15)
|
|
class BaseRegOpenKey(NDRCALL):
|
|
opnum = 15
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpSubKey', RRP_UNICODE_STRING),
|
|
('dwOptions', DWORD),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class BaseRegOpenKeyResponse(NDRCALL):
|
|
structure = (
|
|
('phkResult', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.16 BaseRegQueryInfoKey (Opnum 16)
|
|
class BaseRegQueryInfoKey(NDRCALL):
|
|
opnum = 16
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpClassIn', RRP_UNICODE_STRING),
|
|
)
|
|
|
|
class BaseRegQueryInfoKeyResponse(NDRCALL):
|
|
structure = (
|
|
('lpClassOut', RPC_UNICODE_STRING),
|
|
('lpcSubKeys', DWORD),
|
|
('lpcbMaxSubKeyLen', DWORD),
|
|
('lpcbMaxClassLen', DWORD),
|
|
('lpcValues', DWORD),
|
|
('lpcbMaxValueNameLen', DWORD),
|
|
('lpcbMaxValueLen', DWORD),
|
|
('lpcbSecurityDescriptor', DWORD),
|
|
('lpftLastWriteTime', FILETIME),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.17 BaseRegQueryValue (Opnum 17)
|
|
class BaseRegQueryValue(NDRCALL):
|
|
opnum = 17
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpValueName', RRP_UNICODE_STRING),
|
|
('lpType', LPULONG),
|
|
('lpData', PBYTE_ARRAY),
|
|
('lpcbData', LPULONG),
|
|
('lpcbLen', LPULONG),
|
|
)
|
|
|
|
class BaseRegQueryValueResponse(NDRCALL):
|
|
structure = (
|
|
('lpType', LPULONG),
|
|
('lpData', PBYTE_ARRAY),
|
|
('lpcbData', LPULONG),
|
|
('lpcbLen', LPULONG),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.18 BaseRegReplaceKey (Opnum 18)
|
|
class BaseRegReplaceKey(NDRCALL):
|
|
opnum = 18
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpSubKey', RRP_UNICODE_STRING),
|
|
('lpNewFile', RRP_UNICODE_STRING),
|
|
('lpOldFile', RRP_UNICODE_STRING),
|
|
)
|
|
|
|
class BaseRegReplaceKeyResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.19 BaseRegRestoreKey (Opnum 19)
|
|
class BaseRegRestoreKey(NDRCALL):
|
|
opnum = 19
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpFile', RRP_UNICODE_STRING),
|
|
('Flags', DWORD),
|
|
)
|
|
|
|
class BaseRegRestoreKeyResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.20 BaseRegSaveKey (Opnum 20)
|
|
class BaseRegSaveKey(NDRCALL):
|
|
opnum = 20
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpFile', RRP_UNICODE_STRING),
|
|
('pSecurityAttributes', PRPC_SECURITY_ATTRIBUTES),
|
|
)
|
|
|
|
class BaseRegSaveKeyResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.21 BaseRegSetKeySecurity (Opnum 21)
|
|
class BaseRegSetKeySecurity(NDRCALL):
|
|
opnum = 21
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('SecurityInformation', SECURITY_INFORMATION),
|
|
('pRpcSecurityDescriptor', RPC_SECURITY_DESCRIPTOR),
|
|
)
|
|
|
|
class BaseRegSetKeySecurityResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.22 BaseRegSetValue (Opnum 22)
|
|
class BaseRegSetValue(NDRCALL):
|
|
opnum = 22
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpValueName', RRP_UNICODE_STRING),
|
|
('dwType', DWORD),
|
|
('lpData', NDRUniConformantArray),
|
|
('cbData', DWORD),
|
|
)
|
|
|
|
class BaseRegSetValueResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.23 BaseRegUnLoadKey (Opnum 23)
|
|
class BaseRegUnLoadKey(NDRCALL):
|
|
opnum = 23
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpSubKey', RRP_UNICODE_STRING),
|
|
)
|
|
|
|
class BaseRegUnLoadKeyResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.24 BaseRegGetVersion (Opnum 26)
|
|
class BaseRegGetVersion(NDRCALL):
|
|
opnum = 26
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
)
|
|
|
|
class BaseRegGetVersionResponse(NDRCALL):
|
|
structure = (
|
|
('lpdwVersion', DWORD),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.25 OpenCurrentConfig (Opnum 27)
|
|
class OpenCurrentConfig(NDRCALL):
|
|
opnum = 27
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenCurrentConfigResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.26 BaseRegQueryMultipleValues (Opnum 29)
|
|
class BaseRegQueryMultipleValues(NDRCALL):
|
|
opnum = 29
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('val_listIn', RVALENT_ARRAY),
|
|
('num_vals', DWORD),
|
|
('lpvalueBuf', PBYTE_ARRAY),
|
|
('ldwTotsize', DWORD),
|
|
)
|
|
|
|
class BaseRegQueryMultipleValuesResponse(NDRCALL):
|
|
structure = (
|
|
('val_listOut', RVALENT_ARRAY),
|
|
('lpvalueBuf', PBYTE_ARRAY),
|
|
('ldwTotsize', DWORD),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.27 BaseRegSaveKeyEx (Opnum 31)
|
|
class BaseRegSaveKeyEx(NDRCALL):
|
|
opnum = 31
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpFile', RRP_UNICODE_STRING),
|
|
('pSecurityAttributes', PRPC_SECURITY_ATTRIBUTES),
|
|
('Flags', DWORD),
|
|
)
|
|
|
|
class BaseRegSaveKeyExResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.28 OpenPerformanceText (Opnum 32)
|
|
class OpenPerformanceText(NDRCALL):
|
|
opnum = 32
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenPerformanceTextResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.29 OpenPerformanceNlsText (Opnum 33)
|
|
class OpenPerformanceNlsText(NDRCALL):
|
|
opnum = 33
|
|
structure = (
|
|
('ServerName', PREGISTRY_SERVER_NAME),
|
|
('samDesired', REGSAM),
|
|
)
|
|
|
|
class OpenPerformanceNlsTextResponse(NDRCALL):
|
|
structure = (
|
|
('phKey', RPC_HKEY),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.30 BaseRegQueryMultipleValues2 (Opnum 34)
|
|
class BaseRegQueryMultipleValues2(NDRCALL):
|
|
opnum = 34
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('val_listIn', RVALENT_ARRAY),
|
|
('num_vals', DWORD),
|
|
('lpvalueBuf', PBYTE_ARRAY),
|
|
('ldwTotsize', DWORD),
|
|
)
|
|
|
|
class BaseRegQueryMultipleValues2Response(NDRCALL):
|
|
structure = (
|
|
('val_listOut', RVALENT_ARRAY),
|
|
('lpvalueBuf', PBYTE_ARRAY),
|
|
('ldwRequiredSize', DWORD),
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
# 3.1.5.31 BaseRegDeleteKeyEx (Opnum 35)
|
|
class BaseRegDeleteKeyEx(NDRCALL):
|
|
opnum = 35
|
|
structure = (
|
|
('hKey', RPC_HKEY),
|
|
('lpSubKey', RRP_UNICODE_STRING),
|
|
('AccessMask', REGSAM),
|
|
('Reserved', DWORD),
|
|
)
|
|
|
|
class BaseRegDeleteKeyExResponse(NDRCALL):
|
|
structure = (
|
|
('ErrorCode', error_status_t),
|
|
)
|
|
|
|
################################################################################
|
|
# OPNUMs and their corresponding structures
|
|
################################################################################
|
|
OPNUMS = {
|
|
0 : (OpenClassesRoot, OpenClassesRootResponse),
|
|
1 : (OpenCurrentUser, OpenCurrentUserResponse),
|
|
2 : (OpenLocalMachine, OpenLocalMachineResponse),
|
|
3 : (OpenPerformanceData, OpenPerformanceDataResponse),
|
|
4 : (OpenUsers, OpenUsersResponse),
|
|
5 : (BaseRegCloseKey, BaseRegCloseKeyResponse),
|
|
6 : (BaseRegCreateKey, BaseRegCreateKeyResponse),
|
|
7 : (BaseRegDeleteKey, BaseRegDeleteKeyResponse),
|
|
8 : (BaseRegDeleteValue, BaseRegDeleteValueResponse),
|
|
9 : (BaseRegEnumKey, BaseRegEnumKeyResponse),
|
|
10 : (BaseRegEnumValue, BaseRegEnumValueResponse),
|
|
11 : (BaseRegFlushKey, BaseRegFlushKeyResponse),
|
|
12 : (BaseRegGetKeySecurity, BaseRegGetKeySecurityResponse),
|
|
13 : (BaseRegLoadKey, BaseRegLoadKeyResponse),
|
|
15 : (BaseRegOpenKey, BaseRegOpenKeyResponse),
|
|
16 : (BaseRegQueryInfoKey, BaseRegQueryInfoKeyResponse),
|
|
17 : (BaseRegQueryValue, BaseRegQueryValueResponse),
|
|
18 : (BaseRegReplaceKey, BaseRegReplaceKeyResponse),
|
|
19 : (BaseRegRestoreKey, BaseRegRestoreKeyResponse),
|
|
20 : (BaseRegSaveKey, BaseRegSaveKeyResponse),
|
|
21 : (BaseRegSetKeySecurity, BaseRegSetKeySecurityResponse),
|
|
22 : (BaseRegSetValue, BaseRegSetValueResponse),
|
|
23 : (BaseRegUnLoadKey, BaseRegUnLoadKeyResponse),
|
|
26 : (BaseRegGetVersion, BaseRegGetVersionResponse),
|
|
27 : (OpenCurrentConfig, OpenCurrentConfigResponse),
|
|
29 : (BaseRegQueryMultipleValues, BaseRegQueryMultipleValuesResponse),
|
|
31 : (BaseRegSaveKeyEx, BaseRegSaveKeyExResponse),
|
|
32 : (OpenPerformanceText, OpenPerformanceTextResponse),
|
|
33 : (OpenPerformanceNlsText, OpenPerformanceNlsTextResponse),
|
|
34 : (BaseRegQueryMultipleValues2, BaseRegQueryMultipleValues2Response),
|
|
35 : (BaseRegDeleteKeyEx, BaseRegDeleteKeyExResponse),
|
|
}
|
|
|
|
################################################################################
|
|
# HELPER FUNCTIONS
|
|
################################################################################
|
|
def checkNullString(string):
|
|
if string == NULL:
|
|
return string
|
|
|
|
if string[-1:] != '\x00':
|
|
return string + '\x00'
|
|
else:
|
|
return string
|
|
|
|
def packValue(valueType, value):
|
|
if valueType == REG_DWORD:
|
|
retData = pack('<L', value)
|
|
elif valueType == REG_DWORD_BIG_ENDIAN:
|
|
retData = pack('>L', value)
|
|
elif valueType == REG_EXPAND_SZ:
|
|
try:
|
|
retData = value.encode('utf-16le')
|
|
except UnicodeDecodeError:
|
|
import sys
|
|
retData = value.decode(sys.getfilesystemencoding()).encode('utf-16le')
|
|
elif valueType == REG_MULTI_SZ:
|
|
try:
|
|
retData = value.encode('utf-16le')
|
|
except UnicodeDecodeError:
|
|
import sys
|
|
retData = value.decode(sys.getfilesystemencoding()).encode('utf-16le')
|
|
elif valueType == REG_QWORD:
|
|
retData = pack('<Q', value)
|
|
elif valueType == REG_QWORD_LITTLE_ENDIAN:
|
|
retData = pack('>Q', value)
|
|
elif valueType == REG_SZ:
|
|
try:
|
|
retData = value.encode('utf-16le')
|
|
except UnicodeDecodeError:
|
|
import sys
|
|
retData = value.decode(sys.getfilesystemencoding()).encode('utf-16le')
|
|
else:
|
|
retData = value
|
|
|
|
return retData
|
|
|
|
def unpackValue(valueType, value):
|
|
if valueType == REG_DWORD:
|
|
retData = unpack('<L', b''.join(value))[0]
|
|
elif valueType == REG_DWORD_BIG_ENDIAN:
|
|
retData = unpack('>L', b''.join(value))[0]
|
|
elif valueType == REG_EXPAND_SZ:
|
|
retData = b''.join(value).decode('utf-16le')
|
|
elif valueType == REG_MULTI_SZ:
|
|
retData = b''.join(value).decode('utf-16le')
|
|
elif valueType == REG_QWORD:
|
|
retData = unpack('<Q', b''.join(value))[0]
|
|
elif valueType == REG_QWORD_LITTLE_ENDIAN:
|
|
retData = unpack('>Q', b''.join(value))[0]
|
|
elif valueType == REG_SZ:
|
|
retData = b''.join(value).decode('utf-16le')
|
|
else:
|
|
retData = b''.join(value)
|
|
|
|
return retData
|
|
|
|
def hOpenClassesRoot(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenClassesRoot()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hOpenCurrentUser(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenCurrentUser()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hOpenLocalMachine(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenLocalMachine()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hOpenPerformanceData(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenPerformanceData()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hOpenUsers(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenUsers()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hBaseRegCloseKey(dce, hKey):
|
|
request = BaseRegCloseKey()
|
|
request['hKey'] = hKey
|
|
return dce.request(request)
|
|
|
|
def hBaseRegCreateKey(dce, hKey, lpSubKey, lpClass = NULL, dwOptions = 0x00000001, samDesired = MAXIMUM_ALLOWED, lpSecurityAttributes = NULL, lpdwDisposition = REG_CREATED_NEW_KEY):
|
|
request = BaseRegCreateKey()
|
|
request['hKey'] = hKey
|
|
request['lpSubKey'] = checkNullString(lpSubKey)
|
|
request['lpClass'] = checkNullString(lpClass)
|
|
request['dwOptions'] = dwOptions
|
|
request['samDesired'] = samDesired
|
|
if lpSecurityAttributes == NULL:
|
|
request['lpSecurityAttributes']['RpcSecurityDescriptor']['lpSecurityDescriptor'] = NULL
|
|
else:
|
|
request['lpSecurityAttributes'] = lpSecurityAttributes
|
|
request['lpdwDisposition'] = lpdwDisposition
|
|
|
|
return dce.request(request)
|
|
|
|
def hBaseRegDeleteKey(dce, hKey, lpSubKey):
|
|
request = BaseRegDeleteKey()
|
|
request['hKey'] = hKey
|
|
request['lpSubKey'] = checkNullString(lpSubKey)
|
|
return dce.request(request)
|
|
|
|
def hBaseRegEnumKey(dce, hKey, dwIndex, lpftLastWriteTime = NULL):
|
|
request = BaseRegEnumKey()
|
|
request['hKey'] = hKey
|
|
request['dwIndex'] = dwIndex
|
|
request.fields['lpNameIn'].fields['MaximumLength'] = 1024
|
|
request.fields['lpNameIn'].fields['Data'].fields['Data'].fields['MaximumCount'] = 1024//2
|
|
request['lpClassIn'] = ' '* 64
|
|
request['lpftLastWriteTime'] = lpftLastWriteTime
|
|
|
|
return dce.request(request)
|
|
|
|
def hBaseRegEnumValue(dce, hKey, dwIndex, dataLen=256):
|
|
request = BaseRegEnumValue()
|
|
request['hKey'] = hKey
|
|
request['dwIndex'] = dwIndex
|
|
retries = 1
|
|
|
|
# We need to be aware the size might not be enough, so let's catch ERROR_MORE_DATA exception
|
|
while True:
|
|
try:
|
|
# Only the maximum length field of the lpValueNameIn is used to determine the buffer length to be allocated
|
|
# by the service. Specify a string with a zero length but maximum length set to the largest buffer size
|
|
# needed to hold the value names.
|
|
request.fields['lpValueNameIn'].fields['MaximumLength'] = dataLen*2
|
|
request.fields['lpValueNameIn'].fields['Data'].fields['Data'].fields['MaximumCount'] = dataLen
|
|
|
|
request['lpData'] = b' ' * dataLen
|
|
request['lpcbData'] = dataLen
|
|
request['lpcbLen'] = dataLen
|
|
resp = dce.request(request)
|
|
except DCERPCSessionError as e:
|
|
if retries > 1:
|
|
LOG.debug('Too many retries when calling hBaseRegEnumValue, aborting')
|
|
raise
|
|
if e.get_error_code() == system_errors.ERROR_MORE_DATA:
|
|
# We need to adjust the size
|
|
retries +=1
|
|
dataLen = e.get_packet()['lpcbData']
|
|
continue
|
|
else:
|
|
raise
|
|
else:
|
|
break
|
|
|
|
return resp
|
|
|
|
def hBaseRegFlushKey(dce, hKey):
|
|
request = BaseRegFlushKey()
|
|
request['hKey'] = hKey
|
|
return dce.request(request)
|
|
|
|
def hBaseRegGetKeySecurity(dce, hKey, securityInformation = OWNER_SECURITY_INFORMATION ):
|
|
request = BaseRegGetKeySecurity()
|
|
request['hKey'] = hKey
|
|
request['SecurityInformation'] = securityInformation
|
|
request['pRpcSecurityDescriptorIn']['lpSecurityDescriptor'] = NULL
|
|
request['pRpcSecurityDescriptorIn']['cbInSecurityDescriptor'] = 1024
|
|
|
|
return dce.request(request)
|
|
|
|
def hBaseRegLoadKey(dce, hKey, lpSubKey, lpFile):
|
|
request = BaseRegLoadKey()
|
|
request['hKey'] = hKey
|
|
request['lpSubKey'] = checkNullString(lpSubKey)
|
|
request['lpFile'] = checkNullString(lpFile)
|
|
return dce.request(request)
|
|
|
|
def hBaseRegUnLoadKey(dce, hKey, lpSubKey):
|
|
request = BaseRegUnLoadKey()
|
|
request['hKey'] = hKey
|
|
request['lpSubKey'] = checkNullString(lpSubKey)
|
|
return dce.request(request)
|
|
|
|
def hBaseRegOpenKey(dce, hKey, lpSubKey, dwOptions=0x00000001, samDesired = MAXIMUM_ALLOWED):
|
|
request = BaseRegOpenKey()
|
|
request['hKey'] = hKey
|
|
request['lpSubKey'] = checkNullString(lpSubKey)
|
|
request['dwOptions'] = dwOptions
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hBaseRegQueryInfoKey(dce, hKey):
|
|
request = BaseRegQueryInfoKey()
|
|
request['hKey'] = hKey
|
|
# Not the cleanest way, but oh well
|
|
# Plus, Windows XP needs MaximumCount also set
|
|
request.fields['lpClassIn'].fields['MaximumLength'] = 1024
|
|
request.fields['lpClassIn'].fields['Data'].fields['Data'].fields['MaximumCount'] = 1024//2
|
|
return dce.request(request)
|
|
|
|
def hBaseRegQueryValue(dce, hKey, lpValueName, dataLen=512):
|
|
request = BaseRegQueryValue()
|
|
request['hKey'] = hKey
|
|
request['lpValueName'] = checkNullString(lpValueName)
|
|
retries = 1
|
|
|
|
# We need to be aware the size might not be enough, so let's catch ERROR_MORE_DATA exception
|
|
while True:
|
|
try:
|
|
request['lpData'] =b' ' * dataLen
|
|
request['lpcbData'] = dataLen
|
|
request['lpcbLen'] = dataLen
|
|
resp = dce.request(request)
|
|
except DCERPCSessionError as e:
|
|
if retries > 1:
|
|
LOG.debug('Too many retries when calling hBaseRegQueryValue, aborting')
|
|
raise
|
|
if e.get_error_code() == system_errors.ERROR_MORE_DATA:
|
|
# We need to adjust the size
|
|
dataLen = e.get_packet()['lpcbData']
|
|
continue
|
|
else:
|
|
raise
|
|
else:
|
|
break
|
|
|
|
# Returns
|
|
# ( dataType, data )
|
|
return resp['lpType'], unpackValue(resp['lpType'], resp['lpData'])
|
|
|
|
def hBaseRegReplaceKey(dce, hKey, lpSubKey, lpNewFile, lpOldFile):
|
|
request = BaseRegReplaceKey()
|
|
request['hKey'] = hKey
|
|
request['lpSubKey'] = checkNullString(lpSubKey)
|
|
request['lpNewFile'] = checkNullString(lpNewFile)
|
|
request['lpOldFile'] = checkNullString(lpOldFile)
|
|
return dce.request(request)
|
|
|
|
def hBaseRegRestoreKey(dce, hKey, lpFile, flags=REG_REFRESH_HIVE):
|
|
request = BaseRegRestoreKey()
|
|
request['hKey'] = hKey
|
|
request['lpFile'] = checkNullString(lpFile)
|
|
request['Flags'] = flags
|
|
return dce.request(request)
|
|
|
|
def hBaseRegSaveKey(dce, hKey, lpFile, pSecurityAttributes = NULL):
|
|
request = BaseRegSaveKey()
|
|
request['hKey'] = hKey
|
|
request['lpFile'] = checkNullString(lpFile)
|
|
request['pSecurityAttributes'] = pSecurityAttributes
|
|
return dce.request(request)
|
|
|
|
def hBaseRegSetValue(dce, hKey, lpValueName, dwType, lpData):
|
|
request = BaseRegSetValue()
|
|
request['hKey'] = hKey
|
|
request['lpValueName'] = checkNullString(lpValueName)
|
|
request['dwType'] = dwType
|
|
request['lpData'] = packValue(dwType,lpData)
|
|
request['cbData'] = len(request['lpData'])
|
|
return dce.request(request)
|
|
|
|
def hBaseRegGetVersion(dce, hKey):
|
|
request = BaseRegGetVersion()
|
|
request['hKey'] = hKey
|
|
return dce.request(request)
|
|
|
|
def hOpenCurrentConfig(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenCurrentConfig()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hBaseRegQueryMultipleValues(dce, hKey, val_listIn):
|
|
# ToDo, check the result to see whether we need to
|
|
# have a bigger buffer for the data to receive
|
|
request = BaseRegQueryMultipleValues()
|
|
request['hKey'] = hKey
|
|
|
|
for item in val_listIn:
|
|
itemn = RVALENT()
|
|
itemn['ve_valuename'] = checkNullString(item['ValueName'])
|
|
itemn['ve_valuelen'] = len(itemn['ve_valuename'])
|
|
itemn['ve_valueptr'] = NULL
|
|
itemn['ve_type'] = item['ValueType']
|
|
request['val_listIn'].append(itemn)
|
|
|
|
request['num_vals'] = len(request['val_listIn'])
|
|
request['lpvalueBuf'] = list(b' '*128)
|
|
request['ldwTotsize'] = 128
|
|
|
|
resp = dce.request(request)
|
|
retVal = list()
|
|
for item in resp['val_listOut']:
|
|
itemn = dict()
|
|
itemn['ValueName'] = item['ve_valuename']
|
|
itemn['ValueData'] = unpackValue(item['ve_type'], resp['lpvalueBuf'][item['ve_valueptr'] : item['ve_valueptr']+item['ve_valuelen']])
|
|
retVal.append(itemn)
|
|
|
|
return retVal
|
|
|
|
def hBaseRegSaveKeyEx(dce, hKey, lpFile, pSecurityAttributes = NULL, flags=1):
|
|
request = BaseRegSaveKeyEx()
|
|
request['hKey'] = hKey
|
|
request['lpFile'] = checkNullString(lpFile)
|
|
request['pSecurityAttributes'] = pSecurityAttributes
|
|
request['Flags'] = flags
|
|
return dce.request(request)
|
|
|
|
def hOpenPerformanceText(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenPerformanceText()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hOpenPerformanceNlsText(dce, samDesired = MAXIMUM_ALLOWED):
|
|
request = OpenPerformanceNlsText()
|
|
request['ServerName'] = NULL
|
|
request['samDesired'] = samDesired
|
|
return dce.request(request)
|
|
|
|
def hBaseRegDeleteValue(dce, hKey, lpValueName):
|
|
request = BaseRegDeleteValue()
|
|
request['hKey'] = hKey
|
|
request['lpValueName'] = checkNullString(lpValueName)
|
|
return dce.request(request)
|