ruby_smb 1.0.3 → 2.0.1
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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +3 -2
- data/Gemfile +6 -2
- data/README.md +35 -47
- data/examples/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/negotiate.rb +51 -8
- data/examples/pipes.rb +2 -1
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb.rb +4 -1
- data/lib/ruby_smb/client.rb +233 -22
- data/lib/ruby_smb/client/authentication.rb +70 -33
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +172 -24
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +24 -18
- data/lib/ruby_smb/client/utils.rb +8 -7
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/dispatcher/socket.rb +4 -3
- data/lib/ruby_smb/error.rb +68 -2
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +66 -15
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +3 -6
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +87 -6
- data/lib/ruby_smb/smb1/tree.rb +50 -3
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
- data/lib/ruby_smb/smb2/file.rb +103 -25
- data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -17
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +52 -5
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +93 -10
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +10 -22
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +86 -12
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +65 -21
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1612 -108
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +323 -6
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
- data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +78 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -22
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +286 -149
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +261 -2
- metadata +191 -83
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -0,0 +1,113 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :lp_class }
|
5
|
+
it { is_expected.to respond_to :pad }
|
6
|
+
it { is_expected.to respond_to :lpc_sub_keys }
|
7
|
+
it { is_expected.to respond_to :lpc_max_sub_key_len }
|
8
|
+
it { is_expected.to respond_to :lpc_max_class_len }
|
9
|
+
it { is_expected.to respond_to :lpc_values }
|
10
|
+
it { is_expected.to respond_to :lpcb_max_value_name_len }
|
11
|
+
it { is_expected.to respond_to :lpcb_max_value_len }
|
12
|
+
it { is_expected.to respond_to :lpcb_security_descriptor }
|
13
|
+
it { is_expected.to respond_to :lpft_last_write_time }
|
14
|
+
it { is_expected.to respond_to :error_status }
|
15
|
+
it { is_expected.to respond_to :opnum }
|
16
|
+
|
17
|
+
it 'is little endian' do
|
18
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#lp_class' do
|
22
|
+
it 'is a RrpUnicodeString structure' do
|
23
|
+
expect(packet.lp_class).to be_a RubySMB::Dcerpc::RrpUnicodeString
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'has an initial value of 0' do
|
27
|
+
expect(packet.lp_class).to eq(0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#pad' do
|
32
|
+
it 'is a string' do
|
33
|
+
expect(packet.pad).to be_a BinData::String
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should keep #lpc_sub_keys 4-byte aligned' do
|
37
|
+
packet.lp_class = 'test'
|
38
|
+
expect(packet.lpc_sub_keys.abs_offset % 4).to eq 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#lpc_sub_keys' do
|
43
|
+
it 'is a 32-bit unsigned integer' do
|
44
|
+
expect(packet.lpc_sub_keys).to be_a BinData::Uint32le
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#lpc_max_sub_key_len' do
|
49
|
+
it 'is a 32-bit unsigned integer' do
|
50
|
+
expect(packet.lpc_max_sub_key_len).to be_a BinData::Uint32le
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#lpc_max_class_len' do
|
55
|
+
it 'is a 32-bit unsigned integer' do
|
56
|
+
expect(packet.lpc_max_class_len).to be_a BinData::Uint32le
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#lpc_values' do
|
61
|
+
it 'is a 32-bit unsigned integer' do
|
62
|
+
expect(packet.lpc_values).to be_a BinData::Uint32le
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#lpcb_max_value_name_len' do
|
67
|
+
it 'is a 32-bit unsigned integer' do
|
68
|
+
expect(packet.lpcb_max_value_name_len).to be_a BinData::Uint32le
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#lpcb_max_value_len' do
|
73
|
+
it 'is a 32-bit unsigned integer' do
|
74
|
+
expect(packet.lpcb_max_value_len).to be_a BinData::Uint32le
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#lpcb_security_descriptor' do
|
79
|
+
it 'is a 32-bit unsigned integer' do
|
80
|
+
expect(packet.lpcb_security_descriptor).to be_a BinData::Uint32le
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#lpft_last_write_time' do
|
85
|
+
it 'is a FileTime structure' do
|
86
|
+
expect(packet.lpft_last_write_time).to be_a RubySMB::Field::FileTime
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#error_status' do
|
91
|
+
it 'is a 32-bit unsigned integer' do
|
92
|
+
expect(packet.error_status).to be_a BinData::Uint32le
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#initialize_instance' do
|
97
|
+
it 'sets #opnum to REG_QUERY_INFO_KEY constant' do
|
98
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_QUERY_INFO_KEY)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#pad_length' do
|
103
|
+
it 'returns 0 when #lpc_sub_keys is already 4-byte aligned' do
|
104
|
+
packet.lp_class = 'align'
|
105
|
+
expect(packet.pad_length).to eq 0
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'returns 2 when #lpc_sub_keys is only 2-byte aligned' do
|
109
|
+
packet.lp_class = 'align' + 'A'
|
110
|
+
expect(packet.pad_length).to eq 2
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::RpcHkey do
|
2
|
+
it 'is NdrContextHandle subclass' do
|
3
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrContextHandle
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::QueryValueRequest do
|
8
|
+
subject(:packet) { described_class.new }
|
9
|
+
|
10
|
+
it { is_expected.to respond_to :hkey }
|
11
|
+
it { is_expected.to respond_to :lp_value_name }
|
12
|
+
it { is_expected.to respond_to :pad }
|
13
|
+
it { is_expected.to respond_to :lp_type }
|
14
|
+
it { is_expected.to respond_to :lp_data }
|
15
|
+
it { is_expected.to respond_to :lpcb_data }
|
16
|
+
it { is_expected.to respond_to :lpcb_len }
|
17
|
+
it { is_expected.to respond_to :opnum }
|
18
|
+
|
19
|
+
it 'is little endian' do
|
20
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#hkey' do
|
24
|
+
it 'is a RpcHkey structure' do
|
25
|
+
expect(packet.hkey).to be_a RubySMB::Dcerpc::Winreg::RpcHkey
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#lp_value_name' do
|
30
|
+
it 'is a RrpUnicodeString structure' do
|
31
|
+
expect(packet.lp_value_name).to be_a RubySMB::Dcerpc::RrpUnicodeString
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#pad' do
|
36
|
+
it 'is a string' do
|
37
|
+
expect(packet.pad).to be_a BinData::String
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should keep #lp_type 4-byte aligned' do
|
41
|
+
packet.lp_value_name = 'test'
|
42
|
+
expect(packet.lp_type.abs_offset % 4).to eq 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#lp_type' do
|
47
|
+
it 'is a NdrLpDword structure' do
|
48
|
+
expect(packet.lp_type).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#lp_data' do
|
53
|
+
it 'is a NdrLpByte structure' do
|
54
|
+
expect(packet.lp_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpByte
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#lpcb_data' do
|
59
|
+
it 'is a NdrLpDword structure' do
|
60
|
+
expect(packet.lpcb_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#lpcb_len' do
|
65
|
+
it 'is a NdrLpDword structure' do
|
66
|
+
expect(packet.lpcb_len).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#initialize_instance' do
|
71
|
+
it 'sets #opnum to REG_QUERY_VALUE constant' do
|
72
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_QUERY_VALUE)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#pad_length' do
|
77
|
+
it 'returns 0 when #lp_type is already 4-byte aligned' do
|
78
|
+
packet.lp_value_name = 'align'
|
79
|
+
expect(packet.pad_length).to eq 0
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns 2 when #lp_type is only 2-byte aligned' do
|
83
|
+
packet.lp_value_name = 'align' + 'A'
|
84
|
+
expect(packet.pad_length).to eq 2
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,150 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::QueryValueResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :lp_type }
|
5
|
+
it { is_expected.to respond_to :lp_data }
|
6
|
+
it { is_expected.to respond_to :pad }
|
7
|
+
it { is_expected.to respond_to :lpcb_data }
|
8
|
+
it { is_expected.to respond_to :lpcb_len }
|
9
|
+
it { is_expected.to respond_to :error_status }
|
10
|
+
it { is_expected.to respond_to :opnum }
|
11
|
+
|
12
|
+
it 'is little endian' do
|
13
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#lp_type' do
|
17
|
+
it 'is a NdrLpDword structure' do
|
18
|
+
expect(packet.lp_type).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#lp_data' do
|
23
|
+
it 'is a NdrLpByte structure' do
|
24
|
+
expect(packet.lp_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpByte
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#pad' do
|
29
|
+
it 'is a string' do
|
30
|
+
expect(packet.pad).to be_a BinData::String
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should keep #lpcb_data 4-byte aligned' do
|
34
|
+
packet.lp_data.bytes = 'spec_test'.bytes
|
35
|
+
expect(packet.lpcb_data.abs_offset % 4).to eq 0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#lpcb_data' do
|
40
|
+
it 'is a NdrLpDword structure' do
|
41
|
+
expect(packet.lpcb_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#lpcb_len' do
|
46
|
+
it 'is a NdrLpDword structure' do
|
47
|
+
expect(packet.lpcb_len).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#error_status' do
|
52
|
+
it 'is a 32-bit unsigned integer' do
|
53
|
+
expect(packet.error_status).to be_a BinData::Uint32le
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#initialize_instance' do
|
58
|
+
it 'sets #opnum to REG_QUERY_VALUE constant' do
|
59
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_QUERY_VALUE)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#pad_length' do
|
64
|
+
it 'returns 0 when #lpcb_data is already 4-byte aligned' do
|
65
|
+
packet.lp_data.bytes = 'aligned.'.bytes
|
66
|
+
expect(packet.pad_length).to eq 0
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns 2 when #lpcb_data is only 2-byte aligned' do
|
70
|
+
packet.lp_data.bytes = 'not aligned'.bytes
|
71
|
+
expect(packet.pad_length).to eq 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#data' do
|
76
|
+
context 'when #lp_type is 1 (unicode null-terminated string)' do
|
77
|
+
it 'returns the expected value' do
|
78
|
+
str = 'spec test string'.encode('utf-16le')
|
79
|
+
packet.lp_type = 1
|
80
|
+
packet.lp_data.bytes = str.bytes
|
81
|
+
expect(packet.data).to eq(str)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when #lp_type is 2 (unicode null-terminated string with unexpanded references to environment variables)' do
|
86
|
+
it 'returns the expected value' do
|
87
|
+
str = '/%PATH%/foo'.encode('utf-16le')
|
88
|
+
packet.lp_type = 2
|
89
|
+
packet.lp_data.bytes = str.bytes
|
90
|
+
expect(packet.data).to eq(str)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when #lp_type is 3 (binary data)' do
|
95
|
+
it 'returns the expected value' do
|
96
|
+
bytes = [0xFF, 0xEE, 0xDD, 0xCC].pack('C*')
|
97
|
+
packet.lp_type = 3
|
98
|
+
packet.lp_data.bytes = bytes.bytes
|
99
|
+
expect(packet.data).to eq(bytes)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when #lp_type is 4 (a 32-bit number in little-endian format)' do
|
104
|
+
it 'returns the expected value' do
|
105
|
+
number = 12345
|
106
|
+
packet.lp_type = 4
|
107
|
+
packet.lp_data.bytes = [number].pack('V').bytes
|
108
|
+
expect(packet.data).to eq(number)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'when #lp_type is 5 (a 32-bit number in big-endian format)' do
|
113
|
+
it 'returns the expected value' do
|
114
|
+
number = 12345
|
115
|
+
packet.lp_type = 5
|
116
|
+
packet.lp_data.bytes = [number].pack('N').bytes
|
117
|
+
expect(packet.data).to eq(number)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when #lp_type is 7 (a sequence of unicode null-terminated strings, terminated by an empty string)' do
|
122
|
+
it 'returns the expected value' do
|
123
|
+
str_array = ['String1', 'String2', 'String3', 'LastString'].map {|v| v.encode('utf-16le')}
|
124
|
+
null_byte = "\0".encode('utf-16le')
|
125
|
+
str = (str_array + [null_byte]).join(null_byte)
|
126
|
+
packet.lp_type = 7
|
127
|
+
packet.lp_data.bytes = str.bytes
|
128
|
+
expect(packet.data).to eq(str_array)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when #lp_type is 11 (a 64-bit number in little-endian format)' do
|
133
|
+
it 'returns the expected value' do
|
134
|
+
number = 0x1234567812345678
|
135
|
+
packet.lp_type = 11
|
136
|
+
packet.lp_data.bytes = [number].pack('Q<').bytes
|
137
|
+
expect(packet.data).to eq(number)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when #lp_type is an unknown value' do
|
142
|
+
it 'returns an empty string' do
|
143
|
+
str = 'test'
|
144
|
+
packet.lp_type = 6
|
145
|
+
packet.lp_data.bytes = str.bytes
|
146
|
+
expect(packet.data).to eq('')
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg::Regsam do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :reserved }
|
5
|
+
it { is_expected.to respond_to :key_create_link }
|
6
|
+
it { is_expected.to respond_to :key_notify }
|
7
|
+
it { is_expected.to respond_to :key_enumerate_sub_keys }
|
8
|
+
it { is_expected.to respond_to :key_create_sub_key }
|
9
|
+
it { is_expected.to respond_to :key_set_value }
|
10
|
+
it { is_expected.to respond_to :key_query_value }
|
11
|
+
it { is_expected.to respond_to :reserved2 }
|
12
|
+
it { is_expected.to respond_to :key_wow64_32key }
|
13
|
+
it { is_expected.to respond_to :key_wow64_64key }
|
14
|
+
it { is_expected.to respond_to :reserved3 }
|
15
|
+
it { is_expected.to respond_to :synchronize }
|
16
|
+
it { is_expected.to respond_to :write_owner }
|
17
|
+
it { is_expected.to respond_to :write_dac }
|
18
|
+
it { is_expected.to respond_to :read_control }
|
19
|
+
it { is_expected.to respond_to :delete_access }
|
20
|
+
it { is_expected.to respond_to :generic_read }
|
21
|
+
it { is_expected.to respond_to :generic_write }
|
22
|
+
it { is_expected.to respond_to :generic_execute }
|
23
|
+
it { is_expected.to respond_to :generic_all }
|
24
|
+
it { is_expected.to respond_to :reserved4 }
|
25
|
+
it { is_expected.to respond_to :maximum }
|
26
|
+
it { is_expected.to respond_to :system_security }
|
27
|
+
|
28
|
+
|
29
|
+
it 'is little endian' do
|
30
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,710 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Winreg do
|
2
|
+
let(:winreg) do
|
3
|
+
RubySMB::SMB1::Pipe.new(
|
4
|
+
tree: double('Tree'),
|
5
|
+
response: RubySMB::SMB1::Packet::NtCreateAndxResponse.new,
|
6
|
+
name: 'winreg'
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#open_root_key' do
|
11
|
+
let(:root_key_request_packet) { double('Root Key Request Packet') }
|
12
|
+
let(:response) { double('Response') }
|
13
|
+
let(:root_key_response_packet) { double('Root Key Response Packet') }
|
14
|
+
let(:ph_key) { double('PHKEY') }
|
15
|
+
before :example do
|
16
|
+
allow(described_class::OpenRootKeyRequest).to receive(:new).and_return(root_key_request_packet)
|
17
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
18
|
+
allow(described_class::OpenRootKeyResponse).to receive(:read).and_return(root_key_response_packet)
|
19
|
+
allow(root_key_response_packet).to receive_messages(
|
20
|
+
:error_status => WindowsError::Win32::ERROR_SUCCESS,
|
21
|
+
:ph_key => ph_key
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when the root key is unknown' do
|
26
|
+
it 'raises an ArgumentError exception' do
|
27
|
+
expect { winreg.open_root_key('UNKNOWN') }.to raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'create the expected OpenRootKeyRequest packet' do
|
32
|
+
winreg.open_root_key('HKLM')
|
33
|
+
expect(described_class::OpenRootKeyRequest).to have_received(:new).with(opnum: described_class::OPEN_HKLM)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sends the expected dcerpc request' do
|
37
|
+
winreg.open_root_key('HKLM')
|
38
|
+
expect(winreg).to have_received(:dcerpc_request).with(root_key_request_packet)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'creates a OpenRootKeyResponse structure from the expected dcerpc response' do
|
42
|
+
winreg.open_root_key('HKLM')
|
43
|
+
expect(described_class::OpenRootKeyResponse).to have_received(:read).with(response)
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when an IOError occurs while parsing the response' do
|
47
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
48
|
+
allow(described_class::OpenRootKeyResponse).to receive(:read).and_raise(IOError)
|
49
|
+
expect { winreg.open_root_key('HKLM') }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
54
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
55
|
+
allow(root_key_response_packet).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
56
|
+
expect { winreg.open_root_key('HKLM') }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns the expected handler' do
|
61
|
+
expect(winreg.open_root_key('HKLM')).to eq(ph_key)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#open_key' do
|
66
|
+
let(:handle) { double('Handle') }
|
67
|
+
let(:sub_key) { double('Sub-key') }
|
68
|
+
let(:openkey_request_packet) { double('OpenKey Request Packet') }
|
69
|
+
let(:regsam) { double('Regsam') }
|
70
|
+
let(:response) { double('Response') }
|
71
|
+
let(:open_key_response) { double('OpenKey Response') }
|
72
|
+
let(:phk_result) { double('Phk Result') }
|
73
|
+
before :example do
|
74
|
+
allow(described_class::OpenKeyRequest).to receive(:new).and_return(openkey_request_packet)
|
75
|
+
allow(openkey_request_packet).to receive(:sam_desired).and_return(regsam)
|
76
|
+
allow(regsam).to receive_messages(
|
77
|
+
:read_control= => nil,
|
78
|
+
:key_query_value= => nil,
|
79
|
+
:key_enumerate_sub_keys= => nil,
|
80
|
+
:key_notify= => nil,
|
81
|
+
)
|
82
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
83
|
+
allow(described_class::OpenKeyResponse).to receive(:read).and_return(open_key_response)
|
84
|
+
allow(open_key_response).to receive_messages(
|
85
|
+
:error_status => WindowsError::Win32::ERROR_SUCCESS,
|
86
|
+
:phk_result => phk_result
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'create the expected OpenKeyRequest packet' do
|
91
|
+
winreg.open_key(handle, sub_key)
|
92
|
+
expect(described_class::OpenKeyRequest).to have_received(:new).with(hkey: handle, lp_sub_key: sub_key)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'sets the expected user rights on the request packet' do
|
96
|
+
winreg.open_key(handle, sub_key)
|
97
|
+
expect(regsam).to have_received(:read_control=).with(1)
|
98
|
+
expect(regsam).to have_received(:key_query_value=).with(1)
|
99
|
+
expect(regsam).to have_received(:key_enumerate_sub_keys=).with(1)
|
100
|
+
expect(regsam).to have_received(:key_notify=).with(1)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'sends the expected dcerpc request' do
|
104
|
+
winreg.open_key(handle, sub_key)
|
105
|
+
expect(winreg).to have_received(:dcerpc_request).with(openkey_request_packet)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'creates a OpenKeyResponse structure from the expected dcerpc response' do
|
109
|
+
winreg.open_key(handle, sub_key)
|
110
|
+
expect(described_class::OpenKeyResponse).to have_received(:read).with(response)
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when an IOError occurs while parsing the response' do
|
114
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
115
|
+
allow(described_class::OpenKeyResponse).to receive(:read).and_raise(IOError)
|
116
|
+
expect { winreg.open_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
121
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
122
|
+
allow(open_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
123
|
+
expect { winreg.open_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'returns the expected handler' do
|
128
|
+
expect(winreg.open_key(handle, sub_key)).to eq(phk_result)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#query_value' do
|
133
|
+
let(:handle) { double('Handle') }
|
134
|
+
let(:value_name) { double('Value Name') }
|
135
|
+
let(:query_value_request_packet1) { double('Query Value Request Packet #1') }
|
136
|
+
let(:query_value_request_packet2) { double('Query Value Request Packet #2') }
|
137
|
+
let(:lp_data1) { double('LpData #1') }
|
138
|
+
let(:lp_data2) { double('LpData #2') }
|
139
|
+
let(:response1) { double('Response #1') }
|
140
|
+
let(:response2) { double('Response #2') }
|
141
|
+
let(:query_value_response1) { double('Query Value Response #1') }
|
142
|
+
let(:query_value_response2) { double('Query Value Response #2') }
|
143
|
+
let(:data) { double('Data') }
|
144
|
+
let(:lpcb_data) { double('LpcbData') }
|
145
|
+
let(:lpcb_data_referent) { double('Lpcb Data Referent') }
|
146
|
+
before :example do
|
147
|
+
first_request = true
|
148
|
+
allow(described_class::QueryValueRequest).to receive(:new) do
|
149
|
+
if first_request
|
150
|
+
first_request = false
|
151
|
+
query_value_request_packet1
|
152
|
+
else
|
153
|
+
query_value_request_packet2
|
154
|
+
end
|
155
|
+
end
|
156
|
+
allow(query_value_request_packet1).to receive(:lp_data).and_return(lp_data1)
|
157
|
+
allow(query_value_request_packet2).to receive_messages(
|
158
|
+
:lp_data => lp_data2,
|
159
|
+
:lpcb_data= => nil
|
160
|
+
)
|
161
|
+
allow(lp_data1).to receive(:referent_identifier=)
|
162
|
+
allow(lp_data2).to receive(:max_count=)
|
163
|
+
allow(winreg).to receive(:dcerpc_request).with(query_value_request_packet1).and_return(response1)
|
164
|
+
allow(winreg).to receive(:dcerpc_request).with(query_value_request_packet2).and_return(response2)
|
165
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_return(query_value_response1)
|
166
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_return(query_value_response2)
|
167
|
+
allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
168
|
+
allow(query_value_response2).to receive_messages(
|
169
|
+
:error_status => WindowsError::Win32::ERROR_SUCCESS,
|
170
|
+
:data => data
|
171
|
+
)
|
172
|
+
allow(query_value_response1).to receive(:lpcb_data).and_return(lpcb_data)
|
173
|
+
allow(lpcb_data).to receive(:referent).and_return(lpcb_data_referent)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'create the expected QueryValueRequest packets' do
|
177
|
+
winreg.query_value(handle, value_name)
|
178
|
+
expect(described_class::QueryValueRequest).to have_received(:new).with(hkey: handle, lp_value_name: value_name).twice
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'sets the expected user rights on the first request packet' do
|
182
|
+
winreg.query_value(handle, value_name)
|
183
|
+
expect(lp_data1).to have_received(:referent_identifier=).with(0)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'sets the expected user rights on the second request packet' do
|
187
|
+
winreg.query_value(handle, value_name)
|
188
|
+
expect(lp_data2).to have_received(:max_count=).with(lpcb_data_referent)
|
189
|
+
expect(query_value_request_packet2).to have_received(:lpcb_data=).with(lpcb_data)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'sends the expected dcerpc requests' do
|
193
|
+
winreg.query_value(handle, value_name)
|
194
|
+
expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet1).once.ordered
|
195
|
+
expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet2).once.ordered
|
196
|
+
end
|
197
|
+
|
198
|
+
context 'when receiving the first response' do
|
199
|
+
it 'creates a QueryValueResponse structure from the expected dcerpc response' do
|
200
|
+
winreg.query_value(handle, value_name)
|
201
|
+
expect(described_class::QueryValueResponse).to have_received(:read).with(response1)
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'when an IOError occurs while parsing the response' do
|
205
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
206
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_raise(IOError)
|
207
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'when the first response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
212
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
213
|
+
allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
214
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'when receiving the second response' do
|
220
|
+
it 'creates a QueryValueResponse structure from the expected dcerpc response' do
|
221
|
+
winreg.query_value(handle, value_name)
|
222
|
+
expect(described_class::QueryValueResponse).to have_received(:read).with(response2)
|
223
|
+
end
|
224
|
+
|
225
|
+
context 'when an IOError occurs while parsing the response' do
|
226
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
227
|
+
allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_raise(IOError)
|
228
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'when the first response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
233
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
234
|
+
allow(query_value_response2).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
235
|
+
expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'returns the expected response data' do
|
241
|
+
expect(winreg.query_value(handle, value_name)).to eq(data)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe '#close_key' do
|
246
|
+
let(:handle) { double('Handle') }
|
247
|
+
let(:close_key_request_packet) { double('CloseKey Request Packet') }
|
248
|
+
let(:response) { double('Response') }
|
249
|
+
let(:close_key_response) { double('CloseKey Response') }
|
250
|
+
before :example do
|
251
|
+
allow(described_class::CloseKeyRequest).to receive(:new).and_return(close_key_request_packet)
|
252
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
253
|
+
allow(described_class::CloseKeyResponse).to receive(:read).and_return(close_key_response)
|
254
|
+
allow(close_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'create the expected CloseKeyRequest packet' do
|
258
|
+
winreg.close_key(handle)
|
259
|
+
expect(described_class::CloseKeyRequest).to have_received(:new).with(hkey: handle)
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'sends the expected dcerpc request' do
|
263
|
+
winreg.close_key(handle)
|
264
|
+
expect(winreg).to have_received(:dcerpc_request).with(close_key_request_packet)
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'creates a CloseKeyResponse structure from the expected dcerpc response' do
|
268
|
+
winreg.close_key(handle)
|
269
|
+
expect(described_class::CloseKeyResponse).to have_received(:read).with(response)
|
270
|
+
end
|
271
|
+
|
272
|
+
context 'when an IOError occurs while parsing the response' do
|
273
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
274
|
+
allow(described_class::CloseKeyResponse).to receive(:read).and_raise(IOError)
|
275
|
+
expect { winreg.close_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
280
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
281
|
+
allow(close_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
282
|
+
expect { winreg.close_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'returns the expected error status' do
|
287
|
+
expect(winreg.close_key(handle)).to eq(WindowsError::Win32::ERROR_SUCCESS)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe '#query_info_key' do
|
292
|
+
let(:handle) { double('Handle') }
|
293
|
+
let(:query_info_key_request_packet) { double('CloseKey Request Packet') }
|
294
|
+
let(:response) { double('Response') }
|
295
|
+
let(:query_info_key_response) { double('CloseKey Response') }
|
296
|
+
before :example do
|
297
|
+
allow(described_class::QueryInfoKeyRequest).to receive(:new).and_return(query_info_key_request_packet)
|
298
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
299
|
+
allow(described_class::QueryInfoKeyResponse).to receive(:read).and_return(query_info_key_response)
|
300
|
+
allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'create the expected QueryInfoKeyRequest packet' do
|
304
|
+
winreg.query_info_key(handle)
|
305
|
+
expect(described_class::QueryInfoKeyRequest).to have_received(:new).with(hkey: handle)
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'sends the expected dcerpc request' do
|
309
|
+
winreg.query_info_key(handle)
|
310
|
+
expect(winreg).to have_received(:dcerpc_request).with(query_info_key_request_packet)
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'creates a QueryInfoKeyResponse structure from the expected dcerpc response' do
|
314
|
+
winreg.query_info_key(handle)
|
315
|
+
expect(described_class::QueryInfoKeyResponse).to have_received(:read).with(response)
|
316
|
+
end
|
317
|
+
|
318
|
+
context 'when an IOError occurs while parsing the response' do
|
319
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
320
|
+
allow(described_class::QueryInfoKeyResponse).to receive(:read).and_raise(IOError)
|
321
|
+
expect { winreg.query_info_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
326
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
327
|
+
allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
328
|
+
expect { winreg.query_info_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'returns the expected response' do
|
333
|
+
expect(winreg.query_info_key(handle)).to eq(query_info_key_response)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe '#enum_key' do
|
338
|
+
let(:handle) { double('Handle') }
|
339
|
+
let(:index) { double('Index') }
|
340
|
+
let(:enum_key_request_packet) { double('enum_key Request Packet') }
|
341
|
+
let(:lp_class) { double('Lp Class') }
|
342
|
+
let(:lp_name) { double('Lp Name') }
|
343
|
+
let(:buffer) { double('Buffer') }
|
344
|
+
let(:lp_class_buffer_referent) { double('Lp Class buffer referent') }
|
345
|
+
let(:lp_name_buffer_referent) { double('Lp Name buffer referent') }
|
346
|
+
let(:response) { double('Response') }
|
347
|
+
let(:enum_key_response) { double('enum_key Response') }
|
348
|
+
let(:result_str) { double('Result String') }
|
349
|
+
before :example do
|
350
|
+
allow(described_class::EnumKeyRequest).to receive(:new).and_return(enum_key_request_packet)
|
351
|
+
allow(enum_key_request_packet).to receive_messages(
|
352
|
+
:lpft_last_write_time= => nil,
|
353
|
+
:lp_class => lp_class,
|
354
|
+
:lp_name => lp_name
|
355
|
+
)
|
356
|
+
allow(lp_class).to receive(:referent).and_return(lp_class_buffer_referent)
|
357
|
+
allow(lp_name).to receive(:buffer).and_return(buffer)
|
358
|
+
allow(buffer).to receive(:referent).and_return(lp_name_buffer_referent)
|
359
|
+
allow(lp_class_buffer_referent).to receive(:buffer=)
|
360
|
+
allow(lp_name_buffer_referent).to receive(:max_count=)
|
361
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
362
|
+
allow(described_class::EnumKeyResponse).to receive(:read).and_return(enum_key_response)
|
363
|
+
allow(enum_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
364
|
+
allow(enum_key_response).to receive_message_chain(:lp_name, :to_s => result_str)
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'create the expected EnumKeyRequest packet' do
|
368
|
+
winreg.enum_key(handle, index)
|
369
|
+
expect(described_class::EnumKeyRequest).to have_received(:new).with(hkey: handle, dw_index: index)
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'sets the expected user rights on the request packet' do
|
373
|
+
winreg.enum_key(handle, index)
|
374
|
+
expect(enum_key_request_packet).to have_received(:lpft_last_write_time=).with(0)
|
375
|
+
expect(lp_class_buffer_referent).to have_received(:buffer=).with(0)
|
376
|
+
expect(lp_name_buffer_referent).to have_received(:max_count=).with(256)
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'sends the expected dcerpc request' do
|
380
|
+
winreg.enum_key(handle, index)
|
381
|
+
expect(winreg).to have_received(:dcerpc_request).with(enum_key_request_packet)
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'creates a EnumKeyResponse structure from the expected dcerpc response' do
|
385
|
+
winreg.enum_key(handle, index)
|
386
|
+
expect(described_class::EnumKeyResponse).to have_received(:read).with(response)
|
387
|
+
end
|
388
|
+
|
389
|
+
context 'when an IOError occurs while parsing the response' do
|
390
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
391
|
+
allow(described_class::EnumKeyResponse).to receive(:read).and_raise(IOError)
|
392
|
+
expect { winreg.enum_key(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
397
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
398
|
+
allow(enum_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
399
|
+
expect { winreg.enum_key(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'returns the expected key name' do
|
404
|
+
expect(winreg.enum_key(handle, index)).to eq(result_str)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
describe '#enum_value' do
|
409
|
+
let(:handle) { double('Handle') }
|
410
|
+
let(:index) { double('Index') }
|
411
|
+
let(:enum_value_request_packet) { double('EnumValue Request Packet') }
|
412
|
+
let(:lp_value_name) { double('Lp Value Name') }
|
413
|
+
let(:lp_data) { double('Lp Data') }
|
414
|
+
let(:buffer) { double('Buffer') }
|
415
|
+
let(:referent) { double('Referent') }
|
416
|
+
let(:response) { double('Response') }
|
417
|
+
let(:enum_value_response) { double('EnumValue Response') }
|
418
|
+
let(:result_str) { double('Result String') }
|
419
|
+
before :example do
|
420
|
+
allow(described_class::EnumValueRequest).to receive(:new).and_return(enum_value_request_packet)
|
421
|
+
allow(enum_value_request_packet).to receive_messages(
|
422
|
+
:lp_value_name => lp_value_name,
|
423
|
+
:lp_data => lp_data
|
424
|
+
)
|
425
|
+
allow(lp_value_name).to receive(:buffer).and_return(buffer)
|
426
|
+
allow(buffer).to receive(:referent).and_return(referent)
|
427
|
+
allow(referent).to receive(:max_count=)
|
428
|
+
allow(lp_data).to receive(:referent_identifier=)
|
429
|
+
allow(winreg).to receive(:dcerpc_request).and_return(response)
|
430
|
+
allow(described_class::EnumValueResponse).to receive(:read).and_return(enum_value_response)
|
431
|
+
allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
|
432
|
+
allow(enum_value_response).to receive_message_chain(:lp_value_name, :to_s => result_str)
|
433
|
+
end
|
434
|
+
|
435
|
+
it 'create the expected EnumValueRequest packet' do
|
436
|
+
winreg.enum_value(handle, index)
|
437
|
+
expect(described_class::EnumValueRequest).to have_received(:new).with(hkey: handle, dw_index: index)
|
438
|
+
end
|
439
|
+
|
440
|
+
it 'sets the expected user rights on the request packet' do
|
441
|
+
winreg.enum_value(handle, index)
|
442
|
+
expect(referent).to have_received(:max_count=).with(256)
|
443
|
+
expect(lp_data).to have_received(:referent_identifier=).with(0)
|
444
|
+
end
|
445
|
+
|
446
|
+
it 'sends the expected dcerpc request' do
|
447
|
+
winreg.enum_value(handle, index)
|
448
|
+
expect(winreg).to have_received(:dcerpc_request).with(enum_value_request_packet)
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'creates a EnumValueResponse structure from the expected dcerpc response' do
|
452
|
+
winreg.enum_value(handle, index)
|
453
|
+
expect(described_class::EnumValueResponse).to have_received(:read).with(response)
|
454
|
+
end
|
455
|
+
|
456
|
+
context 'when an IOError occurs while parsing the response' do
|
457
|
+
it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
|
458
|
+
allow(described_class::EnumValueResponse).to receive(:read).and_raise(IOError)
|
459
|
+
expect { winreg.enum_value(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
|
464
|
+
it 'raises a RubySMB::Dcerpc::Error::WinregError' do
|
465
|
+
allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
|
466
|
+
expect { winreg.enum_value(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'returns the expected key name' do
|
471
|
+
expect(winreg.enum_value(handle, index)).to eq(result_str)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
describe '#has_registry_key?' do
|
476
|
+
let(:root_key) { 'HKLM' }
|
477
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
478
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
479
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
480
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
481
|
+
before :example do
|
482
|
+
allow(winreg).to receive_messages(
|
483
|
+
:bind => nil,
|
484
|
+
:open_root_key => root_key_handle,
|
485
|
+
:open_key => subkey_handle,
|
486
|
+
:close_key => nil
|
487
|
+
)
|
488
|
+
end
|
489
|
+
|
490
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
491
|
+
winreg.has_registry_key?(key)
|
492
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
493
|
+
end
|
494
|
+
|
495
|
+
it 'opens the expected root key' do
|
496
|
+
winreg.has_registry_key?(key)
|
497
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'opens the expected registry key' do
|
501
|
+
winreg.has_registry_key?(key)
|
502
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
503
|
+
end
|
504
|
+
|
505
|
+
context 'when a WinregError occurs while opening the root key' do
|
506
|
+
it 'returns false' do
|
507
|
+
allow(winreg).to receive(:open_root_key).and_raise(RubySMB::Dcerpc::Error::WinregError)
|
508
|
+
expect(winreg.has_registry_key?(key)).to be false
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
context 'when a WinregError occurs while opening the registry key' do
|
513
|
+
it 'returns false' do
|
514
|
+
allow(winreg).to receive(:open_key).and_raise(RubySMB::Dcerpc::Error::WinregError)
|
515
|
+
expect(winreg.has_registry_key?(key)).to be false
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'closes the key' do
|
520
|
+
winreg.has_registry_key?(key)
|
521
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
522
|
+
end
|
523
|
+
|
524
|
+
it 'returns true when no error occurs' do
|
525
|
+
expect(winreg.has_registry_key?(key)).to be true
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
describe '#read_registry_key_value' do
|
530
|
+
let(:root_key) { 'HKLM' }
|
531
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
532
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
533
|
+
let(:value_name) { 'registry_value_name' }
|
534
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
535
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
536
|
+
let(:value) { double('Value') }
|
537
|
+
before :example do
|
538
|
+
allow(winreg).to receive_messages(
|
539
|
+
:bind => nil,
|
540
|
+
:open_root_key => root_key_handle,
|
541
|
+
:open_key => subkey_handle,
|
542
|
+
:query_value => value,
|
543
|
+
:close_key => nil
|
544
|
+
)
|
545
|
+
end
|
546
|
+
|
547
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
548
|
+
winreg.read_registry_key_value(key, value_name)
|
549
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
550
|
+
end
|
551
|
+
|
552
|
+
it 'opens the expected root key' do
|
553
|
+
winreg.read_registry_key_value(key, value_name)
|
554
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
555
|
+
end
|
556
|
+
|
557
|
+
it 'opens the expected registry key' do
|
558
|
+
winreg.read_registry_key_value(key, value_name)
|
559
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
560
|
+
end
|
561
|
+
|
562
|
+
it 'queries the expected registry key value' do
|
563
|
+
winreg.read_registry_key_value(key, value_name)
|
564
|
+
expect(winreg).to have_received(:query_value).with(subkey_handle, value_name)
|
565
|
+
end
|
566
|
+
|
567
|
+
it 'closes the key' do
|
568
|
+
winreg.read_registry_key_value(key, value_name)
|
569
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
570
|
+
end
|
571
|
+
|
572
|
+
it 'returns expect registry key value' do
|
573
|
+
expect(winreg.read_registry_key_value(key, value_name)).to eq(value)
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
describe '#enum_registry_key' do
|
578
|
+
let(:root_key) { 'HKLM' }
|
579
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
580
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
581
|
+
let(:value_name) { 'registry_value_name' }
|
582
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
583
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
584
|
+
let(:query_info_key_response) { double('Query Info Key Response') }
|
585
|
+
let(:subkey_nb) { 2 }
|
586
|
+
before :example do
|
587
|
+
allow(winreg).to receive_messages(
|
588
|
+
:bind => nil,
|
589
|
+
:open_root_key => root_key_handle,
|
590
|
+
:open_key => subkey_handle,
|
591
|
+
:query_info_key => query_info_key_response,
|
592
|
+
:enum_key => nil,
|
593
|
+
:close_key => nil
|
594
|
+
)
|
595
|
+
allow(query_info_key_response).to receive(:lpc_sub_keys).and_return(subkey_nb)
|
596
|
+
end
|
597
|
+
|
598
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
599
|
+
winreg.enum_registry_key(key)
|
600
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
601
|
+
end
|
602
|
+
|
603
|
+
it 'opens the expected root key' do
|
604
|
+
winreg.enum_registry_key(key)
|
605
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
606
|
+
end
|
607
|
+
|
608
|
+
context 'when the registry key only contains the root key' do
|
609
|
+
it 'queries information for the root key' do
|
610
|
+
winreg.enum_registry_key(root_key)
|
611
|
+
expect(winreg).to have_received(:query_info_key).with(root_key_handle)
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
it 'opens the expected registry key' do
|
616
|
+
winreg.enum_registry_key(key)
|
617
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
618
|
+
end
|
619
|
+
|
620
|
+
it 'queries information for the expected registry key' do
|
621
|
+
winreg.enum_registry_key(key)
|
622
|
+
expect(winreg).to have_received(:query_info_key).with(subkey_handle)
|
623
|
+
end
|
624
|
+
|
625
|
+
it 'calls #enum_key the expected number of times' do
|
626
|
+
winreg.enum_registry_key(key)
|
627
|
+
expect(winreg).to have_received(:enum_key).with(subkey_handle, instance_of(Fixnum)).twice
|
628
|
+
end
|
629
|
+
|
630
|
+
it 'closes the key' do
|
631
|
+
winreg.enum_registry_key(key)
|
632
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
633
|
+
end
|
634
|
+
|
635
|
+
it 'returns the expected array of enumerated keys' do
|
636
|
+
key1 = 'key1'
|
637
|
+
key2 = 'key2'
|
638
|
+
allow(winreg).to receive(:enum_key).with(subkey_handle, 0).and_return(key1)
|
639
|
+
allow(winreg).to receive(:enum_key).with(subkey_handle, 1).and_return(key2)
|
640
|
+
expect(winreg.enum_registry_key(key)).to eq([key1, key2])
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
describe '#enum_registry_values' do
|
645
|
+
let(:root_key) { 'HKLM' }
|
646
|
+
let(:sub_key) { 'my\\sub\\key\\path' }
|
647
|
+
let(:key) { "#{root_key}\\#{sub_key}" }
|
648
|
+
let(:value_name) { 'registry_value_name' }
|
649
|
+
let(:root_key_handle) { double('Root Key Handle') }
|
650
|
+
let(:subkey_handle) { double('Subkey Handle') }
|
651
|
+
let(:query_info_key_response) { double('Query Info Key Response') }
|
652
|
+
let(:subkey_nb) { 2 }
|
653
|
+
before :example do
|
654
|
+
allow(winreg).to receive_messages(
|
655
|
+
:bind => nil,
|
656
|
+
:open_root_key => root_key_handle,
|
657
|
+
:open_key => subkey_handle,
|
658
|
+
:query_info_key => query_info_key_response,
|
659
|
+
:enum_value => nil,
|
660
|
+
:close_key => nil
|
661
|
+
)
|
662
|
+
allow(query_info_key_response).to receive(:lpc_values).and_return(subkey_nb)
|
663
|
+
end
|
664
|
+
|
665
|
+
it 'binds a DCERPC connection to the expected remote endpoint' do
|
666
|
+
winreg.enum_registry_values(key)
|
667
|
+
expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
|
668
|
+
end
|
669
|
+
|
670
|
+
it 'opens the expected root key' do
|
671
|
+
winreg.enum_registry_values(key)
|
672
|
+
expect(winreg).to have_received(:open_root_key).with(root_key)
|
673
|
+
end
|
674
|
+
|
675
|
+
context 'when the registry key only contains the root key' do
|
676
|
+
it 'queries information for the root key' do
|
677
|
+
winreg.enum_registry_values(root_key)
|
678
|
+
expect(winreg).to have_received(:query_info_key).with(root_key_handle)
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
it 'opens the expected registry key' do
|
683
|
+
winreg.enum_registry_values(key)
|
684
|
+
expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
|
685
|
+
end
|
686
|
+
|
687
|
+
it 'queries information for the expected registry key' do
|
688
|
+
winreg.enum_registry_values(key)
|
689
|
+
expect(winreg).to have_received(:query_info_key).with(subkey_handle)
|
690
|
+
end
|
691
|
+
|
692
|
+
it 'calls #enum_key the expected number of times' do
|
693
|
+
winreg.enum_registry_values(key)
|
694
|
+
expect(winreg).to have_received(:enum_value).with(subkey_handle, instance_of(Fixnum)).twice
|
695
|
+
end
|
696
|
+
|
697
|
+
it 'closes the key' do
|
698
|
+
winreg.enum_registry_values(key)
|
699
|
+
expect(winreg).to have_received(:close_key).with(subkey_handle)
|
700
|
+
end
|
701
|
+
|
702
|
+
it 'returns the expected array of enumerated keys' do
|
703
|
+
value1 = 'value1'
|
704
|
+
value2 = 'value2'
|
705
|
+
allow(winreg).to receive(:enum_value).with(subkey_handle, 0).and_return(value1)
|
706
|
+
allow(winreg).to receive(:enum_value).with(subkey_handle, 1).and_return(value2)
|
707
|
+
expect(winreg.enum_registry_values(key)).to eq([value1, value2])
|
708
|
+
end
|
709
|
+
end
|
710
|
+
end
|