forked from osmocom/wireshark
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:
parent
fe1f947540
commit
2a5b34d8b0
|
@ -1816,6 +1816,7 @@ set(INSTALL_FILES
|
||||||
${CMAKE_BINARY_DIR}/doc/mergecap.html
|
${CMAKE_BINARY_DIR}/doc/mergecap.html
|
||||||
${CMAKE_BINARY_DIR}/doc/randpkt.html
|
${CMAKE_BINARY_DIR}/doc/randpkt.html
|
||||||
${CMAKE_BINARY_DIR}/doc/randpktdump.html
|
${CMAKE_BINARY_DIR}/doc/randpktdump.html
|
||||||
|
${CMAKE_BINARY_DIR}/doc/etwdump.html
|
||||||
${CMAKE_BINARY_DIR}/doc/rawshark.html
|
${CMAKE_BINARY_DIR}/doc/rawshark.html
|
||||||
${CMAKE_BINARY_DIR}/doc/reordercap.html
|
${CMAKE_BINARY_DIR}/doc/reordercap.html
|
||||||
${CMAKE_BINARY_DIR}/doc/sshdump.html
|
${CMAKE_BINARY_DIR}/doc/sshdump.html
|
||||||
|
@ -3170,6 +3171,7 @@ set(CLEAN_C_FILES
|
||||||
${dftest_FILES}
|
${dftest_FILES}
|
||||||
${randpkt_FILES}
|
${randpkt_FILES}
|
||||||
${randpktdump_FILES}
|
${randpktdump_FILES}
|
||||||
|
${etwdump_FILES}
|
||||||
${udpdump_FILES}
|
${udpdump_FILES}
|
||||||
${text2pcap_FILES}
|
${text2pcap_FILES}
|
||||||
${mergecap_FILES}
|
${mergecap_FILES}
|
||||||
|
|
|
@ -22,6 +22,12 @@ option(BUILD_sshdump "Build sshdump" ON)
|
||||||
option(BUILD_ciscodump "Build ciscodump" ON)
|
option(BUILD_ciscodump "Build ciscodump" ON)
|
||||||
option(BUILD_dpauxmon "Build dpauxmon" ON)
|
option(BUILD_dpauxmon "Build dpauxmon" ON)
|
||||||
option(BUILD_randpktdump "Build randpktdump" 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")
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
option(BUILD_sdjournal "Build sdjournal" ON)
|
option(BUILD_sdjournal "Build sdjournal" ON)
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -65,6 +65,7 @@ pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/editcap 1)
|
||||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/mergecap 1)
|
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/mergecap 1)
|
||||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/randpkt 1)
|
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/randpkt 1)
|
||||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/randpktdump 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}/rawshark 1)
|
||||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/reordercap 1)
|
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/reordercap 1)
|
||||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/sshdump 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}/mergecap.1
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/randpkt.1
|
${CMAKE_CURRENT_BINARY_DIR}/randpkt.1
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/randpktdump.1
|
${CMAKE_CURRENT_BINARY_DIR}/randpktdump.1
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/etwdump.1
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/rawshark.1
|
${CMAKE_CURRENT_BINARY_DIR}/rawshark.1
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/reordercap.1
|
${CMAKE_CURRENT_BINARY_DIR}/reordercap.1
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/sshdump.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}/mergecap.html
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/randpkt.html
|
${CMAKE_CURRENT_BINARY_DIR}/randpkt.html
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/randpktdump.html
|
${CMAKE_CURRENT_BINARY_DIR}/randpktdump.html
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/etwdump.html
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/rawshark.html
|
${CMAKE_CURRENT_BINARY_DIR}/rawshark.html
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/reordercap.html
|
${CMAKE_CURRENT_BINARY_DIR}/reordercap.html
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/sshdump.html
|
${CMAKE_CURRENT_BINARY_DIR}/sshdump.html
|
||||||
|
|
|
@ -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>
|
|
@ -1027,6 +1027,7 @@ set(DISSECTOR_SRC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-ethertype.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-ethertype.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-etsi_card_app_toolkit.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-etsi_card_app_toolkit.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-etv.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-evrc.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-evs.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-evs.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-exablaze.c
|
${CMAKE_CURRENT_SOURCE_DIR}/packet-exablaze.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:
|
||||||
|
*/
|
|
@ -2612,14 +2612,20 @@ static const value_string mbim_uicc_file_structure_vals[] = {
|
||||||
|
|
||||||
static guint8
|
static guint8
|
||||||
mbim_dissect_service_id_uuid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint hf,
|
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;
|
e_guid_t uuid;
|
||||||
guint i;
|
guint i;
|
||||||
guint32 uuid_ext[4];
|
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++) {
|
for (i = 0; i < UUID_MAX; i++) {
|
||||||
if (memcmp(&uuid, &(mbim_uuid_service_id_vals[i].uuid), sizeof(e_guid_t)) == 0) {
|
if (memcmp(&uuid, &(mbim_uuid_service_id_vals[i].uuid), sizeof(e_guid_t)) == 0) {
|
||||||
break;
|
break;
|
||||||
|
@ -3483,7 +3489,7 @@ mbim_dissect_device_service_element(tvbuff_t *tvb, packet_info *pinfo, proto_tre
|
||||||
guint32 i, cid_count, cid;
|
guint32 i, cid_count, cid;
|
||||||
struct mbim_uuid_ext *uuid_ext_info = NULL;
|
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,
|
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);
|
ett_mbim_bitmap, mbim_device_service_element_dss_payload_fields, ENC_LITTLE_ENDIAN);
|
||||||
offset += 4;
|
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;
|
guint32 i, cid_count, cid;
|
||||||
struct mbim_uuid_ext *uuid_ext_info = NULL;
|
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);
|
proto_tree_add_item_ret_uint(tree, hf_mbim_event_entry_cid_count, tvb, offset, 4, ENC_LITTLE_ENDIAN, &cid_count);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
for (i = 0; i < cid_count; i++) {
|
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;
|
guint32 dss_session_id;
|
||||||
struct mbim_uuid_ext *uuid_ext_info = NULL;
|
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);
|
dss_session_id = tvb_get_letohl(tvb, offset);
|
||||||
dissector_delete_uint("mbim.dss_session_id", dss_session_id, NULL);
|
dissector_delete_uint("mbim.dss_session_id", dss_session_id, NULL);
|
||||||
if ((dss_session_id <= 255) && uuid_ext_info && uuid_ext_info->dss_handle) {
|
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;
|
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) {
|
if (service_idx != UUID_MULTICARRIER) {
|
||||||
expert_add_info_format(pinfo, NULL, &ei_mbim_unexpected_uuid_value,
|
expert_add_info_format(pinfo, NULL, &ei_mbim_unexpected_uuid_value,
|
||||||
"Unexpected UUID value, should be UUID_MULTICARRIER");
|
"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);
|
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);
|
proto_tree_add_item_ret_uint(mbim_tree, hf_mbim_command_type, frag_tvb, offset, 4, ENC_LITTLE_ENDIAN, &cmd_type);
|
||||||
if (mbim_info) {
|
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);
|
cid = mbim_dissect_cid(frag_tvb, pinfo, mbim_tree, &offset, uuid_idx, uuid_ext_info);
|
||||||
if (msg_type == MBIM_COMMAND_DONE) {
|
if (msg_type == MBIM_COMMAND_DONE) {
|
||||||
proto_tree_add_item(mbim_tree, hf_mbim_status, frag_tvb, offset, 4, ENC_LITTLE_ENDIAN);
|
proto_tree_add_item(mbim_tree, hf_mbim_status, frag_tvb, offset, 4, ENC_LITTLE_ENDIAN);
|
||||||
|
|
|
@ -246,6 +246,33 @@ if(BUILD_randpktdump)
|
||||||
add_dependencies(extcaps randpktdump)
|
add_dependencies(extcaps randpktdump)
|
||||||
endif()
|
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)
|
if(BUILD_sdjournal AND SYSTEMD_FOUND)
|
||||||
set(sdjournal_LIBS
|
set(sdjournal_LIBS
|
||||||
wiretap
|
wiretap
|
||||||
|
|
|
@ -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, ¶ms, err, err_info);
|
||||||
|
|
||||||
|
if (shb_hdrs)
|
||||||
|
{
|
||||||
|
wtap_block_array_free(shb_hdrs);
|
||||||
|
}
|
||||||
|
if (params.idb_inf)
|
||||||
|
{
|
||||||
|
if (params.idb_inf->interface_data)
|
||||||
|
{
|
||||||
|
wtap_block_array_free(params.idb_inf->interface_data);
|
||||||
|
}
|
||||||
|
g_free(params.idb_inf);
|
||||||
|
params.idb_inf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG wtap_etl_record_buffer_init(WTAP_ETL_RECORD** out_etl_record, PEVENT_RECORD ev, BOOLEAN include_user_data, WCHAR* message, WCHAR* provider_name)
|
||||||
|
{
|
||||||
|
ULONG total_packet_length = sizeof(WTAP_ETL_RECORD);
|
||||||
|
WTAP_ETL_RECORD* etl_record = NULL;
|
||||||
|
ULONG user_data_length = 0;
|
||||||
|
ULONG user_data_offset = 0;
|
||||||
|
ULONG message_offset = 0;
|
||||||
|
ULONG provider_name_offset = 0;
|
||||||
|
ULONG message_length = 0;
|
||||||
|
ULONG provider_name_length = 0;
|
||||||
|
|
||||||
|
if (include_user_data)
|
||||||
|
{
|
||||||
|
if (ev->UserDataLength < MAX_PACKET_SIZE)
|
||||||
|
{
|
||||||
|
user_data_length = ev->UserDataLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user_data_length = MAX_PACKET_SIZE;
|
||||||
|
}
|
||||||
|
user_data_offset = sizeof(WTAP_ETL_RECORD);
|
||||||
|
total_packet_length += ROUND_UP_COUNT(user_data_length, sizeof(LONG));
|
||||||
|
}
|
||||||
|
if (message && message[0] != L'\0')
|
||||||
|
{
|
||||||
|
message_offset = total_packet_length;
|
||||||
|
message_length = (ULONG)((wcslen(message) + 1) * sizeof(WCHAR));
|
||||||
|
total_packet_length += ROUND_UP_COUNT(message_length, sizeof(LONG));
|
||||||
|
}
|
||||||
|
if (provider_name && provider_name[0] != L'\0')
|
||||||
|
{
|
||||||
|
provider_name_offset = total_packet_length;
|
||||||
|
provider_name_length = (ULONG)((wcslen(provider_name) + 1) * sizeof(WCHAR));
|
||||||
|
total_packet_length += ROUND_UP_COUNT(provider_name_length, sizeof(LONG));
|
||||||
|
}
|
||||||
|
|
||||||
|
etl_record = g_malloc(total_packet_length);
|
||||||
|
SecureZeroMemory(etl_record, total_packet_length);
|
||||||
|
etl_record->EventHeader = ev->EventHeader;
|
||||||
|
etl_record->BufferContext = ev->BufferContext;
|
||||||
|
etl_record->UserDataLength = user_data_length;
|
||||||
|
etl_record->MessageLength = message_length;
|
||||||
|
etl_record->ProviderLength = provider_name_length;
|
||||||
|
|
||||||
|
if (user_data_offset)
|
||||||
|
{
|
||||||
|
memcpy(ADD_OFFSET_TO_POINTER(etl_record, user_data_offset), ev->UserData, user_data_length);
|
||||||
|
}
|
||||||
|
if (message_offset)
|
||||||
|
{
|
||||||
|
memcpy(ADD_OFFSET_TO_POINTER(etl_record, message_offset), message, message_length);
|
||||||
|
}
|
||||||
|
if (provider_name_offset)
|
||||||
|
{
|
||||||
|
memcpy(ADD_OFFSET_TO_POINTER(etl_record, provider_name_offset), provider_name, provider_name_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_etl_record = etl_record;
|
||||||
|
return total_packet_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wtap_etl_rec_dump(ULARGE_INTEGER timestamp, WTAP_ETL_RECORD* etl_record, ULONG total_packet_length, BOOLEAN is_inbound)
|
||||||
|
{
|
||||||
|
gchar* err_info;
|
||||||
|
int err;
|
||||||
|
wtap_rec rec = { 0 };
|
||||||
|
|
||||||
|
wtap_rec_init(&rec);
|
||||||
|
rec.rec_header.packet_header.caplen = total_packet_length;
|
||||||
|
rec.rec_header.packet_header.len = total_packet_length;
|
||||||
|
rec.rec_header.packet_header.pkt_encap = WTAP_ENCAP_ETL;
|
||||||
|
rec.presence_flags = rec.presence_flags | WTAP_HAS_PACK_FLAGS;
|
||||||
|
rec.rec_header.packet_header.pack_flags = is_inbound ? 1 : 2;
|
||||||
|
/* Convert usec of the timestamp into nstime_t */
|
||||||
|
rec.ts.secs = (time_t)(timestamp.QuadPart / G_USEC_PER_SEC);
|
||||||
|
rec.ts.nsecs = (int)(((timestamp.QuadPart % G_USEC_PER_SEC) * G_NSEC_PER_SEC) / G_USEC_PER_SEC);
|
||||||
|
|
||||||
|
/* and save the packet */
|
||||||
|
if (!wtap_dump(g_pdh, &rec, (guint8*)etl_record, &err, &err_info)) {
|
||||||
|
g_err = err;
|
||||||
|
sprintf_s(g_err_info, sizeof(g_err_info), "wtap_dump failed, %s", err_info);
|
||||||
|
g_free(err_info);
|
||||||
|
}
|
||||||
|
wtap_rec_cleanup(&rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etw_dump_write_opn_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp)
|
||||||
|
{
|
||||||
|
WTAP_ETL_RECORD* etl_record = NULL;
|
||||||
|
ULONG total_packet_length = 0;
|
||||||
|
BOOLEAN is_inbound = FALSE;
|
||||||
|
/* 0x80000000 mask the function to host message */
|
||||||
|
is_inbound = ((*(INT32*)(ev->UserData)) & 0x80000000) ? TRUE : FALSE;
|
||||||
|
total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, TRUE, NULL, NULL);
|
||||||
|
wtap_etl_rec_dump(timestamp, etl_record, total_packet_length, is_inbound);
|
||||||
|
g_free(etl_record);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etw_dump_write_event_head_only(PEVENT_RECORD ev, ULARGE_INTEGER timestamp)
|
||||||
|
{
|
||||||
|
WTAP_ETL_RECORD* etl_record = NULL;
|
||||||
|
ULONG total_packet_length = 0;
|
||||||
|
total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, FALSE, NULL, NULL);
|
||||||
|
wtap_etl_rec_dump(timestamp, etl_record, total_packet_length, FALSE);
|
||||||
|
g_free(etl_record);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etw_dump_write_general_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp)
|
||||||
|
{
|
||||||
|
PTRACE_EVENT_INFO pInfo = NULL;
|
||||||
|
PBYTE pUserData = NULL;
|
||||||
|
PBYTE pEndOfUserData = NULL;
|
||||||
|
DWORD PointerSize = 0;
|
||||||
|
PROPERTY_KEY_VALUE* prop_arr = NULL;
|
||||||
|
DWORD dwTopLevelPropertyCount = 0;
|
||||||
|
DWORD dwSizeofArray = 0;
|
||||||
|
WCHAR wszMessageBuffer[MAX_LOG_LINE_LENGTH] = { 0 };
|
||||||
|
WCHAR formatMessage[MAX_LOG_LINE_LENGTH] = { 0 };
|
||||||
|
|
||||||
|
WTAP_ETL_RECORD* etl_record = NULL;
|
||||||
|
ULONG total_packet_length = 0;
|
||||||
|
BOOLEAN is_message_dumped = FALSE;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Skip EventTrace events */
|
||||||
|
if (ev->EventHeader.Flags & EVENT_HEADER_FLAG_CLASSIC_HEADER &&
|
||||||
|
IsEqualGUID(&ev->EventHeader.ProviderId, &EventTraceGuid))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The first event in every ETL file contains the data from the file header.
|
||||||
|
* This is the same data as was returned in the EVENT_TRACE_LOGFILEW by
|
||||||
|
* OpenTrace. Since we've already seen this information, we'll skip this
|
||||||
|
* event.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip events injected by the XPerf tracemerger - they will never be decodable */
|
||||||
|
if (IsEqualGUID(&ev->EventHeader.ProviderId, &ImageIdGuid) ||
|
||||||
|
IsEqualGUID(&ev->EventHeader.ProviderId, &SystemConfigExGuid) ||
|
||||||
|
IsEqualGUID(&ev->EventHeader.ProviderId, &EventMetadataGuid))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!get_event_information(ev, &pInfo))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip those events without format message since most of them need special logic to decode like NDIS-PackCapture */
|
||||||
|
if (pInfo->EventMessageOffset <= 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVENT_HEADER_FLAG_32_BIT_HEADER == (ev->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER))
|
||||||
|
{
|
||||||
|
PointerSize = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PointerSize = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pUserData = (PBYTE)ev->UserData;
|
||||||
|
pEndOfUserData = (PBYTE)ev->UserData + ev->UserDataLength;
|
||||||
|
|
||||||
|
dwTopLevelPropertyCount = pInfo->TopLevelPropertyCount;
|
||||||
|
if (dwTopLevelPropertyCount > 0)
|
||||||
|
{
|
||||||
|
prop_arr = g_malloc(sizeof(PROPERTY_KEY_VALUE) * dwTopLevelPropertyCount);
|
||||||
|
dwSizeofArray = dwTopLevelPropertyCount * sizeof(PROPERTY_KEY_VALUE);
|
||||||
|
SecureZeroMemory(prop_arr, dwSizeofArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringCbCopy(formatMessage, MAX_LOG_LINE_LENGTH, (LPWSTR)ADD_OFFSET_TO_POINTER(pInfo, pInfo->EventMessageOffset));
|
||||||
|
|
||||||
|
for (USHORT i = 0; i < dwTopLevelPropertyCount; i++)
|
||||||
|
{
|
||||||
|
pUserData = extract_properties(ev, pInfo, PointerSize, i, pUserData, pEndOfUserData, &prop_arr[i]);
|
||||||
|
if (NULL == pUserData)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format_message(formatMessage, prop_arr, dwTopLevelPropertyCount, wszMessageBuffer, sizeof(wszMessageBuffer));
|
||||||
|
|
||||||
|
total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, FALSE, wszMessageBuffer, (WCHAR*)ADD_OFFSET_TO_POINTER(pInfo, pInfo->ProviderNameOffset));
|
||||||
|
wtap_etl_rec_dump(timestamp, etl_record, total_packet_length, FALSE);
|
||||||
|
g_free(etl_record);
|
||||||
|
|
||||||
|
is_message_dumped = TRUE;
|
||||||
|
} while (FALSE);
|
||||||
|
|
||||||
|
if (NULL != prop_arr)
|
||||||
|
{
|
||||||
|
g_free(prop_arr);
|
||||||
|
prop_arr = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != pInfo)
|
||||||
|
{
|
||||||
|
g_free(pInfo);
|
||||||
|
pInfo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_message_dumped && g_include_undecidable_event)
|
||||||
|
{
|
||||||
|
etw_dump_write_event_head_only(ev, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||||
|
*
|
||||||
|
* Local variables:
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* tab-width: 8
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*
|
||||||
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
||||||
|
* :indentSize=4:tabSize=8:noTabs=true:
|
||||||
|
*/
|
|
@ -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:
|
||||||
|
*/
|
|
@ -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:
|
||||||
|
*/
|
|
@ -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:
|
||||||
|
*/
|
|
@ -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:
|
||||||
|
*/
|
|
@ -1183,6 +1183,12 @@ Section /o "Randpktdump" SecRandpktdump
|
||||||
SectionEnd
|
SectionEnd
|
||||||
!insertmacro CheckExtrasFlag "randpktdump"
|
!insertmacro CheckExtrasFlag "randpktdump"
|
||||||
|
|
||||||
|
Section /o "Etwdump" SecEtwdump
|
||||||
|
;-------------------------------------------
|
||||||
|
!insertmacro InstallExtcap "Etwdump"
|
||||||
|
SectionEnd
|
||||||
|
!insertmacro CheckExtrasFlag "Etwdump"
|
||||||
|
|
||||||
SectionGroupEnd ; "Tools"
|
SectionGroupEnd ; "Tools"
|
||||||
|
|
||||||
!ifdef DOCBOOK_DIR
|
!ifdef DOCBOOK_DIR
|
||||||
|
@ -1232,6 +1238,7 @@ SectionEnd
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecSshdump} "Provide remote capture through SSH"
|
!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 ${SecUDPdump} "Provide capture interface that gets UDP packets from network devices"
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecRandpktdump} "Provide random packet generator"
|
!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 ${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 ${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"
|
!insertmacro MUI_DESCRIPTION_TEXT ${SecMergecap} "Combine multiple saved capture files into a single output file"
|
||||||
|
|
|
@ -471,6 +471,26 @@
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
</Fragment>
|
</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 -->
|
<!-- Sshdump -->
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<DirectoryRef Id="dirExtcap">
|
<DirectoryRef Id="dirExtcap">
|
||||||
|
|
|
@ -89,6 +89,9 @@
|
||||||
<Feature Id="Fe.Tools.Randpktdump" Title="Randpktdump" Level="2" AllowAdvertise="yes" Display="expand" Description="Provide random packet generator.">
|
<Feature Id="Fe.Tools.Randpktdump" Title="Randpktdump" Level="2" AllowAdvertise="yes" Display="expand" Description="Provide random packet generator.">
|
||||||
<ComponentGroupRef Id="CG.Tools.Randpktdump" />
|
<ComponentGroupRef Id="CG.Tools.Randpktdump" />
|
||||||
</Feature>
|
</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.">
|
<Feature Id="Fe.Tools.Sshdump" Title="Sshdump" Level="1" AllowAdvertise="yes" Display="expand" Description="Provide remote capture through SSH.">
|
||||||
<ComponentGroupRef Id="CG.Tools.Sshdump" />
|
<ComponentGroupRef Id="CG.Tools.Sshdump" />
|
||||||
</Feature>
|
</Feature>
|
||||||
|
|
|
@ -481,6 +481,9 @@ static const struct {
|
||||||
|
|
||||||
/* USB 2.0/1.1/1.0 packets as transmitted over the cable */
|
/* USB 2.0/1.1/1.0 packets as transmitted over the cable */
|
||||||
{ 288, WTAP_ENCAP_USB_2_0 },
|
{ 288, WTAP_ENCAP_USB_2_0 },
|
||||||
|
|
||||||
|
/* windows ETL*/
|
||||||
|
{ 290, WTAP_ENCAP_ETL},
|
||||||
/*
|
/*
|
||||||
* To repeat:
|
* To repeat:
|
||||||
*
|
*
|
||||||
|
|
|
@ -292,6 +292,7 @@ extern "C" {
|
||||||
#define WTAP_ENCAP_MP4 209
|
#define WTAP_ENCAP_MP4 209
|
||||||
#define WTAP_ENCAP_SLL2 210
|
#define WTAP_ENCAP_SLL2 210
|
||||||
#define WTAP_ENCAP_ZWAVE_SERIAL 211
|
#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 */
|
/* After adding new item here, please also add new item to encap_table_base array */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue