manageiq-smartstate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +4 -0
- data/.rspec_ci +4 -0
- data/.travis.yml +15 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +202 -0
- data/README.md +45 -0
- data/Rakefile +23 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/MiqContainerGroup/MiqContainerGroup.rb +31 -0
- data/lib/MiqVm/MiqLocalVm.rb +50 -0
- data/lib/MiqVm/MiqRhevmVm.rb +179 -0
- data/lib/MiqVm/MiqVm.rb +355 -0
- data/lib/MiqVm/miq_azure_vm.rb +96 -0
- data/lib/MiqVm/miq_scvmm_vm.rb +38 -0
- data/lib/MiqVm/test/camcorder_fleece_test.rb +60 -0
- data/lib/MiqVm/test/localVm.rb +45 -0
- data/lib/MiqVm/test/partitionAlignmentCheck.rb +76 -0
- data/lib/MiqVm/test/remoteVm.rb +65 -0
- data/lib/MiqVm/test/rhevmNfsTest.rb +62 -0
- data/lib/MiqVm/test/rhevmNfsTest2.rb +66 -0
- data/lib/MiqVm/test/rhevmTest.rb +70 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackCommon.rb +107 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackImage.rb +67 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb +182 -0
- data/lib/Scvmm/miq_hyperv_disk.rb +273 -0
- data/lib/Scvmm/miq_scvmm_parse_powershell.rb +75 -0
- data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +135 -0
- data/lib/Scvmm/test/miq_hyperv_disk_test.rb +33 -0
- data/lib/Scvmm/test/miq_scvmm_vm_ssa_info_test.rb +41 -0
- data/lib/VmLocalDiskAccess/test/localCfg.rb +97 -0
- data/lib/VolumeManager/LVM/logical_volume.rb +75 -0
- data/lib/VolumeManager/LVM/lv_segment.rb +43 -0
- data/lib/VolumeManager/LVM/lvm2disk.rb +158 -0
- data/lib/VolumeManager/LVM/parser.rb +138 -0
- data/lib/VolumeManager/LVM/physical_volume.rb +19 -0
- data/lib/VolumeManager/LVM/scanner.rb +156 -0
- data/lib/VolumeManager/LVM/thin/btree.rb +83 -0
- data/lib/VolumeManager/LVM/thin/constants.rb +86 -0
- data/lib/VolumeManager/LVM/thin/data_map.rb +44 -0
- data/lib/VolumeManager/LVM/thin/mapping_tree.rb +19 -0
- data/lib/VolumeManager/LVM/thin/space_maps.rb +58 -0
- data/lib/VolumeManager/LVM/thin/superblock.rb +136 -0
- data/lib/VolumeManager/LVM/thin.rb +6 -0
- data/lib/VolumeManager/LVM/volume_group.rb +97 -0
- data/lib/VolumeManager/LVM.rb +8 -0
- data/lib/VolumeManager/MiqLdm.rb +546 -0
- data/lib/VolumeManager/MiqLvm.rb +17 -0
- data/lib/VolumeManager/MiqNativeVolumeManager.rb +150 -0
- data/lib/VolumeManager/MiqVolumeManager.rb +277 -0
- data/lib/VolumeManager/VolMgrPlatformSupport.rb +18 -0
- data/lib/VolumeManager/VolMgrPlatformSupportLinux.rb +77 -0
- data/lib/VolumeManager/VolMgrPlatformSupportWin.rb +17 -0
- data/lib/VolumeManager/test/blockDevTest.rb +40 -0
- data/lib/VolumeManager/test/ldm.rb +97 -0
- data/lib/blackbox/VmBlackBox.rb +103 -0
- data/lib/blackbox/xmlStorage.rb +180 -0
- data/lib/db/MiqBdb/MiqBdb.rb +309 -0
- data/lib/db/MiqBdb/MiqBdbBtree.rb +219 -0
- data/lib/db/MiqBdb/MiqBdbHash.rb +199 -0
- data/lib/db/MiqBdb/MiqBdbPage.rb +159 -0
- data/lib/db/MiqBdb/MiqBdbUtil.rb +18 -0
- data/lib/db/MiqSqlite/MiqSqlite3.rb +330 -0
- data/lib/db/MiqSqlite/MiqSqlite3Cell.rb +167 -0
- data/lib/db/MiqSqlite/MiqSqlite3Page.rb +151 -0
- data/lib/db/MiqSqlite/MiqSqlite3Table.rb +124 -0
- data/lib/db/MiqSqlite/MiqSqlite3Util.rb +32 -0
- data/lib/disk/DiskProbe.rb +68 -0
- data/lib/disk/MiqDisk.rb +317 -0
- data/lib/disk/camcorder_test.rb +90 -0
- data/lib/disk/dos_mbr.img +0 -0
- data/lib/disk/modules/AzureBlobDisk.rb +101 -0
- data/lib/disk/modules/LocalDevMod.rb +47 -0
- data/lib/disk/modules/LocalDevProbe.rb +6 -0
- data/lib/disk/modules/MSCommon.rb +352 -0
- data/lib/disk/modules/MSVSDiffDisk.rb +91 -0
- data/lib/disk/modules/MSVSDiskProbe.rb +61 -0
- data/lib/disk/modules/MSVSDynamicDisk.rb +42 -0
- data/lib/disk/modules/MSVSFixedDisk.rb +45 -0
- data/lib/disk/modules/MiqLargeFile.rb +63 -0
- data/lib/disk/modules/MiqLargeFileWin32.rb +107 -0
- data/lib/disk/modules/QcowDisk.rb +692 -0
- data/lib/disk/modules/QcowDiskProbe.rb +34 -0
- data/lib/disk/modules/RawBlockIO.rb +116 -0
- data/lib/disk/modules/RawDisk.rb +45 -0
- data/lib/disk/modules/RawDiskProbe.rb +7 -0
- data/lib/disk/modules/RhevmDescriptor.rb +167 -0
- data/lib/disk/modules/RhevmDiskProbe.rb +52 -0
- data/lib/disk/modules/VMWareCowdDisk.rb +207 -0
- data/lib/disk/modules/VMWareDescriptor.rb +214 -0
- data/lib/disk/modules/VMWareDiskProbe.rb +74 -0
- data/lib/disk/modules/VMWareSparseDisk.rb +189 -0
- data/lib/disk/modules/VhdxDisk.rb +625 -0
- data/lib/disk/modules/VhdxDiskProbe.rb +46 -0
- data/lib/disk/modules/VixDiskMod.rb +54 -0
- data/lib/disk/modules/VixDiskProbe.rb +6 -0
- data/lib/disk/modules/miq_disk_cache.rb +135 -0
- data/lib/disk/modules/miq_dummy_disk.rb +41 -0
- data/lib/disk/modules/vhdx_bat_entry.rb +10 -0
- data/lib/disk/test.rb +66 -0
- data/lib/fs/MetakitFS/MetakitFS.rb +530 -0
- data/lib/fs/MetakitFS/test/Makefile +14 -0
- data/lib/fs/MetakitFS/test/MkCollectFiles.rb +165 -0
- data/lib/fs/MetakitFS/test/MkSelectFiles.rb +30 -0
- data/lib/fs/MetakitFS/test/collect_files.yaml +70 -0
- data/lib/fs/MetakitFS/test/init.rb +3 -0
- data/lib/fs/MetakitFS/test/mk2vmdk.rb +64 -0
- data/lib/fs/MetakitFS/test/mk4test.c +92 -0
- data/lib/fs/MetakitFS/test/mkFsTest.rb +113 -0
- data/lib/fs/MetakitFS/test/proto.rb +97 -0
- data/lib/fs/MiqFS/FsProbe.rb +39 -0
- data/lib/fs/MiqFS/MiqFS.rb +515 -0
- data/lib/fs/MiqFS/modules/AUFSProbe.rb +26 -0
- data/lib/fs/MiqFS/modules/Ext3.rb +305 -0
- data/lib/fs/MiqFS/modules/Ext3Probe.rb +25 -0
- data/lib/fs/MiqFS/modules/Ext4.rb +304 -0
- data/lib/fs/MiqFS/modules/Ext4Probe.rb +25 -0
- data/lib/fs/MiqFS/modules/Fat32.rb +318 -0
- data/lib/fs/MiqFS/modules/Fat32Probe.rb +30 -0
- data/lib/fs/MiqFS/modules/HFSProbe.rb +18 -0
- data/lib/fs/MiqFS/modules/Iso9660.rb +293 -0
- data/lib/fs/MiqFS/modules/Iso9660Probe.rb +18 -0
- data/lib/fs/MiqFS/modules/LocalFS.rb +105 -0
- data/lib/fs/MiqFS/modules/NTFS.rb +287 -0
- data/lib/fs/MiqFS/modules/NTFSProbe.rb +21 -0
- data/lib/fs/MiqFS/modules/NativeFS.rb +155 -0
- data/lib/fs/MiqFS/modules/ReFSProbe.rb +17 -0
- data/lib/fs/MiqFS/modules/RealFS.rb +79 -0
- data/lib/fs/MiqFS/modules/RealFSProbe.rb +6 -0
- data/lib/fs/MiqFS/modules/Reiser4Probe.rb +18 -0
- data/lib/fs/MiqFS/modules/ReiserFS.rb +315 -0
- data/lib/fs/MiqFS/modules/ReiserFSProbe.rb +42 -0
- data/lib/fs/MiqFS/modules/UnionFSProbe.rb +18 -0
- data/lib/fs/MiqFS/modules/WebDAV.rb +127 -0
- data/lib/fs/MiqFS/modules/WebDAVFile.rb +68 -0
- data/lib/fs/MiqFS/modules/XFS.rb +300 -0
- data/lib/fs/MiqFS/modules/XFSProbe.rb +26 -0
- data/lib/fs/MiqFS/modules/ZFSProbe.rb +18 -0
- data/lib/fs/MiqFS/test.rb +59 -0
- data/lib/fs/MiqFsUtil.rb +383 -0
- data/lib/fs/MiqMountManager.rb +209 -0
- data/lib/fs/MiqNativeMountManager.rb +101 -0
- data/lib/fs/MountManagerProbe.rb +29 -0
- data/lib/fs/ReiserFS/block.rb +209 -0
- data/lib/fs/ReiserFS/directory.rb +136 -0
- data/lib/fs/ReiserFS/directory_entry.rb +140 -0
- data/lib/fs/ReiserFS/file_data.rb +111 -0
- data/lib/fs/ReiserFS/superblock.rb +140 -0
- data/lib/fs/ReiserFS/utils.rb +95 -0
- data/lib/fs/VimDatastoreFS/VimDatastoreFS.rb +192 -0
- data/lib/fs/ext3/alloc_bitmap.rb +38 -0
- data/lib/fs/ext3/block_pointers_path.rb +130 -0
- data/lib/fs/ext3/directory.rb +51 -0
- data/lib/fs/ext3/directory_entry.rb +67 -0
- data/lib/fs/ext3/ex_attrib_header.rb +14 -0
- data/lib/fs/ext3/ex_attrib_name.rb +23 -0
- data/lib/fs/ext3/file_data.rb +130 -0
- data/lib/fs/ext3/group_descriptor_entry.rb +65 -0
- data/lib/fs/ext3/group_descriptor_table.rb +54 -0
- data/lib/fs/ext3/hash_tree_entry.rb +18 -0
- data/lib/fs/ext3/hash_tree_header.rb +15 -0
- data/lib/fs/ext3/inode.rb +228 -0
- data/lib/fs/ext3/posix_acl_entry.rb +29 -0
- data/lib/fs/ext3/posix_acl_header.rb +11 -0
- data/lib/fs/ext3/superblock.rb +406 -0
- data/lib/fs/ext3/test/tc_Ext3BlockPointersPath.rb +74 -0
- data/lib/fs/ext4/alloc_bitmap.rb +38 -0
- data/lib/fs/ext4/directory.rb +87 -0
- data/lib/fs/ext4/directory_entry.rb +77 -0
- data/lib/fs/ext4/ex_attrib_header.rb +14 -0
- data/lib/fs/ext4/ex_attrib_name.rb +23 -0
- data/lib/fs/ext4/extent.rb +35 -0
- data/lib/fs/ext4/extent_header.rb +40 -0
- data/lib/fs/ext4/extent_index.rb +33 -0
- data/lib/fs/ext4/group_descriptor_entry.rb +69 -0
- data/lib/fs/ext4/group_descriptor_table.rb +54 -0
- data/lib/fs/ext4/hash_tree_entry.rb +58 -0
- data/lib/fs/ext4/hash_tree_header.rb +35 -0
- data/lib/fs/ext4/inode.rb +465 -0
- data/lib/fs/ext4/posix_acl_entry.rb +29 -0
- data/lib/fs/ext4/posix_acl_header.rb +11 -0
- data/lib/fs/ext4/superblock.rb +412 -0
- data/lib/fs/fat32/boot_sect.rb +379 -0
- data/lib/fs/fat32/directory.rb +222 -0
- data/lib/fs/fat32/directory_entry.rb +540 -0
- data/lib/fs/fat32/file_data.rb +128 -0
- data/lib/fs/iso9660/boot_sector.rb +170 -0
- data/lib/fs/iso9660/directory.rb +90 -0
- data/lib/fs/iso9660/directory_entry.rb +147 -0
- data/lib/fs/iso9660/file_data.rb +78 -0
- data/lib/fs/iso9660/rock_ridge.rb +329 -0
- data/lib/fs/iso9660/util.rb +57 -0
- data/lib/fs/modules/LinuxMount.rb +300 -0
- data/lib/fs/modules/LinuxMountProbe.rb +29 -0
- data/lib/fs/modules/WinMount.rb +97 -0
- data/lib/fs/modules/WinMountProbe.rb +24 -0
- data/lib/fs/ntfs/attrib_attribute_list.rb +131 -0
- data/lib/fs/ntfs/attrib_bitmap.rb +26 -0
- data/lib/fs/ntfs/attrib_data.rb +74 -0
- data/lib/fs/ntfs/attrib_file_name.rb +110 -0
- data/lib/fs/ntfs/attrib_header.rb +194 -0
- data/lib/fs/ntfs/attrib_index_allocation.rb +19 -0
- data/lib/fs/ntfs/attrib_index_root.rb +247 -0
- data/lib/fs/ntfs/attrib_object_id.rb +40 -0
- data/lib/fs/ntfs/attrib_standard_information.rb +107 -0
- data/lib/fs/ntfs/attrib_type.rb +49 -0
- data/lib/fs/ntfs/attrib_volume_information.rb +53 -0
- data/lib/fs/ntfs/attrib_volume_name.rb +31 -0
- data/lib/fs/ntfs/boot_sect.rb +253 -0
- data/lib/fs/ntfs/data_run.rb +358 -0
- data/lib/fs/ntfs/directory_index_node.rb +114 -0
- data/lib/fs/ntfs/index_node_header.rb +69 -0
- data/lib/fs/ntfs/index_record_header.rb +85 -0
- data/lib/fs/ntfs/mft_entry.rb +288 -0
- data/lib/fs/ntfs/utils.rb +43 -0
- data/lib/fs/test/camcorder_fs_test.rb +108 -0
- data/lib/fs/test/collect_files_direct.yaml +22 -0
- data/lib/fs/test/collect_files_in.yaml +24 -0
- data/lib/fs/test/collect_files_in_nc.yaml +22 -0
- data/lib/fs/test/collect_files_out.yaml +6 -0
- data/lib/fs/test/collect_files_rm.yaml +6 -0
- data/lib/fs/test/copyTest.rb +126 -0
- data/lib/fs/test/fsTest.rb +87 -0
- data/lib/fs/test/updateTest.rb +184 -0
- data/lib/fs/xfs/allocation_group.rb +160 -0
- data/lib/fs/xfs/bmap_btree_block.rb +125 -0
- data/lib/fs/xfs/bmap_btree_record.rb +80 -0
- data/lib/fs/xfs/bmap_btree_root_node.rb +72 -0
- data/lib/fs/xfs/directory.rb +133 -0
- data/lib/fs/xfs/directory2_data_header.rb +27 -0
- data/lib/fs/xfs/directory3_data_header.rb +34 -0
- data/lib/fs/xfs/directory_block_tail.rb +22 -0
- data/lib/fs/xfs/directory_data_header.rb +46 -0
- data/lib/fs/xfs/directory_entry.rb +106 -0
- data/lib/fs/xfs/inode.rb +532 -0
- data/lib/fs/xfs/inode_map.rb +100 -0
- data/lib/fs/xfs/short_form_directory_entry.rb +91 -0
- data/lib/fs/xfs/short_form_header.rb +44 -0
- data/lib/fs/xfs/superblock.rb +556 -0
- data/lib/lib/tasks/azure.rake +52 -0
- data/lib/manageiq/smartstate/version.rb +5 -0
- data/lib/manageiq/smartstate.rb +7 -0
- data/lib/manageiq-smartstate.rb +1 -0
- data/lib/metadata/MIQExtract/MIQExtract.rb +297 -0
- data/lib/metadata/MIQExtract/test/extractTest.rb +41 -0
- data/lib/metadata/MIQExtract/test/full_extract_test.rb +68 -0
- data/lib/metadata/ScanProfile/HostScanItem.rb +4 -0
- data/lib/metadata/ScanProfile/HostScanProfile.rb +4 -0
- data/lib/metadata/ScanProfile/HostScanProfiles.rb +41 -0
- data/lib/metadata/ScanProfile/ScanItemBase.rb +63 -0
- data/lib/metadata/ScanProfile/ScanProfileBase.rb +51 -0
- data/lib/metadata/ScanProfile/ScanProfilesBase.rb +60 -0
- data/lib/metadata/ScanProfile/VmScanItem.rb +4 -0
- data/lib/metadata/ScanProfile/VmScanProfile.rb +4 -0
- data/lib/metadata/ScanProfile/VmScanProfiles.rb +38 -0
- data/lib/metadata/ScanProfile/modules/HostScanItemFile.rb +51 -0
- data/lib/metadata/ScanProfile/modules/HostScanItemNteventlog.rb +84 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemFile.rb +39 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemNteventlog.rb +34 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemRegistry.rb +64 -0
- data/lib/metadata/VMMount/VMMount.rb +81 -0
- data/lib/metadata/VMMount/VMPlatformMount.rb +18 -0
- data/lib/metadata/VMMount/VMPlatformMountLinux.rb +75 -0
- data/lib/metadata/VMMount/VMPlatformMountWin.rb +13 -0
- data/lib/metadata/VmConfig/GetNativeCfg.rb +45 -0
- data/lib/metadata/VmConfig/VmConfig.rb +947 -0
- data/lib/metadata/VmConfig/cfgConfig.rb +45 -0
- data/lib/metadata/VmConfig/ovfConfig.rb +99 -0
- data/lib/metadata/VmConfig/test/GetVMwareCfgTest.rb +40 -0
- data/lib/metadata/VmConfig/vmcConfig.rb +116 -0
- data/lib/metadata/VmConfig/vmtxConfig.rb +4 -0
- data/lib/metadata/VmConfig/vmxConfig.rb +162 -0
- data/lib/metadata/VmConfig/xmlConfig.rb +79 -0
- data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +41 -0
- data/lib/metadata/linux/InitProcHash.rb +632 -0
- data/lib/metadata/linux/LinuxInitProcs.rb +142 -0
- data/lib/metadata/linux/LinuxOSInfo.rb +237 -0
- data/lib/metadata/linux/LinuxPackages.rb +209 -0
- data/lib/metadata/linux/LinuxSystemd.rb +130 -0
- data/lib/metadata/linux/LinuxUsers.rb +289 -0
- data/lib/metadata/linux/LinuxUtils.rb +197 -0
- data/lib/metadata/linux/MiqConaryPackages.rb +41 -0
- data/lib/metadata/linux/MiqRpmPackages.rb +160 -0
- data/lib/metadata/linux/test/Name +0 -0
- data/lib/metadata/linux/test/Packages +0 -0
- data/lib/metadata/linux/test/rpoTest.rb +5 -0
- data/lib/metadata/linux/test/tc_LinuxUtils.rb +4157 -0
- data/lib/metadata/util/event_log_filter.rb +61 -0
- data/lib/metadata/util/md5deep.rb +280 -0
- data/lib/metadata/util/win32/Win32Accounts.rb +764 -0
- data/lib/metadata/util/win32/Win32EventLog.rb +743 -0
- data/lib/metadata/util/win32/Win32Services.rb +86 -0
- data/lib/metadata/util/win32/Win32Software.rb +326 -0
- data/lib/metadata/util/win32/Win32System.rb +333 -0
- data/lib/metadata/util/win32/boot_info_win.rb +59 -0
- data/lib/metadata/util/win32/fleece_hives.rb +220 -0
- data/lib/metadata/util/win32/ms-registry.rb +650 -0
- data/lib/metadata/util/win32/peheader.rb +868 -0
- data/lib/metadata/util/win32/remote-registry.rb +142 -0
- data/lib/metadata/util/win32/system_path_win.rb +103 -0
- data/lib/metadata/util/win32/versioninfo.rb +17 -0
- data/manageiq-smartstate.gemspec +35 -0
- metadata +486 -0
@@ -0,0 +1,650 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'binary_struct'
|
4
|
+
require 'util/miq-unicode'
|
5
|
+
require 'enumerator'
|
6
|
+
require 'util/miq-xml'
|
7
|
+
require 'util/xml/xml_hash'
|
8
|
+
|
9
|
+
# Constants
|
10
|
+
DEBUG_PRINT = false
|
11
|
+
DEBUG_UNHANDLED_DATA = false
|
12
|
+
DEBUG_LOG_PERFORMANCE = false
|
13
|
+
DEBUG_FILE_READS = false
|
14
|
+
|
15
|
+
class MSRegHive
|
16
|
+
attr_reader :fileLoadTime, :fileParseTime, :digitalProductKeys, :xmlNode
|
17
|
+
|
18
|
+
# Size of the HBIN data (as well as initiale REGF) segments
|
19
|
+
HBIN_SIZE = 0x1000
|
20
|
+
# All data offsets in the registry DO NOT include the first block (REGF) which
|
21
|
+
# is 0x1000 (same as HBIN) and the 4 byte 'hbin' signature
|
22
|
+
REG_DATA_OFFSET = HBIN_SIZE + 0x4
|
23
|
+
|
24
|
+
def initialize(path, hiveName, xmlNode, fs = "M:/", filter = nil)
|
25
|
+
@RegPath = path.gsub(/^"/, "").gsub(/"$/, "")
|
26
|
+
@hiveName = hiveName
|
27
|
+
@xmlNode = xmlNode
|
28
|
+
@fs = fs if fs.kind_of?(MiqFS)
|
29
|
+
@expandEnv = {'%SystemDrive%' => 'C:', "%SystemRoot%" => "\\Windows", "%ProgramFiles%" => "\\Program Files"}
|
30
|
+
@fileLoadTime, @fileParseTime = nil, nil
|
31
|
+
@ccsIdx = 1 # CurrentControlSet default index
|
32
|
+
@ccsName = "controlset%03d" % @ccsIdx
|
33
|
+
@stats = {:cache_hits => 0, :file_reads => 0, :bytes_read => 0}
|
34
|
+
@hbin = {}
|
35
|
+
|
36
|
+
# Load up filters
|
37
|
+
@filter_value = {}
|
38
|
+
@filter = init_filters(filter)
|
39
|
+
|
40
|
+
# Collect DigitalProductKeys as we find them for processing later
|
41
|
+
@digitalProductKeys = []
|
42
|
+
end
|
43
|
+
|
44
|
+
def init_filters(filter)
|
45
|
+
if filter.nil?
|
46
|
+
@filter_value = nil if @filter_value.empty?
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
filters = filter.collect { |f| create_filter_hash(f) }
|
50
|
+
filters.compact!
|
51
|
+
filters = nil if filters.empty?
|
52
|
+
@filter_value = nil if @filter_value.empty?
|
53
|
+
filters
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_filter_hash(filter)
|
57
|
+
if filter.kind_of?(Hash)
|
58
|
+
nh = filter
|
59
|
+
nh[:key] = nh[:key].downcase.split("/")
|
60
|
+
nh[:value].each { |v| @filter_value[v.downcase] = true } if nh[:value].kind_of?(Array)
|
61
|
+
else
|
62
|
+
nh = {:key => filter.downcase.split("/")}
|
63
|
+
end
|
64
|
+
nh[:key_path] = nh[:key].join('\\')
|
65
|
+
nh[:depth] = nh[:depth].to_i
|
66
|
+
nh
|
67
|
+
end
|
68
|
+
|
69
|
+
def close
|
70
|
+
# Force memory cleanup
|
71
|
+
@hbin = nil
|
72
|
+
GC.start
|
73
|
+
end
|
74
|
+
|
75
|
+
def parseHives
|
76
|
+
startTime = Time.now
|
77
|
+
|
78
|
+
# Reads in the registry file and does some basic validation
|
79
|
+
validateRegFile(File.join(@RegPath, @hiveName))
|
80
|
+
|
81
|
+
@fileLoadTime = Time.now - startTime
|
82
|
+
$log.info "Registry Load/Validate time = #{@fileLoadTime} sec" if DEBUG_LOG_PERFORMANCE
|
83
|
+
|
84
|
+
startTime = Time.now
|
85
|
+
pre_process
|
86
|
+
|
87
|
+
# Start parsing the registry based on the data offset stored in the first record
|
88
|
+
if @hiveName == 'ntuser.dat'
|
89
|
+
parseRecord(@hiveHash[:data_offset], @xmlNode, nil, 0)
|
90
|
+
else
|
91
|
+
parseRecord(@hiveHash[:data_offset], @xmlNode, @hiveName, 0)
|
92
|
+
end
|
93
|
+
|
94
|
+
post_process
|
95
|
+
|
96
|
+
@fileParseTime = Time.now - startTime
|
97
|
+
parseStats = "Registry Parsing time = #{@fileParseTime} sec. registry segments loaded:[#{@hbin.length}]" # if DEBUG_LOG_PERFORMANCE
|
98
|
+
parseStats += " Stats:[#{@stats.inspect}]" if DEBUG_FILE_READS
|
99
|
+
$log.info parseStats
|
100
|
+
end
|
101
|
+
|
102
|
+
def pre_process
|
103
|
+
# Determine what System/ControlSet00? to use when CurrentControlSet is
|
104
|
+
# referenced and update the filter list.
|
105
|
+
determine_current_control_set if @hiveName == "system"
|
106
|
+
|
107
|
+
# Load environment variables to be used to "expand string" (REG_EXPAND_SZ) resolution.
|
108
|
+
# load_environment_variables
|
109
|
+
end
|
110
|
+
|
111
|
+
def post_process
|
112
|
+
if @hiveName == "system"
|
113
|
+
ccsNode = MIQRexml.findRegElement("HKEY_LOCAL_MACHINE\\SYSTEM\\#{@ccsName}", @xmlNode.root)
|
114
|
+
if ccsNode
|
115
|
+
$log.debug "Changing [#{@ccsName}] to CurrentControlSet"
|
116
|
+
ccsNode.add_attribute(:keyname, 'CurrentControlSet')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def load_environment_variables
|
122
|
+
$log.debug "Determining ControlControlSet index"
|
123
|
+
save_filters = @filter
|
124
|
+
@filter = [create_filter_hash("#{@ccsName}/Control/Session Manager/Environment".downcase.split("/"))]
|
125
|
+
# Start parsing the registry based on the data offset stored in the first record
|
126
|
+
ccsNode = MiqXml.newNode
|
127
|
+
parseRecord(@hiveHash[:data_offset], ccsNode, @hiveName, 0)
|
128
|
+
@filter = save_filters
|
129
|
+
|
130
|
+
# ccsNode.write(STDOUT,0)
|
131
|
+
# @expandEnv = {"%SystemRoot%"=>"\\Windows", "%ProgramFiles%"=>"\\Program Files"}
|
132
|
+
end
|
133
|
+
|
134
|
+
def determine_current_control_set
|
135
|
+
$log.debug "Determining ControlControlSet index"
|
136
|
+
save_filters = @filter
|
137
|
+
@filter = [create_filter_hash('select')]
|
138
|
+
# Start parsing the registry based on the data offset stored in the first record
|
139
|
+
# ccsNode = MiqXml.newNode(nil, REXML)
|
140
|
+
ccsNode = XmlHash::Document.new("ccs")
|
141
|
+
parseRecord(@hiveHash[:data_offset], ccsNode, @hiveName, 0)
|
142
|
+
# idx = ccsNode.find_first("//value[@name\"Current\"]")
|
143
|
+
@ccsIdx = 0
|
144
|
+
ccsNode.elements[1].each_element_with_attribute(:name, "Current") { |e| @ccsIdx = e.text }
|
145
|
+
@ccsIdx = 1 if @ccsIdx == 0
|
146
|
+
@ccsName = "controlset%03d" % @ccsIdx
|
147
|
+
@filter = save_filters
|
148
|
+
# Search through the filter list and change any "CurrentControlSet" values to the proper idx
|
149
|
+
if @filter
|
150
|
+
@filter.each do |a1|
|
151
|
+
if a1[:key][0] == "currentcontrolset"
|
152
|
+
a1[:key][0] = @ccsName
|
153
|
+
a1[:key_path] = a1[:key].join('\\')
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
$log.debug "ControlControlSet index will be set to [#{@ccsIdx}]"
|
158
|
+
end
|
159
|
+
|
160
|
+
def parseRecord(offset, xmlNode, fqName, level)
|
161
|
+
type = read_buffer(offset, 1).downcase
|
162
|
+
$log.debug sprintf("TYPE = [%s] at offset [0x%08x]", type, offset + REG_DATA_OFFSET) if DEBUG_PRINT
|
163
|
+
begin
|
164
|
+
send("parseRecord#{type}", offset, xmlNode, fqName, level)
|
165
|
+
rescue => err
|
166
|
+
$log.warn sprintf("Unhandled type encountered [%s] at file offset [0x%08X]. Msg:[#{err}]", type, offset + REG_DATA_OFFSET) if DEBUG_UNHANDLED_DATA
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def checkFilters(subKey, fqName, level)
|
171
|
+
return true if @filter.nil? # If there are no filters get out
|
172
|
+
match = false
|
173
|
+
# allNil = true
|
174
|
+
alevel = level - 1
|
175
|
+
|
176
|
+
@filter.each do |f|
|
177
|
+
# $log.debug "Filer [#{f[level]}]"
|
178
|
+
# allNil = false unless f[level].nil?
|
179
|
+
if f[:key][alevel].nil? && fqName.downcase.index(f[:key_path])
|
180
|
+
match = true if f[:depth].to_i == 0
|
181
|
+
|
182
|
+
filter_depth = f[:depth] - 1 + f[:key].length
|
183
|
+
if filter_depth >= level
|
184
|
+
# $log.fatal "REG FILTER 1 fqName:[#{fqName.downcase}] - f[path]:[#{f[:key].join('\\')}] - depth:[#{filter_depth}] -- level:[#{level}]"
|
185
|
+
match = true
|
186
|
+
break
|
187
|
+
end
|
188
|
+
end
|
189
|
+
if match == false && !f[:key][alevel].nil? && f[:key][alevel] == subKey
|
190
|
+
match = true
|
191
|
+
break
|
192
|
+
end
|
193
|
+
end
|
194
|
+
# $log.debug "match [#{match}] allNil [#{allNil}]"
|
195
|
+
# return true if allNil == true # There were no filters specified at this depth
|
196
|
+
match
|
197
|
+
end
|
198
|
+
|
199
|
+
def parseRecordnk(offset, xmlNode, fqName, level)
|
200
|
+
nkHash = REGISTRY_STRUCT_NK.decode(read_buffer(offset, SIZEOF_REGISTRY_STRUCT_NK))
|
201
|
+
# Convert the type from hex to text
|
202
|
+
nkHash[:type_display] = typeToString(nkHash[:type])
|
203
|
+
# Get the keyname which is just beyond the structure
|
204
|
+
nkHash[:keyname] = read_buffer(offset + SIZEOF_REGISTRY_STRUCT_NK, nkHash[:name_length] - 1).chomp("\0")
|
205
|
+
|
206
|
+
DumpHash.SortPrint(nkHash, :NK)
|
207
|
+
|
208
|
+
# $log.debug "parseRecordNK [#{xmlNode}] [#{xmlNode.class}] [#{nkHash[:keyname]}] [#{nkHash[:type_display]}]"
|
209
|
+
if nkHash[:type_display] == :SUB
|
210
|
+
level += 1
|
211
|
+
if fqName.nil?
|
212
|
+
fqName = nkHash[:keyname].chomp
|
213
|
+
else
|
214
|
+
fqName += "\\#{nkHash[:keyname].chomp}"
|
215
|
+
end
|
216
|
+
# $log.debug "Fully Q Name: [#{level}] [#{nkHash['keyname'].chomp}] [#{fqName}]"
|
217
|
+
# Check sub-directory filters
|
218
|
+
# return unless checkFilters(nkHash['keyname'].chomp.downcase, level-1)
|
219
|
+
cf = checkFilters(nkHash[:keyname].chomp.downcase, fqName, level)
|
220
|
+
# $log.debug "Fully Q Name: [#{"%5s" % cf}] [#{fqName}] [#{level}]"
|
221
|
+
# $log.debug "Fully Q Name: [#{fqName}] [#{level}]"
|
222
|
+
return unless cf
|
223
|
+
# xmlSubNode = xmlNode
|
224
|
+
xmlSubNode = xmlNode.add_element(:key, :keyname => nkHash[:keyname].chomp, :fqname => fqName)
|
225
|
+
# on_start_element(:key, {:keyname=>nkHash[:keyname].chomp, :fqname=>fqName})
|
226
|
+
else
|
227
|
+
xmlSubNode = xmlNode
|
228
|
+
end
|
229
|
+
|
230
|
+
# Process all values
|
231
|
+
if nkHash[:num_values] > 0
|
232
|
+
vkOffset = nkHash[:values_offset]
|
233
|
+
nkHash[:num_values].times do
|
234
|
+
vkHash = REGISTRY_STRUCT_VK_OFFSET.decode(read_buffer(vkOffset, SIZEOF_REGISTRY_STRUCT_VK_OFFSET))
|
235
|
+
parseRecord(vkHash[:offset_vk], xmlSubNode, fqName, level)
|
236
|
+
vkOffset += SIZEOF_REGISTRY_STRUCT_VK_OFFSET
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Process all subkeys
|
241
|
+
if nkHash[:num_subkeys] > 0
|
242
|
+
parseRecord(nkHash[:subkeys_offset], xmlSubNode, fqName, level)
|
243
|
+
end
|
244
|
+
|
245
|
+
# on_end_element(:key)
|
246
|
+
end
|
247
|
+
|
248
|
+
def parseRecordri(offset, xmlNode, fqName, level)
|
249
|
+
# $log.debug "parseRecordRI at offset #{offset}"
|
250
|
+
riHash = REGISTRY_STRUCT_RI.decode(read_buffer(offset, SIZEOF_REGISTRY_STRUCT_RI))
|
251
|
+
|
252
|
+
DumpHash.SortPrint(riHash, :RI)
|
253
|
+
|
254
|
+
if riHash[:num_keys] > 0
|
255
|
+
key_offset = offset + SIZEOF_REGISTRY_STRUCT_RI
|
256
|
+
riHash[:num_keys].times do
|
257
|
+
hash = REGISTRY_STRUCT_RI_OFFSET.decode(read_buffer(key_offset, SIZEOF_REGISTRY_STRUCT_RI_OFFSET))
|
258
|
+
parseRecord hash[:offset_ri], xmlNode, fqName, level
|
259
|
+
key_offset += SIZEOF_REGISTRY_STRUCT_RI_OFFSET
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def parseRecordlf(offset, xmlNode, fqName, level)
|
265
|
+
# $log.debug "parseRecordLF at offset #{offset}"
|
266
|
+
lfHash = REGISTRY_STRUCT_LF.decode(read_buffer(offset, SIZEOF_REGISTRY_STRUCT_LF))
|
267
|
+
|
268
|
+
if lfHash[:num_keys] > 0
|
269
|
+
key_offset = offset + SIZEOF_REGISTRY_STRUCT_LF
|
270
|
+
lfHash[:num_keys].times do
|
271
|
+
hash = REGISTRY_STRUCT_LF_HASH.decode(read_buffer(key_offset, SIZEOF_REGISTRY_STRUCT_LF_HASH))
|
272
|
+
parseRecord hash[:offset_nk], xmlNode, fqName, level
|
273
|
+
key_offset += SIZEOF_REGISTRY_STRUCT_LF_HASH
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def parseRecordlh(offset, xmlNode, fqName, level)
|
279
|
+
# $log.debug "parseRecordLH at offset #{offset}"
|
280
|
+
lhHash = REGISTRY_STRUCT_LH.decode(read_buffer(offset, SIZEOF_REGISTRY_STRUCT_LH))
|
281
|
+
|
282
|
+
if lhHash[:num_keys] > 0
|
283
|
+
key_offset = offset + SIZEOF_REGISTRY_STRUCT_LH
|
284
|
+
lhHash[:num_keys].times do
|
285
|
+
hash = REGISTRY_STRUCT_LH_HASH.decode(read_buffer(key_offset, SIZEOF_REGISTRY_STRUCT_LH_HASH))
|
286
|
+
parseRecord hash[:offset_nk], xmlNode, fqName, level
|
287
|
+
key_offset += SIZEOF_REGISTRY_STRUCT_LH_HASH
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def parseRecordvk(offset, xmlNode, _fqName, _level)
|
293
|
+
# $log.debug "parseRecordVK at offset #{offset}"
|
294
|
+
vkHash = REGISTRY_STRUCT_VK.decode(read_buffer(offset, SIZEOF_REGISTRY_STRUCT_VK))
|
295
|
+
vkHash[:data_type_display] = KEY_TYPES[vkHash[:data_type]]
|
296
|
+
if vkHash[:name_length] == 0
|
297
|
+
vkHash[:data_name] = "(Default)"
|
298
|
+
else
|
299
|
+
vkHash[:data_name] = read_buffer(offset + SIZEOF_REGISTRY_STRUCT_VK, vkHash[:name_length] - 1)
|
300
|
+
end
|
301
|
+
|
302
|
+
# Check value filters here
|
303
|
+
return if @filter_value && !@filter_value.key?(vkHash[:data_name].downcase)
|
304
|
+
|
305
|
+
begin
|
306
|
+
case vkHash[:data_type_display]
|
307
|
+
when :REG_SZ, :REG_EXPAND_SZ then vkHash[:data] = getRegString(vkHash, vkHash[:data_type_display])
|
308
|
+
when :REG_DWORD then vkHash[:data] = vkHash[:data_offset]
|
309
|
+
when :REG_NONE then vkHash[:data] = "(zero-length binary value)"
|
310
|
+
when :REG_BINARY then vkHash[:data] = getRegBinary(vkHash)
|
311
|
+
when :REG_QWORD then vkHash[:data] = read_buffer(vkHash[:data_offset], 8).unpack("Q").join.to_i
|
312
|
+
when :REG_MULTI_SZ then vkHash[:data] = getRegMultiString(vkHash)
|
313
|
+
else
|
314
|
+
# Ignore types: REG_RESOURCE_REQUIREMENTS_LIST and REG_RESOURCE_LIS
|
315
|
+
if DEBUG_UNHANDLED_DATA
|
316
|
+
$log.warn "Unhandled vk record type of [#{vkHash[:data_type]}] [#{vkHash[:data_type_display]}]" unless vkHash[:data_type] == 8 || vkHash[:data_type] == 10 || vkHash[:data_type] >= 12
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
ensure
|
321
|
+
DumpHash.SortPrint(vkHash, :VK)
|
322
|
+
# xmlSubNode = xmlNode
|
323
|
+
xmlSubNode = xmlNode.add_element(:value, :type => vkHash[:data_type_display], :name => vkHash[:data_name])
|
324
|
+
xmlSubNode.text = vkHash[:data]
|
325
|
+
|
326
|
+
# This is a performance hack right now since searching the whole xml doc for DigitalProductIds takes so long.
|
327
|
+
@digitalProductKeys << xmlSubNode if vkHash[:data_name].downcase == "digitalproductid"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def getRegMultiString(vkHash)
|
332
|
+
# $log.debug sprintf("data offset: (0x%X) Length: [%d]", vkHash['data_offset']+REG_DATA_OFFSET, vkHash['data_length'])
|
333
|
+
if vkHash[:data_offset] < 0
|
334
|
+
# $log.warn "Invalid offset for multi-string data Key:[#{fqName}] Value:[#{vkHash[:data_name]}] Offset:[#{vkHash[:data_offset]}]"
|
335
|
+
return
|
336
|
+
end
|
337
|
+
vkHash[:data] = read_buffer(vkHash[:data_offset], vkHash[:data_length] - 1)
|
338
|
+
vkHash[:data].UnicodeToUtf8!.strip!
|
339
|
+
ensure
|
340
|
+
vkHash[:data].tr!("\0", "\n") unless vkHash[:data].nil?
|
341
|
+
end
|
342
|
+
|
343
|
+
def getRegString(vkHash, key_type)
|
344
|
+
# $log.debug sprintf("data offset: (0x%X) Length: [%d]", vkHash['data_offset']+REG_DATA_OFFSET, vkHash['data_length'])
|
345
|
+
if (vkHash[:data_length] & 0x80000000) == 0
|
346
|
+
vkHash[:data] = read_buffer(vkHash[:data_offset], vkHash[:data_length] - 1)
|
347
|
+
begin
|
348
|
+
vkHash[:data].UnicodeToUtf8!
|
349
|
+
rescue
|
350
|
+
# Since we are getting Unicode strings out of the registry they should be even numbers lengths
|
351
|
+
if vkHash[:data_length].remainder(2) == 1
|
352
|
+
vkHash[:data] = read_buffer(vkHash[:data_offset], vkHash[:data_length] - 2)
|
353
|
+
vkHash[:data].UnicodeToUtf8!
|
354
|
+
else
|
355
|
+
raise $!
|
356
|
+
end
|
357
|
+
end
|
358
|
+
else
|
359
|
+
vkHash[:data] = (vkHash[:data_offset] & 0xFF).chr
|
360
|
+
end
|
361
|
+
|
362
|
+
# Truncate string at the first null character
|
363
|
+
if i = vkHash[:data].index("\0")
|
364
|
+
vkHash[:data] = vkHash[:data][0...i]
|
365
|
+
end
|
366
|
+
|
367
|
+
# Resolve expand keys
|
368
|
+
@expandEnv.each_pair { |k, v| vkHash[:data].gsub!(k, v) } if key_type == :REG_EXPAND_SZ
|
369
|
+
|
370
|
+
vkHash[:data]
|
371
|
+
end
|
372
|
+
|
373
|
+
def getRegBinary(vkHash)
|
374
|
+
if (vkHash[:data_length] & 0x80000000) == 0
|
375
|
+
res = self.class.rawBinaryToRegBinary(read_buffer(vkHash[:data_offset], vkHash[:data_length] - 1))
|
376
|
+
else
|
377
|
+
res = vkHash[:data_offset].to_s(16).rjust(8, '0')
|
378
|
+
res = "#{res[6..7]},#{res[4..5]},#{res[2..3]},#{res[0..1]}"
|
379
|
+
end
|
380
|
+
|
381
|
+
res
|
382
|
+
end
|
383
|
+
|
384
|
+
def validateRegFile(fileName)
|
385
|
+
t0 = Time.now
|
386
|
+
# Do some basic file validation
|
387
|
+
|
388
|
+
fileObj = @fs ? @fs : File
|
389
|
+
raise "Registry file [#{fileName}] does not exist." if fileObj.send(@fs ? :fileExists? : :exist?, fileName) == false
|
390
|
+
regSize = fileObj.send(@fs ? :fileSize : :size, fileName)
|
391
|
+
raise "Registry file [#{fileName}] is empty." if regSize.zero?
|
392
|
+
@fileHnd = fileObj.send(@fs ? :fileOpen : :open, fileName, 'rb')
|
393
|
+
regf_buf = read_hbin(0)
|
394
|
+
|
395
|
+
raise "Registry file [#{fileName}] does not contain valid marker." if regf_buf[0, 4] != "regf"
|
396
|
+
$log.info "Reading #{fileName} with size (#{regSize})" if DEBUG_PRINT
|
397
|
+
|
398
|
+
# Read in Registry header
|
399
|
+
head_string = regf_buf[0, SIZEOF_REGISTRY_HEADER_REGF]
|
400
|
+
raise "Registry hive [#{fileName}] does not contain a valid header." unless head_string
|
401
|
+
@hiveHash = REGISTRY_HEADER_REGF.decode(head_string)
|
402
|
+
@hiveHash[:name].UnicodeToUtf8!.strip!
|
403
|
+
|
404
|
+
# Dump sorted hash results
|
405
|
+
DumpHash.SortPrint(@hiveHash, :REGF)
|
406
|
+
|
407
|
+
$log.info "Registry hive [#{File.basename(@hiveHash[:name])}] successfully opened for reading in [#{Time.now - t0}] seconds. Size:[#{regSize}] Last registry update: [#{MSRegHive.wtime2time(@hiveHash[:timestamp])}]"
|
408
|
+
end
|
409
|
+
|
410
|
+
def typeToString(type)
|
411
|
+
case
|
412
|
+
when type == 44 then :ROOT
|
413
|
+
when type == 32 then :SUB
|
414
|
+
when type == 4128 then :SUB
|
415
|
+
when type == 16 then :LINK
|
416
|
+
else :UNKNOWN
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def self.wtime2time(wtime)
|
421
|
+
Time.at((wtime - 116444736000000000) / 10000000).getutc
|
422
|
+
rescue RangeError
|
423
|
+
return nil
|
424
|
+
end
|
425
|
+
|
426
|
+
def self.isRegBinary(data)
|
427
|
+
data =~ /^[0-9a-fA-F]{2}(,[0-9a-fA-F]{2})*$/
|
428
|
+
end
|
429
|
+
|
430
|
+
def self.regBinaryToRawBinary(data)
|
431
|
+
raise ArgumentError unless isRegBinary(data)
|
432
|
+
[data.delete(',')].pack("H*")
|
433
|
+
end
|
434
|
+
|
435
|
+
def self.rawBinaryToRegBinary(data)
|
436
|
+
data.unpack("H*")[0].scan(/../).join(',')
|
437
|
+
end
|
438
|
+
|
439
|
+
def getHash
|
440
|
+
@hiveHash
|
441
|
+
end
|
442
|
+
|
443
|
+
def read_buffer(start_offset, data_length)
|
444
|
+
# Adjust offset so it matches the length of the actual registry hive file.
|
445
|
+
start_offset += REG_DATA_OFFSET
|
446
|
+
|
447
|
+
# Find what hbin section this data is in. Also loads data from file if it is not already in memory
|
448
|
+
idx = load_sections(start_offset / HBIN_SIZE)
|
449
|
+
|
450
|
+
# Subtract the section offset from the full offset to get the position inside the buffer
|
451
|
+
@hbin[idx][start_offset - (idx * HBIN_SIZE), data_length + 1]
|
452
|
+
end
|
453
|
+
|
454
|
+
def load_sections(idx)
|
455
|
+
if @hbin.key?(idx)
|
456
|
+
@stats[:cache_hits] += 1 if DEBUG_FILE_READS
|
457
|
+
# If the hash points to data return its index. Otherwise the hash
|
458
|
+
# will point to the index of the starting block of data
|
459
|
+
return @hbin[idx].kind_of?(Integer) ? @hbin[idx] : idx
|
460
|
+
else
|
461
|
+
@hbin[idx] = read_hbin(idx)
|
462
|
+
binHash = REGISTRY_STRUCT_HBIN.decode(@hbin[idx][0, SIZEOF_REGISTRY_STRUCT_HBIN])
|
463
|
+
|
464
|
+
unless binHash[:id] == 'hbin'
|
465
|
+
# If the block does not start with the header sign then back up and find it so
|
466
|
+
# we can load the full hbin which spans several block
|
467
|
+
while binHash[:id] != 'hbin'
|
468
|
+
binHash = REGISTRY_STRUCT_HBIN.decode(read_hbin(idx -= 1)[0, SIZEOF_REGISTRY_STRUCT_HBIN])
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
# Determine if the hbin is more than one block
|
473
|
+
hbin_count = binHash[:offset_to_next] / HBIN_SIZE
|
474
|
+
if hbin_count > 1
|
475
|
+
@hbin[idx] = read_hbin(idx, hbin_count)
|
476
|
+
# Set contiguous blocks with the index of the starting block
|
477
|
+
(idx + 1).upto(idx + hbin_count - 1) { |i| @hbin[i] = idx }
|
478
|
+
end
|
479
|
+
return idx
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
def read_hbin(idx, count = 1)
|
484
|
+
startAddr = idx * HBIN_SIZE
|
485
|
+
readCount = (HBIN_SIZE * count)
|
486
|
+
if DEBUG_FILE_READS
|
487
|
+
@stats[:file_reads] += 1
|
488
|
+
@stats[:bytes_read] += readCount
|
489
|
+
end
|
490
|
+
@fileHnd.seek(startAddr, IO::SEEK_SET)
|
491
|
+
@fileHnd.read(readCount)
|
492
|
+
end
|
493
|
+
|
494
|
+
# def on_start_element(name, attr_hash)
|
495
|
+
# $log.warn "START KEY: fqName:#{fqName}"
|
496
|
+
# end
|
497
|
+
#
|
498
|
+
# def on_end_element(name)
|
499
|
+
# $log.warn "END KEY: fqName:#{fqName}"
|
500
|
+
# end
|
501
|
+
|
502
|
+
# define registry structures
|
503
|
+
REGISTRY_HEADER_REGF = BinaryStruct.new([
|
504
|
+
'a4', :id, # ASCII "regf" = 0x66676572
|
505
|
+
'i', :updates1, # update counter 1
|
506
|
+
'i', :updates2, # update counter 2
|
507
|
+
'Q', :timestamp, # last modified (WinNT format)
|
508
|
+
'i', :version_major, # Version - Major Number
|
509
|
+
'i', :version_minor, # Version - Minor Number
|
510
|
+
'i', :version_release, # Version - Release Number
|
511
|
+
'i', :version_build, # Version - Build Number
|
512
|
+
'i', :data_offset, # Data offset
|
513
|
+
'i', :last_block, # Offset of Last Block
|
514
|
+
'i', nil, # UNKNOWN for 4 =1
|
515
|
+
'a64', :name, # description - last 31 characters of Fully Qualified Hive Name (in Unicode)
|
516
|
+
'a396', nil, # UNKNOWN x396
|
517
|
+
'i', :checksum, # checksum of all DWORDS (XORed) from 0x0000 to 0x01FB
|
518
|
+
])
|
519
|
+
SIZEOF_REGISTRY_HEADER_REGF = REGISTRY_HEADER_REGF.size
|
520
|
+
|
521
|
+
REGISTRY_STRUCT_HBIN = BinaryStruct.new([
|
522
|
+
'a4', :id, # ASCII "hbin" = 0x6E696268
|
523
|
+
'i', :offset_from_first, # Offset from 1st hbin-Block
|
524
|
+
'i', :offset_to_next, # Offset to the next hbin-Block
|
525
|
+
'Q', nil, # UNKNOWN for 8
|
526
|
+
'Q', :timestamp, # last modified (WinNT format)
|
527
|
+
'i', :block_size, # Block size (including the header!)
|
528
|
+
'l', :length, # Negative if not used, positive otherwise. Always a multiple of 8
|
529
|
+
])
|
530
|
+
SIZEOF_REGISTRY_STRUCT_HBIN = REGISTRY_STRUCT_HBIN.size
|
531
|
+
|
532
|
+
REGISTRY_STRUCT_NK = BinaryStruct.new([
|
533
|
+
'a2', :id, # ASCII "nk" = 0x6B6E
|
534
|
+
's', :type, # REG_ROOT_KEY = 0x2C, REG_SUB_KEY = 0x20, REG_SYM_LINK = 0x10
|
535
|
+
'Q', :timestamp,
|
536
|
+
'a4', nil, # UNKNOWN
|
537
|
+
'i', :parent_offset, # Offset of Owner/Parent key
|
538
|
+
'V', :num_subkeys, # Number of Subkeys
|
539
|
+
'a4', nil, # UNKNOWN
|
540
|
+
'i', :subkeys_offset,
|
541
|
+
'i', :unknown_offset,
|
542
|
+
'i', :num_values,
|
543
|
+
'i', :values_offset, # Points to a list of offsets of vk-records
|
544
|
+
'i', :sk_offset,
|
545
|
+
'i', :classname_offset,
|
546
|
+
'a20', nil, # UNKNOWN
|
547
|
+
's', :name_length,
|
548
|
+
's', :classname_length,
|
549
|
+
])
|
550
|
+
SIZEOF_REGISTRY_STRUCT_NK = REGISTRY_STRUCT_NK.size
|
551
|
+
|
552
|
+
# # Subkey listing with hash of first 4 characters
|
553
|
+
REGISTRY_STRUCT_LH = BinaryStruct.new([
|
554
|
+
'a2', :id, # ASCII "lh" = 0x666E
|
555
|
+
's', :num_keys, # number of keys
|
556
|
+
])
|
557
|
+
SIZEOF_REGISTRY_STRUCT_LH = REGISTRY_STRUCT_LH.size
|
558
|
+
|
559
|
+
# # The vk-record consists information to a single value (value key).
|
560
|
+
REGISTRY_STRUCT_VK = BinaryStruct.new([
|
561
|
+
'a2', :id, # ASCII "vk" = 0x6B76
|
562
|
+
's', :name_length,
|
563
|
+
'i', :data_length, # If top-bit set, offset contains the data
|
564
|
+
'i', :data_offset,
|
565
|
+
'i', :data_type,
|
566
|
+
's', :flag, # =1, has name, else no name (=Default).
|
567
|
+
'a2', nil, # UNKNOWN
|
568
|
+
])
|
569
|
+
SIZEOF_REGISTRY_STRUCT_VK = REGISTRY_STRUCT_VK.size
|
570
|
+
|
571
|
+
REGISTRY_STRUCT_LH_HASH = BinaryStruct.new([ # set STRUCT(REC-LH-HASH) {
|
572
|
+
'i', :offset_nk, # offset of corresponding NK record
|
573
|
+
'a4', :keyname, # Key Name
|
574
|
+
])
|
575
|
+
SIZEOF_REGISTRY_STRUCT_LH_HASH = REGISTRY_STRUCT_LH_HASH.size
|
576
|
+
|
577
|
+
REGISTRY_STRUCT_VK_OFFSET = BinaryStruct.new([ # set STRUCT(REC-LH-HASH) {
|
578
|
+
'i', :offset_vk, # offset of corresponding NK record
|
579
|
+
])
|
580
|
+
SIZEOF_REGISTRY_STRUCT_VK_OFFSET = REGISTRY_STRUCT_VK_OFFSET.size
|
581
|
+
|
582
|
+
# The lf-record is the counterpart to the RGKN-record (the hash-function)
|
583
|
+
REGISTRY_STRUCT_LF = BinaryStruct.new([
|
584
|
+
'a2', :id, # ASCII "lf" = 0x666C
|
585
|
+
's', :num_keys, # number of keys
|
586
|
+
])
|
587
|
+
SIZEOF_REGISTRY_STRUCT_LF = REGISTRY_STRUCT_LF.size
|
588
|
+
|
589
|
+
REGISTRY_STRUCT_LF_HASH = BinaryStruct.new([
|
590
|
+
'i', :offset_nk, # offset of corresponding NK record
|
591
|
+
'a4', :keyname, # Key Name
|
592
|
+
])
|
593
|
+
SIZEOF_REGISTRY_STRUCT_LF_HASH = REGISTRY_STRUCT_LF_HASH.size
|
594
|
+
|
595
|
+
# A list of offsets to LI/LH records
|
596
|
+
REGISTRY_STRUCT_RI = BinaryStruct.new([
|
597
|
+
'a2', :id, # ASCII "ri" = 0x6972
|
598
|
+
's', :num_keys, # number of keys
|
599
|
+
])
|
600
|
+
SIZEOF_REGISTRY_STRUCT_RI = REGISTRY_STRUCT_RI.size
|
601
|
+
|
602
|
+
REGISTRY_STRUCT_RI_OFFSET = BinaryStruct.new([ # set STRUCT(REC-LH-HASH) {
|
603
|
+
'i', :offset_ri, # offset of corresponding NK record
|
604
|
+
])
|
605
|
+
SIZEOF_REGISTRY_STRUCT_RI_OFFSET = REGISTRY_STRUCT_RI_OFFSET.size
|
606
|
+
|
607
|
+
#
|
608
|
+
# # sk (? Security Key ?) is the ACL of the registry.
|
609
|
+
# set STRUCT(REC-SK) {
|
610
|
+
# a2 id /* ASCII "sk" = 0x6B73 */
|
611
|
+
# s tag /* */
|
612
|
+
# i prev_offset /* Offset of previous "sk"-Record */
|
613
|
+
# i next_offset /* Offset of next "sk"-Record */
|
614
|
+
# i ref_count /* Reference/Usage counter */
|
615
|
+
# i rec_size /* Record size */
|
616
|
+
# }
|
617
|
+
|
618
|
+
# Return registry key type. Otherwise return the hex value of the integer
|
619
|
+
KEY_TYPES = Hash.new { |_h, k| "%08X" % k }
|
620
|
+
KEY_TYPES.merge!(
|
621
|
+
0 => :REG_NONE, # No value type
|
622
|
+
1 => :REG_SZ, # A null-terminated string (Unicode)
|
623
|
+
2 => :REG_EXPAND_SZ, # A null-terminated string that contains
|
624
|
+
# unexpanded references to environment variables (for example, "%PATH%").
|
625
|
+
# It will be a Unicode or ANSI string depending on whether you use the
|
626
|
+
# Unicode or ANSI functions. To expand the environment variable references,
|
627
|
+
# use the ExpandEnvironmentStrings function.
|
628
|
+
3 => :REG_BINARY, # Free form binary
|
629
|
+
4 => :REG_DWORD, # 32-bit number - Little Endian
|
630
|
+
5 => :REG_DWORD_BIG_ENDIAN, # 32-bit number - Big Endian
|
631
|
+
6 => :REG_LINK, # Symbolic Link (unicode) - Reserved for system use.
|
632
|
+
7 => :REG_MULTI_SZ, # A sequence of null-terminated strings, terminated by an empty string (\0).
|
633
|
+
# The following is an example:
|
634
|
+
# String1\0String2\0String3\0LastString\0\0
|
635
|
+
# The first \0 terminates the first string, the second to the last \0 terminates the last string,
|
636
|
+
# and the final \0 terminates the sequence. Note that the final terminator must be factored into the length of the string.
|
637
|
+
8 => :REG_RESOURCE_LIST, # Resource list in the resource map
|
638
|
+
9 => :REG_FULL_RESOURCE_DESCRIPTOR, # Resource list in the hardware description
|
639
|
+
10 => :REG_RESOURCE_REQUIREMENTS_LIST,
|
640
|
+
11 => :REG_QWORD, # 64-bit number - Little Endian
|
641
|
+
)
|
642
|
+
end
|
643
|
+
|
644
|
+
module DumpHash
|
645
|
+
def self.SortPrint(hash, prefix = :UKN)
|
646
|
+
return unless DEBUG_PRINT
|
647
|
+
$log.debug "#{prefix}(RAW): ========"
|
648
|
+
hash.sort { |a, b| a.to_s <=> b.to_s }.each { |x, y| $log.debug "#{prefix}(#{x})\t\t= #{y}" }
|
649
|
+
end
|
650
|
+
end
|