&ProtocolChar,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (Status != NDIS_STATUS_SUCCESS) { //注册失败,函数返回 return Status; }
/*设置IRP派遣函数和卸载例程*/
DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_Open; DriverObject->MajorFunction[IRP_MJ_CLOSE] = NPF_Close; DriverObject->MajorFunction[IRP_MJ_CLEANUP]= NPF_Cleanup; DriverObject->MajorFunction[IRP_MJ_READ] = NPF_Read; DriverObject->MajorFunction[IRP_MJ_WRITE] = NPF_Write;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NPF_IoControl; DriverObject->DriverUnload = NPF_Unload;// 卸载例程
/*获取系统中可用的网络适配器信息*/ bindP = getAdaptersList();
if (bindP == NULL)
{//没有找到适配器,试图复制TCP-IP的绑定 tcpBindingsP = getTcpBindings();
if (tcpBindingsP == NULL)
{//TCP-IP没有找到,函数退出 goto RegistryError; }
bindP = (WCHAR*)tcpBindingsP;
bindT = (WCHAR*)(tcpBindingsP->Data); } else {
bindT = bindP; }
for (; *bindT != UNICODE_NULL;
bindT += (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR))
{
RtlInitUnicodeString(&macName, bindT);
NPF_CreateDevice(DriverObject, &macName);//给一个适配器创建一个设备对象 }
return STATUS_SUCCESS;
/*处理函数错误*/ RegistryError:
NdisDeregisterProtocol( &Status,
g_NdisProtocolHandle );
Status=STATUS_UNSUCCESSFUL; return(Status); }
1.3.1 getAdaptersList函数
函数getAdaptersList返回系统中可用的MAC链表,函数的原型如下: PWCHAR getAdaptersList(VOID);
函数返回一个包含网络适配器链表的字符串。
该适配器链表从注册表的SYSTEM\\\\CurrentControlSet\\\\Control\\\\Class
\\\\{4D36E972-E325-11CE-BFC1-08002BE10318}注册项获取。函数首先遍历该注册表项,获取子项的信息,再打开子项的“Linkage”子项,在“Linkage”子项下查找“Export”键名的键值,如在图5-2中,键值为“\\Device\\NdisWanIp”。并把键值存储到内存中,形成一个列表。函数最后返回该列表。
NPF试图从这个链表创建它的绑定。通过这种方式,它可以动态的加载或卸载,而不用通过控制面板操作。
图5-2 注册表项0006\\Linkage
函数的主要代码如下: PWCHAR getAdaptersList(void) {
PKEY_VALUE_PARTIAL_INFORMATION result = NULL; OBJECT_ATTRIBUTES objAttrs; NTSTATUS status; HANDLE keyHandle; UINT BufPos=0; UINT BufLen=4096;
/*分配DeviceNames所需的内存空间*/
PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen, '0PWA');
if (DeviceNames == NULL)
{//分配失败,函数返回 return NULL; } /*
*设置一个OBJECT_ATTRIBUTES类型的参数objAttrs,为了后续调用 *其中NDIS_STRING AdapterListKey =
* NDIS_STRING_CONST(\ * \\\\Control\\\\Class\\\\{4D36E972-E325-11CE-BFC1-08002BE10318}\ */
InitializeObjectAttributes(&objAttrs, &AdapterListKey, OBJ_CASE_INSENSITIVE, NULL, NULL);
/*打开注册表表项,返回objAttrs中所描述的注册表表项的句柄*/ status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs); if (!NT_SUCCESS(status)) { //打开失败 }
else { //打开成功 ULONG resultLength;
KEY_VALUE_PARTIAL_INFORMATION valueInfo; CHAR AdapInfo[1024];
UINT i=0;
/*遍历设备链表,获取一个已打开注册表项子项的信息*/ while((status=ZwEnumerateKey(keyHandle,i,KeyBasicInformation,
AdapInfo,sizeof(AdapInfo),&resultLength))==STATUS_SUCCESS) {
WCHAR ExportKeyName [512];
//所打开的注册表项 PWCHAR ExportKeyPrefix =
L\
Control\\\\Class\\\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\\\\; UINT ExportKeyPrefixSize =
sizeof(L\ Control\\\\Class\\\\{4D36E972-E325-11CE-BFC1-08002BE10318}\);
//需要打开的子项\
PWCHAR LinkageKeyPrefix = L\; UINT LinkageKeyPrefixSize = sizeof(L\); //所查找的键名为\
NDIS_STRING FinalExportKey = NDIS_STRING_CONST(\);
PKEY_BASIC_INFORMATION tInfo=
(PKEY_BASIC_INFORMATION)AdapInfo; UNICODE_STRING AdapterKeyName; HANDLE ExportKeyHandle;
//合成要打开的注册表子项,如图5-2中的为:
//”\\\\Registry\\\\Machine\\\\System\\\\CurrentControlSet\\\\Control //\\\\Class\\\\{4D36E972-E325-11CE-BFC1-08002BE10318} //\\\\0006\\\\Linkage”
RtlCopyMemory(ExportKeyName,ExportKeyPrefix, ExportKeyPrefixSize);
RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize,
tInfo->Name,tInfo->NameLength+2); RtlCopyMemory(
(PCHAR)ExportKeyName+ExportKeyPrefixSize+tInfo->NameLength, LinkageKeyPrefix,LinkageKeyPrefixSize);
/*给一个Unicode字符串初始化赋值*/
RtlInitUnicodeString(&AdapterKeyName, ExportKeyName);
/*设置一个OBJECT_ATTRIBUTES类型的参数objAttrs,为了后续调用*/
InitializeObjectAttributes(&objAttrs, &AdapterKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
/*打开注册表表项,返回objAttrs中所描述的注册表表项的句柄*/ status=ZwOpenKey(&ExportKeyHandle,KEY_READ,&objAttrs); if (!NT_SUCCESS(status)) {//打开失败,跳出本次循环 continue; }
/*查找“Export”键名的键值信息*/
status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey, KeyValuePartialInformation, &valueInfo, sizeof(valueInfo), &resultLength);
if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) { //查询失败 }
else { //查询成功
/*计算所需的内存大小*/
ULONG valueInfoLength = valueInfo.DataLength +
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
/*分配内存,用于查询*/
PKEY_VALUE_PARTIAL_INFORMATION valueInfoP =
(PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag
(PagedPool, valueInfoLength, '1PWA');
if (valueInfoP != NULL) {
status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
KeyValuePartialInformation, valueInfoP,
valueInfoLength, &resultLength);