You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows 10内核驱动开发中如何获取NetBIOS主机名

Windows 10内核驱动获取NetBIOS主机名实现方案

用户态下GetComputerNameExA(ComputerNameNetBIOS)可获取NetBIOS格式主机名,内核态下无需跨环调用用户态API,可通过以下两种稳定方案实现相同功能,适配Windows 10全版本。

方案1:调用内核原生API RtlGetComputerNameEx(推荐)

RtlGetComputerNameEx是ntoskrnl.exe导出的内核例程,和用户态GetComputerNameEx逻辑完全对等,WDK头文件未包含该函数声明,需手动定义原型后通过MmGetSystemRoutineAddress动态获取调用。

首先定义依赖的枚举和函数指针:

typedef enum _COMPUTER_NAME_FORMAT {
    ComputerNameNetBIOS,
    ComputerNameDnsHostname,
    ComputerNameDnsDomain,
    ComputerNameDnsFullyQualified,
    ComputerNamePhysicalNetBIOS,
    ComputerNamePhysicalDnsHostname,
    ComputerNamePhysicalDnsDomain,
    ComputerNamePhysicalDnsFullyQualified,
    ComputerNameMax
} COMPUTER_NAME_FORMAT;

typedef NTSTATUS(NTAPI* PFN_RtlGetComputerNameEx)(
    _In_ COMPUTER_NAME_FORMAT NameType,
    _Inout_ PUNICODE_STRING lpBuffer
);

调用示例代码:

// 函数返回后,outName中存储宽字符格式的NetBIOS主机名,使用完成后需释放outName->Buffer指向的内存
NTSTATUS GetKernelNetBIOSName(PUNICODE_STRING outName)
{
    NTSTATUS ntStatus;
    UNICODE_STRING routineName = RTL_CONSTANT_STRING(L"RtlGetComputerNameEx");
    PFN_RtlGetComputerNameEx RtlGetComputerNameEx = 
        (PFN_RtlGetComputerNameEx)MmGetSystemRoutineAddress(&routineName);

    if (RtlGetComputerNameEx == NULL) {
        return STATUS_PROCEDURE_NOT_FOUND;
    }

    // NetBIOS名最大长度15字符,预留足够缓冲区
    const ULONG bufSize = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
    outName->Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_NON_PAGED, bufSize, 'mNbH');
    if (outName->Buffer == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    outName->Length = 0;
    outName->MaximumLength = bufSize;

    ntStatus = RtlGetComputerNameEx(ComputerNameNetBIOS, outName);
    if (!NT_SUCCESS(ntStatus)) {
        ExFreePool(outName->Buffer);
        outName->Buffer = NULL;
    }

    return ntStatus;
}

如果需要和GetComputerNameExA输出完全一致的ANSI格式字符串,拿到UNICODE_STRING结果后调用RtlUnicodeStringToAnsiString转换即可。

方案2:读取注册表获取(备用兼容方案)

系统NetBIOS名持久化存储在注册表中,可通过内核注册表API直接读取,兼容所有Windows版本,适合作为上述API调用失败时的降级方案。
目标注册表路径:\Registry\Machine\System\CurrentControlSet\Control\ComputerName\ComputerName,键值名ComputerName,类型为REG_SZ,存储内容即为NetBIOS主机名。

调用示例代码:

NTSTATUS GetNetBIOSNameFromRegistry(PUNICODE_STRING outName)
{
    NTSTATUS ntStatus;
    HANDLE hRegKey = NULL;
    OBJECT_ATTRIBUTES objAttrs;
    UNICODE_STRING keyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName");
    UNICODE_STRING valueName = RTL_CONSTANT_STRING(L"ComputerName");
    ULONG retSize = 0;
    PKEY_VALUE_PARTIAL_INFORMATION pValueInfo = NULL;

    InitializeObjectAttributes(&objAttrs, &keyPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    ntStatus = ZwOpenKey(&hRegKey, KEY_READ, &objAttrs);
    if (!NT_SUCCESS(ntStatus)) {
        return ntStatus;
    }

    // 先查询键值所需缓冲区长度
    ntStatus = ZwQueryValueKey(hRegKey, &valueName, KeyValuePartialInformation, NULL, 0, &retSize);
    if (ntStatus != STATUS_BUFFER_TOO_SMALL) {
        ZwClose(hRegKey);
        return ntStatus;
    }

    pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, retSize, 'rNbH');
    if (pValueInfo == NULL) {
        ZwClose(hRegKey);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    ntStatus = ZwQueryValueKey(hRegKey, &valueName, KeyValuePartialInformation, pValueInfo, retSize, &retSize);
    if (NT_SUCCESS(ntStatus)) {
        outName->Length = pValueInfo->DataLength;
        outName->MaximumLength = pValueInfo->DataLength;
        outName->Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_NON_PAGED, pValueInfo->DataLength, 'oNbH');
        if (outName->Buffer == NULL) {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        } else {
            RtlCopyMemory(outName->Buffer, pValueInfo->Data, pValueInfo->DataLength);
        }
    }

    ExFreePool(pValueInfo);
    ZwClose(hRegKey);
    return ntStatus;
}

开发注意事项

  • 上述两种方法都必须在IRQL = PASSIVE_LEVEL级别调用,禁止在Dispatch或更高IRQL下执行,否则会触发系统蓝屏
  • 分配的内核内存使用完成后必须调用ExFreePool释放,避免内核内存泄漏
  • 禁止直接从内核态跳转调用用户态GetComputerNameExA,跨环调用无异常处理保护,极易触发权限错误或系统崩溃
  • NetBIOS主机名最大长度为15个字符,缓冲区预留MAX_COMPUTERNAME_LENGTH + 1长度即可满足需求
  • 若需兼容Windows 10 2004以前的版本,可将代码中ExAllocatePool2替换为ExAllocatePoolWithTag即可

内容的提问来源于stack exchange,提问作者osok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 05:36:34