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, root: nil) ⇒ RegistryParser
constructor
A new instance of RegistryParser.
Constructor Details
#initialize(hive_data, name: nil, root: nil) ⇒ RegistryParser
Returns a new instance of RegistryParser.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 203 def initialize(hive_data, name: nil, root: nil) @hive_data = hive_data.b @regf = RegRegf.read(@hive_data) @root_key_block = find_root_key @root = root @root << '\\' unless root.end_with?('\\') case name when :sam require_relative 'sam' extend Sam when :security require_relative 'security' extend Security else wlog("[Msf::Util::WindowsRegistry::RegistryParser] Unknown :name argument: #{name}") unless name.blank? end end |
Instance Method Details
#enum_key(key) ⇒ Array
Enumerate the subkey names under ‘key`
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 418 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`
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 448 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| # TODO: use #to_s to make sure value.data.name is a String 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
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 268 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_block 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
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 226 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_block = 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_block if root_key_block 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
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 290 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
323 324 325 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 323 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.
409 410 411 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 409 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)
358 359 360 361 362 363 364 365 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 358 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
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 333 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
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 248 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`
372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 372 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
392 393 394 395 396 397 398 399 400 |
# File 'lib/msf/util/windows_registry/registry_parser.rb', line 392 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 |