驱动的测试代码解读
1. 打开设备对象:
// 1. 打开底层设备对象
HANDLE hDevice = CreateFile(
L"\\\\.\\NDISFilter", // 设备名称
GENERIC_READ | GENERIC_WRITE, // 访问权限
0, // 不共享
NULL, // 默认安全属性
OPEN_EXISTING, // 打开现有设备
0, // 无特殊标志
NULL // 无模板句柄
);
if (hDevice == INVALID_HANDLE_VALUE)
{
std::cerr << "Failed to open NDISFilter device. Error: " << GetLastError() << std::endl;
return 1;
}
2. 获取网卡地址:
// 2. 获取网卡数目
ULONG ulNetAdapterCount = 0;
DWORD dwReadSize = 0;
BOOL nRet = FALSE;
CHAR* pData = NULL;
CHAR Temp[4];
nRet = DeviceIoControl(
hDevice,
IOCTL_FILTER_GET_NUMBER,
NULL,
0,
&ulNetAdapterCount,
sizeof(ULONG),
&dwReadSize,
NULL
);
if (!nRet)
{
std::cerr << "IOCTL_FILTER_GET_NUMBER DeviceIoControl Faild !" << std::endl;
goto Exit;
}
// 3. 获取网卡的Mac地址
pData = new CHAR[_BUFFER_SIZE];
nRet = DeviceIoControl(
hDevice,
IOCTL_FILTER_GET_ALL_ADDRESS,
NULL,
0,
pData,
ulNetAdapterCount * _MAC_LENGTH,
&dwReadSize,
NULL
);
if (!nRet)
{
std::cerr << "IOCTL_FILTER_GET_ALL_ADDRESS DeviceIoControl Faild !" << std::endl;
goto Exit;
}
for (int i = 0; i < ulNetAdapterCount; i++)
{
UCHAR* pAddr = (UCHAR*)pData + i * _MAC_LENGTH;
std::cout << i << ":" << std::hex << *(pAddr + 0) << std::hex << *(pAddr + 1) << std::hex << *(pAddr + 2) << std::hex << *(pAddr + 3) << std::hex << *(pAddr + 4) << std::hex << *(pAddr + 5) << std::endl;
}
3. 发送数据包
// 4. 测试发送ICMP数据包
PACKET_INFO PacketInfo;
memset(&PacketInfo, 0, sizeof(PACKET_INFO));
PacketInfo.SrcMac[0] = 0x00;
PacketInfo.SrcMac[1] = 0x0C;
PacketInfo.SrcMac[2] = 0x29;
PacketInfo.SrcMac[3] = 0xDB;
PacketInfo.SrcMac[4] = 0x9F;
PacketInfo.SrcMac[5] = 0x34;
PacketInfo.DesMac[0] = 0x00;
PacketInfo.DesMac[1] = 0x0C;
PacketInfo.DesMac[2] = 0x29;
PacketInfo.DesMac[3] = 0xDB;
PacketInfo.DesMac[4] = 0x9F;
PacketInfo.DesMac[5] = 0x34;
// 12.17.10.8
PacketInfo.SrcIPv4 = inet_addr("12.17.10.8");
PacketInfo.DesIPv4 = inet_addr("12.17.10.8");
memset(PacketInfo.Data, 8, _DATA_SIZE);
PacketInfo.Length = ICMP_PACKET_SIZE;
// 发送数据包
nRet = DeviceIoControl(
hDevice,
IOCTL_FILTER_SEND_DATA,
&PacketInfo,
sizeof(PACKET_INFO),
&PacketInfo,
sizeof(PACKET_INFO),
&dwReadSize,
NULL
);
if (!nRet)
{
std::cerr << "IOCTL_FILTER_SEND_DATA DeviceIoControl Faild !" << std::endl;
goto Exit;
}
std::cerr << "IOCTL_FILTER_SEND_DATA DeviceIoControl OK ! count = " << nCount << std::endl;
// 5. 获取数据包
nRet = DeviceIoControl(
hDevice,
IOCTL_FILTER_RECEIVE_DATA,
&PacketInfo,
sizeof(PACKET_INFO),
&PacketInfo,
sizeof(PACKET_INFO),
&dwReadSize,
NULL
);
if (!nRet)
{
std::cerr << "IOCTL_FILTER_RECEIVE_DATA DeviceIoControl Faild !" << std::endl;
goto Exit;
}
std::cerr << "IOCTL_FILTER_RECEIVE_DATA DeviceIoControl OK ! count = " << nCount++
<< ", dwReadSize = " << dwReadSize << ", struct->length = " << PacketInfo.Length << std::endl;
4. 打印数据包:
try
{
memset(pData, 0, _BUFFER_SIZE);
PCHAR pCopy = pData;
for (int i = 0; i < dwReadSize; i++)
{
memset(Temp, 0, 4);
int n = _itoa_s((UCHAR)PacketInfo.Data[i], Temp, 16);
Temp[strlen(Temp)] = '\0';
strcpy_s(pCopy, 4, Temp);
pCopy += strlen(Temp);
}
std::cerr << "IOCTL_FILTER_RECEIVE_DATA DeviceIoControl OK ! Data = " << pData << std::endl;
}
catch (const std::exception& ex)
{
std::cerr << ex.what();
}
5. 关闭设备
Exit:
if (NULL != pData) delete[]pData;
std::cerr << " close NDISFilter device. OK!" << std::endl;
// 关闭设备对象
CloseHandle(hDevice);
代码在资源中的FilterDemo中。
驱动的安装和测试
NDIS比较特殊,我们需要以下面的方式进行安装:
1. 打开任意一个网络适配器,定位到属性:
2. 点击安装后,会有以下界面:
协议驱动也在这里安装,Filter选择服务就行。
3. 找到安装驱动的路径:
4. 然后安装即可,中间会提示我们是否需要加载测试签名的驱动,选择是就好。
5. 测试程序运行界面如下:
此时,我们注意到我们接收到的数据就是我们发送出去的数据,因为我们将缓冲区全部设置为8。