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
}

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:



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

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:



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

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: 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:



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

def enum_key(handle, index)
  enum_key_request_packet = RubySMB::Dcerpc::Winreg::EnumKeyRequest.new(hkey: handle, dw_index: index)
  enum_key_request_packet.lpft_last_write_time = 0
  enum_key_request_packet.lp_class = ''
  enum_key_request_packet.lp_class.referent.buffer = :null
  enum_key_request_packet.lp_name.buffer = ''
  enum_key_request_packet.lp_name.buffer.referent.max_count = 256
  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.to_s
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



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 371

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



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 397

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:



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 249

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.buffer = ''
  enum_value_request_packet.lp_value_name.buffer.referent.max_count = 256
  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.to_s
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)


331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 331

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:



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

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:



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

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:



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

def query_info_key(handle)
  query_info_key_request_packet = RubySMB::Dcerpc::Winreg::QueryInfoKeyRequest.new(hkey: handle)
  query_info_key_request_packet.lp_class = ''
  query_info_key_request_packet.lp_class.referent.actual_count = 0
  query_info_key_request_packet.lp_class.maximum_length = 1024
  query_info_key_request_packet.lp_class.buffer.referent.max_count = 1024 / 2
  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:



132
133
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
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 132

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.referent.max_count = query_value_response.lpcb_data.referent
  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



353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 353

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:



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/ruby_smb/dcerpc/winreg.rb', line 307

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