4、指纹采集技术(上):操作系统层采集

操作系统层的指纹采集,说白了就是跟系统内核“要数据”。Windows 有注册表,Linux 有 /proc 文件系统。这两个东西,是设备指纹最底层的“矿藏”。

我刚开始做资产盘点的时候,也试过用各种 Agent 去扫。后来发现,很多关键信息其实操作系统自己就记着,只是你没找对地方。今天咱们就把这两个“数据源”彻底聊透。

4.1 Windows 注册表:系统的“记忆宫殿”

Windows 注册表,你可以把它想象成一个巨大的树形数据库。从硬件配置到软件安装,从用户设置到网络参数,全在里面。指纹采集,就是从这个“宫殿”里提取关键特征。

4.1.1 注册表结构速览

注册表分五大根键,咱们做指纹采集,重点关注这几个:

根键 缩写 采集价值
HKEY_LOCAL_MACHINE HKLM 硬件、系统、安全信息(核心)
HKEY_CURRENT_CONFIG HKCC 当前硬件配置文件
HKEY_CLASSES_ROOT HKCR 文件关联、COM 组件(辅助)
我的习惯: 优先从 HKLM 下手。HKLM\HARDWARE 下面存的是最原始的硬件探测结果,基本不受用户操作影响,指纹稳定性最高。

4.1.2 关键采集路径

我个人总结了几个“必采”路径,你在项目里可以直接套用:

  • CPU 信息: HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0
    取 ProcessorNameString 和 Identifier。注意,Identifier 里包含步进和修订版本,是区分同型号 CPU 的关键。
  • 主板/BIOS: HKLM\HARDWARE\DESCRIPTION\System\BIOS
    BaseBoardManufacturer、BaseBoardProduct、SystemSerialNumber。序列号是硬指纹,但有些组装机是空值,要做好容错。
  • 网卡 MAC: HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}
    遍历子项,找 NetCfgInstanceId 和 MACAddress。这里有个坑,虚拟网卡和 VPN 网卡也会出现,需要过滤。
  • 磁盘序列号: HKLM\SYSTEM\MountedDevices
    或者通过 WMI 转储到注册表。磁盘序列号是唯一性很高的指纹因子。
我曾经踩过的坑: 注册表路径里的 GUID 是固定的,但子项编号(如 0000、0001)可能因驱动安装顺序变化。不要硬编码子项索引,要用循环遍历。

4.1.3 采集代码示例(PowerShell)

我建议用 PowerShell 做原型验证,它原生支持注册表操作,写起来很快。

# 采集 CPU 信息
$cpuPath = "HKLM:\HARDWARE\DESCRIPTION\System\CentralProcessor\0"
$cpuInfo = Get-ItemProperty -Path $cpuPath
$fingerprint = @{
    CPUName = $cpuInfo.ProcessorNameString
    CPUIdentifier = $cpuInfo.Identifier
}

# 采集 BIOS 序列号
$biosPath = "HKLM:\HARDWARE\DESCRIPTION\System\BIOS"
$biosInfo = Get-ItemProperty -Path $biosPath
$fingerprint.BIOSSerial = $biosInfo.SystemSerialNumber

# 输出 JSON 格式指纹
$fingerprint | ConvertTo-Json

这段代码跑完,你会得到一个 JSON 对象。这就是最原始的“操作系统层指纹片段”。

4.2 Linux /proc 文件系统:内核的“实时快照”

Linux 下没有注册表,但 /proc 文件系统更强大。它不是一个真正的文件系统,而是内核数据结构的运行时接口。你读 /proc 下的文件,其实就是在内核里查表。

你想想看,/proc 里的文件大多是 0 字节,但 cat 一下却能输出一堆信息。为什么?因为它不是静态文件,是内核动态生成的。

4.2.1 核心采集文件

文件路径 采集内容 指纹价值
/proc/cpuinfo CPU 型号、核心数、标志位 高(含 vendor_id、model name、flags)
/proc/meminfo 内存总量、内存分区 中(MemTotal 可用于辅助校验)
/proc/diskstats 磁盘设备号、读写统计 中(设备号可映射到具体磁盘)
/proc/net/arp IP 与 MAC 对应表 高(采集本机 MAC 的可靠来源)
/proc/version 内核版本、GCC 版本 低(变化快,但可做环境校验)
核心原则: /proc 下的信息是“所见即所得”。但要注意,某些容器环境(如 Docker)会隔离 /proc,你看到的可能是宿主机的信息,也可能是容器自己的命名空间视图。采集时一定要判断是否在容器内。

4.2.2 采集代码示例(Shell)

Linux 下我习惯用 Shell 脚本 + awk 处理。简单、高效、依赖少。

#!/bin/bash
# 采集 CPU 指纹
CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | sed 's/^ //')
CPU_CORES=$(grep "cpu cores" /proc/cpuinfo | head -1 | awk '{print $4}')
CPU_FLAGS=$(grep "flags" /proc/cpuinfo | head -1 | cut -d: -f2 | sed 's/^ //')

# 采集 MAC 地址(从 ARP 表取本机)
MY_IP=$(hostname -I | awk '{print $1}')
MAC_ADDR=$(grep "$MY_IP" /proc/net/arp | awk '{print $4}')

# 采集磁盘序列号(通过 udev 或 smartctl,/proc 本身不直接提供)
# 这里用 /proc/diskstats 获取设备名
DISK_DEV=$(grep "sd" /proc/diskstats | head -1 | awk '{print $3}')

echo "{\"cpu_model\":\"$CPU_MODEL\",\"cpu_cores\":\"$CPU_CORES\",\"mac\":\"$MAC_ADDR\",\"disk_dev\":\"$DISK_DEV\"}"
避坑指南: /proc/cpuinfo 里的 "flags" 字段包含 CPU 支持的指令集(如 aes、avx2)。这个字段在不同型号 CPU 上差异很大,是区分“同系列不同批次”CPU 的利器。我曾经靠这个字段,揪出了一批被供应商偷换型号的服务器。

4.3 操作系统层指纹的“稳定性”与“可变性”

采集到数据只是第一步。你得知道哪些指纹是“死”的,哪些是“活”的。我把它分成三类:

  • 硬指纹(高稳定): CPU ID、主板序列号、磁盘序列号。只要硬件不换,这些值不变。
  • 软指纹(中稳定): MAC 地址、主机名、内核版本。重装系统或更换网卡会变。
  • 动态指纹(低稳定): 内存大小、IP 地址、启动时间。每次重启都可能变。

做资产台账时,我建议用“硬指纹 + 软指纹”组合成主键。动态指纹只做辅助校验,不要用它做唯一标识。

4.4 知识体系总览

下面这张图,是我梳理的操作系统层指纹采集的核心逻辑。你可以把它当作本章的“地图”。

操作系统层指纹采集知识体系 操作系统层指纹采集知识体系 操作系统层指纹采集 Windows 注册表 Linux /proc 文件系统 HKLM\HARDWARE HKLM\SYSTEM HKLM\SOFTWARE /proc/cpuinfo /proc/net/arp /proc/diskstats 核心产出:硬指纹 + 软指纹 组合主键 CPU ID / 主板序列号 / MAC 地址 / 磁盘序列号

4.5 本章小结

操作系统层采集,是设备指纹的“地基”。Windows 靠注册表,Linux 靠 /proc。两者思路一致:从系统核心数据结构中,提取那些“换了机器就会变”的特征。

我个人建议,你在做采集引擎时,先把 Windows 和 Linux 的采集模块分开写。不要试图用一个万能脚本兼容两个系统。分开写,维护成本反而更低。