diff options
author | George Hazan <ghazan@miranda.im> | 2022-09-28 19:58:47 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2022-09-28 19:59:04 +0300 |
commit | 96b7e711d06d0a673daf76a12c2bff4de14b0502 (patch) | |
tree | 06f402f16839b7c4e5de669bc63541957431dbc6 /protocols/WhatsAppWeb | |
parent | f53bb5a7dd0568d7849b224db568e380bc147a76 (diff) |
WhatsApp: fix for the binary nodes decoding
Diffstat (limited to 'protocols/WhatsAppWeb')
-rw-r--r-- | protocols/WhatsAppWeb/WhatsAppWeb.vcxproj | 2 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/WhatsAppWeb.vcxproj.filters | 6 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/dicts.h | 187 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/noise.cpp | 26 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/proto.h | 9 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/server.cpp | 68 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/utils.cpp | 449 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/utils.h | 9 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/wareader.cpp | 429 |
9 files changed, 688 insertions, 497 deletions
diff --git a/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj b/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj index 18629828d0..12a1eebf49 100644 --- a/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj +++ b/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj @@ -70,7 +70,9 @@ <PrecompiledHeader>Create</PrecompiledHeader> </ClCompile> <ClCompile Include="src\utils.cpp" /> + <ClCompile Include="src\wareader.cpp" /> <ClInclude Include="src\db.h" /> + <ClInclude Include="src\dicts.h" /> <ClInclude Include="src\proto.h" /> <ClInclude Include="src\resource.h" /> <ClInclude Include="src\stdafx.h" /> diff --git a/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj.filters b/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj.filters index ea4b46ed69..bba054ab20 100644 --- a/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj.filters +++ b/protocols/WhatsAppWeb/WhatsAppWeb.vcxproj.filters @@ -35,6 +35,9 @@ <ClCompile Include="src\noise.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="src\wareader.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="src\db.h"> @@ -55,6 +58,9 @@ <ClInclude Include="src\utils.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="src\dicts.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="res\version.rc"> diff --git a/protocols/WhatsAppWeb/src/dicts.h b/protocols/WhatsAppWeb/src/dicts.h new file mode 100644 index 0000000000..a8c8b25d61 --- /dev/null +++ b/protocols/WhatsAppWeb/src/dicts.h @@ -0,0 +1,187 @@ +static char *SingleByteTokens[] = { + "", "xmlstreamstart", "xmlstreamend", "s.whatsapp.net", "type", "participant", "from", "receipt", "id", "broadcast", "status", "message", "notification", "notify", "to", "jid", "user", + "class", "offline", "g.us", "result", "mediatype", "enc", "skmsg", "off_cnt", "xmlns", "presence", "participants", "ack", "t", "iq", "device_hash", "read", "value", "media", "picture", + "chatstate", "unavailable", "text", "urn:xmpp:whatsapp:push", "devices", "verified_name", "contact", "composing", "edge_routing", "routing_info", "item", "image", "verified_level", + "get", "fallback_hostname", "2", "media_conn", "1", "v", "handshake", "fallback_class", "count", "config", "offline_preview", "download_buckets", "w:profile:picture", "set", + "creation", "location", "fallback_ip4", "msg", "urn:xmpp:ping", "fallback_ip6", "call-creator", "relaylatency", "success", "subscribe", "video", "business_hours_config", + "platform", "hostname", "version", "unknown", "0", "ping", "hash", "edit", "subject", "max_buckets", "download", "delivery", "props", "sticker", "name", "last", "contacts", + "business", "primary", "preview", "w:p", "pkmsg", "call-id", "retry", "prop", "call", "auth_ttl", "available", "relay_id", "last_id", "day_of_week", "w", "host", "seen", + "bits", "list", "atn", "upload", "is_new", "w:stats", "key", "paused", "specific_hours", "multicast", "stream:error", "mmg.whatsapp.net", "code", "deny", "played", "profile", + "fna", "device-list", "close_time", "latency", "gcm", "pop", "audio", "26", "w:web", "open_time", "error", "auth", "ip4", "update", "profile_options", "config_value", "category", + "catalog_not_created", "00", "config_code", "mode", "catalog_status", "ip6", "blocklist", "registration", "7", "web", "fail", "w:m", "cart_enabled", "ttl", "gif", "300", + "device_orientation", "identity", "query", "401", "media-gig2-1.cdn.whatsapp.net", "in", "3", "te2", "add", "fallback", "categories", "ptt", "encrypt", "notice", + "thumbnail-document", "item-not-found", "12", "thumbnail-image", "stage", "thumbnail-link", "usync", "out", "thumbnail-video", "8", "01", "context", "sidelist", + "thumbnail-gif", "terminate", "not-authorized", "orientation", "dhash", "capability", "side_list", "md-app-state", "description", "serial", "readreceipts", "te", + "business_hours", "md-msg-hist", "tag", "attribute_padding", "document", "open_24h", "delete", "expiration", "active", "prev_v_id", "true", "passive", "index", "4", + "conflict", "remove", "w:gp2", "config_expo_key", "screen_height", "replaced", "02", "screen_width", "uploadfieldstat", "2:47DEQpj8", "media-bog1-1.cdn.whatsapp.net", + "encopt", "url", "catalog_exists", "keygen", "rate", "offer", "opus", "media-mia3-1.cdn.whatsapp.net", "privacy", "media-mia3-2.cdn.whatsapp.net", "signature", + "preaccept", "token_id", "media-eze1-1.cdn.whatsapp.net" +}; + +static char *dict0[] = { + "media-for1-1.cdn.whatsapp.net", "relay", "media-gru2-2.cdn.whatsapp.net", "uncompressed", "medium", "voip_settings", "device", "reason", + "media-lim1-1.cdn.whatsapp.net", "media-qro1-2.cdn.whatsapp.net", "media-gru1-2.cdn.whatsapp.net", "action", "features", "media-gru2-1.cdn.whatsapp.net", + "media-gru1-1.cdn.whatsapp.net", "media-otp1-1.cdn.whatsapp.net", "kyc-id", "priority", "phash", "mute", "token", "100", "media-qro1-1.cdn.whatsapp.net", + "none", "media-mrs2-2.cdn.whatsapp.net", "sign_credential", "03", "media-mrs2-1.cdn.whatsapp.net", "protocol", "timezone", "transport", "eph_setting", "1080", + "original_dimensions", "media-frx5-1.cdn.whatsapp.net", "background", "disable", "original_image_url", "5", "transaction-id", "direct_path", "103", "appointment_only", + "request_image_url", "peer_pid", "address", "105", "104", "102", "media-cdt1-1.cdn.whatsapp.net", "101", "109", "110", "106", "background_location", "v_id", "sync", + "status-old", "111", "107", "ppic", "media-scl2-1.cdn.whatsapp.net", "business_profile", "108", "invite", "04", "audio_duration", "media-mct1-1.cdn.whatsapp.net", + "media-cdg2-1.cdn.whatsapp.net", "media-los2-1.cdn.whatsapp.net", "invis", "net", "voip_payload_type", "status-revoke-delay", "404", "state", "use_correct_order_for_hmac_sha1", + "ver", "media-mad1-1.cdn.whatsapp.net", "order", "540", "skey", "blinded_credential", "android", "contact_remove", "enable_downlink_relay_latency_only", "duration", + "enable_vid_one_way_codec_nego", "6", "media-sof1-1.cdn.whatsapp.net", "accept", "all", "signed_credential", "media-atl3-1.cdn.whatsapp.net", "media-lhr8-1.cdn.whatsapp.net", + "website", "05", "latitude", "media-dfw5-1.cdn.whatsapp.net", "forbidden", "enable_audio_piggyback_network_mtu_fix", "media-dfw5-2.cdn.whatsapp.net", "note.m4r", + "media-atl3-2.cdn.whatsapp.net", "jb_nack_discard_count_fix", "longitude", "Opening.m4r", "media-arn2-1.cdn.whatsapp.net", "email", "timestamp", "admin", + "media-pmo1-1.cdn.whatsapp.net", "America/Sao_Paulo", "contact_add", "media-sin6-1.cdn.whatsapp.net", "interactive", "8000", "acs_public_key", + "sigquit_anr_detector_release_rollover_percent", "media.fmed1-2.fna.whatsapp.net", "groupadd", "enabled_for_video_upgrade", "latency_update_threshold", + "media-frt3-2.cdn.whatsapp.net", "calls_row_constraint_layout", "media.fgbb2-1.fna.whatsapp.net", "mms4_media_retry_notification_encryption_enabled", "timeout", + "media-sin6-3.cdn.whatsapp.net", "audio_nack_jitter_multiplier", "jb_discard_count_adjust_pct_rc", "audio_reserve_bps", "delta", "account_sync", "default", + "media.fjed4-6.fna.whatsapp.net", "06", "lock_video_orientation", "media-frt3-1.cdn.whatsapp.net", "w:g2", "media-sin6-2.cdn.whatsapp.net", "audio_nack_algo_mask", + "media.fgbb2-2.fna.whatsapp.net", "media.fmed1-1.fna.whatsapp.net", "cond_range_target_bitrate", "mms4_server_error_receipt_encryption_enabled", "vid_rc_dyn", "fri", + "cart_v1_1_order_message_changes_enabled", "reg_push", "jb_hist_deposit_value", "privatestats", "media.fist7-2.fna.whatsapp.net", "thu", "jb_discard_count_adjust_pct", + "mon", "group_call_video_maximization_enabled", "mms_cat_v1_forward_hot_override_enabled", "audio_nack_new_rtt", "media.fsub2-3.fna.whatsapp.net", + "media_upload_aggressive_retry_exponential_backoff_enabled", "tue", "wed", "media.fruh4-2.fna.whatsapp.net", "audio_nack_max_seq_req", "max_rtp_audio_packet_resends", + "jb_hist_max_cdf_value", "07", "audio_nack_max_jb_delay", "mms_forward_partially_downloaded_video", "media-lcy1-1.cdn.whatsapp.net", "resume", "jb_inband_fec_aware", + "new_commerce_entry_point_enabled", "480", "payments_upi_generate_qr_amount_limit", "sigquit_anr_detector_rollover_percent", "media.fsdu2-1.fna.whatsapp.net", "fbns", + "aud_pkt_reorder_pct", "dec", "stop_probing_before_accept_send", "media_upload_max_aggressive_retries", "edit_business_profile_new_mode_enabled", + "media.fhex4-1.fna.whatsapp.net", "media.fjed4-3.fna.whatsapp.net", "sigquit_anr_detector_64bit_rollover_percent", "cond_range_ema_jb_last_delay", + "watls_enable_early_data_http_get", "media.fsdu2-2.fna.whatsapp.net", "message_qr_disambiguation_enabled", "media-mxp1-1.cdn.whatsapp.net", "sat", "vertical", + "media.fruh4-5.fna.whatsapp.net", "200", "media-sof1-2.cdn.whatsapp.net", "-1", "height", "product_catalog_hide_show_items_enabled", "deep_copy_frm_last", + "tsoffline", "vp8/h.264", "media.fgye5-3.fna.whatsapp.net", "media.ftuc1-2.fna.whatsapp.net", "smb_upsell_chat_banner_enabled", "canonical", "08", "9", ".", + "media.fgyd4-4.fna.whatsapp.net", "media.fsti4-1.fna.whatsapp.net", "mms_vcache_aggregation_enabled", "mms_hot_content_timespan_in_seconds", "nse_ver", "rte", + "third_party_sticker_web_sync", "cond_range_target_total_bitrate", "media_upload_aggressive_retry_enabled", "instrument_spam_report_enabled", "disable_reconnect_tone", + "move_media_folder_from_sister_app", "one_tap_calling_in_group_chat_size", "10", "storage_mgmt_banner_threshold_mb", "enable_backup_passive_mode", "sharechat_inline_player_enabled", + "media.fcnq2-1.fna.whatsapp.net", "media.fhex4-2.fna.whatsapp.net", "media.fist6-3.fna.whatsapp.net", "ephemeral_drop_column_stage", "reconnecting_after_network_change_threshold_ms", + "media-lhr8-2.cdn.whatsapp.net", "cond_jb_last_delay_ema_alpha", "entry_point_block_logging_enabled", "critical_event_upload_log_config", "respect_initial_bitrate_estimate", + "smaller_image_thumbs_status_enabled", "media.fbtz1-4.fna.whatsapp.net", "media.fjed4-1.fna.whatsapp.net", "width", "720", "enable_frame_dropper", "enable_one_side_mode", + "urn:xmpp:whatsapp:dirty", "new_sticker_animation_behavior_v2", "media.flim3-2.fna.whatsapp.net", "media.fuio6-2.fna.whatsapp.net", "skip_forced_signaling", "dleq_proof", + "status_video_max_bitrate", "lazy_send_probing_req", "enhanced_storage_management", "android_privatestats_endpoint_dit_enabled", "media.fscl13-2.fna.whatsapp.net", "video_duration" +}; + +static char *dict1[] = { + "group_call_discoverability_enabled", "media.faep9-2.fna.whatsapp.net", "msgr", "bloks_loggedin_access_app_id", "db_status_migration_step", "watls_prefer_ip6", + "jabber:iq:privacy", "68", "media.fsaw1-11.fna.whatsapp.net", "mms4_media_conn_persist_enabled", "animated_stickers_thread_clean_up", "media.fcgk3-2.fna.whatsapp.net", + "media.fcgk4-6.fna.whatsapp.net", "media.fgye5-2.fna.whatsapp.net", "media.flpb1-1.fna.whatsapp.net", "media.fsub2-1.fna.whatsapp.net", "media.fuio6-3.fna.whatsapp.net", + "not-allowed", "partial_pjpeg_bw_threshold", "cap_estimated_bitrate", "mms_chatd_resume_check_over_thrift", "smb_upsell_business_profile_enabled", "product_catalog_webclient", + "groups", "sigquit_anr_detector_release_updated_rollout", "syncd_key_rotation_enabled", "media.fdmm2-1.fna.whatsapp.net", "media-hou1-1.cdn.whatsapp.net", + "remove_old_chat_notifications", "smb_biztools_deeplink_enabled", "use_downloadable_filters_int", "group_qr_codes_enabled", "max_receipt_processing_time", + "optimistic_image_processing_enabled", "smaller_video_thumbs_status_enabled", "watls_early_data", "reconnecting_before_relay_failover_threshold_ms", "cond_range_packet_loss_pct", + "groups_privacy_blacklist", "status-revoke-drop", "stickers_animated_thumbnail_download", "dedupe_transcode_shared_images", "dedupe_transcode_shared_videos", + "media.fcnq2-2.fna.whatsapp.net", "media.fgyd4-1.fna.whatsapp.net", "media.fist7-1.fna.whatsapp.net", "media.flim3-3.fna.whatsapp.net", "add_contact_by_qr_enabled", + "https://faq.whatsapp.com/payments", "multicast_limit_global", "sticker_notification_preview", "smb_better_catalog_list_adapters_enabled", "bloks_use_minscript_android", + "pen_smoothing_enabled", "media.fcgk4-5.fna.whatsapp.net", "media.fevn1-3.fna.whatsapp.net", "media.fpoj7-1.fna.whatsapp.net", "media-arn2-2.cdn.whatsapp.net", + "reconnecting_before_network_change_threshold_ms", "android_media_use_fresco_for_gifs", "cond_in_congestion", "status_image_max_edge", "sticker_search_enabled", + "starred_stickers_web_sync", "db_blank_me_jid_migration_step", "media.fist6-2.fna.whatsapp.net", "media.ftuc1-1.fna.whatsapp.net", "09", "anr_fast_logs_upload_rollout", + "camera_core_integration_enabled", "11", "third_party_sticker_caching", "thread_dump_contact_support", "wam_privatestats_enabled", "vcard_as_document_size_kb", "maxfpp", + "fbip", "ephemeral_allow_group_members", "media-bom1-2.cdn.whatsapp.net", "media-xsp1-1.cdn.whatsapp.net", "disable_prewarm", "frequently_forwarded_max", + "media.fbtz1-5.fna.whatsapp.net", "media.fevn7-1.fna.whatsapp.net", "media.fgyd4-2.fna.whatsapp.net", "sticker_tray_animation_fully_visible_items", + "green_alert_banner_duration", "reconnecting_after_p2p_failover_threshold_ms", "connected", "share_biz_vcard_enabled", "stickers_animation", "0a", "1200", "WhatsApp", + "group_description_length", "p_v_id", "payments_upi_intent_transaction_limit", "frequently_forwarded_messages", "media-xsp1-2.cdn.whatsapp.net", + "media.faep8-1.fna.whatsapp.net", "media.faep8-2.fna.whatsapp.net", "media.faep9-1.fna.whatsapp.net", "media.fdmm2-2.fna.whatsapp.net", "media.fgzt3-1.fna.whatsapp.net", + "media.flim4-2.fna.whatsapp.net", "media.frao1-1.fna.whatsapp.net", "media.fscl9-2.fna.whatsapp.net", "media.fsub2-2.fna.whatsapp.net", "superadmin", + "media.fbog10-1.fna.whatsapp.net", "media.fcgh28-1.fna.whatsapp.net", "media.fjdo10-1.fna.whatsapp.net", "third_party_animated_sticker_import", "delay_fec", + "attachment_picker_refresh", "android_linked_devices_re_auth_enabled", "rc_dyn", "green_alert_block_jitter", "add_contact_logging_enabled", "biz_message_logging_enabled", + "conversation_media_preview_v2", "media-jnb1-1.cdn.whatsapp.net", "ab_key", "media.fcgk4-2.fna.whatsapp.net", "media.fevn1-1.fna.whatsapp.net", "media.fist6-1.fna.whatsapp.net", + "media.fruh4-4.fna.whatsapp.net", "media.fsti4-2.fna.whatsapp.net", "mms_vcard_autodownload_size_kb", "watls_enabled", "notif_ch_override_off", "media.fsaw1-14.fna.whatsapp.net", + "media.fscl13-1.fna.whatsapp.net", "db_group_participant_migration_step", "1020", "cond_range_sterm_rtt", "invites_logging_enabled", "triggered_block_enabled", + "group_call_max_participants", "media-iad3-1.cdn.whatsapp.net", "product_catalog_open_deeplink", "shops_required_tos_version", "image_max_kbytes", + "cond_low_quality_vid_mode", "db_receipt_migration_step", "jb_early_prob_hist_shrink", "media.fdmm2-3.fna.whatsapp.net", "media.fdmm2-4.fna.whatsapp.net", + "media.fruh4-1.fna.whatsapp.net", "media.fsaw2-2.fna.whatsapp.net", "remove_geolocation_videos", "new_animation_behavior", "fieldstats_beacon_chance", "403", + "authkey_reset_on_ban", "continuous_ptt_playback", "reconnecting_after_relay_failover_threshold_ms", "false", "group", "sun", "conversation_swipe_to_reply", + "ephemeral_messages_setting", "smaller_video_thumbs_enabled", "md_device_sync_enabled", "bloks_shops_pdp_url_regex", "lasso_integration_enabled", + "media-bom1-1.cdn.whatsapp.net", "new_backup_format_enabled", "256", "media.faep6-1.fna.whatsapp.net", "media.fasr1-1.fna.whatsapp.net", "media.fbtz1-7.fna.whatsapp.net", + "media.fesb4-1.fna.whatsapp.net", "media.fjdo1-2.fna.whatsapp.net", "media.frba2-1.fna.whatsapp.net", "watls_no_dns", "600", "db_broadcast_me_jid_migration_step", + "new_wam_runtime_enabled", "group_update", "enhanced_block_enabled", "sync_wifi_threshold_kb", "mms_download_nc_cat", "bloks_minification_enabled", + "ephemeral_messages_enabled", "reject", "voip_outgoing_xml_signaling", "creator", "dl_bw", "payments_request_messages", "target_bitrate", "bloks_rendercore_enabled", + "media-hbe1-1.cdn.whatsapp.net", "media-hel3-1.cdn.whatsapp.net", "media-kut2-2.cdn.whatsapp.net", "media-lax3-1.cdn.whatsapp.net", "media-lax3-2.cdn.whatsapp.net", + "sticker_pack_deeplink_enabled", "hq_image_bw_threshold", "status_info", "voip", "dedupe_transcode_videos", "grp_uii_cleanup", "linked_device_max_count", + "media.flim1-1.fna.whatsapp.net", "media.fsaw2-1.fna.whatsapp.net", "reconnecting_after_call_active_threshold_ms", "1140", "catalog_pdp_new_design", + "media.fbtz1-10.fna.whatsapp.net", "media.fsaw1-15.fna.whatsapp.net", "0b", "consumer_rc_provider", "mms_async_fast_forward_ttl", "jb_eff_size_fix", + "voip_incoming_xml_signaling", "media_provider_share_by_uuid", "suspicious_links", "dedupe_transcode_images", "green_alert_modal_start", "media-cgk1-1.cdn.whatsapp.net", + "media-lga3-1.cdn.whatsapp.net", "template_doc_mime_types", "important_messages", "user_add", "vcard_max_size_kb", "media.fada2-1.fna.whatsapp.net", + "media.fbog2-5.fna.whatsapp.net", "media.fbtz1-3.fna.whatsapp.net", "media.fcgk3-1.fna.whatsapp.net", "media.fcgk7-1.fna.whatsapp.net", "media.flim1-3.fna.whatsapp.net", + "media.fscl9-1.fna.whatsapp.net", "ctwa_context_enterprise_enabled", "media.fsaw1-13.fna.whatsapp.net", "media.fuio11-2.fna.whatsapp.net", "status_collapse_muted", + "db_migration_level_force", "recent_stickers_web_sync", "bloks_session_state", "bloks_shops_enabled", "green_alert_setting_deep_links_enabled", "restrict_groups", + "battery", "green_alert_block_start", "refresh", "ctwa_context_enabled", "md_messaging_enabled", "status_image_quality", "md_blocklist_v2_server", + "media-del1-1.cdn.whatsapp.net", "13", "userrate", "a_v_id", "cond_rtt_ema_alpha", "invalid" +}; + +static char *dict2[] = { + "media.fada1-1.fna.whatsapp.net", "media.fadb3-2.fna.whatsapp.net", "media.fbhz2-1.fna.whatsapp.net", "media.fcor2-1.fna.whatsapp.net", "media.fjed4-2.fna.whatsapp.net", + "media.flhe4-1.fna.whatsapp.net", "media.frak1-2.fna.whatsapp.net", "media.fsub6-3.fna.whatsapp.net", "media.fsub6-7.fna.whatsapp.net", "media.fvvi1-1.fna.whatsapp.net", + "search_v5_eligible", "wam_real_time_enabled", "report_disk_event", "max_tx_rott_based_bitrate", "product", "media.fjdo10-2.fna.whatsapp.net", "video_frame_crc_sample_interval", + "media_max_autodownload", "15", "h.264", "wam_privatestats_buffer_count", "md_phash_v2_enabled", "account_transfer_enabled", "business_product_catalog", + "enable_non_dyn_codec_param_fix", "is_user_under_epd_jurisdiction", "media.fbog2-4.fna.whatsapp.net", "media.fbtz1-2.fna.whatsapp.net", "media.fcfc1-1.fna.whatsapp.net", + "media.fjed4-5.fna.whatsapp.net", "media.flhe4-2.fna.whatsapp.net", "media.flim1-2.fna.whatsapp.net", "media.flos5-1.fna.whatsapp.net", "android_key_store_auth_ver", + "010", "anr_process_monitor", "delete_old_auth_key", "media.fcor10-3.fna.whatsapp.net", "storage_usage_enabled", "android_camera2_support_level", "dirty", + "consumer_content_provider", "status_video_max_duration", "0c", "bloks_cache_enabled", "media.fadb2-2.fna.whatsapp.net", "media.fbko1-1.fna.whatsapp.net", + "media.fbtz1-9.fna.whatsapp.net", "media.fcgk4-4.fna.whatsapp.net", "media.fesb4-2.fna.whatsapp.net", "media.fevn1-2.fna.whatsapp.net", "media.fist2-4.fna.whatsapp.net", + "media.fjdo1-1.fna.whatsapp.net", "media.fruh4-6.fna.whatsapp.net", "media.fsrg5-1.fna.whatsapp.net", "media.fsub6-6.fna.whatsapp.net", "minfpp", "5000", "locales", + "video_max_bitrate", "use_new_auth_key", "bloks_http_enabled", "heartbeat_interval", "media.fbog11-1.fna.whatsapp.net", "ephemeral_group_query_ts", "fec_nack", + "search_in_storage_usage", "c", "media-amt2-1.cdn.whatsapp.net", "linked_devices_ui_enabled", "14", "async_data_load_on_startup", "voip_incoming_xml_ack", "16", + "db_migration_step", "init_bwe", "max_participants", "wam_buffer_count", "media.fada2-2.fna.whatsapp.net", "media.fadb3-1.fna.whatsapp.net", "media.fcor2-2.fna.whatsapp.net", + "media.fdiy1-2.fna.whatsapp.net", "media.frba3-2.fna.whatsapp.net", "media.fsaw2-3.fna.whatsapp.net", "1280", "status_grid_enabled", "w:biz", "product_catalog_deeplink", + "media.fgye10-2.fna.whatsapp.net", "media.fuio11-1.fna.whatsapp.net", "optimistic_upload", "work_manager_init", "lc", "catalog_message", "cond_net_medium", + "enable_periodical_aud_rr_processing", "cond_range_ema_rtt", "media-tir2-1.cdn.whatsapp.net", "frame_ms", "group_invite_sending", "payments_web_enabled", + "wallpapers_v2", "0d", "browser", "hq_image_max_edge", "image_edit_zoom", "linked_devices_re_auth_enabled", "media.faly3-2.fna.whatsapp.net", + "media.fdoh5-3.fna.whatsapp.net", "media.fesb3-1.fna.whatsapp.net", "media.fknu1-1.fna.whatsapp.net", "media.fmex3-1.fna.whatsapp.net", "media.fruh4-3.fna.whatsapp.net", + "255", "web_upgrade_to_md_modal", "audio_piggyback_timeout_msec", "enable_audio_oob_fec_feature", "from_ip", "image_max_edge", "message_qr_enabled", "powersave", + "receipt_pre_acking", "video_max_edge", "full", "011", "012", "enable_audio_oob_fec_for_sender", "md_voip_enabled", "enable_privatestats", "max_fec_ratio", + "payments_cs_faq_url", "media-xsp1-3.cdn.whatsapp.net", "hq_image_quality", "media.fasr1-2.fna.whatsapp.net", "media.fbog3-1.fna.whatsapp.net", + "media.ffjr1-6.fna.whatsapp.net", "media.fist2-3.fna.whatsapp.net", "media.flim4-3.fna.whatsapp.net", "media.fpbc2-4.fna.whatsapp.net", "media.fpku1-1.fna.whatsapp.net", + "media.frba1-1.fna.whatsapp.net", "media.fudi1-1.fna.whatsapp.net", "media.fvvi1-2.fna.whatsapp.net", "gcm_fg_service", "enable_dec_ltr_size_check", "clear", "lg", + "media.fgru11-1.fna.whatsapp.net", "18", "media-lga3-2.cdn.whatsapp.net", "pkey", "0e", "max_subject", "cond_range_lterm_rtt", "announcement_groups", "biz_profile_options", + "s_t", "media.fabv2-1.fna.whatsapp.net", "media.fcai3-1.fna.whatsapp.net", "media.fcgh1-1.fna.whatsapp.net", "media.fctg1-4.fna.whatsapp.net", "media.fdiy1-1.fna.whatsapp.net", + "media.fisb4-1.fna.whatsapp.net", "media.fpku1-2.fna.whatsapp.net", "media.fros9-1.fna.whatsapp.net", "status_v3_text", "usync_sidelist", "17", "announcement", "...", + "md_group_notification", "0f", "animated_pack_in_store", "013", "America/Mexico_City", "1260", "media-ams4-1.cdn.whatsapp.net", "media-cgk1-2.cdn.whatsapp.net", + "media-cpt1-1.cdn.whatsapp.net", "media-maa2-1.cdn.whatsapp.net", "media.fgye10-1.fna.whatsapp.net", "e", "catalog_cart", "hfm_string_changes", "init_bitrate", + "packless_hsm", "group_info", "America/Belem", "50", "960", "cond_range_bwe", "decode", "encode", "media.fada1-8.fna.whatsapp.net", "media.fadb1-2.fna.whatsapp.net", + "media.fasu6-1.fna.whatsapp.net", "media.fbog4-1.fna.whatsapp.net", "media.fcgk9-2.fna.whatsapp.net", "media.fdoh5-2.fna.whatsapp.net", "media.ffjr1-2.fna.whatsapp.net", + "media.fgua1-1.fna.whatsapp.net", "media.fgye1-1.fna.whatsapp.net", "media.fist1-4.fna.whatsapp.net", "media.fpbc2-2.fna.whatsapp.net", "media.fres2-1.fna.whatsapp.net", + "media.fsdq1-2.fna.whatsapp.net", "media.fsub6-5.fna.whatsapp.net", "profilo_enabled", "template_hsm", "use_disorder_prefetching_timer", "video_codec_priority", + "vpx_max_qp", "ptt_reduce_recording_delay", "25", "iphone", "Windows", "s_o", "Africa/Lagos", "abt", "media-kut2-1.cdn.whatsapp.net", "media-mba1-1.cdn.whatsapp.net", + "media-mxp1-2.cdn.whatsapp.net", "md_blocklist_v2", "url_text", "enable_short_offset", "group_join_permissions", "enable_audio_piggyback_feature", "image_quality", + "media.fcgk7-2.fna.whatsapp.net", "media.fcgk8-2.fna.whatsapp.net", "media.fclo7-1.fna.whatsapp.net", "media.fcmn1-1.fna.whatsapp.net", "media.feoh1-1.fna.whatsapp.net", + "media.fgyd4-3.fna.whatsapp.net", "media.fjed4-4.fna.whatsapp.net", "media.flim1-4.fna.whatsapp.net", "media.flim2-4.fna.whatsapp.net", "media.fplu6-1.fna.whatsapp.net", + "media.frak1-1.fna.whatsapp.net", "media.fsdq1-1.fna.whatsapp.net", "to_ip", "015", "vp8", "19", "21", "1320", "auth_key_ver", "message_processing_dedup", "server-error", + "wap4_enabled", "420", "014", "cond_range_rtt", "ptt_fast_lock_enabled", "media-ort2-1.cdn.whatsapp.net", "fwd_ui_start_ts" +}; + +static char *dict3[] = { + "contact_blacklist", "Asia/Jakarta", "media.fepa10-1.fna.whatsapp.net", "media.fmex10-3.fna.whatsapp.net", "disorder_prefetching_start_when_empty", "America/Bogota", + "use_local_probing_rx_bitrate", "America/Argentina/Buenos_Aires", "cross_post", "media.fabb1-1.fna.whatsapp.net", "media.fbog4-2.fna.whatsapp.net", "media.fcgk9-1.fna.whatsapp.net", + "media.fcmn2-1.fna.whatsapp.net", "media.fdel3-1.fna.whatsapp.net", "media.ffjr1-1.fna.whatsapp.net", "media.fgdl5-1.fna.whatsapp.net", "media.flpb1-2.fna.whatsapp.net", + "media.fmex2-1.fna.whatsapp.net", "media.frba2-2.fna.whatsapp.net", "media.fros2-2.fna.whatsapp.net", "media.fruh2-1.fna.whatsapp.net", "media.fybz2-2.fna.whatsapp.net", + "options", "20", "a", "017", "018", "mute_always", "user_notice", "Asia/Kolkata", "gif_provider", "locked", "media-gua1-1.cdn.whatsapp.net", "piggyback_exclude_force_flush", + "24", "media.frec39-1.fna.whatsapp.net", "user_remove", "file_max_size", "cond_packet_loss_pct_ema_alpha", "media.facc1-1.fna.whatsapp.net", "media.fadb2-1.fna.whatsapp.net", + "media.faly3-1.fna.whatsapp.net", "media.fbdo6-2.fna.whatsapp.net", "media.fcmn2-2.fna.whatsapp.net", "media.fctg1-3.fna.whatsapp.net", "media.ffez1-2.fna.whatsapp.net", + "media.fist1-3.fna.whatsapp.net", "media.fist2-2.fna.whatsapp.net", "media.flim2-2.fna.whatsapp.net", "media.fmct2-3.fna.whatsapp.net", "media.fpei3-1.fna.whatsapp.net", + "media.frba3-1.fna.whatsapp.net", "media.fsdu8-2.fna.whatsapp.net", "media.fstu2-1.fna.whatsapp.net", "media_type", "receipt_agg", "016", "enable_pli_for_crc_mismatch", + "live", "enc_rekey", "frskmsg", "d", "media.fdel11-2.fna.whatsapp.net", "proto", "2250", "audio_piggyback_enable_cache", "skip_nack_if_ltrp_sent", "mark_dtx_jb_frames", + "web_service_delay", "7282", "catalog_send_all", "outgoing", "360", "30", "LIMITED", "019", "audio_picker", "bpv2_phase", "media.fada1-7.fna.whatsapp.net", + "media.faep7-1.fna.whatsapp.net", "media.fbko1-2.fna.whatsapp.net", "media.fbni1-2.fna.whatsapp.net", "media.fbtz1-1.fna.whatsapp.net", "media.fbtz1-8.fna.whatsapp.net", + "media.fcjs3-1.fna.whatsapp.net", "media.fesb3-2.fna.whatsapp.net", "media.fgdl5-4.fna.whatsapp.net", "media.fist2-1.fna.whatsapp.net", "media.flhe2-2.fna.whatsapp.net", + "media.flim2-1.fna.whatsapp.net", "media.fmex1-1.fna.whatsapp.net", "media.fpat3-2.fna.whatsapp.net", "media.fpat3-3.fna.whatsapp.net", "media.fros2-1.fna.whatsapp.net", + "media.fsdu8-1.fna.whatsapp.net", "media.fsub3-2.fna.whatsapp.net", "payments_chat_plugin", "cond_congestion_no_rtcp_thr", "green_alert", "not-a-biz", "..", + "shops_pdp_urls_config", "source", "media-dus1-1.cdn.whatsapp.net", "mute_video", "01b", "currency", "max_keys", "resume_check", "contact_array", "qr_scanning", "23", + "b", "media.fbfh15-1.fna.whatsapp.net", "media.flim22-1.fna.whatsapp.net", "media.fsdu11-1.fna.whatsapp.net", "media.fsdu15-1.fna.whatsapp.net", "Chrome", "fts_version", + "60", "media.fada1-6.fna.whatsapp.net", "media.faep4-2.fna.whatsapp.net", "media.fbaq5-1.fna.whatsapp.net", "media.fbni1-1.fna.whatsapp.net", "media.fcai3-2.fna.whatsapp.net", + "media.fdel3-2.fna.whatsapp.net", "media.fdmm3-2.fna.whatsapp.net", "media.fhex3-1.fna.whatsapp.net", "media.fisb4-2.fna.whatsapp.net", "media.fkhi5-2.fna.whatsapp.net", + "media.flos2-1.fna.whatsapp.net", "media.fmct2-1.fna.whatsapp.net", "media.fntr7-1.fna.whatsapp.net", "media.frak3-1.fna.whatsapp.net", "media.fruh5-2.fna.whatsapp.net", + "media.fsub6-1.fna.whatsapp.net", "media.fuab1-2.fna.whatsapp.net", "media.fuio1-1.fna.whatsapp.net", "media.fver1-1.fna.whatsapp.net", "media.fymy1-1.fna.whatsapp.net", + "product_catalog", "1380", "audio_oob_fec_max_pkts", "22", "254", "media-ort2-2.cdn.whatsapp.net", "media-sjc3-1.cdn.whatsapp.net", "1600", "01a", "01c", "405", + "key_frame_interval", "body", "media.fcgh20-1.fna.whatsapp.net", "media.fesb10-2.fna.whatsapp.net", "125", "2000", "media.fbsb1-1.fna.whatsapp.net", + "media.fcmn3-2.fna.whatsapp.net", "media.fcpq1-1.fna.whatsapp.net", "media.fdel1-2.fna.whatsapp.net", "media.ffor2-1.fna.whatsapp.net", "media.fgdl1-4.fna.whatsapp.net", + "media.fhex2-1.fna.whatsapp.net", "media.fist1-2.fna.whatsapp.net", "media.fjed5-2.fna.whatsapp.net", "media.flim6-4.fna.whatsapp.net", "media.flos2-2.fna.whatsapp.net", + "media.fntr6-2.fna.whatsapp.net", "media.fpku3-2.fna.whatsapp.net", "media.fros8-1.fna.whatsapp.net", "media.fymy1-2.fna.whatsapp.net", "ul_bw", "ltrp_qp_offset", + "request", "nack", "dtx_delay_state_reset", "timeoffline", "28", "01f", "32", "enable_ltr_pool", "wa_msys_crypto", "01d", "58", "dtx_freeze_hg_update", + "nack_if_rpsi_throttled", "253", "840", "media.famd15-1.fna.whatsapp.net", "media.fbog17-2.fna.whatsapp.net", "media.fcai19-2.fna.whatsapp.net", "media.fcai21-4.fna.whatsapp.net", + "media.fesb10-4.fna.whatsapp.net", "media.fesb10-5.fna.whatsapp.net", "media.fmaa12-1.fna.whatsapp.net", "media.fmex11-3.fna.whatsapp.net", "media.fpoa33-1.fna.whatsapp.net", + "1050", "021", "clean", "cond_range_ema_packet_loss_pct", "media.fadb6-5.fna.whatsapp.net", "media.faqp4-1.fna.whatsapp.net", "media.fbaq3-1.fna.whatsapp.net", + "media.fbel2-1.fna.whatsapp.net", "media.fblr4-2.fna.whatsapp.net", "media.fclo8-1.fna.whatsapp.net", "media.fcoo1-2.fna.whatsapp.net", "media.ffjr1-4.fna.whatsapp.net", + "media.ffor9-1.fna.whatsapp.net", "media.fisb3-1.fna.whatsapp.net", "media.fkhi2-2.fna.whatsapp.net", "media.fkhi4-1.fna.whatsapp.net", "media.fpbc1-2.fna.whatsapp.net", + "media.fruh2-2.fna.whatsapp.net", "media.fruh5-1.fna.whatsapp.net", "media.fsub3-1.fna.whatsapp.net", "payments_transaction_limit", "252", "27", "29", "tintagel", "01e", + "237", "780", "callee_updated_payload", "020", "257", "price", "025", "239", "payments_cs_phone_number", "mediaretry", "w:auth:backup:token", "Glass.caf", "max_bitrate", + "240", "251", "660", "media.fbog16-1.fna.whatsapp.net", "media.fcgh21-1.fna.whatsapp.net", "media.fkul19-2.fna.whatsapp.net", "media.flim21-2.fna.whatsapp.net", + "media.fmex10-4.fna.whatsapp.net", "64", "33", "34", "35", "interruption", "media.fabv3-1.fna.whatsapp.net", "media.fadb6-1.fna.whatsapp.net", "media.fagr1-1.fna.whatsapp.net", + "media.famd1-1.fna.whatsapp.net", "media.famm6-1.fna.whatsapp.net", "media.faqp2-3.fna.whatsapp.net" +}; diff --git a/protocols/WhatsAppWeb/src/noise.cpp b/protocols/WhatsAppWeb/src/noise.cpp index d5d891d878..5c4037b61f 100644 --- a/protocols/WhatsAppWeb/src/noise.cpp +++ b/protocols/WhatsAppWeb/src/noise.cpp @@ -198,15 +198,29 @@ MBinBuffer WANoise::decrypt(const void *pData, size_t cbLen) return res; } -MBinBuffer WANoise::decodeFrame(const void *pData, size_t cbLen) +size_t WANoise::decodeFrame(const void *&pData, size_t &cbLen) { - if (!bInitFinished) { - MBinBuffer res; - res.assign(pData, cbLen); - return res; + auto *p = (const uint8_t *)pData; + + if (cbLen < 3) + return 0; + + size_t payloadLen = 0; + for (int i = 0; i < 3; i++) { + payloadLen <<= 8; + payloadLen += p[i]; + } + + ppro->debugLogA("got payload of size %d", payloadLen); + + cbLen -= 3; + if (payloadLen > cbLen) { + ppro->debugLogA("payload length %d exceeds capacity %d", payloadLen, cbLen); + return 0; } - return decrypt(pData, cbLen); + pData = p + 3; + return payloadLen; } MBinBuffer WANoise::encodeFrame(const void *pData, size_t cbLen) diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h index 7d02b425bb..54ec389933 100644 --- a/protocols/WhatsAppWeb/src/proto.h +++ b/protocols/WhatsAppWeb/src/proto.h @@ -12,7 +12,7 @@ Copyright © 2019-22 George Hazan #define KEY_BUNDLE_TYPE "\x05" class WhatsAppProto; -typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const void *pData, int cbLen); +typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const WANode &node); struct WARequest { @@ -99,7 +99,7 @@ public: MBinBuffer decrypt(const void *pData, size_t cbLen); MBinBuffer encrypt(const void *pData, size_t cbLen); - MBinBuffer decodeFrame(const void *pData, size_t cbLen); + size_t decodeFrame(const void *&pData, size_t &cbLen); MBinBuffer encodeFrame(const void *pData, size_t cbLen); }; @@ -184,10 +184,11 @@ class WhatsAppProto : public PROTO<WhatsAppProto> void OnSendMessage(const JSONNode &node, void*); void OnProcessHandshake(const void *pData, int cbLen); - void OnStartSession(const void *pData, int cbLen); + + void OnStartSession(const WANode &node); // binary packets - void ProcessBinaryPacket(const uint8_t *pData, size_t cbLen); + void ProcessBinaryPacket(const void *pData, size_t cbLen); // text packets void ProcessPacket(const JSONNode &node); diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp index 1bd6c70b49..1ffa435579 100644 --- a/protocols/WhatsAppWeb/src/server.cpp +++ b/protocols/WhatsAppWeb/src/server.cpp @@ -68,15 +68,8 @@ void WhatsAppProto::ShutdownSession() ///////////////////////////////////////////////////////////////////////////////////////// -void WhatsAppProto::OnStartSession(const void *pData, int cbLen) +void WhatsAppProto::OnStartSession(const WANode &node) { - proto::HandshakeMessage msg; - if (!msg.ParseFromArray(pData, cbLen)) { - debugLogA("Error parsing data, exiting"); - ShutdownSession(); - return; - } - } ///////////////////////////////////////////////////////////////////////////////////////// @@ -269,8 +262,7 @@ bool WhatsAppProto::ServerThreadWorker() auto &pubKey = m_noise->ephemeral.pub; auto *client = new proto::HandshakeMessage::ClientHello(); client->set_ephemeral(pubKey.data(), pubKey.length()); proto::HandshakeMessage msg; msg.set_allocated_clienthello(client); - WSSend(msg, &WhatsAppProto::OnProcessHandshake); - // OnProcessHandshake(0, 0); + WSSend(msg); bool bExit = false; MBinBuffer netbuf; @@ -324,7 +316,7 @@ bool WhatsAppProto::ServerThreadWorker() // try to decode if (hdr.opCode == 2 && hdr.payloadSize > 32) - ProcessBinaryPacket((const uint8_t*)pos, dataSize); + ProcessBinaryPacket(pos, dataSize); else { CMStringA szJson(pos, (int)dataSize); @@ -383,37 +375,41 @@ bool WhatsAppProto::ServerThreadWorker() ///////////////////////////////////////////////////////////////////////////////////////// // Binary data processing -void WhatsAppProto::ProcessBinaryPacket(const uint8_t *pData, size_t cbDataLen) +void WhatsAppProto::ProcessBinaryPacket(const void *pData, size_t cbDataLen) { - Netlib_Dump(m_hServerConn, pData, cbDataLen, false, 0); - - while (cbDataLen > 3) { - size_t payloadLen = 0; - for (int i = 0; i < 3; i++) { - payloadLen <<= 8; - payloadLen += pData[i]; - } - - pData += 3; - cbDataLen -= 3; - debugLogA("got payload of size %d", payloadLen); - - if (payloadLen > cbDataLen) { - debugLogA("payload length exceeds capacity %d", cbDataLen); - return; - } + while (size_t payloadLen = m_noise->decodeFrame(pData, cbDataLen)) { + if (m_noise->bInitFinished) { + MBinBuffer buf = m_noise->decrypt(pData, payloadLen); + + WAReader rdr(buf.data(), buf.length()); + auto b = rdr.readInt8(); + if (b & 2) { + debugLogA("zipped nodes are not supported"); + return; + } - MBinBuffer pkt = m_noise->decodeFrame(pData, payloadLen); + if (WANode *pNode = rdr.readNode()) { + CMStringA szText; + pNode->print(szText); + debugLogA("Got binary node:\n%s", szText.c_str()); - if (m_arPacketQueue.getCount()) { - WARequest req = m_arPacketQueue[0]; - m_arPacketQueue.remove(0); + if (m_arPacketQueue.getCount()) { + WARequest req = m_arPacketQueue[0]; + m_arPacketQueue.remove(0); - (this->*req.pHandler)(pkt.data(), (int)pkt.length()); + (this->*req.pHandler)(*pNode); + delete pNode; + } + else debugLogA("cannot handle incoming message"); + } + else { + debugLogA("wrong or broken payload"); + Netlib_Dump(m_hServerConn, pData, cbDataLen, false, 0); + } } - else debugLogA("cannot handle incoming message"); + else OnProcessHandshake(pData, (int)payloadLen); - pData += payloadLen; + pData = (BYTE*)pData + payloadLen; cbDataLen -= payloadLen; } } diff --git a/protocols/WhatsAppWeb/src/utils.cpp b/protocols/WhatsAppWeb/src/utils.cpp index 99393d65fc..9d62432a10 100644 --- a/protocols/WhatsAppWeb/src/utils.cpp +++ b/protocols/WhatsAppWeb/src/utils.cpp @@ -183,451 +183,6 @@ void WANode::print(CMStringA &dest, int level) const } ///////////////////////////////////////////////////////////////////////////////////////// -// WAReader class members - -bool WAReader::readAttributes(WANode *pNode, int count) -{ - if (count == 0) - return true; - - for (int i = 0; i < count; i++) { - CMStringA name = readString(readInt8()); - if (name.IsEmpty()) - return false; - - CMStringA value = readString(readInt8()); - if (value.IsEmpty()) - return false; - - pNode->addAttr(name, value); - } - return true; -} - -uint32_t WAReader::readInt20() -{ - if (m_limit - m_buf < 3) - return 0; - - int ret = (int(m_buf[0] & 0x0F) << 16) + (int(m_buf[1]) << 8) + int(m_buf[2]); - m_buf += 3; - return ret; -} - -uint32_t WAReader::readIntN(int n) -{ - if (m_limit - m_buf < n) - return 0; - - uint32_t res = 0; - for (int i = 0; i < n; i++, m_buf++) - res = (res <<= 8) + *m_buf; - return res; -} - -bool WAReader::readList(WANode *pParent, int tag) -{ - int size = readListSize(tag); - if (size == -1) - return false; - - for (int i = 0; i < size; i++) { - WANode *pNew = readNode(); - if (pNew == nullptr) - return false; - pParent->children.push_back(pNew); - } - - return true; -} - -int WAReader::readListSize(int tag) -{ - switch (tag) { - case LIST_EMPTY: - return 0; - case LIST_8: - return readInt8(); - case LIST_16: - return readInt16(); - } - return -1; -} - -WANode* WAReader::readNode() -{ - int listSize = readListSize(readInt8()); - if (listSize == -1) - return nullptr; - - int descrTag = readInt8(); - if (descrTag == STREAM_END) - return nullptr; - - CMStringA name = readString(descrTag); - if (name.IsEmpty()) - return nullptr; - - std::unique_ptr<WANode> ret(new WANode()); - ret->title = name.c_str(); - - if (!readAttributes(ret.get(), (listSize-1)>>1)) - return nullptr; - - if ((listSize % 2) == 1) - return ret.release(); - - int size, tag = readInt8(); - switch (tag) { - case LIST_EMPTY: case LIST_8: case LIST_16: - readList(ret.get(), tag); - break; - - case BINARY_8: - size = readInt8(); - -LBL_Binary: - if (m_limit - m_buf < size) - return false; - - ret->content.assign((void*)m_buf, size); - m_buf += size; - break; - - case BINARY_20: - size = readInt20(); - goto LBL_Binary; - - case BINARY_32: - size = readInt32(); - goto LBL_Binary; - - default: - CMStringA str = readString(tag); - ret->content.assign(str.GetBuffer(), str.GetLength() + 1); - } - - return ret.release(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int unpackHex(int val) -{ - if (val < 0 || val > 15) - return -1; - - return (val < 10) ? val + '0' : val - 10 + 'A'; -} - -static int unpackNibble(int val) -{ - if (val < 0 || val > 15) - return -1; - - switch (val) { - case 10: return '-'; - case 11: return '.'; - case 15: return 0; - default: return '0' + val; - } -} - -CMStringA WAReader::readPacked(int tag) -{ - int startByte = readInt8(); - bool bTrim = false; - if (startByte & 0x80) { - startByte &= ~0x80; - bTrim = true; - } - - CMStringA ret; - for (int i = 0; i < startByte; i++) { - BYTE b = readInt8(); - int lower = (tag == NIBBLE_8) ? unpackNibble(b >> 4) : unpackHex(b >> 4); - if (lower == -1) - return ""; - - int higher = (tag == NIBBLE_8) ? unpackNibble(b & 0x0F) : unpackHex(b & 0x0F); - if (higher == -1) - return ""; - - ret.AppendChar(lower); - ret.AppendChar(higher); - } - - if (bTrim && !ret.IsEmpty()) - ret.Truncate(ret.GetLength() - 1); - return ret; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static char *SingleByteTokens[] = { - "", "", "", "200", "400", "404", "500", "501", "502", "action", "add", - "after", "archive", "author", "available", "battery", "before", "body", - "broadcast", "chat", "clear", "code", "composing", "contacts", "count", - "create", "debug", "delete", "demote", "duplicate", "encoding", "error", - "false", "filehash", "from", "g.us", "group", "groups_v2", "height", "id", - "image", "in", "index", "invis", "item", "jid", "kind", "last", "leave", - "live", "log", "media", "message", "mimetype", "missing", "modify", "name", - "notification", "notify", "out", "owner", "participant", "paused", - "picture", "played", "presence", "preview", "promote", "query", "raw", - "read", "receipt", "received", "recipient", "recording", "relay", - "remove", "response", "resume", "retry", "s.whatsapp.net", "seconds", - "set", "size", "status", "subject", "subscribe", "t", "text", "to", "true", - "type", "unarchive", "unavailable", "url", "user", "value", "web", "width", - "mute", "read_only", "admin", "creator", "short", "update", "powersave", - "checksum", "epoch", "block", "previous", "409", "replaced", "reason", - "spam", "modify_tag", "message_info", "delivery", "emoji", "title", - "description", "canonical-url", "matched-text", "star", "unstar", - "media_key", "filename", "identity", "unread", "page", "page_count", - "search", "media_message", "security", "call_log", "profile", "ciphertext", - "invite", "gif", "vcard", "frequent", "privacy", "blacklist", "whitelist", - "verify", "location", "document", "elapsed", "revoke_invite", "expiration", - "unsubscribe", "disable", "vname", "old_jid", "new_jid", "announcement", - "locked", "prop", "label", "color", "call", "offer", "call-id", - "quick_reply", "sticker", "pay_t", "accept", "reject", "sticker_pack", - "invalid", "canceled", "missed", "connected", "result", "audio", - "video", "recent" }; - -CMStringA WAReader::readString(int tag) -{ - if (tag >= 3 && tag < _countof(SingleByteTokens)) { - CMStringA ret = SingleByteTokens[tag]; - if (ret == "s.whatsapp.net") - return "c.us"; - return ret; - } - - switch (tag) { -// case DICTIONARY_0: return dict0[readInt8()]; -// case DICTIONARY_1: return dict1[readInt8()]; -// case DICTIONARY_2: return dict2[readInt8()]; -// case DICTIONARY_3: return dict3[readInt8()]; - case LIST_EMPTY: - return ""; - - case BINARY_8: - return readStringFromChars(readInt8()); - - case BINARY_20: - return readStringFromChars(readInt20()); - - case BINARY_32: - return readStringFromChars(readInt32()); - - case NIBBLE_8: - case HEX_8: - return readPacked(tag); - - case JID_PAIR: - CMStringA s1 = readString(readInt8()); - if (s1.IsEmpty()) - break; - - CMStringA s2 = readString(readInt8()); - if (s2.IsEmpty()) - break; - - return CMStringA(FORMAT, "%s@%s", s1.c_str(), s2.c_str()); - } - - // error - return ""; -} - -CMStringA WAReader::readStringFromChars(int size) -{ - if (m_limit - m_buf < size) - return ""; - - CMStringA ret((char*)m_buf, size); - m_buf += size; - return ret; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// WAWriter class members - -void WAWriter::writeByte(uint8_t b) -{ - body.append(&b, 1); -} - -void WAWriter::writeIntN(int value, int n) -{ - for (int i = n - 1; i >= 0; i--) - writeByte((value >> i * 8) & 0xFF); -} - -void WAWriter::writeInt20(int value) -{ - writeByte((value >> 16) & 0xFF); - writeByte((value >> 8) & 0xFF); - writeByte(value & 0xFF); -} - -void WAWriter::writeLength(int value) -{ - if (value >= (1 << 20)) { - writeByte(BINARY_32); - writeInt32(value); - } - else if (value >= 256) { - writeByte(BINARY_20); - writeInt20(value); - } - else { - writeByte(BINARY_8); - writeInt8(value); - } -} - -void WAWriter::writeListSize(int length) -{ - if (length == 0) - writeByte(LIST_EMPTY); - else if (length < 256) { - writeByte(LIST_8); - writeInt8(length); - } - else { - writeByte(LIST_16); - writeInt16(length); - } -} - -void WAWriter::writeNode(const WANode *pNode) -{ - int numAttrs = (int)pNode->attrs.size(); - int hasContent = pNode->content.length() != 0; - writeListSize(2*numAttrs + 1 + hasContent); - - writeString(pNode->title.c_str()); - - // write attributes - for (auto &it : pNode->attrs) { - if (it->value.IsEmpty()) - continue; - - writeString(it->name.c_str()); - writeString(it->value.c_str()); - } - - // write contents - if (pNode->content.length()) { - writeLength((int)pNode->content.length()); - body.append(pNode->content.data(), pNode->content.length()); - } - - // write children - if (pNode->children.size()) { - writeListSize((int)pNode->children.size()); - for (auto &it : pNode->children) - writeNode(it); - } -} - -void WAWriter::writeString(const char *str, bool bRaw) -{ - if (!bRaw && !mir_strcmp(str, "c.us")) { - writeToken("s.whatsapp.net"); - return; - } - - if (writeToken(str)) - return; - - auto *pszDelimiter = strchr(str, '@'); - if (pszDelimiter) { - writeByte(JID_PAIR); - - if (pszDelimiter == str) // empty jid - writeByte(LIST_EMPTY); - else - writePacked(CMStringA(str, int(pszDelimiter - str))); - } - else { - int len = (int)strlen(str); - writeLength(len); - body.append(str, len); - } -} - -bool WAWriter::writeToken(const char *str) -{ - for (auto &it : SingleByteTokens) - if (!strcmp(str, it)) { - writeByte(int(&it - SingleByteTokens)); - return true; - } - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static BYTE packNibble(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - - switch (c) { - case '-': return 10; - case '.': return 11; - case 0: return 15; - } - - return -1; -} - -static BYTE packHex(char c) -{ - if (c == 0) - return 15; - - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'A' && c <= 'F') - return c - 'A'; - - if (c >= 'a' && c <= 'f') - return c - 'a'; - - return -1; -} - -static BYTE packPair(int type, char c1, char c2) -{ - BYTE b1 = (type == NIBBLE_8) ? packNibble(c1) : packHex(c1); - BYTE b2 = (type == NIBBLE_8) ? packNibble(c2) : packHex(c2); - return (b1 << 4) + b2; -} - -void WAWriter::writePacked(const CMStringA &str) -{ - if (str.GetLength() > 254) - return; - - // all symbols of str can be a nibble? - int type = (strspn(str, "0123456789-.") == str.GetLength()) ? NIBBLE_8 : HEX_8; - - int len = str.GetLength() / 2; - BYTE firstByte = (len % 2) == 0 ? 0 : 0x80; - writeByte(firstByte | len); - - const char *p = str; - for (int i = 0; i < len; i++, p += 2) - writeByte(packPair(type, p[0], p[1])); - - if (firstByte != 0) - writeByte(packPair(type, p[0], 0)); -} - -///////////////////////////////////////////////////////////////////////////////////////// std::string encodeBigEndian(uint32_t num, size_t len) { @@ -658,7 +213,7 @@ static unsigned char *HKDF_Extract(const EVP_MD *evp_md, { unsigned int tmp_len; - if (!HMAC(evp_md, salt, salt_len, key, key_len, prk, &tmp_len)) + if (!HMAC(evp_md, salt, (int)salt_len, key, (int)key_len, prk, &tmp_len)) return NULL; *prk_len = tmp_len; @@ -689,7 +244,7 @@ static unsigned char *HKDF_Expand(const EVP_MD *evp_md, if ((hmac = HMAC_CTX_new()) == NULL) return NULL; - if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL)) + if (!HMAC_Init_ex(hmac, prk, (int)prk_len, evp_md, NULL)) goto err; for (i = 1; i <= n; i++) { diff --git a/protocols/WhatsAppWeb/src/utils.h b/protocols/WhatsAppWeb/src/utils.h index 151f3adffd..72d69c96f0 100644 --- a/protocols/WhatsAppWeb/src/utils.h +++ b/protocols/WhatsAppWeb/src/utils.h @@ -13,6 +13,7 @@ Copyright © 2019-22 George Hazan #define DICTIONARY_1 237 #define DICTIONARY_2 238 #define DICTIONARY_3 239 +#define AD_JID 247 #define LIST_8 248 #define LIST_16 249 #define JID_PAIR 250 @@ -59,10 +60,6 @@ class WAReader uint32_t readIntN(int i); CMStringA readStringFromChars(int size); - __forceinline uint32_t readInt8() { return readIntN(1); } - __forceinline uint32_t readInt16() { return readIntN(2); } - __forceinline uint32_t readInt32() { return readIntN(4); } - bool readAttributes(WANode *node, int count); uint32_t readInt20(); bool readList(WANode *pParent, int tag); @@ -77,6 +74,10 @@ public: {} WANode* readNode(); + + __forceinline uint32_t readInt8() { return readIntN(1); } + __forceinline uint32_t readInt16() { return readIntN(2); } + __forceinline uint32_t readInt32() { return readIntN(4); } }; class WAWriter diff --git a/protocols/WhatsAppWeb/src/wareader.cpp b/protocols/WhatsAppWeb/src/wareader.cpp new file mode 100644 index 0000000000..0f6df4b31a --- /dev/null +++ b/protocols/WhatsAppWeb/src/wareader.cpp @@ -0,0 +1,429 @@ +/* + +WhatsAppWeb plugin for Miranda NG +Copyright © 2019-22 George Hazan + +*/ + +#include "stdafx.h" +#include "dicts.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// WAReader class members + +bool WAReader::readAttributes(WANode *pNode, int count) +{ + if (count == 0) + return true; + + for (int i = 0; i < count; i++) { + CMStringA name = readString(readInt8()); + if (name.IsEmpty()) + return false; + + CMStringA value = readString(readInt8()); + if (value.IsEmpty()) + return false; + + pNode->addAttr(name, value); + } + return true; +} + +uint32_t WAReader::readInt20() +{ + if (m_limit - m_buf < 3) + return 0; + + int ret = (int(m_buf[0] & 0x0F) << 16) + (int(m_buf[1]) << 8) + int(m_buf[2]); + m_buf += 3; + return ret; +} + +uint32_t WAReader::readIntN(int n) +{ + if (m_limit - m_buf < n) + return 0; + + uint32_t res = 0; + for (int i = 0; i < n; i++, m_buf++) + res = (res <<= 8) + *m_buf; + return res; +} + +bool WAReader::readList(WANode *pParent, int tag) +{ + int size = readListSize(tag); + if (size == -1) + return false; + + for (int i = 0; i < size; i++) { + WANode *pNew = readNode(); + if (pNew == nullptr) + return false; + pParent->children.push_back(pNew); + } + + return true; +} + +int WAReader::readListSize(int tag) +{ + switch (tag) { + case LIST_EMPTY: + return 0; + case LIST_8: + return readInt8(); + case LIST_16: + return readInt16(); + } + return -1; +} + +WANode *WAReader::readNode() +{ + int listSize = readListSize(readInt8()); + if (listSize == -1) + return nullptr; + + int descrTag = readInt8(); + if (descrTag == STREAM_END) + return nullptr; + + CMStringA name = readString(descrTag); + if (name.IsEmpty()) + return nullptr; + + std::unique_ptr<WANode> ret(new WANode()); + ret->title = name.c_str(); + + if (!readAttributes(ret.get(), (listSize - 1) >> 1)) + return nullptr; + + if ((listSize % 2) == 1) + return ret.release(); + + int size, tag = readInt8(); + switch (tag) { + case LIST_EMPTY: case LIST_8: case LIST_16: + readList(ret.get(), tag); + break; + + case BINARY_8: + size = readInt8(); + +LBL_Binary: + if (m_limit - m_buf < size) + return false; + + ret->content.assign((void *)m_buf, size); + m_buf += size; + break; + + case BINARY_20: + size = readInt20(); + goto LBL_Binary; + + case BINARY_32: + size = readInt32(); + goto LBL_Binary; + + default: + CMStringA str = readString(tag); + ret->content.assign(str.GetBuffer(), str.GetLength() + 1); + } + + return ret.release(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int unpackHex(int val) +{ + if (val < 0 || val > 15) + return -1; + + return (val < 10) ? val + '0' : val - 10 + 'A'; +} + +static int unpackNibble(int val) +{ + if (val < 0 || val > 15) + return -1; + + switch (val) { + case 10: return '-'; + case 11: return '.'; + case 15: return 0; + default: return '0' + val; + } +} + +CMStringA WAReader::readPacked(int tag) +{ + int startByte = readInt8(); + bool bTrim = false; + if (startByte & 0x80) { + startByte &= ~0x80; + bTrim = true; + } + + CMStringA ret; + for (int i = 0; i < startByte; i++) { + BYTE b = readInt8(); + int lower = (tag == NIBBLE_8) ? unpackNibble(b >> 4) : unpackHex(b >> 4); + if (lower == -1) + return ""; + + int higher = (tag == NIBBLE_8) ? unpackNibble(b & 0x0F) : unpackHex(b & 0x0F); + if (higher == -1) + return ""; + + ret.AppendChar(lower); + ret.AppendChar(higher); + } + + if (bTrim && !ret.IsEmpty()) + ret.Truncate(ret.GetLength() - 1); + return ret; +} + +CMStringA WAReader::readString(int tag) +{ + if (tag >= 1 && tag < _countof(SingleByteTokens)) { + CMStringA ret = SingleByteTokens[tag]; + if (ret == "s.whatsapp.net") + return "c.us"; + return ret; + } + + switch (tag) { + case DICTIONARY_0: return dict0[readInt8()]; + case DICTIONARY_1: return dict1[readInt8()]; + case DICTIONARY_2: return dict2[readInt8()]; + case DICTIONARY_3: return dict3[readInt8()]; + case LIST_EMPTY: + return ""; + + case BINARY_8: + return readStringFromChars(readInt8()); + + case BINARY_20: + return readStringFromChars(readInt20()); + + case BINARY_32: + return readStringFromChars(readInt32()); + + case NIBBLE_8: + case HEX_8: + return readPacked(tag); + + case AD_JID: + { + int agent = readInt8(); + int device = readInt8(); + CMStringA user = readString(readInt8()); + return user + "@c.us"; + } + + case JID_PAIR: + CMStringA s1 = readString(readInt8()); + CMStringA s2 = readString(readInt8()); + if (s1.IsEmpty() && s2.IsEmpty()) + break; + + return CMStringA(FORMAT, "%s@%s", s1.c_str(), s2.c_str()); + } + + // error + return ""; +} + +CMStringA WAReader::readStringFromChars(int size) +{ + if (m_limit - m_buf < size) + return ""; + + CMStringA ret((char *)m_buf, size); + m_buf += size; + return ret; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// WAWriter class members + +void WAWriter::writeByte(uint8_t b) +{ + body.append(&b, 1); +} + +void WAWriter::writeIntN(int value, int n) +{ + for (int i = n - 1; i >= 0; i--) + writeByte((value >> i * 8) & 0xFF); +} + +void WAWriter::writeInt20(int value) +{ + writeByte((value >> 16) & 0xFF); + writeByte((value >> 8) & 0xFF); + writeByte(value & 0xFF); +} + +void WAWriter::writeLength(int value) +{ + if (value >= (1 << 20)) { + writeByte(BINARY_32); + writeInt32(value); + } + else if (value >= 256) { + writeByte(BINARY_20); + writeInt20(value); + } + else { + writeByte(BINARY_8); + writeInt8(value); + } +} + +void WAWriter::writeListSize(int length) +{ + if (length == 0) + writeByte(LIST_EMPTY); + else if (length < 256) { + writeByte(LIST_8); + writeInt8(length); + } + else { + writeByte(LIST_16); + writeInt16(length); + } +} + +void WAWriter::writeNode(const WANode *pNode) +{ + int numAttrs = (int)pNode->attrs.size(); + int hasContent = pNode->content.length() != 0; + writeListSize(2 * numAttrs + 1 + hasContent); + + writeString(pNode->title.c_str()); + + // write attributes + for (auto &it : pNode->attrs) { + if (it->value.IsEmpty()) + continue; + + writeString(it->name.c_str()); + writeString(it->value.c_str()); + } + + // write contents + if (pNode->content.length()) { + writeLength((int)pNode->content.length()); + body.append(pNode->content.data(), pNode->content.length()); + } + + // write children + if (pNode->children.size()) { + writeListSize((int)pNode->children.size()); + for (auto &it : pNode->children) + writeNode(it); + } +} + +void WAWriter::writeString(const char *str, bool bRaw) +{ + if (!bRaw && !mir_strcmp(str, "c.us")) { + writeToken("s.whatsapp.net"); + return; + } + + if (writeToken(str)) + return; + + auto *pszDelimiter = strchr(str, '@'); + if (pszDelimiter) { + writeByte(JID_PAIR); + + if (pszDelimiter == str) // empty jid + writeByte(LIST_EMPTY); + else + writePacked(CMStringA(str, int(pszDelimiter - str))); + } + else { + int len = (int)strlen(str); + writeLength(len); + body.append(str, len); + } +} + +bool WAWriter::writeToken(const char *str) +{ + for (auto &it : SingleByteTokens) + if (!strcmp(str, it)) { + writeByte(int(&it - SingleByteTokens)); + return true; + } + + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static BYTE packNibble(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + + switch (c) { + case '-': return 10; + case '.': return 11; + case 0: return 15; + } + + return -1; +} + +static BYTE packHex(char c) +{ + if (c == 0) + return 15; + + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'A' && c <= 'F') + return c - 'A'; + + if (c >= 'a' && c <= 'f') + return c - 'a'; + + return -1; +} + +static BYTE packPair(int type, char c1, char c2) +{ + BYTE b1 = (type == NIBBLE_8) ? packNibble(c1) : packHex(c1); + BYTE b2 = (type == NIBBLE_8) ? packNibble(c2) : packHex(c2); + return (b1 << 4) + b2; +} + +void WAWriter::writePacked(const CMStringA &str) +{ + if (str.GetLength() > 254) + return; + + // all symbols of str can be a nibble? + int type = (strspn(str, "0123456789-.") == str.GetLength()) ? NIBBLE_8 : HEX_8; + + int len = str.GetLength() / 2; + BYTE firstByte = (len % 2) == 0 ? 0 : 0x80; + writeByte(firstByte | len); + + const char *p = str; + for (int i = 0; i < len; i++, p += 2) + writeByte(packPair(type, p[0], p[1])); + + if (firstByte != 0) + writeByte(packPair(type, p[0], 0)); +} |