ruby_smb 1.0.5 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +3 -2
  5. data/Gemfile +6 -2
  6. data/README.md +35 -47
  7. data/examples/anonymous_auth.rb +3 -3
  8. data/examples/append_file.rb +10 -8
  9. data/examples/authenticate.rb +9 -5
  10. data/examples/delete_file.rb +8 -6
  11. data/examples/enum_registry_key.rb +29 -0
  12. data/examples/enum_registry_values.rb +31 -0
  13. data/examples/list_directory.rb +8 -6
  14. data/examples/negotiate.rb +51 -8
  15. data/examples/negotiate_with_netbios_service.rb +9 -5
  16. data/examples/net_share_enum_all.rb +6 -4
  17. data/examples/pipes.rb +13 -13
  18. data/examples/query_service_status.rb +64 -0
  19. data/examples/read_file.rb +8 -6
  20. data/examples/read_file_encryption.rb +56 -0
  21. data/examples/read_registry_key_value.rb +33 -0
  22. data/examples/rename_file.rb +9 -7
  23. data/examples/tree_connect.rb +7 -5
  24. data/examples/write_file.rb +9 -7
  25. data/lib/ruby_smb.rb +4 -1
  26. data/lib/ruby_smb/client.rb +239 -21
  27. data/lib/ruby_smb/client/authentication.rb +27 -8
  28. data/lib/ruby_smb/client/encryption.rb +62 -0
  29. data/lib/ruby_smb/client/negotiation.rb +154 -12
  30. data/lib/ruby_smb/client/signing.rb +19 -0
  31. data/lib/ruby_smb/client/tree_connect.rb +4 -4
  32. data/lib/ruby_smb/client/utils.rb +8 -7
  33. data/lib/ruby_smb/client/winreg.rb +46 -0
  34. data/lib/ruby_smb/crypto.rb +30 -0
  35. data/lib/ruby_smb/dcerpc.rb +40 -0
  36. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  37. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  38. data/lib/ruby_smb/dcerpc/error.rb +6 -0
  39. data/lib/ruby_smb/dcerpc/ndr.rb +260 -16
  40. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  41. data/lib/ruby_smb/dcerpc/request.rb +41 -9
  42. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  43. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +38 -0
  44. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  45. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  46. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  59. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  60. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  61. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  62. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  63. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  64. data/lib/ruby_smb/dcerpc/winreg.rb +421 -0
  65. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  66. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  67. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  68. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  69. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  70. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  71. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  72. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  73. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  74. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  75. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  76. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  77. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  78. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  79. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +40 -0
  80. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  81. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  82. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  83. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  84. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  85. data/lib/ruby_smb/dispatcher/socket.rb +5 -4
  86. data/lib/ruby_smb/error.rb +28 -1
  87. data/lib/ruby_smb/field/stringz16.rb +17 -1
  88. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  89. data/lib/ruby_smb/smb1/commands.rb +1 -1
  90. data/lib/ruby_smb/smb1/file.rb +8 -14
  91. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  92. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  93. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  94. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  95. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  96. data/lib/ruby_smb/smb1/pipe.rb +81 -3
  97. data/lib/ruby_smb/smb1/tree.rb +12 -3
  98. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  99. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  100. data/lib/ruby_smb/smb2/file.rb +51 -61
  101. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  102. data/lib/ruby_smb/smb2/packet.rb +2 -0
  103. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  104. data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
  105. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  106. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
  107. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  108. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  109. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  110. data/lib/ruby_smb/smb2/pipe.rb +80 -3
  111. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  112. data/lib/ruby_smb/smb2/tree.rb +32 -20
  113. data/lib/ruby_smb/version.rb +1 -1
  114. data/ruby_smb.gemspec +5 -3
  115. data/spec/lib/ruby_smb/client_spec.rb +1583 -102
  116. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  117. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  118. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1729 -0
  120. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  121. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  122. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +135 -0
  123. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  124. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  125. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  126. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  127. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  128. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  129. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  130. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  131. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  132. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  133. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  134. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  135. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  136. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  137. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  138. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  139. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  140. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  141. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  142. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  143. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  144. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  145. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  146. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  147. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +104 -0
  148. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  149. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  150. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  151. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  152. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  153. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +95 -0
  154. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  155. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +35 -0
  156. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  157. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  158. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +138 -0
  159. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  160. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  161. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  162. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +884 -0
  163. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  164. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
  165. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  166. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  167. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  168. data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
  169. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  170. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  171. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  172. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  173. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +216 -147
  174. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  175. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  176. data/spec/lib/ruby_smb/smb2/file_spec.rb +146 -68
  177. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  178. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  179. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +3 -24
  180. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  181. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  182. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  183. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  184. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  185. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +226 -148
  186. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  187. data/spec/lib/ruby_smb/smb2/tree_spec.rb +88 -9
  188. metadata +257 -81
  189. metadata.gz.sig +0 -0
  190. data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
  191. data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,27 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Svcctl
6
+
7
+ # [3.1.4.19 RStartServiceW (Opnum 19)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/d9be95a2-cf01-4bdc-b30f-6fe4b37ada16)
8
+ class StartServiceWRequest < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ sc_rpc_handle :h_service
14
+ uint32 :argc
15
+ ndr_lp_string_ptrsw :argv
16
+
17
+ def initialize_instance
18
+ super
19
+ @opnum = START_SERVICE_W
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+
27
+
@@ -0,0 +1,25 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Svcctl
6
+
7
+ # [3.1.4.19 RStartServiceW (Opnum 19)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/d9be95a2-cf01-4bdc-b30f-6fe4b37ada16)
8
+ class StartServiceWResponse < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ uint32 :error_status
14
+
15
+ def initialize_instance
16
+ super
17
+ @opnum = START_SERVICE_W
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+
@@ -0,0 +1,421 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Winreg
4
+
5
+ UUID = '338CD001-2244-31F1-AAAA-900038001003'
6
+ VER_MAJOR = 1
7
+ VER_MINOR = 0
8
+
9
+ # Operation numbers
10
+ OPEN_HKCR = 0x00
11
+ OPEN_HKCU = 0x01
12
+ OPEN_HKLM = 0x02
13
+ OPEN_HKPD = 0x03
14
+ OPEN_HKU = 0x04
15
+ REG_CLOSE_KEY = 0x05
16
+ REG_CREATE_KEY = 0x06
17
+ REG_ENUM_KEY = 0x09
18
+ REG_ENUM_VALUE = 0x0a
19
+ REG_OPEN_KEY = 0x0f
20
+ REG_QUERY_INFO_KEY = 0x10
21
+ REG_QUERY_VALUE = 0x11
22
+ REG_SAVE_KEY = 0x14
23
+ OPEN_HKCC = 0x1b
24
+ OPEN_HKPT = 0x20
25
+ OPEN_HKPN = 0x21
26
+
27
+ require 'ruby_smb/dcerpc/winreg/regsam'
28
+ require 'ruby_smb/dcerpc/winreg/open_root_key_request'
29
+ require 'ruby_smb/dcerpc/winreg/open_root_key_response'
30
+ require 'ruby_smb/dcerpc/winreg/close_key_request'
31
+ require 'ruby_smb/dcerpc/winreg/close_key_response'
32
+ require 'ruby_smb/dcerpc/winreg/enum_key_request'
33
+ require 'ruby_smb/dcerpc/winreg/enum_key_response'
34
+ require 'ruby_smb/dcerpc/winreg/enum_value_request'
35
+ require 'ruby_smb/dcerpc/winreg/enum_value_response'
36
+ require 'ruby_smb/dcerpc/winreg/open_key_request'
37
+ require 'ruby_smb/dcerpc/winreg/open_key_response'
38
+ require 'ruby_smb/dcerpc/winreg/query_info_key_request'
39
+ require 'ruby_smb/dcerpc/winreg/query_info_key_response'
40
+ require 'ruby_smb/dcerpc/winreg/query_value_request'
41
+ require 'ruby_smb/dcerpc/winreg/query_value_response'
42
+ require 'ruby_smb/dcerpc/winreg/create_key_request'
43
+ require 'ruby_smb/dcerpc/winreg/create_key_response'
44
+ require 'ruby_smb/dcerpc/winreg/save_key_request'
45
+ require 'ruby_smb/dcerpc/winreg/save_key_response'
46
+
47
+ ROOT_KEY_MAP = {
48
+ "HKEY_CLASSES_ROOT" => OPEN_HKCR,
49
+ "HKCR" => OPEN_HKCR,
50
+ "HKEY_CURRENT_USER" => OPEN_HKCU,
51
+ "HKCU" => OPEN_HKCU,
52
+ "HKEY_LOCAL_MACHINE" => OPEN_HKLM,
53
+ "HKLM" => OPEN_HKLM,
54
+ "HKEY_PERFORMANCE_DATA" => OPEN_HKPD,
55
+ "HKPD" => OPEN_HKPD,
56
+ "HKEY_USERS" => OPEN_HKU,
57
+ "HKU" => OPEN_HKU,
58
+ "HKEY_CURRENT_CONFIG" => OPEN_HKCC,
59
+ "HKCC" => OPEN_HKCC,
60
+ "HKEY_PERFORMANCE_TEXT" => OPEN_HKPT,
61
+ "HKPT" => OPEN_HKPT,
62
+ "HKEY_PERFORMANCE_NLS_TEXT" => OPEN_HKPN,
63
+ "HKPN" => OPEN_HKPN
64
+ }
65
+
66
+ # Open the registry root key and return a handle for it. The key can be
67
+ # either a long format (e.g. HKEY_LOCAL_MACHINE) or a short format
68
+ # (e.g. HKLM)
69
+ #
70
+ # @param root_key [String] the root key to open
71
+ # @return [Ndr::NdrContextHandle] the RPC context handle for the root key
72
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenRootKeyResponse packet
73
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
74
+ def open_root_key(root_key)
75
+ root_key_opnum = RubySMB::Dcerpc::Winreg::ROOT_KEY_MAP[root_key]
76
+ raise ArgumentError, "Unknown Root Key: #{root_key}" unless root_key_opnum
77
+
78
+ root_key_request_packet = OpenRootKeyRequest.new(opnum: root_key_opnum)
79
+ response = dcerpc_request(root_key_request_packet)
80
+
81
+ begin
82
+ root_key_response_packet = OpenRootKeyResponse.read(response)
83
+ rescue IOError
84
+ raise RubySMB::Dcerpc::Error::InvalidPacket,
85
+ "Error reading OpenRootKeyResponse (command = #{root_key_opnum})"
86
+ end
87
+ unless root_key_response_packet.error_status == WindowsError::Win32::ERROR_SUCCESS
88
+ raise RubySMB::Dcerpc::Error::WinregError,
89
+ "Error returned when opening root key #{root_key}: "\
90
+ "#{WindowsError::Win32.find_by_retval(root_key_response_packet.error_status.value).join(',')}"
91
+ end
92
+
93
+ root_key_response_packet.ph_key
94
+ end
95
+
96
+ # Open the registry key specified by a root key handle (previously open
97
+ # with #open_root_key) and a subkey. It returns a handle for the key.
98
+ #
99
+ # @param handle [Ndr::NdrContextHandle] the handle for the root key
100
+ # @param sub_key [String] the subkey to open
101
+ # @return [Ndr::NdrContextHandle] the RPC context handle for the key
102
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenKeyResponse packet
103
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
104
+ def open_key(handle, sub_key)
105
+ openkey_request_packet = RubySMB::Dcerpc::Winreg::OpenKeyRequest.new(hkey: handle, lp_sub_key: sub_key)
106
+ openkey_request_packet.sam_desired.read_control = 1
107
+ openkey_request_packet.sam_desired.key_query_value = 1
108
+ openkey_request_packet.sam_desired.key_enumerate_sub_keys = 1
109
+ openkey_request_packet.sam_desired.key_notify = 1
110
+ response = dcerpc_request(openkey_request_packet)
111
+ begin
112
+ open_key_response = RubySMB::Dcerpc::Winreg::OpenKeyResponse.read(response)
113
+ rescue IOError
114
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the OpenKey response"
115
+ end
116
+ unless open_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
117
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when opening subkey #{sub_key}: "\
118
+ "#{WindowsError::Win32.find_by_retval(open_key_response.error_status.value).join(',')}"
119
+ end
120
+
121
+ open_key_response.phk_result
122
+ end
123
+
124
+ # Retrieve the data associated with the named value of a specified
125
+ # registry open key.
126
+ #
127
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
128
+ # @param value_name [String] the name of the value
129
+ # @return [String] the data of the value entry
130
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryValueResponse packet
131
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
132
+ def query_value(handle, value_name)
133
+ query_value_request_packet = RubySMB::Dcerpc::Winreg::QueryValueRequest.new(hkey: handle, lp_value_name: value_name)
134
+ query_value_request_packet.lp_type = 0
135
+ query_value_request_packet.lpcb_data = 0
136
+ query_value_request_packet.lpcb_len = 0
137
+ response = dcerpc_request(query_value_request_packet)
138
+ begin
139
+ query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
140
+ rescue IOError
141
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
142
+ end
143
+ unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
144
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
145
+ "#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
146
+ end
147
+
148
+ query_value_request_packet.lpcb_data = query_value_response.lpcb_data
149
+ query_value_request_packet.lp_data = []
150
+ query_value_request_packet.lp_data.referent.max_count = query_value_response.lpcb_data.referent
151
+ response = dcerpc_request(query_value_request_packet)
152
+ begin
153
+ query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
154
+ rescue IOError
155
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
156
+ end
157
+ unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
158
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
159
+ "#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
160
+ end
161
+
162
+ query_value_response.data
163
+ end
164
+
165
+ # Close the handle to the registry key.
166
+ #
167
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
168
+ # @return [WindowsError::Win32] the response error status
169
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CloseKeyResponse packet
170
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
171
+ def close_key(handle)
172
+ close_key_request_packet = RubySMB::Dcerpc::Winreg::CloseKeyRequest.new(hkey: handle)
173
+ response = dcerpc_request(close_key_request_packet)
174
+ begin
175
+ close_key_response = RubySMB::Dcerpc::Winreg::CloseKeyResponse.read(response)
176
+ rescue IOError
177
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the CloseKey response"
178
+ end
179
+ unless close_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
180
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when closing the key: "\
181
+ "#{WindowsError::Win32.find_by_retval(close_key_response.error_status.value).join(',')}"
182
+ end
183
+
184
+ close_key_response.error_status
185
+ end
186
+
187
+ # Retrive relevant information on the key that corresponds to the
188
+ # specified key handle.
189
+ #
190
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
191
+ # @return [RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse] the QueryInfoKeyResponse packet
192
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryInfoKeyResponse packet
193
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
194
+ def query_info_key(handle)
195
+ query_info_key_request_packet = RubySMB::Dcerpc::Winreg::QueryInfoKeyRequest.new(hkey: handle)
196
+ query_info_key_request_packet.lp_class = ''
197
+ query_info_key_request_packet.lp_class.referent.actual_count = 0
198
+ query_info_key_request_packet.lp_class.maximum_length = 1024
199
+ query_info_key_request_packet.lp_class.buffer.referent.max_count = 1024 / 2
200
+ response = dcerpc_request(query_info_key_request_packet)
201
+ begin
202
+ query_info_key_response = RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse.read(response)
203
+ rescue IOError
204
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the query_infoKey response"
205
+ end
206
+ unless query_info_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
207
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when querying information: "\
208
+ "#{WindowsError::Win32.find_by_retval(query_info_key_response.error_status.value).join(',')}"
209
+ end
210
+
211
+ query_info_key_response
212
+ end
213
+
214
+ # Enumerate the subkey at the specified index.
215
+ #
216
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
217
+ # @param index [Numeric] the index of the subkey
218
+ # @return [String] the subkey name
219
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a EnumKeyResponse packet
220
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
221
+ def enum_key(handle, index)
222
+ enum_key_request_packet = RubySMB::Dcerpc::Winreg::EnumKeyRequest.new(hkey: handle, dw_index: index)
223
+ enum_key_request_packet.lpft_last_write_time = 0
224
+ enum_key_request_packet.lp_class = ''
225
+ enum_key_request_packet.lp_class.referent.buffer = :null
226
+ enum_key_request_packet.lp_name.buffer = ''
227
+ enum_key_request_packet.lp_name.buffer.referent.max_count = 256
228
+ response = dcerpc_request(enum_key_request_packet)
229
+ begin
230
+ enum_key_response = RubySMB::Dcerpc::Winreg::EnumKeyResponse.read(response)
231
+ rescue IOError
232
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the EnumKey response"
233
+ end
234
+ unless enum_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
235
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating the key: "\
236
+ "#{WindowsError::Win32.find_by_retval(enum_key_response.error_status.value).join(',')}"
237
+ end
238
+
239
+ enum_key_response.lp_name.to_s
240
+ end
241
+
242
+ # Enumerate the value at the specified index for the specified registry key.
243
+ #
244
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
245
+ # @param index [Numeric] the index of the subkey
246
+ # @return [String] the data of the value entry
247
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a EnumValueResponse packet
248
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
249
+ def enum_value(handle, index)
250
+ enum_value_request_packet = RubySMB::Dcerpc::Winreg::EnumValueRequest.new(hkey: handle, dw_index: index)
251
+ enum_value_request_packet.lp_value_name.buffer = ''
252
+ enum_value_request_packet.lp_value_name.buffer.referent.max_count = 256
253
+ response = dcerpc_request(enum_value_request_packet)
254
+ begin
255
+ enum_value_response = RubySMB::Dcerpc::Winreg::EnumValueResponse.read(response)
256
+ rescue IOError
257
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the Enumvalue response"
258
+ end
259
+ unless enum_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
260
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating values: "\
261
+ "#{WindowsError::Win32.find_by_retval(enum_value_response.error_status.value).join(',')}"
262
+ end
263
+
264
+ enum_value_response.lp_value_name.to_s
265
+ end
266
+
267
+ # Creates the specified registry key and returns a handle to the newly created key
268
+ #
269
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
270
+ # @param sub_key [String] the name of the key
271
+ # @param opts [Hash] options for the CreateKeyRequest
272
+ # @return [RubySMB::Dcerpc::Winreg::PrpcHkey] the handle to the opened or created key
273
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CreateKeyResponse packet
274
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
275
+ def create_key(handle, sub_key, opts = {})
276
+ opts = {
277
+ hkey: handle,
278
+ lp_sub_key: sub_key,
279
+ lp_class: opts[:lp_class] || :null,
280
+ dw_options: opts[:dw_options] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
281
+ sam_desired: opts[:sam_desired] || RubySMB::Dcerpc::Winreg::Regsam.new(maximum: 1),
282
+ lp_security_attributes: opts[:lp_security_attributes] || RubySMB::Dcerpc::RpcSecurityAttributes.new,
283
+ lpdw_disposition: opts[:lpdw_disposition] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY,
284
+ }
285
+ create_key_request_packet = RubySMB::Dcerpc::Winreg::CreateKeyRequest.new(opts)
286
+ response = dcerpc_request(create_key_request_packet)
287
+ begin
288
+ create_key_response = RubySMB::Dcerpc::Winreg::CreateKeyResponse.read(response)
289
+ rescue IOError
290
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the CreateKey response"
291
+ end
292
+ unless create_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
293
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when creating key #{sub_key}: "\
294
+ "#{WindowsError::Win32.find_by_retval(create_key_response.error_status.value).join(',')}"
295
+ end
296
+
297
+ create_key_response.hkey
298
+ end
299
+
300
+ # Saves the specified key, subkeys, and values to a new file
301
+ #
302
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
303
+ # @param file_name [String] the name of the registry file in which the specified key and subkeys are to be saved
304
+ # @param opts [Hash] options for the SaveKeyRequest
305
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a SaveKeyResponse packet
306
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
307
+ def save_key(handle, file_name, opts = {})
308
+ opts = {
309
+ hkey: handle,
310
+ lp_file: file_name,
311
+ lp_security_attributes: opts[:lp_security_attributes] || :null,
312
+ }
313
+ save_key_request_packet = RubySMB::Dcerpc::Winreg::SaveKeyRequest.new(opts)
314
+ response = dcerpc_request(save_key_request_packet)
315
+ begin
316
+ save_key_response = RubySMB::Dcerpc::Winreg::SaveKeyResponse.read(response)
317
+ rescue IOError
318
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the SaveKeyResponse response"
319
+ end
320
+ unless save_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
321
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when saving key to #{file_name}: "\
322
+ "#{WindowsError::Win32.find_by_retval(save_key_response.error_status.value).join(',')}"
323
+ end
324
+ end
325
+
326
+ # Checks if the specified registry key exists. It returns true if it
327
+ # exists, false otherwise.
328
+ #
329
+ # @param key [String] the registry key to check
330
+ # @return [Boolean]
331
+ def has_registry_key?(key, bind: true)
332
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
333
+
334
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
335
+ begin
336
+ root_key_handle = open_root_key(root_key)
337
+ subkey_handle = open_key(root_key_handle, sub_key)
338
+ rescue RubySMB::Dcerpc::Error::WinregError
339
+ return false
340
+ end
341
+ return true
342
+ ensure
343
+ close_key(subkey_handle) if subkey_handle
344
+ close_key(root_key_handle) if root_key_handle
345
+ end
346
+
347
+ # Retrieve the data associated with the named value of a specified
348
+ # registry key.
349
+ #
350
+ # @param key [String] the registry key
351
+ # @param value_name [String] the name of the value to read
352
+ # @return [String] the data of the value entry
353
+ def read_registry_key_value(key, value_name, bind: true)
354
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
355
+
356
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
357
+ root_key_handle = open_root_key(root_key)
358
+ subkey_handle = open_key(root_key_handle, sub_key)
359
+ value = query_value(subkey_handle, value_name)
360
+ value
361
+ ensure
362
+ close_key(subkey_handle) if subkey_handle
363
+ close_key(root_key_handle) if root_key_handle
364
+ end
365
+
366
+ # Enumerate the subkeys of a specified registry key. If only a root key
367
+ # is provided, it enumerates its subkeys.
368
+ #
369
+ # @param key [String] the registry key
370
+ # @return [Array<String>] the subkeys
371
+ def enum_registry_key(key, bind: true)
372
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
373
+
374
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
375
+ root_key_handle = open_root_key(root_key)
376
+ subkey_handle = if sub_key.nil? || sub_key.empty?
377
+ root_key_handle
378
+ else
379
+ open_key(root_key_handle, sub_key)
380
+ end
381
+ query_info_key_response = query_info_key(subkey_handle)
382
+ key_count = query_info_key_response.lpc_sub_keys.to_i
383
+ enum_result = []
384
+ key_count.times do |i|
385
+ enum_result << enum_key(subkey_handle, i)
386
+ end
387
+ enum_result
388
+ ensure
389
+ close_key(subkey_handle) if subkey_handle
390
+ close_key(root_key_handle) if root_key_handle
391
+ end
392
+
393
+ # Enumerate the values for the specified registry key.
394
+ #
395
+ # @param key [String] the registry key
396
+ # @return [Array<String>] the values
397
+ def enum_registry_values(key, bind: true)
398
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
399
+
400
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
401
+ root_key_handle = open_root_key(root_key)
402
+ subkey_handle = if sub_key.nil? || sub_key.empty?
403
+ root_key_handle
404
+ else
405
+ open_key(root_key_handle, sub_key)
406
+ end
407
+ query_info_key_response = query_info_key(subkey_handle)
408
+ value_count = query_info_key_response.lpc_values.to_i
409
+ enum_result = []
410
+ value_count.times do |i|
411
+ enum_result << enum_value(subkey_handle, i)
412
+ end
413
+ enum_result
414
+ ensure
415
+ close_key(subkey_handle) if subkey_handle
416
+ close_key(root_key_handle) if root_key_handle
417
+ end
418
+
419
+ end
420
+ end
421
+ end