Class: Msf::Util::WindowsRegistry::RegistryParser
- Inherits:
-
Object
- Object
- Msf::Util::WindowsRegistry::RegistryParser
- Defined in:
- lib/msf/util/windows_registry/registry_parser.rb
Overview
This utility class processes binary Windows registry key. It is usually used when only offline processing is possible and [MS-RRP] BaseRegSaveKey() is used to save a registry key to a file.
It also includes helpers for specific registry keys (SAM, SECURITY) through the ‘name` key word argument during instantiation.
Defined Under Namespace
Classes: RegHash, RegHash2, RegHbin, RegHbinBlock, RegLf, RegLh, RegNk, RegRegf, RegRi, RegSk, RegVk
Constant Summary collapse
- ROOT_KEY =
Constants
0x2c
- REG_NONE =
0x00
- REG_SZ =
0x01
- REG_EXPAND_SZ =
0x02
- REG_BINARY =
0x03
- REG_DWORD =
0x04
- REG_MULTISZ =
0x07
- REG_QWORD =
0x0b
- REGF_MAGIC =
REGF magic value: ‘regf’
0x72656766
- NK_MAGIC =
NK magic value: ‘nk’
0x6E6B
- VK_MAGIC =
VK magic value: ‘vk’
0x766B
- LF_MAGIC =
LF magic value: ‘lf’
0x6C66
- LH_MAGIC =
LH magic value: ‘lh’
0x6C68
- RI_MAGIC =
RI magic value: ‘ri’
0x7269
- SK_MAGIC =
SK magic value: ‘sk’
0x7269
- HBIN_MAGIC =
HBIN magic value: ‘hbin’
0x6862696E
Instance Method Summary collapse
-
#enum_key(key) ⇒ Array
Enumerate the subkey names under ‘key`.
-
#enum_values(key) ⇒ Array
Enumerate the subkey values under ‘key`.
-
#find_key(key) ⇒ RegHbinBlock?
Search for a given key from the ROOT key and returns it as a block.
-
#find_root_key ⇒ RegHbinBlock
Returns the ROOT key as a block.
-
#find_sub_key(parent_key, sub_key) ⇒ RegHbinBlock?
Search for a sub key from a given base key.
-
#get_block(offset) ⇒ RegHbinBlock
Returns a registry block given its offset.
-
#get_data(offset, count) ⇒ String
Returns the data at a given offset from the end of the header in the raw hive binary.
-
#get_lh_hash(key) ⇒ Integer
Returns the hash of a LH subkey from www.sentinelchicken.com/data/TheWindowsNTRegistryFileFormat.pdf (Appendix C).
-
#get_offset(magic, hash_rec, key) ⇒ Integer
Returns the offset of a given subkey in a hash record.
-
#get_value(reg_key, reg_value = nil) ⇒ Array
Returns the type and the data of a given key/value pair.
-
#get_value_blocks(offset, count) ⇒ Array
Returns a list of ‘count“value blocks from the offsets located at `offset`.
-
#get_value_data(record) ⇒ String
Returns the data of a VK record value.
-
#initialize(hive_data, name: nil) ⇒ RegistryParser
constructor
A new instance of RegistryParser.
Constructor Details
#initialize(hive_data, name: nil) ⇒ RegistryParser
Returns a new instance of RegistryParser.
202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 202 def initialize(hive_data, name: nil) @hive_data = hive_data.b @regf = RegRegf.read(@hive_data) @root_key = find_root_key case name when :sam require_relative 'sam' extend Sam when :security require_relative 'security' extend Security end end |
Instance Method Details
#enum_key(key) ⇒ Array
Enumerate the subkey names under ‘key`
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 413 def enum_key(key) parent_key = find_key(key) return nil unless parent_key unless parent_key.data&.magic == NK_MAGIC raise ArgumentError, "enum_key: parent key must be a NK record" end block = get_block(parent_key.data.offset_sub_key_lf) records = [] if block.data.magic == RI_MAGIC # ri points to lf/lh records, so we consolidate the hash records in the main records array block.data.hash_records.each do |hash_record| record = get_block(hash_record.offset_nk) records.concat(record.data.hash_records) end else records.concat(block.data.hash_records) end records.map do |reg_hash| nk = get_block(reg_hash.offset_nk) nk.data.key_name.to_s.b end end |
#enum_values(key) ⇒ Array
Enumerate the subkey values under ‘key`
443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 443 def enum_values(key) key_obj = find_key(key) return nil unless key_obj unless key_obj&.data&.magic == NK_MAGIC raise ArgumentError, "enum_values: key must be a NK record" end res = [] value_list = get_value_blocks(key_obj.data.offset_value_list, key_obj.data.num_values + 1) value_list.each do |value| res << (value.data.flag > 0 ? value.data.name : nil) end res end |
#find_key(key) ⇒ RegHbinBlock?
Search for a given key from the ROOT key and returns it as a block
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 263 def find_key(key) # Let's strip '\' from the beginning, except for the case of # only asking for the root node key = key[1..-1] if key[0] == '\\' && key.size > 1 parent_key = @root_key if key.size > 0 && key[0] != '\\' key.split('\\').each do |sub_key| res = find_sub_key(parent_key, sub_key) return nil unless res parent_key = res end end parent_key end |
#find_root_key ⇒ RegHbinBlock
Returns the ROOT key as a block
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 221 def find_root_key reg_hbin = nil # Split the data in 4096-bytes blocks @hive_data.unpack('a4096' * (@hive_data.size / 4096)).each do |data| next unless data[0,4] == 'hbin' reg_hbin = RegHbin.read(data) root_key = reg_hbin.reg_hbin_blocks.find do |block| block.data.respond_to?(:magic) && block.data.magic == NK_MAGIC && block.data.nk_type == ROOT_KEY end return root_key if root_key rescue IOError raise StandardError, 'Cannot parse the RegHbin structure' end raise StandardError, 'Cannot find the RootKey' unless reg_hbin end |
#find_sub_key(parent_key, sub_key) ⇒ RegHbinBlock?
Search for a sub key from a given base key
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 285 def find_sub_key(parent_key, sub_key) unless parent_key&.data&.magic == NK_MAGIC raise ArgumentError, "find_sub_key: parent key must be a NK record" end block = get_block(parent_key.data.offset_sub_key_lf) blocks = [] if block.data.magic == RI_MAGIC # ri points to lf/lh records, so we consolidate them in the main blocks array block.data.hash_records.each do |hash_record| blocks << get_block(hash_record.offset_nk) end else blocks << block end # Let's search the hash records for the name blocks.each do |block| block.data.hash_records.each do |hash_record| res = get_offset(block.data.magic, hash_record, sub_key) if res nk = get_block(res) return nk if nk.data.key_name == sub_key end end end nil end |
#get_block(offset) ⇒ RegHbinBlock
Returns a registry block given its offset
318 319 320 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 318 def get_block(offset) RegHbinBlock.read(@hive_data[4096+offset..-1]) end |
#get_data(offset, count) ⇒ String
Returns the data at a given offset from the end of the header in the raw hive binary.
404 405 406 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 404 def get_data(offset, count) @hive_data[4096+offset, count][4..-1] end |
#get_lh_hash(key) ⇒ Integer
Returns the hash of a LH subkey from www.sentinelchicken.com/data/TheWindowsNTRegistryFileFormat.pdf (Appendix C)
353 354 355 356 357 358 359 360 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 353 def get_lh_hash(key) res = 0 key.upcase.bytes do |byte| res *= 37 res += byte.ord end return res % 0x100000000 end |
#get_offset(magic, hash_rec, key) ⇒ Integer
Returns the offset of a given subkey in a hash record
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 328 def get_offset(magic, hash_rec, key) case magic when LF_MAGIC if hash_rec.key_name.gsub(/(^\x00*)|(\x00*$)/, '') == key[0,4] return hash_rec.offset_nk end when LH_MAGIC if hash_rec.key_name.unpack('L<').first == get_lh_hash(key) return hash_rec.offset_nk end when RI_MAGIC # Special case here, don't know exactly why, an RI pointing to a NK offset = hash_rec.offset_nk nk = get_block(offset) return offset if nk.key_name == key else raise ArgumentError, "Unknown magic: #{magic}" end end |
#get_value(reg_key, reg_value = nil) ⇒ Array
Returns the type and the data of a given key/value pair
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 243 def get_value(reg_key, reg_value = nil) reg_key = find_key(reg_key) return nil unless reg_key if reg_key.data.num_values > 0 value_list = get_value_blocks(reg_key.data.offset_value_list, reg_key.data.num_values + 1) value_list.each do |value| if value.data.name == reg_value.to_s || reg_value.nil? && value.data.flag <= 0 return value.data.value_type.to_i, get_value_data(value.data) end end end nil end |
#get_value_blocks(offset, count) ⇒ Array
Returns a list of ‘count“value blocks from the offsets located at `offset`
367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 367 def get_value_blocks(offset, count) value_list = [] res = [] count.times do |i| value_list << @hive_data[4096+offset+i*4, 4].unpack('l<').first end value_list.each do |value_offset| if value_offset > 0 block = get_block(value_offset) res << block end end return res end |
#get_value_data(record) ⇒ String
Returns the data of a VK record value
387 388 389 390 391 392 393 394 395 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 387 def get_value_data(record) unless record&.magic == VK_MAGIC raise ArgumentError, "get_value_data: record must be a VK record" end return '' if record.data_len == 0 # if DataLen < 5 the value itself is stored in the Offset field return record.offset_data.to_binary_s if record.data_len < 0 return self.get_data(record.offset_data, record.data_len + 4) end |