Skip to content

Commit

Permalink
Adding support for NDIS Metadata blocks as comments in pcapng (#19)
Browse files Browse the repository at this point in the history
- Adding support for NDIS Metadata blocks as comments in pcapng
- Correcting some comments, error messages, and variable types for consistency

Tested changes on two types of wlan adapters (nwifi & wdi) and on ethernet with two interfaces against wireshark version 3.2.0 for viewing pcapng files.
  • Loading branch information
jp-stewart authored Jan 29, 2020
1 parent 9361329 commit 870232e
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 65 deletions.
146 changes: 134 additions & 12 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,57 @@ in Windows that produces packet capture events) to pcapng format
#define KW_SEND 0x100000000
#define KW_RECEIVE 0x200000000

#define tidPacketFragment 1001
#define tidPacketMetadata 1002
#define tidVMSwitchPacketFragment 1003

// From: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/windot11/ns-windot11-dot11_extsta_recv_context
#pragma pack(push,8)
typedef struct _NDIS_OBJECT_HEADER {
unsigned char Type;
unsigned char Revision;
unsigned short Size;
} NDIS_OBJECT_HEADER, * PNDIS_OBJECT_HEADER;

typedef struct DOT11_EXTSTA_RECV_CONTEXT {
NDIS_OBJECT_HEADER Header;
unsigned long uReceiveFlags;
unsigned long uPhyId;
unsigned long uChCenterFrequency;
unsigned short usNumberOfMPDUsReceived;
long lRSSI;
unsigned char ucDataRate;
unsigned long uSizeMediaSpecificInfo;
void *pvMediaSpecificInfo;
unsigned long long ullTimestamp;
} DOT11_EXTSTA_RECV_CONTEXT, * PDOT11_EXTSTA_RECV_CONTEXT;
#pragma pack(pop)

// From: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/windot11/ne-windot11-_dot11_phy_type
#define DOT11_PHY_TYPE_NAMES_MAX 10
static const char* DOT11_PHY_TYPE_NAMES[] = {
"Unknown", // dot11_phy_type_unknown = 0
"Fhss", // dot11_phy_type_fhss = 1
"Dsss", // dot11_phy_type_dsss = 2
"IrBaseband", // dot11_phy_type_irbaseband = 3
"802.11a", // dot11_phy_type_ofdm = 4
"802.11b", // dot11_phy_type_hrdsss = 5
"802.11g", // dot11_phy_type_erp = 6
"802.11n", // dot11_phy_type_ht = 7
"802.11ac", // dot11_phy_type_vht = 8
"802.11ad", // dot11_phy_type_dmg = 9
"802.11ax" // dot11_phy_type_he = 10
};

HANDLE OutFile = INVALID_HANDLE_VALUE;
unsigned long long NumFramesConverted = 0;
BOOLEAN Pass2 = FALSE;
char AuxFragBuf[MAX_PACKET_SIZE] = {0};
unsigned long AuxFragBufOffset = 0;

DOT11_EXTSTA_RECV_CONTEXT PacketMetadata;
BOOLEAN AddMetadata = FALSE;

const GUID NdisCapId = { // Microsoft-Windows-NDIS-PacketCapture {2ED6006E-4729-4609-B423-3EE7BCD678EF}
0x2ed6006e, 0x4729, 0x4609, 0xb4, 0x23, 0x3e, 0xe7, 0xbc, 0xd6, 0x78, 0xef};

Expand Down Expand Up @@ -183,16 +228,17 @@ void WINAPI EventCallback(PEVENT_RECORD ev)
ULARGE_INTEGER TimeStamp;

if (!IsEqualGUID(&ev->EventHeader.ProviderId, &NdisCapId) ||
(ev->EventHeader.EventDescriptor.Id != 1001 && // tidPacketFragment
ev->EventHeader.EventDescriptor.Id != 1003)) { // tidVMSwitchPacketFragment
(ev->EventHeader.EventDescriptor.Id != tidPacketFragment &&
ev->EventHeader.EventDescriptor.Id != tidPacketMetadata &&
ev->EventHeader.EventDescriptor.Id != tidVMSwitchPacketFragment)) {
return;
}

Desc.PropertyName = (ULONGLONG)L"LowerIfIndex";
Desc.PropertyName = (unsigned long long)L"LowerIfIndex";
Desc.ArrayIndex = ULONG_MAX;
Err = TdhGetProperty(ev, 0, NULL, 1, &Desc, sizeof(LowerIfIndex), (PBYTE)&LowerIfIndex);
if (Err != NO_ERROR) {
printf("TdhGetPropertySize failed with %u\n", Err);
printf("TdhGetProperty LowerIfIndex failed with %u\n", Err);
return;
}

Expand All @@ -210,11 +256,11 @@ void WINAPI EventCallback(PEVENT_RECORD ev)
// Record the IfIndex if it's a new one.
if (Iface == NULL) {
unsigned long MiniportIfIndex;
Desc.PropertyName = (ULONGLONG)L"MiniportIfIndex";
Desc.PropertyName = (unsigned long long)L"MiniportIfIndex";
Desc.ArrayIndex = ULONG_MAX;
Err = TdhGetProperty(ev, 0, NULL, 1, &Desc, sizeof(MiniportIfIndex), (PBYTE)&MiniportIfIndex);
if (Err != NO_ERROR) {
printf("TdhGetPropertySize failed with %u\n", Err);
printf("TdhGetProperty MiniportIfIndex failed with %u\n", Err);
return;
}
AddInterface(LowerIfIndex, MiniportIfIndex, Type);
Expand All @@ -231,6 +277,34 @@ void WINAPI EventCallback(PEVENT_RECORD ev)
exit(1);
}

//Save off Ndis/Wlan metadata to be added to the next packet
if (ev->EventHeader.EventDescriptor.Id == tidPacketMetadata) {
unsigned long MetadataLength = 0;
Desc.PropertyName = (unsigned long long)L"MetadataSize";
Desc.ArrayIndex = ULONG_MAX;
Err = TdhGetProperty(ev, 0, NULL, 1, &Desc, sizeof(MetadataLength), (PBYTE)&MetadataLength);
if (Err != NO_ERROR) {
printf("TdhGetProperty MetadataSize failed with %u\n", Err);
return;
}

if (MetadataLength != sizeof(PacketMetadata)) {
printf("Unknown Metadata length. Expected %u, got %u\n", sizeof(DOT11_EXTSTA_RECV_CONTEXT), MetadataLength);
return;
}

Desc.PropertyName = (unsigned long long)L"Metadata";
Desc.ArrayIndex = ULONG_MAX;
Err = TdhGetProperty(ev, 0, NULL, 1, &Desc, MetadataLength, (PBYTE)&PacketMetadata);
if (Err != NO_ERROR) {
printf("TdhGetProperty Metadata failed with %u\n", Err);
return;
}

AddMetadata = TRUE;
return;
}

// N.B.: Here we are querying the FragmentSize property to get the
// total size of the packet, and then reading that many bytes from
// the Fragment property. This is unorthodox (normally you are
Expand All @@ -239,11 +313,11 @@ void WINAPI EventCallback(PEVENT_RECORD ev)
// multiple adjacent properties (which happen to be contiguous in
// memory).

Desc.PropertyName = (ULONGLONG)L"FragmentSize";
Desc.PropertyName = (unsigned long long)L"FragmentSize";
Desc.ArrayIndex = ULONG_MAX;
Err = TdhGetProperty(ev, 0, NULL, 1, &Desc, sizeof(FragLength), (PBYTE)&FragLength);
if (Err != NO_ERROR) {
printf("TdhGetPropertySize failed with %u\n", Err);
printf("TdhGetProperty FragmentSize failed with %u\n", Err);
return;
}

Expand All @@ -252,11 +326,11 @@ void WINAPI EventCallback(PEVENT_RECORD ev)
return;
}

Desc.PropertyName = (ULONGLONG)L"Fragment";
Desc.PropertyName = (unsigned long long)L"Fragment";
Desc.ArrayIndex = ULONG_MAX;
Err = TdhGetProperty(ev, 0, NULL, 1, &Desc, FragLength, (PBYTE)(AuxFragBuf + AuxFragBufOffset));
if (Err != NO_ERROR) {
printf("TdhGetPropertySize failed with %u\n", Err);
printf("TdhGetProperty Fragment failed with %u\n", Err);
return;
}

Expand All @@ -279,6 +353,52 @@ void WINAPI EventCallback(PEVENT_RECORD ev)
// This logic is here to support packet captures from older systems.

if (!!(ev->EventHeader.EventDescriptor.Keyword & KW_PACKET_END)) {

if (ev->EventHeader.EventDescriptor.Keyword & KW_MEDIA_NATIVE_802_11 &&
AuxFragBuf[1] & 0x40) {
// Clear Protected bit in the case of 802.11
// Ndis captures will be decrypted in the etl file

AuxFragBuf[1] = AuxFragBuf[1] & 0xBF; // _1011_1111_ - Clear "Protected Flag"
}

// COMMENT_MAX_SIZE must be multiple of 4
#define COMMENT_MAX_SIZE 256
char Comment[COMMENT_MAX_SIZE] = { 0 };
size_t CommentLength = 0;

if (AddMetadata) {
if (PacketMetadata.uPhyId > DOT11_PHY_TYPE_NAMES_MAX) {
PacketMetadata.uPhyId = 0; // Set to unknown if outside known bounds.
}

Err = StringCchPrintfA(Comment, COMMENT_MAX_SIZE, "PID=%d Packet Metadata: ReceiveFlags:0x%x, PhyType:%s, CenterCh:%u, NumMPDUsReceived:%u, RSSI:%d, DataRate:%u",
ev->EventHeader.ProcessId,
PacketMetadata.uReceiveFlags,
DOT11_PHY_TYPE_NAMES[PacketMetadata.uPhyId],
PacketMetadata.uChCenterFrequency,
PacketMetadata.usNumberOfMPDUsReceived,
PacketMetadata.lRSSI,
PacketMetadata.ucDataRate);

AddMetadata = FALSE;
memset(&PacketMetadata, 0, sizeof(DOT11_EXTSTA_RECV_CONTEXT));
} else {
Err = StringCchPrintfA(Comment, COMMENT_MAX_SIZE, "PID=%d", ev->EventHeader.ProcessId);
}

if (Err != NO_ERROR) {
printf("Failed converting comment to string with error: %u\n", Err);
} else {
Err = StringCchLengthA(Comment, COMMENT_MAX_SIZE, &CommentLength);

if (Err != NO_ERROR) {
printf("Failed getting length of comment string with error: %u\n", Err);
CommentLength = 0;
memset(Comment, 0, COMMENT_MAX_SIZE);
}
}

PcapNgWriteEnhancedPacket(
OutFile,
AuxFragBuf,
Expand All @@ -287,7 +407,9 @@ void WINAPI EventCallback(PEVENT_RECORD ev)
!!(ev->EventHeader.EventDescriptor.Keyword & KW_SEND),
TimeStamp.HighPart,
TimeStamp.LowPart,
ev->EventHeader.ProcessId);
CommentLength > 0 ? (char*)&Comment : NULL,
(unsigned short)CommentLength);

AuxFragBufOffset = 0;
NumFramesConverted++;
} else {
Expand All @@ -306,7 +428,7 @@ int __cdecl wmain(int argc, wchar_t** argv)
if (argc == 2 &&
(!wcscmp(argv[1], L"-v") ||
!wcscmp(argv[1], L"--version"))) {
printf("etl2pcapng version 1.3.0\n");
printf("etl2pcapng version 1.4.0\n");
return 0;
}

Expand Down
Loading

0 comments on commit 870232e

Please sign in to comment.