I'm trying to intercept and locate tcp packets in memory through debugging of windows 10. Suppose I set a break point at TcpReceive, the call stack looks like this
kd> kc
# Call Site
tcpip!TcpReceive
tcpip!TcpNlClientReceiveDatagrams
tcpip!IppProcessDeliverlist
tcpip!IppReceiveHeaderBatch
tcpip!IppReceivePackets
tcpip!FlpReceiveNonPreValidatedNetBufferListChain
tcpip!FlReceiveNetBufferListChainCalloutRoutine
nt!KeExpandKernelStackAndCalloutInternal
nt!KeExpandKernelStackAndCalloutEx
tcpip!NetioExpandKernelStackAndCallout
tcpip!FlReceiveNetBufferListChain
NDIS!ndisMIndicateNetBufferlistsToOpen
NDIS!ndisMTopReceiveNetBufferLists
Here are the problems:
- Through static analysis of code in IDA. tcpip!IppProcessDeliverlist doesn't even call TcpNlClientReceiveDatagrams. The code of tcpip.sys(file directly extracted from machine) doesn't even have tcpip!IppReceivePackets. What might be the problem?
- There are multiple protocols that will use tcpip!IppReceiveHeaderBatch. But I only want break point of tcpip!IppReceiveHeaderBatch to be triggered when tcpip!TcpReceive is triggered. My approach is
bp tcpip!TcpReceive
bp tcpip!IppReceiveHeaderBatch ".echo header batch;r;k;g" //display function arguments
But the output of IppReceiveHeaderBatch just above TcpReceive won't necessarily be the actual upstream of TcpReceive. How do I know which output is the real upstream?
- Windows use NET_BUFFER and NET_BUFFER_LIST to store packet data. I can use !ndiskd.nb and !ndiskd.nbl to walk through them and I also have the offset and address of the above structures. But these 2 structures serve for general purpose and doesn't have the section in header like IP,port number. Memory scan of Mdl and physical address doesn't help. Can someone point out a direction?
typedef struct _NET_BUFFER {
NET_BUFFER *Next;
MDL *CurrentMdl;
ULONG CurrentMdlOffset;
...
PHYSICAL_ADDRESS DataPhysicalAddress;
...
}
kc
is walking the frame pointers, and it's likely that the function being called does not use a frame pointer. This results in a partial view of the callstack. However, if you go to your Disassembly Options in IDA and enable display of the "Stack Pointer". This will show you the distance to the top of the frame for any given instruction address. Essentially if you add this value to @rsp, that should shift your stack to the actual return address. You can then use that address to get the next frame size and repeat until you get to the actual top of the stack.