阅读:2347回复:8
NDIS驱动 菜鸟求教。在NDIS驱动中,如何把接受的数据包。转发出去。有人说改IP头或IP。然后算校检,然后发送出去,是这样吗? 现在的问题是,在xpassthru中调用MPSendOnePacket自定义函数在这个函数里面如何改IP地址和校检? 我是刚学的菜鸟,请前辈们指点一下,非常感谢了。如果有源码,可以贴出来我学习。。先谢了 |
|
沙发#
发布于:2012-12-08 23:53
xpassthru没看过,只看过passthru,它的packet buffer和内存都是自己分配的话,肯定是可以改的
|
|
板凳#
发布于:2012-12-09 15:34
有没有什么资料参考呢?如果能修改IP和包的内容在转发出去,那需要怎么做?
很是郁闷 |
|
地板#
发布于:2012-12-10 00:22
收报后转发我在网上快找死了也没找到,后来自己写的,还算能用,就是不知道有没有内存泄露什么的,主要函数就是下面几个,看名字就知道了
NDIS_STATUS getPacketBuffer(PNDIS_PACKET Packet, PUCHAR *ppBuffer, UINT *pnBufferLen) { NDIS_STATUS status; PNDIS_BUFFER NdisBuffer ; UINT TotalPacketLength = 0; UINT copysize = 0; UINT DataOffset = 0 ; UINT PhysicalBufferCount; UINT BufferCount ; PUCHAR pPacketContent = NULL; char* tcsPrintBuf = NULL; PUCHAR tembuffer = NULL ; UCHAR s; status = NdisAllocateMemoryWithTag(&pPacketContent, 2048, TAG); //分配带标签的内存 if (status != NDIS_STATUS_SUCCESS) { return status; } NdisZeroMemory(pPacketContent, 2048); //分配2k bits内存 // 找到第一个Ndis_Buffer。然后通过通过NdisGetNextBuffer来获得后续的NDIS_BUFFER。 // 如果只是找第一个节点,更快且方便的方法是调用NdisGetFirstBufferFromPacket。 NdisQueryPacket(Packet, // NDIS_PACKET &PhysicalBufferCount,// 内存中的物理块数 &BufferCount, // 多少个NDIS_BUFFER包 &NdisBuffer, // 将返回第一个包 &TotalPacketLength // 总共的包数据长度 ); while (TRUE) { // 取得Ndis_Buffer中存储缓冲区的虚拟地址。 // 这个函数的另一个版本是NdisQueryBuffer。 // 后者在系统资源低或者甚至耗尽的时候,会产生Bug Check,导致蓝屏。 NdisQueryBufferSafe(NdisBuffer, &tembuffer,// 缓冲区地址 ©size, // 缓冲区大小 NormalPagePriority ); // 如果tembuffer为NULL,说明当前系统资源匮乏。 if (tembuffer != NULL) { NdisMoveMemory( pPacketContent + DataOffset , tembuffer, copysize) ; DataOffset += copysize; } else { status = NDIS_STATUS_FAILURE; return status; } // 获得下一个NDIS_BUFFER。 // 如果得到的是一个NULL指针,说明已经到了链式缓冲区的末尾,我们的循环应该结束了。 NdisGetNextBuffer(NdisBuffer, &NdisBuffer); if (NdisBuffer == NULL) break; } // 取得数据包内容后,下面将对其内容进行过滤。 (*ppBuffer) = pPacketContent; (*pnBufferLen) = DataOffset; return FILTER_STATUS_PASS; } void freePacketBuffer(PCHAR pBuffer) { NdisFreeMemory(pBuffer, 0, 0); } NDIS_STATUS sendRawBuffer(PADAPT adapt, PUCHAR pBuffer, ULONG nBufLen) { NDIS_STATUS status = NDIS_STATUS_SUCCESS; PNDIS_PACKET ndisPacket = NULL; PNDIS_BUFFER ndisBuffer = NULL; PUCHAR sendBuffer = NULL; PSEND_RSVD sendRsvd = NULL; NDIS_PHYSICAL_ADDRESS highestAcceptableAddress; highestAcceptableAddress.QuadPart = -1; DbgPrint("passthru sendRawData,正在发包\n"); NdisAllocatePacket(&status, &ndisPacket, adapt->SendPacketPoolHandle); if (status != NDIS_STATUS_SUCCESS) { NdisFreeMemory(sendBuffer, nBufLen, 0); return status; } NdisAllocateBuffer(&status, &ndisBuffer, adapt->SendPacketPoolHandle, pBuffer, nBufLen); if (status != NDIS_STATUS_SUCCESS) { NdisFreeMemory(sendBuffer, nBufLen, 0); NdisFreePacket(ndisPacket); return status; } NdisChainBufferAtFront(ndisPacket, ndisBuffer); sendRsvd = (PSEND_RSVD)(ndisPacket->ProtocolReserved); sendRsvd->OriginalPkt = 0xfcfcfcfc; //标记自己 ndisPacket->Private.Head->Next = NULL; ndisPacket->Private.Tail = NULL; NdisSetPacketFlags(ndisPacket, NDIS_FLAGS_DONT_LOOPBACK); NdisSend(&status, adapt->BindingHandle, ndisPacket); if (status != STATUS_PENDING) { NdisUnchainBufferAtFront(ndisPacket, &ndisBuffer); NdisQueryBufferSafe(ndisBuffer, &sendBuffer, &nBufLen, NormalPagePriority); NdisFreeBuffer(ndisBuffer); NdisFreeMemory(sendBuffer, nBufLen, 0); NdisFreePacket(ndisPacket); } return status; } void freePacket(PNDIS_PACKET Packet) { NDIS_STATUS status; PNDIS_BUFFER NdisBuffer; PNDIS_BUFFER OldNdisBuffer; UINT TotalPacketLength = 0; UINT PhysicalBufferCount; UINT BufferCount; PUCHAR tembuffer = NULL; UINT copysize = 0; if (!Packet) { status = NDIS_STATUS_FAILURE; return status; } NdisQueryPacket(Packet, // NDIS_PACKET &PhysicalBufferCount,// 内存中的物理块数 &BufferCount, // 多少个NDIS_BUFFER包 &NdisBuffer, // 将返回第一个包 &TotalPacketLength // 总共的包数据长度 ); while (TRUE) { NdisQueryBufferSafe(NdisBuffer, &tembuffer,// 缓冲区地址 ©size, // 缓冲区大小 NormalPagePriority ); // 如果tembuffer为NULL,说明当前系统资源匮乏。 if (tembuffer == NULL) { status = NDIS_STATUS_FAILURE; return status; } // 获得下一个NDIS_BUFFER。 // 如果得到的是一个NULL指针,说明已经到了链式缓冲区的末尾,我们的循环应该结束了。 OldNdisBuffer = NdisBuffer; NdisGetNextBuffer(NdisBuffer, &NdisBuffer); NdisUnchainBufferAtFront(Packet, &OldNdisBuffer); NdisFreeBuffer(OldNdisBuffer); NdisFreeMemory(tembuffer, 0, 0); if (NdisBuffer == NULL) break; } NdisFreePacket(Packet); } |
|
地下室#
发布于:2012-12-10 10:52
回 hsluoyz 的帖子
hsluoyz:收报后转发我在网上快找死了也没找到,后来自己写的,还算能用,就是不知道有没有内存泄露什么的,主要函数就是下面几个,看名字就知道了 谢谢你了,看了对我很有帮助,真的很感谢 |
|
5楼#
发布于:2012-12-10 13:18
回 hsluoyz 的帖子
hsluoyz:收报后转发我在网上快找死了也没找到,后来自己写的,还算能用,就是不知道有没有内存泄露什么的,主要函数就是下面几个,看名字就知道了 对了,包头的IP好像没有改,如何把包头IP改成我自己想发送的IP地址呢? |
|
6楼#
发布于:2012-12-10 23:46
用下面的几个结构套在字节指针上,再修改就行了,IP地址注意字节序
#define ETHER_ADDR_LEN 6 typedef struct _Eth_Header { UCHAR eth_DstAddr[ETHER_ADDR_LEN]; UCHAR eth_SrcAddr[ETHER_ADDR_LEN]; USHORT eth_Type; } Eth_Header, *PEth_Header; typedef struct _ARP_header //ARP头部 { USHORT arp_HardType; USHORT arp_ProtType; UCHAR arp_hardAddrLen; UCHAR arp_protAddrLen; USHORT arp_Opcode; UCHAR arp_srcHardAddr[6]; ULONG arp_srcProtAddr; UCHAR arp_dstHardAddr[6]; ULONG arp_dstProtAddr; } ARP_Header, *PARP_Header; typedef struct _IP_Header // 20字节的IP头 { UCHAR ip_hVerLen; // 4位首部长度+4位IP版本号 | Version (4 bits) + Internet header length (4 bits) UCHAR ip_TOS; // 8位服务类型 | TOS Type of service USHORT ip_Length; // 16位封包总长度,即整个IP报的长度 | Total length USHORT ip_ID; // 16位封包标识,惟一标识发送的每一个数据报 | Identification USHORT ip_Flags; // 3位标志位+13报片偏移 | Flags (3 bits) + Fragment offset (13 bits) UCHAR ip_TTL; // 8位生存时间,就是TTL | Time to live UCHAR ip_Protocol; // 8位协议,TCP、UDP、ICMP等 | Protocol USHORT ip_Checksum; // 16位IP首部校验和 | Header checksum ULONG ip_Src; // 32位源IP地址 | Source address ULONG ip_Dst; // 32位目标IP地址 | Destination address } IP_Header, *PIP_Header; |
|
7楼#
发布于:2012-12-11 10:12
修改报文的ip,最好是在mpsendpackets里面,抓到要发送的报文后,在内存buffer里面修改报文内容(参照楼上的格式),然后用修改后的报文内存,另外组建一个packet发送出去。
至于原来的packet,先不动他,将它的地址保存在新packet里面(见下面的代码,新packet是MyPacket,原来的packet是Packet),等到新packet发送成功了,销毁新packet申请的资源,并通知上层旧packet发送成功了。 三句两句很难讲清楚,你可以买《寒江独钓——Windows内核安全编程》看看。 typedef struct _SEND_RSVD { PNDIS_PACKET OriginalPkt; } SEND_RSVD, *PSEND_RSVD; PSEND_RSVD SendRsvd; SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved); SendRsvd->OriginalPkt = Packet; |
|
8楼#
发布于:2012-12-12 21:53
谢谢大家了,虽然我还没有搞定,但是还是要谢谢你们
|
|