diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d50309da..323ae32e88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1816,6 +1816,7 @@ set(INSTALL_FILES ${CMAKE_BINARY_DIR}/doc/mergecap.html ${CMAKE_BINARY_DIR}/doc/randpkt.html ${CMAKE_BINARY_DIR}/doc/randpktdump.html + ${CMAKE_BINARY_DIR}/doc/etwdump.html ${CMAKE_BINARY_DIR}/doc/rawshark.html ${CMAKE_BINARY_DIR}/doc/reordercap.html ${CMAKE_BINARY_DIR}/doc/sshdump.html @@ -3170,6 +3171,7 @@ set(CLEAN_C_FILES ${dftest_FILES} ${randpkt_FILES} ${randpktdump_FILES} + ${etwdump_FILES} ${udpdump_FILES} ${text2pcap_FILES} ${mergecap_FILES} diff --git a/CMakeOptions.txt b/CMakeOptions.txt index 143df081e8..a651c2ebb6 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -22,6 +22,12 @@ option(BUILD_sshdump "Build sshdump" ON) option(BUILD_ciscodump "Build ciscodump" ON) option(BUILD_dpauxmon "Build dpauxmon" ON) option(BUILD_randpktdump "Build randpktdump" ON) +if(WIN32) + option(BUILD_etwdump "Build etwdump" ON) +else() + option(BUILD_etwdump "Build etwdump" OFF) +endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") option(BUILD_sdjournal "Build sdjournal" ON) else() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 129adeaf62..5dd284936c 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -65,6 +65,7 @@ pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/editcap 1) pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/mergecap 1) pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/randpkt 1) pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/randpktdump 1) +pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/etwdump 1) pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/rawshark 1) pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/reordercap 1) pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/sshdump 1) @@ -107,6 +108,7 @@ set(MAN1_INSTALL_FILES ${CMAKE_CURRENT_BINARY_DIR}/mergecap.1 ${CMAKE_CURRENT_BINARY_DIR}/randpkt.1 ${CMAKE_CURRENT_BINARY_DIR}/randpktdump.1 + ${CMAKE_CURRENT_BINARY_DIR}/etwdump.1 ${CMAKE_CURRENT_BINARY_DIR}/rawshark.1 ${CMAKE_CURRENT_BINARY_DIR}/reordercap.1 ${CMAKE_CURRENT_BINARY_DIR}/sshdump.1 @@ -164,6 +166,7 @@ set(HTML_INSTALL_FILES ${CMAKE_CURRENT_BINARY_DIR}/mergecap.html ${CMAKE_CURRENT_BINARY_DIR}/randpkt.html ${CMAKE_CURRENT_BINARY_DIR}/randpktdump.html + ${CMAKE_CURRENT_BINARY_DIR}/etwdump.html ${CMAKE_CURRENT_BINARY_DIR}/rawshark.html ${CMAKE_CURRENT_BINARY_DIR}/reordercap.html ${CMAKE_CURRENT_BINARY_DIR}/sshdump.html diff --git a/doc/etwdump.pod b/doc/etwdump.pod new file mode 100644 index 0000000000..07ebdd85fc --- /dev/null +++ b/doc/etwdump.pod @@ -0,0 +1,130 @@ +=begin man + +=encoding utf8 + +=end man + +=head1 NAME + +etwdump - Provide an interface to read ETW + +=head1 SYNOPSIS + +B +S<[ B<--help> ]> +S<[ B<--version> ]> +S<[ B<--extcap-interfaces> ]> +S<[ B<--extcap-dlts> ]> +S<[ B<--extcap-interface>=EinterfaceE ]> +S<[ B<--extcap-config> ]> +S<[ B<--capture> ]> +S<[ B<--fifo>=Epath to file or pipeE ]> +S<[ B<--iue>=EShould undecidable events be includedE ]> +S<[ B<--etlfile>=Eetl fileE ]> + +=head1 DESCRIPTION + +B is a extcap tool that provides access to a etl file. +It is only used to display event trace on Windows. + +=head1 OPTIONS + +=over 4 + +=item --help + +Print program arguments. + +=item --version + +Print program version. + +=item --extcap-interfaces + +List available interfaces. + +=item --extcap-interface=EinterfaceE + +Use specified interfaces. + +=item --extcap-dlts + +List DLTs of specified interface. + +=item --extcap-config + +List configuration options of specified interface. + +=item --capture + +Start capturing from specified interface save saved it in place specified by --fifo. + +=item --fifo=Epath to file or pipeE + +Save captured packet to file or send it through pipe. + +=item --iue=EShould undecidable events be includedE + +Choose if the undecidable event is included. + +=item --etlfile=EEtl fileE + +Select etl file to display in Wireshark. + +=back + +=head1 EXAMPLES + +To see program arguments: + + etwdump --help + +To see program version: + + etwdump --version + +To see interfaces: + + etwdump --extcap-interfaces + + Example output: + interface {value=etwdump}{display=ETW reader} + +To see interface DLTs: + + etwdump --extcap-interface=etwdump --extcap-dlts + + Example output: + dlt {number=1}{name=etwdump}{display=DLT_ETW} + +To see interface configuration options: + + etwdump --extcap-interface=etwdump --extcap-config + + Example output: + arg {number=0}{call=--iue}{display=Should undecidable events be included}{type=boolflag}{default=false}{tooltip=Choose if the undecidable event is included}{group=Capture} + arg {number=1}{call=--etlfile}{display=etl file}{type=fileselect}{tooltip=Select etl file to display in Wireshark}{required=true}{group=Capture} + +To capture: + + etwdump --extcap-interface=etwdump --fifo=/tmp/etw.pcapng --capture + +NOTE: To stop capturing CTRL+C/kill/terminate application. + +=head1 SEE ALSO + +wireshark(1), tshark(1), dumpcap(1), extcap(4) + +=head1 NOTES + +B is part of the B distribution. The latest version +of B can be found at L. + +HTML versions of the Wireshark project man pages are available at: +L. + +=head1 AUTHORS + + Original Author + --------------- + Odysseus Yang L diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt index 56e9986193..90b641fc1b 100644 --- a/epan/dissectors/CMakeLists.txt +++ b/epan/dissectors/CMakeLists.txt @@ -1027,6 +1027,7 @@ set(DISSECTOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/packet-ethertype.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-etsi_card_app_toolkit.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-etv.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-etw.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-evrc.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-evs.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-exablaze.c diff --git a/epan/dissectors/packet-etw.c b/epan/dissectors/packet-etw.c new file mode 100644 index 0000000000..93b9378c2a --- /dev/null +++ b/epan/dissectors/packet-etw.c @@ -0,0 +1,334 @@ +/* packet-etw.c + * Routines for ETW Dissection + * + * Copyright 2020, Odysseus Yang + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* Dissector based on ETW Trace +* https://docs.microsoft.com/en-us/windows/win32/etw/event-tracing-portal +*/ + +#include "config.h" + +#include + +void proto_register_etw(void); +void proto_reg_handoff_etw(void); + +static int proto_etw = -1; +static int hf_etw_size = -1; +static int hf_etw_header_type = -1; +static int hf_etw_flags = -1; +static int hf_etw_event_property = -1; +static int hf_etw_thread_id = -1; +static int hf_etw_process_id = -1; +static int hf_etw_time_stamp = -1; +static int hf_etw_provider_id = -1; +static int hf_etw_buffer_context_processor_number = -1; +static int hf_etw_buffer_context_alignment = -1; +static int hf_etw_buffer_context_logger_id = -1; +static int hf_etw_message_length = -1; +static int hf_etw_provider_name_length = -1; +static int hf_etw_provider_name = -1; +static int hf_etw_message = -1; +static int hf_etw_user_data_length = -1; +static int hf_etw_descriptor_id = -1; +static int hf_etw_descriptor_version = -1; +static int hf_etw_descriptor_channel = -1; +static int hf_etw_descriptor_level = -1; +static int hf_etw_descriptor_opcode = -1; +static int hf_etw_descriptor_task = -1; +static int hf_etw_descriptor_keywords = -1; +static int hf_etw_processor_time = -1; +static int hf_etw_activity_id = -1; + +static gint ett_etw_header = -1; +static gint ett_etw_descriptor = -1; +static gint ett_etw_buffer_context = -1; + +static dissector_handle_t mbim_dissector; + +static e_guid_t mbim_net_providerid = { 0xA42FE227, 0xA7BF, 0x4483, {0xA5, 0x02, 0x6B, 0xCD, 0xA4, 0x28, 0xCD, 0x96} }; + +#define ROUND_UP_COUNT(Count,Pow2) \ + ( ((Count)+(Pow2)-1) & (~(((int)(Pow2))-1)) ) +#define ETW_HEADER_SIZE 0x60 + +static int etw_counter = 0; + +static int +dissect_etw(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree _U_, void* data _U_) +{ + proto_tree* etw_header, * etw_descriptor, * etw_buffer_context; + tvbuff_t* mbim_tvb; + guint32 message_offset, message_length, provider_name_offset, provider_name_length, user_data_offset, user_data_length; + e_guid_t provider_id; + gint offset = 0; + + etw_header = proto_tree_add_subtree(tree, tvb, 0, ETW_HEADER_SIZE, ett_etw_header, NULL, "ETW Header"); + proto_tree_add_item(etw_header, hf_etw_size, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(etw_header, hf_etw_header_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(etw_header, hf_etw_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(etw_header, hf_etw_event_property, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(etw_header, hf_etw_thread_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(etw_header, hf_etw_process_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(etw_header, hf_etw_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + tvb_get_letohguid(tvb, offset, &provider_id); + proto_tree_add_item(etw_header, hf_etw_provider_id, tvb, offset, 16, ENC_LITTLE_ENDIAN); + offset += 16; + + etw_descriptor = proto_tree_add_subtree(etw_header, tvb, 40, 16, ett_etw_descriptor, NULL, "Descriptor"); + proto_tree_add_item(etw_descriptor, hf_etw_descriptor_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(etw_descriptor, hf_etw_descriptor_version, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(etw_descriptor, hf_etw_descriptor_channel, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(etw_descriptor, hf_etw_descriptor_level, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(etw_descriptor, hf_etw_descriptor_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(etw_descriptor, hf_etw_descriptor_task, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(etw_descriptor, hf_etw_descriptor_keywords, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + proto_tree_add_item(etw_header, hf_etw_processor_time, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + proto_tree_add_item(etw_header, hf_etw_activity_id, tvb, offset, 16, ENC_LITTLE_ENDIAN); + offset += 16; + + etw_buffer_context = proto_tree_add_subtree(etw_header, tvb, 80, 4, ett_etw_descriptor, NULL, "Buffer Context"); + proto_tree_add_item(etw_buffer_context, hf_etw_buffer_context_processor_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(etw_buffer_context, hf_etw_buffer_context_alignment, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + proto_tree_add_item(etw_buffer_context, hf_etw_buffer_context_logger_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item_ret_uint(etw_header, hf_etw_user_data_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &user_data_length); + offset += 4; + proto_tree_add_item_ret_uint(etw_header, hf_etw_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &message_length); + offset += 4; + proto_tree_add_item_ret_uint(etw_header, hf_etw_provider_name_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &provider_name_length); + offset += 4; + user_data_offset = offset; + message_offset = user_data_offset + ROUND_UP_COUNT(user_data_length, sizeof(gint32)); + if (message_length) { + proto_tree_add_item(etw_header, hf_etw_message, tvb, message_offset, message_length, ENC_LITTLE_ENDIAN | ENC_UTF_16); + } + provider_name_offset = message_offset + ROUND_UP_COUNT(message_length, sizeof(gint32)); + if (provider_name_length) { + proto_tree_add_item(etw_header, hf_etw_provider_name, tvb, provider_name_offset, provider_name_length, ENC_LITTLE_ENDIAN | ENC_UTF_16); + } + + col_set_str(pinfo->cinfo, COL_DEF_SRC, "windows"); + col_set_str(pinfo->cinfo, COL_DEF_DST, "windows"); + if (memcmp(&mbim_net_providerid, &provider_id, sizeof(e_guid_t)) == 0) { + if (pinfo->rec->presence_flags & WTAP_HAS_PACK_FLAGS) { + switch(pinfo->rec->rec_header.packet_header.pack_flags) { + case 1: + col_set_str(pinfo->cinfo, COL_DEF_SRC, "device"); + col_set_str(pinfo->cinfo, COL_DEF_DST, "host"); + break; + case 2: + col_set_str(pinfo->cinfo, COL_DEF_SRC, "host"); + col_set_str(pinfo->cinfo, COL_DEF_DST, "device"); + break; + } + } + mbim_tvb = tvb_new_subset_remaining(tvb, user_data_offset); + call_dissector_only(mbim_dissector, mbim_tvb, pinfo, tree, data); + } + else if (message_length){ + char* message = (char*)tvb_get_string_enc(wmem_packet_scope(), tvb, message_offset, message_length, ENC_LITTLE_ENDIAN | ENC_UTF_16); + col_set_str(pinfo->cinfo, COL_INFO, message); + if (provider_name_offset) { + char* provider_name = (char*)tvb_get_string_enc(wmem_packet_scope(), tvb, provider_name_offset, provider_name_length, ENC_LITTLE_ENDIAN | ENC_UTF_16); + col_set_str(pinfo->cinfo, COL_PROTOCOL, provider_name); + } + } else { + col_set_str(pinfo->cinfo, COL_INFO, guids_resolve_guid_to_str(&provider_id)); + } + + etw_counter += 1; + return tvb_captured_length(tvb); +} + +void +proto_register_etw(void) +{ + static hf_register_info hf[] = { + { &hf_etw_size, + { "Size", "etw.size", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_header_type, + { "Header Type", "etw.header_type", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_flags, + { "Flags", "etw.flags", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_event_property, + { "Event Property", "etw.event_property", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_thread_id, + { "Thread ID", "etw.thread_id", + FT_UINT32, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_process_id, + { "Process ID", "etw.process_id", + FT_UINT32, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_time_stamp, + { "Time Stamp", "etw.time_stamp", + FT_UINT64, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_provider_id, + { "Provider ID", "etw.provider_id", + FT_GUID, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_buffer_context_processor_number, + { "Processor Number", "etw.buffer_context.processor_number", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_buffer_context_alignment, + { "Alignment", "etw.buffer_context.alignment", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_buffer_context_logger_id, + { "ID", "etw.buffer_context.logger_id", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_message_length, + { "Message Length", "etw.message_length", + FT_UINT32, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_provider_name_length, + { "Provider Name Length", "etw.provider_name_length", + FT_UINT32, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_provider_name, + { "Provider Name", "etw.provider_name", + FT_STRINGZ, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_message, + { "Event Message", "etw.message", + FT_STRINGZ, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_user_data_length, + { "User Data Length", "etw.user_data_length", + FT_UINT32, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_descriptor_id, + { "ID", "etw.descriptor.id", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_descriptor_version, + { "Version", "etw.descriptor.version", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_descriptor_channel, + { "Channel", "etw.descriptor.channel", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_descriptor_level, + { "Level", "etw.descriptor.level", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_descriptor_opcode, + { "Opcode", "etw.descriptor.opcode", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_descriptor_task, + { "Task", "etw.descriptor.task", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_descriptor_keywords, + { "Keywords", "etw.descriptor.keywords", + FT_UINT64, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_processor_time, + { "Processor Time", "etw.processor_time", + FT_UINT64, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_etw_activity_id, + { "Activity ID", "etw.activity_id", + FT_GUID, BASE_NONE, NULL, 0, + NULL, HFILL } + } + }; + + static gint *ett[] = { + &ett_etw_header, + &ett_etw_descriptor, + &ett_etw_buffer_context + }; + + proto_etw = proto_register_protocol("Event Trace Windows", "ETW", "etw"); + proto_register_field_array(proto_etw, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_reg_handoff_etw(void) +{ + static dissector_handle_t etw_handle; + + etw_handle = create_dissector_handle(dissect_etw, proto_etw); + dissector_add_uint("wtap_encap", WTAP_ENCAP_ETL, etw_handle); + + mbim_dissector = find_dissector("mbim.control"); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/dissectors/packet-mbim.c b/epan/dissectors/packet-mbim.c index eb01f008e1..db3d003b4e 100644 --- a/epan/dissectors/packet-mbim.c +++ b/epan/dissectors/packet-mbim.c @@ -2612,14 +2612,20 @@ static const value_string mbim_uicc_file_structure_vals[] = { static guint8 mbim_dissect_service_id_uuid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint hf, - gint *offset, struct mbim_uuid_ext **uuid_ext_info) + gint *offset, struct mbim_uuid_ext **uuid_ext_info, gboolean is_net_guid) { e_guid_t uuid; guint i; guint32 uuid_ext[4]; - tvb_get_ntohguid(tvb, *offset, &uuid); - + if (is_net_guid) + { + tvb_get_ntohguid(tvb, *offset, &uuid); + } + else + { + tvb_get_letohguid(tvb, *offset, &uuid); + } for (i = 0; i < UUID_MAX; i++) { if (memcmp(&uuid, &(mbim_uuid_service_id_vals[i].uuid), sizeof(e_guid_t)) == 0) { break; @@ -3483,7 +3489,7 @@ mbim_dissect_device_service_element(tvbuff_t *tvb, packet_info *pinfo, proto_tre guint32 i, cid_count, cid; struct mbim_uuid_ext *uuid_ext_info = NULL; - uuid_idx = mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_device_service_element_device_service_id, &offset, &uuid_ext_info); + uuid_idx = mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_device_service_element_device_service_id, &offset, &uuid_ext_info, TRUE); proto_tree_add_bitmask(tree, tvb, offset, hf_mbim_device_service_element_dss_payload, ett_mbim_bitmap, mbim_device_service_element_dss_payload_fields, ENC_LITTLE_ENDIAN); offset += 4; @@ -3555,7 +3561,7 @@ mbim_dissect_event_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gi guint32 i, cid_count, cid; struct mbim_uuid_ext *uuid_ext_info = NULL; - uuid_idx = mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_event_entry_device_service_id, &offset, &uuid_ext_info); + uuid_idx = mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_event_entry_device_service_id, &offset, &uuid_ext_info, TRUE); proto_tree_add_item_ret_uint(tree, hf_mbim_event_entry_cid_count, tvb, offset, 4, ENC_LITTLE_ENDIAN, &cid_count); offset += 4; for (i = 0; i < cid_count; i++) { @@ -4524,7 +4530,7 @@ mbim_dissect_set_dss_connect(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree * guint32 dss_session_id; struct mbim_uuid_ext *uuid_ext_info = NULL; - mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_set_dss_connect_device_service_id, &offset, &uuid_ext_info); + mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_set_dss_connect_device_service_id, &offset, &uuid_ext_info, TRUE); dss_session_id = tvb_get_letohl(tvb, offset); dissector_delete_uint("mbim.dss_session_id", dss_session_id, NULL); if ((dss_session_id <= 255) && uuid_ext_info && uuid_ext_info->dss_handle) { @@ -4540,7 +4546,7 @@ mbim_dissect_muticarrier_current_cid_list_req(tvbuff_t *tvb, packet_info *pinfo { guint8 service_idx; - service_idx = mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_multicarrier_current_cid_list_req_uuid, &offset, NULL); + service_idx = mbim_dissect_service_id_uuid(tvb, pinfo, tree, hf_mbim_multicarrier_current_cid_list_req_uuid, &offset, NULL, TRUE); if (service_idx != UUID_MULTICARRIER) { expert_add_info_format(pinfo, NULL, &ei_mbim_unexpected_uuid_value, "Unexpected UUID value, should be UUID_MULTICARRIER"); @@ -5574,7 +5580,7 @@ dissect_mbim_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * } } - uuid_idx = mbim_dissect_service_id_uuid(frag_tvb, pinfo, mbim_tree, hf_mbim_device_service_id, &offset, &uuid_ext_info); + uuid_idx = mbim_dissect_service_id_uuid(frag_tvb, pinfo, mbim_tree, hf_mbim_device_service_id, &offset, &uuid_ext_info, pinfo->rec->rec_header.packet_header.pkt_encap != WTAP_ENCAP_ETL); cid = mbim_dissect_cid(frag_tvb, pinfo, mbim_tree, &offset, uuid_idx, uuid_ext_info); proto_tree_add_item_ret_uint(mbim_tree, hf_mbim_command_type, frag_tvb, offset, 4, ENC_LITTLE_ENDIAN, &cmd_type); if (mbim_info) { @@ -6462,7 +6468,7 @@ dissect_mbim_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * } } - uuid_idx = mbim_dissect_service_id_uuid(frag_tvb, pinfo, mbim_tree, hf_mbim_device_service_id, &offset, &uuid_ext_info); + uuid_idx = mbim_dissect_service_id_uuid(frag_tvb, pinfo, mbim_tree, hf_mbim_device_service_id, &offset, &uuid_ext_info, pinfo->rec->rec_header.packet_header.pkt_encap != WTAP_ENCAP_ETL); cid = mbim_dissect_cid(frag_tvb, pinfo, mbim_tree, &offset, uuid_idx, uuid_ext_info); if (msg_type == MBIM_COMMAND_DONE) { proto_tree_add_item(mbim_tree, hf_mbim_status, frag_tvb, offset, 4, ENC_LITTLE_ENDIAN); diff --git a/extcap/CMakeLists.txt b/extcap/CMakeLists.txt index 39389aced1..f59fd55838 100644 --- a/extcap/CMakeLists.txt +++ b/extcap/CMakeLists.txt @@ -246,6 +246,33 @@ if(BUILD_randpktdump) add_dependencies(extcaps randpktdump) endif() + +if(BUILD_etwdump AND WIN32) + set(etwdump_LIBS + wiretap + wsutil + tdh + ${GLIB2_LIBRARIES} + ${ZLIB_LIBRARIES} + ${CMAKE_DL_LIBS} + ${WIN_WS2_32_LIBRARY} + ) + set(etwdump_FILES + $ + $ + etwdump.c + etl.c + etw_message.c + ) + + set_executable_resources(etwdump "etwdump") + add_executable(etwdump ${etwdump_FILES}) + set_extcap_executable_properties(etwdump) + target_link_libraries(etwdump ${etwdump_LIBS}) + install(TARGETS etwdump RUNTIME DESTINATION ${EXTCAP_INSTALL_LIBDIR}) + add_dependencies(extcaps etwdump) +endif() + if(BUILD_sdjournal AND SYSTEMD_FOUND) set(sdjournal_LIBS wiretap diff --git a/extcap/etl.c b/extcap/etl.c new file mode 100644 index 0000000000..0aac40751b --- /dev/null +++ b/extcap/etl.c @@ -0,0 +1,438 @@ +/* etl.c + * + * Copyright 2020, Odysseus Yang + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + /* + https://docs.microsoft.com/en-us/windows/win32/etw/event-tracing-portal + */ + +#include "config.h" +#include "etl.h" + +#include "etw_message.h" + +#define MAX_PACKET_SIZE 0xFFFF +#define G_NSEC_PER_SEC 1000000000 +#define ADD_OFFSET_TO_POINTER(buffer, offset) (((PBYTE)buffer) + offset) +#define ROUND_UP_COUNT(Count,Pow2) \ + ( ((Count)+(Pow2)-1) & (~(((int)(Pow2))-1)) ) + +extern int g_include_undecidable_event; + +const GUID mbb_provider = { 0xA42FE227, 0xA7BF, 0x4483, {0xA5, 0x02, 0x6B, 0xCD, 0xA4, 0x28, 0xCD, 0x96} }; + +EXTERN_C const GUID DECLSPEC_SELECTANY EventTraceGuid = { 0x68fdd900, 0x4a3e, 0x11d1, {0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3} }; +EXTERN_C const GUID DECLSPEC_SELECTANY ImageIdGuid = { 0xb3e675d7, 0x2554, 0x4f18, { 0x83, 0xb, 0x27, 0x62, 0x73, 0x25, 0x60, 0xde } }; +EXTERN_C const GUID DECLSPEC_SELECTANY SystemConfigExGuid = { 0x9b79ee91, 0xb5fd, 0x41c0, { 0xa2, 0x43, 0x42, 0x48, 0xe2, 0x66, 0xe9, 0xd0 } }; +EXTERN_C const GUID DECLSPEC_SELECTANY EventMetadataGuid = { 0xbbccf6c1, 0x6cd1, 0x48c4, {0x80, 0xff, 0x83, 0x94, 0x82, 0xe3, 0x76, 0x71 } }; + +typedef struct _WTAP_ETL_RECORD { + EVENT_HEADER EventHeader; // Event header + ETW_BUFFER_CONTEXT BufferContext; // Buffer context + ULONG UserDataLength; + ULONG MessageLength; + ULONG ProviderLength; +} WTAP_ETL_RECORD; + +static gchar g_err_info[FILENAME_MAX] = { 0 }; +static int g_err = ERROR_SUCCESS; +static wtap_dumper* g_pdh = NULL; +extern ULONGLONG g_num_events; + +static void WINAPI event_callback(PEVENT_RECORD ev); +void etw_dump_write_opn_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp); +void etw_dump_write_general_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp); +void etw_dump_write_event_head_only(PEVENT_RECORD ev, ULARGE_INTEGER timestamp); +void wtap_etl_rec_dump(ULARGE_INTEGER timestamp, WTAP_ETL_RECORD* etl_record, ULONG total_packet_length, BOOLEAN is_inbound); +wtap_dumper* etw_dump_open(const char* pcapng_filename, int* err, gchar** err_info); + +wtap_open_return_val etw_dump(const char* etl_filename, const char* pcapng_filename, int* err, gchar** err_info) +{ + EVENT_TRACE_LOGFILE log_file; + TRACEHANDLE trace_handle = INVALID_PROCESSTRACE_HANDLE; + WCHAR w_etl_filename[FILENAME_MAX] = { 0 }; + WCHAR w_pcapng_filename[FILENAME_MAX] = { 0 }; + ULONG trace_error; + wtap_open_return_val returnVal = WTAP_OPEN_MINE; + + SecureZeroMemory(g_err_info, FILENAME_MAX); + g_err = ERROR_SUCCESS; + g_num_events = 0; + + /* do/while(FALSE) is used to jump out of loop so no complex nested if/else is needed */ + do + { + mbstowcs(w_etl_filename, etl_filename, FILENAME_MAX); + mbstowcs(w_pcapng_filename, pcapng_filename, FILENAME_MAX); + + SecureZeroMemory(&log_file, sizeof(log_file)); + log_file.LogFileName = w_etl_filename; + log_file.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD; + log_file.EventRecordCallback = event_callback; + log_file.Context = NULL; + + trace_handle = OpenTrace(&log_file); + if (trace_handle == INVALID_PROCESSTRACE_HANDLE) { + *err_info = g_strdup_printf("OpenTrace failed with %u", err); + returnVal = WTAP_OPEN_NOT_MINE; + break; + } + + g_pdh = etw_dump_open(pcapng_filename, err, err_info); + if (g_pdh == NULL) + { + returnVal = WTAP_OPEN_ERROR; + break; + } + + trace_error = ProcessTrace(&trace_handle, 1, 0, 0); + if (trace_error != ERROR_SUCCESS) { + returnVal = WTAP_OPEN_ERROR; + break; + } + + if (g_err != ERROR_SUCCESS) + { + *err = g_err; + *err_info = g_strdup(g_err_info); + returnVal = WTAP_OPEN_ERROR; + break; + } + + if (!g_num_events) { + *err_info = g_strdup_printf("Didn't find any etw event"); + returnVal = WTAP_OPEN_NOT_MINE; + break; + } + } while (FALSE); + + if (trace_handle != INVALID_PROCESSTRACE_HANDLE) + { + CloseTrace(trace_handle); + } + if (g_pdh != NULL) + { + if (!wtap_dump_close(g_pdh, err, err_info)) + { + returnVal = WTAP_OPEN_ERROR; + } + } + return returnVal; +} + +static void WINAPI event_callback(PEVENT_RECORD ev) +{ + ULARGE_INTEGER timestamp; + g_num_events++; + /* + * 100ns since 1/1/1601 -> usec since 1/1/1970. + * The offset of 11644473600 seconds can be calculated with a couple of calls to SystemTimeToFileTime. + */ + timestamp.QuadPart = (ev->EventHeader.TimeStamp.QuadPart / 10) - 11644473600000000ll; + + /* Write OPN events that needs mbim sub dissector */ + if (IsEqualGUID(&ev->EventHeader.ProviderId, &mbb_provider)) + { + etw_dump_write_opn_event(ev, timestamp); + } + /* TODO:: You can write events from other providers that needs specific sub dissector */ +#if 0 + else if (IsEqualGUID(&ev->EventHeader.ProviderId, &ndis_packcapture_provider)) + { + etw_dump_write_packet_event(ev, timestamp); + } +#endif + /* Write any event form other providers other than above */ + else + { + etw_dump_write_general_event(ev, timestamp); + } +} + +wtap_dumper* etw_dump_open(const char* pcapng_filename, int* err, gchar** err_info) +{ + wtap_dump_params params = { 0 }; + GArray* shb_hdrs = NULL; + wtap_block_t shb_hdr; + wtapng_iface_descriptions_t* idb_info; + GArray* idb_datas; + wtap_block_t idb_data; + wtapng_if_descr_mandatory_t* descr_mand; + + wtap_dumper* pdh = NULL; + + shb_hdrs = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); + shb_hdr = wtap_block_create(WTAP_BLOCK_NG_SECTION); + g_array_append_val(shb_hdrs, shb_hdr); + + /* In the future, may create multiple WTAP_BLOCK_IF_DESCR separately for IP packet */ + idb_info = g_new(wtapng_iface_descriptions_t, 1); + idb_datas = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); + idb_data = wtap_block_create(WTAP_BLOCK_IF_DESCR); + descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(idb_data); + descr_mand->tsprecision = WTAP_TSPREC_USEC; + descr_mand->wtap_encap = WTAP_ENCAP_ETL; + /* Timestamp for each pcapng packet is usec units, so time_units_per_second need be set to 10^6 */ + descr_mand->time_units_per_second = G_USEC_PER_SEC; + g_array_append_val(idb_datas, idb_data); + idb_info->interface_data = idb_datas; + + params.encap = WTAP_ENCAP_ETL; + params.snaplen = 0; + params.tsprec = WTAP_TSPREC_USEC; + params.shb_hdrs = shb_hdrs; + params.idb_inf = idb_info; + + pdh = wtap_dump_open(pcapng_filename, WTAP_FILE_TYPE_SUBTYPE_PCAPNG, WTAP_UNCOMPRESSED, ¶ms, err, err_info); + + if (shb_hdrs) + { + wtap_block_array_free(shb_hdrs); + } + if (params.idb_inf) + { + if (params.idb_inf->interface_data) + { + wtap_block_array_free(params.idb_inf->interface_data); + } + g_free(params.idb_inf); + params.idb_inf = NULL; + } + + return pdh; +} + +ULONG wtap_etl_record_buffer_init(WTAP_ETL_RECORD** out_etl_record, PEVENT_RECORD ev, BOOLEAN include_user_data, WCHAR* message, WCHAR* provider_name) +{ + ULONG total_packet_length = sizeof(WTAP_ETL_RECORD); + WTAP_ETL_RECORD* etl_record = NULL; + ULONG user_data_length = 0; + ULONG user_data_offset = 0; + ULONG message_offset = 0; + ULONG provider_name_offset = 0; + ULONG message_length = 0; + ULONG provider_name_length = 0; + + if (include_user_data) + { + if (ev->UserDataLength < MAX_PACKET_SIZE) + { + user_data_length = ev->UserDataLength; + } + else + { + user_data_length = MAX_PACKET_SIZE; + } + user_data_offset = sizeof(WTAP_ETL_RECORD); + total_packet_length += ROUND_UP_COUNT(user_data_length, sizeof(LONG)); + } + if (message && message[0] != L'\0') + { + message_offset = total_packet_length; + message_length = (ULONG)((wcslen(message) + 1) * sizeof(WCHAR)); + total_packet_length += ROUND_UP_COUNT(message_length, sizeof(LONG)); + } + if (provider_name && provider_name[0] != L'\0') + { + provider_name_offset = total_packet_length; + provider_name_length = (ULONG)((wcslen(provider_name) + 1) * sizeof(WCHAR)); + total_packet_length += ROUND_UP_COUNT(provider_name_length, sizeof(LONG)); + } + + etl_record = g_malloc(total_packet_length); + SecureZeroMemory(etl_record, total_packet_length); + etl_record->EventHeader = ev->EventHeader; + etl_record->BufferContext = ev->BufferContext; + etl_record->UserDataLength = user_data_length; + etl_record->MessageLength = message_length; + etl_record->ProviderLength = provider_name_length; + + if (user_data_offset) + { + memcpy(ADD_OFFSET_TO_POINTER(etl_record, user_data_offset), ev->UserData, user_data_length); + } + if (message_offset) + { + memcpy(ADD_OFFSET_TO_POINTER(etl_record, message_offset), message, message_length); + } + if (provider_name_offset) + { + memcpy(ADD_OFFSET_TO_POINTER(etl_record, provider_name_offset), provider_name, provider_name_length); + } + + *out_etl_record = etl_record; + return total_packet_length; +} + +void wtap_etl_rec_dump(ULARGE_INTEGER timestamp, WTAP_ETL_RECORD* etl_record, ULONG total_packet_length, BOOLEAN is_inbound) +{ + gchar* err_info; + int err; + wtap_rec rec = { 0 }; + + wtap_rec_init(&rec); + rec.rec_header.packet_header.caplen = total_packet_length; + rec.rec_header.packet_header.len = total_packet_length; + rec.rec_header.packet_header.pkt_encap = WTAP_ENCAP_ETL; + rec.presence_flags = rec.presence_flags | WTAP_HAS_PACK_FLAGS; + rec.rec_header.packet_header.pack_flags = is_inbound ? 1 : 2; + /* Convert usec of the timestamp into nstime_t */ + rec.ts.secs = (time_t)(timestamp.QuadPart / G_USEC_PER_SEC); + rec.ts.nsecs = (int)(((timestamp.QuadPart % G_USEC_PER_SEC) * G_NSEC_PER_SEC) / G_USEC_PER_SEC); + + /* and save the packet */ + if (!wtap_dump(g_pdh, &rec, (guint8*)etl_record, &err, &err_info)) { + g_err = err; + sprintf_s(g_err_info, sizeof(g_err_info), "wtap_dump failed, %s", err_info); + g_free(err_info); + } + wtap_rec_cleanup(&rec); +} + +void etw_dump_write_opn_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp) +{ + WTAP_ETL_RECORD* etl_record = NULL; + ULONG total_packet_length = 0; + BOOLEAN is_inbound = FALSE; + /* 0x80000000 mask the function to host message */ + is_inbound = ((*(INT32*)(ev->UserData)) & 0x80000000) ? TRUE : FALSE; + total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, TRUE, NULL, NULL); + wtap_etl_rec_dump(timestamp, etl_record, total_packet_length, is_inbound); + g_free(etl_record); +} + +void etw_dump_write_event_head_only(PEVENT_RECORD ev, ULARGE_INTEGER timestamp) +{ + WTAP_ETL_RECORD* etl_record = NULL; + ULONG total_packet_length = 0; + total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, FALSE, NULL, NULL); + wtap_etl_rec_dump(timestamp, etl_record, total_packet_length, FALSE); + g_free(etl_record); +} + +void etw_dump_write_general_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp) +{ + PTRACE_EVENT_INFO pInfo = NULL; + PBYTE pUserData = NULL; + PBYTE pEndOfUserData = NULL; + DWORD PointerSize = 0; + PROPERTY_KEY_VALUE* prop_arr = NULL; + DWORD dwTopLevelPropertyCount = 0; + DWORD dwSizeofArray = 0; + WCHAR wszMessageBuffer[MAX_LOG_LINE_LENGTH] = { 0 }; + WCHAR formatMessage[MAX_LOG_LINE_LENGTH] = { 0 }; + + WTAP_ETL_RECORD* etl_record = NULL; + ULONG total_packet_length = 0; + BOOLEAN is_message_dumped = FALSE; + + do + { + /* Skip EventTrace events */ + if (ev->EventHeader.Flags & EVENT_HEADER_FLAG_CLASSIC_HEADER && + IsEqualGUID(&ev->EventHeader.ProviderId, &EventTraceGuid)) + { + /* + * The first event in every ETL file contains the data from the file header. + * This is the same data as was returned in the EVENT_TRACE_LOGFILEW by + * OpenTrace. Since we've already seen this information, we'll skip this + * event. + */ + break; + } + + /* Skip events injected by the XPerf tracemerger - they will never be decodable */ + if (IsEqualGUID(&ev->EventHeader.ProviderId, &ImageIdGuid) || + IsEqualGUID(&ev->EventHeader.ProviderId, &SystemConfigExGuid) || + IsEqualGUID(&ev->EventHeader.ProviderId, &EventMetadataGuid)) + { + break; + } + + if (!get_event_information(ev, &pInfo)) + { + break; + } + + /* Skip those events without format message since most of them need special logic to decode like NDIS-PackCapture */ + if (pInfo->EventMessageOffset <= 0) + { + break; + } + + if (EVENT_HEADER_FLAG_32_BIT_HEADER == (ev->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER)) + { + PointerSize = 4; + } + else + { + PointerSize = 8; + } + + pUserData = (PBYTE)ev->UserData; + pEndOfUserData = (PBYTE)ev->UserData + ev->UserDataLength; + + dwTopLevelPropertyCount = pInfo->TopLevelPropertyCount; + if (dwTopLevelPropertyCount > 0) + { + prop_arr = g_malloc(sizeof(PROPERTY_KEY_VALUE) * dwTopLevelPropertyCount); + dwSizeofArray = dwTopLevelPropertyCount * sizeof(PROPERTY_KEY_VALUE); + SecureZeroMemory(prop_arr, dwSizeofArray); + } + + StringCbCopy(formatMessage, MAX_LOG_LINE_LENGTH, (LPWSTR)ADD_OFFSET_TO_POINTER(pInfo, pInfo->EventMessageOffset)); + + for (USHORT i = 0; i < dwTopLevelPropertyCount; i++) + { + pUserData = extract_properties(ev, pInfo, PointerSize, i, pUserData, pEndOfUserData, &prop_arr[i]); + if (NULL == pUserData) + { + break; + } + } + + format_message(formatMessage, prop_arr, dwTopLevelPropertyCount, wszMessageBuffer, sizeof(wszMessageBuffer)); + + total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, FALSE, wszMessageBuffer, (WCHAR*)ADD_OFFSET_TO_POINTER(pInfo, pInfo->ProviderNameOffset)); + wtap_etl_rec_dump(timestamp, etl_record, total_packet_length, FALSE); + g_free(etl_record); + + is_message_dumped = TRUE; + } while (FALSE); + + if (NULL != prop_arr) + { + g_free(prop_arr); + prop_arr = NULL; + } + if (NULL != pInfo) + { + g_free(pInfo); + pInfo = NULL; + } + + if (!is_message_dumped && g_include_undecidable_event) + { + etw_dump_write_event_head_only(ev, timestamp); + } +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/extcap/etl.h b/extcap/etl.h new file mode 100644 index 0000000000..7410de3a85 --- /dev/null +++ b/extcap/etl.h @@ -0,0 +1,42 @@ +/* etl.h +* + * Copyright 2020, Odysseus Yang + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __W_ETL_H__ +#define __W_ETL_H__ + +#include "wiretap/wtap.h" +#include "ws_symbol_export.h" +#include "wiretap/wtap-int.h" + +#include +#include +#include +#include +#include +#include + +wtap_open_return_val etw_dump(const char* etl_filename, const char* pcapng_filename, int* err, gchar** err_info); + +#endif + + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/extcap/etw_message.c b/extcap/etw_message.c new file mode 100644 index 0000000000..fa74d8b637 --- /dev/null +++ b/extcap/etw_message.c @@ -0,0 +1,416 @@ +/* etw_message.h + * + * Copyright 2020, Odysseus Yang + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "etw_message.h" +ULONGLONG g_num_events = 0; + +VOID format_message(WCHAR* lpszMessage, PROPERTY_KEY_VALUE* propArray, DWORD dwPropertyCount, WCHAR* lpszOutBuffer, DWORD dwOutBufferCount) +{ + DWORD startLoc = 0; + int percent_loc = 0; + + for (int i = 0; lpszMessage[i] != L'\0';) + { + if (lpszMessage[i] != L'%') + { + i++; + continue; + } + if (lpszMessage[i + 1] == '%') + { + i += 2; + continue; + } + + percent_loc = i; + i++; + + if (iswdigit(lpszMessage[i])) + { + DWORD dwDigitalCount = 0; + WCHAR smallBuffer[MAX_SMALL_BUFFER] = { 0 }; + while (iswdigit(lpszMessage[i])) + { + if (dwDigitalCount < (MAX_SMALL_BUFFER - 1)) + { + smallBuffer[dwDigitalCount] = lpszMessage[i]; + } + dwDigitalCount++; + i++; + } + + /* We are not parsing this */ + if (dwDigitalCount >= (MAX_SMALL_BUFFER - 1)) + { + continue; + } + DWORD num = _wtoi(smallBuffer); + /* We are not parsing this */ + if (num == 0 || num > dwPropertyCount || propArray[num - 1].value[0] == L'\0') + { + continue; + } + + if (lpszMessage[i] == L'!' && lpszMessage[i + 1] == L'S' && lpszMessage[i + 2] == L'!') + { + i += 3; + } + + /* We have everything */ + lpszMessage[percent_loc] = L'\0'; + StringCbCat(lpszOutBuffer, dwOutBufferCount, lpszMessage + startLoc); + StringCbCat(lpszOutBuffer, dwOutBufferCount, propArray[num - 1].value); + startLoc = i; + continue; // for + } + } + StringCbCat(lpszOutBuffer, dwOutBufferCount, lpszMessage + startLoc); +} + +/* +* Get the length of the property data. For MOF-based events, the size is inferred from the data type +* of the property. For manifest-based events, the property can specify the size of the property value +* using the length attribute. The length attribue can specify the size directly or specify the name +* of another property in the event data that contains the size. If the property does not include the +* length attribute, the size is inferred from the data type. The length will be zero for variable +* length, null-terminated strings and structures. +*/ +DWORD GetPropertyLength(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT PropertyLength) +{ + DWORD status = ERROR_SUCCESS; + PROPERTY_DATA_DESCRIPTOR DataDescriptor = { 0 }; + DWORD PropertySize = 0; + + /* + * If the property is a binary blob and is defined in a manifest, the property can + * specify the blob's size or it can point to another property that defines the + * blob's size. The PropertyParamLength flag tells you where the blob's size is defined. + */ + if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamLength) == PropertyParamLength) + { + DWORD Length = 0; // Expects the length to be defined by a UINT16 or UINT32 + DWORD j = pInfo->EventPropertyInfoArray[i].lengthPropertyIndex; + DataDescriptor.PropertyName = ((ULONGLONG)(pInfo)+(ULONGLONG)pInfo->EventPropertyInfoArray[j].NameOffset); + DataDescriptor.ArrayIndex = ULONG_MAX; + status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize); + status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Length); + *PropertyLength = (USHORT)Length; + } + else + { + if (pInfo->EventPropertyInfoArray[i].length > 0) + { + *PropertyLength = pInfo->EventPropertyInfoArray[i].length; + } + else + { + /* + * If the property is a binary blob and is defined in a MOF class, the extension + * qualifier is used to determine the size of the blob. However, if the extension + * is IPAddrV6, you must set the PropertyLength variable yourself because the + * EVENT_PROPERTY_INFO.length field will be zero. + */ + if (TDH_INTYPE_BINARY == pInfo->EventPropertyInfoArray[i].nonStructType.InType && + TDH_OUTTYPE_IPV6 == pInfo->EventPropertyInfoArray[i].nonStructType.OutType) + { + *PropertyLength = (USHORT)sizeof(IN6_ADDR); + } + else if (TDH_INTYPE_UNICODESTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType || + TDH_INTYPE_ANSISTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType || + (pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct) + { + *PropertyLength = pInfo->EventPropertyInfoArray[i].length; + } + else + { + g_debug("Event %d Unexpected length of 0 for intype %d and outtype %d", g_num_events, + pInfo->EventPropertyInfoArray[i].nonStructType.InType, + pInfo->EventPropertyInfoArray[i].nonStructType.OutType); + + status = ERROR_EVT_INVALID_EVENT_DATA; + goto cleanup; + } + } + } +cleanup: + return status; +} + +DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize) +{ + DWORD status = ERROR_SUCCESS; + PROPERTY_DATA_DESCRIPTOR DataDescriptor = { 0 }; + DWORD PropertySize = 0; + + if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount) + { + /* Expects the count to be defined by a UINT16 or UINT32 */ + DWORD Count = 0; + DWORD j = pInfo->EventPropertyInfoArray[i].countPropertyIndex; + DataDescriptor.PropertyName = ((ULONGLONG)(pInfo)+(ULONGLONG)(pInfo->EventPropertyInfoArray[j].NameOffset)); + DataDescriptor.ArrayIndex = ULONG_MAX; + status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize); + status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Count); + *ArraySize = (USHORT)Count; + } + else + { + *ArraySize = pInfo->EventPropertyInfoArray[i].count; + } + return status; +} + +DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, PEVENT_MAP_INFO* pMapInfo) +{ + DWORD status = ERROR_SUCCESS; + DWORD MapSize = 0; + + /* Retrieve the required buffer size for the map info. */ + status = TdhGetEventMapInformation(pEvent, pMapName, *pMapInfo, &MapSize); + if (ERROR_INSUFFICIENT_BUFFER == status) + { + *pMapInfo = (PEVENT_MAP_INFO)g_malloc(MapSize); + if (*pMapInfo == NULL) + { + status = ERROR_OUTOFMEMORY; + goto cleanup; + } + /* Retrieve the map info. */ + status = TdhGetEventMapInformation(pEvent, pMapName, *pMapInfo, &MapSize); + } + + if (ERROR_NOT_FOUND == status) + { + /* This case is okay. */ + status = ERROR_SUCCESS; + } + +cleanup: + + return status; +} + + +PBYTE extract_properties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData, PROPERTY_KEY_VALUE* pExtract) +{ + TDHSTATUS status = ERROR_SUCCESS; + USHORT PropertyLength = 0; + USHORT UserDataConsumed = 0; + /* Last member of a structure */ + DWORD LastMember = 0; + USHORT ArraySize = 0; + PEVENT_MAP_INFO pMapInfo = NULL; + WCHAR formatted_data[MAX_LOG_LINE_LENGTH]; + DWORD formatted_data_size = sizeof(formatted_data); + LPWSTR oversize_formatted_data = NULL; + + do + { + StringCbCopy(pExtract->key, sizeof(pExtract->key), (PWCHAR)((PBYTE)(pInfo)+pInfo->EventPropertyInfoArray[i].NameOffset)); + /* Get the length of the property. */ + status = GetPropertyLength(pEvent, pInfo, i, &PropertyLength); + if (ERROR_SUCCESS != status) + { + StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: GetPropertyLength failed 0x%x", pExtract->key, status); + break; + } + + /* Get the size of the array if the property is an array. */ + status = GetArraySize(pEvent, pInfo, i, &ArraySize); + if (ERROR_SUCCESS != status) + { + StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: GetArraySize failed 0x%x", pExtract->key, status); + break; + } + + /* Add [] for an array property */ + if (ArraySize > 1) + { + StringCbCat(pExtract->value, sizeof(pExtract->value), L"["); + } + + for (USHORT k = 0; k < ArraySize; k++) + { + /* Add array item separator "," */ + if (k > 0) + { + StringCbCat(pExtract->value, sizeof(pExtract->value), L","); + } + /* If the property is a structure, print the members of the structure. */ + if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct) + { + /* Add {} for an array property */ + StringCbCat(pExtract->value, sizeof(pExtract->value), L"{"); + /* Add struct member separator ";" */ + if (k > 0) + { + StringCbCat(pExtract->value, sizeof(pExtract->value), L";"); + } + LastMember = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex + + pInfo->EventPropertyInfoArray[i].structType.NumOfStructMembers; + + for (USHORT j = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < LastMember; j++) + { + pUserData = extract_properties(pEvent, pInfo, PointerSize, j, pUserData, pEndOfUserData, pExtract); + if (NULL == pUserData) + { + StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: extract_properties of member %d failed 0x%x", pExtract->key, j, status); + break; + } + } + StringCbCat(pExtract->value, sizeof(pExtract->value), L"}"); + } + else + { + /* Get the name/value mapping only at the first time if the property specifies a value map. */ + if (pMapInfo == NULL) + { + status = GetMapInfo(pEvent, + (PWCHAR)((PBYTE)(pInfo)+pInfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset), + &pMapInfo); + + if (ERROR_SUCCESS != status) + { + StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: GetMapInfo failed 0x%x", pExtract->key, status); + break; + } + } + + /* Get the size of the buffer required for the formatted data. */ + + status = TdhFormatProperty( + pInfo, + pMapInfo, + PointerSize, + pInfo->EventPropertyInfoArray[i].nonStructType.InType, + pInfo->EventPropertyInfoArray[i].nonStructType.OutType, + PropertyLength, + (USHORT)(pEndOfUserData - pUserData), + pUserData, + &formatted_data_size, + formatted_data, + &UserDataConsumed); + + if (ERROR_INSUFFICIENT_BUFFER == status) + { + if (oversize_formatted_data) + { + g_free(oversize_formatted_data); + oversize_formatted_data = NULL; + } + + oversize_formatted_data = (LPWSTR)g_malloc(formatted_data_size); + if (oversize_formatted_data == NULL) + { + status = ERROR_OUTOFMEMORY; + StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: Allocate FormattedData memory (size %d) for array item %d failed 0x%x", pExtract->key, formatted_data_size, k, status); + break; + } + + /* Retrieve the formatted data. */ + status = TdhFormatProperty( + pInfo, + pMapInfo, + PointerSize, + pInfo->EventPropertyInfoArray[i].nonStructType.InType, + pInfo->EventPropertyInfoArray[i].nonStructType.OutType, + PropertyLength, + (USHORT)(pEndOfUserData - pUserData), + pUserData, + &formatted_data_size, + oversize_formatted_data, + &UserDataConsumed); + } + + if (ERROR_SUCCESS == status) + { + if (formatted_data_size > sizeof(formatted_data) && oversize_formatted_data != NULL) + { + /* Any oversize FormattedData will be truncated */ + StringCbCat(pExtract->value, sizeof(pExtract->value), oversize_formatted_data); + } + else + { + StringCbCat(pExtract->value, sizeof(pExtract->value), formatted_data); + } + pUserData += UserDataConsumed; + } + else + { + StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: TdhFormatProperty for array item %d failed 0x%x", pExtract->key, k, status); + break; + } + } + } + /* Add [] for an array property */ + if (ArraySize > 1) + { + StringCbCat(pExtract->value, sizeof(pExtract->value), L"]"); + } + } while (FALSE); + + if (oversize_formatted_data) + { + g_free(oversize_formatted_data); + oversize_formatted_data = NULL; + } + if (pMapInfo) + { + g_free(pMapInfo); + pMapInfo = NULL; + } + + return (ERROR_SUCCESS == status) ? pUserData : NULL; +} + + +BOOL get_event_information(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO* pInfo) +{ + BOOL bReturn = FALSE; + DWORD status; + DWORD BufferSize = 0; + + /* Retrieve the required buffer size for the event metadata. */ + status = TdhGetEventInformation(pEvent, 0, NULL, *pInfo, &BufferSize); + if (ERROR_INSUFFICIENT_BUFFER == status) + { + *pInfo = (TRACE_EVENT_INFO*)g_malloc(BufferSize); + if (*pInfo == NULL) + { + g_debug("Event %d GetEventInformation Failed to allocate memory for event info (size=%lu).", g_num_events, BufferSize); + goto Exit; + } + /* Retrieve the event metadata. */ + status = TdhGetEventInformation(pEvent, 0, NULL, *pInfo, &BufferSize); + } + + if (ERROR_SUCCESS != status) + { + goto Exit; + } + bReturn = TRUE; +Exit: + + return bReturn; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/extcap/etw_message.h b/extcap/etw_message.h new file mode 100644 index 0000000000..b88e320233 --- /dev/null +++ b/extcap/etw_message.h @@ -0,0 +1,60 @@ +/* etl.h +* + * Copyright 2020, Odysseus Yang + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __W_ETW_MESSAGE_H__ +#define __W_ETW_MESSAGE_H__ + +#include +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#define MAX_SMALL_BUFFER 4 +#define MAX_LOG_LINE_LENGTH 1024 +#define MAX_KEY_LENGTH 64 + +typedef struct Property_Key_Value +{ + WCHAR key[MAX_KEY_LENGTH]; + WCHAR value[MAX_LOG_LINE_LENGTH]; +} PROPERTY_KEY_VALUE; + +typedef struct in6_addr { + union { + UCHAR Byte[16]; + USHORT Word[8]; + } u; +} IN6_ADDR, * PIN6_ADDR, FAR* LPIN6_ADDR; + +VOID format_message(WCHAR* lpszMessage, PROPERTY_KEY_VALUE* propArray, DWORD dwPropertyCount, WCHAR* lpszOutBuffer, DWORD dwOutBufferCount); +BOOL get_event_information(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO* pInfo); +PBYTE extract_properties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData, PROPERTY_KEY_VALUE* pExtract); + +#endif + + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/extcap/etwdump.c b/extcap/etwdump.c new file mode 100644 index 0000000000..dcc0e293cf --- /dev/null +++ b/extcap/etwdump.c @@ -0,0 +1,262 @@ +/* etwdump.c + * etwdump is an extcap tool used to dump etw to pcapng + * + * Copyright 2020, Odysseus Yang + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include "extcap-base.h" + +#include +#include +#include +#include + +#include +#include +#include "etl.h" + +/* extcap-interface has to be unique, or it may use wrong option output by a different extcapbin */ +#define ETW_EXTCAP_INTERFACE "etwdump" +#define ETWDUMP_VERSION_MAJOR "1" +#define ETWDUMP_VERSION_MINOR "0" +#define ETWDUMP_VERSION_RELEASE "0" + +enum { + EXTCAP_BASE_OPTIONS_ENUM, + OPT_HELP, + OPT_VERSION, + OPT_INCLUDE_UNDECIDABLE_EVENT, + OPT_ETLFILE +}; + +static struct option longopts[] = { + EXTCAP_BASE_OPTIONS, + { "help", no_argument, NULL, OPT_HELP}, + { "version", no_argument, NULL, OPT_VERSION}, + { "iue", optional_argument, NULL, OPT_INCLUDE_UNDECIDABLE_EVENT}, + { "etlfile", required_argument, NULL, OPT_ETLFILE}, + { 0, 0, 0, 0 } +}; + +int g_include_undecidable_event = FALSE; + +static void help(extcap_parameters* extcap_conf) +{ + extcap_help_print(extcap_conf); +} + +static int list_config(char* interface) +{ + unsigned inc = 0; + + if (!interface) { + g_warning("No interface specified."); + return EXIT_FAILURE; + } + + if (g_strcmp0(interface, ETW_EXTCAP_INTERFACE)) { + g_warning("Interface must be %s", ETW_EXTCAP_INTERFACE); + return EXIT_FAILURE; + } + /* Saved for later live capture support */ +#if 0 + printf("arg {number=%u}{call=--type}{display=Capture type}" + "{type=selector}{tooltip=Choose the type of capture}{group=Capture}\n", + inc); + printf("value {arg=%u}{value=etl}{display=From a etl file}\n", inc); + printf("value {arg=%u}{value=live}{display=From a live session}\n", inc); + inc++; +#endif + /* + * The undecidable events are those that either don't have sub-dissector or don't have anthing meaningful to display except for the EVENT_HEADER. + */ + printf("arg {number=%u}{call=--iue}{display=Should undecidable events be included}" + "{type=boolflag}{default=false}{tooltip=Choose if the undecidable event is included}{group=Capture}\n", + inc++); + printf("arg {number=%u}{call=--etlfile}{display=etl file}" + "{type=fileselect}{tooltip=Select etl file to display in Wireshark}{required=true}{group=Capture}\n", + inc++); + /* Saved for later live capture support */ +#if 0 + printf("arg {number=%u}{call=--session-params}{display=Live session parameters}" + "{type=string}{tooltip=providers, keyword and level}{group=Capture}\n", + inc++); +#endif + + extcap_config_debug(&inc); + return EXIT_SUCCESS; +} + +int main(int argc, char* argv[]) +{ + char* err_msg; + int option_idx = 0; + int result; + int ret = EXIT_FAILURE; + + char* etlfile = NULL; + + extcap_parameters* extcap_conf = g_new0(extcap_parameters, 1); + char* help_url; + char* help_header = NULL; + + /* + * Get credential information for later use. + */ + init_process_policies(); + + /* + * Attempt to get the pathname of the directory containing the + * executable file. + */ + err_msg = init_progfile_dir(argv[0]); + if (err_msg != NULL) { + g_warning("Can't get pathname of directory containing the captype program: %s.", + err_msg); + g_free(err_msg); + } + + help_url = data_file_url("etwdump.html"); + extcap_base_set_util_info(extcap_conf, argv[0], ETWDUMP_VERSION_MAJOR, ETWDUMP_VERSION_MINOR, + ETWDUMP_VERSION_RELEASE, help_url); + g_free(help_url); + extcap_base_register_interface(extcap_conf, ETW_EXTCAP_INTERFACE, "ETW reader", 290, "DLT_ETW"); + + help_header = g_strdup_printf( + " %s --extcap-interfaces\n" + " %s --extcap-interface=%s --extcap-dlts\n" + " %s --extcap-interface=%s --extcap-config\n" + " %s --extcap-interface=%s --etlfile c:\\wwansvc.etl \n" + "--fifo=FILENAME --capture\n", argv[0], argv[0], ETW_EXTCAP_INTERFACE, argv[0], ETW_EXTCAP_INTERFACE, + argv[0], ETW_EXTCAP_INTERFACE); + extcap_help_add_header(extcap_conf, help_header); + g_free(help_header); + + extcap_help_add_option(extcap_conf, "--help", "print this help"); + extcap_help_add_option(extcap_conf, "--version", "print the version"); + extcap_help_add_option(extcap_conf, "--etlfile ", "A etl filename"); + extcap_help_add_option(extcap_conf, "--iue", "Choose if undecidable event is included"); + + if (argc == 1) { + help(extcap_conf); + goto end; + } + + while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) { + switch (result) { + case OPT_VERSION: + extcap_version_print(extcap_conf); + ret = EXIT_SUCCESS; + goto end; + + case OPT_HELP: + help(extcap_conf); + ret = EXIT_SUCCESS; + goto end; + + case OPT_ETLFILE: + etlfile = g_strdup(optarg); + break; + + case OPT_INCLUDE_UNDECIDABLE_EVENT: + g_include_undecidable_event = TRUE; + break; + + case ':': + /* missing option argument */ + g_warning("Option '%s' requires an argument", argv[optind - 1]); + break; + + default: + /* Handle extcap specific options */ + if (!extcap_base_parse_options(extcap_conf, result - EXTCAP_OPT_LIST_INTERFACES, optarg)) + { + g_warning("Invalid option: %s", argv[optind - 1]); + goto end; + } + } + } + + extcap_cmdline_debug(argv, argc); + + if (extcap_base_handle_interface(extcap_conf)) { + ret = EXIT_SUCCESS; + goto end; + } + + if (extcap_conf->show_config) { + ret = list_config(extcap_conf->interface); + goto end; + } + + if (extcap_conf->capture) { + + if (g_strcmp0(extcap_conf->interface, ETW_EXTCAP_INTERFACE)) { + g_warning("ERROR: invalid interface"); + goto end; + } + + wtap_init(FALSE); + + switch(etw_dump(etlfile, extcap_conf->fifo, &ret, &err_msg)) + { + case WTAP_OPEN_ERROR: + if (err_msg != NULL) { + g_warning("etw_dump failed: %s.", + err_msg); + g_free(err_msg); + } + else + { + g_warning("etw_dump failed"); + } + break; + case WTAP_OPEN_NOT_MINE: + if (err_msg != NULL) { + g_warning("The file %s is not etl format. Error message: %s.", + etlfile, err_msg); + g_free(err_msg); + } + else + { + g_warning("The file %s is not etl format"); + } + break; + case WTAP_OPEN_MINE: + ret = EXIT_SUCCESS; + break; + } + } + +end: + /* clean up stuff */ + extcap_base_cleanup(&extcap_conf); + + if (etlfile != NULL) + { + g_free(etlfile); + } + + return ret; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/packaging/nsis/wireshark.nsi b/packaging/nsis/wireshark.nsi index f96a14a574..7af2a5c6e5 100644 --- a/packaging/nsis/wireshark.nsi +++ b/packaging/nsis/wireshark.nsi @@ -1183,6 +1183,12 @@ Section /o "Randpktdump" SecRandpktdump SectionEnd !insertmacro CheckExtrasFlag "randpktdump" +Section /o "Etwdump" SecEtwdump +;------------------------------------------- + !insertmacro InstallExtcap "Etwdump" +SectionEnd +!insertmacro CheckExtrasFlag "Etwdump" + SectionGroupEnd ; "Tools" !ifdef DOCBOOK_DIR @@ -1232,6 +1238,7 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${SecSshdump} "Provide remote capture through SSH" !insertmacro MUI_DESCRIPTION_TEXT ${SecUDPdump} "Provide capture interface that gets UDP packets from network devices" !insertmacro MUI_DESCRIPTION_TEXT ${SecRandpktdump} "Provide random packet generator" + !insertmacro MUI_DESCRIPTION_TEXT ${SecEtwdump} "Provide ETW reader" !insertmacro MUI_DESCRIPTION_TEXT ${SecEditCap} "Copy packets to a new file, optionally trimmming packets, omitting them, or saving to a different format." !insertmacro MUI_DESCRIPTION_TEXT ${SecText2Pcap} "Read an ASCII hex dump and write the data into a libpcap-style capture file." !insertmacro MUI_DESCRIPTION_TEXT ${SecMergecap} "Combine multiple saved capture files into a single output file" diff --git a/packaging/wix/ComponentGroups.wxi b/packaging/wix/ComponentGroups.wxi index 5468978bfd..59c6a1c84a 100644 --- a/packaging/wix/ComponentGroups.wxi +++ b/packaging/wix/ComponentGroups.wxi @@ -471,6 +471,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/wix/Features.wxi b/packaging/wix/Features.wxi index eb37b11f95..58837cba21 100644 --- a/packaging/wix/Features.wxi +++ b/packaging/wix/Features.wxi @@ -89,6 +89,9 @@ + + + diff --git a/wiretap/pcap-common.c b/wiretap/pcap-common.c index e7e367f343..406b1c04e0 100644 --- a/wiretap/pcap-common.c +++ b/wiretap/pcap-common.c @@ -481,6 +481,9 @@ static const struct { /* USB 2.0/1.1/1.0 packets as transmitted over the cable */ { 288, WTAP_ENCAP_USB_2_0 }, + + /* windows ETL*/ + { 290, WTAP_ENCAP_ETL}, /* * To repeat: * diff --git a/wiretap/wtap.h b/wiretap/wtap.h index e01b30c461..6f8f35f969 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -292,6 +292,7 @@ extern "C" { #define WTAP_ENCAP_MP4 209 #define WTAP_ENCAP_SLL2 210 #define WTAP_ENCAP_ZWAVE_SERIAL 211 +#define WTAP_ENCAP_ETL 212 /* After adding new item here, please also add new item to encap_table_base array */