ruby_smb 2.0.2 → 3.0.0
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/verify.yml +46 -0
- data/README.md +0 -1
- data/examples/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/auth_capture.rb +71 -0
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/dump_secrets_from_sid.rb +207 -0
- data/examples/enum_domain_users.rb +75 -0
- data/examples/enum_registry_key.rb +5 -4
- data/examples/enum_registry_values.rb +5 -4
- data/examples/get_computer_info.rb +42 -0
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +11 -12
- data/examples/query_service_status.rb +102 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_registry_key_value.rb +6 -5
- 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/client/authentication.rb +5 -10
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/negotiation.rb +13 -16
- data/lib/ruby_smb/client/tree_connect.rb +2 -4
- data/lib/ruby_smb/client/utils.rb +16 -10
- data/lib/ruby_smb/client/winreg.rb +1 -1
- data/lib/ruby_smb/client.rb +102 -75
- data/lib/ruby_smb/compression/lznt1.rb +164 -0
- data/lib/ruby_smb/compression.rb +7 -0
- data/lib/ruby_smb/dcerpc/bind.rb +28 -20
- data/lib/ruby_smb/dcerpc/bind_ack.rb +29 -28
- data/lib/ruby_smb/dcerpc/client.rb +542 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_bind_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_bind_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_request.rb +57 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_response.rb +76 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_request.rb +46 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_response.rb +168 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_extensions.rb +56 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_request.rb +121 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_response.rb +118 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_unbind_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_unbind_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/drsr.rb +909 -0
- data/lib/ruby_smb/dcerpc/epm/epm_ept_map_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/epm/epm_ept_map_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/epm/epm_twrt.rb +211 -0
- data/lib/ruby_smb/dcerpc/epm.rb +75 -0
- data/lib/ruby_smb/dcerpc/error.rb +20 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +1204 -80
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/netlogon.rb +102 -0
- data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +4 -3
- data/lib/ruby_smb/dcerpc/pdu_header.rb +7 -7
- data/lib/ruby_smb/dcerpc/ptypes.rb +1 -0
- data/lib/ruby_smb/dcerpc/request.rb +85 -19
- data/lib/ruby_smb/dcerpc/response.rb +45 -10
- data/lib/ruby_smb/dcerpc/rpc_auth3.rb +28 -0
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +118 -0
- data/lib/ruby_smb/dcerpc/samr/rpc_sid.rb +150 -0
- data/lib/ruby_smb/dcerpc/samr/samr_close_handle_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_close_handle_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_connect_request.rb +32 -0
- data/lib/ruby_smb/dcerpc/samr/samr_connect_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +55 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +38 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_response.rb +48 -0
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_domain_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_domain_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_user_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_user_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr.rb +613 -0
- data/lib/ruby_smb/dcerpc/sec_trailer.rb +26 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +56 -79
- data/lib/ruby_smb/dcerpc/srvsvc.rb +27 -4
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +36 -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 +25 -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 +23 -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 +45 -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 +26 -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/svcctl.rb +477 -0
- data/lib/ruby_smb/dcerpc/uuid.rb +3 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +2 -2
- data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +62 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +2 -19
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +3 -20
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +5 -14
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +5 -14
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +1 -9
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +4 -3
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +6 -7
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +2 -2
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +9 -18
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +4 -13
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +7 -15
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +3 -1
- data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +28 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +99 -22
- data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response.rb +88 -0
- data/lib/ruby_smb/dcerpc/wkssvc.rb +65 -0
- data/lib/ruby_smb/dcerpc.rb +45 -11
- data/lib/ruby_smb/dialect.rb +45 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +2 -2
- data/lib/ruby_smb/error.rb +21 -5
- data/lib/ruby_smb/field/file_time.rb +1 -1
- data/lib/ruby_smb/field/string16.rb +5 -1
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/generic_packet.rb +11 -1
- data/lib/ruby_smb/gss/provider/authenticator.rb +42 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +303 -0
- data/lib/ruby_smb/gss/provider.rb +35 -0
- data/lib/ruby_smb/gss.rb +56 -63
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/ntlm.rb +61 -0
- data/lib/ruby_smb/server/server_client/negotiation.rb +156 -0
- data/lib/ruby_smb/server/server_client/session_setup.rb +82 -0
- data/lib/ruby_smb/server/server_client.rb +162 -0
- data/lib/ruby_smb/server.rb +54 -0
- data/lib/ruby_smb/signing.rb +59 -0
- data/lib/ruby_smb/smb1/file.rb +10 -25
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +11 -11
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
- data/lib/ruby_smb/smb1/pipe.rb +12 -6
- data/lib/ruby_smb/smb1/tree.rb +13 -9
- data/lib/ruby_smb/smb2/file.rb +33 -33
- data/lib/ruby_smb/smb2/negotiate_context.rb +18 -2
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +4 -0
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +9 -0
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +0 -1
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +1 -1
- data/lib/ruby_smb/smb2/pipe.rb +13 -6
- data/lib/ruby_smb/smb2/tree.rb +21 -11
- data/lib/ruby_smb/smb2.rb +3 -1
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +199 -86
- data/spec/lib/ruby_smb/compression/lznt1_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +69 -41
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +75 -21
- data/spec/lib/ruby_smb/dcerpc/client_spec.rb +714 -0
- data/spec/lib/ruby_smb/dcerpc/drsr_spec.rb +2169 -0
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +3977 -239
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +18 -4
- data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +27 -1
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +76 -11
- data/spec/lib/ruby_smb/dcerpc/response_spec.rb +99 -9
- data/spec/lib/ruby_smb/dcerpc/rpc_auth3_spec.rb +75 -0
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +162 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string_spec.rb +340 -0
- data/spec/lib/ruby_smb/dcerpc/samr/rpc_sid_spec.rb +116 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_request_spec.rb +40 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_response_spec.rb +48 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_request_spec.rb +56 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_response_spec.rb +47 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request_spec.rb +63 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +265 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request_spec.rb +52 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_request_spec.rb +56 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_response_spec.rb +48 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request_spec.rb +48 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response_spec.rb +42 -0
- data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +420 -0
- data/spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb +92 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +149 -110
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +21 -17
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +168 -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 +68 -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 +53 -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 +76 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +47 -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 +508 -0
- data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +15 -23
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +73 -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 +4 -56
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +4 -56
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +10 -34
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +10 -34
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +2 -26
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +17 -20
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +20 -44
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +8 -32
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +18 -42
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +4 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +219 -62
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb +43 -0
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb +70 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
- data/spec/lib/ruby_smb/error_spec.rb +34 -5
- data/spec/lib/ruby_smb/field/string16_spec.rb +22 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm/account_spec.rb +32 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +101 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm/os_version_spec.rb +32 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm_spec.rb +113 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/server/server_client_spec.rb +156 -0
- data/spec/lib/ruby_smb/server_spec.rb +32 -0
- data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +20 -14
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +20 -14
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/bin_helper.rb +9 -0
- data.tar.gz.sig +0 -0
- metadata +229 -23
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -6
- data/lib/ruby_smb/client/signing.rb +0 -64
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +0 -35
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +0 -98
|
@@ -1,410 +1,4148 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
require 'ruby_smb/dcerpc/ndr'
|
|
2
|
+
|
|
3
|
+
RSpec.shared_examples 'a properly aligned field in a NdrStruct' do |field, alignment|
|
|
4
|
+
let(:test_struct_class) do
|
|
5
|
+
klass = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
6
|
+
default_parameters byte_align: alignment
|
|
7
|
+
ndr_char :a
|
|
8
|
+
end
|
|
9
|
+
klass.send(field.to_sym, :test)
|
|
10
|
+
klass
|
|
11
|
+
end
|
|
12
|
+
let(:test_struct) do
|
|
13
|
+
test_struct_class.new(a: 'A', test: test_value)
|
|
7
14
|
end
|
|
15
|
+
let(:struct_bin) { "A#{"\x00" * (alignment - 1)}#{test_bin}".b }
|
|
8
16
|
|
|
9
|
-
it
|
|
17
|
+
it "is always #{alignment}-bytes aligned" do
|
|
18
|
+
(1..8).each do |i|
|
|
19
|
+
test_struct = test_struct_class.new(a: 'A' * i, test: test_value)
|
|
20
|
+
expect(test_struct.test.abs_offset % alignment).to eq(0)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
it 'writes the expected binary stream with the correct padding bytes' do
|
|
24
|
+
expect(test_struct.to_binary_s).to eq(struct_bin)
|
|
25
|
+
end
|
|
26
|
+
it 'reads a padded binary stream' do
|
|
27
|
+
test_struct2 = test_struct_class.read(struct_bin)
|
|
28
|
+
expect(test_struct2).to eq(test_struct)
|
|
29
|
+
end
|
|
30
|
+
it 'reports the expected structure size' do
|
|
31
|
+
expect(test_struct.num_bytes).to eq(struct_bin.size)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
10
34
|
|
|
11
|
-
|
|
12
|
-
|
|
35
|
+
RSpec.shared_examples 'a properly aligned conformant structure in a NdrStruct' do |field, alignment|
|
|
36
|
+
let(:test_struct_class) do
|
|
37
|
+
klass = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
38
|
+
default_parameters byte_align: alignment
|
|
39
|
+
ndr_char :a
|
|
40
|
+
end
|
|
41
|
+
klass.send(field.to_sym, :test)
|
|
42
|
+
klass
|
|
43
|
+
end
|
|
44
|
+
let(:test_struct) do
|
|
45
|
+
test_struct_class.new(a: 'A', test: test_value)
|
|
46
|
+
end
|
|
47
|
+
let(:struct_bin) do
|
|
48
|
+
max_count = test_bin.slice!(0, 4)
|
|
49
|
+
offset = max_count.size + 1
|
|
50
|
+
align = (alignment - (offset % alignment)) % alignment
|
|
51
|
+
"#{max_count}A#{"\x00" * align}#{test_bin}".b
|
|
13
52
|
end
|
|
14
53
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
54
|
+
it "is always #{alignment}-bytes aligned" do
|
|
55
|
+
(1..8).each do |i|
|
|
56
|
+
test_struct = test_struct_class.new(a: 'A' * i, test: test_value)
|
|
57
|
+
expect(test_struct.test.abs_offset % alignment).to eq(0)
|
|
18
58
|
end
|
|
59
|
+
end
|
|
60
|
+
it 'writes the expected binary stream with the correct padding bytes' do
|
|
61
|
+
expect(test_struct.to_binary_s).to eq(struct_bin)
|
|
62
|
+
end
|
|
63
|
+
it 'reads a padded binary stream' do
|
|
64
|
+
test_struct2 = test_struct_class.read(struct_bin)
|
|
65
|
+
expect(test_struct2).to eq(test_struct)
|
|
66
|
+
end
|
|
67
|
+
it 'reports the expected structure size' do
|
|
68
|
+
expect(test_struct.num_bytes).to eq(struct_bin.size)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrBoolean do
|
|
73
|
+
it 'is a BinData::Uint32le class' do
|
|
74
|
+
expect(described_class).to be < BinData::Uint32le
|
|
75
|
+
end
|
|
76
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
77
|
+
expect(described_class.default_parameters[:byte_align]).to eq(4)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
subject(:boolean) { described_class.new }
|
|
19
81
|
|
|
20
|
-
|
|
21
|
-
|
|
82
|
+
context 'with #new' do
|
|
83
|
+
it 'is false its default value' do
|
|
84
|
+
expect(boolean.new).to eq(false)
|
|
85
|
+
end
|
|
86
|
+
it 'sets true to true' do
|
|
87
|
+
expect(boolean.new(true)).to eq(true)
|
|
88
|
+
end
|
|
89
|
+
it 'sets false to false' do
|
|
90
|
+
expect(boolean.new(false)).to eq(false)
|
|
91
|
+
end
|
|
92
|
+
it 'sets 1 to true' do
|
|
93
|
+
expect(boolean.new(1)).to eq(true)
|
|
94
|
+
end
|
|
95
|
+
it 'sets 0 to false' do
|
|
96
|
+
expect(boolean.new(0)).to eq(false)
|
|
97
|
+
end
|
|
98
|
+
it 'sets any integer > 0 to true' do
|
|
99
|
+
expect(boolean.new(rand(1..1000))).to eq(true)
|
|
100
|
+
end
|
|
101
|
+
it 'raises an ArgumentError error when passing a String' do
|
|
102
|
+
expect { boolean.new("false") }.to raise_error(ArgumentError)
|
|
22
103
|
end
|
|
23
104
|
end
|
|
24
105
|
|
|
25
|
-
|
|
26
|
-
it '
|
|
27
|
-
|
|
28
|
-
expect(
|
|
106
|
+
context 'with #assign' do
|
|
107
|
+
it 'sets true to true' do
|
|
108
|
+
boolean.assign(true)
|
|
109
|
+
expect(boolean).to eq(true)
|
|
110
|
+
end
|
|
111
|
+
it 'sets false to false' do
|
|
112
|
+
boolean.assign(false)
|
|
113
|
+
expect(boolean).to eq(false)
|
|
114
|
+
end
|
|
115
|
+
it 'sets 1 to true' do
|
|
116
|
+
boolean.assign(1)
|
|
117
|
+
expect(boolean).to eq(true)
|
|
118
|
+
end
|
|
119
|
+
it 'sets 0 to false' do
|
|
120
|
+
boolean.assign(0)
|
|
121
|
+
expect(boolean).to eq(false)
|
|
122
|
+
end
|
|
123
|
+
it 'sets any integer > 0 to true' do
|
|
124
|
+
boolean.assign(rand(1..100))
|
|
125
|
+
expect(boolean).to eq(true)
|
|
29
126
|
end
|
|
127
|
+
it 'raises an ArgumentError error when passing a String' do
|
|
128
|
+
expect { boolean.assign("false") }.to raise_error(ArgumentError)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
30
131
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
132
|
+
context 'when reading data' do
|
|
133
|
+
it 'sets false with an uint32 zero value' do
|
|
134
|
+
boolean.read("\x00\x00\x00\x00")
|
|
135
|
+
expect(boolean).to eq(false)
|
|
136
|
+
end
|
|
137
|
+
it 'sets true with an uint32 1 value' do
|
|
138
|
+
boolean.read("\x01\x00\x00\x00")
|
|
139
|
+
expect(boolean).to eq(true)
|
|
140
|
+
end
|
|
141
|
+
it 'sets true with any uint32 value > 0' do
|
|
142
|
+
boolean.read([rand(1..1000)].pack('L'))
|
|
143
|
+
expect(boolean).to eq(true)
|
|
144
|
+
end
|
|
145
|
+
it 'reads itself' do
|
|
146
|
+
expect(boolean.read(described_class.new(true).to_binary_s)).to eq(true)
|
|
34
147
|
end
|
|
35
148
|
end
|
|
36
149
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
expect(packet.referent_identifier).to eq(0)
|
|
42
|
-
end
|
|
150
|
+
context 'with #to_binary_s' do
|
|
151
|
+
it 'returns the expected true binary representation' do
|
|
152
|
+
boolean.assign(true)
|
|
153
|
+
expect(boolean.to_binary_s).to eq("\x01\x00\x00\x00")
|
|
43
154
|
end
|
|
155
|
+
it 'returns the expected false binary representation' do
|
|
156
|
+
boolean.assign(false)
|
|
157
|
+
expect(boolean.to_binary_s).to eq("\x00\x00\x00\x00")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
44
160
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expect(packet.referent).to eq(str)
|
|
50
|
-
end
|
|
161
|
+
context 'when testing alignment in a NdrStruct' do
|
|
162
|
+
it_behaves_like 'a properly aligned field in a NdrStruct', described_class.bindata_name.to_sym, 4 do
|
|
163
|
+
let(:test_value) { 1 }
|
|
164
|
+
let(:test_bin) { "\x01\x00\x00\x00".b }
|
|
51
165
|
end
|
|
52
166
|
end
|
|
53
167
|
end
|
|
54
168
|
|
|
55
|
-
RSpec.describe RubySMB::Dcerpc::Ndr::
|
|
56
|
-
|
|
169
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrChar do
|
|
170
|
+
it 'is a BinData::String class' do
|
|
171
|
+
expect(described_class).to be < BinData::String
|
|
172
|
+
end
|
|
173
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
174
|
+
expect(described_class.default_parameters[:byte_align]).to eq(1)
|
|
175
|
+
end
|
|
57
176
|
|
|
58
|
-
|
|
59
|
-
it { is_expected.to respond_to :offset }
|
|
60
|
-
it { is_expected.to respond_to :actual_count }
|
|
61
|
-
it { is_expected.to respond_to :str }
|
|
177
|
+
subject(:char) { described_class.new }
|
|
62
178
|
|
|
63
|
-
|
|
64
|
-
|
|
179
|
+
context 'with #new' do
|
|
180
|
+
it 'is "\x00" its default value' do
|
|
181
|
+
expect(char.new).to eq("\x00")
|
|
182
|
+
end
|
|
183
|
+
it 'sets a character' do
|
|
184
|
+
expect(char.new('A')).to eq('A')
|
|
185
|
+
end
|
|
186
|
+
it 'sets the first character when passing a String' do
|
|
187
|
+
expect(char.new('ABC')).to eq('A')
|
|
188
|
+
end
|
|
189
|
+
it 'does not set a value when passing anything else than a string' do
|
|
190
|
+
char.new(['ABC'])
|
|
191
|
+
expect(char).to eq("\x00")
|
|
192
|
+
char.new(67)
|
|
193
|
+
expect(char).to eq("\x00")
|
|
194
|
+
end
|
|
65
195
|
end
|
|
66
196
|
|
|
67
|
-
|
|
68
|
-
it '
|
|
69
|
-
|
|
197
|
+
context 'with #assign' do
|
|
198
|
+
it 'sets a character' do
|
|
199
|
+
char.assign('A')
|
|
200
|
+
expect(char).to eq('A')
|
|
201
|
+
end
|
|
202
|
+
it 'sets the first character when passing a String' do
|
|
203
|
+
char.assign('ABC')
|
|
204
|
+
expect(char).to eq('A')
|
|
205
|
+
end
|
|
206
|
+
it 'converts the argument to string and keeps the first character' do
|
|
207
|
+
char.assign(['ABC'])
|
|
208
|
+
expect(char).to eq('[')
|
|
209
|
+
char.assign(67)
|
|
210
|
+
expect(char).to eq('6')
|
|
70
211
|
end
|
|
71
212
|
end
|
|
72
213
|
|
|
73
|
-
|
|
74
|
-
it '
|
|
75
|
-
|
|
214
|
+
context 'when reading data' do
|
|
215
|
+
it 'sets a character' do
|
|
216
|
+
char.read("\x41")
|
|
217
|
+
expect(char).to eq('A')
|
|
76
218
|
end
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
expect(packet.offset).to eq(0)
|
|
219
|
+
it 'reads itself' do
|
|
220
|
+
expect(char.read(described_class.new('A').to_binary_s)).to eq('A')
|
|
80
221
|
end
|
|
81
222
|
end
|
|
82
223
|
|
|
83
|
-
|
|
84
|
-
it '
|
|
85
|
-
|
|
224
|
+
context 'with #to_binary_s' do
|
|
225
|
+
it 'returns the expected character binary representation' do
|
|
226
|
+
char.assign('A')
|
|
227
|
+
expect(char.to_binary_s).to eq("\x41")
|
|
86
228
|
end
|
|
87
229
|
end
|
|
88
230
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
231
|
+
context 'when testing alignment in a NdrStruct' do
|
|
232
|
+
it_behaves_like 'a properly aligned field in a NdrStruct', described_class.bindata_name.to_sym, 1 do
|
|
233
|
+
let(:test_value) { 'B' }
|
|
234
|
+
let(:test_bin) { 'B'.b }
|
|
92
235
|
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrWideChar do
|
|
240
|
+
it 'is a RubySMB::Field::String16 class' do
|
|
241
|
+
expect(described_class).to be < RubySMB::Field::String16
|
|
242
|
+
end
|
|
243
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
244
|
+
expect(described_class.default_parameters[:byte_align]).to eq(2)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
subject(:char) { described_class.new }
|
|
93
248
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
expect(
|
|
249
|
+
context 'with #new' do
|
|
250
|
+
it 'is "\x00" its default value' do
|
|
251
|
+
expect(char.new).to eq("\x00".encode('utf-16le'))
|
|
97
252
|
end
|
|
253
|
+
it 'sets a character' do
|
|
254
|
+
expect(char.new('A')).to eq('A'.encode('utf-16le'))
|
|
255
|
+
end
|
|
256
|
+
it 'sets the first character when passing a String' do
|
|
257
|
+
expect(char.new('ABC')).to eq('A'.encode('utf-16le'))
|
|
258
|
+
end
|
|
259
|
+
it 'does not set a value when passing anything else than a string' do
|
|
260
|
+
char.new(['ABC'])
|
|
261
|
+
expect(char).to eq("\x00".encode('utf-16le'))
|
|
262
|
+
char.new(67)
|
|
263
|
+
expect(char).to eq("\x00".encode('utf-16le'))
|
|
264
|
+
end
|
|
265
|
+
end
|
|
98
266
|
|
|
99
|
-
|
|
100
|
-
|
|
267
|
+
context 'with #assign' do
|
|
268
|
+
it 'sets a character' do
|
|
269
|
+
char.assign('A')
|
|
270
|
+
expect(char).to eq('A'.encode('utf-16le'))
|
|
271
|
+
end
|
|
272
|
+
it 'sets the first character when passing a String' do
|
|
273
|
+
char.assign('ABC')
|
|
274
|
+
expect(char).to eq('A'.encode('utf-16le'))
|
|
275
|
+
end
|
|
276
|
+
it 'converts the argument to string and keeps the first character' do
|
|
277
|
+
char.assign(['ABC'])
|
|
278
|
+
expect(char).to eq('['.encode('utf-16le'))
|
|
279
|
+
char.assign(67)
|
|
280
|
+
expect(char).to eq('6'.encode('utf-16le'))
|
|
101
281
|
end
|
|
102
282
|
end
|
|
103
283
|
|
|
104
|
-
|
|
105
|
-
it '
|
|
106
|
-
|
|
284
|
+
context 'when reading data' do
|
|
285
|
+
it 'sets a character' do
|
|
286
|
+
char.read("\x41\x00")
|
|
287
|
+
expect(char).to eq('A'.encode('utf-16le'))
|
|
107
288
|
end
|
|
289
|
+
it 'reads itself' do
|
|
290
|
+
expect(char.read(described_class.new('A').to_binary_s)).to eq('A'.encode('utf-16le'))
|
|
291
|
+
end
|
|
292
|
+
end
|
|
108
293
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
expect(packet.get).to eq(strz16)
|
|
294
|
+
context 'with #to_binary_s' do
|
|
295
|
+
it 'returns the expected character binary representation' do
|
|
296
|
+
char.assign('A')
|
|
297
|
+
expect(char.to_binary_s).to eq("\x41\x00")
|
|
114
298
|
end
|
|
115
299
|
end
|
|
116
300
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
expect(packet.actual_count).to eq(0)
|
|
122
|
-
end
|
|
301
|
+
context 'when testing alignment in a NdrStruct' do
|
|
302
|
+
it_behaves_like 'a properly aligned field in a NdrStruct', described_class.bindata_name.to_sym, 2 do
|
|
303
|
+
let(:test_value) { 'B' }
|
|
304
|
+
let(:test_bin) { "B\x00".b }
|
|
123
305
|
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
124
308
|
|
|
125
|
-
|
|
126
|
-
|
|
309
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrEnum do
|
|
310
|
+
it 'is a BinData::Int16le class' do
|
|
311
|
+
expect(described_class).to be < BinData::Int16le
|
|
312
|
+
end
|
|
313
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
314
|
+
expect(described_class.default_parameters[:byte_align]).to eq(2)
|
|
315
|
+
end
|
|
127
316
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
317
|
+
context 'when testing alignment in a NdrStruct' do
|
|
318
|
+
it_behaves_like 'a properly aligned field in a NdrStruct', described_class.bindata_name.to_sym, 2 do
|
|
319
|
+
let(:test_value) { 1 }
|
|
320
|
+
let(:test_bin) { "\x01\x00".b }
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
{
|
|
326
|
+
NdrUint8: { parent_class: :Uint8, nb_bytes: 1},
|
|
327
|
+
NdrUint16: { parent_class: :Uint16le, nb_bytes: 2},
|
|
328
|
+
NdrUint32: { parent_class: :Uint32le, nb_bytes: 4},
|
|
329
|
+
NdrUint64: { parent_class: :Uint64le, nb_bytes: 8},
|
|
330
|
+
}.each do |klass, info|
|
|
331
|
+
full_klass = RubySMB::Dcerpc::Ndr.const_get(klass)
|
|
332
|
+
RSpec.describe(full_klass) do
|
|
333
|
+
it "is a BinData::#{info[:parent_class]} class" do
|
|
334
|
+
expect(described_class).to be < BinData.const_get(info[:parent_class])
|
|
335
|
+
end
|
|
336
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
337
|
+
expect(described_class.default_parameters[:byte_align]).to eq(info[:nb_bytes])
|
|
338
|
+
end
|
|
133
339
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
340
|
+
context 'when testing alignment in a NdrStruct' do
|
|
341
|
+
it_behaves_like 'a properly aligned field in a NdrStruct', full_klass.bindata_name.to_sym, info[:nb_bytes] do
|
|
342
|
+
let(:test_value) { 1 }
|
|
343
|
+
let(:test_bin) { "\x01#{"\x00" * (info[:nb_bytes] - 1)}".b }
|
|
138
344
|
end
|
|
139
345
|
end
|
|
140
346
|
end
|
|
141
347
|
end
|
|
142
348
|
|
|
143
|
-
RSpec.describe RubySMB::Dcerpc::Ndr::
|
|
144
|
-
it 'is
|
|
145
|
-
expect(described_class).to be < RubySMB::
|
|
349
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrFileTime do
|
|
350
|
+
it 'is a RubySMB::Field::FileTime' do
|
|
351
|
+
expect(described_class).to be < RubySMB::Field::FileTime
|
|
352
|
+
end
|
|
353
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
354
|
+
expect(described_class.default_parameters[:byte_align]).to eq(4)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
context 'when testing alignment in a NdrStruct' do
|
|
358
|
+
it_behaves_like 'a properly aligned field in a NdrStruct', described_class.bindata_name.to_sym, 4 do
|
|
359
|
+
let(:test_value) { 132820620350000000 }
|
|
360
|
+
let(:test_bin) { "\x80\v\xCF\x86\xA6\xDF\xD7\x01" }
|
|
361
|
+
end
|
|
146
362
|
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
#####################################
|
|
366
|
+
# NDR Constructed Types #
|
|
367
|
+
#####################################
|
|
147
368
|
|
|
148
|
-
subject(:packet) { described_class.new }
|
|
149
369
|
|
|
150
|
-
|
|
370
|
+
#
|
|
371
|
+
# Arrays
|
|
372
|
+
#
|
|
151
373
|
|
|
152
|
-
|
|
153
|
-
|
|
374
|
+
RSpec.shared_examples "a BinData::Array" do
|
|
375
|
+
it 'is a BinData::Array class' do
|
|
376
|
+
expect(described_class).to be < BinData::Array
|
|
377
|
+
end
|
|
378
|
+
it 'is an empty array by default' do
|
|
379
|
+
expect(described_class.new(type: element_class)).to eq([])
|
|
154
380
|
end
|
|
155
381
|
|
|
156
|
-
|
|
157
|
-
it '
|
|
158
|
-
expect(
|
|
382
|
+
context 'with elements' do
|
|
383
|
+
it 'contains the expected element types' do
|
|
384
|
+
expect(subject.all? {|e| e.is_a?(element_class)}).to be true
|
|
159
385
|
end
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
expect(packet.referent?).to be true
|
|
386
|
+
it 'has the expected size' do
|
|
387
|
+
expect(subject.size).to eq(values.size)
|
|
163
388
|
end
|
|
164
389
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
390
|
+
context 'when setting a value at index greater than the current number of elements' do
|
|
391
|
+
let(:index_offset) { 3 }
|
|
392
|
+
let(:new_element) { element_class.new(values[0]) }
|
|
393
|
+
before :example do
|
|
394
|
+
subject[values.size + index_offset] = new_element
|
|
395
|
+
end
|
|
396
|
+
it 'adds elements until it reaches the new index' do
|
|
397
|
+
expect(subject.size).to eq(values.size + index_offset + 1)
|
|
398
|
+
end
|
|
399
|
+
it 'sets the new elements to the element type default value' do
|
|
400
|
+
(values.size..(index_offset - 1)).each do |i|
|
|
401
|
+
expect(subject[i]).to eq(0)
|
|
402
|
+
end
|
|
403
|
+
expect(subject[values.size + index_offset]).to eq(new_element)
|
|
404
|
+
end
|
|
168
405
|
end
|
|
169
|
-
end
|
|
170
406
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
407
|
+
context 'when getting a value at index greater than the current number of elements' do
|
|
408
|
+
let(:index_offset) { 3 }
|
|
409
|
+
it 'adds elements until it reaches the new index' do
|
|
410
|
+
subject[values.size + index_offset]
|
|
411
|
+
expect(subject.size).to eq(values.size + index_offset + 1)
|
|
412
|
+
end
|
|
413
|
+
it 'sets the new elements to the element type default value' do
|
|
414
|
+
(values.size..index_offset).each do |i|
|
|
415
|
+
expect(subject[i]).to eq(element_class.new)
|
|
416
|
+
end
|
|
417
|
+
end
|
|
175
418
|
end
|
|
176
419
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
420
|
+
context 'when assigning another array' do
|
|
421
|
+
let(:new_array) { [values[0], values[1], values[2]] }
|
|
422
|
+
before :example do
|
|
423
|
+
subject.assign(new_array)
|
|
424
|
+
end
|
|
425
|
+
it 'has the same size than the other array' do
|
|
426
|
+
expect(subject.size).to eq(new_array.size)
|
|
427
|
+
end
|
|
428
|
+
it 'replaces all the elements' do
|
|
429
|
+
new_array.each_with_index do |e, i|
|
|
430
|
+
expect(subject[i]).to eq(e)
|
|
431
|
+
end
|
|
432
|
+
end
|
|
180
433
|
end
|
|
181
434
|
end
|
|
182
435
|
end
|
|
183
436
|
|
|
184
|
-
RSpec.
|
|
185
|
-
let(:
|
|
186
|
-
let(:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
437
|
+
RSpec.shared_examples "a NDR Array" do |conformant:, varying:|
|
|
438
|
+
let(:max_count) { subject.to_binary_s.slice(0, 4).unpack('L' * 4)[0] }
|
|
439
|
+
let(:actual_count) do
|
|
440
|
+
index = conformant ? 8 : 4
|
|
441
|
+
subject.to_binary_s.slice(index, 4).unpack('L' * 4)[0]
|
|
442
|
+
end
|
|
443
|
+
let(:offset) do
|
|
444
|
+
index = conformant ? 4 : 0
|
|
445
|
+
subject.to_binary_s.slice(index, 4).unpack('L' * 4)[0]
|
|
446
|
+
end
|
|
191
447
|
|
|
192
|
-
|
|
193
|
-
|
|
448
|
+
if conformant
|
|
449
|
+
it "has :max_count set to 0 (little endian uint32) by default" do
|
|
450
|
+
empty_array = described_class.new(type: element_class)
|
|
451
|
+
expect(empty_array.to_binary_s[0, 4]).to eq("\x00\x00\x00\x00")
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
if varying
|
|
455
|
+
it "has :offset and :actual_count set to 0 (little endian uint32) by default" do
|
|
456
|
+
empty_array = described_class.new(type: element_class)
|
|
457
|
+
# offset
|
|
458
|
+
expect(empty_array.to_binary_s[0, 4]).to eq("\x00\x00\x00\x00")
|
|
459
|
+
# actual_count
|
|
460
|
+
expect(empty_array.to_binary_s[4, 4]).to eq("\x00\x00\x00\x00")
|
|
461
|
+
end
|
|
462
|
+
end
|
|
463
|
+
it 'reads itself' do
|
|
464
|
+
expect(described_class.new(type: element_class).read(subject.to_binary_s)).to eq(values)
|
|
465
|
+
end
|
|
466
|
+
it 'has :byte_align parameter set to the largest alignment of the array element type and the size information type, if any' do
|
|
467
|
+
# minimum alignment is 4 bytes since arrays are prefixed with an uint32 size element for 32-bit NDR
|
|
468
|
+
align = [4, element_size].max
|
|
469
|
+
expect(subject.eval_parameter(:byte_align)).to eq(align)
|
|
194
470
|
end
|
|
195
471
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
472
|
+
context 'when checking if its elements have :byte_align parameter set' do
|
|
473
|
+
# element independent
|
|
474
|
+
it 'does not raise error when the :byte_align parameter is set in the element class' do
|
|
475
|
+
test_element = Class.new(BinData::Record) do
|
|
476
|
+
default_parameters byte_align: 4
|
|
477
|
+
endian :little
|
|
478
|
+
uint32 :a
|
|
479
|
+
end
|
|
480
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
481
|
+
expect { described_class.new(type: :test_element, byte_align: 4) }.to_not raise_error
|
|
482
|
+
end
|
|
483
|
+
# element independent
|
|
484
|
+
it 'does not raise error when the :byte_align parameter is set during instantiation' do
|
|
485
|
+
test_element = Class.new(BinData::Record) do
|
|
486
|
+
endian :little
|
|
487
|
+
uint32 :a
|
|
488
|
+
end
|
|
489
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
490
|
+
expect { described_class.new(type: [:test_element, {byte_align: 4}], byte_align: 4) }.to_not raise_error
|
|
491
|
+
end
|
|
492
|
+
context 'with a NDR element' do
|
|
493
|
+
# element independent
|
|
494
|
+
it 'does not raise error when the type element is a symbol' do
|
|
495
|
+
expect { described_class.new(type: :ndr_uint32, byte_align: 4) }.to_not raise_error
|
|
496
|
+
end
|
|
497
|
+
# element independent
|
|
498
|
+
it 'does not raise error when the type element is a class' do
|
|
499
|
+
expect { described_class.new(type: RubySMB::Dcerpc::Ndr::NdrUint32, byte_align: 4) }.to_not raise_error
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
# element independent
|
|
503
|
+
it 'raises an ArgumentError when the element has no :byte_align' do
|
|
504
|
+
test_element = Class.new(BinData::Record) do
|
|
505
|
+
endian :little
|
|
506
|
+
uint32 :a
|
|
507
|
+
end
|
|
508
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
509
|
+
expect { described_class.new(type: :test_element, byte_align: 4) }.to raise_error(ArgumentError)
|
|
510
|
+
end
|
|
511
|
+
# element independent
|
|
512
|
+
it 'raises an ArgumentError when the element has a parameter different than :byte_align' do
|
|
513
|
+
test_element = Class.new(BinData::Array) do
|
|
514
|
+
default_parameters type: :uint8
|
|
515
|
+
end
|
|
516
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
517
|
+
expect { described_class.new(type: [:test_element, {other_param: 1}], byte_align: 4) }.to raise_error(ArgumentError)
|
|
199
518
|
end
|
|
200
519
|
end
|
|
201
520
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
521
|
+
context 'with size information' do
|
|
522
|
+
if conformant
|
|
523
|
+
it "sets :max_count to a little endian uint32 value representing the number of elements" do
|
|
524
|
+
expect(max_count).to eq(subject.size)
|
|
525
|
+
end
|
|
526
|
+
it "updates :max_count when adding one element" do
|
|
527
|
+
subject << values[0]
|
|
528
|
+
expect(max_count).to eq(subject.size)
|
|
529
|
+
end
|
|
530
|
+
context 'when setting a value at index greater than the current number of elements' do
|
|
531
|
+
it "sets :max_count to the new number of elements" do
|
|
532
|
+
index_offset = rand(10)
|
|
533
|
+
subject[values.size + index_offset] = values[0]
|
|
534
|
+
expect(max_count).to eq(values.size + index_offset + 1)
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
context 'when reading a value at index greater than the current number of elements' do
|
|
538
|
+
it "sets :max_count to the new number of elements" do
|
|
539
|
+
index_offset = rand(10)
|
|
540
|
+
subject[values.size + index_offset]
|
|
541
|
+
expect(max_count).to eq(values.size + index_offset + 1)
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
context 'when assigning another array' do
|
|
545
|
+
it "sets :max_count to the new number of elements" do
|
|
546
|
+
new_size = rand(10)
|
|
547
|
+
new_array = new_size.times.map { values[0] }
|
|
548
|
+
subject.assign(new_array)
|
|
549
|
+
expect(max_count).to eq(new_size)
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
if varying
|
|
555
|
+
it "sets :actual_count to a little endian uint32 value representing the number of elements" do
|
|
556
|
+
expect(actual_count).to eq(subject.size)
|
|
557
|
+
end
|
|
558
|
+
it "updates :actual_count when adding one element" do
|
|
559
|
+
subject << values[0]
|
|
560
|
+
expect(actual_count).to eq(subject.size)
|
|
561
|
+
end
|
|
562
|
+
it 'has offset always set to 0' do
|
|
563
|
+
expect(offset).to eq(0)
|
|
564
|
+
subject << values[0]
|
|
565
|
+
expect(offset).to eq(0)
|
|
566
|
+
end
|
|
567
|
+
context 'when setting a value at index greater than the current number of elements' do
|
|
568
|
+
it "sets :actual_count to the new number of elements" do
|
|
569
|
+
index_offset = rand(10)
|
|
570
|
+
subject[values.size + index_offset] = values[0]
|
|
571
|
+
expect(actual_count).to eq(values.size + index_offset + 1)
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
context 'when reading a value at index greater than the current number of elements' do
|
|
575
|
+
it "sets :actual_count to the new number of elements" do
|
|
576
|
+
index_offset = rand(10)
|
|
577
|
+
subject[values.size + index_offset]
|
|
578
|
+
expect(actual_count).to eq(values.size + index_offset + 1)
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
context 'when assigning another array' do
|
|
582
|
+
it "sets :actual_count to the new number of elements" do
|
|
583
|
+
new_size = rand(10)
|
|
584
|
+
new_array = new_size.times.map { values[0] }
|
|
585
|
+
subject.assign(new_array)
|
|
586
|
+
expect(actual_count).to eq(new_size)
|
|
587
|
+
end
|
|
588
|
+
end
|
|
205
589
|
end
|
|
206
590
|
end
|
|
207
591
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
expect(
|
|
592
|
+
context 'when reading a binary stream' do
|
|
593
|
+
subject { described_class.new(type: element_class).read(binary_stream) }
|
|
594
|
+
|
|
595
|
+
it 'has the expected size' do
|
|
596
|
+
expect(subject.size).to eq(values.size)
|
|
597
|
+
end
|
|
598
|
+
it 'sets the new element values' do
|
|
599
|
+
values.each_with_index do |value, i|
|
|
600
|
+
expect(subject[i]).to eq(value)
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
it 'has the same binary representation than the original binary stream' do
|
|
604
|
+
expect(subject.to_binary_s).to eq(binary_stream)
|
|
605
|
+
end
|
|
606
|
+
if conformant
|
|
607
|
+
it "sets :max_count to the new number of elements" do
|
|
608
|
+
expect(max_count).to eq(values.size)
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
if varying
|
|
612
|
+
it "sets :actual_count to the new number of elements" do
|
|
613
|
+
expect(actual_count).to eq(values.size)
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
it 'sets @read_until_index to the number of elements' do
|
|
617
|
+
expect(subject.read_until_index).to eq(values.size)
|
|
618
|
+
end
|
|
619
|
+
context 'with an empty array' do
|
|
620
|
+
let(:empty_binary_str) do
|
|
621
|
+
str = ''
|
|
622
|
+
str << "\x00\x00\x00\x00" if conformant
|
|
623
|
+
str << "\x00\x00\x00\x00\x00\x00\x00\x00" if varying
|
|
624
|
+
str
|
|
625
|
+
end
|
|
626
|
+
subject { described_class.new(type: element_class).read(empty_binary_str) }
|
|
627
|
+
|
|
628
|
+
it 'is an empty array' do
|
|
629
|
+
expect(subject).to eq([])
|
|
630
|
+
end
|
|
631
|
+
it 'sets @read_until_index to 0' do
|
|
632
|
+
expect(subject.read_until_index).to eq(0)
|
|
633
|
+
end
|
|
634
|
+
if conformant
|
|
635
|
+
it "sets :max_count to 0" do
|
|
636
|
+
expect(max_count).to eq(0)
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
if varying
|
|
640
|
+
it "sets :actual_count to 0" do
|
|
641
|
+
expect(actual_count).to eq(0)
|
|
642
|
+
end
|
|
643
|
+
end
|
|
213
644
|
end
|
|
214
645
|
end
|
|
215
646
|
|
|
216
|
-
|
|
217
|
-
|
|
647
|
+
context 'when getting a binary stream' do
|
|
648
|
+
it 'outputs the expected binary' do
|
|
649
|
+
expect(subject.to_binary_s).to eq(binary_stream)
|
|
650
|
+
end
|
|
651
|
+
context 'with an empty array' do
|
|
652
|
+
let(:empty_binary_str) do
|
|
653
|
+
str = ''
|
|
654
|
+
str << "\x00\x00\x00\x00" if conformant
|
|
655
|
+
str << "\x00\x00\x00\x00\x00\x00\x00\x00" if varying
|
|
656
|
+
str
|
|
657
|
+
end
|
|
658
|
+
subject { described_class.new(type: element_class).assign([]) }
|
|
218
659
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
packet.set(handle)
|
|
222
|
-
expect(packet.context_handle_attributes).to eq(attr)
|
|
223
|
-
expect(packet.context_handle_uuid).to eq(uuid)
|
|
660
|
+
it 'outputs the expected binary' do
|
|
661
|
+
expect(subject.to_binary_s).to eq(empty_binary_str)
|
|
224
662
|
end
|
|
225
663
|
end
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
context 'when calling #do_num_bytes' do
|
|
667
|
+
it 'returns the expected number of bytes' do
|
|
668
|
+
expect(subject.do_num_bytes).to eq(binary_stream.size)
|
|
669
|
+
end
|
|
670
|
+
context 'with NDR structures' do
|
|
671
|
+
let(:array_with_struct) do
|
|
672
|
+
described_class.new([{a: 2, b: 'A'}, {a: 3, b: 'B'}], type: :test_struct)
|
|
673
|
+
end
|
|
674
|
+
before :example do
|
|
675
|
+
test_struct = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
676
|
+
default_parameters byte_align: 4
|
|
677
|
+
ndr_uint32 :a
|
|
678
|
+
ndr_char :b
|
|
679
|
+
end
|
|
680
|
+
BinData::RegisteredClasses.register('test_struct', test_struct)
|
|
681
|
+
end
|
|
226
682
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
683
|
+
it 'returns the expected number of bytes, including padding' do
|
|
684
|
+
uint32_size = 4
|
|
685
|
+
char_size = 1
|
|
686
|
+
pad_size = 3
|
|
687
|
+
expected_nb = (uint32_size + char_size) * 2
|
|
688
|
+
expected_nb += pad_size
|
|
689
|
+
expected_nb += 4 if conformant
|
|
690
|
+
expected_nb += 8 if varying
|
|
691
|
+
expect(array_with_struct.do_num_bytes).to eq(expected_nb)
|
|
234
692
|
end
|
|
235
693
|
end
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
{
|
|
697
|
+
NdrUint8: { align: 1, data: rand(0xFF), pack: 'C' },
|
|
698
|
+
NdrUint16: { align: 2, data: rand(0xFFFF), pack: 'S<' },
|
|
699
|
+
NdrUint32: { align: 4, data: rand(0xFFFFFFFF), pack: 'L<' },
|
|
700
|
+
NdrUint64: { align: 8, data: rand(0xFFFFFFFFFFFFFFFF), pack: 'Q<'},
|
|
701
|
+
NdrChar: { align: 1, data: 'A', binary: 'A'.b },
|
|
702
|
+
NdrVarString: { align: 4, data: 'AAAAA'.encode('ASCII-8BIT'), binary: "#{[0].pack('L')}#{[5].pack('L')}AAAAA".b},
|
|
703
|
+
NdrVarStringz: { align: 4, data: 'AAAAA'.encode('ASCII-8BIT'), binary: "#{[0].pack('L')}#{[6].pack('L')}AAAAA\x00".b},
|
|
704
|
+
NdrVarWideString: { align: 4, data: 'AAAAA'.encode('UTF-16LE'), binary: "#{[0].pack('L')}#{[5].pack('L')}A\x00A\x00A\x00A\x00A\x00".b},
|
|
705
|
+
NdrVarWideStringz: { align: 4, data: 'AAAAA'.encode('UTF-16LE'), binary: "#{[0].pack('L')}#{[6].pack('L')}A\x00A\x00A\x00A\x00A\x00\x00\x00".b},
|
|
706
|
+
}.each do |klass, info|
|
|
707
|
+
context "when it is embedded in a NDR structure and preceeded by a #{klass}" do
|
|
708
|
+
let(:field_class) { RubySMB::Dcerpc::Ndr.const_get(klass) }
|
|
709
|
+
let(:field_obj) { field_class.new(info[:data]) }
|
|
710
|
+
let(:embedded_struct) do
|
|
711
|
+
byte_align = struct_max_align
|
|
712
|
+
embedded_struct = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
713
|
+
default_parameters(byte_align: byte_align)
|
|
714
|
+
end
|
|
715
|
+
embedded_struct.send(field_class.bindata_name.to_sym, :a)
|
|
716
|
+
embedded_struct
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
context 'directly as an array' do
|
|
720
|
+
before :example do
|
|
721
|
+
embedded_struct.send(described_class.bindata_name.to_sym, :ary, type: element_class)
|
|
722
|
+
end
|
|
723
|
+
let(:array_max_align) { (varying && element_size < 4) ? 4 : element_size }
|
|
724
|
+
let(:struct_max_align) { [array_max_align, info[:align]].max }
|
|
725
|
+
let(:test_instance) { embedded_struct.new(a: field_obj, ary: values) }
|
|
726
|
+
let(:binary_str) do
|
|
727
|
+
binary_str = "".b
|
|
728
|
+
if conformant
|
|
729
|
+
binary_str << binary_stream.slice!(0, 4)
|
|
730
|
+
end
|
|
731
|
+
pad_length = (struct_max_align - (binary_str.size % struct_max_align)) % struct_max_align
|
|
732
|
+
binary_str << "\x00" * pad_length
|
|
733
|
+
if info[:data].is_a?(String)
|
|
734
|
+
binary_str << info[:binary]
|
|
735
|
+
else
|
|
736
|
+
binary_str << "#{[info[:data]].pack(info[:pack])}"
|
|
737
|
+
end
|
|
738
|
+
if varying
|
|
739
|
+
pad_length = (array_max_align - (binary_str.size % array_max_align)) % array_max_align
|
|
740
|
+
binary_str << "\x00" * pad_length
|
|
741
|
+
binary_str << binary_stream.slice!(0, 8)
|
|
742
|
+
end
|
|
743
|
+
pad_length = (element_size - (binary_str.size % element_size)) % element_size
|
|
744
|
+
binary_str << "\x00" * pad_length
|
|
745
|
+
binary_str << bin_values
|
|
746
|
+
binary_str
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
context 'when writing the stream of bytes' do
|
|
750
|
+
it 'outputs the expect binary' do
|
|
751
|
+
expect(test_instance.to_binary_s).to eq(binary_str)
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
context 'when reading a stream of bytes' do
|
|
756
|
+
it 'outputs the expected structure' do
|
|
757
|
+
expect(embedded_struct.read(binary_str)).to eq({ a: info[:data], ary: values })
|
|
758
|
+
end
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
context 'when calling #num_bytes' do
|
|
762
|
+
it 'outputs the expected number of bytes' do
|
|
763
|
+
expect(test_instance.num_bytes).to eq(binary_str.size)
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
context 'as a pointer to an array' do
|
|
769
|
+
before :example do
|
|
770
|
+
array_ptr = Class.new(described_class) do
|
|
771
|
+
extend RubySMB::Dcerpc::Ndr::PointerClassPlugin
|
|
772
|
+
end
|
|
773
|
+
BinData::RegisteredClasses.register('test_array_ptr', array_ptr)
|
|
774
|
+
embedded_struct.send(:test_array_ptr, :ary_ptr, type: element_class)
|
|
775
|
+
end
|
|
776
|
+
let(:struct_max_align) { [4, info[:align]].max }
|
|
777
|
+
let(:test_instance) { embedded_struct.new(a: field_obj, ary_ptr: values) }
|
|
778
|
+
let(:binary_str) do
|
|
779
|
+
binary_str = "".b
|
|
780
|
+
if info[:data].is_a?(String)
|
|
781
|
+
binary_str << info[:binary]
|
|
782
|
+
else
|
|
783
|
+
binary_str << "#{[info[:data]].pack(info[:pack])}"
|
|
784
|
+
end
|
|
785
|
+
pad_length = (4 - (binary_str.size % 4)) % 4
|
|
786
|
+
binary_str << "\x00" * pad_length
|
|
787
|
+
ref_id = [RubySMB::Dcerpc::Ndr::INITIAL_REF_ID].pack('L<')
|
|
788
|
+
binary_str << ref_id
|
|
789
|
+
if conformant
|
|
790
|
+
binary_str << binary_stream.slice!(0, 4)
|
|
791
|
+
end
|
|
792
|
+
if varying
|
|
793
|
+
binary_str << binary_stream.slice!(0, 8)
|
|
794
|
+
end
|
|
795
|
+
pad_length = (element_size - (binary_str.size % element_size)) % element_size
|
|
796
|
+
binary_str << "\x00" * pad_length
|
|
797
|
+
binary_str << bin_values
|
|
798
|
+
binary_str
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
context 'when writing the stream of bytes' do
|
|
802
|
+
it 'outputs the expect binary' do
|
|
803
|
+
expect(test_instance.to_binary_s).to eq(binary_str)
|
|
804
|
+
end
|
|
805
|
+
end
|
|
236
806
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
807
|
+
context 'when reading a stream of bytes' do
|
|
808
|
+
it 'outputs the expected structure' do
|
|
809
|
+
expect(embedded_struct.read(binary_str)).to eq({ a: info[:data], ary_ptr: values })
|
|
810
|
+
end
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
context 'when calling #num_bytes' do
|
|
814
|
+
it 'outputs the expected number of bytes' do
|
|
815
|
+
expect(test_instance.num_bytes).to eq(binary_str.size)
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
context 'embedded in another structure' do
|
|
821
|
+
before :example do
|
|
822
|
+
byte_align = struct_max_align
|
|
823
|
+
embedded_struct2 = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
824
|
+
default_parameters(byte_align: byte_align)
|
|
825
|
+
end
|
|
826
|
+
embedded_struct2.send(field_class.bindata_name.to_sym, :a)
|
|
827
|
+
embedded_struct2.send(described_class.bindata_name.to_sym, :ary, type: element_class)
|
|
828
|
+
BinData::RegisteredClasses.register('embedded_struct_2nd_lvl', embedded_struct2)
|
|
829
|
+
embedded_struct.send(:embedded_struct_2nd_lvl, :struct2)
|
|
830
|
+
end
|
|
831
|
+
let(:array_max_align) { (varying && element_size < 4) ? 4 : element_size }
|
|
832
|
+
let(:struct2_max_align) { [array_max_align, info[:align]].max }
|
|
833
|
+
let(:struct_max_align) { [struct2_max_align, info[:align]].max }
|
|
834
|
+
let(:test_instance) { embedded_struct.new(a: field_obj, struct2: { a: field_obj, ary: values }) }
|
|
835
|
+
let(:binary_str) do
|
|
836
|
+
binary_str = "".b
|
|
837
|
+
if conformant
|
|
838
|
+
binary_str << binary_stream.slice!(0, 4)
|
|
839
|
+
end
|
|
840
|
+
# a
|
|
841
|
+
pad_length = (struct_max_align - (binary_str.size % struct_max_align)) % struct_max_align
|
|
842
|
+
binary_str << "\x00" * pad_length
|
|
843
|
+
if info[:data].is_a?(String)
|
|
844
|
+
binary_str << info[:binary]
|
|
845
|
+
else
|
|
846
|
+
binary_str << "#{[info[:data]].pack(info[:pack])}"
|
|
847
|
+
end
|
|
848
|
+
# struct2.a
|
|
849
|
+
pad_length = (struct2_max_align - (binary_str.size % struct2_max_align)) % struct2_max_align
|
|
850
|
+
binary_str << "\x00" * pad_length
|
|
851
|
+
if info[:data].is_a?(String)
|
|
852
|
+
binary_str << info[:binary]
|
|
853
|
+
else
|
|
854
|
+
binary_str << "#{[info[:data]].pack(info[:pack])}"
|
|
855
|
+
end
|
|
856
|
+
# struct2.ary
|
|
857
|
+
if varying
|
|
858
|
+
pad_length = (array_max_align - (binary_str.size % array_max_align)) % array_max_align
|
|
859
|
+
binary_str << "\x00" * pad_length
|
|
860
|
+
binary_str << binary_stream.slice!(0, 8)
|
|
861
|
+
end
|
|
862
|
+
pad_length = (element_size - (binary_str.size % element_size)) % element_size
|
|
863
|
+
binary_str << "\x00" * pad_length
|
|
864
|
+
binary_str << bin_values
|
|
865
|
+
binary_str
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
context 'when writing the stream of bytes' do
|
|
869
|
+
it 'outputs the expect binary' do
|
|
870
|
+
expect(test_instance.to_binary_s).to eq(binary_str)
|
|
871
|
+
end
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
context 'when reading a stream of bytes' do
|
|
875
|
+
it 'outputs the expected structure' do
|
|
876
|
+
expect(embedded_struct.read(binary_str)).to eq({ a: field_obj, struct2: { a: field_obj, ary: values } })
|
|
877
|
+
end
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
context 'when calling #num_bytes' do
|
|
881
|
+
it 'outputs the expected number of bytes' do
|
|
882
|
+
expect(test_instance.num_bytes).to eq(binary_str.size)
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
unless conformant
|
|
888
|
+
{
|
|
889
|
+
NdrUint8: { size: 1 },
|
|
890
|
+
NdrUint16: { size: 2 },
|
|
891
|
+
NdrUint32: { size: 4 },
|
|
892
|
+
NdrUint64: { size: 8 }
|
|
893
|
+
}.each do |klass2, info2|
|
|
894
|
+
context "directly as an array and followed by a #{klass2}" do
|
|
895
|
+
before :example do
|
|
896
|
+
embedded_struct.send(described_class.bindata_name.to_sym, :ary, type: element_class)
|
|
897
|
+
embedded_struct.send(field_class2.bindata_name.to_sym, :b)
|
|
898
|
+
end
|
|
899
|
+
let(:field_class2) { RubySMB::Dcerpc::Ndr.const_get(klass2) }
|
|
900
|
+
let(:field_obj2) { field_class2.new(rand(0xFF)) }
|
|
901
|
+
let(:array_max_align) { element_size < 4 ? 4 : element_size }
|
|
902
|
+
let(:struct_max_align) { [array_max_align, info[:align], info2[:size]].max }
|
|
903
|
+
let(:test_instance) { embedded_struct.new(a: field_obj, ary: values, b: field_obj2) }
|
|
904
|
+
let(:binary_str) do
|
|
905
|
+
binary_str = "".b
|
|
906
|
+
# a
|
|
907
|
+
if info[:data].is_a?(String)
|
|
908
|
+
binary_str << info[:binary]
|
|
909
|
+
else
|
|
910
|
+
binary_str << "#{[info[:data]].pack(info[:pack])}"
|
|
911
|
+
end
|
|
912
|
+
# ary
|
|
913
|
+
pad_length = (array_max_align - (binary_str.size % array_max_align)) % array_max_align
|
|
914
|
+
binary_str << "\x00" * pad_length
|
|
915
|
+
binary_str << binary_stream.slice!(0, 8)
|
|
916
|
+
pad_length = (element_size - (binary_str.size % element_size)) % element_size
|
|
917
|
+
binary_str << "\x00" * pad_length
|
|
918
|
+
binary_str << bin_values
|
|
919
|
+
# b
|
|
920
|
+
pad_length = (info2[:size] - (binary_str.size % info2[:size])) % info2[:size]
|
|
921
|
+
binary_str << "\x00" * pad_length
|
|
922
|
+
binary_str << field_obj2.to_binary_s
|
|
923
|
+
binary_str
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
context 'when writing the stream of bytes' do
|
|
927
|
+
it 'outputs the expect binary' do
|
|
928
|
+
expect(test_instance.to_binary_s).to eq(binary_str)
|
|
929
|
+
end
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
context 'when reading a stream of bytes' do
|
|
933
|
+
it 'outputs the expected structure' do
|
|
934
|
+
expect(embedded_struct.read(binary_str)).to eq({ a: info[:data], ary: values, b: field_obj2.to_i })
|
|
935
|
+
end
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
context 'when calling #num_bytes' do
|
|
939
|
+
it 'outputs the expected number of bytes' do
|
|
940
|
+
expect(test_instance.num_bytes).to eq(binary_str.size)
|
|
941
|
+
end
|
|
942
|
+
end
|
|
943
|
+
end
|
|
944
|
+
end
|
|
242
945
|
end
|
|
243
946
|
end
|
|
244
947
|
end
|
|
245
948
|
end
|
|
246
949
|
|
|
247
|
-
RSpec.describe RubySMB::Dcerpc::Ndr::
|
|
248
|
-
it 'is
|
|
249
|
-
expect(described_class).to be <
|
|
950
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrFixArray do
|
|
951
|
+
it 'is a BinData::Array class' do
|
|
952
|
+
expect(described_class).to be < BinData::Array
|
|
953
|
+
end
|
|
954
|
+
it 'is an empty array by default' do
|
|
955
|
+
expect(described_class.new(type: :ndr_uint16, byte_align: 2)).to eq([])
|
|
250
956
|
end
|
|
251
957
|
|
|
252
|
-
subject
|
|
958
|
+
subject { described_class.new(type: :ndr_uint16, byte_align: 2, initial_length: 4) }
|
|
253
959
|
|
|
254
|
-
it
|
|
960
|
+
it 'is an array of initial_length default elements' do
|
|
961
|
+
expect(subject).to eq([0, 0, 0, 0])
|
|
962
|
+
end
|
|
255
963
|
|
|
256
|
-
|
|
257
|
-
|
|
964
|
+
context 'when checking if its elements have :byte_align parameter set' do
|
|
965
|
+
it 'does not raise error when the :byte_align parameter is set in the element class' do
|
|
966
|
+
test_element = Class.new(BinData::Record) do
|
|
967
|
+
default_parameters byte_align: 4
|
|
968
|
+
endian :little
|
|
969
|
+
uint32 :a
|
|
970
|
+
end
|
|
971
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
972
|
+
expect { described_class.new(type: :test_element, byte_align: 4) }.to_not raise_error
|
|
973
|
+
end
|
|
974
|
+
it 'does not raise error when the :byte_align parameter is set during instantiation' do
|
|
975
|
+
test_element = Class.new(BinData::Record) do
|
|
976
|
+
endian :little
|
|
977
|
+
uint32 :a
|
|
978
|
+
end
|
|
979
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
980
|
+
expect { described_class.new(type: [:test_element, {byte_align: 4}], byte_align: 4) }.to_not raise_error
|
|
981
|
+
end
|
|
982
|
+
context 'with a NDR element' do
|
|
983
|
+
it 'does not raise error when the type element is a symbol' do
|
|
984
|
+
expect { described_class.new(type: :ndr_uint32, byte_align: 4) }.to_not raise_error
|
|
985
|
+
end
|
|
986
|
+
it 'does not raise error when the type element is a class' do
|
|
987
|
+
expect { described_class.new(type: RubySMB::Dcerpc::Ndr::NdrUint32, byte_align: 4) }.to_not raise_error
|
|
988
|
+
end
|
|
989
|
+
end
|
|
990
|
+
it 'raises an ArgumentError when no :byte_align is provided' do
|
|
991
|
+
test_element = Class.new(BinData::Record) do
|
|
992
|
+
endian :little
|
|
993
|
+
uint32 :a
|
|
994
|
+
end
|
|
995
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
996
|
+
expect { described_class.new(type: :test_element, byte_align: 4) }.to raise_error(ArgumentError)
|
|
997
|
+
end
|
|
998
|
+
it 'raises an ArgumentError when other parameters than :byte_align are provided' do
|
|
999
|
+
test_element = Class.new(BinData::Array) do
|
|
1000
|
+
default_parameters type: :uint8
|
|
1001
|
+
end
|
|
1002
|
+
BinData::RegisteredClasses.register('test_element', test_element)
|
|
1003
|
+
expect { described_class.new(type: [:test_element, {other_param: 1}], byte_align: 4) }.to raise_error(ArgumentError)
|
|
1004
|
+
end
|
|
258
1005
|
end
|
|
259
1006
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
1007
|
+
context 'with elements' do
|
|
1008
|
+
before :example do
|
|
1009
|
+
subject.assign([1, 2, 3, 4])
|
|
1010
|
+
end
|
|
1011
|
+
it 'contains the expected element types' do
|
|
1012
|
+
expect(subject.all? {|e| e.is_a?(BinData::Uint16le)}).to be true
|
|
1013
|
+
end
|
|
1014
|
+
it 'has the expected size' do
|
|
1015
|
+
expect(subject.size).to eq(4)
|
|
263
1016
|
end
|
|
264
1017
|
|
|
265
|
-
|
|
266
|
-
|
|
1018
|
+
context 'when setting a value to an element array' do
|
|
1019
|
+
context 'in the array bounds' do
|
|
1020
|
+
it 'does not raise error and sets the new value' do
|
|
1021
|
+
expect { subject[3] = 14 }.to_not raise_error
|
|
1022
|
+
expect(subject[3]).to eq(14)
|
|
1023
|
+
end
|
|
1024
|
+
end
|
|
1025
|
+
context 'outside of the array bounds' do
|
|
1026
|
+
it 'raises an error' do
|
|
1027
|
+
expect { subject[4] = 14 }.to raise_error(ArgumentError)
|
|
1028
|
+
end
|
|
1029
|
+
end
|
|
1030
|
+
end
|
|
1031
|
+
context 'when reading the value of an element array' do
|
|
1032
|
+
context 'in the array bounds' do
|
|
1033
|
+
it 'does not raise error and returns the value' do
|
|
1034
|
+
expect { subject[3] }.to_not raise_error
|
|
1035
|
+
expect(subject[3]).to eq(4)
|
|
1036
|
+
end
|
|
1037
|
+
end
|
|
1038
|
+
context 'outside of the array bounds' do
|
|
1039
|
+
it 'raises an error' do
|
|
1040
|
+
expect { subject[4] }.to raise_error(ArgumentError)
|
|
1041
|
+
end
|
|
1042
|
+
end
|
|
1043
|
+
end
|
|
1044
|
+
context 'when assigning another array' do
|
|
1045
|
+
context 'with the same number of elements' do
|
|
1046
|
+
it 'does not raise error and returns the value' do
|
|
1047
|
+
expect { subject.assign([5, 6, 7, 8]) }.to_not raise_error
|
|
1048
|
+
expect(subject).to eq([5, 6, 7, 8])
|
|
1049
|
+
end
|
|
1050
|
+
end
|
|
1051
|
+
context 'with more elements' do
|
|
1052
|
+
it 'raises an error' do
|
|
1053
|
+
expect { subject.assign([5, 6, 7, 8, 9]) }.to raise_error(ArgumentError)
|
|
1054
|
+
end
|
|
1055
|
+
end
|
|
1056
|
+
context 'with less elements' do
|
|
1057
|
+
it 'raises an error' do
|
|
1058
|
+
expect { subject.assign([5, 6, 7]) }.to raise_error(ArgumentError)
|
|
1059
|
+
end
|
|
1060
|
+
end
|
|
1061
|
+
end
|
|
1062
|
+
context 'when pushing a new element' do
|
|
1063
|
+
it 'raises an error' do
|
|
1064
|
+
expect { subject << 88 }.to raise_error(ArgumentError)
|
|
1065
|
+
end
|
|
1066
|
+
end
|
|
1067
|
+
context 'when unshifting a new element' do
|
|
1068
|
+
it 'raises an error' do
|
|
1069
|
+
expect { subject.unshift(88) }.to raise_error(ArgumentError)
|
|
1070
|
+
end
|
|
1071
|
+
end
|
|
1072
|
+
context 'when concatenating another array' do
|
|
1073
|
+
it 'raises an error' do
|
|
1074
|
+
expect { subject.concat([3,4]) }.to raise_error(ArgumentError)
|
|
1075
|
+
end
|
|
267
1076
|
end
|
|
1077
|
+
context 'when cheking if :byte_align parameter is set' do
|
|
1078
|
+
it 'does not raise error when it is set' do
|
|
1079
|
+
expect { described_class.new(type: :ndr_uint16, byte_align: 2, initial_length: 4) }.to_not raise_error
|
|
1080
|
+
end
|
|
268
1081
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
1082
|
+
it 'raises an error when it is not set' do
|
|
1083
|
+
expect { described_class.new(type: :uint16le, initial_length: 4) }.to raise_error(ArgumentError)
|
|
1084
|
+
end
|
|
272
1085
|
end
|
|
273
1086
|
end
|
|
274
1087
|
end
|
|
275
1088
|
|
|
276
|
-
RSpec.describe RubySMB::Dcerpc::Ndr::
|
|
277
|
-
|
|
1089
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrFixedByteArray do
|
|
1090
|
+
it 'is a RubySMB::Dcerpc::Ndr::NdrFixArray class' do
|
|
1091
|
+
expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrFixArray
|
|
1092
|
+
end
|
|
1093
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
1094
|
+
expect(described_class.default_parameters[:byte_align]).to eq(1)
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1097
|
+
subject { described_class.new(initial_length: 4) }
|
|
278
1098
|
|
|
279
|
-
it
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
it { is_expected.to respond_to :actual_count }
|
|
283
|
-
it { is_expected.to respond_to :bytes }
|
|
1099
|
+
it 'composed of NdrUint8 elements' do
|
|
1100
|
+
expect(subject[0]).to be_a( RubySMB::Dcerpc::Ndr::NdrUint8)
|
|
1101
|
+
end
|
|
284
1102
|
|
|
285
|
-
it '
|
|
286
|
-
expect(
|
|
1103
|
+
it 'has #initial_length elements' do
|
|
1104
|
+
expect(subject.size).to eq(4)
|
|
287
1105
|
end
|
|
288
1106
|
|
|
289
|
-
describe '#
|
|
290
|
-
it '
|
|
291
|
-
|
|
1107
|
+
describe '#assign' do
|
|
1108
|
+
it 'assign elements from another array of bytes' do
|
|
1109
|
+
ary = [0x33, 0x43, 0x64, 0x22]
|
|
1110
|
+
subject.assign(ary)
|
|
1111
|
+
expect(subject).to eq(ary)
|
|
292
1112
|
end
|
|
293
1113
|
|
|
294
|
-
it '
|
|
295
|
-
|
|
1114
|
+
it 'assign bytes from string' do
|
|
1115
|
+
str = '_Str'
|
|
1116
|
+
subject.assign(str)
|
|
1117
|
+
expect(subject).to eq(str.bytes)
|
|
296
1118
|
end
|
|
297
1119
|
end
|
|
1120
|
+
end
|
|
298
1121
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
1122
|
+
{
|
|
1123
|
+
NdrUint8: { size: 1, data: rand(0xFF), pack: 'C' },
|
|
1124
|
+
NdrUint16: { size: 2, data: rand(0xFFFF), pack: 'S<' },
|
|
1125
|
+
NdrUint32: { size: 4, data: rand(0xFFFFFFFF), pack: 'L<' },
|
|
1126
|
+
NdrUint64: { size: 8, data: rand(0xFFFFFFFFFFFFFFFF), pack: 'Q<'},
|
|
1127
|
+
NdrChar: { size: 1, data: 'A', binary: 'A'.b },
|
|
1128
|
+
NdrVarString: { size: 4, data: 'AAAAA'.encode('ASCII-8BIT'), binary: "#{[0].pack('L')}#{[5].pack('L')}AAAAA".b},
|
|
1129
|
+
NdrVarStringz: { size: 4, data: 'AAAAA'.encode('ASCII-8BIT'), binary: "#{[0].pack('L')}#{[6].pack('L')}AAAAA\x00".b},
|
|
1130
|
+
NdrVarWideString: { size: 4, data: 'AAAAA'.encode('UTF-16LE'), binary: "#{[0].pack('L')}#{[5].pack('L')}A\x00A\x00A\x00A\x00A\x00".b},
|
|
1131
|
+
NdrVarWideStringz: { size: 4, data: 'AAAAA'.encode('UTF-16LE'), binary: "#{[0].pack('L')}#{[6].pack('L')}A\x00A\x00A\x00A\x00A\x00\x00\x00".b},
|
|
1132
|
+
}.each do |klass, info|
|
|
1133
|
+
RSpec.describe "NDR Array with #{klass}" do
|
|
1134
|
+
let(:element_size) { info[:size] }
|
|
1135
|
+
let(:element_class) { RubySMB::Dcerpc::Ndr.const_get(klass) }
|
|
1136
|
+
let(:values) { rand(3..16).times.map { info[:data] } }
|
|
1137
|
+
#let(:values) { [0xFF, 0xFF, 0xFF, 0xFF] }
|
|
1138
|
+
let(:bin_values) do
|
|
1139
|
+
if info[:data].is_a?(String)
|
|
1140
|
+
info[:binary] * values.size
|
|
1141
|
+
else
|
|
1142
|
+
values.map { |e| [e].pack(info[:pack]) }.join
|
|
1143
|
+
end
|
|
1144
|
+
end
|
|
1145
|
+
let(:binary_stream) do
|
|
1146
|
+
pad_length = (element_size - (size_info.size % element_size)) % element_size
|
|
1147
|
+
"#{size_info}#{"\x00" * pad_length}#{bin_values}".b
|
|
302
1148
|
end
|
|
1149
|
+
subject { described_class.new(values, type: element_class) }
|
|
303
1150
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
1151
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfArray do
|
|
1152
|
+
let(:size_info) { [values.size].pack('L<') }
|
|
1153
|
+
it_behaves_like 'a BinData::Array'
|
|
1154
|
+
it_behaves_like 'a NDR Array', conformant: true, varying: false
|
|
307
1155
|
end
|
|
308
1156
|
|
|
309
|
-
|
|
310
|
-
|
|
1157
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarArray do
|
|
1158
|
+
let(:size_info) { "\x00\x00\x00\x00#{[values.size].pack('L<')}" }
|
|
1159
|
+
it_behaves_like 'a BinData::Array'
|
|
1160
|
+
it_behaves_like 'a NDR Array', conformant: false, varying: true
|
|
311
1161
|
end
|
|
312
1162
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
1163
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarArray do
|
|
1164
|
+
let(:size_info) { "#{[values.size].pack('L<')}\x00\x00\x00\x00#{[values.size].pack('L<')}" }
|
|
1165
|
+
it_behaves_like 'a BinData::Array'
|
|
1166
|
+
it_behaves_like 'a NDR Array', conformant: true, varying: true
|
|
316
1167
|
end
|
|
317
1168
|
end
|
|
1169
|
+
end
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
#
|
|
1173
|
+
# Strings
|
|
1174
|
+
#
|
|
1175
|
+
|
|
1176
|
+
RSpec.shared_examples "a NDR String" do |conformant:, char_size:, null_terminated:|
|
|
1177
|
+
let(:first_char_offset) { conformant ? 12 : 8}
|
|
1178
|
+
|
|
1179
|
+
it 'has :byte_align parameter set to the expected value' do
|
|
1180
|
+
expect(described_class.default_parameters[:byte_align]).to eq(4)
|
|
1181
|
+
end
|
|
1182
|
+
|
|
1183
|
+
if conformant
|
|
1184
|
+
it_behaves_like "a Conformant Varying String", null_terminated: null_terminated
|
|
1185
|
+
else
|
|
1186
|
+
it_behaves_like "a Varying String", null_terminated: null_terminated
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1189
|
+
it 'is an empty string by default' do
|
|
1190
|
+
expect(subject).to eq('')
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
it 'has a binary representation of an empty string by default' do
|
|
1194
|
+
expect(subject.to_binary_s[first_char_offset..-1]).to be_empty
|
|
1195
|
+
end
|
|
1196
|
+
|
|
1197
|
+
it 'reads itself' do
|
|
1198
|
+
subject.assign(value)
|
|
1199
|
+
expect(subject.read(subject.to_binary_s)).to eq(value)
|
|
1200
|
+
end
|
|
318
1201
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
1202
|
+
context 'when reading another binary stream' do
|
|
1203
|
+
before :example do
|
|
1204
|
+
subject.read(binary_stream)
|
|
322
1205
|
end
|
|
1206
|
+
it 'has the expected size' do
|
|
1207
|
+
expect(subject.size).to eq(value.size)
|
|
1208
|
+
end
|
|
1209
|
+
it 'sets the new element values' do
|
|
1210
|
+
expect(subject.to_s).to eq(value)
|
|
1211
|
+
end
|
|
1212
|
+
it 'has the same binary representation than the original binary stream' do
|
|
1213
|
+
expect(subject.to_binary_s).to eq(binary_stream)
|
|
1214
|
+
end
|
|
1215
|
+
end
|
|
1216
|
+
end
|
|
1217
|
+
|
|
1218
|
+
RSpec.shared_examples "a Conformant Varying String" do |null_terminated:|
|
|
1219
|
+
minimum_size = null_terminated ? 1 : 0
|
|
323
1220
|
|
|
324
|
-
|
|
325
|
-
|
|
1221
|
+
it_behaves_like 'a Varying String', offset: 4, null_terminated: null_terminated
|
|
1222
|
+
|
|
1223
|
+
describe '#initialize' do
|
|
1224
|
+
it "sets #max_count to 0 (uint32) by default" do
|
|
1225
|
+
expect(subject.max_count).to eq(0)
|
|
1226
|
+
expect(subject.to_binary_s[0, 4]).to eq([0].pack('L'))
|
|
326
1227
|
end
|
|
1228
|
+
end
|
|
327
1229
|
|
|
328
|
-
|
|
329
|
-
|
|
1230
|
+
describe '#do_write' do
|
|
1231
|
+
it "writes #max_count corresponding to the number of elements#{' (including the NULL terminator)' if null_terminated}" do
|
|
1232
|
+
subject.assign(value)
|
|
1233
|
+
expect(subject.to_binary_s[0, 4]).to eq([value.size + minimum_size].pack('L'))
|
|
330
1234
|
end
|
|
1235
|
+
end
|
|
331
1236
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
1237
|
+
describe '#do_read' do
|
|
1238
|
+
it "sets #max_count to the string size#{' (including the NULL terminator)' if null_terminated}" do
|
|
1239
|
+
subject.read(binary_stream)
|
|
1240
|
+
expect(subject.max_count).to eq(value.size + minimum_size)
|
|
335
1241
|
end
|
|
336
1242
|
end
|
|
337
1243
|
|
|
338
|
-
describe '#
|
|
339
|
-
|
|
340
|
-
|
|
1244
|
+
describe '#assign' do
|
|
1245
|
+
context 'with a string' do
|
|
1246
|
+
it "sets #max_count to the string length#{' (including the NULL terminator)' if null_terminated}" do
|
|
1247
|
+
subject.assign(value)
|
|
1248
|
+
expect(subject.max_count).to eq(value.length + minimum_size)
|
|
1249
|
+
end
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
context 'with a varying string' do
|
|
1253
|
+
it "sets #max_count to the string length#{' (including the NULL terminator)' if null_terminated}" do
|
|
1254
|
+
case subject
|
|
1255
|
+
when RubySMB::Field::Stringz16
|
|
1256
|
+
str = RubySMB::Dcerpc::Ndr::NdrVarWideStringz.new(value)
|
|
1257
|
+
when RubySMB::Field::String16
|
|
1258
|
+
str = RubySMB::Dcerpc::Ndr::NdrVarWideString.new(value)
|
|
1259
|
+
when BinData::Stringz
|
|
1260
|
+
str = RubySMB::Dcerpc::Ndr::NdrVarStringz.new(value)
|
|
1261
|
+
when BinData::String
|
|
1262
|
+
str = RubySMB::Dcerpc::Ndr::NdrVarString.new(value)
|
|
1263
|
+
end
|
|
1264
|
+
subject.assign(str)
|
|
1265
|
+
expect(subject.max_count).to eq(value.length + minimum_size)
|
|
1266
|
+
end
|
|
341
1267
|
end
|
|
342
1268
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
1269
|
+
context 'with a conformant varying string' do
|
|
1270
|
+
it 'sets #max_count to the conformant varying string #max_count value' do
|
|
1271
|
+
case subject
|
|
1272
|
+
when RubySMB::Field::Stringz16
|
|
1273
|
+
str = RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz.new(value)
|
|
1274
|
+
when RubySMB::Field::String16
|
|
1275
|
+
str = RubySMB::Dcerpc::Ndr::NdrConfVarWideString.new(value)
|
|
1276
|
+
when BinData::Stringz
|
|
1277
|
+
str = RubySMB::Dcerpc::Ndr::NdrConfVarStringz.new(value)
|
|
1278
|
+
when BinData::String
|
|
1279
|
+
str = RubySMB::Dcerpc::Ndr::NdrConfVarString.new(value)
|
|
1280
|
+
end
|
|
1281
|
+
str.max_count = 30
|
|
1282
|
+
subject.assign(str)
|
|
1283
|
+
expect(subject.max_count).to eq(30)
|
|
1284
|
+
end
|
|
346
1285
|
end
|
|
1286
|
+
end
|
|
347
1287
|
|
|
348
|
-
|
|
349
|
-
|
|
1288
|
+
describe '#do_num_bytes' do
|
|
1289
|
+
it 'give the correct total size in bytes' do
|
|
1290
|
+
subject.assign(value)
|
|
1291
|
+
expect(subject.do_num_bytes).to eq(binary_stream.size)
|
|
350
1292
|
end
|
|
1293
|
+
end
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
RSpec.shared_examples "a Varying String" do |offset: 0, null_terminated:|
|
|
1297
|
+
minimum_size = null_terminated ? 1 : 0
|
|
351
1298
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
expect(
|
|
1299
|
+
describe '#initialize' do
|
|
1300
|
+
it 'sets #actual_count to 0 (uint32) by default' do
|
|
1301
|
+
expect(subject.actual_count).to eq(0)
|
|
1302
|
+
expect(subject.to_binary_s[offset + 4, 4]).to eq([0].pack('L'))
|
|
355
1303
|
end
|
|
356
1304
|
end
|
|
357
1305
|
|
|
358
|
-
describe '#
|
|
359
|
-
it '
|
|
360
|
-
expect(
|
|
1306
|
+
describe '#do_write' do
|
|
1307
|
+
it 'always writes 0 for "offset"' do
|
|
1308
|
+
expect(subject.to_binary_s[offset, 4]).to eq("\x00\x00\x00\x00".b)
|
|
1309
|
+
subject.assign('Test')
|
|
1310
|
+
expect(subject.to_binary_s[offset, 4]).to eq("\x00\x00\x00\x00".b)
|
|
361
1311
|
end
|
|
362
1312
|
|
|
363
|
-
it
|
|
364
|
-
|
|
365
|
-
expect(
|
|
1313
|
+
it "writes #actual_count corresponding to the number of elements#{' (including the NULL terminator)' if null_terminated}" do
|
|
1314
|
+
subject.assign(value)
|
|
1315
|
+
expect(subject.to_binary_s[offset + 4, 4]).to eq([value.size + minimum_size].pack('L'))
|
|
366
1316
|
end
|
|
1317
|
+
end
|
|
367
1318
|
|
|
368
|
-
|
|
369
|
-
|
|
1319
|
+
describe '#do_read' do
|
|
1320
|
+
it "sets #actual_count to the string size#{' (including the NULL terminator)' if null_terminated}" do
|
|
1321
|
+
subject.read(binary_stream)
|
|
1322
|
+
expect(subject.actual_count).to eq(value.size + minimum_size)
|
|
370
1323
|
end
|
|
1324
|
+
end
|
|
371
1325
|
|
|
372
|
-
|
|
373
|
-
|
|
1326
|
+
describe '#assign' do
|
|
1327
|
+
it "sets #actual_count to the string length#{' (including the NULL terminator)' if null_terminated}" do
|
|
1328
|
+
subject.assign(value)
|
|
1329
|
+
expect(subject.actual_count).to eq(value.length + minimum_size)
|
|
374
1330
|
end
|
|
1331
|
+
end
|
|
375
1332
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
1333
|
+
describe '#do_num_bytes' do
|
|
1334
|
+
it 'give the correct total size in bytes' do
|
|
1335
|
+
subject.assign(value)
|
|
1336
|
+
expect(subject.do_num_bytes).to eq(binary_stream.size)
|
|
379
1337
|
end
|
|
380
1338
|
end
|
|
381
1339
|
end
|
|
382
1340
|
|
|
383
|
-
RSpec.describe RubySMB::Dcerpc::Ndr::
|
|
384
|
-
|
|
385
|
-
|
|
1341
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarString do
|
|
1342
|
+
subject { described_class.new }
|
|
1343
|
+
it 'is a BinData::String class' do
|
|
1344
|
+
expect(described_class).to be < BinData::String
|
|
1345
|
+
expect(described_class).not_to be < RubySMB::Field::String16
|
|
1346
|
+
end
|
|
1347
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 1, null_terminated: false do
|
|
1348
|
+
let(:binary_stream) {
|
|
1349
|
+
"\x00\x00\x00\x00"\
|
|
1350
|
+
"\x04\x00\x00\x00"\
|
|
1351
|
+
"\x41\x42\x43\x44".b
|
|
1352
|
+
}
|
|
1353
|
+
let(:value) { 'ABCD' }
|
|
386
1354
|
end
|
|
1355
|
+
end
|
|
387
1356
|
|
|
388
|
-
|
|
1357
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarStringz do
|
|
1358
|
+
subject { described_class.new }
|
|
1359
|
+
it 'is a BinData::Stringz class' do
|
|
1360
|
+
expect(described_class).to be < BinData::Stringz
|
|
1361
|
+
expect(described_class).not_to be < RubySMB::Field::Stringz16
|
|
1362
|
+
end
|
|
1363
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 1, null_terminated: true do
|
|
1364
|
+
let(:binary_stream) {
|
|
1365
|
+
"\x00\x00\x00\x00"\
|
|
1366
|
+
"\x05\x00\x00\x00"\
|
|
1367
|
+
"\x41\x42\x43\x44\x00".b
|
|
1368
|
+
}
|
|
1369
|
+
let(:value) { 'ABCD' }
|
|
1370
|
+
end
|
|
1371
|
+
end
|
|
389
1372
|
|
|
390
|
-
|
|
1373
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarWideString do
|
|
1374
|
+
subject { described_class.new }
|
|
1375
|
+
it 'is a RubySMB::Field::String16 class' do
|
|
1376
|
+
expect(described_class).to be < RubySMB::Field::String16
|
|
1377
|
+
end
|
|
1378
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 2, null_terminated: false do
|
|
1379
|
+
let(:binary_stream) {
|
|
1380
|
+
"\x00\x00\x00\x00"\
|
|
1381
|
+
"\x04\x00\x00\x00"\
|
|
1382
|
+
"\x41\x00\x42\x00\x43\x00\x44\x00".b
|
|
1383
|
+
}
|
|
1384
|
+
let(:value) { 'ABCD'.encode('utf-16le') }
|
|
1385
|
+
end
|
|
1386
|
+
end
|
|
391
1387
|
|
|
392
|
-
|
|
393
|
-
|
|
1388
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrVarWideStringz do
|
|
1389
|
+
subject { described_class.new }
|
|
1390
|
+
it 'is a RubySMB::Field::Stringz16 class' do
|
|
1391
|
+
expect(described_class).to be < RubySMB::Field::Stringz16
|
|
1392
|
+
end
|
|
1393
|
+
it_behaves_like 'a NDR String', conformant: false, char_size: 2, null_terminated: true do
|
|
1394
|
+
let(:binary_stream) {
|
|
1395
|
+
"\x00\x00\x00\x00"\
|
|
1396
|
+
"\x05\x00\x00\x00"\
|
|
1397
|
+
"\x41\x00\x42\x00\x43\x00\x44\x00\x00\x00".b
|
|
1398
|
+
}
|
|
1399
|
+
let(:value) { 'ABCD'.encode('utf-16le') }
|
|
394
1400
|
end
|
|
1401
|
+
end
|
|
395
1402
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
1403
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarString do
|
|
1404
|
+
subject { described_class.new }
|
|
1405
|
+
it 'is a BinData::String class' do
|
|
1406
|
+
expect(described_class).to be < BinData::String
|
|
1407
|
+
expect(described_class).not_to be < RubySMB::Field::String16
|
|
1408
|
+
end
|
|
1409
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 1, null_terminated: false do
|
|
1410
|
+
let(:binary_stream) {
|
|
1411
|
+
"\x04\x00\x00\x00"\
|
|
1412
|
+
"\x00\x00\x00\x00"\
|
|
1413
|
+
"\x04\x00\x00\x00"\
|
|
1414
|
+
"\x41\x42\x43\x44".b
|
|
1415
|
+
}
|
|
1416
|
+
let(:value) { 'ABCD' }
|
|
1417
|
+
end
|
|
1418
|
+
end
|
|
1419
|
+
|
|
1420
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarStringz do
|
|
1421
|
+
subject { described_class.new }
|
|
1422
|
+
it 'is a BinData::Stringz class' do
|
|
1423
|
+
expect(described_class).to be < BinData::Stringz
|
|
1424
|
+
expect(described_class).not_to be < RubySMB::Field::Stringz16
|
|
1425
|
+
end
|
|
1426
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 1, null_terminated: true do
|
|
1427
|
+
let(:binary_stream) {
|
|
1428
|
+
"\x05\x00\x00\x00"\
|
|
1429
|
+
"\x00\x00\x00\x00"\
|
|
1430
|
+
"\x05\x00\x00\x00"\
|
|
1431
|
+
"\x41\x42\x43\x44\x00".b
|
|
1432
|
+
}
|
|
1433
|
+
let(:value) { 'ABCD' }
|
|
1434
|
+
end
|
|
1435
|
+
end
|
|
1436
|
+
|
|
1437
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarWideString do
|
|
1438
|
+
subject { described_class.new }
|
|
1439
|
+
it 'is a RubySMB::Field::String16 class' do
|
|
1440
|
+
expect(described_class).to be < RubySMB::Field::String16
|
|
1441
|
+
end
|
|
1442
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 2, null_terminated: false do
|
|
1443
|
+
let(:binary_stream) {
|
|
1444
|
+
"\x04\x00\x00\x00"\
|
|
1445
|
+
"\x00\x00\x00\x00"\
|
|
1446
|
+
"\x04\x00\x00\x00"\
|
|
1447
|
+
"\x41\x00\x42\x00\x43\x00\x44\x00".b
|
|
1448
|
+
}
|
|
1449
|
+
let(:value) { 'ABCD'.encode('utf-16le') }
|
|
1450
|
+
end
|
|
1451
|
+
end
|
|
1452
|
+
|
|
1453
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz do
|
|
1454
|
+
subject { described_class.new }
|
|
1455
|
+
it 'is a RubySMB::Field::Stringz16 class' do
|
|
1456
|
+
expect(described_class).to be < RubySMB::Field::Stringz16
|
|
1457
|
+
end
|
|
1458
|
+
it_behaves_like 'a NDR String', conformant: true, char_size: 2, null_terminated: true do
|
|
1459
|
+
let(:binary_stream) {
|
|
1460
|
+
"\x05\x00\x00\x00"\
|
|
1461
|
+
"\x00\x00\x00\x00"\
|
|
1462
|
+
"\x05\x00\x00\x00"\
|
|
1463
|
+
"\x41\x00\x42\x00\x43\x00\x44\x00\x00\x00".b
|
|
1464
|
+
}
|
|
1465
|
+
let(:value) { 'ABCD'.encode('utf-16le') }
|
|
1466
|
+
end
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
|
|
1470
|
+
#
|
|
1471
|
+
# Structures
|
|
1472
|
+
#
|
|
1473
|
+
|
|
1474
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrStruct do
|
|
1475
|
+
|
|
1476
|
+
describe 'Struct.method_missing' do
|
|
1477
|
+
context 'When validating conformant arrays' do
|
|
1478
|
+
let(:super_result) { double('Super method_missing result') }
|
|
1479
|
+
let(:super_result_array) { [super_result] }
|
|
1480
|
+
before :example do
|
|
1481
|
+
allow(super_result).to receive(:has_parameter?).and_return(true)
|
|
1482
|
+
allow(BinData::Record).to receive(:method_missing).and_return(super_result_array)
|
|
1483
|
+
allow(described_class).to receive(:validate_conformant_array)
|
|
1484
|
+
allow(described_class).to receive(:default_parameters).and_return({byte_align: 4})
|
|
1485
|
+
end
|
|
1486
|
+
it 'calls the superclass method_missing and returns the result' do
|
|
1487
|
+
expect(described_class.method_missing(1, 2)).to eq(super_result_array)
|
|
1488
|
+
end
|
|
1489
|
+
it 'performs conformant array validation if the field is an array of BinData::SanitizedField' do
|
|
1490
|
+
allow(super_result).to receive(:is_a?).with(BinData::SanitizedField).and_return(true)
|
|
1491
|
+
described_class.method_missing(1, 2)
|
|
1492
|
+
expect(described_class).to have_received(:validate_conformant_array).with(super_result_array)
|
|
1493
|
+
end
|
|
1494
|
+
it 'does not perform conformant array validation if the field is not an array of BinData::SanitizedField' do
|
|
1495
|
+
allow(super_result).to receive(:is_a?).with(BinData::SanitizedField).and_return(false)
|
|
1496
|
+
described_class.method_missing(1, 2)
|
|
1497
|
+
expect(described_class).to_not have_received(:validate_conformant_array).with(super_result_array)
|
|
1498
|
+
end
|
|
1499
|
+
end
|
|
1500
|
+
|
|
1501
|
+
context 'when cheking if the fields have :byte_align parameter' do
|
|
1502
|
+
it 'does not raise error when it is set' do
|
|
1503
|
+
expect {
|
|
1504
|
+
Class.new(described_class) do
|
|
1505
|
+
default_parameters byte_align: 4
|
|
1506
|
+
endian :little
|
|
1507
|
+
ndr_uint32 :a
|
|
1508
|
+
end.new
|
|
1509
|
+
}.to_not raise_error
|
|
1510
|
+
end
|
|
1511
|
+
|
|
1512
|
+
it 'raises an error when it is not set' do
|
|
1513
|
+
expect {
|
|
1514
|
+
Class.new(described_class) do
|
|
1515
|
+
endian :little
|
|
1516
|
+
ndr_uint32 :a
|
|
1517
|
+
end.new
|
|
1518
|
+
}.to raise_error(ArgumentError)
|
|
1519
|
+
end
|
|
1520
|
+
|
|
1521
|
+
it 'does not raise error when the field is a BinData:Bit*' do
|
|
1522
|
+
expect {
|
|
1523
|
+
Class.new(described_class) do
|
|
1524
|
+
default_parameters byte_align: 4
|
|
1525
|
+
endian :little
|
|
1526
|
+
bit2 :a
|
|
1527
|
+
end.new
|
|
1528
|
+
}.to_not raise_error
|
|
1529
|
+
end
|
|
1530
|
+
end
|
|
1531
|
+
end
|
|
1532
|
+
|
|
1533
|
+
describe 'Struct.validate_conformant_array' do
|
|
1534
|
+
context 'with a conformant array' do
|
|
1535
|
+
it 'does not raise error if the array is the last member' do
|
|
1536
|
+
expect {
|
|
1537
|
+
Class.new(described_class) do
|
|
1538
|
+
default_parameters byte_align: 4
|
|
1539
|
+
endian :little
|
|
1540
|
+
|
|
1541
|
+
ndr_uint32 :a
|
|
1542
|
+
ndr_conf_array :b, type: :ndr_uint16
|
|
1543
|
+
end
|
|
1544
|
+
}.to_not raise_error
|
|
1545
|
+
end
|
|
1546
|
+
it 'raises error if the array is not the last member' do
|
|
1547
|
+
expect {
|
|
1548
|
+
Class.new(described_class) do
|
|
1549
|
+
default_parameters byte_align: 4
|
|
1550
|
+
endian :little
|
|
1551
|
+
|
|
1552
|
+
ndr_conf_array :b, type: :ndr_uint16
|
|
1553
|
+
ndr_uint32 :a
|
|
1554
|
+
end
|
|
1555
|
+
}.to raise_error(ArgumentError)
|
|
1556
|
+
end
|
|
1557
|
+
it 'does not raise error if the array is not the last member of a non NdrStruct' do
|
|
1558
|
+
expect {
|
|
1559
|
+
Class.new(BinData::Record) do
|
|
1560
|
+
default_parameters byte_align: 4
|
|
1561
|
+
endian :little
|
|
1562
|
+
|
|
1563
|
+
ndr_conf_array :b, type: :ndr_uint16
|
|
1564
|
+
ndr_uint32 :a
|
|
1565
|
+
end
|
|
1566
|
+
}.to_not raise_error
|
|
1567
|
+
end
|
|
1568
|
+
end
|
|
1569
|
+
|
|
1570
|
+
context 'with a conformant varying array' do
|
|
1571
|
+
it 'does not raise error if the array is the last member' do
|
|
1572
|
+
expect {
|
|
1573
|
+
Class.new(described_class) do
|
|
1574
|
+
default_parameters byte_align: 4
|
|
1575
|
+
endian :little
|
|
1576
|
+
|
|
1577
|
+
ndr_uint32 :a
|
|
1578
|
+
ndr_conf_var_array :b, type: :ndr_uint16
|
|
1579
|
+
end
|
|
1580
|
+
}.to_not raise_error
|
|
1581
|
+
end
|
|
1582
|
+
it 'raises error if the array is not the last member' do
|
|
1583
|
+
expect {
|
|
1584
|
+
Class.new(described_class) do
|
|
1585
|
+
default_parameters byte_align: 4
|
|
1586
|
+
endian :little
|
|
1587
|
+
|
|
1588
|
+
ndr_conf_var_array :b, type: :ndr_uint16
|
|
1589
|
+
ndr_uint32 :a
|
|
1590
|
+
end
|
|
1591
|
+
}.to raise_error(ArgumentError)
|
|
1592
|
+
end
|
|
1593
|
+
end
|
|
1594
|
+
|
|
1595
|
+
context 'with a conformant varying string' do
|
|
1596
|
+
it 'does not raise error if the string is the last member' do
|
|
1597
|
+
expect {
|
|
1598
|
+
Class.new(described_class) do
|
|
1599
|
+
default_parameters byte_align: 4
|
|
1600
|
+
endian :little
|
|
1601
|
+
|
|
1602
|
+
ndr_uint32 :a
|
|
1603
|
+
ndr_conf_var_string :b
|
|
1604
|
+
end
|
|
1605
|
+
}.to_not raise_error
|
|
1606
|
+
end
|
|
1607
|
+
it 'raises error if the string is not the last member' do
|
|
1608
|
+
expect {
|
|
1609
|
+
Class.new(described_class) do
|
|
1610
|
+
default_parameters byte_align: 4
|
|
1611
|
+
endian :little
|
|
1612
|
+
|
|
1613
|
+
ndr_conf_var_string :b
|
|
1614
|
+
ndr_uint32 :a
|
|
1615
|
+
end
|
|
1616
|
+
}.to raise_error(ArgumentError)
|
|
1617
|
+
end
|
|
1618
|
+
end
|
|
1619
|
+
|
|
1620
|
+
context 'with an embedded structure containing a conformant array' do
|
|
1621
|
+
after :example do
|
|
1622
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
1623
|
+
end
|
|
1624
|
+
|
|
1625
|
+
context 'when the embedded structure is the last member' do
|
|
1626
|
+
it 'does not raise error' do
|
|
1627
|
+
expect {
|
|
1628
|
+
struct_with_array = Class.new(described_class) do
|
|
1629
|
+
default_parameters byte_align: 4
|
|
1630
|
+
endian :little
|
|
1631
|
+
|
|
1632
|
+
ndr_uint32 :a
|
|
1633
|
+
ndr_conf_var_array :b, type: :ndr_uint16
|
|
1634
|
+
end
|
|
1635
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
1636
|
+
Class.new(described_class) do
|
|
1637
|
+
default_parameters byte_align: 4
|
|
1638
|
+
endian :little
|
|
1639
|
+
|
|
1640
|
+
ndr_uint32 :a
|
|
1641
|
+
test_struct :b
|
|
1642
|
+
end
|
|
1643
|
+
}.to_not raise_error
|
|
1644
|
+
end
|
|
1645
|
+
end
|
|
1646
|
+
|
|
1647
|
+
context 'when the embedded structure is not the last member' do
|
|
1648
|
+
it 'raises error' do
|
|
1649
|
+
expect {
|
|
1650
|
+
struct_with_array = Class.new(described_class) do
|
|
1651
|
+
default_parameters byte_align: 4
|
|
1652
|
+
endian :little
|
|
1653
|
+
|
|
1654
|
+
ndr_uint32 :a
|
|
1655
|
+
ndr_conf_var_array :b, type: :ndr_uint16
|
|
1656
|
+
end
|
|
1657
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
1658
|
+
Class.new(described_class) do
|
|
1659
|
+
default_parameters byte_align: 4
|
|
1660
|
+
endian :little
|
|
1661
|
+
|
|
1662
|
+
test_struct :b
|
|
1663
|
+
ndr_uint32 :a
|
|
1664
|
+
end
|
|
1665
|
+
}.to raise_error(ArgumentError)
|
|
1666
|
+
end
|
|
1667
|
+
end
|
|
1668
|
+
end
|
|
1669
|
+
end
|
|
1670
|
+
|
|
1671
|
+
it 'is a BinData::Record class' do
|
|
1672
|
+
expect(described_class).to be < BinData::Record
|
|
1673
|
+
end
|
|
1674
|
+
|
|
1675
|
+
context 'with only primitives' do
|
|
1676
|
+
let(:struct) do
|
|
1677
|
+
Class.new(described_class) do
|
|
1678
|
+
default_parameters byte_align: 4
|
|
1679
|
+
endian :little
|
|
1680
|
+
|
|
1681
|
+
ndr_uint8 :a
|
|
1682
|
+
ndr_uint16 :b
|
|
1683
|
+
ndr_uint32 :c
|
|
1684
|
+
ndr_char :d
|
|
1685
|
+
ndr_boolean :e
|
|
1686
|
+
end
|
|
1687
|
+
end
|
|
1688
|
+
|
|
1689
|
+
it 'initializes the members to their default value' do
|
|
1690
|
+
expect(struct.new).to eq(a: 0, b: 0, c: 0, d: "\x00", e: false)
|
|
1691
|
+
end
|
|
1692
|
+
it 'reads itself' do
|
|
1693
|
+
values = {a: 44, b: 444, c: 4444, d: "T", e: true}
|
|
1694
|
+
struct_instance = struct.new(values)
|
|
1695
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1696
|
+
end
|
|
1697
|
+
context 'with values' do
|
|
1698
|
+
subject do
|
|
1699
|
+
struct.new(a: 1, b: 2, c: 3, d: "A", e: true)
|
|
1700
|
+
end
|
|
1701
|
+
it 'returns the expected member values' do
|
|
1702
|
+
expect(subject).to eq(a: 1, b: 2, c: 3, d: "A", e: true)
|
|
1703
|
+
end
|
|
1704
|
+
it 'outputs the expected binary representation' do
|
|
1705
|
+
binary = "\x01" # a
|
|
1706
|
+
binary << "\x00" # pad
|
|
1707
|
+
binary << "\x02\x00" # b
|
|
1708
|
+
binary << "\x03\x00\x00\x00" # c
|
|
1709
|
+
binary << "\x41" # d
|
|
1710
|
+
binary << "\x00\x00\x00" # pad
|
|
1711
|
+
binary << "\x01\x00\x00\x00" # e
|
|
1712
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1713
|
+
end
|
|
1714
|
+
end
|
|
1715
|
+
end
|
|
1716
|
+
|
|
1717
|
+
context 'with pointers' do
|
|
1718
|
+
let(:struct) do
|
|
1719
|
+
Class.new(described_class) do
|
|
1720
|
+
default_parameters byte_align: 4
|
|
1721
|
+
endian :little
|
|
1722
|
+
|
|
1723
|
+
ndr_uint8 :a
|
|
1724
|
+
ndr_uint16_ptr :b
|
|
1725
|
+
ndr_uint32 :c
|
|
1726
|
+
ndr_char_ptr :d
|
|
1727
|
+
ndr_boolean :e
|
|
1728
|
+
end
|
|
1729
|
+
end
|
|
1730
|
+
|
|
1731
|
+
it 'initializes the members to their default value' do
|
|
1732
|
+
expect(struct.new).to eq(a: 0, b: :null, c: 0, d: :null, e: false)
|
|
1733
|
+
end
|
|
1734
|
+
it 'reads itself' do
|
|
1735
|
+
values = {a: 44, b: 444, c: 4444, d: "T", e: true}
|
|
1736
|
+
struct_instance = struct.new(values)
|
|
1737
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1738
|
+
end
|
|
1739
|
+
context 'with values' do
|
|
1740
|
+
subject do
|
|
1741
|
+
struct.new(a: 1, b: 2, c: 3, d: "A", e: true)
|
|
1742
|
+
end
|
|
1743
|
+
it 'returns the expected member values' do
|
|
1744
|
+
expect(subject).to eq(a: 1, b: 2, c: 3, d: "A", e: true)
|
|
1745
|
+
end
|
|
1746
|
+
it 'outputs the expected binary representation' do
|
|
1747
|
+
binary = "\x01" # a
|
|
1748
|
+
binary << "\x00\x00\x00" # pad
|
|
1749
|
+
binary << "\x01\x00\x00\x00" # b.ref_id
|
|
1750
|
+
binary << "\x03\x00\x00\x00" # c
|
|
1751
|
+
binary << "\x02\x00\x00\x00" # d.ref_id
|
|
1752
|
+
binary << "\x01\x00\x00\x00" # e
|
|
1753
|
+
binary << "\x02\x00" # deferred b
|
|
1754
|
+
binary << "\x41" # deferred d
|
|
1755
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1756
|
+
end
|
|
1757
|
+
end
|
|
1758
|
+
end
|
|
1759
|
+
|
|
1760
|
+
context 'with fixed arrays' do
|
|
1761
|
+
let(:struct) do
|
|
1762
|
+
Class.new(described_class) do
|
|
1763
|
+
default_parameters byte_align: 4
|
|
1764
|
+
endian :little
|
|
1765
|
+
|
|
1766
|
+
ndr_uint32 :a
|
|
1767
|
+
ndr_fix_array :b, type: :ndr_uint32, initial_length: 3, byte_align: 4
|
|
1768
|
+
ndr_uint32 :c
|
|
1769
|
+
end
|
|
1770
|
+
end
|
|
1771
|
+
|
|
1772
|
+
it 'initializes the members to their default value' do
|
|
1773
|
+
expect(struct.new).to eq(a: 0, b: [0, 0, 0], c: 0)
|
|
1774
|
+
end
|
|
1775
|
+
it 'reads itself' do
|
|
1776
|
+
values = {a: 44, b: [1,2,3], c: 4444}
|
|
1777
|
+
struct_instance = struct.new(values)
|
|
1778
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1779
|
+
end
|
|
1780
|
+
context 'with values' do
|
|
1781
|
+
subject do
|
|
1782
|
+
struct.new(a: 4, b: [1,2,3], c: 5)
|
|
1783
|
+
end
|
|
1784
|
+
it 'returns the expected member values' do
|
|
1785
|
+
expect(subject).to eq(a: 4, b: [1,2,3], c: 5)
|
|
1786
|
+
end
|
|
1787
|
+
it 'outputs the expected binary representation' do
|
|
1788
|
+
binary = "\x04\x00\x00\x00" # a
|
|
1789
|
+
binary << "\x01\x00\x00\x00" # b[0]
|
|
1790
|
+
binary << "\x02\x00\x00\x00" # b[1]
|
|
1791
|
+
binary << "\x03\x00\x00\x00" # b[2]
|
|
1792
|
+
binary << "\x05\x00\x00\x00" # c
|
|
1793
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1794
|
+
end
|
|
1795
|
+
end
|
|
1796
|
+
end
|
|
1797
|
+
|
|
1798
|
+
context 'with fixed arrays containing pointers' do
|
|
1799
|
+
let(:struct) do
|
|
1800
|
+
Class.new(described_class) do
|
|
1801
|
+
default_parameters byte_align: 4
|
|
1802
|
+
endian :little
|
|
1803
|
+
|
|
1804
|
+
ndr_uint32 :a
|
|
1805
|
+
ndr_fix_array :b, type: :ndr_uint32_ptr, initial_length: 3, byte_align: 4
|
|
1806
|
+
ndr_uint32 :c
|
|
1807
|
+
end
|
|
1808
|
+
end
|
|
1809
|
+
|
|
1810
|
+
it 'initializes the members to their default value' do
|
|
1811
|
+
expect(struct.new).to eq(a: 0, b: [:null, :null, :null], c: 0)
|
|
1812
|
+
end
|
|
1813
|
+
it 'reads itself' do
|
|
1814
|
+
values = {a: 44, b: [1,2,3], c: 4444}
|
|
1815
|
+
struct_instance = struct.new(values)
|
|
1816
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1817
|
+
end
|
|
1818
|
+
context 'with values' do
|
|
1819
|
+
subject do
|
|
1820
|
+
struct.new(a: 4, b: [1,2,3], c: 5)
|
|
1821
|
+
end
|
|
1822
|
+
it 'returns the expected member values' do
|
|
1823
|
+
expect(subject).to eq(a: 4, b: [1,2,3], c: 5)
|
|
1824
|
+
end
|
|
1825
|
+
it 'outputs the expected binary representation' do
|
|
1826
|
+
binary = "\x04\x00\x00\x00" # a
|
|
1827
|
+
binary << "\x01\x00\x00\x00" # b[0].ref_id
|
|
1828
|
+
binary << "\x02\x00\x00\x00" # b[1].ref_id
|
|
1829
|
+
binary << "\x03\x00\x00\x00" # b[2].ref_id
|
|
1830
|
+
binary << "\x05\x00\x00\x00" # c
|
|
1831
|
+
binary << "\x01\x00\x00\x00" # b[0]
|
|
1832
|
+
binary << "\x02\x00\x00\x00" # b[1]
|
|
1833
|
+
binary << "\x03\x00\x00\x00" # b[2]
|
|
1834
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1835
|
+
end
|
|
1836
|
+
end
|
|
1837
|
+
end
|
|
1838
|
+
|
|
1839
|
+
context 'with varying arrays' do
|
|
1840
|
+
let(:struct) do
|
|
1841
|
+
Class.new(described_class) do
|
|
1842
|
+
default_parameters byte_align: 4
|
|
1843
|
+
endian :little
|
|
1844
|
+
|
|
1845
|
+
ndr_uint32 :a
|
|
1846
|
+
ndr_var_array :b, type: :ndr_uint32
|
|
1847
|
+
ndr_uint32 :c
|
|
1848
|
+
end
|
|
1849
|
+
end
|
|
1850
|
+
|
|
1851
|
+
it 'initializes the members to their default value' do
|
|
1852
|
+
expect(struct.new).to eq(a: 0, b: [], c: 0)
|
|
1853
|
+
end
|
|
1854
|
+
it 'reads itself' do
|
|
1855
|
+
values = {a: 44, b: [1,2,3], c: 4444}
|
|
1856
|
+
struct_instance = struct.new(values)
|
|
1857
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1858
|
+
end
|
|
1859
|
+
context 'with values' do
|
|
1860
|
+
subject do
|
|
1861
|
+
struct.new(a: 4, b: [1,2,3], c: 5)
|
|
1862
|
+
end
|
|
1863
|
+
it 'returns the expected member values' do
|
|
1864
|
+
expect(subject).to eq(a: 4, b: [1,2,3], c: 5)
|
|
1865
|
+
end
|
|
1866
|
+
it 'outputs the expected binary representation' do
|
|
1867
|
+
binary = "\x04\x00\x00\x00" # a
|
|
1868
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
1869
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
1870
|
+
binary << "\x01\x00\x00\x00" # b[0]
|
|
1871
|
+
binary << "\x02\x00\x00\x00" # b[1]
|
|
1872
|
+
binary << "\x03\x00\x00\x00" # b[2]
|
|
1873
|
+
binary << "\x05\x00\x00\x00" # c
|
|
1874
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1875
|
+
end
|
|
1876
|
+
end
|
|
1877
|
+
end
|
|
1878
|
+
|
|
1879
|
+
context 'with varying arrays containing pointers' do
|
|
1880
|
+
let(:struct) do
|
|
1881
|
+
Class.new(described_class) do
|
|
1882
|
+
default_parameters byte_align: 4
|
|
1883
|
+
endian :little
|
|
1884
|
+
|
|
1885
|
+
ndr_uint32 :a
|
|
1886
|
+
ndr_var_array :b, type: :ndr_uint32_ptr
|
|
1887
|
+
ndr_uint32 :c
|
|
1888
|
+
end
|
|
1889
|
+
end
|
|
1890
|
+
|
|
1891
|
+
it 'initializes the members to their default value' do
|
|
1892
|
+
expect(struct.new).to eq(a: 0, b: [], c: 0)
|
|
1893
|
+
end
|
|
1894
|
+
it 'reads itself' do
|
|
1895
|
+
values = {a: 44, b: [1,2,3], c: 4444}
|
|
1896
|
+
struct_instance = struct.new(values)
|
|
1897
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1898
|
+
end
|
|
1899
|
+
context 'with values' do
|
|
1900
|
+
subject do
|
|
1901
|
+
struct.new(a: 4, b: [1,2,3], c: 5)
|
|
1902
|
+
end
|
|
1903
|
+
it 'returns the expected member values' do
|
|
1904
|
+
expect(subject).to eq(a: 4, b: [1,2,3], c: 5)
|
|
1905
|
+
end
|
|
1906
|
+
it 'outputs the expected binary representation' do
|
|
1907
|
+
binary = "\x04\x00\x00\x00" # a
|
|
1908
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
1909
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
1910
|
+
binary << "\x01\x00\x00\x00" # b[0].ref_id
|
|
1911
|
+
binary << "\x02\x00\x00\x00" # b[1].ref_id
|
|
1912
|
+
binary << "\x03\x00\x00\x00" # b[2].ref_id
|
|
1913
|
+
binary << "\x05\x00\x00\x00" # c
|
|
1914
|
+
binary << "\x01\x00\x00\x00" # deferred b[0]
|
|
1915
|
+
binary << "\x02\x00\x00\x00" # deferred b[1]
|
|
1916
|
+
binary << "\x03\x00\x00\x00" # deferred b[2]
|
|
1917
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1918
|
+
end
|
|
1919
|
+
end
|
|
1920
|
+
end
|
|
1921
|
+
|
|
1922
|
+
context 'with conformant arrays' do
|
|
1923
|
+
let(:struct) do
|
|
1924
|
+
Class.new(described_class) do
|
|
1925
|
+
default_parameters byte_align: 4
|
|
1926
|
+
endian :little
|
|
1927
|
+
|
|
1928
|
+
ndr_uint32 :a
|
|
1929
|
+
ndr_uint32 :b
|
|
1930
|
+
ndr_conf_array :c, type: :ndr_uint32
|
|
1931
|
+
end
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
it 'initializes the members to their default value' do
|
|
1935
|
+
expect(struct.new).to eq(a: 0, b: 0, c: [])
|
|
1936
|
+
end
|
|
1937
|
+
it 'reads itself' do
|
|
1938
|
+
values = {a: 44, b: 4444, c: [1,2,3]}
|
|
1939
|
+
struct_instance = struct.new(values)
|
|
1940
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1941
|
+
end
|
|
1942
|
+
context 'with values' do
|
|
1943
|
+
subject do
|
|
1944
|
+
struct.new(a: 4, b: 5, c: [1,2,3])
|
|
1945
|
+
end
|
|
1946
|
+
it 'returns the expected member values' do
|
|
1947
|
+
expect(subject).to eq(a: 4, b: 5, c: [1,2,3])
|
|
1948
|
+
end
|
|
1949
|
+
it 'outputs the expected binary representation' do
|
|
1950
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
1951
|
+
binary << "\x04\x00\x00\x00" # a
|
|
1952
|
+
binary << "\x05\x00\x00\x00" # b
|
|
1953
|
+
binary << "\x01\x00\x00\x00" # c[0]
|
|
1954
|
+
binary << "\x02\x00\x00\x00" # c[1]
|
|
1955
|
+
binary << "\x03\x00\x00\x00" # c[2]
|
|
1956
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1957
|
+
end
|
|
1958
|
+
end
|
|
1959
|
+
end
|
|
1960
|
+
|
|
1961
|
+
context 'with conformant arrays containing pointers' do
|
|
1962
|
+
let(:struct) do
|
|
1963
|
+
Class.new(described_class) do
|
|
1964
|
+
default_parameters byte_align: 4
|
|
1965
|
+
endian :little
|
|
1966
|
+
|
|
1967
|
+
ndr_uint32 :a
|
|
1968
|
+
ndr_uint32 :b
|
|
1969
|
+
ndr_conf_array :c, type: :ndr_uint32_ptr
|
|
1970
|
+
end
|
|
1971
|
+
end
|
|
1972
|
+
|
|
1973
|
+
it 'initializes the members to their default value' do
|
|
1974
|
+
expect(struct.new).to eq(a: 0, b: 0, c: [])
|
|
1975
|
+
end
|
|
1976
|
+
it 'reads itself' do
|
|
1977
|
+
values = {a: 44, b: 4444, c: [1,2,3]}
|
|
1978
|
+
struct_instance = struct.new(values)
|
|
1979
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
1980
|
+
end
|
|
1981
|
+
context 'with values' do
|
|
1982
|
+
subject do
|
|
1983
|
+
struct.new(a: 4, b: 5, c: [1,2,3])
|
|
1984
|
+
end
|
|
1985
|
+
it 'returns the expected member values' do
|
|
1986
|
+
expect(subject).to eq(a: 4, b: 5, c: [1,2,3])
|
|
1987
|
+
end
|
|
1988
|
+
it 'outputs the expected binary representation' do
|
|
1989
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
1990
|
+
binary << "\x04\x00\x00\x00" # a
|
|
1991
|
+
binary << "\x05\x00\x00\x00" # b
|
|
1992
|
+
binary << "\x01\x00\x00\x00" # c[0].ref_id
|
|
1993
|
+
binary << "\x02\x00\x00\x00" # c[1].ref_id
|
|
1994
|
+
binary << "\x03\x00\x00\x00" # c[2].ref_id
|
|
1995
|
+
binary << "\x01\x00\x00\x00" # c[0]
|
|
1996
|
+
binary << "\x02\x00\x00\x00" # c[1]
|
|
1997
|
+
binary << "\x03\x00\x00\x00" # c[2]
|
|
1998
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
1999
|
+
end
|
|
2000
|
+
end
|
|
2001
|
+
end
|
|
2002
|
+
|
|
2003
|
+
context 'with a conformant varying array' do
|
|
2004
|
+
let(:struct) do
|
|
2005
|
+
Class.new(described_class) do
|
|
2006
|
+
default_parameters byte_align: 4
|
|
2007
|
+
endian :little
|
|
2008
|
+
|
|
2009
|
+
ndr_uint32 :a
|
|
2010
|
+
ndr_uint32 :b
|
|
2011
|
+
ndr_conf_var_array :c, type: :ndr_uint32
|
|
2012
|
+
end
|
|
2013
|
+
end
|
|
2014
|
+
|
|
2015
|
+
it 'initializes the members to their default value' do
|
|
2016
|
+
expect(struct.new).to eq(a: 0, b: 0, c: [])
|
|
2017
|
+
end
|
|
2018
|
+
it 'reads itself' do
|
|
2019
|
+
values = {a: 44, b: 4444, c: [1,2,3]}
|
|
2020
|
+
struct_instance = struct.new(values)
|
|
2021
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2022
|
+
end
|
|
2023
|
+
context 'with values' do
|
|
2024
|
+
subject do
|
|
2025
|
+
struct.new(a: 4, b: 5, c: [1,2,3])
|
|
2026
|
+
end
|
|
2027
|
+
it 'returns the expected member values' do
|
|
2028
|
+
expect(subject).to eq(a: 4, b: 5, c: [1,2,3])
|
|
2029
|
+
end
|
|
2030
|
+
it 'outputs the expected binary representation' do
|
|
2031
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
2032
|
+
binary << "\x04\x00\x00\x00" # a
|
|
2033
|
+
binary << "\x05\x00\x00\x00" # b
|
|
2034
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
2035
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
2036
|
+
binary << "\x01\x00\x00\x00" # c[0]
|
|
2037
|
+
binary << "\x02\x00\x00\x00" # c[1]
|
|
2038
|
+
binary << "\x03\x00\x00\x00" # c[2]
|
|
2039
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2040
|
+
end
|
|
2041
|
+
end
|
|
2042
|
+
end
|
|
2043
|
+
|
|
2044
|
+
context 'with a conformant varying array containing pointers' do
|
|
2045
|
+
let(:struct) do
|
|
2046
|
+
Class.new(described_class) do
|
|
2047
|
+
default_parameters byte_align: 4
|
|
2048
|
+
endian :little
|
|
2049
|
+
|
|
2050
|
+
ndr_uint32 :a
|
|
2051
|
+
ndr_uint32 :b
|
|
2052
|
+
ndr_conf_var_array :c, type: :ndr_uint32_ptr
|
|
2053
|
+
end
|
|
2054
|
+
end
|
|
2055
|
+
|
|
2056
|
+
it 'initializes the members to their default value' do
|
|
2057
|
+
expect(struct.new).to eq(a: 0, b: 0, c: [])
|
|
2058
|
+
end
|
|
2059
|
+
it 'reads itself' do
|
|
2060
|
+
values = {a: 44, b: 4444, c: [1,2,3]}
|
|
2061
|
+
struct_instance = struct.new(values)
|
|
2062
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2063
|
+
end
|
|
2064
|
+
context 'with values' do
|
|
2065
|
+
subject do
|
|
2066
|
+
struct.new(a: 4, b: 5, c: [1,2,3])
|
|
2067
|
+
end
|
|
2068
|
+
it 'returns the expected member values' do
|
|
2069
|
+
expect(subject).to eq(a: 4, b: 5, c: [1,2,3])
|
|
2070
|
+
end
|
|
2071
|
+
it 'outputs the expected binary representation' do
|
|
2072
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
2073
|
+
binary << "\x04\x00\x00\x00" # a
|
|
2074
|
+
binary << "\x05\x00\x00\x00" # c
|
|
2075
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
2076
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
2077
|
+
binary << "\x01\x00\x00\x00" # b[0].ref_id
|
|
2078
|
+
binary << "\x02\x00\x00\x00" # b[1].ref_id
|
|
2079
|
+
binary << "\x03\x00\x00\x00" # b[2].ref_id
|
|
2080
|
+
binary << "\x01\x00\x00\x00" # deferred b[0]
|
|
2081
|
+
binary << "\x02\x00\x00\x00" # deferred b[1]
|
|
2082
|
+
binary << "\x03\x00\x00\x00" # deferred b[2]
|
|
2083
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2084
|
+
end
|
|
2085
|
+
end
|
|
2086
|
+
end
|
|
2087
|
+
|
|
2088
|
+
context 'with an embedded structure containing a fixed array' do
|
|
2089
|
+
after :example do
|
|
2090
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2091
|
+
end
|
|
2092
|
+
|
|
2093
|
+
let(:struct) do
|
|
2094
|
+
struct_with_array = Class.new(described_class) do
|
|
2095
|
+
default_parameters byte_align: 4
|
|
2096
|
+
endian :little
|
|
2097
|
+
|
|
2098
|
+
ndr_uint16 :a
|
|
2099
|
+
ndr_fix_array :b, type: :ndr_uint32, initial_length: 3, byte_align: 4
|
|
2100
|
+
ndr_uint16 :c
|
|
2101
|
+
end
|
|
2102
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2103
|
+
Class.new(described_class) do
|
|
2104
|
+
default_parameters byte_align: 4
|
|
2105
|
+
endian :little
|
|
2106
|
+
|
|
2107
|
+
ndr_uint16 :a
|
|
2108
|
+
ndr_uint16 :b
|
|
2109
|
+
test_struct :c
|
|
2110
|
+
end
|
|
2111
|
+
end
|
|
2112
|
+
|
|
2113
|
+
it 'initializes the members to their default value' do
|
|
2114
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: [0, 0 ,0], c: 0})
|
|
2115
|
+
end
|
|
2116
|
+
it 'reads itself' do
|
|
2117
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: [1, 2, 3], c: 77}}
|
|
2118
|
+
struct_instance = struct.new(values)
|
|
2119
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2120
|
+
end
|
|
2121
|
+
context 'with values' do
|
|
2122
|
+
subject do
|
|
2123
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2124
|
+
end
|
|
2125
|
+
it 'returns the expected member values' do
|
|
2126
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2127
|
+
end
|
|
2128
|
+
it 'outputs the expected binary representation' do
|
|
2129
|
+
binary = "\x05\x00" # a
|
|
2130
|
+
binary << "\x06\x00" # b
|
|
2131
|
+
binary << "\x07\x00" # c.a
|
|
2132
|
+
binary << "\x00\x00" # pad
|
|
2133
|
+
binary << "\x01\x00\x00\x00" # c.b[0]
|
|
2134
|
+
binary << "\x02\x00\x00\x00" # c.b[1]
|
|
2135
|
+
binary << "\x03\x00\x00\x00" # c.b[2]
|
|
2136
|
+
binary << "\x08\x00" # c.c
|
|
2137
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2138
|
+
end
|
|
2139
|
+
end
|
|
2140
|
+
end
|
|
2141
|
+
|
|
2142
|
+
context 'with an embedded structure containing a fixed array of pointers' do
|
|
2143
|
+
after :example do
|
|
2144
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2145
|
+
end
|
|
2146
|
+
|
|
2147
|
+
let(:struct) do
|
|
2148
|
+
struct_with_array = Class.new(described_class) do
|
|
2149
|
+
default_parameters byte_align: 4
|
|
2150
|
+
endian :little
|
|
2151
|
+
|
|
2152
|
+
ndr_uint16 :a
|
|
2153
|
+
ndr_fix_array :b, type: :ndr_uint32_ptr, initial_length: 3, byte_align: 4
|
|
2154
|
+
ndr_uint16 :c
|
|
2155
|
+
end
|
|
2156
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2157
|
+
Class.new(described_class) do
|
|
2158
|
+
default_parameters byte_align: 4
|
|
2159
|
+
endian :little
|
|
2160
|
+
|
|
2161
|
+
ndr_uint16 :a
|
|
2162
|
+
ndr_uint16 :b
|
|
2163
|
+
test_struct :c
|
|
2164
|
+
end
|
|
2165
|
+
end
|
|
2166
|
+
|
|
2167
|
+
it 'initializes the members to their default value' do
|
|
2168
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: [:null, :null ,:null], c: 0})
|
|
2169
|
+
end
|
|
2170
|
+
it 'reads itself' do
|
|
2171
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: [1, 2, 3], c: 77}}
|
|
2172
|
+
struct_instance = struct.new(values)
|
|
2173
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2174
|
+
end
|
|
2175
|
+
context 'with values' do
|
|
2176
|
+
subject do
|
|
2177
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2178
|
+
end
|
|
2179
|
+
it 'returns the expected member values' do
|
|
2180
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2181
|
+
end
|
|
2182
|
+
it 'outputs the expected binary representation' do
|
|
2183
|
+
binary = "\x05\x00" # a
|
|
2184
|
+
binary << "\x06\x00" # b
|
|
2185
|
+
binary << "\x07\x00" # c.a
|
|
2186
|
+
binary << "\x00\x00" # pad
|
|
2187
|
+
binary << "\x01\x00\x00\x00" # c.b[0].ref_id
|
|
2188
|
+
binary << "\x02\x00\x00\x00" # c.b[1].ref_id
|
|
2189
|
+
binary << "\x03\x00\x00\x00" # c.b[2].ref_id
|
|
2190
|
+
binary << "\x08\x00" # c.c
|
|
2191
|
+
binary << "\x00\x00" # pad
|
|
2192
|
+
binary << "\x01\x00\x00\x00" # deferred c.b[0]
|
|
2193
|
+
binary << "\x02\x00\x00\x00" # deferred c.b[1]
|
|
2194
|
+
binary << "\x03\x00\x00\x00" # deferred c.b[2]
|
|
2195
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2196
|
+
end
|
|
2197
|
+
end
|
|
2198
|
+
end
|
|
2199
|
+
|
|
2200
|
+
context 'with an embedded structure containing a varying array' do
|
|
2201
|
+
after :example do
|
|
2202
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2203
|
+
end
|
|
2204
|
+
|
|
2205
|
+
let(:struct) do
|
|
2206
|
+
struct_with_array = Class.new(described_class) do
|
|
2207
|
+
default_parameters byte_align: 4
|
|
2208
|
+
endian :little
|
|
2209
|
+
|
|
2210
|
+
ndr_uint16 :a
|
|
2211
|
+
ndr_var_array :b, type: :ndr_uint32
|
|
2212
|
+
ndr_uint16 :c
|
|
2213
|
+
end
|
|
2214
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2215
|
+
Class.new(described_class) do
|
|
2216
|
+
default_parameters byte_align: 4
|
|
2217
|
+
endian :little
|
|
2218
|
+
|
|
2219
|
+
ndr_uint16 :a
|
|
2220
|
+
ndr_uint16 :b
|
|
2221
|
+
test_struct :c
|
|
2222
|
+
end
|
|
2223
|
+
end
|
|
2224
|
+
|
|
2225
|
+
it 'initializes the members to their default value' do
|
|
2226
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: [], c: 0})
|
|
2227
|
+
end
|
|
2228
|
+
it 'reads itself' do
|
|
2229
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: [1, 2, 3], c: 77}}
|
|
2230
|
+
struct_instance = struct.new(values)
|
|
2231
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2232
|
+
end
|
|
2233
|
+
context 'with values' do
|
|
2234
|
+
subject do
|
|
2235
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2236
|
+
end
|
|
2237
|
+
it 'returns the expected member values' do
|
|
2238
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2239
|
+
end
|
|
2240
|
+
it 'outputs the expected binary representation' do
|
|
2241
|
+
binary = "\x05\x00" # a
|
|
2242
|
+
binary << "\x06\x00" # b
|
|
2243
|
+
binary << "\x07\x00" # c.a
|
|
2244
|
+
binary << "\x00\x00" # pad
|
|
2245
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
2246
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
2247
|
+
binary << "\x01\x00\x00\x00" # c.b[0]
|
|
2248
|
+
binary << "\x02\x00\x00\x00" # c.b[1]
|
|
2249
|
+
binary << "\x03\x00\x00\x00" # c.b[2]
|
|
2250
|
+
binary << "\x08\x00" # c.c
|
|
2251
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2252
|
+
end
|
|
2253
|
+
end
|
|
2254
|
+
end
|
|
2255
|
+
|
|
2256
|
+
context 'with an embedded structure containing a varying array of pointers' do
|
|
2257
|
+
after :example do
|
|
2258
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2259
|
+
end
|
|
2260
|
+
|
|
2261
|
+
let(:struct) do
|
|
2262
|
+
struct_with_array = Class.new(described_class) do
|
|
2263
|
+
default_parameters byte_align: 4
|
|
2264
|
+
endian :little
|
|
2265
|
+
|
|
2266
|
+
ndr_uint16 :a
|
|
2267
|
+
ndr_var_array :b, type: :ndr_uint32_ptr
|
|
2268
|
+
ndr_uint16 :c
|
|
2269
|
+
end
|
|
2270
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2271
|
+
Class.new(described_class) do
|
|
2272
|
+
default_parameters byte_align: 4
|
|
2273
|
+
endian :little
|
|
2274
|
+
|
|
2275
|
+
ndr_uint16 :a
|
|
2276
|
+
ndr_uint16 :b
|
|
2277
|
+
test_struct :c
|
|
2278
|
+
end
|
|
2279
|
+
end
|
|
2280
|
+
|
|
2281
|
+
it 'initializes the members to their default value' do
|
|
2282
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: [], c: 0})
|
|
2283
|
+
end
|
|
2284
|
+
it 'reads itself' do
|
|
2285
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: [1, 2, 3], c: 77}}
|
|
2286
|
+
struct_instance = struct.new(values)
|
|
2287
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2288
|
+
end
|
|
2289
|
+
context 'with values' do
|
|
2290
|
+
subject do
|
|
2291
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2292
|
+
end
|
|
2293
|
+
it 'returns the expected member values' do
|
|
2294
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b: [1, 2, 3], c: 8})
|
|
2295
|
+
end
|
|
2296
|
+
it 'outputs the expected binary representation' do
|
|
2297
|
+
binary = "\x05\x00" # a
|
|
2298
|
+
binary << "\x06\x00" # b
|
|
2299
|
+
binary << "\x07\x00" # c.a
|
|
2300
|
+
binary << "\x00\x00" # pad
|
|
2301
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
2302
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
2303
|
+
binary << "\x01\x00\x00\x00" # c.b[0].ref_id
|
|
2304
|
+
binary << "\x02\x00\x00\x00" # c.b[1].ref_id
|
|
2305
|
+
binary << "\x03\x00\x00\x00" # c.b[2].ref_id
|
|
2306
|
+
binary << "\x08\x00" # c.c
|
|
2307
|
+
binary << "\x00\x00" # pad
|
|
2308
|
+
binary << "\x01\x00\x00\x00" # deferred c.b[0]
|
|
2309
|
+
binary << "\x02\x00\x00\x00" # deferred c.b[1]
|
|
2310
|
+
binary << "\x03\x00\x00\x00" # deferred c.b[2]
|
|
2311
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2312
|
+
end
|
|
2313
|
+
end
|
|
2314
|
+
end
|
|
2315
|
+
|
|
2316
|
+
context 'with an embedded structure containing a conformant array' do
|
|
2317
|
+
after :example do
|
|
2318
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2319
|
+
end
|
|
2320
|
+
|
|
2321
|
+
let(:struct) do
|
|
2322
|
+
struct_with_array = Class.new(described_class) do
|
|
2323
|
+
default_parameters byte_align: 4
|
|
2324
|
+
endian :little
|
|
2325
|
+
|
|
2326
|
+
ndr_uint16 :a
|
|
2327
|
+
ndr_uint16 :b
|
|
2328
|
+
ndr_conf_array :c, type: :ndr_uint32
|
|
2329
|
+
end
|
|
2330
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2331
|
+
Class.new(described_class) do
|
|
2332
|
+
default_parameters byte_align: 4
|
|
2333
|
+
endian :little
|
|
2334
|
+
|
|
2335
|
+
ndr_uint16 :a
|
|
2336
|
+
ndr_uint16 :b
|
|
2337
|
+
test_struct :c
|
|
2338
|
+
end
|
|
2339
|
+
end
|
|
2340
|
+
|
|
2341
|
+
it 'initializes the members to their default value' do
|
|
2342
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: 0, c: []})
|
|
2343
|
+
end
|
|
2344
|
+
it 'reads itself' do
|
|
2345
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: 77, c: [1, 2, 3]}}
|
|
2346
|
+
struct_instance = struct.new(values)
|
|
2347
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2348
|
+
end
|
|
2349
|
+
context 'with values' do
|
|
2350
|
+
subject do
|
|
2351
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: 8, c: [1, 2, 3]})
|
|
2352
|
+
end
|
|
2353
|
+
it 'returns the expected member values' do
|
|
2354
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b:8, c: [1, 2, 3]})
|
|
2355
|
+
end
|
|
2356
|
+
it 'outputs the expected binary representation' do
|
|
2357
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
2358
|
+
binary << "\x05\x00" # a
|
|
2359
|
+
binary << "\x06\x00" # b
|
|
2360
|
+
binary << "\x07\x00" # c.a
|
|
2361
|
+
binary << "\x08\x00" # c.b
|
|
2362
|
+
binary << "\x01\x00\x00\x00" # c.c[0]
|
|
2363
|
+
binary << "\x02\x00\x00\x00" # c.c[1]
|
|
2364
|
+
binary << "\x03\x00\x00\x00" # c.c[2]
|
|
2365
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2366
|
+
end
|
|
2367
|
+
end
|
|
2368
|
+
end
|
|
2369
|
+
|
|
2370
|
+
context 'with an embedded structure containing a conformant array of pointers' do
|
|
2371
|
+
after :example do
|
|
2372
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2373
|
+
end
|
|
2374
|
+
|
|
2375
|
+
let(:struct) do
|
|
2376
|
+
struct_with_array = Class.new(described_class) do
|
|
2377
|
+
default_parameters byte_align: 4
|
|
2378
|
+
endian :little
|
|
2379
|
+
|
|
2380
|
+
ndr_uint16 :a
|
|
2381
|
+
ndr_uint16 :b
|
|
2382
|
+
ndr_conf_array :c, type: :ndr_uint32_ptr
|
|
2383
|
+
end
|
|
2384
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2385
|
+
Class.new(described_class) do
|
|
2386
|
+
default_parameters byte_align: 4
|
|
2387
|
+
endian :little
|
|
2388
|
+
|
|
2389
|
+
ndr_uint16 :a
|
|
2390
|
+
ndr_uint16 :b
|
|
2391
|
+
test_struct :c
|
|
2392
|
+
end
|
|
2393
|
+
end
|
|
2394
|
+
|
|
2395
|
+
it 'initializes the members to their default value' do
|
|
2396
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: 0, c: []})
|
|
2397
|
+
end
|
|
2398
|
+
it 'reads itself' do
|
|
2399
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: 77, c: [1, 2, 3]}}
|
|
2400
|
+
struct_instance = struct.new(values)
|
|
2401
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2402
|
+
end
|
|
2403
|
+
context 'with values' do
|
|
2404
|
+
subject do
|
|
2405
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: 8, c: [1, 2, 3]})
|
|
2406
|
+
end
|
|
2407
|
+
it 'returns the expected member values' do
|
|
2408
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b:8, c: [1, 2, 3]})
|
|
2409
|
+
end
|
|
2410
|
+
it 'outputs the expected binary representation' do
|
|
2411
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
2412
|
+
binary << "\x05\x00" # a
|
|
2413
|
+
binary << "\x06\x00" # b
|
|
2414
|
+
binary << "\x07\x00" # c.a
|
|
2415
|
+
binary << "\x08\x00" # c.b
|
|
2416
|
+
binary << "\x01\x00\x00\x00" # c.b[0].ref_id
|
|
2417
|
+
binary << "\x02\x00\x00\x00" # c.b[1].ref_id
|
|
2418
|
+
binary << "\x03\x00\x00\x00" # c.b[2].ref_id
|
|
2419
|
+
binary << "\x01\x00\x00\x00" # deferred c.b[0]
|
|
2420
|
+
binary << "\x02\x00\x00\x00" # deferred c.b[1]
|
|
2421
|
+
binary << "\x03\x00\x00\x00" # deferred c.b[2]
|
|
2422
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2423
|
+
end
|
|
2424
|
+
end
|
|
2425
|
+
end
|
|
2426
|
+
|
|
2427
|
+
context 'with an embedded structure containing a conformant varying array' do
|
|
2428
|
+
after :example do
|
|
2429
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2430
|
+
end
|
|
2431
|
+
|
|
2432
|
+
let(:struct) do
|
|
2433
|
+
struct_with_array = Class.new(described_class) do
|
|
2434
|
+
default_parameters byte_align: 4
|
|
2435
|
+
endian :little
|
|
2436
|
+
|
|
2437
|
+
ndr_uint16 :a
|
|
2438
|
+
ndr_uint16 :b
|
|
2439
|
+
ndr_conf_var_array :c, type: :ndr_uint32
|
|
2440
|
+
end
|
|
2441
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2442
|
+
Class.new(described_class) do
|
|
2443
|
+
default_parameters byte_align: 4
|
|
2444
|
+
endian :little
|
|
2445
|
+
|
|
2446
|
+
ndr_uint16 :a
|
|
2447
|
+
ndr_uint16 :b
|
|
2448
|
+
test_struct :c
|
|
2449
|
+
end
|
|
2450
|
+
end
|
|
2451
|
+
|
|
2452
|
+
it 'initializes the members to their default value' do
|
|
2453
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: 0, c: []})
|
|
2454
|
+
end
|
|
2455
|
+
it 'reads itself' do
|
|
2456
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: 77, c: [1, 2, 3]}}
|
|
2457
|
+
struct_instance = struct.new(values)
|
|
2458
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2459
|
+
end
|
|
2460
|
+
context 'with values' do
|
|
2461
|
+
subject do
|
|
2462
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: 8, c: [1, 2, 3]})
|
|
2463
|
+
end
|
|
2464
|
+
it 'returns the expected member values' do
|
|
2465
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b:8, c: [1, 2, 3]})
|
|
2466
|
+
end
|
|
2467
|
+
it 'outputs the expected binary representation' do
|
|
2468
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
2469
|
+
binary << "\x05\x00" # a
|
|
2470
|
+
binary << "\x06\x00" # b
|
|
2471
|
+
binary << "\x07\x00" # c.a
|
|
2472
|
+
binary << "\x08\x00" # c.b
|
|
2473
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
2474
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
2475
|
+
binary << "\x01\x00\x00\x00" # c.c[0]
|
|
2476
|
+
binary << "\x02\x00\x00\x00" # c.c[1]
|
|
2477
|
+
binary << "\x03\x00\x00\x00" # c.c[2]
|
|
2478
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2479
|
+
end
|
|
2480
|
+
end
|
|
2481
|
+
end
|
|
2482
|
+
|
|
2483
|
+
context 'with an embedded structure containing a conformant varying array of pointers' do
|
|
2484
|
+
after :example do
|
|
2485
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2486
|
+
end
|
|
2487
|
+
|
|
2488
|
+
let(:struct) do
|
|
2489
|
+
struct_with_array = Class.new(described_class) do
|
|
2490
|
+
default_parameters byte_align: 4
|
|
2491
|
+
endian :little
|
|
2492
|
+
|
|
2493
|
+
ndr_uint16 :a
|
|
2494
|
+
ndr_uint16 :b
|
|
2495
|
+
ndr_conf_var_array :c, type: :ndr_uint32_ptr
|
|
2496
|
+
end
|
|
2497
|
+
BinData::RegisteredClasses.register('test_struct', struct_with_array)
|
|
2498
|
+
Class.new(described_class) do
|
|
2499
|
+
default_parameters byte_align: 4
|
|
2500
|
+
endian :little
|
|
2501
|
+
|
|
2502
|
+
ndr_uint16 :a
|
|
2503
|
+
ndr_uint16 :b
|
|
2504
|
+
test_struct :c
|
|
2505
|
+
end
|
|
2506
|
+
end
|
|
2507
|
+
|
|
2508
|
+
it 'initializes the members to their default value' do
|
|
2509
|
+
expect(struct.new).to eq(a: 0, b: 0, c: {a: 0, b: 0, c: []})
|
|
2510
|
+
end
|
|
2511
|
+
it 'reads itself' do
|
|
2512
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: 77, c: [1, 2, 3]}}
|
|
2513
|
+
struct_instance = struct.new(values)
|
|
2514
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2515
|
+
end
|
|
2516
|
+
context 'with values' do
|
|
2517
|
+
subject do
|
|
2518
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: 8, c: [1, 2, 3]})
|
|
2519
|
+
end
|
|
2520
|
+
it 'returns the expected member values' do
|
|
2521
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b:8, c: [1, 2, 3]})
|
|
2522
|
+
end
|
|
2523
|
+
it 'outputs the expected binary representation' do
|
|
2524
|
+
binary = "\x03\x00\x00\x00" # array max_count
|
|
2525
|
+
binary << "\x05\x00" # a
|
|
2526
|
+
binary << "\x06\x00" # b
|
|
2527
|
+
binary << "\x07\x00" # c.a
|
|
2528
|
+
binary << "\x08\x00" # c.b
|
|
2529
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
2530
|
+
binary << "\x03\x00\x00\x00" # array actual_count
|
|
2531
|
+
binary << "\x01\x00\x00\x00" # c.b[0].ref_id
|
|
2532
|
+
binary << "\x02\x00\x00\x00" # c.b[1].ref_id
|
|
2533
|
+
binary << "\x03\x00\x00\x00" # c.b[2].ref_id
|
|
2534
|
+
binary << "\x01\x00\x00\x00" # deferred c.b[0]
|
|
2535
|
+
binary << "\x02\x00\x00\x00" # deferred c.b[1]
|
|
2536
|
+
binary << "\x03\x00\x00\x00" # deferred c.b[2]
|
|
2537
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2538
|
+
end
|
|
2539
|
+
end
|
|
2540
|
+
end
|
|
2541
|
+
|
|
2542
|
+
context 'with a pointer to a conformant arrays' do
|
|
2543
|
+
let(:struct) do
|
|
2544
|
+
struct_ptr = Class.new(RubySMB::Dcerpc::Ndr::NdrConfArray) do
|
|
2545
|
+
default_parameters(type: :ndr_uint32)
|
|
2546
|
+
extend RubySMB::Dcerpc::Ndr::PointerClassPlugin
|
|
2547
|
+
end
|
|
2548
|
+
BinData::RegisteredClasses.register('test_conf_array_ptr', struct_ptr)
|
|
2549
|
+
Class.new(described_class) do
|
|
2550
|
+
default_parameters byte_align: 4
|
|
2551
|
+
endian :little
|
|
2552
|
+
|
|
2553
|
+
ndr_uint32 :a
|
|
2554
|
+
ndr_uint32 :b
|
|
2555
|
+
test_conf_array_ptr :c
|
|
2556
|
+
end
|
|
2557
|
+
end
|
|
2558
|
+
|
|
2559
|
+
it 'initializes the members to their default value' do
|
|
2560
|
+
expect(struct.new).to eq(a: 0, b: 0, c: :null)
|
|
2561
|
+
end
|
|
2562
|
+
it 'reads itself' do
|
|
2563
|
+
values = {a: 44, b: 4444, c: [1,2,3]}
|
|
2564
|
+
struct_instance = struct.new(values)
|
|
2565
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2566
|
+
end
|
|
2567
|
+
context 'with values' do
|
|
2568
|
+
subject do
|
|
2569
|
+
struct.new(a: 4, b: 5, c: [1,2,3])
|
|
2570
|
+
end
|
|
2571
|
+
it 'returns the expected member values' do
|
|
2572
|
+
expect(subject).to eq(a: 4, b: 5, c: [1,2,3])
|
|
2573
|
+
end
|
|
2574
|
+
it 'outputs the expected binary representation' do
|
|
2575
|
+
binary = "\x04\x00\x00\x00" # a
|
|
2576
|
+
binary << "\x05\x00\x00\x00" # b
|
|
2577
|
+
binary << "\x01\x00\x00\x00" # c.ref_id
|
|
2578
|
+
binary << "\x03\x00\x00\x00" # array max_count
|
|
2579
|
+
binary << "\x01\x00\x00\x00" # c[0]
|
|
2580
|
+
binary << "\x02\x00\x00\x00" # c[1]
|
|
2581
|
+
binary << "\x03\x00\x00\x00" # c[2]
|
|
2582
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2583
|
+
end
|
|
2584
|
+
end
|
|
2585
|
+
end
|
|
2586
|
+
|
|
2587
|
+
context 'with a pointer to an embedded structure containing a conformant arrays' do
|
|
2588
|
+
after :example do
|
|
2589
|
+
BinData::RegisteredClasses.unregister('test_struct')
|
|
2590
|
+
end
|
|
2591
|
+
|
|
2592
|
+
let(:struct) do
|
|
2593
|
+
struct_with_array = Class.new(described_class) do
|
|
2594
|
+
default_parameters byte_align: 4
|
|
2595
|
+
endian :little
|
|
2596
|
+
|
|
2597
|
+
ndr_uint32 :a
|
|
2598
|
+
ndr_conf_var_array :b, type: :ndr_uint32
|
|
2599
|
+
end
|
|
2600
|
+
struct_ptr = Class.new(struct_with_array) do
|
|
2601
|
+
extend RubySMB::Dcerpc::Ndr::PointerClassPlugin
|
|
2602
|
+
end
|
|
2603
|
+
BinData::RegisteredClasses.register('test_struct_ptr', struct_ptr)
|
|
2604
|
+
Class.new(BinData::Record) do
|
|
2605
|
+
default_parameters byte_align: 4
|
|
2606
|
+
endian :little
|
|
2607
|
+
|
|
2608
|
+
ndr_uint32 :a
|
|
2609
|
+
ndr_uint32 :b
|
|
2610
|
+
test_struct_ptr :c
|
|
2611
|
+
end
|
|
2612
|
+
end
|
|
2613
|
+
|
|
2614
|
+
it 'initializes the members to their default value' do
|
|
2615
|
+
expect(struct.new).to eq(a: 0, b: 0, c: :null)
|
|
2616
|
+
end
|
|
2617
|
+
it 'reads itself' do
|
|
2618
|
+
values = {a: 44, b: 4444, c: {a: 5555, b: [1, 2, 3, 4]}}
|
|
2619
|
+
struct_instance = struct.new(values)
|
|
2620
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2621
|
+
end
|
|
2622
|
+
context 'with values' do
|
|
2623
|
+
subject do
|
|
2624
|
+
struct.new(a: 5, b: 6, c: {a: 7, b: [1, 2, 3, 4]})
|
|
2625
|
+
end
|
|
2626
|
+
it 'returns the expected member values' do
|
|
2627
|
+
expect(subject).to eq(a: 5, b: 6, c: {a: 7, b: [1, 2, 3, 4]})
|
|
2628
|
+
end
|
|
2629
|
+
it 'outputs the expected binary representation' do
|
|
2630
|
+
binary = "\x05\x00\x00\x00" # a
|
|
2631
|
+
binary << "\x06\x00\x00\x00" # b
|
|
2632
|
+
binary << "\x01\x00\x00\x00" # c.ref_id
|
|
2633
|
+
binary << "\x04\x00\x00\x00" # array max_count
|
|
2634
|
+
binary << "\x07\x00\x00\x00" # c.a
|
|
2635
|
+
binary << "\x00\x00\x00\x00" # array offset
|
|
2636
|
+
binary << "\x04\x00\x00\x00" # array actual_count
|
|
2637
|
+
binary << "\x01\x00\x00\x00" # c.b[0]
|
|
2638
|
+
binary << "\x02\x00\x00\x00" # c.b[1]
|
|
2639
|
+
binary << "\x03\x00\x00\x00" # c.b[2]
|
|
2640
|
+
binary << "\x04\x00\x00\x00" # c.b[3]
|
|
2641
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2642
|
+
end
|
|
2643
|
+
end
|
|
2644
|
+
end
|
|
2645
|
+
|
|
2646
|
+
context 'with varying strings' do
|
|
2647
|
+
let(:struct) do
|
|
2648
|
+
Class.new(described_class) do
|
|
2649
|
+
default_parameters byte_align: 4
|
|
2650
|
+
endian :little
|
|
2651
|
+
|
|
2652
|
+
ndr_uint8 :a
|
|
2653
|
+
ndr_var_string :b
|
|
2654
|
+
ndr_uint32 :c
|
|
2655
|
+
ndr_var_string :d
|
|
2656
|
+
ndr_boolean :e
|
|
2657
|
+
end
|
|
2658
|
+
end
|
|
2659
|
+
|
|
2660
|
+
it 'initializes the members to their default value' do
|
|
2661
|
+
expect(struct.new).to eq(a: 0, b: '', c: 0, d: '', e: false)
|
|
2662
|
+
end
|
|
2663
|
+
it 'reads itself' do
|
|
2664
|
+
values = {a: 44, b: 'Test1', c: 4444, d: 'Test22', e: true}
|
|
2665
|
+
struct_instance = struct.new(values)
|
|
2666
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2667
|
+
end
|
|
2668
|
+
context 'with values' do
|
|
2669
|
+
subject do
|
|
2670
|
+
struct.new(a: 1, b: 'Test1', c: 3, d: 'Test22', e: true)
|
|
2671
|
+
end
|
|
2672
|
+
it 'returns the expected member values' do
|
|
2673
|
+
expect(subject).to eq(a: 1, b: 'Test1', c: 3, d: 'Test22', e: true)
|
|
2674
|
+
end
|
|
2675
|
+
it 'outputs the expected binary representation' do
|
|
2676
|
+
binary = "\x01" # a
|
|
2677
|
+
binary << "\x00\x00\x00" # pad
|
|
2678
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2679
|
+
binary << "\x05\x00\x00\x00" # b actual_count
|
|
2680
|
+
binary << 'Test1' # b
|
|
2681
|
+
binary << "\x00\x00\x00" # pad
|
|
2682
|
+
binary << "\x03\x00\x00\x00" # c
|
|
2683
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2684
|
+
binary << "\x06\x00\x00\x00" # b actual_count
|
|
2685
|
+
binary << 'Test22' # d
|
|
2686
|
+
binary << "\x00\x00" # pad
|
|
2687
|
+
binary << "\x01\x00\x00\x00" # e
|
|
2688
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2689
|
+
end
|
|
2690
|
+
end
|
|
2691
|
+
end
|
|
2692
|
+
|
|
2693
|
+
context 'with varying null terminated strings' do
|
|
2694
|
+
let(:struct) do
|
|
2695
|
+
Class.new(described_class) do
|
|
2696
|
+
default_parameters byte_align: 4
|
|
2697
|
+
endian :little
|
|
2698
|
+
|
|
2699
|
+
ndr_uint8 :a
|
|
2700
|
+
ndr_var_stringz :b
|
|
2701
|
+
ndr_uint32 :c
|
|
2702
|
+
ndr_var_stringz :d
|
|
2703
|
+
ndr_boolean :e
|
|
2704
|
+
end
|
|
2705
|
+
end
|
|
2706
|
+
|
|
2707
|
+
it 'initializes the members to their default value' do
|
|
2708
|
+
expect(struct.new).to eq(a: 0, b: '', c: 0, d: '', e: false)
|
|
2709
|
+
end
|
|
2710
|
+
it 'reads itself' do
|
|
2711
|
+
values = {a: 44, b: 'Test1', c: 4444, d: 'Test22', e: true}
|
|
2712
|
+
struct_instance = struct.new(values)
|
|
2713
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2714
|
+
end
|
|
2715
|
+
context 'with values' do
|
|
2716
|
+
subject do
|
|
2717
|
+
struct.new(a: 1, b: 'Test1', c: 3, d: 'Test22', e: true)
|
|
2718
|
+
end
|
|
2719
|
+
it 'returns the expected member values' do
|
|
2720
|
+
expect(subject).to eq(a: 1, b: 'Test1', c: 3, d: 'Test22', e: true)
|
|
2721
|
+
end
|
|
2722
|
+
it 'outputs the expected binary representation' do
|
|
2723
|
+
binary = "\x01" # a
|
|
2724
|
+
binary << "\x00\x00\x00" # pad
|
|
2725
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2726
|
+
binary << "\x06\x00\x00\x00" # b actual_count
|
|
2727
|
+
binary << "Test1\x00" # b
|
|
2728
|
+
binary << "\x00\x00" # pad
|
|
2729
|
+
binary << "\x03\x00\x00\x00" # c
|
|
2730
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2731
|
+
binary << "\x07\x00\x00\x00" # b actual_count
|
|
2732
|
+
binary << "Test22\x00" # d
|
|
2733
|
+
binary << "\x00" # pad
|
|
2734
|
+
binary << "\x01\x00\x00\x00" # e
|
|
2735
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2736
|
+
end
|
|
2737
|
+
end
|
|
2738
|
+
end
|
|
2739
|
+
|
|
2740
|
+
context 'with varying wide strings' do
|
|
2741
|
+
let(:struct) do
|
|
2742
|
+
Class.new(described_class) do
|
|
2743
|
+
default_parameters byte_align: 4
|
|
2744
|
+
endian :little
|
|
2745
|
+
|
|
2746
|
+
ndr_uint8 :a
|
|
2747
|
+
ndr_var_wide_string :b
|
|
2748
|
+
ndr_uint32 :c
|
|
2749
|
+
ndr_var_wide_string :d
|
|
2750
|
+
ndr_boolean :e
|
|
2751
|
+
end
|
|
2752
|
+
end
|
|
2753
|
+
|
|
2754
|
+
it 'initializes the members to their default value' do
|
|
2755
|
+
expect(struct.new).to eq(a: 0, b: '', c: 0, d: '', e: false)
|
|
2756
|
+
end
|
|
2757
|
+
it 'reads itself' do
|
|
2758
|
+
values = {a: 44, b: 'Test1'.encode('utf-16le'), c: 4444, d: 'Test22'.encode('utf-16le'), e: true}
|
|
2759
|
+
struct_instance = struct.new(values)
|
|
2760
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2761
|
+
end
|
|
2762
|
+
context 'with values' do
|
|
2763
|
+
subject do
|
|
2764
|
+
struct.new(a: 1, b: 'Test1', c: 3, d: 'Test22', e: true)
|
|
2765
|
+
end
|
|
2766
|
+
it 'returns the expected member values' do
|
|
2767
|
+
expect(subject).to eq(a: 1, b: 'Test1'.encode('utf-16le'), c: 3, d: 'Test22'.encode('utf-16le'), e: true)
|
|
2768
|
+
end
|
|
2769
|
+
it 'outputs the expected binary representation' do
|
|
2770
|
+
binary = "\x01" # a
|
|
2771
|
+
binary << "\x00\x00\x00" # pad
|
|
2772
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2773
|
+
binary << "\x05\x00\x00\x00" # b actual_count
|
|
2774
|
+
binary << 'Test1'.encode('utf-16le').b # b
|
|
2775
|
+
binary << "\x00\x00" # pad
|
|
2776
|
+
binary << "\x03\x00\x00\x00" # c
|
|
2777
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2778
|
+
binary << "\x06\x00\x00\x00" # b actual_count
|
|
2779
|
+
binary << 'Test22'.encode('utf-16le').b # d
|
|
2780
|
+
binary << "\x01\x00\x00\x00" # e
|
|
2781
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2782
|
+
end
|
|
2783
|
+
end
|
|
2784
|
+
end
|
|
2785
|
+
|
|
2786
|
+
context 'with varying null terminated wide strings' do
|
|
2787
|
+
let(:struct) do
|
|
2788
|
+
Class.new(described_class) do
|
|
2789
|
+
default_parameters byte_align: 4
|
|
2790
|
+
endian :little
|
|
2791
|
+
|
|
2792
|
+
ndr_uint8 :a
|
|
2793
|
+
ndr_var_wide_stringz :b
|
|
2794
|
+
ndr_uint32 :c
|
|
2795
|
+
ndr_var_wide_stringz :d
|
|
2796
|
+
ndr_boolean :e
|
|
2797
|
+
end
|
|
2798
|
+
end
|
|
2799
|
+
|
|
2800
|
+
it 'initializes the members to their default value' do
|
|
2801
|
+
expect(struct.new).to eq(a: 0, b: '', c: 0, d: '', e: false)
|
|
2802
|
+
end
|
|
2803
|
+
it 'reads itself' do
|
|
2804
|
+
values = {a: 44, b: 'Test1'.encode('utf-16le'), c: 4444, d: 'Test22'.encode('utf-16le'), e: true}
|
|
2805
|
+
struct_instance = struct.new(values)
|
|
2806
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2807
|
+
end
|
|
2808
|
+
context 'with values' do
|
|
2809
|
+
subject do
|
|
2810
|
+
struct.new(a: 1, b: 'Test1', c: 3, d: 'Test22', e: true)
|
|
2811
|
+
end
|
|
2812
|
+
it 'returns the expected member values' do
|
|
2813
|
+
expect(subject).to eq(a: 1, b: 'Test1'.encode('utf-16le'), c: 3, d: 'Test22'.encode('utf-16le'), e: true)
|
|
2814
|
+
end
|
|
2815
|
+
it 'outputs the expected binary representation' do
|
|
2816
|
+
binary = "\x01" # a
|
|
2817
|
+
binary << "\x00\x00\x00" # pad
|
|
2818
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2819
|
+
binary << "\x06\x00\x00\x00" # b actual_count
|
|
2820
|
+
binary << "Test1\x00".encode('utf-16le').b # b
|
|
2821
|
+
binary << "\x03\x00\x00\x00" # c
|
|
2822
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2823
|
+
binary << "\x07\x00\x00\x00" # b actual_count
|
|
2824
|
+
binary << "Test22\x00".encode('utf-16le').b # d
|
|
2825
|
+
binary << "\x00\x00" # pad
|
|
2826
|
+
binary << "\x01\x00\x00\x00" # e
|
|
2827
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2828
|
+
end
|
|
2829
|
+
end
|
|
2830
|
+
end
|
|
2831
|
+
|
|
2832
|
+
context 'with conformant varying strings' do
|
|
2833
|
+
let(:struct) do
|
|
2834
|
+
Class.new(described_class) do
|
|
2835
|
+
default_parameters byte_align: 4
|
|
2836
|
+
endian :little
|
|
2837
|
+
|
|
2838
|
+
ndr_uint8 :a
|
|
2839
|
+
ndr_uint32 :b
|
|
2840
|
+
ndr_boolean :c
|
|
2841
|
+
ndr_conf_var_string :d
|
|
2842
|
+
end
|
|
2843
|
+
end
|
|
2844
|
+
|
|
2845
|
+
it 'initializes the members to their default value' do
|
|
2846
|
+
expect(struct.new).to eq(a: 0, b: 0, c: false, d: '')
|
|
2847
|
+
end
|
|
2848
|
+
it 'reads itself' do
|
|
2849
|
+
values = {a: 44, b: 4444, c: true, d: 'Test22'}
|
|
2850
|
+
struct_instance = struct.new(values)
|
|
2851
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2852
|
+
end
|
|
2853
|
+
context 'with values' do
|
|
2854
|
+
subject do
|
|
2855
|
+
struct.new(a: 1, b: 3, c: true, d: 'Test22')
|
|
2856
|
+
end
|
|
2857
|
+
it 'returns the expected member values' do
|
|
2858
|
+
expect(subject).to eq(a: 1, b: 3, c: true, d: 'Test22')
|
|
2859
|
+
end
|
|
2860
|
+
it 'outputs the expected binary representation' do
|
|
2861
|
+
binary = "\x06\x00\x00\x00" # b max_count
|
|
2862
|
+
binary << "\x01" # a
|
|
2863
|
+
binary << "\x00\x00\x00" # pad
|
|
2864
|
+
binary << "\x03\x00\x00\x00" # b
|
|
2865
|
+
binary << "\x01\x00\x00\x00" # c
|
|
2866
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2867
|
+
binary << "\x06\x00\x00\x00" # b actual_count
|
|
2868
|
+
binary << 'Test22' # d
|
|
2869
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2870
|
+
end
|
|
2871
|
+
end
|
|
2872
|
+
end
|
|
2873
|
+
|
|
2874
|
+
context 'with conformant varying null-terminated strings' do
|
|
2875
|
+
let(:struct) do
|
|
2876
|
+
Class.new(described_class) do
|
|
2877
|
+
default_parameters byte_align: 4
|
|
2878
|
+
endian :little
|
|
2879
|
+
|
|
2880
|
+
ndr_uint8 :a
|
|
2881
|
+
ndr_uint32 :b
|
|
2882
|
+
ndr_boolean :c
|
|
2883
|
+
ndr_conf_var_stringz :d
|
|
2884
|
+
end
|
|
2885
|
+
end
|
|
2886
|
+
|
|
2887
|
+
it 'initializes the members to their default value' do
|
|
2888
|
+
expect(struct.new).to eq(a: 0, b: 0, c: false, d: '')
|
|
2889
|
+
end
|
|
2890
|
+
it 'reads itself' do
|
|
2891
|
+
values = {a: 44, b: 4444, c: true, d: 'Test22'}
|
|
2892
|
+
struct_instance = struct.new(values)
|
|
2893
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2894
|
+
end
|
|
2895
|
+
context 'with values' do
|
|
2896
|
+
subject do
|
|
2897
|
+
struct.new(a: 1, b: 3, c: true, d: 'Test22')
|
|
2898
|
+
end
|
|
2899
|
+
it 'returns the expected member values' do
|
|
2900
|
+
expect(subject).to eq(a: 1, b: 3, c: true, d: 'Test22')
|
|
2901
|
+
end
|
|
2902
|
+
it 'outputs the expected binary representation' do
|
|
2903
|
+
binary = "\x07\x00\x00\x00" # b max_count
|
|
2904
|
+
binary << "\x01" # a
|
|
2905
|
+
binary << "\x00\x00\x00" # pad
|
|
2906
|
+
binary << "\x03\x00\x00\x00" # b
|
|
2907
|
+
binary << "\x01\x00\x00\x00" # c
|
|
2908
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2909
|
+
binary << "\x07\x00\x00\x00" # b actual_count
|
|
2910
|
+
binary << "Test22\x00" # d
|
|
2911
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2912
|
+
end
|
|
2913
|
+
end
|
|
2914
|
+
end
|
|
2915
|
+
|
|
2916
|
+
context 'with conformant varying wide strings' do
|
|
2917
|
+
let(:struct) do
|
|
2918
|
+
Class.new(described_class) do
|
|
2919
|
+
default_parameters byte_align: 4
|
|
2920
|
+
endian :little
|
|
2921
|
+
|
|
2922
|
+
ndr_uint8 :a
|
|
2923
|
+
ndr_uint32 :b
|
|
2924
|
+
ndr_boolean :c
|
|
2925
|
+
ndr_conf_var_wide_string :d
|
|
2926
|
+
end
|
|
2927
|
+
end
|
|
2928
|
+
|
|
2929
|
+
it 'initializes the members to their default value' do
|
|
2930
|
+
expect(struct.new).to eq(a: 0, b: 0, c: false, d: '')
|
|
2931
|
+
end
|
|
2932
|
+
it 'reads itself' do
|
|
2933
|
+
values = {a: 44, b: 4444, c: true, d: 'Test22'.encode('utf-16le')}
|
|
2934
|
+
struct_instance = struct.new(values)
|
|
2935
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2936
|
+
end
|
|
2937
|
+
context 'with values' do
|
|
2938
|
+
subject do
|
|
2939
|
+
struct.new(a: 1, b: 3, c: true, d: 'Test22')
|
|
2940
|
+
end
|
|
2941
|
+
it 'returns the expected member values' do
|
|
2942
|
+
expect(subject).to eq(a: 1, b: 3, c: true, d: 'Test22'.encode('utf-16le'))
|
|
2943
|
+
end
|
|
2944
|
+
it 'outputs the expected binary representation' do
|
|
2945
|
+
binary = "\x06\x00\x00\x00" # b max_count
|
|
2946
|
+
binary << "\x01" # a
|
|
2947
|
+
binary << "\x00\x00\x00" # pad
|
|
2948
|
+
binary << "\x03\x00\x00\x00" # b
|
|
2949
|
+
binary << "\x01\x00\x00\x00" # c
|
|
2950
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2951
|
+
binary << "\x06\x00\x00\x00" # b actual_count
|
|
2952
|
+
binary << 'Test22'.encode('utf-16le').b # d
|
|
2953
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2954
|
+
end
|
|
2955
|
+
end
|
|
2956
|
+
end
|
|
2957
|
+
|
|
2958
|
+
context 'with conformant varying null-terminated wide strings' do
|
|
2959
|
+
let(:struct) do
|
|
2960
|
+
Class.new(described_class) do
|
|
2961
|
+
default_parameters byte_align: 4
|
|
2962
|
+
endian :little
|
|
2963
|
+
|
|
2964
|
+
ndr_uint8 :a
|
|
2965
|
+
ndr_uint32 :b
|
|
2966
|
+
ndr_boolean :c
|
|
2967
|
+
ndr_conf_var_wide_stringz :d
|
|
2968
|
+
end
|
|
2969
|
+
end
|
|
2970
|
+
|
|
2971
|
+
it 'initializes the members to their default value' do
|
|
2972
|
+
expect(struct.new).to eq(a: 0, b: 0, c: false, d: '')
|
|
2973
|
+
end
|
|
2974
|
+
it 'reads itself' do
|
|
2975
|
+
values = {a: 44, b: 4444, c: true, d: 'Test22'.encode('utf-16le')}
|
|
2976
|
+
struct_instance = struct.new(values)
|
|
2977
|
+
expect(struct.read(struct_instance.to_binary_s)).to eq(values)
|
|
2978
|
+
end
|
|
2979
|
+
context 'with values' do
|
|
2980
|
+
subject do
|
|
2981
|
+
struct.new(a: 1, b: 3, c: true, d: 'Test22')
|
|
2982
|
+
end
|
|
2983
|
+
it 'returns the expected member values' do
|
|
2984
|
+
expect(subject).to eq(a: 1, b: 3, c: true, d: 'Test22'.encode('utf-16le'))
|
|
2985
|
+
end
|
|
2986
|
+
it 'outputs the expected binary representation' do
|
|
2987
|
+
binary = "\x07\x00\x00\x00" # b max_count
|
|
2988
|
+
binary << "\x01" # a
|
|
2989
|
+
binary << "\x00\x00\x00" # pad
|
|
2990
|
+
binary << "\x03\x00\x00\x00" # b
|
|
2991
|
+
binary << "\x01\x00\x00\x00" # c
|
|
2992
|
+
binary << "\x00\x00\x00\x00" # b offset
|
|
2993
|
+
binary << "\x07\x00\x00\x00" # b actual_count
|
|
2994
|
+
binary << "Test22\x00".encode('utf-16le').b # d
|
|
2995
|
+
expect(subject.to_binary_s).to eq(binary.b)
|
|
2996
|
+
end
|
|
2997
|
+
end
|
|
2998
|
+
end
|
|
2999
|
+
end
|
|
3000
|
+
|
|
3001
|
+
|
|
3002
|
+
#
|
|
3003
|
+
# Pointers
|
|
3004
|
+
#
|
|
3005
|
+
{
|
|
3006
|
+
NdrUint8Ptr: { parent_class: :NdrUint8, data: 2, binary: "\x02", size: 1 },
|
|
3007
|
+
NdrUint16Ptr: { parent_class: :NdrUint16, data: 3, binary: [3].pack('S'), size: 2 },
|
|
3008
|
+
NdrUint32Ptr: { parent_class: :NdrUint32, data: 5, binary: [5].pack('L'), size: 4 },
|
|
3009
|
+
NdrUint64Ptr: { parent_class: :NdrUint64, data: 7, binary: [7].pack('Q'), size: 8 },
|
|
3010
|
+
NdrCharPtr: { parent_class: :NdrChar, data: 'C', binary: 'C', size: 1 },
|
|
3011
|
+
NdrBooleanPtr: { parent_class: :NdrBoolean, data: true, binary: [1].pack('L'), size: 4 },
|
|
3012
|
+
NdrStringPtr: {
|
|
3013
|
+
parent_class: :NdrConfVarString,
|
|
3014
|
+
data: 'Test1',
|
|
3015
|
+
binary: "#{[5].pack('L')}#{[0].pack('L')}#{[5].pack('L')}Test1", size: 4
|
|
3016
|
+
},
|
|
3017
|
+
NdrStringzPtr: {
|
|
3018
|
+
parent_class: :NdrConfVarStringz,
|
|
3019
|
+
data: 'Test2',
|
|
3020
|
+
binary: "#{[6].pack('L')}#{[0].pack('L')}#{[6].pack('L')}Test2\x00", size: 4
|
|
3021
|
+
},
|
|
3022
|
+
NdrWideStringPtr: {
|
|
3023
|
+
parent_class: :NdrConfVarWideString,
|
|
3024
|
+
data: 'Test3'.encode('utf-16le'),
|
|
3025
|
+
binary: "#{[5].pack('L')}#{[0].pack('L')}#{[5].pack('L')}#{'Test3'.encode('utf-16le').b}", size: 4
|
|
3026
|
+
},
|
|
3027
|
+
NdrWideStringzPtr: {
|
|
3028
|
+
parent_class: :NdrConfVarWideStringz,
|
|
3029
|
+
data: 'Test4'.encode('utf-16le'),
|
|
3030
|
+
binary: "#{[6].pack('L')}#{[0].pack('L')}#{[6].pack('L')}#{'Test4'.encode('utf-16le').b}\x00\x00", size: 4
|
|
3031
|
+
},
|
|
3032
|
+
NdrByteArrayPtr: {
|
|
3033
|
+
parent_class: :NdrConfVarArray,
|
|
3034
|
+
data: [1,2,3,4],
|
|
3035
|
+
binary: "#{[4].pack('L')}#{[0].pack('L')}#{[4].pack('L')}\x01\x02\x03\x04", size: 4
|
|
3036
|
+
},
|
|
3037
|
+
NdrFileTimePtr: {
|
|
3038
|
+
parent_class: :NdrFileTime,
|
|
3039
|
+
data: 132682503830000000,
|
|
3040
|
+
binary: [132682503830000000].pack('Q'), size: 4
|
|
3041
|
+
}
|
|
3042
|
+
}.each do |ndr_class, info|
|
|
3043
|
+
RSpec.describe(RubySMB::Dcerpc::Ndr.const_get(ndr_class)) do
|
|
3044
|
+
subject { described_class.new }
|
|
3045
|
+
let(:class_with_ref_to) do
|
|
3046
|
+
struct = Class.new(BinData::Record) do
|
|
3047
|
+
endian :little
|
|
3048
|
+
ndr_uint32 :a
|
|
3049
|
+
end
|
|
3050
|
+
struct.send(described_class.bindata_name.to_sym, :b)
|
|
3051
|
+
struct.send(described_class.bindata_name.to_sym, :c, ref_to: :b)
|
|
3052
|
+
struct
|
|
3053
|
+
end
|
|
3054
|
+
let(:ref_to_instance) { class_with_ref_to.new(a: 1, b: info[:data]) }
|
|
3055
|
+
let(:ref_id) { [RubySMB::Dcerpc::Ndr::INITIAL_REF_ID].pack('L') }
|
|
400
3056
|
|
|
401
|
-
it '
|
|
402
|
-
expect(
|
|
3057
|
+
it 'is a RubySMB::Dcerpc::Ndr::PointerClassPlugin class' do
|
|
3058
|
+
expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
|
|
3059
|
+
end
|
|
3060
|
+
it 'is not a Top Level class' do
|
|
3061
|
+
expect(described_class).not_to be_a(RubySMB::Dcerpc::Ndr::TopLevelPlugin)
|
|
3062
|
+
end
|
|
3063
|
+
it "is a RubySMB::Dcerpc::Ndr::#{info[:parent_class]} class" do
|
|
3064
|
+
parent_class = if info[:parent_class].is_a?(Symbol)
|
|
3065
|
+
RubySMB::Dcerpc::Ndr.const_get(info[:parent_class])
|
|
3066
|
+
else
|
|
3067
|
+
info[:parent_class]
|
|
3068
|
+
end
|
|
3069
|
+
expect(described_class).to be < parent_class
|
|
3070
|
+
end
|
|
3071
|
+
|
|
3072
|
+
it { is_expected.to respond_to :ref_id }
|
|
3073
|
+
|
|
3074
|
+
describe '#initialize_instance' do
|
|
3075
|
+
it 'sets #ref_id to 0 by default' do
|
|
3076
|
+
expect(subject.ref_id).to eq(0)
|
|
3077
|
+
end
|
|
3078
|
+
it 'does not reset #ref_id to 0 when it has already been set to a value' do
|
|
3079
|
+
subject.ref_id = 5
|
|
3080
|
+
subject.initialize_instance
|
|
3081
|
+
expect(subject.ref_id).to eq(5)
|
|
3082
|
+
end
|
|
3083
|
+
it 'sets #ref_id to INITIAL_REF_ID by default when :initial_value parameter is provided' do
|
|
3084
|
+
test_instance = described_class.new(nil, {initial_value: info[:data]})
|
|
3085
|
+
expect(test_instance.ref_id).to eq(RubySMB::Dcerpc::Ndr::INITIAL_REF_ID)
|
|
3086
|
+
end
|
|
3087
|
+
end
|
|
3088
|
+
|
|
3089
|
+
describe '#extend_top_level_class' do
|
|
3090
|
+
it 'extends to TopLevelPlugin' do
|
|
3091
|
+
expect(subject).to be_a(RubySMB::Dcerpc::Ndr::TopLevelPlugin)
|
|
3092
|
+
end
|
|
3093
|
+
it 'sets the pointer to top level pointer' do
|
|
3094
|
+
expect(subject.is_top_level_ptr).to be true
|
|
3095
|
+
end
|
|
3096
|
+
context 'when embedded in another structure' do
|
|
3097
|
+
let(:struct_class) do
|
|
3098
|
+
struct_class = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
3099
|
+
default_parameters byte_align: 4
|
|
3100
|
+
endian :little
|
|
3101
|
+
end
|
|
3102
|
+
struct_class.send(described_class.bindata_name.to_sym, :c)
|
|
3103
|
+
struct_class
|
|
3104
|
+
end
|
|
3105
|
+
let(:top_level_class) do
|
|
3106
|
+
Class.new(BinData::Record) do
|
|
3107
|
+
endian :little
|
|
3108
|
+
ndr_uint32 :a
|
|
3109
|
+
test_struct :b
|
|
3110
|
+
end
|
|
3111
|
+
end
|
|
3112
|
+
before :example do
|
|
3113
|
+
BinData::RegisteredClasses.register('test_struct', struct_class)
|
|
3114
|
+
end
|
|
3115
|
+
|
|
3116
|
+
it 'extends the parents to TopLevelPlugin' do
|
|
3117
|
+
struct = top_level_class.new(a: 2, b: {c: info[:data]})
|
|
3118
|
+
expect(struct).to be_a(RubySMB::Dcerpc::Ndr::TopLevelPlugin)
|
|
3119
|
+
expect(struct.b).to be_a(RubySMB::Dcerpc::Ndr::TopLevelPlugin)
|
|
3120
|
+
end
|
|
3121
|
+
it 'only sets the top level structure as a top level pointer' do
|
|
3122
|
+
struct = top_level_class.new(a: 2, b: {c: info[:data]})
|
|
3123
|
+
expect(struct.is_top_level_ptr).to be true
|
|
3124
|
+
expect(struct.b.is_top_level_ptr).to be false
|
|
3125
|
+
expect(struct.b.c.is_top_level_ptr).to be false
|
|
3126
|
+
end
|
|
3127
|
+
end
|
|
3128
|
+
end
|
|
3129
|
+
|
|
3130
|
+
describe '#snapshot' do
|
|
3131
|
+
it 'outputs :null by default' do
|
|
3132
|
+
expect(subject.snapshot).to eq(:null)
|
|
3133
|
+
end
|
|
3134
|
+
it 'outputs the referent when it refers to another Top-Level pointer' do
|
|
3135
|
+
expect(ref_to_instance.snapshot).to eq({a:1, b:info[:data], c:info[:data]})
|
|
3136
|
+
end
|
|
3137
|
+
# BinData does not support initial_value parameter for arrays
|
|
3138
|
+
unless ndr_class == :NdrByteArrayPtr
|
|
3139
|
+
it 'outputs the :initial_value parameter value when nothing has been assigned yet' do
|
|
3140
|
+
test_ptr = described_class.new(nil, {initial_value: info[:data]})
|
|
3141
|
+
expect(test_ptr.snapshot).to eq(info[:data])
|
|
3142
|
+
end
|
|
3143
|
+
end
|
|
3144
|
+
end
|
|
3145
|
+
|
|
3146
|
+
describe '#do_write' do
|
|
3147
|
+
it 'outputs 32-bit zero binary representation when it is a null pointer' do
|
|
3148
|
+
expect(subject.to_binary_s).to eq("\x00\x00\x00\x00".b)
|
|
3149
|
+
end
|
|
3150
|
+
it 'outputs the initial referent ID followed by the representation of the referent' do
|
|
3151
|
+
expect(subject.new(info[:data]).to_binary_s).to eq("#{ref_id}#{info[:binary]}".b)
|
|
3152
|
+
end
|
|
3153
|
+
it 'outputs the referent ID of the Top-Level pointer it is refering to' do
|
|
3154
|
+
align = (4 - (info[:binary].size % 4)) % 4
|
|
3155
|
+
pad = "\x00" * align
|
|
3156
|
+
expect(ref_to_instance.to_binary_s).to eq(
|
|
3157
|
+
"#{[1].pack('L')}#{ref_id}#{info[:binary]}#{pad}#{ref_id}"
|
|
3158
|
+
)
|
|
3159
|
+
expect(ref_to_instance.c.to_binary_s).to eq(ref_id)
|
|
3160
|
+
end
|
|
3161
|
+
it 'outputs the initial referent ID and the referent representaiton if it is not embedded in another constructed structure' do
|
|
3162
|
+
expect(subject.new(info[:data]).to_binary_s).to eq("#{ref_id}#{info[:binary]}".b)
|
|
3163
|
+
end
|
|
3164
|
+
# BinData does not support initial_value parameter for arrays
|
|
3165
|
+
unless ndr_class == :NdrByteArrayPtr
|
|
3166
|
+
it 'outputs the :initial_value parameter value when nothing has been assigned yet' do
|
|
3167
|
+
test_ptr = described_class.new(nil, {initial_value: info[:data]})
|
|
3168
|
+
expect(test_ptr.new.to_binary_s).to eq("#{ref_id}#{info[:binary]}".b)
|
|
3169
|
+
end
|
|
3170
|
+
end
|
|
3171
|
+
context 'when embedded in another constructed structure'do
|
|
3172
|
+
let(:embedding_struct) do
|
|
3173
|
+
RubySMB::Dcerpc::Ndr::NdrConfArray.new([info[:data], info[:data]], type: described_class)
|
|
3174
|
+
end
|
|
3175
|
+
let(:output_str) do
|
|
3176
|
+
ref_id2 = [RubySMB::Dcerpc::Ndr::INITIAL_REF_ID + 1].pack('L')
|
|
3177
|
+
output_str = "#{[2].pack('L')}#{ref_id}#{ref_id2}".b
|
|
3178
|
+
align = (info[:size] - (output_str.size % info[:size])) % info[:size]
|
|
3179
|
+
output_str << "\x00".b * align
|
|
3180
|
+
output_str << info[:binary]
|
|
3181
|
+
align = (info[:size] - (output_str.size % info[:size])) % info[:size]
|
|
3182
|
+
output_str << "\x00".b * align
|
|
3183
|
+
output_str << info[:binary]
|
|
3184
|
+
end
|
|
3185
|
+
|
|
3186
|
+
it 'does not change the embedded structure binary representation' do
|
|
3187
|
+
expect(embedding_struct[0].to_binary_s).to eq("#{ref_id}#{info[:binary]}".b)
|
|
3188
|
+
expect(embedding_struct[1].to_binary_s).to eq("#{ref_id}#{info[:binary]}".b)
|
|
3189
|
+
end
|
|
3190
|
+
it 'returns the correct aligned binary stream' do
|
|
3191
|
+
expect(embedding_struct.to_binary_s).to eq(output_str)
|
|
3192
|
+
end
|
|
3193
|
+
context 'when calling #to_binary_s on embedded structures' do
|
|
3194
|
+
# There was a bug where calling to_binary_s updated the ref_id
|
|
3195
|
+
# persistently, which resulted in wrong output
|
|
3196
|
+
it 'returns the correct aligned binary stream' do
|
|
3197
|
+
embedding_struct[0].to_binary_s
|
|
3198
|
+
embedding_struct[1].to_binary_s
|
|
3199
|
+
expect(embedding_struct.to_binary_s).to eq(output_str)
|
|
3200
|
+
end
|
|
3201
|
+
end
|
|
3202
|
+
end
|
|
3203
|
+
end
|
|
3204
|
+
|
|
3205
|
+
describe '#do_read' do
|
|
3206
|
+
it 'reads a 32-bit zero binary representation as a null pointer' do
|
|
3207
|
+
expect(subject.read("\x00\x00\x00\x00".b)).to eq(:null)
|
|
3208
|
+
end
|
|
3209
|
+
it 'reads the referent ID followed by the representation of the referent' do
|
|
3210
|
+
expect(subject.read("#{ref_id}#{info[:binary]}")).to eq(info[:data])
|
|
3211
|
+
expect(subject.ref_id).to eq(RubySMB::Dcerpc::Ndr::INITIAL_REF_ID)
|
|
3212
|
+
end
|
|
3213
|
+
it 'reads the referent ID of the Top-Level pointer it is refering to' do
|
|
3214
|
+
align = (4 - (info[:binary].size % 4)) % 4
|
|
3215
|
+
pad = "\x00" * align
|
|
3216
|
+
binary_str = "#{[1].pack('L')}"\
|
|
3217
|
+
"#{ref_id}"\
|
|
3218
|
+
"#{info[:binary]}"\
|
|
3219
|
+
"#{pad}"\
|
|
3220
|
+
"#{ref_id}"
|
|
3221
|
+
test_instance = class_with_ref_to.read(binary_str)
|
|
3222
|
+
expect(test_instance.c.snapshot).to eq(info[:data])
|
|
3223
|
+
expect(test_instance.c.ref_id).to eq(test_instance.b.ref_id)
|
|
3224
|
+
end
|
|
3225
|
+
it 'reads the initial referent ID and the referent representaiton if it is not embedded in another constructed structure' do
|
|
3226
|
+
expect(subject.read("#{ref_id}#{info[:binary]}".b)).to eq(info[:data])
|
|
3227
|
+
expect(subject.ref_id).to eq(RubySMB::Dcerpc::Ndr::INITIAL_REF_ID)
|
|
3228
|
+
end
|
|
3229
|
+
context 'when embedded in another constructed structure'do
|
|
3230
|
+
let(:test_struct) { described_class.new(info[:data].dup) }
|
|
3231
|
+
let(:embedding_struct) do
|
|
3232
|
+
subject.assign(info[:data])
|
|
3233
|
+
RubySMB::Dcerpc::Ndr::NdrConfArray.new([subject, test_struct], type: described_class)
|
|
3234
|
+
end
|
|
3235
|
+
let(:binary_str) do
|
|
3236
|
+
ref_id2 = [RubySMB::Dcerpc::Ndr::INITIAL_REF_ID + 1].pack('L')
|
|
3237
|
+
binary_str = "#{[2].pack('L')}#{ref_id}#{ref_id2}".b
|
|
3238
|
+
align = (info[:size] - (binary_str.size % info[:size])) % info[:size]
|
|
3239
|
+
binary_str << "\x00".b * align
|
|
3240
|
+
binary_str << info[:binary]
|
|
3241
|
+
align = (info[:size] - (binary_str.size % info[:size])) % info[:size]
|
|
3242
|
+
binary_str << "\x00".b * align
|
|
3243
|
+
binary_str << info[:binary]
|
|
3244
|
+
binary_str
|
|
3245
|
+
end
|
|
3246
|
+
it 'correctly defers the referent after the embedding structure in the stream' do
|
|
3247
|
+
obj = embedding_struct.read(binary_str)
|
|
3248
|
+
expect(obj).to eq([subject, test_struct])
|
|
3249
|
+
end
|
|
3250
|
+
end
|
|
3251
|
+
end
|
|
3252
|
+
|
|
3253
|
+
describe '#assign' do
|
|
3254
|
+
it 'sets #ref_id to 0 when assigning :null' do
|
|
3255
|
+
subject.assign(:null)
|
|
3256
|
+
expect(subject.ref_id).to eq(0)
|
|
3257
|
+
end
|
|
3258
|
+
it 'assigns the value to the referent when it refers to another Top-Level pointer' do
|
|
3259
|
+
ref_to_instance.c = info[:data]
|
|
3260
|
+
expect(ref_to_instance.b).to eq(info[:data])
|
|
3261
|
+
end
|
|
3262
|
+
it 'sets #ref_id to the initial reference ID value' do
|
|
3263
|
+
subject.assign(info[:data])
|
|
3264
|
+
expect(subject.ref_id).to eq(RubySMB::Dcerpc::Ndr::INITIAL_REF_ID)
|
|
3265
|
+
end
|
|
3266
|
+
it 'does not change #ref_id when it has already been set' do
|
|
3267
|
+
subject.ref_id = 20
|
|
3268
|
+
subject.assign(info[:data])
|
|
3269
|
+
expect(subject.ref_id).to eq(20)
|
|
3270
|
+
end
|
|
3271
|
+
end
|
|
3272
|
+
|
|
3273
|
+
describe '#alias?' do
|
|
3274
|
+
it 'returns true if it refers to another Top-Level pointer' do
|
|
3275
|
+
expect(ref_to_instance.c.is_alias?).to be true
|
|
3276
|
+
end
|
|
3277
|
+
end
|
|
3278
|
+
|
|
3279
|
+
describe '#fetch_alias_referent' do
|
|
3280
|
+
it 'returns the referent' do
|
|
3281
|
+
expect(ref_to_instance.c.fetch_alias_referent).to eq(info[:data])
|
|
3282
|
+
end
|
|
3283
|
+
context 'when the referent is in a NDR structure' do
|
|
3284
|
+
let(:class_with_ref_to) do
|
|
3285
|
+
test_struct_class = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
3286
|
+
default_parameters(byte_align: 4)
|
|
3287
|
+
ndr_uint32 :a
|
|
3288
|
+
end
|
|
3289
|
+
test_struct_class.send(described_class.bindata_name.to_sym, :ptr1)
|
|
3290
|
+
BinData::RegisteredClasses.register('test_struct', test_struct_class)
|
|
3291
|
+
struct = Class.new(BinData::Record) do
|
|
3292
|
+
test_struct :struct1
|
|
3293
|
+
end
|
|
3294
|
+
struct.send(described_class.bindata_name.to_sym, :ptr2, ref_to: :ptr1)
|
|
3295
|
+
struct
|
|
3296
|
+
end
|
|
3297
|
+
let(:ref_to_instance) { class_with_ref_to.new(struct1: { a: 2, ptr1: info[:data] }) }
|
|
3298
|
+
it 'returns the referent' do
|
|
3299
|
+
expect(ref_to_instance.ptr2.fetch_alias_referent).to eq(info[:data])
|
|
3300
|
+
end
|
|
3301
|
+
end
|
|
3302
|
+
end
|
|
3303
|
+
|
|
3304
|
+
describe '#do_num_bytes' do
|
|
3305
|
+
it 'returns 4 if it is a null pointer' do
|
|
3306
|
+
expect(subject.do_num_bytes).to eq(4)
|
|
3307
|
+
end
|
|
3308
|
+
it 'returns 4 if it refers to another Top-Level pointer' do
|
|
3309
|
+
expect(ref_to_instance.c.do_num_bytes).to eq(4)
|
|
3310
|
+
end
|
|
3311
|
+
it "returns #{4 + info[:binary].size} a first-instance pointer" do
|
|
3312
|
+
subject.assign(info[:data])
|
|
3313
|
+
expect(subject.do_num_bytes).to eq(4 + info[:binary].size)
|
|
3314
|
+
end
|
|
3315
|
+
end
|
|
3316
|
+
end
|
|
3317
|
+
end
|
|
3318
|
+
|
|
3319
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::TopLevelPlugin do
|
|
3320
|
+
let(:ref_id) { RubySMB::Dcerpc::Ndr::INITIAL_REF_ID }
|
|
3321
|
+
let(:struct_with_ptr) do
|
|
3322
|
+
Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
3323
|
+
default_parameters byte_align: 4
|
|
3324
|
+
endian :little
|
|
3325
|
+
|
|
3326
|
+
ndr_uint32 :b
|
|
3327
|
+
ndr_char_ptr :ptr2
|
|
3328
|
+
ndr_uint32_ptr :ptr3
|
|
3329
|
+
end
|
|
3330
|
+
end
|
|
3331
|
+
let(:random_struct) do
|
|
3332
|
+
Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
3333
|
+
default_parameters byte_align: 4
|
|
3334
|
+
endian :little
|
|
3335
|
+
|
|
3336
|
+
ndr_uint32 :rand1
|
|
3337
|
+
ndr_uint32 :rand2
|
|
3338
|
+
end
|
|
3339
|
+
end
|
|
3340
|
+
|
|
3341
|
+
before :example do
|
|
3342
|
+
BinData::RegisteredClasses.register('struct_with_ptr', struct_with_ptr)
|
|
3343
|
+
BinData::RegisteredClasses.register('random_struct', random_struct)
|
|
3344
|
+
end
|
|
3345
|
+
|
|
3346
|
+
context 'with a BinData structure' do
|
|
3347
|
+
let(:test_struct) do
|
|
3348
|
+
Class.new(BinData::Record) do
|
|
3349
|
+
endian :little
|
|
3350
|
+
|
|
3351
|
+
ndr_uint32 :a
|
|
3352
|
+
ndr_char_ptr :ptr1
|
|
3353
|
+
struct_with_ptr :d
|
|
3354
|
+
ndr_uint32_ptr :ptr4
|
|
3355
|
+
end
|
|
3356
|
+
end
|
|
3357
|
+
let(:snapshot) { { a: 55, ptr1: 'M', d: { b: 66, ptr2: 'A', ptr3: 33 }, ptr4: 44 } }
|
|
3358
|
+
let(:binary) do
|
|
3359
|
+
"#{[55].pack('L')}"\
|
|
3360
|
+
"#{[ref_id].pack('L')}"\
|
|
3361
|
+
"M"\
|
|
3362
|
+
"\x00\x00\x00"\
|
|
3363
|
+
"#{[66].pack('L')}"\
|
|
3364
|
+
"#{[ref_id + 1].pack('L')}"\
|
|
3365
|
+
"#{[ref_id + 2].pack('L')}"\
|
|
3366
|
+
"A"\
|
|
3367
|
+
"\x00\x00\x00"\
|
|
3368
|
+
"#{[33].pack('L')}"\
|
|
3369
|
+
"#{[ref_id + 3].pack('L')}"\
|
|
3370
|
+
"#{[44].pack('L')}".b
|
|
3371
|
+
end
|
|
3372
|
+
subject { test_struct.new(snapshot) }
|
|
3373
|
+
|
|
3374
|
+
it 'outputs the correct binary stream' do
|
|
3375
|
+
expect(subject.to_binary_s).to eq(binary)
|
|
3376
|
+
end
|
|
3377
|
+
end
|
|
3378
|
+
|
|
3379
|
+
context 'with a BinData structure containing pointers with :initial_value set' do
|
|
3380
|
+
let(:test_struct) do
|
|
3381
|
+
Class.new(BinData::Record) do
|
|
3382
|
+
endian :little
|
|
3383
|
+
|
|
3384
|
+
ndr_uint32 :a
|
|
3385
|
+
ndr_char_ptr :ptr1, initial_value: 'M'
|
|
3386
|
+
struct_with_ptr :d
|
|
3387
|
+
ndr_uint32_ptr :ptr4, initial_value: 44
|
|
3388
|
+
end
|
|
3389
|
+
end
|
|
3390
|
+
let(:snapshot) { { a: 55, d: { b: 66, ptr2: 'A', ptr3: 33 } } }
|
|
3391
|
+
let(:binary) do
|
|
3392
|
+
"#{[55].pack('L')}"\
|
|
3393
|
+
"#{[ref_id].pack('L')}"\
|
|
3394
|
+
"M"\
|
|
3395
|
+
"\x00\x00\x00"\
|
|
3396
|
+
"#{[66].pack('L')}"\
|
|
3397
|
+
"#{[ref_id + 1].pack('L')}"\
|
|
3398
|
+
"#{[ref_id + 2].pack('L')}"\
|
|
3399
|
+
"A"\
|
|
3400
|
+
"\x00\x00\x00"\
|
|
3401
|
+
"#{[33].pack('L')}"\
|
|
3402
|
+
"#{[ref_id + 3].pack('L')}"\
|
|
3403
|
+
"#{[44].pack('L')}".b
|
|
3404
|
+
end
|
|
3405
|
+
subject { test_struct.new(snapshot) }
|
|
3406
|
+
|
|
3407
|
+
it 'outputs the correct binary stream' do
|
|
3408
|
+
expect(subject.to_binary_s).to eq(binary)
|
|
3409
|
+
end
|
|
3410
|
+
end
|
|
3411
|
+
|
|
3412
|
+
context 'with a BinData::Choice' do
|
|
3413
|
+
let(:test_struct) do
|
|
3414
|
+
Class.new(BinData::Record) do
|
|
3415
|
+
endian :little
|
|
3416
|
+
|
|
3417
|
+
ndr_uint32 :a
|
|
3418
|
+
ndr_char_ptr :ptr1
|
|
3419
|
+
choice :choice1, selection: :a, byte_align: 4 do
|
|
3420
|
+
struct_with_ptr 55
|
|
3421
|
+
end
|
|
3422
|
+
ndr_uint32_ptr :ptr4
|
|
3423
|
+
end
|
|
3424
|
+
end
|
|
3425
|
+
let(:snapshot) { { a: 55, ptr1: 'M', choice1: { b: 66, ptr2: 'A', ptr3: 33 }, ptr4: 44 } }
|
|
3426
|
+
let(:binary) do
|
|
3427
|
+
"#{[55].pack('L')}"\
|
|
3428
|
+
"#{[ref_id].pack('L')}"\
|
|
3429
|
+
"M"\
|
|
3430
|
+
"\x00\x00\x00"\
|
|
3431
|
+
"#{[66].pack('L')}"\
|
|
3432
|
+
"#{[ref_id + 1].pack('L')}"\
|
|
3433
|
+
"#{[ref_id + 2].pack('L')}"\
|
|
3434
|
+
"A"\
|
|
3435
|
+
"\x00\x00\x00"\
|
|
3436
|
+
"#{[33].pack('L')}"\
|
|
3437
|
+
"#{[ref_id + 3].pack('L')}"\
|
|
3438
|
+
"#{[44].pack('L')}".b
|
|
3439
|
+
end
|
|
3440
|
+
subject { test_struct.new(snapshot) }
|
|
3441
|
+
|
|
3442
|
+
it 'outputs the correct binary stream' do
|
|
3443
|
+
expect(subject.to_binary_s).to eq(binary)
|
|
3444
|
+
end
|
|
3445
|
+
end
|
|
3446
|
+
|
|
3447
|
+
context 'with a NDR array and an alias pointer' do
|
|
3448
|
+
let(:test_struct) do
|
|
3449
|
+
Class.new(BinData::Record) do
|
|
3450
|
+
endian :little
|
|
3451
|
+
|
|
3452
|
+
ndr_uint32 :a
|
|
3453
|
+
ndr_char_ptr :ptr1
|
|
3454
|
+
ndr_conf_array :array1, type: :random_struct
|
|
3455
|
+
struct_with_ptr :d
|
|
3456
|
+
ndr_uint32_ptr :ptr4, ref_to: :ptr3
|
|
3457
|
+
end
|
|
3458
|
+
end
|
|
3459
|
+
let(:snapshot) do
|
|
3460
|
+
{
|
|
3461
|
+
a: 0xF1,
|
|
3462
|
+
ptr1: 'A',
|
|
3463
|
+
array1: [
|
|
3464
|
+
{ rand1: 0xF2, rand2: 0xF3 },
|
|
3465
|
+
{ rand1: 0xF4, rand2: 0xF5 }
|
|
3466
|
+
],
|
|
3467
|
+
d: { b: 0xF6, ptr2: 'B', ptr3: 0xF7 }
|
|
3468
|
+
}
|
|
3469
|
+
end
|
|
3470
|
+
let(:binary) do
|
|
3471
|
+
"#{[0xF1].pack('L<')}"\
|
|
3472
|
+
"#{[ref_id].pack('L<')}"\
|
|
3473
|
+
"A"\
|
|
3474
|
+
"\x00\x00\x00"\
|
|
3475
|
+
"#{[2].pack('L<')}"\
|
|
3476
|
+
"#{[0xF2].pack('L<')}"\
|
|
3477
|
+
"#{[0xF3].pack('L<')}"\
|
|
3478
|
+
"#{[0xF4].pack('L<')}"\
|
|
3479
|
+
"#{[0xF5].pack('L<')}"\
|
|
3480
|
+
"#{[0xF6].pack('L<')}"\
|
|
3481
|
+
"#{[ref_id + 1].pack('L<')}"\
|
|
3482
|
+
"#{[ref_id + 2].pack('L<')}"\
|
|
3483
|
+
"B"\
|
|
3484
|
+
"\x00\x00\x00"\
|
|
3485
|
+
"#{[0xF7].pack('L<')}"\
|
|
3486
|
+
"#{[ref_id + 2].pack('L<')}"
|
|
3487
|
+
end
|
|
3488
|
+
subject { test_struct.new(snapshot) }
|
|
3489
|
+
|
|
3490
|
+
it 'outputs the correct binary stream' do
|
|
3491
|
+
expect(subject.to_binary_s).to eq(binary)
|
|
3492
|
+
end
|
|
3493
|
+
|
|
3494
|
+
context 'when the alias pointer is positioned after the referent pointer' do
|
|
3495
|
+
let(:test_struct2) do
|
|
3496
|
+
Class.new(BinData::Record) do
|
|
3497
|
+
endian :little
|
|
3498
|
+
|
|
3499
|
+
ndr_uint32 :a
|
|
3500
|
+
ndr_char_ptr :ptr1
|
|
3501
|
+
ndr_conf_array :array1, type: :random_struct
|
|
3502
|
+
# :ptr3 is part of :d structure, which appears after :ptr4
|
|
3503
|
+
ndr_uint32_ptr :ptr4, ref_to: :ptr3
|
|
3504
|
+
struct_with_ptr :d
|
|
3505
|
+
end
|
|
3506
|
+
end
|
|
3507
|
+
|
|
3508
|
+
context 'with #snapshot' do
|
|
3509
|
+
it 'raises an exception' do
|
|
3510
|
+
expect { test_struct2.new(snapshot).snapshot }.to raise_error(ArgumentError)
|
|
3511
|
+
end
|
|
3512
|
+
end
|
|
3513
|
+
|
|
3514
|
+
context 'with #to_binary_s' do
|
|
3515
|
+
it 'raises an exception' do
|
|
3516
|
+
expect { test_struct2.new(snapshot).to_binary_s }.to raise_error(ArgumentError)
|
|
3517
|
+
end
|
|
3518
|
+
end
|
|
3519
|
+
end
|
|
3520
|
+
|
|
3521
|
+
context 'when the alias pointer refers to a non-existing pointer' do
|
|
3522
|
+
let(:test_struct2) do
|
|
3523
|
+
Class.new(BinData::Record) do
|
|
3524
|
+
endian :little
|
|
3525
|
+
|
|
3526
|
+
ndr_uint32 :a
|
|
3527
|
+
ndr_char_ptr :ptr1
|
|
3528
|
+
ndr_conf_array :array1, type: :random_struct
|
|
3529
|
+
ndr_uint32_ptr :ptr4, ref_to: :ptr5
|
|
3530
|
+
struct_with_ptr :d
|
|
3531
|
+
end
|
|
3532
|
+
end
|
|
3533
|
+
|
|
3534
|
+
it 'raises an exception' do
|
|
3535
|
+
expect { test_struct2.new(snapshot).snapshot }.to raise_error(ArgumentError)
|
|
3536
|
+
end
|
|
3537
|
+
end
|
|
3538
|
+
end
|
|
3539
|
+
end
|
|
3540
|
+
|
|
3541
|
+
RSpec.describe ::BinData::NdrPointerArgProcessor do
|
|
3542
|
+
let(:embedding_struct) do
|
|
3543
|
+
Class.new(BinData::Record) do
|
|
3544
|
+
ndr_class :a
|
|
3545
|
+
end
|
|
3546
|
+
end
|
|
3547
|
+
|
|
3548
|
+
before :example do
|
|
3549
|
+
ndr_class = Class.new(ref_class) do
|
|
3550
|
+
#default_parameters byte_align: 4
|
|
3551
|
+
arg_processor :ndr_pointer
|
|
3552
|
+
end
|
|
3553
|
+
BinData::RegisteredClasses.register('ndr_class', ndr_class)
|
|
3554
|
+
end
|
|
3555
|
+
|
|
3556
|
+
context 'with a NDR structure as referent' do
|
|
3557
|
+
let(:ref_class) { RubySMB::Dcerpc::Ndr::NdrUint32 }
|
|
3558
|
+
it 'does not raise error' do
|
|
3559
|
+
expect { embedding_struct }.to_not raise_error
|
|
3560
|
+
end
|
|
3561
|
+
end
|
|
3562
|
+
context 'with a BinData structure as referent' do
|
|
3563
|
+
let(:ref_class) { BinData::Uint32le }
|
|
3564
|
+
|
|
3565
|
+
it 'raises an error' do
|
|
3566
|
+
expect { embedding_struct }.to raise_error(ArgumentError)
|
|
3567
|
+
end
|
|
3568
|
+
context 'with byte_align parameter' do
|
|
3569
|
+
let(:embedding_struct) do
|
|
3570
|
+
Class.new(BinData::Record) do
|
|
3571
|
+
ndr_class :a, byte_align: 4
|
|
3572
|
+
end
|
|
3573
|
+
end
|
|
3574
|
+
it 'raises an error' do
|
|
3575
|
+
expect { embedding_struct }.to raise_error(ArgumentError)
|
|
3576
|
+
end
|
|
3577
|
+
end
|
|
3578
|
+
context 'with referent_byte_align parameter' do
|
|
3579
|
+
let(:embedding_struct) do
|
|
3580
|
+
Class.new(BinData::Record) do
|
|
3581
|
+
ndr_class :a, referent_byte_align: 4
|
|
3582
|
+
end
|
|
3583
|
+
end
|
|
3584
|
+
it 'does not raise error' do
|
|
3585
|
+
expect { embedding_struct }.to_not raise_error
|
|
3586
|
+
end
|
|
3587
|
+
end
|
|
3588
|
+
end
|
|
3589
|
+
end
|
|
3590
|
+
|
|
3591
|
+
RSpec.describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
|
|
3592
|
+
it 'is a BinData::Primitive class' do
|
|
3593
|
+
expect(described_class).to be < BinData::Primitive
|
|
3594
|
+
end
|
|
3595
|
+
|
|
3596
|
+
subject { described_class.new }
|
|
3597
|
+
|
|
3598
|
+
it { is_expected.to respond_to :context_handle_attributes }
|
|
3599
|
+
it { is_expected.to respond_to :context_handle_uuid }
|
|
3600
|
+
|
|
3601
|
+
context 'with #get' do
|
|
3602
|
+
it 'returns a hash with the default values' do
|
|
3603
|
+
expect(subject.get).to eq({context_handle_attributes: 0, context_handle_uuid: '00000000-0000-0000-0000-000000000000'})
|
|
3604
|
+
end
|
|
3605
|
+
it 'returns a hash with the expected values' do
|
|
3606
|
+
subject.assign(context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000')
|
|
3607
|
+
expect(subject.get).to eq({context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000'})
|
|
3608
|
+
end
|
|
3609
|
+
end
|
|
3610
|
+
|
|
3611
|
+
context 'with #set' do
|
|
3612
|
+
context 'with a hash' do
|
|
3613
|
+
it 'sets the expected values' do
|
|
3614
|
+
subject.set({context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000'})
|
|
3615
|
+
expect(subject).to eq({context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000'})
|
|
3616
|
+
end
|
|
3617
|
+
end
|
|
3618
|
+
context 'with a NdrContextHandle object' do
|
|
3619
|
+
it 'sets the expected values' do
|
|
3620
|
+
object = described_class.new
|
|
3621
|
+
object.set({context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000'})
|
|
3622
|
+
subject.set(object)
|
|
3623
|
+
expect(subject).to eq({context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000'})
|
|
3624
|
+
end
|
|
3625
|
+
end
|
|
3626
|
+
context 'with a binary string' do
|
|
3627
|
+
it 'sets the expected values' do
|
|
3628
|
+
subject.set("\x04\x00\x00\x00\x05\x04\x80\x57\x01\x03\x30\x33\x55\x66\x04\x00\x23\x00\x70\x00")
|
|
3629
|
+
expect(subject).to eq({context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000'})
|
|
3630
|
+
end
|
|
3631
|
+
end
|
|
3632
|
+
end
|
|
3633
|
+
end
|
|
3634
|
+
|
|
3635
|
+
RSpec.describe 'Alignment' do
|
|
3636
|
+
RSpec.shared_examples 'an aligned structure' do |align: 4, field_value:, field_binary:|
|
|
3637
|
+
let(:struct_obj) do
|
|
3638
|
+
struct_class.new(aligned_field: field_value)
|
|
3639
|
+
end
|
|
3640
|
+
it "is #{align}-bytes aligned" do
|
|
3641
|
+
expect(struct_obj.aligned_field.rel_offset % align).to eq(0)
|
|
3642
|
+
end
|
|
3643
|
+
it 'includes padding in its binary representation' do
|
|
3644
|
+
expect(struct_obj.to_binary_s).to eq("A#{"\x00" * (align - 1)}#{field_binary}".b)
|
|
3645
|
+
end
|
|
3646
|
+
end
|
|
3647
|
+
|
|
3648
|
+
let(:params) { {} }
|
|
3649
|
+
let(:struct_class) do
|
|
3650
|
+
Class.new(BinData::Record) do
|
|
3651
|
+
endian :little
|
|
3652
|
+
string :one_byte, value: 'A'
|
|
3653
|
+
end
|
|
3654
|
+
end
|
|
3655
|
+
|
|
3656
|
+
context 'in a BinData::Struct' do
|
|
3657
|
+
let(:params) { {} }
|
|
3658
|
+
before :example do
|
|
3659
|
+
struct_class.send(described_class.bindata_name.to_sym, :aligned_field, params)
|
|
3660
|
+
end
|
|
3661
|
+
|
|
3662
|
+
describe RubySMB::Dcerpc::Ndr::NdrBoolean do
|
|
3663
|
+
it_behaves_like(
|
|
3664
|
+
'an aligned structure',
|
|
3665
|
+
field_value: true,
|
|
3666
|
+
field_binary: [1].pack('L')
|
|
3667
|
+
)
|
|
3668
|
+
end
|
|
3669
|
+
|
|
3670
|
+
describe RubySMB::Dcerpc::Ndr::NdrWideChar do
|
|
3671
|
+
it_behaves_like(
|
|
3672
|
+
'an aligned structure',
|
|
3673
|
+
align: 2,
|
|
3674
|
+
field_value: 'B'.encode('utf-16le'),
|
|
3675
|
+
field_binary: "B\x00"
|
|
3676
|
+
)
|
|
3677
|
+
end
|
|
3678
|
+
|
|
3679
|
+
describe RubySMB::Dcerpc::Ndr::NdrEnum do
|
|
3680
|
+
it_behaves_like(
|
|
3681
|
+
'an aligned structure',
|
|
3682
|
+
align: 2,
|
|
3683
|
+
field_value: 3,
|
|
3684
|
+
field_binary: [3].pack('S')
|
|
3685
|
+
)
|
|
3686
|
+
end
|
|
3687
|
+
|
|
3688
|
+
describe RubySMB::Dcerpc::Ndr::NdrFixArray do
|
|
3689
|
+
context 'with an array of NdrUint32' do
|
|
3690
|
+
it_behaves_like(
|
|
3691
|
+
'an aligned structure',
|
|
3692
|
+
field_value: [1, 2, 3],
|
|
3693
|
+
field_binary: [1, 2, 3].pack('LLL')
|
|
3694
|
+
) do
|
|
3695
|
+
let(:params) { {type: :ndr_uint32, initial_length: 3, byte_align: 4} }
|
|
3696
|
+
end
|
|
3697
|
+
end
|
|
3698
|
+
context 'with an array of NdrUint64' do
|
|
3699
|
+
it_behaves_like(
|
|
3700
|
+
'an aligned structure',
|
|
3701
|
+
align: 8,
|
|
3702
|
+
field_value: [1, 2],
|
|
3703
|
+
field_binary: [1, 2].pack('QQ')
|
|
3704
|
+
) do
|
|
3705
|
+
let(:params) { {type: :ndr_uint64, initial_length: 2, byte_align: 8} }
|
|
3706
|
+
end
|
|
3707
|
+
end
|
|
3708
|
+
end
|
|
3709
|
+
|
|
3710
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfArray do
|
|
3711
|
+
context 'with an array of NdrUint32' do
|
|
3712
|
+
it_behaves_like(
|
|
3713
|
+
'an aligned structure',
|
|
3714
|
+
field_value: [1, 2, 3],
|
|
3715
|
+
field_binary: [3].pack('L') + [1, 2, 3].pack('LLL')
|
|
3716
|
+
) do
|
|
3717
|
+
let(:params) { {type: :ndr_uint32 } }
|
|
3718
|
+
end
|
|
3719
|
+
end
|
|
3720
|
+
context 'with an array of NdrUint64' do
|
|
3721
|
+
it_behaves_like(
|
|
3722
|
+
'an aligned structure',
|
|
3723
|
+
align: 8,
|
|
3724
|
+
field_value: [1, 2],
|
|
3725
|
+
field_binary: [2].pack('L') + [0].pack('L') + [1, 2].pack('QQ')
|
|
3726
|
+
) do
|
|
3727
|
+
let(:params) { {type: :ndr_uint64 } }
|
|
3728
|
+
end
|
|
3729
|
+
end
|
|
3730
|
+
end
|
|
3731
|
+
|
|
3732
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarArray do
|
|
3733
|
+
context 'with an array of NdrUint32' do
|
|
3734
|
+
it_behaves_like(
|
|
3735
|
+
'an aligned structure',
|
|
3736
|
+
field_value: [1 ,2 ,3],
|
|
3737
|
+
field_binary: [0].pack('L') + [3].pack('L') + [1, 2, 3].pack('LLL')
|
|
3738
|
+
) do
|
|
3739
|
+
let(:params) { {type: :ndr_uint32 } }
|
|
3740
|
+
end
|
|
3741
|
+
end
|
|
3742
|
+
context 'with an array of NdrUint64' do
|
|
3743
|
+
it_behaves_like(
|
|
3744
|
+
'an aligned structure',
|
|
3745
|
+
align: 8,
|
|
3746
|
+
field_value: [1, 2],
|
|
3747
|
+
field_binary: [0].pack('L') + [2].pack('L') + [1, 2].pack('QQ')
|
|
3748
|
+
) do
|
|
3749
|
+
let(:params) { {type: :ndr_uint64 } }
|
|
3750
|
+
end
|
|
3751
|
+
end
|
|
3752
|
+
end
|
|
3753
|
+
|
|
3754
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarArray do
|
|
3755
|
+
context 'with an array of NdrUint32' do
|
|
3756
|
+
it_behaves_like(
|
|
3757
|
+
'an aligned structure',
|
|
3758
|
+
field_value: [1, 2, 3],
|
|
3759
|
+
field_binary: [3].pack('L') + [0].pack('L') + [3].pack('L') + [1, 2, 3].pack('LLL')
|
|
3760
|
+
) do
|
|
3761
|
+
let(:params) { {type: :ndr_uint32 } }
|
|
3762
|
+
end
|
|
3763
|
+
end
|
|
3764
|
+
context 'with an array of NdrUint64' do
|
|
3765
|
+
it_behaves_like(
|
|
3766
|
+
'an aligned structure',
|
|
3767
|
+
align: 8,
|
|
3768
|
+
field_value: [1, 2],
|
|
3769
|
+
field_binary: [2].pack('L') + [0].pack('L') + [2].pack('L') + [0].pack('L') + [1, 2].pack('QQ')
|
|
3770
|
+
) do
|
|
3771
|
+
let(:params) { {type: :ndr_uint64 } }
|
|
3772
|
+
end
|
|
3773
|
+
end
|
|
3774
|
+
end
|
|
3775
|
+
|
|
3776
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarString do
|
|
3777
|
+
it_behaves_like(
|
|
3778
|
+
'an aligned structure',
|
|
3779
|
+
field_value: "Test1",
|
|
3780
|
+
field_binary: [0].pack('L') + [5].pack('L') + "Test1"
|
|
3781
|
+
)
|
|
3782
|
+
end
|
|
3783
|
+
|
|
3784
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarStringz do
|
|
3785
|
+
it_behaves_like(
|
|
3786
|
+
'an aligned structure',
|
|
3787
|
+
field_value: "Test1",
|
|
3788
|
+
field_binary: [0].pack('L') + [6].pack('L') + "Test1\x00"
|
|
3789
|
+
)
|
|
3790
|
+
end
|
|
3791
|
+
|
|
3792
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarWideString do
|
|
3793
|
+
it_behaves_like(
|
|
3794
|
+
'an aligned structure',
|
|
3795
|
+
field_value: "Test1".encode('utf-16le'),
|
|
3796
|
+
field_binary: [0].pack('L') + [5].pack('L') + "Test1".encode('utf-16le').force_encoding('ASCII')
|
|
3797
|
+
)
|
|
3798
|
+
end
|
|
3799
|
+
|
|
3800
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarWideStringz do
|
|
3801
|
+
it_behaves_like(
|
|
3802
|
+
'an aligned structure',
|
|
3803
|
+
field_value: "Test1".encode('utf-16le'),
|
|
3804
|
+
field_binary: [0].pack('L') + [6].pack('L') + "Test1\x00".encode('utf-16le').force_encoding('ASCII')
|
|
3805
|
+
)
|
|
3806
|
+
end
|
|
3807
|
+
|
|
3808
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarString do
|
|
3809
|
+
it_behaves_like(
|
|
3810
|
+
'an aligned structure',
|
|
3811
|
+
field_value: "Test1",
|
|
3812
|
+
field_binary: [5].pack('L') + [0].pack('L') + [5].pack('L') + "Test1"
|
|
3813
|
+
)
|
|
3814
|
+
end
|
|
3815
|
+
|
|
3816
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarStringz do
|
|
3817
|
+
it_behaves_like(
|
|
3818
|
+
'an aligned structure',
|
|
3819
|
+
field_value: "Test1",
|
|
3820
|
+
field_binary: [6].pack('L') + [0].pack('L') + [6].pack('L') + "Test1\x00"
|
|
3821
|
+
)
|
|
3822
|
+
end
|
|
3823
|
+
|
|
3824
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarWideString do
|
|
3825
|
+
it_behaves_like(
|
|
3826
|
+
'an aligned structure',
|
|
3827
|
+
field_value: "Test1".encode('utf-16le'),
|
|
3828
|
+
field_binary: [5].pack('L') + [0].pack('L') + [5].pack('L') + "Test1".encode('utf-16le').force_encoding('ASCII')
|
|
3829
|
+
)
|
|
3830
|
+
end
|
|
3831
|
+
|
|
3832
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz do
|
|
3833
|
+
it_behaves_like(
|
|
3834
|
+
'an aligned structure',
|
|
3835
|
+
field_value: "Test1".encode('utf-16le'),
|
|
3836
|
+
field_binary: [6].pack('L') + [0].pack('L') + [6].pack('L') + "Test1\x00".encode('utf-16le').force_encoding('ASCII')
|
|
3837
|
+
)
|
|
3838
|
+
end
|
|
3839
|
+
|
|
3840
|
+
{
|
|
3841
|
+
NdrUint8Ptr: { data: 2, binary: "\x02" },
|
|
3842
|
+
NdrUint16Ptr: { data: 3, binary: [3].pack('S') },
|
|
3843
|
+
NdrUint32Ptr: { data: 5, binary: [5].pack('L') },
|
|
3844
|
+
NdrUint64Ptr: { data: 7, binary: [7].pack('Q') },
|
|
3845
|
+
NdrCharPtr: { data: 'C', binary: 'C' },
|
|
3846
|
+
NdrBooleanPtr: { data: true, binary: [1].pack('L')},
|
|
3847
|
+
NdrStringPtr: { data: 'Test1', binary: "#{[5].pack('L')}#{[0].pack('L')}#{[5].pack('L')}Test1" },
|
|
3848
|
+
NdrStringzPtr: { data: 'Test2', binary: "#{[6].pack('L')}#{[0].pack('L')}#{[6].pack('L')}Test2\x00" },
|
|
3849
|
+
NdrWideStringPtr: { data: 'Test3'.encode('utf-16le'), binary: "#{[5].pack('L')}#{[0].pack('L')}#{[5].pack('L')}#{'Test3'.encode('utf-16le').force_encoding('ASCII')}" },
|
|
3850
|
+
NdrWideStringzPtr: { data: 'Test4'.encode('utf-16le'), binary: "#{[6].pack('L')}#{[0].pack('L')}#{[6].pack('L')}#{'Test4'.encode('utf-16le').force_encoding('ASCII')}\x00\x00" },
|
|
3851
|
+
NdrByteArrayPtr: { data: [1,2,3,4], binary: "#{[4].pack('L')}#{[0].pack('L')}#{[4].pack('L')}\x01\x02\x03\x04" },
|
|
3852
|
+
NdrFileTimePtr: { data: 132682503830000000, binary: [132682503830000000].pack('Q') }
|
|
3853
|
+
}.each do |ndr_class, info|
|
|
3854
|
+
describe(RubySMB::Dcerpc::Ndr.const_get(ndr_class)) do
|
|
3855
|
+
it_behaves_like(
|
|
3856
|
+
'an aligned structure',
|
|
3857
|
+
field_value: info[:data],
|
|
3858
|
+
field_binary: [RubySMB::Dcerpc::Ndr::INITIAL_REF_ID].pack('L')+ info[:binary]
|
|
3859
|
+
)
|
|
3860
|
+
end
|
|
3861
|
+
end
|
|
3862
|
+
|
|
3863
|
+
describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
|
|
3864
|
+
it_behaves_like(
|
|
3865
|
+
'an aligned structure',
|
|
3866
|
+
field_value: { context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000' },
|
|
3867
|
+
field_binary: "\x04\x00\x00\x00\x05\x04\x80\x57\x01\x03\x30\x33\x55\x66\x04\x00\x23\x00\x70\x00"
|
|
3868
|
+
)
|
|
3869
|
+
end
|
|
3870
|
+
end
|
|
3871
|
+
|
|
3872
|
+
context 'in a NDR structure' do
|
|
3873
|
+
describe 'Structure of mixed integers' do
|
|
3874
|
+
before :example do
|
|
3875
|
+
ndr_struct_class = Class.new(RubySMB::Dcerpc::Ndr::NdrStruct) do
|
|
3876
|
+
default_parameters byte_align: 4
|
|
3877
|
+
endian :little
|
|
3878
|
+
|
|
3879
|
+
ndr_uint32 :int_value1, byte_align: 4
|
|
3880
|
+
ndr_uint8 :int_value2
|
|
3881
|
+
end
|
|
3882
|
+
BinData::RegisteredClasses.register('ndr_struct_class', ndr_struct_class)
|
|
3883
|
+
struct_class.send(:ndr_struct_class, :aligned_field, params)
|
|
3884
|
+
end
|
|
3885
|
+
|
|
3886
|
+
it_behaves_like(
|
|
3887
|
+
'an aligned structure',
|
|
3888
|
+
align: 4,
|
|
3889
|
+
field_value: { int_value1: 5, int_value2: 3 },
|
|
3890
|
+
field_binary: [5].pack('L') + "\x03"
|
|
3891
|
+
) do
|
|
3892
|
+
# :byte_align is set according to the type of the largest element in
|
|
3893
|
+
# the structure (uint32):
|
|
3894
|
+
let(:params) { {byte_align: 4 } }
|
|
3895
|
+
end
|
|
3896
|
+
end
|
|
3897
|
+
end
|
|
3898
|
+
|
|
3899
|
+
context 'in a conformant array' do
|
|
3900
|
+
let(:params) { {} }
|
|
3901
|
+
before :example do
|
|
3902
|
+
struct_class.send(:ndr_conf_array, :aligned_field, { :type => [ described_class, params ] } )
|
|
3903
|
+
end
|
|
3904
|
+
|
|
3905
|
+
describe RubySMB::Dcerpc::Ndr::NdrBoolean do
|
|
3906
|
+
it_behaves_like(
|
|
3907
|
+
'an aligned structure',
|
|
3908
|
+
field_value: [true, false, true],
|
|
3909
|
+
field_binary: [3].pack('L') + [1, 0, 1].pack('LLL')
|
|
3910
|
+
)
|
|
3911
|
+
end
|
|
3912
|
+
|
|
3913
|
+
describe RubySMB::Dcerpc::Ndr::NdrWideChar do
|
|
3914
|
+
it_behaves_like(
|
|
3915
|
+
'an aligned structure',
|
|
3916
|
+
field_value: 'ABC'.encode('utf-16le').chars,
|
|
3917
|
+
field_binary: [3].pack('L') + "A\x00B\x00C\x00"
|
|
3918
|
+
)
|
|
3919
|
+
end
|
|
3920
|
+
|
|
3921
|
+
describe RubySMB::Dcerpc::Ndr::NdrEnum do
|
|
3922
|
+
it_behaves_like(
|
|
3923
|
+
'an aligned structure',
|
|
3924
|
+
field_value: [1, 2, 3],
|
|
3925
|
+
field_binary: [3].pack('L') + [1, 2, 3].pack('SSS')
|
|
3926
|
+
)
|
|
3927
|
+
end
|
|
3928
|
+
|
|
3929
|
+
describe RubySMB::Dcerpc::Ndr::NdrFixArray do
|
|
3930
|
+
context 'with an array of NdrUint32' do
|
|
3931
|
+
it_behaves_like(
|
|
3932
|
+
'an aligned structure',
|
|
3933
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
3934
|
+
field_binary: [2].pack('L') + [1, 2].pack('LL') + [3, 4].pack('LL')
|
|
3935
|
+
) do
|
|
3936
|
+
let(:params) { {type: :ndr_uint32, initial_length: 2, byte_align: 4} }
|
|
3937
|
+
end
|
|
3938
|
+
end
|
|
3939
|
+
context 'with an array of NdrUint64' do
|
|
3940
|
+
it_behaves_like(
|
|
3941
|
+
'an aligned structure',
|
|
3942
|
+
align: 8,
|
|
3943
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
3944
|
+
field_binary: [2].pack('L') + [0].pack('L') + [1, 2].pack('QQ') + [3, 4].pack('QQ')
|
|
3945
|
+
) do
|
|
3946
|
+
let(:params) { {type: :ndr_uint64, initial_length: 2, byte_align: 8} }
|
|
3947
|
+
end
|
|
3948
|
+
end
|
|
3949
|
+
end
|
|
3950
|
+
|
|
3951
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfArray do
|
|
3952
|
+
context 'with an array of NdrUint32' do
|
|
3953
|
+
it_behaves_like(
|
|
3954
|
+
'an aligned structure',
|
|
3955
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
3956
|
+
field_binary: [2].pack('L') + [2].pack('L') + [1, 2].pack('LL') + [2].pack('L') + [3, 4].pack('LL')
|
|
3957
|
+
) do
|
|
3958
|
+
let(:params) { {type: :ndr_uint32} }
|
|
3959
|
+
end
|
|
3960
|
+
end
|
|
3961
|
+
context 'with an array of NdrUint64' do
|
|
3962
|
+
it_behaves_like(
|
|
3963
|
+
'an aligned structure',
|
|
3964
|
+
align: 8,
|
|
3965
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
3966
|
+
field_binary: [2].pack('L') + [0].pack('L') + [2].pack('L') + [0].pack('L') + [1, 2].pack('QQ') + [2].pack('L') + [0].pack('L') + [3, 4].pack('QQ')
|
|
3967
|
+
) do
|
|
3968
|
+
let(:params) { {type: :ndr_uint64} }
|
|
3969
|
+
end
|
|
3970
|
+
end
|
|
3971
|
+
end
|
|
3972
|
+
|
|
3973
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarArray do
|
|
3974
|
+
context 'with an array of NdrUint32' do
|
|
3975
|
+
it_behaves_like(
|
|
3976
|
+
'an aligned structure',
|
|
3977
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
3978
|
+
field_binary: [2].pack('L') + [0].pack('L') + [2].pack('L') + [1, 2].pack('LL') + [0].pack('L') + [2].pack('L') + [3, 4].pack('LL')
|
|
3979
|
+
) do
|
|
3980
|
+
let(:params) { {type: :ndr_uint32} }
|
|
3981
|
+
end
|
|
3982
|
+
end
|
|
3983
|
+
context 'with an array of NdrUint64' do
|
|
3984
|
+
it_behaves_like(
|
|
3985
|
+
'an aligned structure',
|
|
3986
|
+
align: 8,
|
|
3987
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
3988
|
+
field_binary: [2].pack('L') + [0].pack('L') + [0].pack('L') + [2].pack('L') + [1, 2].pack('QQ') + [0].pack('L') + [2].pack('L') + [3, 4].pack('QQ')
|
|
3989
|
+
) do
|
|
3990
|
+
let(:params) { {type: :ndr_uint64} }
|
|
3991
|
+
end
|
|
3992
|
+
end
|
|
3993
|
+
end
|
|
3994
|
+
|
|
3995
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarArray do
|
|
3996
|
+
context 'with an array of NdrUint32' do
|
|
3997
|
+
it_behaves_like(
|
|
3998
|
+
'an aligned structure',
|
|
3999
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
4000
|
+
field_binary: [2].pack('L') + [2].pack('L') + [0].pack('L') + [2].pack('L') + [1, 2].pack('LL') + [2].pack('L') + [0].pack('L') + [2].pack('L') + [3, 4].pack('LL')
|
|
4001
|
+
) do
|
|
4002
|
+
let(:params) { {type: :ndr_uint32 } }
|
|
4003
|
+
end
|
|
4004
|
+
end
|
|
4005
|
+
context 'with an array of NdrUint64' do
|
|
4006
|
+
it_behaves_like(
|
|
4007
|
+
'an aligned structure',
|
|
4008
|
+
align: 8,
|
|
4009
|
+
field_value: [ [1, 2], [3, 4] ],
|
|
4010
|
+
field_binary: [2].pack('L') + [0].pack('L') + [2].pack('L') + [0].pack('L') + [2].pack('L') + [0].pack('L') + [1, 2].pack('QQ') + [2].pack('L') + [0].pack('L') + [2].pack('L') + [0].pack('L') + [3, 4].pack('QQ')
|
|
4011
|
+
) do
|
|
4012
|
+
let(:params) { {type: :ndr_uint64} }
|
|
4013
|
+
end
|
|
4014
|
+
end
|
|
4015
|
+
end
|
|
4016
|
+
|
|
4017
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarString do
|
|
4018
|
+
it_behaves_like(
|
|
4019
|
+
'an aligned structure',
|
|
4020
|
+
field_value: [ "Test1", "Test2" ],
|
|
4021
|
+
field_binary: [2].pack('L') + [0].pack('L') + [5].pack('L') + "Test1" + [0].pack('L') + [5].pack('L') + "Test2"
|
|
4022
|
+
)
|
|
4023
|
+
end
|
|
4024
|
+
|
|
4025
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarStringz do
|
|
4026
|
+
it_behaves_like(
|
|
4027
|
+
'an aligned structure',
|
|
4028
|
+
field_value: [ "Test1", "Test2" ],
|
|
4029
|
+
field_binary: [2].pack('L') + [0].pack('L') + [6].pack('L') + "Test1\x00" + [0].pack('L') + [6].pack('L') + "Test2\x00"
|
|
4030
|
+
)
|
|
4031
|
+
end
|
|
4032
|
+
|
|
4033
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarWideString do
|
|
4034
|
+
it_behaves_like(
|
|
4035
|
+
'an aligned structure',
|
|
4036
|
+
field_value: [ "Test1".encode('utf-16le'), "Test2".encode('utf-16le') ],
|
|
4037
|
+
field_binary: [2].pack('L') + [0].pack('L') + [5].pack('L') + "Test1".encode('utf-16le').force_encoding('ASCII') + [0].pack('L') + [5].pack('L') + "Test2".encode('utf-16le').force_encoding('ASCII')
|
|
4038
|
+
)
|
|
4039
|
+
end
|
|
4040
|
+
|
|
4041
|
+
describe RubySMB::Dcerpc::Ndr::NdrVarWideStringz do
|
|
4042
|
+
it_behaves_like(
|
|
4043
|
+
'an aligned structure',
|
|
4044
|
+
field_value: [ "Test1".encode('utf-16le'), "Test2".encode('utf-16le') ],
|
|
4045
|
+
field_binary: [2].pack('L') + [0].pack('L') + [6].pack('L') + "Test1\x00".encode('utf-16le').force_encoding('ASCII') + [0].pack('L') + [6].pack('L') + "Test2\x00".encode('utf-16le').force_encoding('ASCII')
|
|
4046
|
+
)
|
|
4047
|
+
end
|
|
4048
|
+
|
|
4049
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarString do
|
|
4050
|
+
it_behaves_like(
|
|
4051
|
+
'an aligned structure',
|
|
4052
|
+
field_value: [ "Test1", "Test2" ],
|
|
4053
|
+
field_binary: [2].pack('L') + [5].pack('L') + [0].pack('L') + [5].pack('L') + "Test1" + [5].pack('L') + [0].pack('L') + [5].pack('L') + "Test2"
|
|
4054
|
+
)
|
|
4055
|
+
end
|
|
4056
|
+
|
|
4057
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarStringz do
|
|
4058
|
+
it_behaves_like(
|
|
4059
|
+
'an aligned structure',
|
|
4060
|
+
field_value: [ "Test1", "Test2" ],
|
|
4061
|
+
field_binary: [2].pack('L') + [6].pack('L') + [0].pack('L') + [6].pack('L') + "Test1\x00" + [6].pack('L') + [0].pack('L') + [6].pack('L') + "Test2\x00"
|
|
4062
|
+
)
|
|
4063
|
+
end
|
|
4064
|
+
|
|
4065
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarWideString do
|
|
4066
|
+
it_behaves_like(
|
|
4067
|
+
'an aligned structure',
|
|
4068
|
+
field_value: [ "Test1".encode('utf-16le'), "Test2".encode('utf-16le') ],
|
|
4069
|
+
field_binary: [2].pack('L') + [5].pack('L') + [0].pack('L') + [5].pack('L') + "Test1".encode('utf-16le').force_encoding('ASCII') + [5].pack('L') + [0].pack('L') + [5].pack('L') + "Test2".encode('utf-16le').force_encoding('ASCII')
|
|
4070
|
+
)
|
|
4071
|
+
end
|
|
4072
|
+
|
|
4073
|
+
describe RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz do
|
|
4074
|
+
it_behaves_like(
|
|
4075
|
+
'an aligned structure',
|
|
4076
|
+
field_value: [ "Test1".encode('utf-16le'), "Test2".encode('utf-16le') ],
|
|
4077
|
+
field_binary: [2].pack('L') + [6].pack('L') + [0].pack('L') + [6].pack('L') + "Test1\x00".encode('utf-16le').force_encoding('ASCII') + [6].pack('L') + [0].pack('L') + [6].pack('L') + "Test2\x00".encode('utf-16le').force_encoding('ASCII')
|
|
4078
|
+
)
|
|
4079
|
+
end
|
|
4080
|
+
|
|
4081
|
+
{
|
|
4082
|
+
NdrUint8Ptr: { data: 2, binary: "\x02", size: 1 },
|
|
4083
|
+
NdrUint16Ptr: { data: 3, binary: [3].pack('S'), size: 2 },
|
|
4084
|
+
NdrUint32Ptr: { data: 5, binary: [5].pack('L'), size: 4 },
|
|
4085
|
+
NdrUint64Ptr: { data: 7, binary: [7].pack('Q'), size: 8 },
|
|
4086
|
+
NdrCharPtr: { data: 'C', binary: 'C', size: 1 },
|
|
4087
|
+
NdrBooleanPtr: { data: true, binary: [1].pack('L'), size: 4 },
|
|
4088
|
+
NdrStringPtr: {
|
|
4089
|
+
data: 'Test1',
|
|
4090
|
+
binary: "#{[5].pack('L')}#{[0].pack('L')}#{[5].pack('L')}Test1",
|
|
4091
|
+
size: 4
|
|
4092
|
+
},
|
|
4093
|
+
NdrStringzPtr: {
|
|
4094
|
+
data: 'Test2',
|
|
4095
|
+
binary: "#{[6].pack('L')}#{[0].pack('L')}#{[6].pack('L')}Test2\x00",
|
|
4096
|
+
size: 4
|
|
4097
|
+
},
|
|
4098
|
+
NdrWideStringPtr: {
|
|
4099
|
+
data: 'Test3'.encode('utf-16le'),
|
|
4100
|
+
binary: "#{[5].pack('L')}#{[0].pack('L')}#{[5].pack('L')}#{'Test3'.encode('utf-16le').b}",
|
|
4101
|
+
size: 4
|
|
4102
|
+
},
|
|
4103
|
+
NdrWideStringzPtr: {
|
|
4104
|
+
data: 'Test4'.encode('utf-16le'),
|
|
4105
|
+
binary: "#{[6].pack('L')}#{[0].pack('L')}#{[6].pack('L')}#{'Test4'.encode('utf-16le').b}\x00\x00",
|
|
4106
|
+
size: 4
|
|
4107
|
+
},
|
|
4108
|
+
NdrByteArrayPtr: {
|
|
4109
|
+
data: [1,2,3,4],
|
|
4110
|
+
binary: "#{[4].pack('L')}#{[0].pack('L')}#{[4].pack('L')}\x01\x02\x03\x04",
|
|
4111
|
+
size: 4
|
|
4112
|
+
},
|
|
4113
|
+
NdrFileTimePtr: { data: 132682503830000000, binary: [132682503830000000].pack('Q'), size: 4 }
|
|
4114
|
+
}.each do |ndr_class, info|
|
|
4115
|
+
describe(RubySMB::Dcerpc::Ndr.const_get(ndr_class)) do
|
|
4116
|
+
ref_id = [RubySMB::Dcerpc::Ndr::INITIAL_REF_ID].pack('L')
|
|
4117
|
+
ref_id2 = [RubySMB::Dcerpc::Ndr::INITIAL_REF_ID + 1].pack('L')
|
|
4118
|
+
binary_str = [2].pack('L') + ref_id + ref_id2
|
|
4119
|
+
# Embedding structure starts with 'A' + pad (4 bytes)
|
|
4120
|
+
current_size = 4 + binary_str.size
|
|
4121
|
+
align = (info[:size] - (current_size % info[:size])) % info[:size]
|
|
4122
|
+
binary_str << "\x00".b * align
|
|
4123
|
+
current_size += align
|
|
4124
|
+
binary_str << info[:binary]
|
|
4125
|
+
current_size += info[:binary].size
|
|
4126
|
+
align = (info[:size] - (current_size % info[:size])) % info[:size]
|
|
4127
|
+
binary_str << "\x00".b * align
|
|
4128
|
+
binary_str << info[:binary]
|
|
4129
|
+
it_behaves_like(
|
|
4130
|
+
'an aligned structure',
|
|
4131
|
+
field_value: [ info[:data], info[:data] ],
|
|
4132
|
+
field_binary: binary_str
|
|
4133
|
+
)
|
|
4134
|
+
end
|
|
403
4135
|
end
|
|
404
4136
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
4137
|
+
describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
|
|
4138
|
+
it_behaves_like(
|
|
4139
|
+
'an aligned structure',
|
|
4140
|
+
field_value: [
|
|
4141
|
+
{ context_handle_attributes: 4, context_handle_uuid: '57800405-0301-3330-5566-040023007000' },
|
|
4142
|
+
{ context_handle_attributes: 2, context_handle_uuid: '57800405-0301-3330-5566-040023007000' }
|
|
4143
|
+
],
|
|
4144
|
+
field_binary: [2].pack('L') + "\x04\x00\x00\x00\x05\x04\x80\x57\x01\x03\x30\x33\x55\x66\x04\x00\x23\x00\x70\x00\x02\x00\x00\x00\x05\x04\x80\x57\x01\x03\x30\x33\x55\x66\x04\x00\x23\x00\x70\x00"
|
|
4145
|
+
)
|
|
408
4146
|
end
|
|
409
4147
|
end
|
|
410
4148
|
end
|