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.
- 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/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/enum_registry_key.rb +29 -0
- data/examples/enum_registry_values.rb +31 -0
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate.rb +51 -8
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +13 -13
- data/examples/query_service_status.rb +64 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +33 -0
- data/examples/rename_file.rb +9 -7
- data/examples/tree_connect.rb +7 -5
- data/examples/write_file.rb +9 -7
- data/lib/ruby_smb.rb +4 -1
- data/lib/ruby_smb/client.rb +239 -21
- data/lib/ruby_smb/client/authentication.rb +27 -8
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +154 -12
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +4 -4
- 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 +40 -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 +6 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +260 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +41 -9
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +38 -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/svcctl.rb +479 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +421 -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/create_key_request.rb +73 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -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 +40 -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/dcerpc/winreg/save_key_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +5 -4
- data/lib/ruby_smb/error.rb +28 -1
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +8 -14
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +81 -3
- data/lib/ruby_smb/smb1/tree.rb +12 -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 +51 -61
- 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/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
- data/lib/ruby_smb/smb2/pipe.rb +80 -3
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +32 -20
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1583 -102
- 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 +1729 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +135 -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/svcctl/change_service_config_w_request_spec.rb +191 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -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/create_key_request_spec.rb +110 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +104 -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 +95 -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 +35 -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 +138 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +884 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
- 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/pipe_spec.rb +216 -147
- 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 +146 -68
- 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 +3 -24
- 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/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 -30
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +226 -148
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +88 -9
- metadata +257 -81
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Crypto::KDF do
|
4
|
+
describe '.counter_mode' do
|
5
|
+
it 'generates the expected 128-bit key' do
|
6
|
+
expected_key = "\x3c\x5e\x0a\x1b\x0a\xce\xa5\xb2\x64\x3f\xab\x78\xdc\x82\x31\x3b".b
|
7
|
+
expect(described_class.counter_mode('ki', 'label', 'context')).to eq(expected_key)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'generates the expected 256-bit key' do
|
11
|
+
expected_key =
|
12
|
+
"\x33\x4d\xa9\x6d\x24\x7e\xcb\x14\xf6\x24\x00\x97\x26\x51\xd5\xb4"\
|
13
|
+
"\x54\x5f\xda\x95\xf0\x5a\xcb\x25\x92\x57\xae\x71\x1c\x37\x20\x5b".b
|
14
|
+
expect(described_class.counter_mode('ki', 'label', 'context', length: 256)).to eq(expected_key)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'raises the expected exception when an error occurs' do
|
18
|
+
allow(OpenSSL::Digest).to receive(:new).and_raise(OpenSSL::OpenSSLError)
|
19
|
+
expect { described_class.counter_mode('ki', 'label', 'context') }.to raise_error(
|
20
|
+
RubySMB::Error::EncryptionError,
|
21
|
+
"Crypto::KDF.counter_mode OpenSSL error: OpenSSL::OpenSSLError"
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -31,7 +31,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'should have a default value of 0xFFFF' do
|
34
|
-
expect(packet.max_xmit_frag).to eq
|
34
|
+
expect(packet.max_xmit_frag).to eq RubySMB::Dcerpc::MAX_XMIT_FRAG
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -41,7 +41,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should have a default value of 0xFFFF' do
|
44
|
-
expect(packet.max_recv_frag).to eq
|
44
|
+
expect(packet.max_recv_frag).to eq RubySMB::Dcerpc::MAX_RECV_FRAG
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -41,7 +41,7 @@ RSpec.describe RubySMB::Dcerpc::Bind do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should have a default value of 0xFFFF' do
|
44
|
-
expect(packet.max_xmit_frag).to eq
|
44
|
+
expect(packet.max_xmit_frag).to eq RubySMB::Dcerpc::MAX_XMIT_FRAG
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -51,7 +51,7 @@ RSpec.describe RubySMB::Dcerpc::Bind do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'should have a default value of 0xFFFF' do
|
54
|
-
expect(packet.max_recv_frag).to eq
|
54
|
+
expect(packet.max_recv_frag).to eq RubySMB::Dcerpc::MAX_RECV_FRAG
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -0,0 +1,1729 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrPointer do
|
2
|
+
subject(:packet) do
|
3
|
+
Class.new(described_class) do
|
4
|
+
endian :little
|
5
|
+
string :referent
|
6
|
+
end.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it { is_expected.to respond_to :referent_id }
|
10
|
+
|
11
|
+
it 'is little endian' do
|
12
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#referent_id' do
|
16
|
+
it 'is a 32-bit unsigned integer' do
|
17
|
+
expect(packet.referent_id).to be_a BinData::Uint32le
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'has an initial value of 0' do
|
21
|
+
expect(packet.referent_id).to eq(0)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#get' do
|
26
|
+
it 'returns :null when #referent_id is 0' do
|
27
|
+
packet.referent_id = 0
|
28
|
+
expect(packet.get).to eq(:null)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns #referent when #referent_id is not 0' do
|
32
|
+
packet.set('spec_test')
|
33
|
+
expect(packet.get).to eq(packet.referent)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#set' do
|
38
|
+
context 'when the value is :null' do
|
39
|
+
it 'clears #referent' do
|
40
|
+
expect(packet.referent).to receive(:clear)
|
41
|
+
packet.set(:null)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'sets #referent_id to 0' do
|
45
|
+
packet.set(:null)
|
46
|
+
expect(packet.referent_id).to eq(0)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when the value is a string' do
|
51
|
+
let(:str) { 'spec_test' }
|
52
|
+
|
53
|
+
it 'sets #referent to the value' do
|
54
|
+
packet.set(str)
|
55
|
+
expect(packet.referent).to eq(str)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'calls #set when #referent support it' do
|
59
|
+
module TestSet; def set(v); end; end
|
60
|
+
packet.referent.extend(TestSet)
|
61
|
+
expect(packet.referent).to receive(:set).with(str)
|
62
|
+
packet.set(str)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'assigns directly to #referent when it does not support #set' do
|
66
|
+
expect(packet).to receive(:referent=).with(str)
|
67
|
+
packet.set(str)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'sets #referent_id to a random value' do
|
71
|
+
rnd = double('Random Value')
|
72
|
+
allow(packet).to receive(:rand).and_return(rnd)
|
73
|
+
expect(packet).to receive(:referent_id=).with(rnd)
|
74
|
+
packet.set(str)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'does not change #referent_id if it is already set' do
|
78
|
+
packet.referent_id = 0xCCCCCC
|
79
|
+
packet.set(str)
|
80
|
+
expect(packet.referent_id).to eq(0xCCCCCC)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#do_read' do
|
86
|
+
let(:io) { StringIO.new }
|
87
|
+
|
88
|
+
it 'asks referent_id to read the io stream' do
|
89
|
+
expect(packet.referent_id).to receive(:do_read).with(io)
|
90
|
+
packet.do_read(io)
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when it can process #referent' do
|
94
|
+
before :example do
|
95
|
+
allow(packet).to receive(:process_referent?).and_return(true)
|
96
|
+
allow(packet.referent_id).to receive(:do_read)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'asks referent to read the io stream if referent_id is not 0' do
|
100
|
+
packet.referent_id = 0xCCCC
|
101
|
+
expect(packet.referent).to receive(:do_read).with(io)
|
102
|
+
packet.do_read(io)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'does not ask referent to read the io stream if referent_id is 0' do
|
106
|
+
packet.referent_id = 0
|
107
|
+
expect(packet.referent).to_not receive(:do_read).with(io)
|
108
|
+
packet.do_read(io)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#do_write' do
|
114
|
+
let(:io) { StringIO.new }
|
115
|
+
|
116
|
+
it 'asks referent_id to write the io stream' do
|
117
|
+
expect(packet.referent_id).to receive(:do_write).with(io)
|
118
|
+
packet.do_write(io)
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when it can process #referent' do
|
122
|
+
before :example do
|
123
|
+
allow(packet).to receive(:process_referent?).and_return(true)
|
124
|
+
allow(packet.referent_id).to receive(:do_write)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'asks referent to write the io stream if referent_id is not 0' do
|
128
|
+
packet.referent_id = 0xCCCC
|
129
|
+
expect(packet.referent).to receive(:do_write).with(io)
|
130
|
+
packet.do_write(io)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'does not ask referent to write the io stream if referent_id is 0' do
|
134
|
+
packet.referent_id = 0
|
135
|
+
expect(packet.referent).to_not receive(:do_write).with(io)
|
136
|
+
packet.do_write(io)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#process_referent?' do
|
142
|
+
let(:ndr_struct) { RubySMB::Dcerpc::Ndr::NdrStruct.new }
|
143
|
+
it 'returns false if the parent is a NdrStruct' do
|
144
|
+
obj = described_class.new(nil, {}, ndr_struct)
|
145
|
+
expect(obj.process_referent?).to be false
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns false if one of the parents is a NdrStruct' do
|
149
|
+
obj1 = described_class.new(nil, {}, ndr_struct)
|
150
|
+
obj2 = described_class.new(nil, {}, obj1)
|
151
|
+
obj3 = described_class.new(nil, {}, obj2)
|
152
|
+
obj4 = described_class.new(nil, {}, obj3)
|
153
|
+
obj5 = described_class.new(nil, {}, obj4)
|
154
|
+
expect(obj5.process_referent?).to be false
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'returns true if none of the parents is a NdrStruct' do
|
158
|
+
obj1 = described_class.new
|
159
|
+
obj2 = described_class.new(nil, {}, obj1)
|
160
|
+
obj3 = described_class.new(nil, {}, obj2)
|
161
|
+
obj4 = described_class.new(nil, {}, obj3)
|
162
|
+
obj5 = described_class.new(nil, {}, obj4)
|
163
|
+
expect(obj5.process_referent?).to be true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe '#read' do
|
168
|
+
let(:struct) do
|
169
|
+
Class.new(described_class) do
|
170
|
+
attr_accessor :str_length
|
171
|
+
endian :little
|
172
|
+
string :referent, read_length: -> { self.str_length }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'with a null string' do
|
177
|
+
it 'reads its own binary representation' do
|
178
|
+
raw = packet.to_binary_s
|
179
|
+
expect(struct.read(raw)).to eq(packet)
|
180
|
+
expect(struct.read(raw).to_binary_s).to eq(raw)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'with a normal string' do
|
185
|
+
it 'reads its own binary representation' do
|
186
|
+
packet.set('testing')
|
187
|
+
raw = packet.to_binary_s
|
188
|
+
struct_obj = struct.new
|
189
|
+
struct_obj.str_length = 'testing'.size
|
190
|
+
expect(struct_obj.read(raw)).to eq(packet)
|
191
|
+
expect(struct_obj.read(raw).to_binary_s).to eq(raw)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrString do
|
198
|
+
subject(:packet) { described_class.new }
|
199
|
+
|
200
|
+
it { is_expected.to respond_to :max_count }
|
201
|
+
it { is_expected.to respond_to :offset }
|
202
|
+
it { is_expected.to respond_to :actual_count }
|
203
|
+
it { is_expected.to respond_to :str }
|
204
|
+
|
205
|
+
it 'is little endian' do
|
206
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
207
|
+
end
|
208
|
+
|
209
|
+
describe '#max_count' do
|
210
|
+
it 'is a 32-bit unsigned integer' do
|
211
|
+
expect(packet.max_count).to be_a BinData::Uint32le
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#offset' do
|
216
|
+
it 'is a 32-bit unsigned integer' do
|
217
|
+
expect(packet.offset).to be_a BinData::Uint32le
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'has an initial valu of 0' do
|
221
|
+
expect(packet.offset).to eq(0)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '#actual_count' do
|
226
|
+
it 'is a 32-bit unsigned integer' do
|
227
|
+
expect(packet.actual_count).to be_a BinData::Uint32le
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe '#str' do
|
232
|
+
it 'is a RubySMB::Field::Stringz16' do
|
233
|
+
expect(packet.str).to be_a RubySMB::Field::Stringz16
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'exists if #actual_count is greater than 0' do
|
237
|
+
packet.actual_count = 4
|
238
|
+
expect(packet.str?).to be true
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'does not exist if #actual_count is 0' do
|
242
|
+
expect(packet.str?).to be false
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe '#get' do
|
247
|
+
it 'returns 0 when #actual_count is 0' do
|
248
|
+
expect(packet.get).to eq(0)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'returns #str when #actual_count is greater than 0' do
|
252
|
+
str = 'spec_test'
|
253
|
+
strz16 = RubySMB::Field::Stringz16.new(str)
|
254
|
+
packet.set(str)
|
255
|
+
expect(packet.get).to eq(strz16)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe '#set' do
|
260
|
+
context 'when the value is 0' do
|
261
|
+
it 'sets #actual_count to 0' do
|
262
|
+
packet.set(0)
|
263
|
+
expect(packet.actual_count).to eq(0)
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'clears #str' do
|
267
|
+
expect(packet.str).to receive(:clear)
|
268
|
+
packet.set(0)
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'keeps #actual_count set to 0 when called from #to_binary_s' do
|
272
|
+
packet.set(0)
|
273
|
+
packet.to_binary_s
|
274
|
+
expect(packet.actual_count).to eq(0)
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'keeps #actual_count set to 0 when called from #do_num_bytes' do
|
278
|
+
packet.set(0)
|
279
|
+
packet.to_binary_s
|
280
|
+
packet.do_num_bytes
|
281
|
+
expect(packet.actual_count).to eq(0)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'when the value is a string' do
|
286
|
+
let(:str) { 'spec_test' }
|
287
|
+
|
288
|
+
it 'sets #str to the value' do
|
289
|
+
packet.set(str)
|
290
|
+
strz16 = RubySMB::Field::Stringz16.new(str)
|
291
|
+
expect(packet.str).to eq(strz16)
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'sets #max_count and #actual_count to the expected value' do
|
295
|
+
packet.set(str)
|
296
|
+
expect(packet.max_count).to eq(str.length + 1)
|
297
|
+
expect(packet.actual_count).to eq(str.length + 1)
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'sets #actual_count to 0 when the value is an empty string' do
|
301
|
+
packet.actual_count = 10
|
302
|
+
packet.set('')
|
303
|
+
expect(packet.actual_count).to eq(0)
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'keeps custom #max_count and #offset values when called from #to_binary_s' do
|
307
|
+
packet.set(str)
|
308
|
+
packet.max_count = 3
|
309
|
+
packet.offset = 10
|
310
|
+
packet.to_binary_s
|
311
|
+
expect(packet.max_count).to eq(3)
|
312
|
+
expect(packet.offset).to eq(10)
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'keeps custom #max_count value when called from #do_num_bytes' do
|
316
|
+
packet.set(str)
|
317
|
+
packet.max_count = 3
|
318
|
+
packet.offset = 10
|
319
|
+
packet.do_num_bytes
|
320
|
+
expect(packet.max_count).to eq(3)
|
321
|
+
expect(packet.offset).to eq(10)
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'sets #max_count to the number of elements set after setting custom #max_count value' do
|
325
|
+
packet.set(str)
|
326
|
+
packet.max_count = 3
|
327
|
+
packet.set(str * 2)
|
328
|
+
expect(packet.max_count).to eq(str.size * 2 + 1)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
describe '#clear' do
|
334
|
+
it 'clears #str' do
|
335
|
+
expect(packet.str).to receive(:clear)
|
336
|
+
packet.clear
|
337
|
+
end
|
338
|
+
|
339
|
+
it 'clears #actual_count' do
|
340
|
+
expect(packet.actual_count).to receive(:clear)
|
341
|
+
packet.clear
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'does to clear out #max_count and #offset' do
|
345
|
+
expect(packet.max_count).to_not receive(:clear)
|
346
|
+
expect(packet.offset).to_not receive(:clear)
|
347
|
+
packet.clear
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe '#to_s' do
|
352
|
+
it 'calls str#to_s' do
|
353
|
+
expect(packet.str).to receive(:to_s)
|
354
|
+
packet.to_s
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'outputs the expected string with the correct encoding' do
|
358
|
+
str = 'testing'
|
359
|
+
packet.assign(str)
|
360
|
+
expect(packet.to_s.encoding).to eq(Encoding::UTF_16LE)
|
361
|
+
expect(packet.to_s).to eq(str.encode(Encoding::UTF_16LE))
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
describe '#read' do
|
366
|
+
context 'with a null string' do
|
367
|
+
it 'reads its own binary representation' do
|
368
|
+
packet.set(0)
|
369
|
+
raw = packet.to_binary_s
|
370
|
+
expect(described_class.read(raw)).to eq(packet)
|
371
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
context 'with a normal string' do
|
376
|
+
it 'reads its own binary representation' do
|
377
|
+
packet.set('testing')
|
378
|
+
raw = packet.to_binary_s
|
379
|
+
expect(described_class.read(raw)).to eq(packet)
|
380
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
context 'with different #offset and #max_count values' do
|
385
|
+
it 'reads its own binary representation' do
|
386
|
+
packet.set('testing')
|
387
|
+
packet.max_count = 256
|
388
|
+
packet.offset = 40
|
389
|
+
raw = packet.to_binary_s
|
390
|
+
expect(described_class.read(raw)).to eq(packet)
|
391
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
context 'with #actual_count less than elements size' do
|
396
|
+
it 'reads its own binary representation reduced to #actual_count elements' do
|
397
|
+
str = '12345'
|
398
|
+
packet.set(str)
|
399
|
+
packet.actual_count = 4
|
400
|
+
max_count = packet.max_count.to_i
|
401
|
+
raw = packet.to_binary_s
|
402
|
+
packet2 = described_class.read(raw)
|
403
|
+
expect(packet2.max_count).to eq(max_count)
|
404
|
+
expect(packet2.offset).to eq(0)
|
405
|
+
expect(packet2.actual_count).to eq(4)
|
406
|
+
expect(packet2.str).to eq(str[0,3].encode(Encoding::UTF_16LE))
|
407
|
+
expect(packet2.to_binary_s).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x001\x002\x003\x00\x00\x00".b)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStr do
|
414
|
+
it 'is NdrPointer subclass' do
|
415
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
|
416
|
+
end
|
417
|
+
|
418
|
+
subject(:packet) { described_class.new }
|
419
|
+
|
420
|
+
it { is_expected.to respond_to :referent }
|
421
|
+
|
422
|
+
it 'is little endian' do
|
423
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
424
|
+
end
|
425
|
+
|
426
|
+
describe '#referent' do
|
427
|
+
it 'is a NdrString' do
|
428
|
+
expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrString
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'exists if superclass #referent_id is not zero' do
|
432
|
+
packet.referent_id = 0xCCCC
|
433
|
+
expect(packet.referent?).to be true
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'does not exist if superclass #referent_id is zero' do
|
437
|
+
packet.referent_id = 0
|
438
|
+
expect(packet.referent?).to be false
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
describe '#read' do
|
443
|
+
context 'with a null pointer' do
|
444
|
+
it 'reads its own binary representation' do
|
445
|
+
raw = packet.to_binary_s
|
446
|
+
expect(described_class.read(raw)).to eq(packet)
|
447
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
context 'with a normal string' do
|
452
|
+
it 'reads its own binary representation' do
|
453
|
+
packet.set('testing')
|
454
|
+
raw = packet.to_binary_s
|
455
|
+
expect(described_class.read(raw)).to eq(packet)
|
456
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
|
463
|
+
let(:uuid) { 'c3bce70d-5155-472b-9f2f-b824e5fc9b60' }
|
464
|
+
let(:attr) { 123 }
|
465
|
+
subject(:packet) { described_class.new }
|
466
|
+
|
467
|
+
it { is_expected.to respond_to :context_handle_attributes }
|
468
|
+
it { is_expected.to respond_to :context_handle_uuid }
|
469
|
+
|
470
|
+
it 'is little endian' do
|
471
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
472
|
+
end
|
473
|
+
|
474
|
+
describe '#context_handle_attributes' do
|
475
|
+
it 'is a 32-bit unsigned integer' do
|
476
|
+
expect(packet.context_handle_attributes).to be_a BinData::Uint32le
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
describe '#context_handle_uuid' do
|
481
|
+
it 'is a UUID' do
|
482
|
+
expect(packet.context_handle_uuid).to be_a RubySMB::Dcerpc::Uuid
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe '#get' do
|
487
|
+
it 'returns the expeted hash' do
|
488
|
+
packet.context_handle_attributes = attr
|
489
|
+
packet.context_handle_uuid = uuid
|
490
|
+
expect(packet.get).to eq({context_handle_attributes: attr, context_handle_uuid: uuid})
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
describe '#set' do
|
495
|
+
let(:handle) { {context_handle_attributes: attr, context_handle_uuid: uuid} }
|
496
|
+
|
497
|
+
context 'when the value is a hash' do
|
498
|
+
it 'sets #context_handle_attributes and #context_handle_uuid to the expected values' do
|
499
|
+
packet.set(handle)
|
500
|
+
expect(packet.context_handle_attributes).to eq(attr)
|
501
|
+
expect(packet.context_handle_uuid).to eq(uuid)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
context 'when the value is a NdrContextHandle'do
|
506
|
+
it 'reads the value binary representaion ' do
|
507
|
+
ndr_context_handle = described_class.new(handle)
|
508
|
+
allow(ndr_context_handle).to receive(:to_binary_s).and_call_original
|
509
|
+
packet.set(ndr_context_handle)
|
510
|
+
expect(ndr_context_handle).to have_received(:to_binary_s)
|
511
|
+
expect(packet.get).to eq(ndr_context_handle)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
context 'when the value is a binary string'do
|
516
|
+
it 'reads the value' do
|
517
|
+
ndr_context_handle = described_class.new(handle)
|
518
|
+
packet.set(ndr_context_handle.to_binary_s)
|
519
|
+
expect(packet.get).to eq(ndr_context_handle)
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
describe '#read' do
|
525
|
+
context 'with a hash' do
|
526
|
+
it 'reads its own binary representation' do
|
527
|
+
packet.set({context_handle_attributes: attr, context_handle_uuid: uuid})
|
528
|
+
raw = packet.to_binary_s
|
529
|
+
expect(described_class.read(raw)).to eq(packet)
|
530
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
context 'with a NdrContextHandle' do
|
535
|
+
it 'reads its own binary representation' do
|
536
|
+
nch = described_class.new
|
537
|
+
nch.set({context_handle_attributes: attr, context_handle_uuid: uuid})
|
538
|
+
packet.set(nch)
|
539
|
+
raw = packet.to_binary_s
|
540
|
+
expect(described_class.read(raw)).to eq(packet)
|
541
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
context 'with a binary string' do
|
546
|
+
it 'reads its own binary representation' do
|
547
|
+
packet.set("{\x00\x00\x00\r\xE7\xBC\xC3UQ+G\x9F/\xB8$\xE5\xFC\x9B`".b)
|
548
|
+
raw = packet.to_binary_s
|
549
|
+
expect(described_class.read(raw)).to eq(packet)
|
550
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpDword do
|
557
|
+
it 'is NdrPointer subclass' do
|
558
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
|
559
|
+
end
|
560
|
+
|
561
|
+
subject(:packet) { described_class.new }
|
562
|
+
|
563
|
+
it { is_expected.to respond_to :referent }
|
564
|
+
|
565
|
+
it 'is little endian' do
|
566
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
567
|
+
end
|
568
|
+
|
569
|
+
describe '#referent' do
|
570
|
+
it 'is a 32-bit unsigned integer' do
|
571
|
+
expect(packet.referent).to be_a BinData::Uint32le
|
572
|
+
end
|
573
|
+
|
574
|
+
it 'exists if superclass #referent_id is not zero' do
|
575
|
+
packet.referent_id = 0xCCCC
|
576
|
+
expect(packet.referent?).to be true
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'does not exist if superclass #referent_id is zero' do
|
580
|
+
packet.referent_id = 0
|
581
|
+
expect(packet.referent?).to be false
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
describe '#read' do
|
586
|
+
context 'with a null pointer' do
|
587
|
+
it 'reads its own binary representation' do
|
588
|
+
raw = packet.to_binary_s
|
589
|
+
expect(described_class.read(raw)).to eq(packet)
|
590
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
context 'with a normal integer' do
|
595
|
+
it 'reads its own binary representation' do
|
596
|
+
packet.set(123)
|
597
|
+
raw = packet.to_binary_s
|
598
|
+
expect(described_class.read(raw)).to eq(packet)
|
599
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByteArray do
|
606
|
+
it 'is NdrPointer subclass' do
|
607
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
|
608
|
+
end
|
609
|
+
|
610
|
+
subject(:packet) { described_class.new }
|
611
|
+
|
612
|
+
it { is_expected.to respond_to :referent }
|
613
|
+
|
614
|
+
it 'is little endian' do
|
615
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
616
|
+
end
|
617
|
+
|
618
|
+
describe '#referent' do
|
619
|
+
it 'is a NdrByteArray structure' do
|
620
|
+
expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrByteArray
|
621
|
+
end
|
622
|
+
|
623
|
+
it 'exists if superclass #referent_id is not zero' do
|
624
|
+
packet.referent_id = 0xCCCC
|
625
|
+
expect(packet.referent?).to be true
|
626
|
+
end
|
627
|
+
|
628
|
+
it 'does not exist if superclass #referent_id is zero' do
|
629
|
+
packet.referent_id = 0
|
630
|
+
expect(packet.referent?).to be false
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
describe '#set' do
|
635
|
+
it 'accepts a NdrLpByteArray structure' do
|
636
|
+
struct = described_class.new([1, 2, 3])
|
637
|
+
packet.set(struct)
|
638
|
+
expect(packet).to eq(struct)
|
639
|
+
end
|
640
|
+
|
641
|
+
it 'accepts a NdrLpByteArray null pointer' do
|
642
|
+
struct = described_class.new
|
643
|
+
packet.set(struct)
|
644
|
+
expect(packet).to eq(:null)
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'accepts a BinData::Array' do
|
648
|
+
struct = BinData::Array.new([1, 2, 3], type: :uint8)
|
649
|
+
packet.set(struct)
|
650
|
+
expect(packet).to eq(struct)
|
651
|
+
end
|
652
|
+
|
653
|
+
it 'accepts an Array' do
|
654
|
+
struct = Array.new([1, 2, 3])
|
655
|
+
packet.set(struct)
|
656
|
+
expect(packet).to eq(struct)
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
describe '#read' do
|
661
|
+
context 'with a null pointer' do
|
662
|
+
it 'reads its own binary representation' do
|
663
|
+
raw = packet.to_binary_s
|
664
|
+
expect(described_class.read(raw)).to eq(packet)
|
665
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
context 'with a normal array of bytes' do
|
670
|
+
it 'reads its own binary representation' do
|
671
|
+
packet.set([1, 2, 3])
|
672
|
+
raw = packet.to_binary_s
|
673
|
+
expect(described_class.read(raw)).to eq(packet)
|
674
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
675
|
+
end
|
676
|
+
end
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
|
681
|
+
subject(:packet) { described_class.new }
|
682
|
+
|
683
|
+
it { is_expected.to respond_to :max_count }
|
684
|
+
it { is_expected.to respond_to :elements }
|
685
|
+
|
686
|
+
it 'is little endian' do
|
687
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
688
|
+
end
|
689
|
+
|
690
|
+
describe '#max_count' do
|
691
|
+
it 'is a 32-bit unsigned integer' do
|
692
|
+
expect(packet.max_count).to be_a BinData::Uint32le
|
693
|
+
end
|
694
|
+
|
695
|
+
it 'has an initial value equal to #elements size' do
|
696
|
+
packet.elements = [1, 2, 3]
|
697
|
+
expect(packet.max_count).to eq(3)
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
describe '#elements' do
|
702
|
+
it 'is a Bindata::Array' do
|
703
|
+
expect(packet.elements).to be_a BinData::Array
|
704
|
+
end
|
705
|
+
|
706
|
+
it 'is 8-bit unsigned integer elements' do
|
707
|
+
expect(packet.elements[0]).to be_a BinData::Uint8
|
708
|
+
end
|
709
|
+
|
710
|
+
it 'exists if #max_count is greater than 0' do
|
711
|
+
packet.max_count = 2
|
712
|
+
expect(packet.elements?).to be true
|
713
|
+
end
|
714
|
+
|
715
|
+
it 'does not exist if #max_count is 0' do
|
716
|
+
packet.max_count = 0
|
717
|
+
expect(packet.elements?).to be false
|
718
|
+
end
|
719
|
+
|
720
|
+
it 'reads at most #max_counts elements' do
|
721
|
+
bin = "ABCDEFG".b
|
722
|
+
packet.max_count = 3
|
723
|
+
packet.elements.read(bin)
|
724
|
+
expect(packet.elements).to eq(bin.bytes[0,3])
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
describe '#get' do
|
729
|
+
it 'returns the elements' do
|
730
|
+
packet.elements = [1, 2, 3]
|
731
|
+
expect(packet.get).to eq([1, 2, 3])
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
describe '#set' do
|
736
|
+
it 'sets #elements as expected' do
|
737
|
+
packet.set([1, 2, 3])
|
738
|
+
expect(packet.elements).to eq([1, 2, 3])
|
739
|
+
end
|
740
|
+
|
741
|
+
it 'sets #max_count to the number of elements set' do
|
742
|
+
packet.set([1, 2, 3])
|
743
|
+
expect(packet.max_count).to eq(3)
|
744
|
+
end
|
745
|
+
|
746
|
+
it 'calls #to_ary before setting the elements' do
|
747
|
+
ary = BinData::Array.new([1, 2, 3], type: :uint8)
|
748
|
+
expect(ary).to receive(:to_ary).and_call_original
|
749
|
+
packet.set(ary)
|
750
|
+
expect(packet.elements).to eq([1, 2, 3])
|
751
|
+
end
|
752
|
+
|
753
|
+
it 'keeps custom #max_count value when called from #to_binary_s' do
|
754
|
+
packet.set([1, 2, 3, 4, 5])
|
755
|
+
packet.max_count = 3
|
756
|
+
packet.to_binary_s
|
757
|
+
expect(packet.max_count).to eq(3)
|
758
|
+
end
|
759
|
+
|
760
|
+
it 'keeps custom #max_count value when called from #do_num_bytes' do
|
761
|
+
packet.set([1, 2, 3, 4, 5])
|
762
|
+
packet.max_count = 3
|
763
|
+
packet.do_num_bytes
|
764
|
+
expect(packet.max_count).to eq(3)
|
765
|
+
end
|
766
|
+
|
767
|
+
it 'sets #max_count to the number of elements set after setting custom #max_count value' do
|
768
|
+
packet.set([1, 2, 3, 4, 5])
|
769
|
+
packet.max_count = 3
|
770
|
+
packet.set([1, 2, 3, 4, 5])
|
771
|
+
expect(packet.max_count).to eq(5)
|
772
|
+
end
|
773
|
+
end
|
774
|
+
|
775
|
+
describe '#read' do
|
776
|
+
context 'with a no elements' do
|
777
|
+
it 'reads its own binary representation' do
|
778
|
+
raw = packet.to_binary_s
|
779
|
+
expect(described_class.read(raw)).to eq(packet)
|
780
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
context 'with some elements' do
|
785
|
+
it 'reads its own binary representation' do
|
786
|
+
packet.set([1, 2, 3])
|
787
|
+
raw = packet.to_binary_s
|
788
|
+
expect(described_class.read(raw)).to eq(packet)
|
789
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
context 'with #max_count less than elements size' do
|
794
|
+
it 'reads its own binary representation reduced to #max_count elements' do
|
795
|
+
packet.set([1, 2, 3, 4, 5])
|
796
|
+
packet.max_count = 3
|
797
|
+
raw = packet.to_binary_s
|
798
|
+
packet2 = described_class.new([1, 2, 3])
|
799
|
+
raw2 = packet2.to_binary_s
|
800
|
+
expect(described_class.read(raw)).to eq(packet2)
|
801
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw2)
|
802
|
+
end
|
803
|
+
end
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrByteArray do
|
808
|
+
subject(:packet) { described_class.new }
|
809
|
+
|
810
|
+
it { is_expected.to respond_to :max_count }
|
811
|
+
it { is_expected.to respond_to :offset }
|
812
|
+
it { is_expected.to respond_to :actual_count }
|
813
|
+
it { is_expected.to respond_to :bytes }
|
814
|
+
|
815
|
+
it 'is little endian' do
|
816
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
817
|
+
end
|
818
|
+
|
819
|
+
describe '#max_count' do
|
820
|
+
it 'is a 32-bit unsigned integer' do
|
821
|
+
expect(packet.max_count).to be_a BinData::Uint32le
|
822
|
+
end
|
823
|
+
|
824
|
+
it 'has an initial value equal to #actual_count' do
|
825
|
+
packet.actual_count = 345
|
826
|
+
expect(packet.max_count).to eq(345)
|
827
|
+
end
|
828
|
+
end
|
829
|
+
|
830
|
+
describe '#offset' do
|
831
|
+
it 'is a 32-bit unsigned integer' do
|
832
|
+
expect(packet.offset).to be_a BinData::Uint32le
|
833
|
+
end
|
834
|
+
|
835
|
+
it 'has an initial value of 0' do
|
836
|
+
expect(packet.offset).to eq(0)
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
describe '#actual_count' do
|
841
|
+
it 'is a 32-bit unsigned integer' do
|
842
|
+
expect(packet.actual_count).to be_a BinData::Uint32le
|
843
|
+
end
|
844
|
+
|
845
|
+
it 'has an initial value equal to #bytes size' do
|
846
|
+
packet.bytes << 2 << 3 << 4 << 5
|
847
|
+
expect(packet.actual_count).to eq(4)
|
848
|
+
end
|
849
|
+
end
|
850
|
+
|
851
|
+
describe '#bytes' do
|
852
|
+
it 'is a Bindata::Array' do
|
853
|
+
expect(packet.bytes).to be_a BinData::Array
|
854
|
+
end
|
855
|
+
|
856
|
+
it 'has an initial length equal to #actual_count' do
|
857
|
+
packet.actual_count = 3
|
858
|
+
expect(packet.bytes.size).to eq(3)
|
859
|
+
end
|
860
|
+
|
861
|
+
it 'is 8-bit unsigned integer elements' do
|
862
|
+
expect(packet.bytes[0]).to be_a BinData::Uint8
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
describe '#get' do
|
867
|
+
it 'returns bytes' do
|
868
|
+
packet.bytes = [1, 2, 3]
|
869
|
+
expect(packet.get).to eq([1, 2, 3])
|
870
|
+
end
|
871
|
+
end
|
872
|
+
|
873
|
+
describe '#set' do
|
874
|
+
it 'sets #bytes as expected' do
|
875
|
+
packet.set([1, 2, 3])
|
876
|
+
expect(packet.bytes).to eq([1, 2, 3])
|
877
|
+
end
|
878
|
+
|
879
|
+
it 'sets #actual_count and #max_count to the number of bytes set' do
|
880
|
+
packet.set([1, 2, 3])
|
881
|
+
expect(packet.max_count).to eq(3)
|
882
|
+
expect(packet.actual_count).to eq(3)
|
883
|
+
end
|
884
|
+
|
885
|
+
it 'calls #to_ary before setting the elements' do
|
886
|
+
ary = BinData::Array.new([1, 2, 3], type: :uint8)
|
887
|
+
expect(ary).to receive(:to_ary).and_call_original
|
888
|
+
packet.set(ary)
|
889
|
+
expect(packet.bytes).to eq([1, 2, 3])
|
890
|
+
end
|
891
|
+
|
892
|
+
it 'keeps custom #max_count and #offset values when called from #to_binary_s' do
|
893
|
+
packet.set([1, 2, 3, 4, 5])
|
894
|
+
packet.max_count = 3
|
895
|
+
packet.offset = 40
|
896
|
+
packet.to_binary_s
|
897
|
+
expect(packet.max_count).to eq(3)
|
898
|
+
expect(packet.offset).to eq(40)
|
899
|
+
end
|
900
|
+
|
901
|
+
it 'keeps custom #max_count and #offset values when called from #do_num_bytes' do
|
902
|
+
packet.set([1, 2, 3, 4, 5])
|
903
|
+
packet.max_count = 3
|
904
|
+
packet.offset = 40
|
905
|
+
packet.do_num_bytes
|
906
|
+
expect(packet.max_count).to eq(3)
|
907
|
+
expect(packet.offset).to eq(40)
|
908
|
+
end
|
909
|
+
|
910
|
+
it 'sets #max_count to the number of bytes set after setting custom #max_count value' do
|
911
|
+
packet.set([1, 2, 3, 4, 5])
|
912
|
+
packet.max_count = 3
|
913
|
+
packet.set([1, 2, 3, 4, 5])
|
914
|
+
expect(packet.max_count).to eq(5)
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
describe '#read' do
|
919
|
+
context 'with a no elements' do
|
920
|
+
it 'reads its own binary representation' do
|
921
|
+
raw = packet.to_binary_s
|
922
|
+
expect(described_class.read(raw)).to eq(packet)
|
923
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
context 'with some elements' do
|
928
|
+
it 'reads its own binary representation' do
|
929
|
+
packet.set([1, 2, 3])
|
930
|
+
raw = packet.to_binary_s
|
931
|
+
expect(described_class.read(raw)).to eq(packet)
|
932
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
933
|
+
end
|
934
|
+
end
|
935
|
+
|
936
|
+
context 'with #max_count less than elements size' do
|
937
|
+
it 'reads its own binary representation reduced to #max_count elements' do
|
938
|
+
packet.set([1, 2, 3, 4, 5])
|
939
|
+
packet.actual_count = 3
|
940
|
+
max_count = packet.max_count.to_i
|
941
|
+
raw = packet.to_binary_s
|
942
|
+
packet2 = described_class.read(raw)
|
943
|
+
expect(packet2.max_count).to eq(max_count)
|
944
|
+
expect(packet2.offset).to eq(0)
|
945
|
+
expect(packet2.actual_count).to eq(3)
|
946
|
+
expect(packet2.bytes).to eq([1, 2, 3])
|
947
|
+
expect(packet2.to_binary_s).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x01\x02\x03".b)
|
948
|
+
end
|
949
|
+
end
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpFileTime do
|
954
|
+
it 'is NdrPointer subclass' do
|
955
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
|
956
|
+
end
|
957
|
+
|
958
|
+
subject(:packet) { described_class.new }
|
959
|
+
|
960
|
+
it { is_expected.to respond_to :referent }
|
961
|
+
|
962
|
+
it 'is little endian' do
|
963
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
964
|
+
end
|
965
|
+
|
966
|
+
describe '#referent' do
|
967
|
+
it 'is a FileTime' do
|
968
|
+
expect(packet.referent).to be_a RubySMB::Field::FileTime
|
969
|
+
end
|
970
|
+
|
971
|
+
it 'exists if superclass #referent_id is not zero' do
|
972
|
+
packet.referent_id = 0xCCCC
|
973
|
+
expect(packet.referent?).to be true
|
974
|
+
end
|
975
|
+
|
976
|
+
it 'does not exist if superclass #referent_id is zero' do
|
977
|
+
packet.referent_id = 0
|
978
|
+
expect(packet.referent?).to be false
|
979
|
+
end
|
980
|
+
end
|
981
|
+
|
982
|
+
describe '#read' do
|
983
|
+
context 'with a null pointer' do
|
984
|
+
it 'reads its own binary representation' do
|
985
|
+
raw = packet.to_binary_s
|
986
|
+
expect(described_class.read(raw)).to eq(packet)
|
987
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
988
|
+
end
|
989
|
+
end
|
990
|
+
|
991
|
+
context 'with a normal FileTime' do
|
992
|
+
it 'reads its own binary representation' do
|
993
|
+
time = RubySMB::Field::FileTime.new(Time.now)
|
994
|
+
packet.set(time)
|
995
|
+
raw = packet.to_binary_s
|
996
|
+
expect(described_class.read(raw)).to eq(packet)
|
997
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
end
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrStruct do
|
1004
|
+
describe '#do_read' do
|
1005
|
+
let(:io) { BinData::IO::Read.new(bin_str) }
|
1006
|
+
context 'with a structure containg an array of pointers to integer' do
|
1007
|
+
subject(:struct) do
|
1008
|
+
Class.new(described_class) do
|
1009
|
+
endian :little
|
1010
|
+
uint32 :a
|
1011
|
+
array :b, type: :ndr_lp_dword, read_until: -> { index == a - 1 }
|
1012
|
+
uint32 :c
|
1013
|
+
end.new
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
context 'without null pointers' do
|
1017
|
+
let(:bin_str) do
|
1018
|
+
"\x03\x00\x00\x00" + # a
|
1019
|
+
"\xA8\xC9\x1D\x9D" + # b[0] referent_id
|
1020
|
+
"&_>=" + # b[1] referent_id
|
1021
|
+
"T\r%\x18" + # b[2] referent_id
|
1022
|
+
"7\x00\x00\x00" + # c
|
1023
|
+
"\x01\x00\x00\x00" + # b[0]
|
1024
|
+
"\x02\x00\x00\x00" + # b[1]
|
1025
|
+
"\x03\x00\x00\x00" # b[2]
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
it 'reads as expected' do
|
1029
|
+
struct.do_read(io)
|
1030
|
+
expect(struct.a).to eq(3)
|
1031
|
+
expect(struct.b).to eq([1, 2, 3])
|
1032
|
+
expect(struct.b[0].referent_id).to eq(2635975080)
|
1033
|
+
expect(struct.b[0].referent).to eq(1)
|
1034
|
+
expect(struct.b[1].referent_id).to eq(1027497766)
|
1035
|
+
expect(struct.b[1].referent).to eq(2)
|
1036
|
+
expect(struct.b[2].referent_id).to eq(405081428)
|
1037
|
+
expect(struct.b[2].referent).to eq(3)
|
1038
|
+
expect(struct.c).to eq(55)
|
1039
|
+
end
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
context 'with null pointers' do
|
1043
|
+
let(:bin_str) do
|
1044
|
+
"\x03\x00\x00\x00" + # a
|
1045
|
+
"\xA8\xC9\x1D\x9D" + # b[0] referent_id
|
1046
|
+
"\x00\x00\x00\x00" + # b[1] referent_id (null)
|
1047
|
+
"T\r%\x18" + # b[2] referent_id
|
1048
|
+
"7\x00\x00\x00" + # c
|
1049
|
+
"\x01\x00\x00\x00" + # b[0]
|
1050
|
+
"\x03\x00\x00\x00" # b[2]
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
it 'reads as expected' do
|
1054
|
+
struct.do_read(io)
|
1055
|
+
expect(struct.a).to eq(3)
|
1056
|
+
expect(struct.b).to eq([1, :null, 3])
|
1057
|
+
expect(struct.b[0].referent_id).to eq(2635975080)
|
1058
|
+
expect(struct.b[0].referent).to eq(1)
|
1059
|
+
expect(struct.b[1].referent_id).to eq(0)
|
1060
|
+
expect(struct.b[2].referent_id).to eq(405081428)
|
1061
|
+
expect(struct.b[2].referent).to eq(3)
|
1062
|
+
expect(struct.c).to eq(55)
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
context 'with a structure containg an array of pointers to strings' do
|
1068
|
+
subject(:struct) do
|
1069
|
+
Class.new(described_class) do
|
1070
|
+
endian :little
|
1071
|
+
uint32 :a
|
1072
|
+
array :b, type: :ndr_lp_str, read_until: -> { index == a - 1 }
|
1073
|
+
uint32 :c
|
1074
|
+
end.new
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
context 'without null pointers' do
|
1078
|
+
let(:bin_str) do
|
1079
|
+
"\x03\x00\x00\x00" + # a
|
1080
|
+
"\xA8\xC9\x1D\x9D" + # b[0] referent_id
|
1081
|
+
"&_>=" + # b[1] referent_id
|
1082
|
+
"T\r%\x18" + # b[2] referent_id
|
1083
|
+
"7\x00\x00\x00" + # c
|
1084
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
|
1085
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # b[1]
|
1086
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
it 'reads as expected' do
|
1090
|
+
struct.do_read(io)
|
1091
|
+
str1 = 'test1'.encode(Encoding::UTF_16LE)
|
1092
|
+
str2 = 'test2'.encode(Encoding::UTF_16LE)
|
1093
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1094
|
+
expect(struct.a).to eq(3)
|
1095
|
+
expect(struct.b).to eq([str1, str2, str3])
|
1096
|
+
expect(struct.b[0].referent_id).to eq(2635975080)
|
1097
|
+
expect(struct.b[0].referent).to eq(str1)
|
1098
|
+
expect(struct.b[1].referent_id).to eq(1027497766)
|
1099
|
+
expect(struct.b[1].referent).to eq(str2)
|
1100
|
+
expect(struct.b[2].referent_id).to eq(405081428)
|
1101
|
+
expect(struct.b[2].referent).to eq(str3)
|
1102
|
+
expect(struct.c).to eq(55)
|
1103
|
+
end
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
context 'with null pointers' do
|
1107
|
+
let(:bin_str) do
|
1108
|
+
"\x03\x00\x00\x00" + # a
|
1109
|
+
"\xA8\xC9\x1D\x9D" + # b[0] referent_id
|
1110
|
+
"\x00\x00\x00\x00" + # b[1] referent_id (null)
|
1111
|
+
"T\r%\x18" + # b[2] referent_id
|
1112
|
+
"7\x00\x00\x00" + # c
|
1113
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
|
1114
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
it 'reads as expected' do
|
1118
|
+
struct.do_read(io)
|
1119
|
+
str1 = 'test1'.encode(Encoding::UTF_16LE)
|
1120
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1121
|
+
expect(struct.a).to eq(3)
|
1122
|
+
expect(struct.b).to eq([str1, :null, str3])
|
1123
|
+
expect(struct.b[0].referent_id).to eq(2635975080)
|
1124
|
+
expect(struct.b[0].referent).to eq(str1)
|
1125
|
+
expect(struct.b[1].referent_id).to eq(0)
|
1126
|
+
expect(struct.b[2].referent_id).to eq(405081428)
|
1127
|
+
expect(struct.b[2].referent).to eq(str3)
|
1128
|
+
expect(struct.c).to eq(55)
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
context 'with null strings' do
|
1133
|
+
let(:bin_str) do
|
1134
|
+
"\x03\x00\x00\x00" + # a
|
1135
|
+
"\xA8\xC9\x1D\x9D" + # b[0] referent_id
|
1136
|
+
"&_>=" + # b[1] referent_id
|
1137
|
+
"T\r%\x18" + # b[2] referent_id
|
1138
|
+
"7\x00\x00\x00" + # c
|
1139
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
|
1140
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # b[1] null string
|
1141
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
it 'reads as expected' do
|
1145
|
+
struct.do_read(io)
|
1146
|
+
str1 = 'test1'.encode(Encoding::UTF_16LE)
|
1147
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1148
|
+
expect(struct.a).to eq(3)
|
1149
|
+
expect(struct.b).to eq([str1, 0, str3])
|
1150
|
+
expect(struct.b[0].referent_id).to eq(2635975080)
|
1151
|
+
expect(struct.b[0].referent).to eq(str1)
|
1152
|
+
expect(struct.b[1].referent_id).to eq(1027497766)
|
1153
|
+
expect(struct.b[1].referent).to eq(0)
|
1154
|
+
expect(struct.b[2].referent_id).to eq(405081428)
|
1155
|
+
expect(struct.b[2].referent).to eq(str3)
|
1156
|
+
expect(struct.c).to eq(55)
|
1157
|
+
end
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
context 'with padding' do
|
1161
|
+
let(:bin_str) do
|
1162
|
+
"\x03\x00\x00\x00" + # a
|
1163
|
+
"\xA8\xC9\x1D\x9D" + # b[0] referent_id
|
1164
|
+
"&_>=" + # b[1] referent_id
|
1165
|
+
"T\r%\x18" + # b[2] referent_id
|
1166
|
+
"7\x00\x00\x00" + # c
|
1167
|
+
"\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00" + # b[0]
|
1168
|
+
"\x00\x00" + # pad
|
1169
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # b[1]
|
1170
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
it 'reads as expected' do
|
1174
|
+
struct.do_read(io)
|
1175
|
+
str1 = 'test'.encode(Encoding::UTF_16LE)
|
1176
|
+
str2 = 'test2'.encode(Encoding::UTF_16LE)
|
1177
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1178
|
+
expect(struct.a).to eq(3)
|
1179
|
+
expect(struct.b).to eq([str1, str2, str3])
|
1180
|
+
expect(struct.b[0].referent_id).to eq(2635975080)
|
1181
|
+
expect(struct.b[0].referent).to eq(str1)
|
1182
|
+
expect(struct.b[1].referent_id).to eq(1027497766)
|
1183
|
+
expect(struct.b[1].referent).to eq(str2)
|
1184
|
+
expect(struct.b[2].referent_id).to eq(405081428)
|
1185
|
+
expect(struct.b[2].referent).to eq(str3)
|
1186
|
+
expect(struct.c).to eq(55)
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
context 'with a structure containg an pointers to strings' do
|
1192
|
+
subject(:struct) do
|
1193
|
+
Class.new(described_class) do
|
1194
|
+
endian :little
|
1195
|
+
uint32 :a
|
1196
|
+
ndr_lp_str :b
|
1197
|
+
ndr_lp_str :c
|
1198
|
+
ndr_lp_str :d
|
1199
|
+
uint32 :e
|
1200
|
+
end.new
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
context 'without null pointers' do
|
1204
|
+
let(:bin_str) do
|
1205
|
+
"\x03\x00\x00\x00" + # a
|
1206
|
+
"\xA8\xC9\x1D\x9D" + # b referent_id
|
1207
|
+
"&_>=" + # c referent_id
|
1208
|
+
"T\r%\x18" + # d referent_id
|
1209
|
+
"7\x00\x00\x00" + # c
|
1210
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
|
1211
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # c
|
1212
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
it 'reads as expected' do
|
1216
|
+
struct.do_read(io)
|
1217
|
+
str1 = 'test1'.encode(Encoding::UTF_16LE)
|
1218
|
+
str2 = 'test2'.encode(Encoding::UTF_16LE)
|
1219
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1220
|
+
expect(struct.a).to eq(3)
|
1221
|
+
expect(struct.b).to eq(str1)
|
1222
|
+
expect(struct.c).to eq(str2)
|
1223
|
+
expect(struct.d).to eq(str3)
|
1224
|
+
expect(struct.b.referent_id).to eq(2635975080)
|
1225
|
+
expect(struct.b.referent).to eq(str1)
|
1226
|
+
expect(struct.c.referent_id).to eq(1027497766)
|
1227
|
+
expect(struct.c.referent).to eq(str2)
|
1228
|
+
expect(struct.d.referent_id).to eq(405081428)
|
1229
|
+
expect(struct.d.referent).to eq(str3)
|
1230
|
+
expect(struct.e).to eq(55)
|
1231
|
+
end
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
context 'with null pointers' do
|
1235
|
+
let(:bin_str) do
|
1236
|
+
"\x03\x00\x00\x00" + # a
|
1237
|
+
"\xA8\xC9\x1D\x9D" + # b referent_id
|
1238
|
+
"\x00\x00\x00\x00" + # c referent_id (null)
|
1239
|
+
"T\r%\x18" + # d referent_id
|
1240
|
+
"7\x00\x00\x00" + # c
|
1241
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
|
1242
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
it 'reads as expected' do
|
1246
|
+
struct.do_read(io)
|
1247
|
+
str1 = 'test1'.encode(Encoding::UTF_16LE)
|
1248
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1249
|
+
expect(struct.a).to eq(3)
|
1250
|
+
expect(struct.b).to eq(str1)
|
1251
|
+
expect(struct.c).to eq(:null)
|
1252
|
+
expect(struct.d).to eq(str3)
|
1253
|
+
expect(struct.b.referent_id).to eq(2635975080)
|
1254
|
+
expect(struct.b.referent).to eq(str1)
|
1255
|
+
expect(struct.c.referent_id).to eq(0)
|
1256
|
+
expect(struct.d.referent_id).to eq(405081428)
|
1257
|
+
expect(struct.d.referent).to eq(str3)
|
1258
|
+
expect(struct.e).to eq(55)
|
1259
|
+
end
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
context 'with null strings' do
|
1263
|
+
let(:bin_str) do
|
1264
|
+
"\x03\x00\x00\x00" + # a
|
1265
|
+
"\xA8\xC9\x1D\x9D" + # b referent_id
|
1266
|
+
"&_>=" + # c referent_id
|
1267
|
+
"T\r%\x18" + # d referent_id
|
1268
|
+
"7\x00\x00\x00" + # c
|
1269
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
|
1270
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # c null string
|
1271
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
|
1272
|
+
end
|
1273
|
+
|
1274
|
+
it 'reads as expected' do
|
1275
|
+
struct.do_read(io)
|
1276
|
+
str1 = 'test1'.encode(Encoding::UTF_16LE)
|
1277
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1278
|
+
expect(struct.a).to eq(3)
|
1279
|
+
expect(struct.b).to eq(str1)
|
1280
|
+
expect(struct.c).to eq(0)
|
1281
|
+
expect(struct.d).to eq(str3)
|
1282
|
+
expect(struct.b.referent_id).to eq(2635975080)
|
1283
|
+
expect(struct.b.referent).to eq(str1)
|
1284
|
+
expect(struct.c.referent_id).to eq(1027497766)
|
1285
|
+
expect(struct.c.referent).to eq(0)
|
1286
|
+
expect(struct.d.referent_id).to eq(405081428)
|
1287
|
+
expect(struct.d.referent).to eq(str3)
|
1288
|
+
expect(struct.e).to eq(55)
|
1289
|
+
end
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
context 'with padding' do
|
1293
|
+
let(:bin_str) do
|
1294
|
+
"\x03\x00\x00\x00" + # a
|
1295
|
+
"\xA8\xC9\x1D\x9D" + # b referent_id
|
1296
|
+
"&_>=" + # c referent_id
|
1297
|
+
"T\r%\x18" + # d referent_id
|
1298
|
+
"7\x00\x00\x00" + # c
|
1299
|
+
"\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00" + # b
|
1300
|
+
"\x00\x00" + # pad
|
1301
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # c
|
1302
|
+
"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
it 'reads as expected' do
|
1306
|
+
struct.do_read(io)
|
1307
|
+
str1 = 'test'.encode(Encoding::UTF_16LE)
|
1308
|
+
str2 = 'test2'.encode(Encoding::UTF_16LE)
|
1309
|
+
str3 = 'test3'.encode(Encoding::UTF_16LE)
|
1310
|
+
expect(struct.a).to eq(3)
|
1311
|
+
expect(struct.b).to eq(str1)
|
1312
|
+
expect(struct.c).to eq(str2)
|
1313
|
+
expect(struct.d).to eq(str3)
|
1314
|
+
expect(struct.b.referent_id).to eq(2635975080)
|
1315
|
+
expect(struct.b.referent).to eq(str1)
|
1316
|
+
expect(struct.c.referent_id).to eq(1027497766)
|
1317
|
+
expect(struct.c.referent).to eq(str2)
|
1318
|
+
expect(struct.d.referent_id).to eq(405081428)
|
1319
|
+
expect(struct.d.referent).to eq(str3)
|
1320
|
+
expect(struct.e).to eq(55)
|
1321
|
+
end
|
1322
|
+
end
|
1323
|
+
end
|
1324
|
+
end
|
1325
|
+
|
1326
|
+
describe '#do_write' do
|
1327
|
+
let(:raw_io) { BinData::IO.create_string_io }
|
1328
|
+
let(:io) { BinData::IO::Write.new(raw_io) }
|
1329
|
+
context 'with a structure containg an array of pointers to integer' do
|
1330
|
+
subject(:struct) do
|
1331
|
+
Class.new(described_class) do
|
1332
|
+
endian :little
|
1333
|
+
uint32 :a
|
1334
|
+
array :b, type: :ndr_lp_dword, read_until: -> { index == a - 1 }
|
1335
|
+
uint32 :c
|
1336
|
+
end.new
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
context 'without null pointers' do
|
1340
|
+
let(:packet) do
|
1341
|
+
struct.new(a: 3, b: [1, 2, 3], c: 55)
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
it 'writes as expected' do
|
1345
|
+
packet.do_write(io)
|
1346
|
+
raw_io.rewind
|
1347
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1348
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
|
1349
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
|
1350
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
|
1351
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
|
1352
|
+
expect(raw_io.read(4)).to eq("\x01\x00\x00\x00".b) # b[0]
|
1353
|
+
expect(raw_io.read(4)).to eq("\x02\x00\x00\x00".b) # b[1]
|
1354
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # b[2]
|
1355
|
+
expect(raw_io.eof).to be true
|
1356
|
+
end
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
context 'with null pointers' do
|
1360
|
+
let(:packet) do
|
1361
|
+
struct.new(a: 3, b: [1, :null, 3], c: 55)
|
1362
|
+
end
|
1363
|
+
|
1364
|
+
it 'writes as expected' do
|
1365
|
+
packet.do_write(io)
|
1366
|
+
raw_io.rewind
|
1367
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1368
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
|
1369
|
+
expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # b[1] referent_id (null)
|
1370
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
|
1371
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
|
1372
|
+
expect(raw_io.read(4)).to eq("\x01\x00\x00\x00".b) # b[0]
|
1373
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # b[2]
|
1374
|
+
expect(raw_io.eof).to be true
|
1375
|
+
end
|
1376
|
+
end
|
1377
|
+
end
|
1378
|
+
|
1379
|
+
context 'with a structure containg an array of pointers to strings' do
|
1380
|
+
subject(:struct) do
|
1381
|
+
Class.new(described_class) do
|
1382
|
+
endian :little
|
1383
|
+
uint32 :a
|
1384
|
+
array :b, type: :ndr_lp_str, read_until: -> { index == a - 1 }
|
1385
|
+
uint32 :c
|
1386
|
+
end.new
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
context 'without null pointers' do
|
1390
|
+
let(:packet) do
|
1391
|
+
struct.new(a: 3, b: ['test1', 'test2', 'test3'], c: 55)
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
it 'writes as expected' do
|
1395
|
+
packet.do_write(io)
|
1396
|
+
raw_io.rewind
|
1397
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1398
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
|
1399
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
|
1400
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
|
1401
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
|
1402
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
|
1403
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00".b) # b[1]
|
1404
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
|
1405
|
+
expect(raw_io.eof).to be true
|
1406
|
+
end
|
1407
|
+
end
|
1408
|
+
|
1409
|
+
context 'with null pointers' do
|
1410
|
+
let(:packet) do
|
1411
|
+
struct.new(a: 3, b: ['test1', :null, 'test3'], c: 55)
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
it 'writes as expected' do
|
1415
|
+
packet.do_write(io)
|
1416
|
+
raw_io.rewind
|
1417
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1418
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
|
1419
|
+
expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # b[1] referent_id (null)
|
1420
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
|
1421
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
|
1422
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
|
1423
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
|
1424
|
+
expect(raw_io.eof).to be true
|
1425
|
+
end
|
1426
|
+
end
|
1427
|
+
|
1428
|
+
context 'with null strings' do
|
1429
|
+
let(:packet) do
|
1430
|
+
struct.new(a: 3, b: ['test1', 0, 'test3'], c: 55)
|
1431
|
+
end
|
1432
|
+
|
1433
|
+
it 'writes as expected' do
|
1434
|
+
packet.do_write(io)
|
1435
|
+
raw_io.rewind
|
1436
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1437
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
|
1438
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
|
1439
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
|
1440
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
|
1441
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
|
1442
|
+
expect(raw_io.read(12)).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".b) # b[1] null string
|
1443
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
|
1444
|
+
expect(raw_io.eof).to be true
|
1445
|
+
end
|
1446
|
+
end
|
1447
|
+
|
1448
|
+
context 'with padding' do
|
1449
|
+
let(:packet) do
|
1450
|
+
struct.new(a: 3, b: ['test1', 'test', 'test3'], c: 55)
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
it 'writes as expected' do
|
1454
|
+
packet.do_write(io)
|
1455
|
+
raw_io.rewind
|
1456
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1457
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
|
1458
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
|
1459
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
|
1460
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
|
1461
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
|
1462
|
+
expect(raw_io.read(22)).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00".b) # b[1]
|
1463
|
+
expect(raw_io.read(2)).to eq("\x00\x00".b) # pad
|
1464
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
|
1465
|
+
expect(raw_io.eof).to be true
|
1466
|
+
end
|
1467
|
+
end
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
context 'with a structure containg pointers to strings' do
|
1471
|
+
subject(:struct) do
|
1472
|
+
Class.new(described_class) do
|
1473
|
+
endian :little
|
1474
|
+
uint32 :a
|
1475
|
+
ndr_lp_str :b
|
1476
|
+
ndr_lp_str :c
|
1477
|
+
ndr_lp_str :d
|
1478
|
+
uint32 :e
|
1479
|
+
end.new
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
context 'without null pointers' do
|
1483
|
+
let(:packet) do
|
1484
|
+
struct.new(a: 3, b: 'test1', c: 'test2', d: 'test3', e: 55)
|
1485
|
+
end
|
1486
|
+
|
1487
|
+
it 'writes as expected' do
|
1488
|
+
packet.do_write(io)
|
1489
|
+
raw_io.rewind
|
1490
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1491
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
|
1492
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
|
1493
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
|
1494
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
|
1495
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
|
1496
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00".b) # c
|
1497
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
|
1498
|
+
expect(raw_io.eof).to be true
|
1499
|
+
end
|
1500
|
+
end
|
1501
|
+
|
1502
|
+
context 'with null pointers' do
|
1503
|
+
let(:packet) do
|
1504
|
+
struct.new(a: 3, b: 'test1', c: :null, d: 'test3', e: 55)
|
1505
|
+
end
|
1506
|
+
|
1507
|
+
it 'writes as expected' do
|
1508
|
+
packet.do_write(io)
|
1509
|
+
raw_io.rewind
|
1510
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1511
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
|
1512
|
+
expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # c referent_id (null)
|
1513
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
|
1514
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
|
1515
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
|
1516
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
|
1517
|
+
expect(raw_io.eof).to be true
|
1518
|
+
end
|
1519
|
+
end
|
1520
|
+
|
1521
|
+
context 'with null strings' do
|
1522
|
+
let(:packet) do
|
1523
|
+
struct.new(a: 3, b: 'test1', c: 0, d: 'test3', e: 55)
|
1524
|
+
end
|
1525
|
+
|
1526
|
+
it 'writes as expected' do
|
1527
|
+
packet.do_write(io)
|
1528
|
+
raw_io.rewind
|
1529
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1530
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
|
1531
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
|
1532
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
|
1533
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
|
1534
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
|
1535
|
+
expect(raw_io.read(12)).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".b) # c
|
1536
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
|
1537
|
+
expect(raw_io.eof).to be true
|
1538
|
+
end
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
context 'with padding' do
|
1542
|
+
let(:packet) do
|
1543
|
+
struct.new(a: 3, b: 'test1', c: 'test', d: 'test3', e: 55)
|
1544
|
+
end
|
1545
|
+
|
1546
|
+
it 'writes as expected' do
|
1547
|
+
packet.do_write(io)
|
1548
|
+
raw_io.rewind
|
1549
|
+
expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
|
1550
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
|
1551
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
|
1552
|
+
expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
|
1553
|
+
expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
|
1554
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
|
1555
|
+
expect(raw_io.read(22)).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00".b) # c
|
1556
|
+
expect(raw_io.read(2)).to eq("\x00\x00".b) # pad
|
1557
|
+
expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
|
1558
|
+
expect(raw_io.eof).to be true
|
1559
|
+
end
|
1560
|
+
end
|
1561
|
+
end
|
1562
|
+
end
|
1563
|
+
end
|
1564
|
+
|
1565
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrStringPtrsw do
|
1566
|
+
subject(:packet) { described_class.new }
|
1567
|
+
|
1568
|
+
it { is_expected.to respond_to :max_count }
|
1569
|
+
it { is_expected.to respond_to :elements }
|
1570
|
+
|
1571
|
+
it 'is little endian' do
|
1572
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
1573
|
+
end
|
1574
|
+
|
1575
|
+
describe '#max_count' do
|
1576
|
+
it 'is a 32-bit unsigned integer' do
|
1577
|
+
expect(packet.max_count).to be_a BinData::Uint32le
|
1578
|
+
end
|
1579
|
+
|
1580
|
+
it 'has an initial value equal to #elements size' do
|
1581
|
+
packet.elements = ['A', 'B', 'C']
|
1582
|
+
expect(packet.max_count).to eq(3)
|
1583
|
+
end
|
1584
|
+
end
|
1585
|
+
|
1586
|
+
describe '#elements' do
|
1587
|
+
it 'is a Bindata::Array' do
|
1588
|
+
expect(packet.elements).to be_a BinData::Array
|
1589
|
+
end
|
1590
|
+
|
1591
|
+
it 'is an array of NdrLpStr' do
|
1592
|
+
expect(packet.elements[0]).to be_a RubySMB::Dcerpc::Ndr::NdrLpStr
|
1593
|
+
end
|
1594
|
+
|
1595
|
+
it 'exists if #max_count is greater than 0' do
|
1596
|
+
packet.max_count = 2
|
1597
|
+
expect(packet.elements?).to be true
|
1598
|
+
end
|
1599
|
+
|
1600
|
+
it 'does not exist if #max_count is 0' do
|
1601
|
+
packet.max_count = 0
|
1602
|
+
expect(packet.elements?).to be false
|
1603
|
+
end
|
1604
|
+
end
|
1605
|
+
|
1606
|
+
describe '#get' do
|
1607
|
+
it 'returns elements' do
|
1608
|
+
packet.elements = ['1', '2', '3']
|
1609
|
+
expect(packet.get).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
|
1610
|
+
end
|
1611
|
+
end
|
1612
|
+
|
1613
|
+
describe '#set' do
|
1614
|
+
it 'sets #elements as expected' do
|
1615
|
+
packet.set(['1', '2', '3'])
|
1616
|
+
expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
it 'sets #max_count to the number of elements set' do
|
1620
|
+
packet.set(['1', '2', '3'])
|
1621
|
+
expect(packet.max_count).to eq(3)
|
1622
|
+
end
|
1623
|
+
|
1624
|
+
it 'calls #to_ary before setting the elements' do
|
1625
|
+
ary = BinData::Array.new(['1','2', '3'], type: :ndr_lp_str)
|
1626
|
+
expect(ary).to receive(:to_ary).and_call_original
|
1627
|
+
packet.set(ary)
|
1628
|
+
expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
|
1629
|
+
end
|
1630
|
+
|
1631
|
+
it 'keeps custom #max_count value when called from #to_binary_s' do
|
1632
|
+
packet.set(['1', '2', '3', '4', '5'])
|
1633
|
+
packet.max_count = 3
|
1634
|
+
packet.to_binary_s
|
1635
|
+
expect(packet.max_count).to eq(3)
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
it 'keeps custom #max_count and #offset values when called from #do_num_bytes' do
|
1639
|
+
packet.set(['1', '2', '3', '4', '5'])
|
1640
|
+
packet.max_count = 3
|
1641
|
+
packet.do_num_bytes
|
1642
|
+
expect(packet.max_count).to eq(3)
|
1643
|
+
end
|
1644
|
+
|
1645
|
+
it 'sets #max_count to the number of elements set after setting custom #max_count value' do
|
1646
|
+
packet.set(['1', '2', '3', '4', '5'])
|
1647
|
+
packet.max_count = 3
|
1648
|
+
packet.set(['1', '2', '3', '4', '5'])
|
1649
|
+
expect(packet.max_count).to eq(5)
|
1650
|
+
end
|
1651
|
+
end
|
1652
|
+
|
1653
|
+
describe '#read' do
|
1654
|
+
context 'with a no elements' do
|
1655
|
+
it 'reads its own binary representation' do
|
1656
|
+
raw = packet.to_binary_s
|
1657
|
+
expect(described_class.read(raw)).to eq(packet)
|
1658
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
1659
|
+
end
|
1660
|
+
end
|
1661
|
+
|
1662
|
+
context 'with some elements' do
|
1663
|
+
it 'reads its own binary representation' do
|
1664
|
+
packet.set(['1', '2', '3'])
|
1665
|
+
raw = packet.to_binary_s
|
1666
|
+
expect(described_class.read(raw)).to eq(packet)
|
1667
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
1668
|
+
end
|
1669
|
+
end
|
1670
|
+
end
|
1671
|
+
end
|
1672
|
+
|
1673
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStringPtrsw do
|
1674
|
+
it 'is NdrPointer subclass' do
|
1675
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
|
1676
|
+
end
|
1677
|
+
|
1678
|
+
subject(:packet) { described_class.new }
|
1679
|
+
|
1680
|
+
it { is_expected.to respond_to :referent }
|
1681
|
+
|
1682
|
+
it 'is little endian' do
|
1683
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
describe '#referent' do
|
1687
|
+
it 'is a NdrStringPtrsw structure' do
|
1688
|
+
expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrStringPtrsw
|
1689
|
+
end
|
1690
|
+
|
1691
|
+
it 'exists if superclass #referent_id is not zero' do
|
1692
|
+
packet.referent_id = 0xCCCC
|
1693
|
+
expect(packet.referent?).to be true
|
1694
|
+
end
|
1695
|
+
|
1696
|
+
it 'does not exist if superclass #referent_id is zero' do
|
1697
|
+
packet.referent_id = 0
|
1698
|
+
expect(packet.referent?).to be false
|
1699
|
+
end
|
1700
|
+
end
|
1701
|
+
|
1702
|
+
describe '#set' do
|
1703
|
+
it 'calls #to_ary before setting the elements, if supported' do
|
1704
|
+
ary = BinData::Array.new(['1', '2', '3'], type: :ndr_lp_str)
|
1705
|
+
expect(ary).to receive(:to_ary).and_call_original
|
1706
|
+
packet.set(ary)
|
1707
|
+
expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
|
1708
|
+
end
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
describe '#read' do
|
1712
|
+
context 'with a null pointer' do
|
1713
|
+
it 'reads its own binary representation' do
|
1714
|
+
raw = packet.to_binary_s
|
1715
|
+
expect(described_class.read(raw)).to eq(packet)
|
1716
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
1717
|
+
end
|
1718
|
+
end
|
1719
|
+
|
1720
|
+
context 'with a normal NdrStringPtrsw structure' do
|
1721
|
+
it 'reads its own binary representation' do
|
1722
|
+
packet.set(['1', '2', '3'])
|
1723
|
+
raw = packet.to_binary_s
|
1724
|
+
expect(described_class.read(raw)).to eq(packet)
|
1725
|
+
expect(described_class.read(raw).to_binary_s).to eq(raw)
|
1726
|
+
end
|
1727
|
+
end
|
1728
|
+
end
|
1729
|
+
end
|