本帖最后由 gsgdf 于 2026-9-11 00:39 编辑
K3和GLM5.3的额度见底,用DeepSeek V4.1 Flash先凑活玩玩。跑了快两小时终于跑出来了。模型:DeepSeek V4.1 Flash 智能体:zcode
PlugPlayService.sys 安全分析报告[td]项目 | 内容 | | 分析对象 | C:\Users\**\Desktop\12\PlugPlayService.sys | | 文件大小 | 128,200 字节 | | 分析日期 | 2026-09-11 | | 分析方法 | 纯静态逆向(IDA 级手工 + Ghidra 12.1.3 Headless + Detect It Easy)+ OSINT | | 执行情况 | 全程未执行、未加载、未注册该驱动(详见 §11 方法论与限制) | | 结论摘要 | 恶意。经确认为已公开收录的 WHQL 签名 BYOVD 内核恶意驱动(内核 PE 加载器 / Rootkit 原语) |
1. 结论摘要(TL;DR)PlugPlayService.sys 不是普通商业软件组件,也不是误报。它是一个持有有效微软 WHQL/attestation 签名、但被高度混淆的恶意 Windows 内核驱动,在 LOLDrivers 漏洞驱动库中已被独立收录并标记为 malicious(MITRE T1014 Rootkit,Verified=TRUE)。 本报告基于完全独立的静态逆向,得出与该情报逐条吻合的结论: [td]我方独立观测(实测) | LOLDrivers 情报描述 | | 所有内核 API 调用均通过"指针混淆表"间接发起 | "encoded indirect calls" | | DriverEntry 调用 PsCreateSystemThread 创建工作线程 | "system-thread creation" | | FUN_140011729 调用 MmMapIoSpace / MmUnmapIoSpace | "physical-memory mapping" | | FUN_140005324 用 ObReferenceObjectByName 打开 \Driver\Disk 并 IoEnumerateDeviceObjectList 枚举其设备对象 | "enumeration of Disk driver device objects" | | 无资源/无版本信息/无 PDB,含 MBA 常量展开与反编译阻断结构 | "heavily obfuscated" |
核心风险:该驱动具备任意物理内存映射、按字节特征码在其它内核模块中定位并调用函数、直接改写其它驱动设备扩展(Device Extension)、直接访问 RAID/磁盘设备栈、TPM 设备访问、以及内嵌加密载荷等能力。这类驱动是典型的 BYOVD(Bring Your Own Vulnerable Driver)武器化组件:因其携带合法微软签名,可在启用了驱动签名强制的 Windows 上被正常加载,从而绕过后被用于关闭/绕过 EDR、篡改安全软件、或作为 Rootkit/Bootkit 的落地原语。 处置建议(一句话):不要加载。按 IOC 全网排查 + 阻断哈希/签名 + 上报微软 MSRC 吊销签名。 置信度:高。静态证据、能力映射、外部情报三方独立一致。
2. 样本信息与证据固化2.1 哈希与文件属性[td]算法 | 值 | | MD5 | a26abe238cc339da81f4853ab16e1a6a | | SHA1 | 4a0afc37e3a0f180ca3540aabe871d274caafc30 | | SHA256 | 8f6d843cdec4d3477867225cf0804850e4901a541e095c01feab5634c3f3de99 | | Imphash | bf2ebfe7fdc706c13b4427fe5fa3413c | | Authentihash (SHA256) | 10d0c1f97625ee033b0bdf4136d47a34779a36cf83b82410722ad51fa50df5a6 | | 文件时间戳 | LastWriteTime 2026-09-08 10:42:46 UTC | | 属性 | Archive(非隐藏/非系统) | 2.2 样本同一性核验与同源样本分析全程使用主样本 PlugPlayService.sys 的唯一副本,副本哈希与原件逐一比对一致(SHA256 均为 8f6d843c…3de99,校验结果 identical: True),确保本报告所述现象与交付样本同一。 旁证:LOLDrivers 情报显示存在一个名为 neonddu.sys 的兄弟样本——与 PlugPlayService.sys PE 段字节级一致、Authentihash 相同,但内嵌签名不同且验签失败。这意味着同一份代码曾被更换签名再次投递(一个有效 WHQL 签名版本 + 一个无效签名版本),是典型的攻击者签名策略。本报告交付对象为验签有效的 PlugPlayService.sys。
3. 签名与真实性判定Status : Valid (签名已通过验证)
SignatureType : Authenticode
Signer Subject: CN=Microsoft Windows Hardware Compatibility Publisher, O=Microsoft Corporation, ...
Signer Issuer : CN=Microsoft Windows Third Party Component CA 2014
Serial : 330000006E1229856F0ADE6CFC00000000006E
NotBefore/After: 2024-10-11 03:04:53 / 2025-10-09 03:04:53
SigAlg : sha256RSA (RSA 2048)
EKU : 1.3.6.1.4.1.311.10.3.5 Windows Hardware Driver Verification
1.3.6.1.4.1.311.10.3.5.1 Windows Hardware Driver Attestation Verification
1.5.5.7.3.3 Code Signing
RFC3161 时间戳: 2024-12-12 04:09:29.736Z (Microsoft Time-Stamp Service, nShield TSS)
证书提交方名称 : HBRAINSTORM SISTEMAS DE SOFTWARE LTD (UTF-16,位于证书 blob 内偏移 0x1DBA4)关键判断(务必理解其含义): 签名是真实的,不是伪造或被篡改的。 这是货真价实的微软 WHQL/attestation 签名链,可溯至 Microsoft Root Certificate Authority 2010。 "签名有效" ≠ "文件安全"。 该签名只证明"某个提交方通过微软硬件兼容性门户(WHQL/attestation)提交并通过了自动化签名流程",不包含任何人工安全审计。攻击者(或灰产厂商)恰恰利用这一点,把恶意内核驱动包装成"硬件兼容性驱动"换取微软签名,从而在启用驱动签名强制的系统上无障碍加载——这正是 BYOVD 攻击成立的前提。 签名有效期已过(2025-10-09),但因存在 RFC3161 可信时间戳(2024-12-12,落在有效期内),签名在验证上仍然有效。 这一点常被误判为"已过期所以安全",实际相反:带时间戳的过期签名依然可以正常加载驱动,除非该系统启用了微软易受攻击驱动阻断列表(Microsoft Vulnerable Driver Blocklist)。 提交方名称 HBRAINSTORM SISTEMAS DE SOFTWARE LTD 是证书内的字符串,属于签署主体名称,不构成任何可信背书——它只说明该签名是由这个名义主体提交申请的。
4. 静态结构分析4.1 PE 头[td]字段 | 值 | 说明 | | Machine | 0x8664 | AMD64 | | Magic | 0x020B | PE32+ (64-bit) | | NumberOfSections | 6 | 正常驱动范围下限 | | TimeDateStamp | 0x675A5FB7 → 2024-12-12 03:59:51 UTC | 与签名时间戳同日(2024-12-12) | | SizeOfOptionalHeader | 0x00F0 | 标准 | | Characteristics | 0x0022 | EXECUTABLE_IMAGE|LARGE_ADDRESS_AWARE(IMAGE_FILE_DLL 未置位,与系统内置 .sys 一致) | | AddressOfEntryPoint | 0x0000FA40 | 位于 .text,对应函数 0x14000FA40(21 条指令)→ 即 DriverEntry | | ImageBase | 0x140000000 |
| | Subsystem | 0x0001 | NATIVE —— 真正的内核驱动,非伪装成 .sys 的用户态程序 | | DllCharacteristics | 0x0160 | HIGH_ENTROPY_VA|DYNAMIC_BASE|NX_COMPAT;GUARD_CF (0x4000) 未置位(对照:Windows 内置驱动通常为 0x4160,即 CFG 开启) | | CheckSum (存储值) | 0x0002F34A | 未能用现有工具复现校验和计算(同法对系统内置驱动同样不匹配,故不作为篡改结论) | 4.2 数据目录(16 项)[td]# | 目录 | RVA | Size | 状态 | | 0 | Export | 0 | 0 | 空(无导出) | | 1 | Import | 0x0001F000 | 0x50 | 有(3 个 DLL,位于 INIT 段内) | | 2 | Resource | 0 | 0 | 空(无任何资源) | | 3 | Exception | 0x0001E000 | 0x258 | 有(.pdata,50 个函数) | | 4 | Security | 0x0001CC00 | 0x28C8 | 有(Authenticode 证书表) | | 5 | BaseReloc | 0x00020000 | 0x100 | 有(104 条重定位) | | 6 | Debug | 0 | 0 | 空(无 PDB 路径泄露) | | 10 | LoadConfig | 0x00016000 | 0x140 | 有(SecurityCookie @ RVA 0x1D940) | | 12 | IAT | 0x00016170 | 0xF8 | 有(31 槽) | | 其余 | Architecture/GlobalPtr/TLS/BoundImport/DelayImport/CLR/Reserved | 0 | 0 | 空 | 4.3 段表与熵[td]段 | VirtualAddress | VirtualSize | RawSize | 熵 | 权限 | | .text | 0x1000 | 0x14A66 | 0x14C00 | 6.7524 | R-X | | .rdata | 0x16000 | 0x620 | 0x800 | 3.4949 | R-- | | .data | 0x17000 | 0x6D54 | 0x6A00 | 6.0242 | RW- | | .pdata | 0x1E000 | 0x258 | 0x400 | 3.1177 | R-- | | INIT | 0x1F000 | 0x3CD | 0x400 | 4.7009 | RW-(DISCARDABLE) | | .reloc | 0x20000 | 0x100 | 0x200 | 3.0232 | R-- |
结论:不加壳(No Packer)。 无 UPX/自定义段名,最高段熵 6.75 属正常 x64 代码范围,所有段名均为标准 MSVC/WDK 命名。但 .data 熵高达 6.02(对纯数据段明显偏高),原因是其中存放了大量由运行时算术展开构造的混淆常量表(见 §6)。 4.4 覆盖数据(Overlay)最后段原始数据结束 : 0x0001CC00
Security 目录偏移 : 0x0001CC00 大小 0x28C8
0x1CC00 + 0x28C8 = 0x1F4C8 = 文件大小(完全吻合)无 Overlay。 文件尾部 10,440 字节全部是 Authenticode 证书表,不存在追加载荷。全文件仅 1 处 MZ(偏移 0)。Detect It Easy 把该区域标为 "Overlay, entropy 7.4838: packed" 属于误报——那只是 PKCS#7 证书数据的高熵特性。 4.5 缺失项(重要的"负面证据")无 .rsrc 段、无版本信息(VS_VERSION_INFO 全为空)、无导出、无 Debug 目录/PDB 路径、无 Rich header(DOS stub 恰好 0x38 字节,无空间放置)。这是刻意最小化指纹的构建方式——正常商业驱动会带版本信息和公司名,此处全部剥离。
5. 导入表与能力矩阵导入表位于 INIT 段(RVA 0x1F000 → 文件 0x1C600),共 3 个 DLL / 28 个函数,全部为内核态模块,无任何用户态 DLL(无 kernel32/user32/advapi32/ws2_32/wininet/ntdll)。这确认它是真正的内核驱动,而非伪装成 .sys 的用户态可执行文件。 [td]DLL | 函数 | | ntoskrnl.exe (21) | ExAllocatePool、ExAllocatePoolWithTag、ExFreePoolWithTag、IoDriverObjectType、IoEnumerateDeviceObjectList、IoGetDeviceObjectPointer、KeDelayExecutionThread、KeQuerySystemTimePrecise、MmMapIoSpace、MmUnmapIoSpace、ObReferenceObjectByName、ObfDereferenceObject、PsCreateSystemThread、RtlInitUnicodeString、RtlRandomEx、ZwQuerySystemInformation、__chkstk、_vsnwprintf、strlen、strstr、vDbgPrintExWithPrefix | | cng.sys (6) | BCryptOpenAlgorithmProvider、BCryptGenerateKeyPair、BCryptFinalizeKeyPair、BCryptExportKey、BCryptDestroyKey、BCryptCloseAlgorithmProvider | | HAL.dll (1) | KeStallExecutionProcessor |
能力解读:这 28 个函数的组合极其"功能聚焦"——枚举并打开任意驱动/设备对象、枚举设备对象列表、映射物理内存、创建系统线程、按名称在模块列表中查找内核模块、生成并导出 RSA 密钥对。这组能力组合本身就是 BYOVD 内核原语的典型特征,与任何常规硬件驱动(存储/网卡/显卡)的正常导入集都不相符。 关键负面证据:无 IoCreateDevice / IoCreateDriver / IoCreateSymbolicLink(不创建自己的设备对象),无注册表路径字符串,无文件路径字符串,无网络相关字符串,无进程/线程/注册表回调注册。它不通过自己的设备对象暴露接口——所有行为由内核线程独立驱动,或通过劫持其它驱动的分发路径触达。
6. 混淆与反分析技术(重点章节)样本采用了多层、刻意设计的反分析方法。这是本报告最重要的技术发现之一,也是判定"恶意意图"的关键依据——正常驱动没有理由这样做。 6.1 调用目标指针混淆(已完整破解)现象:Ghidra 的交叉引用分析显示,驱动代码从不静态引用自己的导入跳转桩(0x158C0–0x15A60 的 jmp [IAT] 桩)。也就是说,静态看过去,这个驱动"似乎不调用任何内核 API"。 真相:所有 API 调用以如下形式发起: ; 典型调用点(反编译视图)
(*(code *)(DAT_14001c9c8 + -0x7f1a0bb8bd56ec7))(PhysicalAddress, Size, 0)其中 .data 段全局变量存放的是 真实目标 - 常数,运行时求和即得真实函数地址: 真实目标 = [.data 全局变量] + 调用点常数 (mod 2^64)破解方法:本分析从反编译产物中正则提取全部 (全局, 常数) 配对,直接读取 .data 中对应 8 字节值并求和,完整还原了全部调用目标。例如: [td].data 全局 | 解析出的真实目标 | 含义 | | 0x14001AAE8 | 0x140011729 | 内部函数 FUN_140011729 | | 0x14001AAF0 | 0x140015A60 → IAT | PsCreateSystemThread | | 0x140017098 | 0x140015920 → IAT | ObReferenceObjectByName | | 0x1400170A0 | 0x140015930 → IAT | IoEnumerateDeviceObjectList | | 0x14001C9C8 | 0x1400159A0 → IAT | MmMapIoSpace | | 0x14001C9D8 | 0x1400159B0 → IAT | MmUnmapIoSpace | | 0x14001D250 | 0x1400159C0 → IAT | ZwQuerySystemInformation | | 0x14001D2D0…0x14001D2E8 | IAT | BCrypt 全套(RSA 密钥生成/导出) |
共解析出 60 个不同调用目标,覆盖全部 28 个导入函数与 30 余个内部函数。 这一步是本次分析的核心突破——解决了"驱动到底调用了什么"这一根本问题。 技术细节:这些"混淆常量"之所以需要参与 .reloc 重定位,是因为目标地址包含 ImageBase;因此驱动加载后,加载器的重定位会把这批常量一并修正,使 常量 + 全局 恰好等于修正后的真实地址。这既保证了运行正确性,又彻底破坏了静态交叉引用。 6.2 MBA 常量展开(数学恒等式混淆)全样本共 1,312 处 imul/mul 指令,分布在 41 个函数中(FUN_140001540 282 处、FUN_14000BF00 154 处、FUN_14000DD90 131 处)。典型形态: 8B 0D 92 BC 00 00 mov ecx, [rip+0xBC92] ; 读取 .data 全局
8B 15 90 BC 00 00 mov edx, [rip+0xBC90]
69 C9 15 3D 97 BE imul ecx, ecx, 0BE973D15h ; 乘随机常数
69 D2 47 34 29 4D imul edx, edx, 4D293447h
01 D1 add ecx, edx
81 C1 4D EE 70 0D add ecx, 0D70EE4Dh ; 再叠加常数
...
4D 89 45 00 mov [r13+0], r8 ; 结果存入连续槽位
E9 D0 01 00 00 jmp +0x1D0 ; 跳过下一块即:用大量乘法/加法恒等式在运行时"算"出本该直接写死的常量,最终在 .data 里拼装出一张运行时表。这解释了 .data 段 6.02 的异常熵值,也让静态数据流分析几乎失效。 6.3 反编译阻断结构对 81 个函数逐一尝试反编译,结果: 失败者的结构特征(实测): [td]特征 | 证据 | | 函数大小高度均匀 | 约 30 个函数集中在 1,900–2,100 字节,彼此紧邻 | | 反复申请大栈帧 | FUN_140001540 内 65 次 call __chkstk;FUN_14000BF00 37 次;FUN_14000DD90 34 次 | | 跳跃表/平坦化控制流 | 大量 JMP 落在函数体尾部近似地址(如 FUN_14000BF00 中 30 处跳向 0x14000DD88) | | 代码中内嵌高熵数据块 | 见下表 |
.text 内嵌高熵数据块(非 .pdata 覆盖区,位于函数体内): [td]RVA | 大小 | 熵 | 内容 | | 0x7759 | 375 B | 6.82 | UTF-16 \Device\RaidPort%d + \Driver\Disk + 高熵数据 | | 0xB490 | 448 B | 7.50 | 高熵(接近随机) | | 0xBEC9 | 55 B | 5.39 | DriverEntry 调用的参数块 | | 0x10DF5 | 27 B | 2.75 | UTF-16 \Driver\TPM | | 0x130F5 | 251 B | 6.79 | 代码 + 高熵数据 | | 0x1510D | 227 B | 6.58 | UTF-16 RSA、RSAPUBLICBLOB + 高熵数据 | | 0x15887 | 479 B | 1.97 | 尾部对齐填充 + 24 个 jmp [IAT] 桩 |
判定(与情报交叉印证):这种"均匀尺寸 + 反复大栈帧 + 跳跃表 + 内嵌高熵块"的组合,配合 LOLDrivers 情报所称的 "obfuscated kernel PE loader with arbitrary shellcode execution capabilities"(混淆内核 PE 加载器,具备任意 shellcode 执行能力),可判定这些高熵块是运行时解密/展开的加密载荷或代码,反编译失败是被刻意设计的结果而非工具缺陷。 6.4 其它反分析/反调试要素[td]技术 | 证据(实测) | | RDTSC 计时检测 | 7 处 RDTSC,分布在 FUN_140013869(3)、FUN_14001102D(2)、FUN_140013608(2) | | CPUID / XGETBV 特征探测 | FUN_1400151F0:3 处 CPUID + 1 处 XGETBV + 4 处 BT/BTS,读取 CPU 特性位并写入全局 DAT_14001D900(用于选择代码路径,属 CPU 特性探测,兼可作虚拟化环境判别) | | 无 PDB / 无版本信息 | 见 §4.5 | | 字符串极简 | 镜像体内仅 5 条有意义的 UTF-16 字符串(见 §7) |
7. 关键字符串(镜像体内全部)去除证书 blob 内的 140 余条 PKI 字符串后,驱动镜像体内的真实字符串总共只有以下 5 条: [td]RVA | 字符串 | 位置 | | 0x7766 | \Device\RaidPort%d | .text(函数体内) | | 0x77B2 | \Driver\Disk | .text(函数体内) | | 0x10DF6 | \Driver\TPM | .text(函数体内) | | 0x1510E | RSA | .text | | 0x15116 | RSAPUBLICBLOB | .text |
这 5 条字符串本身就是最强的行为指标:它们精确指向"磁盘/RAID 设备栈"与"TPM 安全芯片",而 RSA/RSAPUBLICBLOB 指向 RSA 密钥导出。 明确未发现(逐项搜索确认):URL、IP、域名、User-Agent、注册表路径(\Registry\Machine\...、CurrentControlSet、Services)、文件路径(\??\、\SystemRoot\、System32)、反虚拟机字符串(VBox/VMware/qemu/sandbox/SbieDll)、反调试工具字符串(x64dbg/procmon/wireshark)、PlugPlay 字样(文件名与文件内容完全无关——这是刻意冒用 Windows 组件命名 Plug and Play 的伪装)。 注:驱动引用 \Driver\TPM、\Device\RaidPort%d、\Driver\Disk 三个对象名,却不创建任何自己的设备/符号链接(无 IoCreateDevice)。这意味着它不向用户态暴露接口,而是从内核侧直接操作这些既有设备。
8. 反编译分析与行为还原以下为逐一反编译/反汇编并已还原全部被混淆调用目标后的行为结论。每条均标注"实测"(有指令级证据)或"推断"。 8.1 DriverEntry(RVA 0xFA40)—— 实测undefined8 entry(void) {
(*(code *)(DAT_14001aae8 + K))(); // -> FUN_140011729()
(*(code *)(_DAT_14001aaf0 + K))(local_10, 0x1fffff, 0, 0, 0, FUN_14000bf00, 0);
return 0;
}解密后的真实调用(K = -0x559bdc79c72d7f9b): undefined8 DriverEntry(void) {
FUN_140011729(); // ① 物理内存映射 / 模块定位
PsCreateSystemThread(&hThread, 0x1FFFFF, // ② 创建系统线程
NULL, NULL, NULL,
FUN_14000BF00, NULL); // 线程入口 = FUN_14000BF00
return 0;
}实测要点: 7 个参数与 PsCreateSystemThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, ClientId, StartRoutine, StartContext) 完全对应,0x1FFFFF = THREAD_ALL_ACCESS。 DriverEntry 忽略了自己的 (PDRIVER_OBJECT, PUNICODE_STRING) 参数,不注册任何分发例程、不创建设备——这是刻意规避静态检测的写法。 驱动把主要工作放进一个由自身创建的系统线程,并先同步执行一次物理内存相关例程。
8.2 FUN_140011729 —— 物理内存映射 + 模块内特征码定位(实测)调用链(全部经还原): FUN_1400119D0 ─┐
FUN_1400131F0 ─┤ 内核模块查找
FUN_1400121B0 ─┤
FUN_14001353A ─┤ PE 段扫描("PAGE" 段)
FUN_1400129B0 ─┘
MmMapIoSpace ← 映射物理内存 (实测:调用目标解析为 IAT 槽 0x1400161B0)
FUN_140011694 ← 对映射区操作
MmUnmapIoSpace ← 解除映射 (实测:0x1400161B8)实测代码片段: puVar5 = (undefined8 *)(*(int *)(lVar3 + 3) + lVar3 + 7); // 由结构体派生目标指针
...
lVar2 = (*(code *)(DAT_14001c9c8 + K))(*puVar5, iVar1, 0); // == MmMapIoSpace(ptr, size, 0)
if (lVar2 == 0) return 0xc0000001;
(*(code *)(DAT_14001c9d0 + K))(lVar2, iVar1); // FUN_140011694:操作映射区
(*(code *)(_DAT_14001c9d8 + K))(lVar2, iVar1); // == MmUnmapIoSpace(ptr, size)实测要点:成功时返回 STATUS_SUCCESS,失败返回 0xC0000001 (STATUS_UNSUCCESSFUL)。映射的对象不是本模块,而是经模块查找 + 特征码定位得到的目标。 8.3 FUN_1400131F0 —— 按名称查找内核模块(实测)调用 ZwQuerySystemInformation + strstr + ExAllocatePoolWithTag/ExFreePoolWithTag。 推断:典型的 SystemModuleInformation 枚举 + 用 strstr 在内核模块名列表中匹配目标模块,返回模块基址。这是绕过 MmGetSystemRoutineAddress / 导入表以隐藏意图的常规手法。 8.4 FUN_14001353A / FUN_140013489 / FUN_140013462 —— PE 段扫描 + 通配符特征码匹配(实测)实测指令: 14001358e 41813c2450414745 CMP dword ptr [R12], 0x45474150 ; 0x45474150 = "PAGE"FUN_14001353A 的实测逻辑: 从 param_1 + 0x3C 读取 e_lfanew,从 param_1 + 0x14 + e_lfanew 读取 SizeOfOptionalHeader,定位段表(步长 40 字节 = sizeof(IMAGE_SECTION_HEADER))——确认是标准 PE 段表遍历。 对每个段,比较段名前 4 字节是否为 0x45474150("PAGE");否则回退到 RtlInitUnicodeString + memcmp(段名, 字符串, 5) 的 5 字节精确比较。 命中后调用 FUN_140013489(基址+VirtualAddress, VirtualSize, 特征码, 输出)。
FUN_140013489 实测逻辑:在给定缓冲区中逐字节滑动,调用 FUN_140013462 做匹配: // FUN_140013462:通配符匹配,'x' 为通配符
for (lVar2 = 0; (c = *(char*)(pat + lVar2), c != 0 &&
((c != 'x') || (*(char*)(a + lVar2) == *(char*)(b + lVar2)))); lVar2++);
return (c == '\0');'x' 作通配符是特征码扫描的标准写法。 结论(实测 + 推断):驱动持有一个字节级特征码(signature)扫描引擎,用于在某内核模块的(特定段内)定位函数地址,随后通过函数指针调用(见 §8.5 的 (*pcVar8)(...))。这是为了使自己不依赖任何硬编码地址或符号,从而跨 Windows 版本"通用"。对恶意驱动而言,这是定位并劫持目标模块内部函数的手段;对"内核 PE 加载器"而言,这是解析宿主模块以完成加载的手段。 8.5 FUN_140005324 —— 打开 \Driver\Disk、枚举设备对象、改写设备扩展(最关键证据,实测)完整还原后的逻辑: FUN_1400067F0(&DAT_14001d978, &DAT_140007854); // 初始化目标模块名
hMod = FUN_1400131F0(&DAT_14001d978); // ① 按名查找内核模块 -> 模块基址
if (!hMod) return 0xC0000001;
// ② 在模块中按特征码定位函数
pcVar8 = FUN_14001353A(hMod, &DAT_14000778C, &DAT_14001d988);
if (pcVar8 == NULL) return 0xC0000001;
RtlInitUnicodeString(&us, L"\\Driver\\Disk"); // ③ 目标锁定 \Driver\Disk
p = NULL;
status = ObReferenceObjectByName(&us, 0x240, NULL, 0,
(POBJECT_TYPE)IoDriverObjectType, // = IoDriverObjectType
KernelMode, NULL, &p); // ④ 取得 DriverObject
if (NT_SUCCESS(status)) {
memset(buf, 0, 0x200);
// ⑤ 枚举该驱动的全部设备对象
st = IoEnumerateDeviceObjectList(p, buf, 0x200, &count);
if (!NT_SUCCESS(st)) return 0xC0000001;
for (i = 0; i < count; i++) {
dev = buf; // PDEVICE_OBJECT
target = *(PVOID *)((PUCHAR)dev + 0x40); // dev->DeviceExtension
if (target != NULL) {
(*pcVar8)(*(PVOID *)((PUCHAR)target + 0x60), 0); // ⑥ 调用特征码定位出的函数
q = *(PVOID *)((PUCHAR)target + 0x60);
if (q != NULL)
*(ULONG_PTR *)((PUCHAR)q + 0x10) = 1; // ⑦ 直接写内存!
}
ObfDereferenceObject(dev);
}
ObfDereferenceObject(p);
}对应汇编证据(实测,FUN_140005324 内): 1400053bd 488d1590240000 LEA RDX, [0x140007854] ; 模块名/特征码
1400055d6 488d15d5210000 LEA RDX, [0x1400077b2] ; "\Driver\Disk"
1400057db 488b5160 MOV RDX, qword ptr [RCX + 0x60]
1400057e9 48c7421001000000 MOV qword ptr [RDX + 0x10], 0x1 ; ★ 写入 1判定(实测):驱动获取 \Driver\Disk 的驱动对象,枚举其全部设备对象,并直接向每个设备对象的设备扩展(DeviceExtension)内部字段写入常量 1,同时调用一个按特征码在模块内定位出来的函数。 8.6 FUN_140001232 + FUN_140001000 —— 枚举并打开 RAID 设备(实测)14000141e 488d1d41630000 LEA RBX, [0x140007766] ; "\Device\RaidPort%d"FUN_140001000 实测调用 RtlInitUnicodeString + IoGetDeviceObjectPointer(按名打开设备)。 推断:FUN_140001232 以 \Device\RaidPort0、\Device\RaidPort1… 循环构造设备名并逐个打开,即直接枚举并取得 RAID 端口设备对象。与情报所称 "direct access to RAID devices" 完全一致。 8.7 FUN_14000BF00 —— 主工作线程(实测引用点)入口:由 DriverEntry 通过 PsCreateSystemThread 启动(§8.1,实测)。 实测:该函数内部 LEA RDX, [0x140010df6] → \Driver\TPM(0x14000c618),即线程会去访问 TPM 驱动对象。 实测:内部 37 次 call __chkstk(反复分配大栈帧),30 处跳向 0x14000DD88(跳跃表/控制流平坦化),且反编译失败(240 秒超时)。 推断:这是驱动的主体逻辑载体,负责 TPM 访问、加密载荷处理与线程循环。因混淆过强,未能完整还原其算法——这是本次分析的主要残留不确定性(见 §11)。
8.8 FUN_140013A9C —— RSA 密钥对生成与公钥导出(实测)实测引用的字符串: 140013d8e 4c8d0581130000 LEA R8, [0x140015116] ; "RSAPUBLICBLOB"
140013de0 4c8d052f130000 LEA R8, [0x140015116]
140013e55 488d1dba120000 LEA RBX, [0x140015116]实测调用(全部 6 个 cng.sys 函数):BCryptOpenAlgorithmProvider → BCryptGenerateKeyPair → BCryptFinalizeKeyPair → BCryptExportKey → BCryptDestroyKey → BCryptCloseAlgorithmProvider,配合 ExAllocatePool/ExFreePoolWithTag。 判定(实测 + 推断):驱动在内核态生成 RSA 密钥对并导出公钥(RSAPUBLICBLOB 格式)。结合"任意内存访问 + 内核 PE 加载器"的整体画像,推断其用途是为所加载的载荷/通信提供密钥或完整性校验,而非"硬件授权"——因为同一驱动同时具备改写他人驱动内存的能力,良性授权场景没有理由需要这些原语。 8.9 其余辅助函数(实测)[td]函数 | 实测调用 | 判定 | | FUN_14001102D、FUN_140013608、FUN_140013869 | KeQuerySystemTimePrecise + RtlRandomEx(+RDTSC) | 随机数/计时;兼作时间与反调试检测 | | FUN_1400140D4 | KeStallExecutionProcessor + KeDelayExecutionThread | 忙等/延时(常用于规避检测或等待加载完成) | | FUN_14000B650 | vDbgPrintExWithPrefix → FUN_14000B700 | 调试输出通道 | | FUN_140013F7C | ExAllocatePool | 内存分配封装 | | FUN_140010E95 | strlen + ExAllocatePoolWithTag(0, len, 0x6D766C4C) + memcpy + ExFreePoolWithTag | 带特征池标签 'mvlL' 的字符串复制/比较 |
持久化/通信 IOC:池标签 0x6D766C4C(显示为 mvlL)可用于内存取证中定位该驱动的池分配。 8.10 未发现的行为(重要的排除项)逐项确认没有以下行为,这对定性同样重要: 无网络通信:无 socket/TDI/WFP/NDIS 相关导入或字符串,无 URL/IP。 无文件系统操作:无 ZwCreateFile/ZwWriteFile/ZwReadFile,无任何文件路径字符串。 无注册表操作:无 ZwOpenKey/ZwSetValueKey,无任何注册表路径字符串。 无进程/线程/注册表回调注册:无 PsSetCreateProcessNotifyRoutine、ObRegisterCallbacks、CmRegisterCallback。 不创建自己的设备对象:无 IoCreateDevice/IoCreateDriver/IoCreateSymbolicLink(已实测的负面证据)。
这一点必须准确表述:该驱动自身不是一套完整的持久化后门。它的定位是能力提供者 / 落地原语——一个被加载后可对内核实施任意读写的"武器",真正的恶意操作由用户态配套组件或后续投递的加密载荷完成(这也与"内嵌加密载荷 + 内核 PE 加载器"的情报定性吻合)。因此本报告对该驱动的定性不依赖于任何外部配套文件:仅凭其自身的代码能力(物理内存映射、他人驱动内存改写、特征码定位调用、内核 PE 加载)即足以判定为恶意。
9. 定性裁决与风险评估9.1 裁决:恶意在分析规划阶段曾并列两个假设: [td]假设 | 内容 | 裁决 | | H1 | 恶意:BYOVD 内核原语 / Rootkit 组件 | ✅ 成立 | | H2 | 灰产/商业:良性"硬件指纹授权"驱动 | ❌ 被证伪 |
证伪 H2 的决定性证据(全部为实测): FUN_140005324 向 \Driver\Disk 各设备对象的 DeviceExtension 内部写入常量 1——良性授权驱动只读采集,不会改写他人驱动内部状态。 具备在其它内核模块中按字节特征码定位并调用函数的能力——良性授权驱动不需要这种能力。 具备物理内存映射(MmMapIoSpace)——良性授权驱动只读硬件标识符即可,无需映射物理内存。 无版本信息、无公司名、无 PDB、无资源——真实商业授权驱动必然带这些。 刻意多层反分析(指针混淆 + MBA 展开 + 反编译阻断 + RDTSC)——商业软件的"保护壳"目标是防破解,不会连调用链都系统性地隐藏。 外部情报独立确认:LOLDrivers 将其标记为 malicious / T1014 / Verified=TRUE,并描述为 "obfuscated kernel PE loader with arbitrary shellcode execution capabilities"。
9.2 风险等级[td]维度 | 评级 | 说明 | | 综合风险 | 严重(Critical) | 内核态任意内存读写 + 合法微软签名,可直接用于关闭/绕过 EDR | | 可利用性 | 高 | 携带有效 WHQL 签名,在启用驱动签名强制的系统上可正常加载;是即成可用的 BYOVD 载荷 | | 隐蔽性 | 高 | 指针混淆 + MBA 展开 + 反编译阻断 + 无版本信息 + 极小字符串面 | | 破坏性 | 高 | 物理内存映射 + 他人驱动内存改写,可导致系统完整性丧失、蓝屏或安全机制失效 | | 自传播 | 无 | 无网络、无文件操作,自身不具备横向或自复制能力 | 9.3 MITRE ATT&CK 映射仅映射已证实或被情报支持的技术,并区分"实测"与"情报/家族级"。 [td]ID | 技术 | 依据 | 类型 | | T1014 | Rootkit | LOLDrivers MitreID 字段;内核驱动 + 物理内存映射 + 篡改他人驱动内存 | 实测 + 情报 | | T1543.003 | Create or Modify System Process: Windows Service | 内核驱动必须以服务形式加载;驱动自身具备完整内核功能 | 实测(加载方式) | | T1027 | Obfuscated Files or Information | 指针混淆、1,312 处 MBA 展开、反编译阻断、无版本信息 | 实测 | | T1620 | Reflective Code Loading | 情报定性 "kernel PE loader with arbitrary shellcode execution";我方实测内嵌高熵载荷块 + PE 段扫描引擎 | 情报 + 实测(结构支持) | | T1562.001 | Impair Defenses: Disable or Modify Tools | BYOVD 类驱动的典型用途(任意内核读写→关闭 EDR);本样本未实测到直接的 EDR 关闭代码 | 情报/家族级,非本样本实测 | | T1542.003 | Pre-OS Boot: Bootkit | 情报提及与 xigmapper(UEFI bootkit)关联部署 | 情报级,非本样本实测 | | T1055 | Process Injection | 情报提及任意 shellcode 执行能力 | 情报级 |
诚实标注:T1562.001 / T1542.003 / T1055 属于情报/家族层面的关联,未经本样本代码级证实。本样本实测支持的是 T1014 / T1027 / T1620(结构证据)/ T1543.003。
10. IOC 与检测建议10.1 主机 IOC文件名 : PlugPlayService.sys
路径 : 通常应为 System32\drivers\ 下(伪装为 PnP 组件)
服务名 : 可能注册为 PlugPlayService / PlugPlay(注意:系统自带 "PlugPlay" 是 services.exe 内的
用户态 PnP 服务,并非驱动 —— 同名驱动的存在即为异常)
MD5 : a26abe238cc339da81f4853ab16e1a6a
SHA1 : 4a0afc37e3a0f180ca3540aabe871d274caafc30
SHA256 : 8f6d843cdec4d3477867225cf0804850e4901a541e095c01feab5634c3f3de99
Imphash : bf2ebfe7fdc706c13b4427fe5fa3413c
Authentihash SHA256 : 10d0c1f97625ee033b0bdf4136d47a34779a36cf83b82410722ad51fa50df5a6同源兄弟样本(情报提供,同一代码不同签名):neonddu.sys —— 与上者 PE 段字节级一致、Authentihash 相同,但内嵌签名无效/验签失败。排查时按 Authentihash 而非仅按内嵌签名匹配,可一次性覆盖两个样本。 签名主体(用于检测"该签名的驱动出现在非硬件场景"): CN=Microsoft Windows Hardware Compatibility Publisher
序列号 : 330000006E1229856F0ADE6CFC00000000006E
指纹 : A5D13378E659DDC05C03EE71B432DD667A302999
证书内提交方 : HBRAINSTORM SISTEMAS DE SOFTWARE LTD内存取证特征: 10.2 行为检测思路[td]检测点 | 说明 | | 驱动 DriverEntry 直接调用 PsCreateSystemThread 且不创建任何设备对象 | 高度可疑的驱动形态;正常驱动先建 IoCreateDevice | | 驱动导入 IoEnumerateDeviceObjectList + IoDriverObjectType + ObReferenceObjectByName 组合 | 该组合基本只出现在"操作他人驱动对象"的场景 | | 驱动导入 MmMapIoSpace,且其 \Device\RaidPort* / \Driver\Disk / \Driver\TPM 同时被引用 | 存储栈 + 物理内存组合异常 | | 内核线程访问 \Driver\TPM 且伴有 RSA 密钥生成 | 与正常 TPM 使用主体(TPM 栈/BitLocker)不符 | | 驱动镜像导入表存在但代码对导入桩零交叉引用 | 指针混淆的静态指纹,可用于批量发现同类样本 | 10.3 YARA 思路(基于本次分析的特征)rule BYOVD_PlugPlayService_obfuscated_loader
{
meta:
description = "PlugPlayService.sys / neonddu.sys - WHQL-signed obfuscated BYOVD kernel PE loader"
reference = "loldrivers.io 03d1a3a2-e76c-4fd5-a134-55ec983fdc4c"
author = "static analysis"
strings:
$rsa = "RSA" wide
$rpub = "RSAPUBLICBLOB" wide
$raid = "\\Device\\RaidPort" wide
$disk = "\\Driver\\Disk" wide
$tpm = "\\Driver\\TPM" wide
$pageC = { 41 81 3C 24 50 41 47 45 } // cmp dword ptr [r12], "PAGE"
$mba = { 69 C? ?? ?? ?? ?? 69 D? ?? ?? ?? ?? 01 D1 } // imul/imul/add 常量展开
condition:
uint16(0) == 0x5A4D
and ($rsa and $rpub)
and 3 of ($raid, $disk, $tpm)
and ($pageC or $mba)
}该规则刻意使用行为性特征(PAGE 段扫描指令序列 + MBA 常量展开字节模式 + 5 条关键字符串),而非文件哈希,可覆盖重签名/轻微变种的同类样本。哈希匹配仅适用于已知样本。 10.4 处置与缓解建议处置(按优先级): 不要加载该驱动。 本报告自始至终未执行它(见 §11)。 阻断:在 EDR/防病毒与网络层添加上述哈希、Imphash、Authentihash、签名序列号与 YARA 规则。 加固(针对 BYOVD 根本缓解):
启用 Microsoft 易受攻击驱动阻断列表(Microsoft Vulnerable Driver Blocklist); 启用 HVCI(内存完整性)/ VBS(若当前未启用则强烈建议开启); 启用 WDAC / 驱动签名策略,限制非白名单驱动加载。
上报:将哈希与签名信息提交 Microsoft MSRC 以吊销该签名并加入阻断列表(同类样本 neonddu.sys 一并提交)。 排查:按 §10.1 IOC 全网 / 全主机排查是否已存在该驱动或其服务注册;建议连同来源目录一并排查是否有其它同源内核驱动(按 §10.1 的 Authentihash 匹配可覆盖重签名变种)。 取证:若怀疑已加载,按池标签 mvlL 与 \Driver\TPM 访问行为做内存取证,并注意 \Driver\Disk 设备扩展可能已被篡改(重启可清除)。
11. 方法论、合规声明与限制11.1 合规声明(硬约束,全程遵守)该驱动全程未被执行、未被加载、未被注册。 未使用 sc create / Start-Service / rundll32 / regsvr32 / 任何驱动加载器。 未将样本复制到任何系统目录或驱动加载路径(分析副本放在 C:\Users\Public\ppsvc_analysis\,仅作静态解析,哈希校验与原件一致)。 未修改注册表、未修改系统配置、未安装任何软件。 Ghidra 仅以导入并反编译为数据的方式使用,从未将其加载进内核。 对样本文件本身仅做只读访问。 VM 快照作为兜底手段存在,但未因意外执行而需要回滚——因为从未执行。
11.2 工具链[td]工具 | 用途 | 备注 | | 自研 PowerShell PE 解析器 | 头/段/熵/数据目录/导入表/.pdata/Overlay/字符串 | 独立实现,用于交叉验证 | | Ghidra 12.1.3 Headless + 自带 JDK 21 | 自动分析(491 秒)、反汇编、反编译 | 详见下方"工具链坑" | | Detect It Easy 3.21 (diec.exe) | 格式/编译器/加壳/签名启发式 | 静态扫描 | | 自研混淆还原器 | 破解指针混淆表,还原全部调用目标 | 本次核心突破 | | LOLDrivers 数据集(32.9 MB) | 情报核验 | 命中确认 |
工具链坑(对后续分析者的提醒):工具目录位于含中文的路径(脱壳),导致 Ghidra/Java 无法加载自身 jar(Opaque part contains invalid character)。已通过创建 ASCII 目录联接(junction) 解决。此外 analyzeHeadless.bat 在错误路径上会停在 pause 导致挂起,需重定向空 stdin。 11.3 本报告的局限性(务必阅读)未做动态分析。 全部结论来自静态逆向 + 情报,不含运行时行为观测。按你的明确要求,未在 VM 中执行该驱动;因此以下内容未经运行验证:加密载荷的实际解密算法与最终载荷内容、线程 FUN_14000BF00 的完整算法、\Driver\Disk 设备扩展被改写字段的语义。 FUN_14000BF00(7,823 字节)、FUN_14000FAA0(4,949)、FUN_140001540(15,844)等 15 个核心函数未能成功反编译(Ghidra 240 秒超时,属被刻意反编译阻断)。本报告对这些函数的描述基于反汇编 + 调用目标还原 + 交叉情报,已逐条标注"实测/推断"。其中最关键的"载荷解密与执行"环节仍属结构性推断,未取得算法级确证。 外部情报仅核验了 LOLDrivers 一个数据源。 VirusTotal、MalwareBazaar、微软阻断列表因本轮网络配额/接口限制未能查询(详见下方)。情报部分以 LOLDrivers 为准,其余标注为"未核验"。 PE 校验和未能复现(同法对系统内置驱动亦不匹配),故未将其作为篡改依据。 DllCharacteristics 缺少 GUARD_CF、.text 中数据块落在非 .pdata 覆盖区等现象已如实记录为观测差异,未据此单独下结论。
11.4 未完成的核验项(后续工作)[td]项 | 状态 | 建议 | | VirusTotal / MalwareBazaar 哈希核验 | 未核验(网络配额限制) | 有 API key 时补充 | | 微软易受攻击驱动阻断列表查询 | 未核验(官方 URL 404 / 配额) | 用官方最新 XML 复核 | | FUN_14000BF00 算法级还原 | 未完成(反编译被阻断) | 用 x64dbg 动态脱壳(需在隔离 VM 且明确授权) | | 加密载荷解密结果 | 未完成 | 同上 |
12. 附录:证据文件清单所有证据均由本次分析生成,位于 C:\Users\**\Desktop\123\_analysis\: [td]文件 | 内容 | | 01_evidence.ps1 / evidence_snapshot.txt | 哈希、签名链、版本信息、主机安全上下文 | | 04_pe_parse.ps1 / pe_structure.txt | PE 头、16 个数据目录、段表 + 熵、入口点、Overlay 计算 | | 05_strings.ps1 / strings_and_imports.txt | ASCII/UTF-16 字符串(区分镜像体与证书)、关键字逐项搜索、内嵌数据块十六进制、导入表(ILT 解析) | | 06_asm_scan.ps1 / asm_pattern_scan.txt | 81 个函数的指令模式扫描(间接调用/RDTSC/CPUID/CR/MSR/INT/LOCK/MBA 等) | | 07_deobfuscate.ps1 / deobf_callsites.txt | 指针混淆调用点逐一还原(60 个目标) | | 08_api_map.ps1 / api_call_map.txt | 函数→API 与 API→函数 双向往来表、.data 混淆表原始值 | | 09_strings_targets.ps1 / strings_and_targets.txt | 字符串描述符、\Driver\Disk 等字符串的十六进制与归属、大函数调用目标统计 | | 10_osint.ps1 / osint_loldrivers.txt | LOLDrivers 命中条目完整元数据 | | pdata_functions.txt | .pdata 50 个函数区间表 | | decompiled/ | Ghidra 产物:_index.txt(含导入引用映射与函数清单)、asm/(81 个函数反汇编)、*.c(66 个函数反编译 C 代码) | | decompiled/_REVIEW_small.txt | 小型函数反编译合集(人工审阅用) |
工作副本与分析工作区:C:\Users\Public\ppsvc_analysis\(含 ASCII junction tools → 脱壳)。分析完成后如需清理,可整体删除该目录;其中包含一份样本副本。 分析过程副产物(非样本组成部分)[td]路径 | 说明 | 处置 | | C:\Users\**\Desktop\123\nul; echo(34 B) | 分析过程中 > nul 重定向被 shell 误解析为文件名产生的文本文件 | 可安全删除 | | %TEMP% 下的 1 个 0 字节临时文件 | 分析工具探测过程中产生的空文件 | 可安全删除 | | C:\Users\Public\ppsvc_analysis\(目录) | 分析工作区,含样本副本、Ghidra 工程、下载的 LOLDrivers 数据集 | 建议处置完成后删除 |
13. 最终结论PlugPlayService.sys 是一个恶意的、经微软 WHQL 签名的、高度混淆的 Windows 内核驱动。 它通过伪造为"即插即用服务组件"的命名和合法的微软硬件兼容性签名绕过驱动签名强制,在内核态提供任意物理内存映射、跨内核模块的特征码定位与函数调用、对 \Driver\Disk 设备扩展的直接改写、RAID/TPM 设备访问、以及内嵌加密载荷的加载与执行能力。其多重反分析设计(指针混淆、MBA 常量展开、反编译阻断、无版本信息)与正常硬件的功能需求完全不相称,明确指向规避检测的恶意意图。 该结论得到三条相互独立的证据链支持:本次静态逆向的指令级证据、行为能力矩阵、以及 LOLDrivers 的独立收录定性(malicious / T1014 / Verified=TRUE,由 Nextron Systems 提交)。 它本身不是一套完整的持久化后门,而是一枚内核级"武器"——真正的恶意行为由配套的用户态组件或后续投递的加密载荷完成。因此对该样本的正确态度是:视为高危内核原语,绝不加载,并按 IOC 与加固建议(特别是启用 HVCI/VBS 与微软易受攻击驱动阻断列表)进行处置。
报告结束。本报告所有事实性陈述均标注来源(实测 / 推断 / 情报),未标注者不得引用为事实。
|