xczc10@sina.cn
驱动牛犊
驱动牛犊
  • 注册日期2012-12-06
  • 最后登录2012-12-23
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望171点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2347回复:8

NDIS驱动 菜鸟求教。

楼主#
更多 发布于:2012-12-07 20:20


在NDIS驱动中,如何把接受的数据包。转发出去。有人说改IP头或IP。然后算校检,然后发送出去,是这样吗?

现在的问题是,在xpassthru中调用MPSendOnePacket自定义函数在这个函数里面如何改IP地址和校检?
我是刚学的菜鸟,请前辈们指点一下,非常感谢了。如果有源码,可以贴出来我学习。。先谢了
hsluoyz
驱动牛犊
驱动牛犊
  • 注册日期2009-01-31
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望111点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2012-12-08 23:53
xpassthru没看过,只看过passthru,它的packet buffer和内存都是自己分配的话,肯定是可以改的
xczc10@sina.cn
驱动牛犊
驱动牛犊
  • 注册日期2012-12-06
  • 最后登录2012-12-23
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望171点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2012-12-09 15:34
有没有什么资料参考呢?如果能修改IP和包的内容在转发出去,那需要怎么做?
很是郁闷
hsluoyz
驱动牛犊
驱动牛犊
  • 注册日期2009-01-31
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望111点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于: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,// 缓冲区地址
            &copysize, // 缓冲区大小
            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,// 缓冲区地址
            &copysize, // 缓冲区大小
            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);
}
xczc10@sina.cn
驱动牛犊
驱动牛犊
  • 注册日期2012-12-06
  • 最后登录2012-12-23
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望171点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2012-12-10 10:52
回 hsluoyz 的帖子
hsluoyz:收报后转发我在网上快找死了也没找到,后来自己写的,还算能用,就是不知道有没有内存泄露什么的,主要函数就是下面几个,看名字就知道了

NDIS_STATUS getPacketBuffer(PNDIS_PACKET Packet, PUCHAR *ppBuffer, UINT *pnBufferLen)
{
    NDIS_STATUS status .. (2012-12-10 00:22)

谢谢你了,看了对我很有帮助,真的很感谢
xczc10@sina.cn
驱动牛犊
驱动牛犊
  • 注册日期2012-12-06
  • 最后登录2012-12-23
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望171点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2012-12-10 13:18
回 hsluoyz 的帖子
hsluoyz:收报后转发我在网上快找死了也没找到,后来自己写的,还算能用,就是不知道有没有内存泄露什么的,主要函数就是下面几个,看名字就知道了

NDIS_STATUS getPacketBuffer(PNDIS_PACKET Packet, PUCHAR *ppBuffer, UINT *pnBufferLen)
{
    NDIS_STATUS status .. (2012-12-10 00:22)

对了,包头的IP好像没有改,如何把包头IP改成我自己想发送的IP地址呢?
hsluoyz
驱动牛犊
驱动牛犊
  • 注册日期2009-01-31
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望111点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
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;
zhangfresh
驱动牛犊
驱动牛犊
  • 注册日期2008-07-21
  • 最后登录2024-11-22
  • 粉丝1
  • 关注2
  • 积分94分
  • 威望871点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
  • 社区居民
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;
xczc10@sina.cn
驱动牛犊
驱动牛犊
  • 注册日期2012-12-06
  • 最后登录2012-12-23
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望171点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2012-12-12 21:53
谢谢大家了,虽然我还没有搞定,但是还是要谢谢你们
游客

返回顶部