Generated from Manticore v1.1.5 • 201 packages. View on pkg.go.dev

ms_rrp

import "github.com/TheManticoreProject/Manticore/network/dcerpc/ms-protocols/ms-rrp"

Package ms_rrp implements the high-level MS-RRP (Windows Remote Registry Protocol) client API over the winreg DCE/RPC interface (338cd001-2244-31f1-aaaa-900038001003 v1.0), carried over the \winreg named pipe on the IPC$ tree.

It is the protocol layer above the interface: callers hold a connected and authenticated SMB client and drive a RemoteRegistry, which binds winreg once and then exposes every interface method by its exact name (OpenLocalMachine, BaseRegOpenKey, BaseRegQueryValue, …) as a method on the struct, plus a small set of ergonomic, reg.exe-style helpers (OpenKeyByPath, QueryValueByPath, EnumKeys, …).

Unlike the stateless MS-SRVS layer, registry context handles CHAIN (HKLM -> subkey -> close) and are scoped to the RPC association, so RemoteRegistry binds a SINGLE \winreg pipe in Connect and reuses it for the lifetime of the client; a handle obtained on one association cannot be used on another. Close tears the pipe down, which releases any server-side handles.

References:

  • [MS-RRP] 3.1.5 winreg method behaviours; 2.2.4 REGSAM; [MS-ERREF] 2.2 Win32 codes
  • [MS-RPCE] DCE/RPC over SMB named pipes

Index

Constants

REGSAM access rights ([MS-RRP] 2.2.4), re-exported from the winreg interface and typed as ndr.DWORD so they can be passed directly as the samDesired argument of the Open* / BaseRegOpenKey / BaseRegCreateKey methods without conversion or importing the interface package.

const (
    KeyQueryValue       = ndr.DWORD(winreg.KeyQueryValue)
    KeySetValue         = ndr.DWORD(winreg.KeySetValue)
    KeyCreateSubKey     = ndr.DWORD(winreg.KeyCreateSubKey)
    KeyEnumerateSubKeys = ndr.DWORD(winreg.KeyEnumerateSubKeys)
    KeyNotify           = ndr.DWORD(winreg.KeyNotify)
    KeyCreateLink       = ndr.DWORD(winreg.KeyCreateLink)
    KeyWow6464Key       = ndr.DWORD(winreg.KeyWow64_64Key)
    KeyWow6432Key       = ndr.DWORD(winreg.KeyWow64_32Key)
    KeyRead             = ndr.DWORD(winreg.KeyRead)
    KeyWrite            = ndr.DWORD(winreg.KeyWrite)
    KeyExecute          = ndr.DWORD(winreg.KeyExecute)
    KeyAllAccess        = ndr.DWORD(winreg.KeyAllAccess)

    // MaximumAllowed is MAXIMUM_ALLOWED ([MS-DTYP] 2.4.3): grant the most access the caller
    // is permitted.
    MaximumAllowed = maximumAllowed
)

dwOptions for BaseRegCreateKey ([MS-RRP] 3.1.5.7), re-exported and typed as ndr.DWORD.

const (
    RegOptionNonVolatile = ndr.DWORD(winreg.RegOptionNonVolatile)
    RegOptionVolatile    = ndr.DWORD(winreg.RegOptionVolatile)
)

Registry value types (the RegistryValue.Type / dwType field) ([MS-RRP] 3.1.1.6), re-exported from the winreg interface as plain uint32 to match RegistryValue.Type.

const (
    RegNone     = winreg.RegNone
    RegSz       = winreg.RegSz
    RegExpandSz = winreg.RegExpandSz
    RegBinary   = winreg.RegBinary
    RegDword    = winreg.RegDword
    RegLink     = winreg.RegLink
    RegMultiSz  = winreg.RegMultiSz
    RegQword    = winreg.RegQword
)

Key-creation disposition values returned by BaseRegCreateKey / CreateKeyByPath ([MS-RRP] 3.1.5.7).

const (
    RegCreatedNewKey     = winreg.RegCreatedNewKey
    RegOpenedExistingKey = winreg.RegOpenedExistingKey
)

Variables

ErrNotConnected is returned by methods invoked before a successful Connect.

var ErrNotConnected = errors.New("ms_rrp: not connected; call Connect first")

type Handle

Handle is an open registry key context handle returned by the Open*/BaseRegCreateKey/ BaseRegOpenKey methods. It aliases the interface’s RPC_HKEY so it can be passed back to any method without conversion.

type Handle = structures.RPC_HKEY

type PipeDialer

PipeDialer opens a fresh DCE/RPC named-pipe transport over an established, IPC$-tree- connected SMB session. It is the only capability MS-RRP needs from the SMB layer, so depending on this interface (rather than a concrete SMB client) keeps ms_rrp independent of the SMB dialect: network/smb/client.Client satisfies it (via its RPCTransport method) and routes to an SMB1 or SMB2 named-pipe transport according to what was negotiated.

type PipeDialer interface {
    RPCTransport(pipeName string) (dcerpctransport.Transport, error)
}

type RegistryValue

RegistryValue is a typed registry value: its REG_* type and its raw little-endian data bytes, exactly as carried on the wire. The decode helpers (String, Uint32, …) project the bytes per Type; the constructor helpers (StringValue, DwordValue, …) build the bytes for SetValue.

type RegistryValue struct {
    Type uint32
    Data []byte
}

func BinaryValue

func BinaryValue(b []byte) RegistryValue

BinaryValue builds a REG_BINARY value from raw bytes.

func DwordValue

func DwordValue(v uint32) RegistryValue

DwordValue builds a REG_DWORD value (little-endian).

func ExpandStringValue

func ExpandStringValue(s string) RegistryValue

ExpandStringValue builds a REG_EXPAND_SZ value from a Go string.

func MultiStringValue

func MultiStringValue(items []string) RegistryValue

MultiStringValue builds a REG_MULTI_SZ value: each string NUL-terminated, the block terminated by a final empty string.

func QwordValue

func QwordValue(v uint64) RegistryValue

QwordValue builds a REG_QWORD value (little-endian).

func StringValue

func StringValue(s string) RegistryValue

StringValue builds a REG_SZ value from a Go string.

func (RegistryValue) MultiString

func (v RegistryValue) MultiString() []string

MultiString decodes a REG_MULTI_SZ: a sequence of UTF-16LE strings, each NUL-terminated, the whole terminated by an empty string. Empty trailing entries are dropped.

func (RegistryValue) String

func (v RegistryValue) String() string

String decodes REG_SZ / REG_EXPAND_SZ / REG_LINK as a UTF-16LE string (trailing NULs stripped). For other types it returns the empty string; use the type-specific helpers.

func (RegistryValue) Uint32

func (v RegistryValue) Uint32() (uint32, bool)

Uint32 decodes a REG_DWORD (little-endian). ok is false if the data is too short.

func (RegistryValue) Uint64

func (v RegistryValue) Uint64() (uint64, bool)

Uint64 decodes a REG_QWORD (little-endian). ok is false if the data is too short.

type RemoteRegistry

RemoteRegistry is the connected MS-RRP client. It carries the session it is reached over (the pipe dialer) and, once Connect has run, the single bound \winreg association that all method calls and chained key handles share.

type RemoteRegistry struct {
    // contains filtered or unexported fields
}

func New

func New(dialer PipeDialer) *RemoteRegistry

New returns a RemoteRegistry over the given pipe dialer (typically a *network/smb/client.Client). The dialer MUST be connected, authenticated, and tree-connected to IPC$ before Connect is called.

func (*RemoteRegistry) BaseRegCloseKey

func (r *RemoteRegistry) BaseRegCloseKey(hKey structures.PRPC_HKEY) (structures.PRPC_HKEY, error)

BaseRegCloseKey calls BaseRegCloseKey (opnum 5): releases an open key handle.

func (*RemoteRegistry) BaseRegCreateKey

func (r *RemoteRegistry) BaseRegCreateKey(hKey structures.RPC_HKEY, lpSubKey structures.RRP_UNICODE_STRING, lpClass structures.RRP_UNICODE_STRING, dwOptions ndr.DWORD, samDesired ndr.DWORD, lpSecurityAttributes *structures.RPC_SECURITY_ATTRIBUTES, lpdwDisposition *ndr.DWORD) (structures.PRPC_HKEY, *ndr.DWORD, error)

BaseRegCreateKey calls BaseRegCreateKey (opnum 6): creates or opens a subkey.

func (*RemoteRegistry) BaseRegDeleteKey

func (r *RemoteRegistry) BaseRegDeleteKey(hKey structures.RPC_HKEY, lpSubKey structures.RRP_UNICODE_STRING) error

BaseRegDeleteKey calls BaseRegDeleteKey (opnum 7): deletes a subkey with no subkeys.

func (*RemoteRegistry) BaseRegDeleteKeyEx

func (r *RemoteRegistry) BaseRegDeleteKeyEx(hKey structures.RPC_HKEY, lpSubKey structures.RRP_UNICODE_STRING, accessMask ndr.DWORD, reserved ndr.DWORD) error

BaseRegDeleteKeyEx calls BaseRegDeleteKeyEx (opnum 35): deletes a subkey honouring the KEY_WOW64_* view selected by accessMask.

func (*RemoteRegistry) BaseRegDeleteValue

func (r *RemoteRegistry) BaseRegDeleteValue(hKey structures.RPC_HKEY, lpValueName structures.RRP_UNICODE_STRING) error

BaseRegDeleteValue calls BaseRegDeleteValue (opnum 8): removes a named value.

func (*RemoteRegistry) BaseRegEnumKey

func (r *RemoteRegistry) BaseRegEnumKey(hKey structures.RPC_HKEY, dwIndex ndr.DWORD, lpNameIn structures.RRP_UNICODE_STRING, lpClassIn *structures.RRP_UNICODE_STRING, lpftLastWriteTime *dtyp.FILETIME) (structures.RRP_UNICODE_STRING, *dtyp.RPC_UNICODE_STRING, *dtyp.FILETIME, error)

BaseRegEnumKey calls BaseRegEnumKey (opnum 9): returns the subkey at dwIndex.

func (*RemoteRegistry) BaseRegEnumValue

func (r *RemoteRegistry) BaseRegEnumValue(hKey structures.RPC_HKEY, dwIndex ndr.DWORD, lpValueNameIn structures.RRP_UNICODE_STRING, lpType *ndr.DWORD, lpData []uint8, lpcbData *ndr.DWORD, lpcbLen *ndr.DWORD) (dtyp.RPC_UNICODE_STRING, *ndr.DWORD, []uint8, *ndr.DWORD, *ndr.DWORD, error)

BaseRegEnumValue calls BaseRegEnumValue (opnum 10): returns the value at dwIndex.

func (*RemoteRegistry) BaseRegFlushKey

func (r *RemoteRegistry) BaseRegFlushKey(hKey structures.RPC_HKEY) error

BaseRegFlushKey calls BaseRegFlushKey (opnum 11): writes a key’s changes to disk.

func (*RemoteRegistry) BaseRegGetKeySecurity

func (r *RemoteRegistry) BaseRegGetKeySecurity(hKey structures.RPC_HKEY, securityInformation ndr.DWORD, pRpcSecurityDescriptorIn structures.RPC_SECURITY_DESCRIPTOR) (structures.RPC_SECURITY_DESCRIPTOR, error)

BaseRegGetKeySecurity calls BaseRegGetKeySecurity (opnum 12): returns the parts of a key’s security descriptor selected by securityInformation (an OWNER/GROUP/DACL/SACL bitmask).

func (*RemoteRegistry) BaseRegGetVersion

func (r *RemoteRegistry) BaseRegGetVersion(hKey structures.RPC_HKEY) (ndr.DWORD, error)

BaseRegGetVersion calls BaseRegGetVersion (opnum 26): returns the registry version.

func (*RemoteRegistry) BaseRegLoadKey

func (r *RemoteRegistry) BaseRegLoadKey(hKey structures.RPC_HKEY, lpSubKey structures.RRP_UNICODE_STRING, lpFile structures.RRP_UNICODE_STRING) error

BaseRegLoadKey calls BaseRegLoadKey (opnum 13): loads a hive file under a subkey.

func (*RemoteRegistry) BaseRegOpenKey

func (r *RemoteRegistry) BaseRegOpenKey(hKey structures.RPC_HKEY, lpSubKey structures.RRP_UNICODE_STRING, dwOptions ndr.DWORD, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

BaseRegOpenKey calls BaseRegOpenKey (opnum 15): opens an existing subkey.

func (*RemoteRegistry) BaseRegQueryInfoKey

func (r *RemoteRegistry) BaseRegQueryInfoKey(hKey structures.RPC_HKEY, lpClassIn structures.RRP_UNICODE_STRING) (dtyp.RPC_UNICODE_STRING, ndr.DWORD, ndr.DWORD, ndr.DWORD, ndr.DWORD, ndr.DWORD, ndr.DWORD, ndr.DWORD, dtyp.FILETIME, error)

BaseRegQueryInfoKey calls BaseRegQueryInfoKey (opnum 16): returns subkey/value counts, maximum lengths, and the last-write time of a key.

func (*RemoteRegistry) BaseRegQueryMultipleValues

func (r *RemoteRegistry) BaseRegQueryMultipleValues(hKey structures.RPC_HKEY, val_listIn []structures.RVALENT, num_vals ndr.DWORD, lpvalueBuf []byte, ldwTotsize ndr.DWORD) ([]structures.RVALENT, []byte, ndr.DWORD, error)

BaseRegQueryMultipleValues calls BaseRegQueryMultipleValues (opnum 29).

func (*RemoteRegistry) BaseRegQueryMultipleValues2

func (r *RemoteRegistry) BaseRegQueryMultipleValues2(hKey structures.RPC_HKEY, val_listIn []structures.RVALENT, num_vals ndr.DWORD, lpvalueBuf []byte, ldwTotsize ndr.DWORD) ([]structures.RVALENT, []byte, ndr.DWORD, error)

BaseRegQueryMultipleValues2 calls BaseRegQueryMultipleValues2 (opnum 34).

func (*RemoteRegistry) BaseRegQueryValue

func (r *RemoteRegistry) BaseRegQueryValue(hKey structures.RPC_HKEY, lpValueName structures.RRP_UNICODE_STRING, lpType *ndr.DWORD, lpData []uint8, lpcbData *ndr.DWORD, lpcbLen *ndr.DWORD) (*ndr.DWORD, []uint8, *ndr.DWORD, *ndr.DWORD, error)

BaseRegQueryValue calls BaseRegQueryValue (opnum 17). It mirrors the interface function exactly (minus the invoker); for ergonomic reads use QueryValueByPath / queryValue.

func (*RemoteRegistry) BaseRegReplaceKey

func (r *RemoteRegistry) BaseRegReplaceKey(hKey structures.RPC_HKEY, lpSubKey structures.RRP_UNICODE_STRING, lpNewFile structures.RRP_UNICODE_STRING, lpOldFile structures.RRP_UNICODE_STRING) error

BaseRegReplaceKey calls BaseRegReplaceKey (opnum 18).

func (*RemoteRegistry) BaseRegRestoreKey

func (r *RemoteRegistry) BaseRegRestoreKey(hKey structures.RPC_HKEY, lpFile structures.RRP_UNICODE_STRING, flags ndr.DWORD) error

BaseRegRestoreKey calls BaseRegRestoreKey (opnum 19).

func (*RemoteRegistry) BaseRegSaveKey

func (r *RemoteRegistry) BaseRegSaveKey(hKey structures.RPC_HKEY, lpFile structures.RRP_UNICODE_STRING, pSecurityAttributes *structures.RPC_SECURITY_ATTRIBUTES) error

BaseRegSaveKey calls BaseRegSaveKey (opnum 20): saves a key and its subtree to a file.

func (*RemoteRegistry) BaseRegSaveKeyEx

func (r *RemoteRegistry) BaseRegSaveKeyEx(hKey structures.RPC_HKEY, lpFile structures.RRP_UNICODE_STRING, pSecurityAttributes *structures.RPC_SECURITY_ATTRIBUTES, flags ndr.DWORD) error

BaseRegSaveKeyEx calls BaseRegSaveKeyEx (opnum 31): saves a key with format flags.

func (*RemoteRegistry) BaseRegSetKeySecurity

func (r *RemoteRegistry) BaseRegSetKeySecurity(hKey structures.RPC_HKEY, securityInformation ndr.DWORD, pRpcSecurityDescriptor structures.RPC_SECURITY_DESCRIPTOR) error

BaseRegSetKeySecurity calls BaseRegSetKeySecurity (opnum 21): sets the parts of a key’s security descriptor selected by securityInformation.

func (*RemoteRegistry) BaseRegSetValue

func (r *RemoteRegistry) BaseRegSetValue(hKey structures.RPC_HKEY, lpValueName structures.RRP_UNICODE_STRING, dwType ndr.DWORD, lpData []uint8, cbData ndr.DWORD) error

BaseRegSetValue calls BaseRegSetValue (opnum 22): writes a value’s type and data.

func (*RemoteRegistry) BaseRegUnLoadKey

func (r *RemoteRegistry) BaseRegUnLoadKey(hKey structures.RPC_HKEY, lpSubKey structures.RRP_UNICODE_STRING) error

BaseRegUnLoadKey calls BaseRegUnLoadKey (opnum 23): unloads a previously loaded hive.

func (*RemoteRegistry) Close

func (r *RemoteRegistry) Close() error

Close tears down the winreg association, releasing any server-side key handles still open on it. It is safe to call on a client that was never connected.

func (*RemoteRegistry) Connect

func (r *RemoteRegistry) Connect() error

Connect opens the \winreg pipe and binds the winreg abstract syntax, establishing the single association that all subsequent calls and key handles use. It is idempotent: calling it on an already-connected client is a no-op.

func (*RemoteRegistry) CreateKeyByPath

func (r *RemoteRegistry) CreateKeyByPath(keyPath string, samDesired ndr.DWORD) (Handle, ndr.DWORD, error)

CreateKeyByPath creates (or opens, if it already exists) the key at keyPath, returning the new handle and the disposition (RegCreatedNewKey / RegOpenedExistingKey). The caller must BaseRegCloseKey the returned handle.

func (*RemoteRegistry) DeleteKeyByPath

func (r *RemoteRegistry) DeleteKeyByPath(keyPath string) error

DeleteKeyByPath deletes the key at keyPath. The key must have no subkeys (per BaseRegDeleteKey). Root keys cannot be deleted.

func (*RemoteRegistry) DeleteValueByPath

func (r *RemoteRegistry) DeleteValueByPath(keyPath, valueName string) error

DeleteValueByPath opens keyPath for write, removes valueName, and closes the key.

func (*RemoteRegistry) EnumKeys

func (r *RemoteRegistry) EnumKeys(h Handle) ([]string, error)

EnumKeys returns the names of all immediate subkeys of an open key, looping BaseRegEnumKey until ERROR_NO_MORE_ITEMS. Subkey names are capped at 255 UTF-16 code units by the registry, but the name/class buffers grow and retry the same index on ERROR_MORE_DATA to stay robust if a server reports a longer name. The server counts the terminating NUL in the returned name’s length, so it is stripped to yield a clean Go string usable as a path component.

func (*RemoteRegistry) EnumKeysByPath

func (r *RemoteRegistry) EnumKeysByPath(keyPath string) ([]string, error)

EnumKeysByPath opens keyPath, enumerates its subkeys, and closes the key.

func (*RemoteRegistry) EnumValues

func (r *RemoteRegistry) EnumValues(h Handle) ([]ValueEntry, error)

EnumValues returns all values of an open key, looping BaseRegEnumValue until ERROR_NO_MORE_ITEMS. The data buffer is negotiated per value: it grows and retries the same index on ERROR_MORE_DATA (e.g. values whose data exceeds the initial buffer). The server counts the terminating NUL in the returned value name’s length, so it is stripped.

func (*RemoteRegistry) EnumValuesByPath

func (r *RemoteRegistry) EnumValuesByPath(keyPath string) ([]ValueEntry, error)

EnumValuesByPath opens keyPath, enumerates its values, and closes the key.

func (*RemoteRegistry) IsConnected

func (r *RemoteRegistry) IsConnected() bool

IsConnected reports whether Connect has succeeded and Close has not yet run.

func (*RemoteRegistry) OpenClassesRoot

func (r *RemoteRegistry) OpenClassesRoot(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenClassesRoot calls OpenClassesRoot (opnum 0): opens HKEY_CLASSES_ROOT.

func (*RemoteRegistry) OpenCurrentConfig

func (r *RemoteRegistry) OpenCurrentConfig(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenCurrentConfig calls OpenCurrentConfig (opnum 27): opens HKEY_CURRENT_CONFIG.

func (*RemoteRegistry) OpenCurrentUser

func (r *RemoteRegistry) OpenCurrentUser(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenCurrentUser calls OpenCurrentUser (opnum 1): opens HKEY_CURRENT_USER.

func (*RemoteRegistry) OpenKeyByPath

func (r *RemoteRegistry) OpenKeyByPath(keyPath string, samDesired ndr.DWORD) (Handle, error)

OpenKeyByPath opens the key at a full path such as “HKLM\\SOFTWARE\\Microsoft”, with the requested access. The caller owns the returned handle and must BaseRegCloseKey it. The transient root handle is closed before returning.

func (*RemoteRegistry) OpenLocalMachine

func (r *RemoteRegistry) OpenLocalMachine(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenLocalMachine calls OpenLocalMachine (opnum 2): opens HKEY_LOCAL_MACHINE.

func (*RemoteRegistry) OpenPerformanceData

func (r *RemoteRegistry) OpenPerformanceData(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenPerformanceData calls OpenPerformanceData (opnum 3): opens HKEY_PERFORMANCE_DATA.

func (*RemoteRegistry) OpenPerformanceNlsText

func (r *RemoteRegistry) OpenPerformanceNlsText(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenPerformanceNlsText calls OpenPerformanceNlsText (opnum 33).

func (*RemoteRegistry) OpenPerformanceText

func (r *RemoteRegistry) OpenPerformanceText(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenPerformanceText calls OpenPerformanceText (opnum 32).

func (*RemoteRegistry) OpenUsers

func (r *RemoteRegistry) OpenUsers(serverName *ndr.WSTR, samDesired ndr.DWORD) (structures.PRPC_HKEY, error)

OpenUsers calls OpenUsers (opnum 4): opens HKEY_USERS.

func (*RemoteRegistry) QueryValueByPath

func (r *RemoteRegistry) QueryValueByPath(keyPath, valueName string) (RegistryValue, error)

QueryValueByPath opens keyPath for read, reads valueName, and closes the key.

func (*RemoteRegistry) SetValueByPath

func (r *RemoteRegistry) SetValueByPath(keyPath, valueName string, value RegistryValue) error

SetValueByPath opens keyPath for write, writes value under valueName, and closes the key.

type ValueEntry

ValueEntry pairs a value’s name with its typed data, as returned by EnumValues.

type ValueEntry struct {
    Name  string
    Value RegistryValue
}