aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOdysseus Yang <wiresharkyyh@outlook.com>2020-12-02 09:05:11 +0000
committerAndersBroman <a.broman58@gmail.com>2020-12-02 09:05:11 +0000
commit2a5b34d8b02b1663237490eec5dfd8652a9bdb51 (patch)
tree5acf1640ab708e32a172a00763145e41e19c5089
parentfe1f9475409f252b6ca2dccc71187868e168c74b (diff)
MBIM: Update dissector to support DLT_ETW
New link type DLT_ETW is added for write and read Event Trace on Windows. This change updates MBIM dissector to decode a MBIM message from a DLT_ETW packet.
-rw-r--r--CMakeLists.txt2
-rw-r--r--CMakeOptions.txt6
-rw-r--r--doc/CMakeLists.txt3
-rw-r--r--doc/etwdump.pod130
-rw-r--r--epan/dissectors/CMakeLists.txt1
-rw-r--r--epan/dissectors/packet-etw.c334
-rw-r--r--epan/dissectors/packet-mbim.c24
-rw-r--r--extcap/CMakeLists.txt27
-rw-r--r--extcap/etl.c438
-rw-r--r--extcap/etl.h42
-rw-r--r--extcap/etw_message.c416
-rw-r--r--extcap/etw_message.h60
-rw-r--r--extcap/etwdump.c262
-rw-r--r--packaging/nsis/wireshark.nsi7
-rw-r--r--packaging/wix/ComponentGroups.wxi20
-rw-r--r--packaging/wix/Features.wxi3
-rw-r--r--wiretap/pcap-common.c3
-rw-r--r--wiretap/wtap.h1
18 files changed, 1770 insertions, 9 deletions
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<etwdump>
+S<[ B<--help> ]>
+S<[ B<--version> ]>
+S<[ B<--extcap-interfaces> ]>
+S<[ B<--extcap-dlts> ]>
+S<[ B<--extcap-interface>=E<lt>interfaceE<gt> ]>
+S<[ B<--extcap-config> ]>
+S<[ B<--capture> ]>
+S<[ B<--fifo>=E<lt>path to file or pipeE<gt> ]>
+S<[ B<--iue>=E<lt>Should undecidable events be includedE<gt> ]>
+S<[ B<--etlfile>=E<lt>etl fileE<gt> ]>
+
+=head1 DESCRIPTION
+
+B<etwdump> 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=E<lt>interfaceE<gt>
+
+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=E<lt>path to file or pipeE<gt>
+
+Save captured packet to file or send it through pipe.
+
+=item --iue=E<lt>Should undecidable events be includedE<gt>
+
+Choose if the undecidable event is included.
+
+=item --etlfile=E<lt>Etl fileE<gt>
+
+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<etwdump> is part of the B<Wireshark> distribution. The latest version
+of B<Wireshark> can be found at L<https://www.wireshark.org>.
+
+HTML versions of the Wireshark project man pages are available at:
+L<https://www.wireshark.org/docs/man-pages>.
+
+=head1 AUTHORS
+
+ Original Author
+ ---------------
+ Odysseus Yang L<wiresharkyyh@outlook.com>
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 <gerald@wireshark.org>
+ * 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 <epan/packet.h>
+
+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
+ $<TARGET_OBJECTS:cli_main>
+ $<TARGET_OBJECTS:extcap-base>
+ 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 <gerald@wireshark.org>
+ * 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, &params, 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 <gerald@wireshark.org>
+ * 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 <glib.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <strsafe.h>
+#include <tdh.h>
+#include <guiddef.h>
+
+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 <gerald@wireshark.org>
+ * 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 <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __W_ETW_MESSAGE_H__
+#define __W_ETW_MESSAGE_H__
+
+#include <glib.h>
+#include "config.h"
+
+#include <windows.h>
+#include <SDKDDKVer.h>
+#include <strsafe.h>
+#include <evntcons.h>
+#include <tdh.h>
+#include <stdlib.h>
+
+#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 <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include "extcap-base.h"
+
+#include <wsutil/strtoi.h>
+#include <wsutil/filesystem.h>
+#include <wsutil/privileges.h>
+#include <wsutil/please_report_bug.h>
+
+#include <cli_main.h>
+#include <ui/cmdarg_err.h>
+#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 <filename>", "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 @@
</ComponentGroup>
</Fragment>
+ <!-- Etwdump -->
+ <Fragment>
+ <DirectoryRef Id="dirExtcap">
+ <Component Id="cmpEtwdump_exe" Guid="*">
+ <File Id="filEtwdump_exe" KeyPath="yes" Source="$(var.Extcap.Dir)\etwdump.exe" />
+ </Component>
+ </DirectoryRef>
+ <DirectoryRef Id="INSTALLFOLDER">
+ <Component Id="cmpEtwdump_html" Guid="*">
+ <File Id="filEtwdump_html" KeyPath="yes" Source="$(var.Staging.Dir)\etwdump.html" />
+ </Component>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <ComponentGroup Id="CG.Tools.Etwdump">
+ <ComponentRef Id="cmpEtwdump_exe" />
+ <ComponentRef Id="cmpEtwdump_html" />
+ </ComponentGroup>
+ </Fragment>
+
<!-- Sshdump -->
<Fragment>
<DirectoryRef Id="dirExtcap">
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 @@
<Feature Id="Fe.Tools.Randpktdump" Title="Randpktdump" Level="2" AllowAdvertise="yes" Display="expand" Description="Provide random packet generator.">
<ComponentGroupRef Id="CG.Tools.Randpktdump" />
</Feature>
+ <Feature Id="Fe.Tools.Etwdump" Title="Etwdump" Level="2" AllowAdvertise="yes" Display="expand" Description="Provide ETW reader.">
+ <ComponentGroupRef Id="CG.Tools.Etwdump" />
+ </Feature>
<Feature Id="Fe.Tools.Sshdump" Title="Sshdump" Level="1" AllowAdvertise="yes" Display="expand" Description="Provide remote capture through SSH.">
<ComponentGroupRef Id="CG.Tools.Sshdump" />
</Feature>
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 */