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.
This commit is contained in:
Odysseus Yang 2020-12-02 09:05:11 +00:00 committed by AndersBroman
parent fe1f947540
commit 2a5b34d8b0
18 changed files with 1770 additions and 9 deletions

View File

@ -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}

View File

@ -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()

View File

@ -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

130
doc/etwdump.pod Normal file
View File

@ -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>

View File

@ -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

View File

@ -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:
*/

View File

@ -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);

View File

@ -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

438
extcap/etl.c Normal file
View File

@ -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:
*/

42
extcap/etl.h Normal file
View File

@ -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:
*/

416
extcap/etw_message.c Normal file
View File

@ -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:
*/

60
extcap/etw_message.h Normal file
View File

@ -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:
*/

262
extcap/etwdump.c Normal file
View File

@ -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:
*/

View File

@ -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"

View File

@ -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">

View File

@ -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>

View File

@ -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:
*

View File

@ -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 */