丢失数据包(Windows NDIS 驱动程序过滤器)
Missing packets (Windows NDIS Driver Filter)
我是 WDD 的初学者。我需要制作一个网络驱动程序过滤器,根据签名丢弃某些数据包,以保护系统免受程序漏洞的影响。
现在,我只是想获取我需要的数据包并找到我的签名。我使用 Metasploit Framework 来利用此漏洞并使用 Wireshark 来跟踪流量。在 Wireshark 中,我看到 4 个目标端口为 8000 的数据包,如下所示:
但是当我试图获得它们时,我只有 2 个第一个 - 带有 SYN 和 ACK。
我的代码基于 NDIS driver filter sample。我在 FilterReceiveNetBufferLists 函数中编写。这是代码:
_Use_decl_annotations_
VOID
FilterReceiveNetBufferLists(
NDIS_HANDLE FilterModuleContext,
PNET_BUFFER_LIST NetBufferLists,
NDIS_PORT_NUMBER PortNumber,
ULONG NumberOfNetBufferLists,
ULONG ReceiveFlags
)
/*++
Routine Description:
FilerReceiveNetBufferLists is an optional function for filter drivers.
If provided, this function processes receive indications made by underlying
NIC or lower level filter drivers. This function can also be called as a
result of loopback. If this handler is NULL, NDIS will skip calling this
filter when processing a receive indication and will call the next higher
driver in the stack. A filter that doesn't provide a
FilterReceiveNetBufferLists handler cannot provide a
FilterReturnNetBufferLists handler and cannot a initiate an original receive
indication on its own.
Arguments:
FilterModuleContext - our filter context area.
NetBufferLists - a linked list of NetBufferLists
PortNumber - Port on which the receive is indicated
ReceiveFlags -
N.B.: It is important to check the ReceiveFlags in NDIS_TEST_RECEIVE_CANNOT_PEND.
This controls whether the receive indication is an synchronous or
asynchronous function call.
--*/
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN DispatchLevel;
ULONG Ref;
BOOLEAN bFalse = FALSE;
#if DBG
ULONG ReturnFlags;
#endif
DEBUGP(DL_TRACE, "===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists);
do
{
DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
#if DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
{
ReturnFlags = 0;
if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
{
NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
}
NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
}
break;
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif
ASSERT(NumberOfNetBufferLists >= 1);
////////////////////////////// MY CODE //////////////////////////////////////
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
PNET_BUFFER_LIST pCurrentNetBufferList = NetBufferLists;
PNET_BUFFER pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(pCurrentNetBufferList);
while (pCurrentNetBufferList)
{
while (pCurrentNetBuffer)
{
ULONG netbuffer_size = NET_BUFFER_DATA_LENGTH(pCurrentNetBuffer);
BYTE* buffer = (BYTE*)NdisGetDataBuffer(
pCurrentNetBuffer,
netbuffer_size,
NULL,
1,
0);
if (buffer) {
ParseBuffer(buffer, netbuffer_size);
}
else
{
void* alloc_mem = ExAllocatePoolWithTag(PagedPool, netbuffer_size, 'BteN');
buffer = (BYTE*)NdisGetDataBuffer(
pCurrentNetBuffer,
netbuffer_size,
alloc_mem,
1,
0);
if (buffer) {
ParseBuffer(buffer, netbuffer_size);
}
else {
DbgPrint("T.T");
}
ExFreePoolWithTag(alloc_mem, 'BteN');
}
pCurrentNetBuffer = NET_BUFFER_NEXT_NB(pCurrentNetBuffer);
}
pCurrentNetBufferList = NET_BUFFER_LIST_NEXT_NBL(pCurrentNetBufferList);
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
////////////////////////////////////////////////////////////////////////////
//
// If you would like to drop a received packet, then you must carefully
// modify the NBL chain as follows:
//
// if NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags):
// For each NBL that is NOT dropped, temporarily unlink it from
// the linked list, and indicate it up alone with
// NdisFIndicateReceiveNetBufferLists and the
// NDIS_RECEIVE_FLAGS_RESOURCES flag set. Then immediately
// relink the NBL back into the chain. When all NBLs have been
// indicated up, you may return from this function.
// otherwise (NDIS_TEST_RECEIVE_CANNOT_PEND is FALSE):
// Divide the linked list of NBLs into two chains: one chain
// of packets to drop, and everything else in another chain.
// Return the first chain with NdisFReturnNetBufferLists, and
// indicate up the rest with NdisFIndicateReceiveNetBufferLists.
//
// Note: on the receive path for Ethernet packets, one NBL will have
// exactly one NB. So (assuming you are receiving on Ethernet, or are
// attached above Native WiFi) you do not need to worry about dropping
// one NB, but trying to indicate up the remaining NBs on the same NBL.
// In other words, if the first NB should be dropped, drop the whole NBL.
//
//
// If you would like to modify a packet, and can do so quickly, you may
// do it here. However, make sure you save enough information to undo
// your modification in the FilterReturnNetBufferLists handler.
//
//
// If necessary, queue the NetBufferLists in a local structure for later
// processing. However, do not queue them for "too long", or else the
// system's performance may be degraded. If you need to hold onto an
// NBL for an unbounded amount of time, then allocate memory, perform a
// deep copy, and return the original NBL.
//
if (pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs += NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}
NdisFIndicateReceiveNetBufferLists(
pFilter->FilterHandle,
NetBufferLists,
PortNumber,
NumberOfNetBufferLists,
ReceiveFlags);
if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) &&
pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}
} while (bFalse);
DEBUGP(DL_TRACE, "<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags);
}
ParseBuffer 函数:
VOID ParseBuffer(BYTE *buffer, ULONG netbuffer_size)
{
// parse ethernet
eth_header_t* pEthHeader = (eth_header_t*)buffer;
ASSERT(pEthHeader);
if (pEthHeader->type == RtlUshortByteSwap(EtherType_IPv4))
{
// parse ipv4
ipv4_header_t* pIpHeader = (ipv4_header_t*)(buffer + sizeof(eth_header_t));
ASSERT(pIpHeader);
ASSERT(pIpHeader->version == IPPROTO_IPV4);
if (pIpHeader->protocol == IPPROTO_TCP)
{
// parse tcp
tcp_header_t* pTcpHeader = (tcp_header_t*)(buffer + sizeof(eth_header_t) + sizeof(ipv4_header_t));
ASSERT(pTcpHeader);
if (pTcpHeader->dst_port == RtlUshortByteSwap(8000))
{
if (netbuffer_size) {}
DbgPrint("PACKET DUMP:\n");
DbgPrintHexDump(buffer, netbuffer_size);
WORD ip_total_length = RtlUshortByteSwap(pIpHeader->total_length);
WORD tcp_size = ip_total_length - sizeof(ipv4_header_t);
WORD data_size = tcp_size - (pTcpHeader->data_offset << 2);
DbgPrint("DATA SIZE: %d \n", data_size);
// if there is any data in packet
if(data_size)
{
BYTE* data = (buffer + sizeof(eth_header_t) + sizeof(ipv4_header_t) + (pTcpHeader->data_offset << 2));
ASSERT(data);
DbgPrint("Data:\n");
DbgPrintHexDump(data, data_size);
const char* signature = "\xEB\x0C / HTTP/1.1 ";
const char* pch = strstr((const char*)data, signature);
if (pch != NULL)
{
DbgPrint("Got it!\n");
}
}
DbgPrint("\n");
}
}
}
}
也许我必须在处理 NetBufferLists 之前克隆它们,我不知道。如果我必须这样做,我应该什么时候做?
P.S。 The full code(如果你需要的话)。
好吧,这是一个愚蠢的错误,我把 PNET_BUFFER pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(pCurrentNetBufferList)
放错了地方。它必须在 while (pCurrentNetBufferList)
.
之后
我是 WDD 的初学者。我需要制作一个网络驱动程序过滤器,根据签名丢弃某些数据包,以保护系统免受程序漏洞的影响。 现在,我只是想获取我需要的数据包并找到我的签名。我使用 Metasploit Framework 来利用此漏洞并使用 Wireshark 来跟踪流量。在 Wireshark 中,我看到 4 个目标端口为 8000 的数据包,如下所示:
我的代码基于 NDIS driver filter sample。我在 FilterReceiveNetBufferLists 函数中编写。这是代码:
_Use_decl_annotations_
VOID
FilterReceiveNetBufferLists(
NDIS_HANDLE FilterModuleContext,
PNET_BUFFER_LIST NetBufferLists,
NDIS_PORT_NUMBER PortNumber,
ULONG NumberOfNetBufferLists,
ULONG ReceiveFlags
)
/*++
Routine Description:
FilerReceiveNetBufferLists is an optional function for filter drivers.
If provided, this function processes receive indications made by underlying
NIC or lower level filter drivers. This function can also be called as a
result of loopback. If this handler is NULL, NDIS will skip calling this
filter when processing a receive indication and will call the next higher
driver in the stack. A filter that doesn't provide a
FilterReceiveNetBufferLists handler cannot provide a
FilterReturnNetBufferLists handler and cannot a initiate an original receive
indication on its own.
Arguments:
FilterModuleContext - our filter context area.
NetBufferLists - a linked list of NetBufferLists
PortNumber - Port on which the receive is indicated
ReceiveFlags -
N.B.: It is important to check the ReceiveFlags in NDIS_TEST_RECEIVE_CANNOT_PEND.
This controls whether the receive indication is an synchronous or
asynchronous function call.
--*/
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN DispatchLevel;
ULONG Ref;
BOOLEAN bFalse = FALSE;
#if DBG
ULONG ReturnFlags;
#endif
DEBUGP(DL_TRACE, "===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists);
do
{
DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
#if DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
{
ReturnFlags = 0;
if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
{
NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
}
NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
}
break;
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif
ASSERT(NumberOfNetBufferLists >= 1);
////////////////////////////// MY CODE //////////////////////////////////////
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
PNET_BUFFER_LIST pCurrentNetBufferList = NetBufferLists;
PNET_BUFFER pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(pCurrentNetBufferList);
while (pCurrentNetBufferList)
{
while (pCurrentNetBuffer)
{
ULONG netbuffer_size = NET_BUFFER_DATA_LENGTH(pCurrentNetBuffer);
BYTE* buffer = (BYTE*)NdisGetDataBuffer(
pCurrentNetBuffer,
netbuffer_size,
NULL,
1,
0);
if (buffer) {
ParseBuffer(buffer, netbuffer_size);
}
else
{
void* alloc_mem = ExAllocatePoolWithTag(PagedPool, netbuffer_size, 'BteN');
buffer = (BYTE*)NdisGetDataBuffer(
pCurrentNetBuffer,
netbuffer_size,
alloc_mem,
1,
0);
if (buffer) {
ParseBuffer(buffer, netbuffer_size);
}
else {
DbgPrint("T.T");
}
ExFreePoolWithTag(alloc_mem, 'BteN');
}
pCurrentNetBuffer = NET_BUFFER_NEXT_NB(pCurrentNetBuffer);
}
pCurrentNetBufferList = NET_BUFFER_LIST_NEXT_NBL(pCurrentNetBufferList);
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
////////////////////////////////////////////////////////////////////////////
//
// If you would like to drop a received packet, then you must carefully
// modify the NBL chain as follows:
//
// if NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags):
// For each NBL that is NOT dropped, temporarily unlink it from
// the linked list, and indicate it up alone with
// NdisFIndicateReceiveNetBufferLists and the
// NDIS_RECEIVE_FLAGS_RESOURCES flag set. Then immediately
// relink the NBL back into the chain. When all NBLs have been
// indicated up, you may return from this function.
// otherwise (NDIS_TEST_RECEIVE_CANNOT_PEND is FALSE):
// Divide the linked list of NBLs into two chains: one chain
// of packets to drop, and everything else in another chain.
// Return the first chain with NdisFReturnNetBufferLists, and
// indicate up the rest with NdisFIndicateReceiveNetBufferLists.
//
// Note: on the receive path for Ethernet packets, one NBL will have
// exactly one NB. So (assuming you are receiving on Ethernet, or are
// attached above Native WiFi) you do not need to worry about dropping
// one NB, but trying to indicate up the remaining NBs on the same NBL.
// In other words, if the first NB should be dropped, drop the whole NBL.
//
//
// If you would like to modify a packet, and can do so quickly, you may
// do it here. However, make sure you save enough information to undo
// your modification in the FilterReturnNetBufferLists handler.
//
//
// If necessary, queue the NetBufferLists in a local structure for later
// processing. However, do not queue them for "too long", or else the
// system's performance may be degraded. If you need to hold onto an
// NBL for an unbounded amount of time, then allocate memory, perform a
// deep copy, and return the original NBL.
//
if (pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs += NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}
NdisFIndicateReceiveNetBufferLists(
pFilter->FilterHandle,
NetBufferLists,
PortNumber,
NumberOfNetBufferLists,
ReceiveFlags);
if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) &&
pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}
} while (bFalse);
DEBUGP(DL_TRACE, "<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags);
}
ParseBuffer 函数:
VOID ParseBuffer(BYTE *buffer, ULONG netbuffer_size)
{
// parse ethernet
eth_header_t* pEthHeader = (eth_header_t*)buffer;
ASSERT(pEthHeader);
if (pEthHeader->type == RtlUshortByteSwap(EtherType_IPv4))
{
// parse ipv4
ipv4_header_t* pIpHeader = (ipv4_header_t*)(buffer + sizeof(eth_header_t));
ASSERT(pIpHeader);
ASSERT(pIpHeader->version == IPPROTO_IPV4);
if (pIpHeader->protocol == IPPROTO_TCP)
{
// parse tcp
tcp_header_t* pTcpHeader = (tcp_header_t*)(buffer + sizeof(eth_header_t) + sizeof(ipv4_header_t));
ASSERT(pTcpHeader);
if (pTcpHeader->dst_port == RtlUshortByteSwap(8000))
{
if (netbuffer_size) {}
DbgPrint("PACKET DUMP:\n");
DbgPrintHexDump(buffer, netbuffer_size);
WORD ip_total_length = RtlUshortByteSwap(pIpHeader->total_length);
WORD tcp_size = ip_total_length - sizeof(ipv4_header_t);
WORD data_size = tcp_size - (pTcpHeader->data_offset << 2);
DbgPrint("DATA SIZE: %d \n", data_size);
// if there is any data in packet
if(data_size)
{
BYTE* data = (buffer + sizeof(eth_header_t) + sizeof(ipv4_header_t) + (pTcpHeader->data_offset << 2));
ASSERT(data);
DbgPrint("Data:\n");
DbgPrintHexDump(data, data_size);
const char* signature = "\xEB\x0C / HTTP/1.1 ";
const char* pch = strstr((const char*)data, signature);
if (pch != NULL)
{
DbgPrint("Got it!\n");
}
}
DbgPrint("\n");
}
}
}
}
也许我必须在处理 NetBufferLists 之前克隆它们,我不知道。如果我必须这样做,我应该什么时候做?
P.S。 The full code(如果你需要的话)。
好吧,这是一个愚蠢的错误,我把 PNET_BUFFER pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(pCurrentNetBufferList)
放错了地方。它必须在 while (pCurrentNetBufferList)
.