这一节主要学习网络请求的过滤,铁锤大佬讲了些关于IRP的知识。
笔记
先祭出一张灵魂作画,这是用来描述IRP的流转形式的。
通过这幅图着重解释了一下IoSkipCurrentIrpStackLocation(pirp);
的过程,就是在流转到当前的IRP请求之后,不做任何处理,将当前的IRP堆栈传到下一层,使之和上一次内容一样,就相当于“跳过”了。
VOID
IoSkipCurrentIrpStackLocation (
_Inout_ PIRP Irp
){
NT_ASSERT(Irp->CurrentLocation <= Irp->StackCount);
Irp->CurrentLocation++;
Irp->Tail.Overlay.CurrentStackLocation++;
}
各种IRP也是分层过滤的,一层一层的传递,然后不同的驱动设备都可以修改。
在拦截IRP这一步就很简单,下边是效果,网络请求也可以拦截到。
接下来是对请求IRP中的内容进行解析,一般是IRP堆栈里边有很多结构,我们需要通过文档或是经验贴,定义或者强转成我们需要的内容。
具体的分发例程:
NTSTATUS MyDispath(
PDEVICE_OBJECT pdevice,
PIRP pirp
) {
PIO_STACK_LOCATION pripstack = NULL;
// 我们只关心TCP请求,且流入本驱动的
if (pdevice == pfilterdevobj)
{
pripstack = IoGetCurrentIrpStackLocation(pirp);
if (pripstack ==NULL)
{
return STATUS_UNSUCCESSFUL;
}
if (pripstack->MinorFunction == TDI_CONNECT)
{
PTDI_REQUEST_KERNEL_CONNECT ptdiconnect =
(PTDI_REQUEST_KERNEL_CONNECT)(&pripstack->Parameters);
PTA_ADDRESS ta_addr =
((PTRANSPORT_ADDRESS)(ptdiconnect->RequestConnectionInformation->RemoteAddress))->Address;
PTDI_ADDRESS_IP tdi_addr =
(PTDI_ADDRESS_IP)(ta_addr->Address);
DWORD address = tdi_addr->in_addr;
USHORT port = tdi_addr->sin_port;
NETWORK_ADDRESS data = { 0 };
data.address[0] = ((PCHAR)&address)[0];
data.address[1] = ((PCHAR)&address)[1];
data.address[2] = ((PCHAR)&address)[2];
data.address[3] = ((PCHAR)&address)[3];
data.post[0] = ((PCHAR)&port)[0];
data.post[1] = ((PCHAR)&port)[1];
port = HTONS(port);
DbgPrint("connect %d.%d.%d.%d:%d\n", data.address[0],
data.address[1],
data.address[2],
data.address[3], port);
DbgPrint("connect io address <%x>\n", address);
}
}
IoSkipCurrentIrpStackLocation(pirp);
return IoCallDriver(pdodevobj, pirp);
}
里边在端口的转换时,使用了HTONS
宏
HTONS本身所做的就是将USHORT从主机序转化为网络序
参考:用C语言进一步优化Windows Shellcode
然后里边对结构内容的查找,涉及很多类型和指针的调用,其实也米有难得地方,对应好结构的说明进行指定或强转。(很复杂就是😗)
小结
锤哥在视频里边花了很多时间来调试找错误,来接解决端口显示异常的问题,感谢大佬,很受用!
”本着调试的精神来解决问题“ Getit✅