Module: RubySMB::Dcerpc::Winreg

Defined in:
lib/ruby_smb/dcerpc/winreg.rb,
lib/ruby_smb/dcerpc/winreg/regsam.rb,
lib/ruby_smb/dcerpc/winreg/enum_key_request.rb,
lib/ruby_smb/dcerpc/winreg/open_key_request.rb,
lib/ruby_smb/dcerpc/winreg/save_key_request.rb,
lib/ruby_smb/dcerpc/winreg/close_key_request.rb,
lib/ruby_smb/dcerpc/winreg/enum_key_response.rb,
lib/ruby_smb/dcerpc/winreg/open_key_response.rb,
lib/ruby_smb/dcerpc/winreg/save_key_response.rb,
lib/ruby_smb/dcerpc/winreg/close_key_response.rb,
lib/ruby_smb/dcerpc/winreg/create_key_request.rb,
lib/ruby_smb/dcerpc/winreg/enum_value_request.rb,
lib/ruby_smb/dcerpc/winreg/create_key_response.rb,
lib/ruby_smb/dcerpc/winreg/enum_value_response.rb,
lib/ruby_smb/dcerpc/winreg/query_value_request.rb,
lib/ruby_smb/dcerpc/winreg/query_value_response.rb,
lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb,
lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb,
lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb,
lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb

Defined Under Namespace

Classes: CloseKeyRequest, CloseKeyResponse, CreateKeyRequest, CreateKeyResponse, EnumKeyRequest, EnumKeyResponse, EnumValueRequest, EnumValueResponse, OpenKeyRequest, OpenKeyResponse, OpenRootKeyRequest, OpenRootKeyResponse, PRegistryServerName, PrpcHkey, QueryInfoKeyRequest, QueryInfoKeyResponse, QueryValueRequest, QueryValueResponse, Regsam, RpcHkey, SaveKeyRequest, SaveKeyResponse

Constant Summary collapse

UUID =
'338CD001-2244-31F1-AAAA-900038001003'
VER_MAJOR =
1
VER_MINOR =
0
OPEN_HKCR =

Operation numbers

0x00
OPEN_HKCU =
0x01
OPEN_HKLM =
0x02
OPEN_HKPD =
0x03
OPEN_HKU =
0x04
REG_CLOSE_KEY =
0x05
REG_CREATE_KEY =
0x06
REG_ENUM_KEY =
0x09
REG_ENUM_VALUE =
0x0a
REG_OPEN_KEY =
0x0f
REG_QUERY_INFO_KEY =
0x10
REG_QUERY_VALUE =
0x11
REG_SAVE_KEY =
0x14
OPEN_HKCC =
0x1b
OPEN_HKPT =
0x20
OPEN_HKPN =
0x21
ROOT_KEY_MAP =
{
  "HKEY_CLASSES_ROOT"         => OPEN_HKCR,
  "HKCR"                      => OPEN_HKCR,
  "HKEY_CURRENT_USER"         => OPEN_HKCU,
  "HKCU"                      => OPEN_HKCU,
  "HKEY_LOCAL_MACHINE"        => OPEN_HKLM,
  "HKLM"                      => OPEN_HKLM,
  "HKEY_PERFORMANCE_DATA"     => OPEN_HKPD,
  "HKPD"                      => OPEN_HKPD,
  "HKEY_USERS"                => OPEN_HKU,
  "HKU"                       => OPEN_HKU,
  "HKEY_CURRENT_CONFIG"       => OPEN_HKCC,
  "HKCC"                      => OPEN_HKCC,
  "HKEY_PERFORMANCE_TEXT"     => OPEN_HKPT,
  "HKPT"                      => OPEN_HKPT,
  "HKEY_PERFORMANCE_NLS_TEXT" => OPEN_HKPN,
  "HKPN"                      => OPEN_HKPN
}
BUFFER_SIZE =
1024

Instance Method Summary collapse

Instance Method Details

#close_key(handle) ⇒ WindowsError::Win32

Close the handle to the registry key.

Parameters:

Returns:

  • (WindowsError::Win32)

    the response error status

Raises:



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 173

def close_key(handle)
  close_key_request_packet = RubySMB::Dcerpc::Winreg::CloseKeyRequest.new(hkey: handle)
  response = dcerpc_request(close_key_request_packet)
  begin
    close_key_response = RubySMB::Dcerpc::Winreg::CloseKeyResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the CloseKey response"
  end
  unless close_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when closing the key: "\
      "#{WindowsError::Win32.find_by_retval(close_key_response.error_status.value).join(',')}"
  end

  close_key_response.error_status
end

#create_key(handle, sub_key, opts = {}) ⇒ RubySMB::Dcerpc::Winreg::PrpcHkey

Creates the specified registry key and returns a handle to the newly created key

Parameters:

  • handle (Ndr::NdrContextHandle)

    the handle for the key

  • sub_key (String)

    the name of the key

  • opts (Hash) (defaults to: {})

    options for the CreateKeyRequest

Returns:

Raises:



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 271

def create_key(handle, sub_key, opts = {})
  opts = {
    hkey:                   handle,
    lp_sub_key:             sub_key,
    lp_class:               opts[:lp_class] || :null,
    dw_options:             opts[:dw_options] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
    sam_desired:            opts[:sam_desired] || RubySMB::Dcerpc::Winreg::Regsam.new(maximum_allowed: 1),
    lp_security_attributes: opts[:lp_security_attributes] || RubySMB::Dcerpc::RpcSecurityAttributes.new,
    lpdw_disposition:       opts[:lpdw_disposition] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY,
  }
  create_key_request_packet = RubySMB::Dcerpc::Winreg::CreateKeyRequest.new(opts)
  response = dcerpc_request(create_key_request_packet)
  begin
    create_key_response = RubySMB::Dcerpc::Winreg::CreateKeyResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the CreateKey response"
  end
  unless create_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when creating key #{sub_key}: "\
      "#{WindowsError::Win32.find_by_retval(create_key_response.error_status.value).join(',')}"
  end

  create_key_response.hkey
end

#enum_key(handle, index) ⇒ String

Enumerate the subkey at the specified index.

Parameters:

Returns:

  • (String)

    the subkey name

Raises:



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 220

def enum_key(handle, index)
  enum_key_request_packet = RubySMB::Dcerpc::Winreg::EnumKeyRequest.new(hkey: handle, dw_index: index)
  # `lp_class` cannot be null, even if it contains no value
  enum_key_request_packet.lp_class.instantiate_referent
  enum_key_request_packet.lp_name.set_max_buffer_size(BUFFER_SIZE)
  response = dcerpc_request(enum_key_request_packet)
  begin
    enum_key_response = RubySMB::Dcerpc::Winreg::EnumKeyResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the EnumKey response"
  end
  unless enum_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating the key: "\
      "#{WindowsError::Win32.find_by_retval(enum_key_response.error_status.value).join(',')}"
  end

  enum_key_response.lp_name[:buffer]
end

#enum_registry_key(key, bind: true) ⇒ Array<String>

Enumerate the subkeys of a specified registry key. If only a root key is provided, it enumerates its subkeys.

Parameters:

  • key (String)

    the registry key

Returns:

  • (Array<String>)

    the subkeys



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 367

def enum_registry_key(key, bind: true)
  bind(endpoint: RubySMB::Dcerpc::Winreg) if bind

  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
  root_key_handle = open_root_key(root_key)
  subkey_handle = if sub_key.nil? || sub_key.empty?
                    root_key_handle
                  else
                    open_key(root_key_handle, sub_key)
                  end
  query_info_key_response = query_info_key(subkey_handle)
  key_count = query_info_key_response.lpc_sub_keys.to_i
  enum_result = []
  key_count.times do |i|
    enum_result << enum_key(subkey_handle, i)
  end
  enum_result
ensure
  close_key(subkey_handle) if subkey_handle
  close_key(root_key_handle) if root_key_handle && root_key_handle != subkey_handle
end

#enum_registry_values(key, bind: true) ⇒ Array<String>

Enumerate the values for the specified registry key.

Parameters:

  • key (String)

    the registry key

Returns:

  • (Array<String>)

    the values



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 393

def enum_registry_values(key, bind: true)
  bind(endpoint: RubySMB::Dcerpc::Winreg) if bind

  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
  root_key_handle = open_root_key(root_key)
  subkey_handle = if sub_key.nil? || sub_key.empty?
                    root_key_handle
                  else
                    open_key(root_key_handle, sub_key)
                  end
  query_info_key_response = query_info_key(subkey_handle)
  value_count = query_info_key_response.lpc_values.to_i
  enum_result = []
  value_count.times do |i|
    enum_result << enum_value(subkey_handle, i)
  end
  enum_result
ensure
  close_key(subkey_handle) if subkey_handle
  close_key(root_key_handle) if root_key_handle && root_key_handle != subkey_handle
end

#enum_value(handle, index) ⇒ String

Enumerate the value at the specified index for the specified registry key.

Parameters:

Returns:

  • (String)

    the data of the value entry

Raises:



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 246

def enum_value(handle, index)
  enum_value_request_packet = RubySMB::Dcerpc::Winreg::EnumValueRequest.new(hkey: handle, dw_index: index)
  enum_value_request_packet.lp_value_name.set_max_buffer_size(BUFFER_SIZE)
  response = dcerpc_request(enum_value_request_packet)
  begin
    enum_value_response = RubySMB::Dcerpc::Winreg::EnumValueResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the Enumvalue response"
  end
  unless enum_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating values: "\
      "#{WindowsError::Win32.find_by_retval(enum_value_response.error_status.value).join(',')}"
  end

  enum_value_response.lp_value_name[:buffer]
end

#has_registry_key?(key, bind: true) ⇒ Boolean

Checks if the specified registry key exists. It returns true if it exists, false otherwise.

Parameters:

  • key (String)

    the registry key to check

Returns:

  • (Boolean)


327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 327

def has_registry_key?(key, bind: true)
  bind(endpoint: RubySMB::Dcerpc::Winreg) if bind

  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
  begin
    root_key_handle = open_root_key(root_key)
    subkey_handle = open_key(root_key_handle, sub_key)
  rescue RubySMB::Dcerpc::Error::WinregError
    return false
  end
  return true
ensure
  close_key(subkey_handle) if subkey_handle
  close_key(root_key_handle) if root_key_handle
end

#open_key(handle, sub_key) ⇒ Ndr::NdrContextHandle

Open the registry key specified by a root key handle (previously open with #open_root_key) and a subkey. It returns a handle for the key.

Parameters:

Returns:

Raises:



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 106

def open_key(handle, sub_key)
  openkey_request_packet = RubySMB::Dcerpc::Winreg::OpenKeyRequest.new(hkey: handle, lp_sub_key: sub_key)
  openkey_request_packet.sam_desired.read_control = 1
  openkey_request_packet.sam_desired.key_query_value = 1
  openkey_request_packet.sam_desired.key_enumerate_sub_keys = 1
  openkey_request_packet.sam_desired.key_notify = 1
  response = dcerpc_request(openkey_request_packet)
  begin
    open_key_response = RubySMB::Dcerpc::Winreg::OpenKeyResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the OpenKey response"
  end
  unless open_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when opening subkey #{sub_key}: "\
      "#{WindowsError::Win32.find_by_retval(open_key_response.error_status.value).join(',')}"
  end

  open_key_response.phk_result
end

#open_root_key(root_key) ⇒ Ndr::NdrContextHandle

Open the registry root key and return a handle for it. The key can be either a long format (e.g. HKEY_LOCAL_MACHINE) or a short format (e.g. HKLM)

Parameters:

  • root_key (String)

    the root key to open

Returns:

Raises:



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 76

def open_root_key(root_key)
  root_key_opnum = RubySMB::Dcerpc::Winreg::ROOT_KEY_MAP[root_key]
  raise ArgumentError, "Unknown Root Key: #{root_key}" unless root_key_opnum

  root_key_request_packet = OpenRootKeyRequest.new(opnum: root_key_opnum)
  response = dcerpc_request(root_key_request_packet)

  begin
    root_key_response_packet = OpenRootKeyResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket,
      "Error reading OpenRootKeyResponse (command = #{root_key_opnum})"
  end
  unless root_key_response_packet.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError,
      "Error returned when opening root key #{root_key}: "\
      "#{WindowsError::Win32.find_by_retval(root_key_response_packet.error_status.value).join(',')}"
  end

  root_key_response_packet.ph_key
end

#query_info_key(handle) ⇒ RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse

Retrive relevant information on the key that corresponds to the specified key handle.

Parameters:

Returns:

Raises:



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 196

def query_info_key(handle)
  query_info_key_request_packet = RubySMB::Dcerpc::Winreg::QueryInfoKeyRequest.new(hkey: handle)
  query_info_key_request_packet.lp_class.set_max_buffer_size(BUFFER_SIZE)
  response = dcerpc_request(query_info_key_request_packet)
  begin
    query_info_key_response = RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the query_infoKey response"
  end
  unless query_info_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when querying information: "\
      "#{WindowsError::Win32.find_by_retval(query_info_key_response.error_status.value).join(',')}"
  end

  query_info_key_response
end

#query_value(handle, value_name) ⇒ String

Retrieve the data associated with the named value of a specified registry open key.

Parameters:

  • handle (Ndr::NdrContextHandle)

    the handle for the key

  • value_name (String)

    the name of the value

Returns:

  • (String)

    the data of the value entry

Raises:



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 134

def query_value(handle, value_name)
  query_value_request_packet = RubySMB::Dcerpc::Winreg::QueryValueRequest.new(hkey: handle, lp_value_name: value_name)
  query_value_request_packet.lp_type = 0
  query_value_request_packet.lpcb_data = 0
  query_value_request_packet.lpcb_len = 0
  response = dcerpc_request(query_value_request_packet)
  begin
    query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
  end
  unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
      "#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
  end

  query_value_request_packet.lpcb_data = query_value_response.lpcb_data
  query_value_request_packet.lp_data = []
  query_value_request_packet.lp_data.max_count = query_value_response.lpcb_data.to_i
  response = dcerpc_request(query_value_request_packet)
  begin
    query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
  end
  unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
      "#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
  end

  query_value_response.data
end

#read_registry_key_value(key, value_name, bind: true) ⇒ String

Retrieve the data associated with the named value of a specified registry key.

Parameters:

  • key (String)

    the registry key

  • value_name (String)

    the name of the value to read

Returns:

  • (String)

    the data of the value entry



349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 349

def read_registry_key_value(key, value_name, bind: true)
  bind(endpoint: RubySMB::Dcerpc::Winreg) if bind

  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
  root_key_handle = open_root_key(root_key)
  subkey_handle = open_key(root_key_handle, sub_key)
  value = query_value(subkey_handle, value_name)
  value
ensure
  close_key(subkey_handle) if subkey_handle
  close_key(root_key_handle) if root_key_handle
end

#save_key(handle, file_name, opts = {}) ⇒ Object

Saves the specified key, subkeys, and values to a new file

Parameters:

  • handle (Ndr::NdrContextHandle)

    the handle for the key

  • file_name (String)

    the name of the registry file in which the specified key and subkeys are to be saved

  • opts (Hash) (defaults to: {})

    options for the SaveKeyRequest

Raises:



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 303

def save_key(handle, file_name, opts = {})
  opts = {
    hkey:                   handle,
    lp_file:                file_name,
    lp_security_attributes: opts[:lp_security_attributes] || :null,
  }
  save_key_request_packet = RubySMB::Dcerpc::Winreg::SaveKeyRequest.new(opts)
  response = dcerpc_request(save_key_request_packet)
  begin
    save_key_response = RubySMB::Dcerpc::Winreg::SaveKeyResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the SaveKeyResponse response"
  end
  unless save_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::WinregError, "Error returned when saving key to #{file_name}: "\
      "#{WindowsError::Win32.find_by_retval(save_key_response.error_status.value).join(',')}"
  end
end