FwpsInjectNetworkSendAsync0 BSOD directly

The simplest form of Inject go into BSOD right away, i cloned the NBL and inject it back absorbing the old packet first, if the NBL is the cloned one the BOSD happens right away, I tried to Deep Clone with creating a new NBL, but still the same, i believe there is something wrong with the cloned NBL.

the simplified code is below showing the current state removing everything else (i have been working on crafting a new paket with MDLs and so Originally) the below code Crashes all the time on the injection.

Notice i made a new injection handle (the code is modified inspect example)
I changed the filter to capture all packets
I removed the capture on transport Layer so its on network and the ALE layers only now .

void
TLInspectOutboundNetworkClassify(
In const FWPS_INCOMING_VALUES* inFixedValues,
In const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
Inout_opt void* layerData,
In const FWPS_FILTER* filter,
In UINT64 flowContext,
Inout FWPS_CLASSIFY_OUT* classifyOut
)
{
classifyOut->actionType = FWP_ACTION_PERMIT;
FWPS_PACKET_INJECTION_STATE packetState;
//NdisRetreatNetBufferDataStart(pNetBuffer, inMetaValues->ipHeaderSize, FALSE, NULL);

packetState = FwpsQueryPacketInjectionState(
gNetworkInjectionHandle,
layerData,
NULL
);

if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
(packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
{
classifyOut->actionType = FWP_ACTION_PERMIT;
if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
{
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
}
goto Exit;
}

PNET_BUFFER_LIST pClonedNBL = NULL;

NTSTATUS status = STATUS_SUCCESS;
status = FwpsAllocateCloneNetBufferList(
(PNET_BUFFER_LIST)layerData,
NULL,
NULL,
0,
&pClonedNBL
);

if (!NT_SUCCESS(status))
goto Exit;

// CRASHES DIRECTLY HERE
status = FwpsInjectNetworkSendAsync0(
gNetworkInjectionHandle,
NULL,
0,
UNSPECIFIED_COMPARTMENT_ID,//inMetaValues->compartmentId,
pClonedNBL,//pNewNbl,
TLInspectNetworkInjectComplete,
NULL
);

if (!NT_SUCCESS(status))
{
if (pClonedNBL != NULL)
{
FwpsFreeCloneNetBufferList(pClonedNBL, 0);
}
goto Exit;
}

pClonedNBL = NULL; // ownership transferred to the
// completion function.

classifyOut->actionType = FWP_ACTION_BLOCK;
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;

Exit:
classifyOut->actionType = FWP_ACTION_PERMIT;
return;
}

try reference the netbufferlist before cloning.

Thank you Ashish ,

I have referenced the NBL before cloning directly the dereferenced it after But the same result

PNET_BUFFER_LIST pClonedNBL = NULL;

NTSTATUS status = STATUS_SUCCESS;

FwpsReferenceNetBufferList((PNET_BUFFER_LIST)layerData, TRUE);

status = FwpsAllocateCloneNetBufferList(
(PNET_BUFFER_LIST)layerData,
NULL,
NULL,
0,
&pClonedNBL
);

if (!NT_SUCCESS(status))
goto Exit;

The Crash Still happens in the injection, This is my first time injecting anything so i think i am missing something …

Any help will be appreciated .

How have you created gNetworkInjectionHandle ? What WFP layer is your TLInspectOutboundNetworkClassify callout for?

Packet injection will often (always?) require the PNET_BUFFER_LIST passed to the injection function to be starting with a particular network header. For example to use FwpsInjectTransportReceiveAsync the PNET_BUFFER_LIST must begin with an IP header.

J

Ok The regeneration happens here :
status = TLInspectRegisterNetworkCallouts(
&FWPM_LAYER_OUTBOUND_IPPACKET_V4,
&TL_INSPECT_OUTBOUND_IPPAKCET_CALLOUT_V4,
deviceObject,
&gOutboundTlCalloutIdV4
);

The injection handle is here :

status = FwpsInjectionHandleCreate(
AF_INET,
FWPS_INJECTION_TYPE_NETWORK,
&gNetworkInjectionHandle
);

Before i got an error when the injection handle been created for the Transport Layer, but it doesn’t give a BSOD , from the status error in the debugview i figured the problem and corrected it to the proper injection type : FWPS_INJECTION_TYPE_NETWORK

Also I am sure the NBL starts with the IP header because in the Classifyfn I can do this :

PNET_BUFFER pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetbufferlist);
PMDL packet_mdl = NULL;
PMDL CurrentMdl = NET_BUFFER_CURRENT_MDL(pNetBuffer);
PUCHAR SrcMemory = NULL;
ULONG Length = 0, MdlOffset = 0, DestOffset = 0, IP_HEADER_SIZE = sizeof(IP_HEADER_V4), UDP_HEADER_SIZE = sizeof(UDP_HEADER);
PVOID Dest = ExAllocatePoolWithTag(NonPagedPool, sizeof(BYTE[1500]), ‘tag9’);
while (CurrentMdl != NULL)
{
SrcMemory = MmGetSystemAddressForMdlSafe(CurrentMdl, LowPagePriority | MdlMappingNoExecute);
Length = MmGetMdlByteCount(CurrentMdl);

MdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pNetBuffer);
SrcMemory += MdlOffset;
Length -= MdlOffset;

NdisMoveMemory((PUCHAR)Dest + DestOffset, SrcMemory, Length);
DestOffset += Length;
CurrentMdl = NDIS_MDL_LINKAGE(CurrentMdl);
}

DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
“[status: %#x]\n”, RtlUshortByteSwap((ULONG)((IP_HEADER_V4*)(Dest))->protocol));

And the protocol either UDP or TCP will be printed properly 0x6 or 0x11(17) in the DebugView .

what do you think ?

To make sure the NBL starts with the IP header I done this even further :

if (RtlUshortByteSwap((ULONG)((IP_HEADER_V4*)(Dest))->protocol) == 0x600)
{

status = FwpsInjectNetworkSendAsync0(
gNetworkInjectionHandle,
NULL,
0,
inMetaValues->compartmentId, //UNSPECIFIED_COMPARTMENT_ID,
pClonedNBL,//pNewNbl,
TLInspectNetworkInjectComplete,
NULL
);

FwpsDereferenceNetBufferList(pOrgNBL, FALSE);

}

The protocol captured in the proper offset of the IP header , it should mean the packet is formed properly ( despite the fact i modify nothing on the received NBL in the first place)

the injection wont be called unless the NBL ip header at least is properly formed .

before injection free the original netbufferlist.

Also copy & paste the analyze -v dump.

Thank you for the help, I figured the problem it was from a forgotten line in the completion function to free an unreserved memory .

Completion function should only free NBL if we cloned it

Thanks everyone