manageiq-smartstate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (305) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +4 -0
  4. data/.rspec_ci +4 -0
  5. data/.travis.yml +15 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE.txt +202 -0
  8. data/README.md +45 -0
  9. data/Rakefile +23 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/MiqContainerGroup/MiqContainerGroup.rb +31 -0
  13. data/lib/MiqVm/MiqLocalVm.rb +50 -0
  14. data/lib/MiqVm/MiqRhevmVm.rb +179 -0
  15. data/lib/MiqVm/MiqVm.rb +355 -0
  16. data/lib/MiqVm/miq_azure_vm.rb +96 -0
  17. data/lib/MiqVm/miq_scvmm_vm.rb +38 -0
  18. data/lib/MiqVm/test/camcorder_fleece_test.rb +60 -0
  19. data/lib/MiqVm/test/localVm.rb +45 -0
  20. data/lib/MiqVm/test/partitionAlignmentCheck.rb +76 -0
  21. data/lib/MiqVm/test/remoteVm.rb +65 -0
  22. data/lib/MiqVm/test/rhevmNfsTest.rb +62 -0
  23. data/lib/MiqVm/test/rhevmNfsTest2.rb +66 -0
  24. data/lib/MiqVm/test/rhevmTest.rb +70 -0
  25. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackCommon.rb +107 -0
  26. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackImage.rb +67 -0
  27. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb +182 -0
  28. data/lib/Scvmm/miq_hyperv_disk.rb +273 -0
  29. data/lib/Scvmm/miq_scvmm_parse_powershell.rb +75 -0
  30. data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +135 -0
  31. data/lib/Scvmm/test/miq_hyperv_disk_test.rb +33 -0
  32. data/lib/Scvmm/test/miq_scvmm_vm_ssa_info_test.rb +41 -0
  33. data/lib/VmLocalDiskAccess/test/localCfg.rb +97 -0
  34. data/lib/VolumeManager/LVM/logical_volume.rb +75 -0
  35. data/lib/VolumeManager/LVM/lv_segment.rb +43 -0
  36. data/lib/VolumeManager/LVM/lvm2disk.rb +158 -0
  37. data/lib/VolumeManager/LVM/parser.rb +138 -0
  38. data/lib/VolumeManager/LVM/physical_volume.rb +19 -0
  39. data/lib/VolumeManager/LVM/scanner.rb +156 -0
  40. data/lib/VolumeManager/LVM/thin/btree.rb +83 -0
  41. data/lib/VolumeManager/LVM/thin/constants.rb +86 -0
  42. data/lib/VolumeManager/LVM/thin/data_map.rb +44 -0
  43. data/lib/VolumeManager/LVM/thin/mapping_tree.rb +19 -0
  44. data/lib/VolumeManager/LVM/thin/space_maps.rb +58 -0
  45. data/lib/VolumeManager/LVM/thin/superblock.rb +136 -0
  46. data/lib/VolumeManager/LVM/thin.rb +6 -0
  47. data/lib/VolumeManager/LVM/volume_group.rb +97 -0
  48. data/lib/VolumeManager/LVM.rb +8 -0
  49. data/lib/VolumeManager/MiqLdm.rb +546 -0
  50. data/lib/VolumeManager/MiqLvm.rb +17 -0
  51. data/lib/VolumeManager/MiqNativeVolumeManager.rb +150 -0
  52. data/lib/VolumeManager/MiqVolumeManager.rb +277 -0
  53. data/lib/VolumeManager/VolMgrPlatformSupport.rb +18 -0
  54. data/lib/VolumeManager/VolMgrPlatformSupportLinux.rb +77 -0
  55. data/lib/VolumeManager/VolMgrPlatformSupportWin.rb +17 -0
  56. data/lib/VolumeManager/test/blockDevTest.rb +40 -0
  57. data/lib/VolumeManager/test/ldm.rb +97 -0
  58. data/lib/blackbox/VmBlackBox.rb +103 -0
  59. data/lib/blackbox/xmlStorage.rb +180 -0
  60. data/lib/db/MiqBdb/MiqBdb.rb +309 -0
  61. data/lib/db/MiqBdb/MiqBdbBtree.rb +219 -0
  62. data/lib/db/MiqBdb/MiqBdbHash.rb +199 -0
  63. data/lib/db/MiqBdb/MiqBdbPage.rb +159 -0
  64. data/lib/db/MiqBdb/MiqBdbUtil.rb +18 -0
  65. data/lib/db/MiqSqlite/MiqSqlite3.rb +330 -0
  66. data/lib/db/MiqSqlite/MiqSqlite3Cell.rb +167 -0
  67. data/lib/db/MiqSqlite/MiqSqlite3Page.rb +151 -0
  68. data/lib/db/MiqSqlite/MiqSqlite3Table.rb +124 -0
  69. data/lib/db/MiqSqlite/MiqSqlite3Util.rb +32 -0
  70. data/lib/disk/DiskProbe.rb +68 -0
  71. data/lib/disk/MiqDisk.rb +317 -0
  72. data/lib/disk/camcorder_test.rb +90 -0
  73. data/lib/disk/dos_mbr.img +0 -0
  74. data/lib/disk/modules/AzureBlobDisk.rb +101 -0
  75. data/lib/disk/modules/LocalDevMod.rb +47 -0
  76. data/lib/disk/modules/LocalDevProbe.rb +6 -0
  77. data/lib/disk/modules/MSCommon.rb +352 -0
  78. data/lib/disk/modules/MSVSDiffDisk.rb +91 -0
  79. data/lib/disk/modules/MSVSDiskProbe.rb +61 -0
  80. data/lib/disk/modules/MSVSDynamicDisk.rb +42 -0
  81. data/lib/disk/modules/MSVSFixedDisk.rb +45 -0
  82. data/lib/disk/modules/MiqLargeFile.rb +63 -0
  83. data/lib/disk/modules/MiqLargeFileWin32.rb +107 -0
  84. data/lib/disk/modules/QcowDisk.rb +692 -0
  85. data/lib/disk/modules/QcowDiskProbe.rb +34 -0
  86. data/lib/disk/modules/RawBlockIO.rb +116 -0
  87. data/lib/disk/modules/RawDisk.rb +45 -0
  88. data/lib/disk/modules/RawDiskProbe.rb +7 -0
  89. data/lib/disk/modules/RhevmDescriptor.rb +167 -0
  90. data/lib/disk/modules/RhevmDiskProbe.rb +52 -0
  91. data/lib/disk/modules/VMWareCowdDisk.rb +207 -0
  92. data/lib/disk/modules/VMWareDescriptor.rb +214 -0
  93. data/lib/disk/modules/VMWareDiskProbe.rb +74 -0
  94. data/lib/disk/modules/VMWareSparseDisk.rb +189 -0
  95. data/lib/disk/modules/VhdxDisk.rb +625 -0
  96. data/lib/disk/modules/VhdxDiskProbe.rb +46 -0
  97. data/lib/disk/modules/VixDiskMod.rb +54 -0
  98. data/lib/disk/modules/VixDiskProbe.rb +6 -0
  99. data/lib/disk/modules/miq_disk_cache.rb +135 -0
  100. data/lib/disk/modules/miq_dummy_disk.rb +41 -0
  101. data/lib/disk/modules/vhdx_bat_entry.rb +10 -0
  102. data/lib/disk/test.rb +66 -0
  103. data/lib/fs/MetakitFS/MetakitFS.rb +530 -0
  104. data/lib/fs/MetakitFS/test/Makefile +14 -0
  105. data/lib/fs/MetakitFS/test/MkCollectFiles.rb +165 -0
  106. data/lib/fs/MetakitFS/test/MkSelectFiles.rb +30 -0
  107. data/lib/fs/MetakitFS/test/collect_files.yaml +70 -0
  108. data/lib/fs/MetakitFS/test/init.rb +3 -0
  109. data/lib/fs/MetakitFS/test/mk2vmdk.rb +64 -0
  110. data/lib/fs/MetakitFS/test/mk4test.c +92 -0
  111. data/lib/fs/MetakitFS/test/mkFsTest.rb +113 -0
  112. data/lib/fs/MetakitFS/test/proto.rb +97 -0
  113. data/lib/fs/MiqFS/FsProbe.rb +39 -0
  114. data/lib/fs/MiqFS/MiqFS.rb +515 -0
  115. data/lib/fs/MiqFS/modules/AUFSProbe.rb +26 -0
  116. data/lib/fs/MiqFS/modules/Ext3.rb +305 -0
  117. data/lib/fs/MiqFS/modules/Ext3Probe.rb +25 -0
  118. data/lib/fs/MiqFS/modules/Ext4.rb +304 -0
  119. data/lib/fs/MiqFS/modules/Ext4Probe.rb +25 -0
  120. data/lib/fs/MiqFS/modules/Fat32.rb +318 -0
  121. data/lib/fs/MiqFS/modules/Fat32Probe.rb +30 -0
  122. data/lib/fs/MiqFS/modules/HFSProbe.rb +18 -0
  123. data/lib/fs/MiqFS/modules/Iso9660.rb +293 -0
  124. data/lib/fs/MiqFS/modules/Iso9660Probe.rb +18 -0
  125. data/lib/fs/MiqFS/modules/LocalFS.rb +105 -0
  126. data/lib/fs/MiqFS/modules/NTFS.rb +287 -0
  127. data/lib/fs/MiqFS/modules/NTFSProbe.rb +21 -0
  128. data/lib/fs/MiqFS/modules/NativeFS.rb +155 -0
  129. data/lib/fs/MiqFS/modules/ReFSProbe.rb +17 -0
  130. data/lib/fs/MiqFS/modules/RealFS.rb +79 -0
  131. data/lib/fs/MiqFS/modules/RealFSProbe.rb +6 -0
  132. data/lib/fs/MiqFS/modules/Reiser4Probe.rb +18 -0
  133. data/lib/fs/MiqFS/modules/ReiserFS.rb +315 -0
  134. data/lib/fs/MiqFS/modules/ReiserFSProbe.rb +42 -0
  135. data/lib/fs/MiqFS/modules/UnionFSProbe.rb +18 -0
  136. data/lib/fs/MiqFS/modules/WebDAV.rb +127 -0
  137. data/lib/fs/MiqFS/modules/WebDAVFile.rb +68 -0
  138. data/lib/fs/MiqFS/modules/XFS.rb +300 -0
  139. data/lib/fs/MiqFS/modules/XFSProbe.rb +26 -0
  140. data/lib/fs/MiqFS/modules/ZFSProbe.rb +18 -0
  141. data/lib/fs/MiqFS/test.rb +59 -0
  142. data/lib/fs/MiqFsUtil.rb +383 -0
  143. data/lib/fs/MiqMountManager.rb +209 -0
  144. data/lib/fs/MiqNativeMountManager.rb +101 -0
  145. data/lib/fs/MountManagerProbe.rb +29 -0
  146. data/lib/fs/ReiserFS/block.rb +209 -0
  147. data/lib/fs/ReiserFS/directory.rb +136 -0
  148. data/lib/fs/ReiserFS/directory_entry.rb +140 -0
  149. data/lib/fs/ReiserFS/file_data.rb +111 -0
  150. data/lib/fs/ReiserFS/superblock.rb +140 -0
  151. data/lib/fs/ReiserFS/utils.rb +95 -0
  152. data/lib/fs/VimDatastoreFS/VimDatastoreFS.rb +192 -0
  153. data/lib/fs/ext3/alloc_bitmap.rb +38 -0
  154. data/lib/fs/ext3/block_pointers_path.rb +130 -0
  155. data/lib/fs/ext3/directory.rb +51 -0
  156. data/lib/fs/ext3/directory_entry.rb +67 -0
  157. data/lib/fs/ext3/ex_attrib_header.rb +14 -0
  158. data/lib/fs/ext3/ex_attrib_name.rb +23 -0
  159. data/lib/fs/ext3/file_data.rb +130 -0
  160. data/lib/fs/ext3/group_descriptor_entry.rb +65 -0
  161. data/lib/fs/ext3/group_descriptor_table.rb +54 -0
  162. data/lib/fs/ext3/hash_tree_entry.rb +18 -0
  163. data/lib/fs/ext3/hash_tree_header.rb +15 -0
  164. data/lib/fs/ext3/inode.rb +228 -0
  165. data/lib/fs/ext3/posix_acl_entry.rb +29 -0
  166. data/lib/fs/ext3/posix_acl_header.rb +11 -0
  167. data/lib/fs/ext3/superblock.rb +406 -0
  168. data/lib/fs/ext3/test/tc_Ext3BlockPointersPath.rb +74 -0
  169. data/lib/fs/ext4/alloc_bitmap.rb +38 -0
  170. data/lib/fs/ext4/directory.rb +87 -0
  171. data/lib/fs/ext4/directory_entry.rb +77 -0
  172. data/lib/fs/ext4/ex_attrib_header.rb +14 -0
  173. data/lib/fs/ext4/ex_attrib_name.rb +23 -0
  174. data/lib/fs/ext4/extent.rb +35 -0
  175. data/lib/fs/ext4/extent_header.rb +40 -0
  176. data/lib/fs/ext4/extent_index.rb +33 -0
  177. data/lib/fs/ext4/group_descriptor_entry.rb +69 -0
  178. data/lib/fs/ext4/group_descriptor_table.rb +54 -0
  179. data/lib/fs/ext4/hash_tree_entry.rb +58 -0
  180. data/lib/fs/ext4/hash_tree_header.rb +35 -0
  181. data/lib/fs/ext4/inode.rb +465 -0
  182. data/lib/fs/ext4/posix_acl_entry.rb +29 -0
  183. data/lib/fs/ext4/posix_acl_header.rb +11 -0
  184. data/lib/fs/ext4/superblock.rb +412 -0
  185. data/lib/fs/fat32/boot_sect.rb +379 -0
  186. data/lib/fs/fat32/directory.rb +222 -0
  187. data/lib/fs/fat32/directory_entry.rb +540 -0
  188. data/lib/fs/fat32/file_data.rb +128 -0
  189. data/lib/fs/iso9660/boot_sector.rb +170 -0
  190. data/lib/fs/iso9660/directory.rb +90 -0
  191. data/lib/fs/iso9660/directory_entry.rb +147 -0
  192. data/lib/fs/iso9660/file_data.rb +78 -0
  193. data/lib/fs/iso9660/rock_ridge.rb +329 -0
  194. data/lib/fs/iso9660/util.rb +57 -0
  195. data/lib/fs/modules/LinuxMount.rb +300 -0
  196. data/lib/fs/modules/LinuxMountProbe.rb +29 -0
  197. data/lib/fs/modules/WinMount.rb +97 -0
  198. data/lib/fs/modules/WinMountProbe.rb +24 -0
  199. data/lib/fs/ntfs/attrib_attribute_list.rb +131 -0
  200. data/lib/fs/ntfs/attrib_bitmap.rb +26 -0
  201. data/lib/fs/ntfs/attrib_data.rb +74 -0
  202. data/lib/fs/ntfs/attrib_file_name.rb +110 -0
  203. data/lib/fs/ntfs/attrib_header.rb +194 -0
  204. data/lib/fs/ntfs/attrib_index_allocation.rb +19 -0
  205. data/lib/fs/ntfs/attrib_index_root.rb +247 -0
  206. data/lib/fs/ntfs/attrib_object_id.rb +40 -0
  207. data/lib/fs/ntfs/attrib_standard_information.rb +107 -0
  208. data/lib/fs/ntfs/attrib_type.rb +49 -0
  209. data/lib/fs/ntfs/attrib_volume_information.rb +53 -0
  210. data/lib/fs/ntfs/attrib_volume_name.rb +31 -0
  211. data/lib/fs/ntfs/boot_sect.rb +253 -0
  212. data/lib/fs/ntfs/data_run.rb +358 -0
  213. data/lib/fs/ntfs/directory_index_node.rb +114 -0
  214. data/lib/fs/ntfs/index_node_header.rb +69 -0
  215. data/lib/fs/ntfs/index_record_header.rb +85 -0
  216. data/lib/fs/ntfs/mft_entry.rb +288 -0
  217. data/lib/fs/ntfs/utils.rb +43 -0
  218. data/lib/fs/test/camcorder_fs_test.rb +108 -0
  219. data/lib/fs/test/collect_files_direct.yaml +22 -0
  220. data/lib/fs/test/collect_files_in.yaml +24 -0
  221. data/lib/fs/test/collect_files_in_nc.yaml +22 -0
  222. data/lib/fs/test/collect_files_out.yaml +6 -0
  223. data/lib/fs/test/collect_files_rm.yaml +6 -0
  224. data/lib/fs/test/copyTest.rb +126 -0
  225. data/lib/fs/test/fsTest.rb +87 -0
  226. data/lib/fs/test/updateTest.rb +184 -0
  227. data/lib/fs/xfs/allocation_group.rb +160 -0
  228. data/lib/fs/xfs/bmap_btree_block.rb +125 -0
  229. data/lib/fs/xfs/bmap_btree_record.rb +80 -0
  230. data/lib/fs/xfs/bmap_btree_root_node.rb +72 -0
  231. data/lib/fs/xfs/directory.rb +133 -0
  232. data/lib/fs/xfs/directory2_data_header.rb +27 -0
  233. data/lib/fs/xfs/directory3_data_header.rb +34 -0
  234. data/lib/fs/xfs/directory_block_tail.rb +22 -0
  235. data/lib/fs/xfs/directory_data_header.rb +46 -0
  236. data/lib/fs/xfs/directory_entry.rb +106 -0
  237. data/lib/fs/xfs/inode.rb +532 -0
  238. data/lib/fs/xfs/inode_map.rb +100 -0
  239. data/lib/fs/xfs/short_form_directory_entry.rb +91 -0
  240. data/lib/fs/xfs/short_form_header.rb +44 -0
  241. data/lib/fs/xfs/superblock.rb +556 -0
  242. data/lib/lib/tasks/azure.rake +52 -0
  243. data/lib/manageiq/smartstate/version.rb +5 -0
  244. data/lib/manageiq/smartstate.rb +7 -0
  245. data/lib/manageiq-smartstate.rb +1 -0
  246. data/lib/metadata/MIQExtract/MIQExtract.rb +297 -0
  247. data/lib/metadata/MIQExtract/test/extractTest.rb +41 -0
  248. data/lib/metadata/MIQExtract/test/full_extract_test.rb +68 -0
  249. data/lib/metadata/ScanProfile/HostScanItem.rb +4 -0
  250. data/lib/metadata/ScanProfile/HostScanProfile.rb +4 -0
  251. data/lib/metadata/ScanProfile/HostScanProfiles.rb +41 -0
  252. data/lib/metadata/ScanProfile/ScanItemBase.rb +63 -0
  253. data/lib/metadata/ScanProfile/ScanProfileBase.rb +51 -0
  254. data/lib/metadata/ScanProfile/ScanProfilesBase.rb +60 -0
  255. data/lib/metadata/ScanProfile/VmScanItem.rb +4 -0
  256. data/lib/metadata/ScanProfile/VmScanProfile.rb +4 -0
  257. data/lib/metadata/ScanProfile/VmScanProfiles.rb +38 -0
  258. data/lib/metadata/ScanProfile/modules/HostScanItemFile.rb +51 -0
  259. data/lib/metadata/ScanProfile/modules/HostScanItemNteventlog.rb +84 -0
  260. data/lib/metadata/ScanProfile/modules/VmScanItemFile.rb +39 -0
  261. data/lib/metadata/ScanProfile/modules/VmScanItemNteventlog.rb +34 -0
  262. data/lib/metadata/ScanProfile/modules/VmScanItemRegistry.rb +64 -0
  263. data/lib/metadata/VMMount/VMMount.rb +81 -0
  264. data/lib/metadata/VMMount/VMPlatformMount.rb +18 -0
  265. data/lib/metadata/VMMount/VMPlatformMountLinux.rb +75 -0
  266. data/lib/metadata/VMMount/VMPlatformMountWin.rb +13 -0
  267. data/lib/metadata/VmConfig/GetNativeCfg.rb +45 -0
  268. data/lib/metadata/VmConfig/VmConfig.rb +947 -0
  269. data/lib/metadata/VmConfig/cfgConfig.rb +45 -0
  270. data/lib/metadata/VmConfig/ovfConfig.rb +99 -0
  271. data/lib/metadata/VmConfig/test/GetVMwareCfgTest.rb +40 -0
  272. data/lib/metadata/VmConfig/vmcConfig.rb +116 -0
  273. data/lib/metadata/VmConfig/vmtxConfig.rb +4 -0
  274. data/lib/metadata/VmConfig/vmxConfig.rb +162 -0
  275. data/lib/metadata/VmConfig/xmlConfig.rb +79 -0
  276. data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +41 -0
  277. data/lib/metadata/linux/InitProcHash.rb +632 -0
  278. data/lib/metadata/linux/LinuxInitProcs.rb +142 -0
  279. data/lib/metadata/linux/LinuxOSInfo.rb +237 -0
  280. data/lib/metadata/linux/LinuxPackages.rb +209 -0
  281. data/lib/metadata/linux/LinuxSystemd.rb +130 -0
  282. data/lib/metadata/linux/LinuxUsers.rb +289 -0
  283. data/lib/metadata/linux/LinuxUtils.rb +197 -0
  284. data/lib/metadata/linux/MiqConaryPackages.rb +41 -0
  285. data/lib/metadata/linux/MiqRpmPackages.rb +160 -0
  286. data/lib/metadata/linux/test/Name +0 -0
  287. data/lib/metadata/linux/test/Packages +0 -0
  288. data/lib/metadata/linux/test/rpoTest.rb +5 -0
  289. data/lib/metadata/linux/test/tc_LinuxUtils.rb +4157 -0
  290. data/lib/metadata/util/event_log_filter.rb +61 -0
  291. data/lib/metadata/util/md5deep.rb +280 -0
  292. data/lib/metadata/util/win32/Win32Accounts.rb +764 -0
  293. data/lib/metadata/util/win32/Win32EventLog.rb +743 -0
  294. data/lib/metadata/util/win32/Win32Services.rb +86 -0
  295. data/lib/metadata/util/win32/Win32Software.rb +326 -0
  296. data/lib/metadata/util/win32/Win32System.rb +333 -0
  297. data/lib/metadata/util/win32/boot_info_win.rb +59 -0
  298. data/lib/metadata/util/win32/fleece_hives.rb +220 -0
  299. data/lib/metadata/util/win32/ms-registry.rb +650 -0
  300. data/lib/metadata/util/win32/peheader.rb +868 -0
  301. data/lib/metadata/util/win32/remote-registry.rb +142 -0
  302. data/lib/metadata/util/win32/system_path_win.rb +103 -0
  303. data/lib/metadata/util/win32/versioninfo.rb +17 -0
  304. data/manageiq-smartstate.gemspec +35 -0
  305. 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