目标:锐捷认证客户端 5.0.2014.108(
RG_SU_For_Windows 6.61) 环境:Windows 10 / PowerShell 7 / objdump
TL;DR
锐捷的「多网卡检测」分三步:建可疑网卡名单 → 真实联网探测 → 弹窗并踢下线。
- 建名单时豁免
PnpInstanceID含VMWARE的网卡,所以 VMware 的 VMnet 一直无事; - 探测方式是把 socket
bind到每块候选网卡 IP,再真的去connect www.baidu.com(最多 3 次); - 命中后调用
StopAuthentication(102),发 Logoff 报文并释放 IP,把你踢下线。
VirtualBox Host-Only 网卡(192.168.56.1)三条豁免都不沾、又通过了探测,于是中招。本文给出 3 处等长字节补丁(共 14 字节),让它彻底闭嘴。
1. 现象与取证
现象:启用 VirtualBox Host-Only 网卡后,认证几分钟内被踢,弹窗提示「服务器禁止设置多个IP来提供代理服务」,并点名 VirtualBox Host-Only Ethernet Adapter。
对照组:同机 VMware VMnet1 / VMnet8 带 IP 却一直平安。
安装目录:
C:\Program Files\Ruijie Networks\Ruijie Supplicant\
├─ 8021x.exe ← 主程序(GUI + 认证协议 + 各种检测)
├─ suservice.exe ← SYSTEM 权限后台服务
├─ Nic.dll / NetworkDetect.exe / W32N55.dll / snetcfg.exe
└─ logs\ ← 行为日志
8021x.exe:PE32、未加壳、镜像基址 0x400000,文件偏移 = 虚拟地址 − 0x400000。
日志(GBK 编码)里躺着完整证据链:
[2026-09-25 18:35:29] CContextControlThread::CheckMulNICDevice helpInfo 服务器禁止设置多个IP……
[2026-09-25 18:35:29] Enter CContextControlThread::StopAuthentication
[2026-09-25 18:35:29] nLogOffReson 102
[2026-09-25 18:35:29] SendLogOffPacket 释放ip
同流程在 18:35–20:07 重复 6 次,与被踢时间完全吻合。提示文案本身不在本地任何文件中,推测由服务器下发或运行时拼装。
字符串扫描(ASCII / UTF-16LE / GBK 三编码)显示:VirtualBox / VBox 命中 0 次,VMware 命中 2 次。这不是按名字匹配的黑名单——弹窗里的网卡名只是系统读到的描述原样打印,改网卡名骗不过检测。
关键锚点:
| 锚点字符串 | 文件偏移 | VA |
|---|---|---|
"www.baidu.com" |
0x1B7944 |
0x5B7944 |
"GetProcxyDefenseStatus, bRet = 0x%x" |
0x1B7FD0 |
0x5B7FD0 |
"nLogOffReson %d" |
0x1B9B10 |
0x5B9B10 |
"CContextControlThread::CheckMulNICDevice" |
0x1BA1FC |
0x5BA1FC |
| 跳过关键词表(miniport/video/pseudo/netpas/ras/wan) | 0x1B88C4–0x1B88EC |
— |
2. 静态分析:三条主干
反汇编:objdump -d -M intel --no-show-raw-insn 8021x.exe > dis.txt,字符串 VA = 文件偏移 + 0x400000,在 dis.txt 中 grep push 0x5b7944 找引用。
调用链总览:
[3 个调用点:网络状态事件处理 / 事件码 0x16 分发 / 状态同步]
└─ CheckMulNICDevice (0x4432BF)
├─ 0x43D540 建「可疑网卡」名单
│ ├─ GetAdaptersInfo 枚举(两段式:先取长度 0x6F,再取数据)
│ ├─ 只要 Type==6(以太网) / 0x47(无线)
│ ├─ 读注册表 Connection\PnpInstanceID → 含 "VMWARE" 跳过 ← VMware 免死金牌
│ └─ 描述转小写 → Find(miniport/video/pseudo/netpas/ras/wan) → 跳过
├─ 0x434ED9 NicConnected:逐条探测
│ └─ 0x434C60 bind 本网卡 IP → connect www.baidu.com(最多 3 次)
├─ GetProcxyDefenseStatus (0x4377CF):取服务器下发的「防代理」标志位
└─ 名单非空 → 弹窗(资源 ID 0x127)+ 全局状态 0x475 + StopAuthentication(102)
建名单(0x43D540) 关键汇编:
43d5fd: mov eax,[ebx+0x1a0] ; IP_ADAPTER_INFO.Type
43d603: cmp eax,0x6 ; 以太网?
43d608: cmp eax,0x47 ; 无线?
43d622: lea eax,[ebx+8] ; AdapterName,即 {GUID}
43d628: call 0x43a086 ; ← 读 ...\Connection\PnpInstanceID,返回是否含 "VMWARE"
43d62d: test al,al
43d62f: jne 0x43d7e5 ; 命中 VMWARE → 跳过该网卡
43d64d: push 0x5b88e0 ; "netpas"
43d655: call 0x40be85 ; Find
43d664: push 0x5b88d0 ; "video"
43d66c: call 0x40be85 ; Find → 命中即跳过
本机注册表实测:
| 网卡 | PnpInstanceID | 结局 |
|---|---|---|
| VMware VMnet1 / VMnet8 | ROOT\VMWARE\0000 / 0001 |
✅ 豁免 |
| 板载 Realtek | PCI\VEN_10EC&… |
认证网卡,走另一分支 |
| VirtualBox Host-Only | 不含 VMWARE |
❌ 中招 |
探测(0x434C60) 伪代码:
WSAStartup(2, 2);
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, 1000ms);
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, 1000ms);
bind(s, {AF_INET, inet_addr(候选网卡的 IP)}); // ← 绑定到目标网卡
hostent* h = gethostbyname("www.baidu.com");
for (int i = 0; i < 3; i++) {
SOCKET c = socket(...);
if (connect(c, h->addr, 80) 判定通过) { *out = 1; break; }
}
即按「这块网卡是否真能连通外网」认定你有没有第二条上网出口。这种探测相当糙:bind 只改源地址,路由仍按目的地址选默认路由;再叠上 Windows 弱主机模型,虚拟网卡通断判定本就时灵时不灵。这也是它必须靠白名单兜底的原因——而白名单里唯独没有 VirtualBox。
判定与处罚(CheckMulNICDevice 0x4432BF):
4434d7: mov ebx,[ebp-0x28] ; 拼好的「多余网卡」名单(CString)
4434da: cmp DWORD PTR [ebx-0xc],0 ; 名单为空?
4434de: je 0x443575 ; ├─ 空 → 另一分支
...
443573: jmp 0x44357b ; └─ 非空 → 落入「处罚块」
443575: cmp BYTE PTR [ebp-0xd],0 ; 辅助标志路径
443579: je 0x4435ee ; └─ 为 0 → 直接收尾
44357b: mov edi,[ebp-0x18] ; ┐
44357e: push 0x1 ; │
443580: push 0x1 ; │ 处罚块
443582: push 0x66 ; │ 下线原因 102
443584: mov ecx,edi ; │
443586: call 0x44180f ; ┘ StopAuthentication(102) → Logoff + 释放 IP
自校验排查:对「篡改 / 校验 / 完整性 / MD5 / Checksum / 重新安装」全目录三编码扫描,命中的只有 EAP-MD5、下载组件完整性校验、私有协议签名,均与 8021x.exe 自身 SHA1 不匹配。结论:无自校验,可放心改。
3. 补丁设计
两条思路:
- 拆引信——把「处罚块」两个入口全部改成无条件跳过:探测爱跑跑,弹窗和
StopAuthentication(102)永不执行; - 隐身——把跳过关键词表里的
video改成virtu,让VirtualBox …描述在建名单阶段直接命中「跳过」。(匹配前描述转小写,virtualbox host-only ethernet adapter含virtu。)
全部为等长字节替换:不增减字节、不移动偏移、不动区段/导入表/文件头,无需修复 PE。
| 文件偏移 | 原始字节 | 补丁后 | 说明 |
|---|---|---|---|
0x434DE |
0F 84 91 00 00 00(je) |
E9 92 00 00 00 90(jmp+nop) |
名单非空不再进处罚块 |
0x43579 |
74 73(je) |
EB 73(jmp) |
辅助标志路径不再进处罚块 |
0x1B88D0 |
"video" |
"virtu" |
VirtualBox 网卡建名单即跳过 |
副作用:处罚块成为不可达代码;认证、DHCP、无线、VMware 豁免等逻辑均不受影响;可随时用备份还原。
补丁脚本 patch-ruijie.ps1
特性:管理员/进程占用检查、自动备份(8021x.exe.orig,不覆盖)、改前逐字节核验(版本不符直接中止)、改后复检、可重复运行。
# 锐捷 8021x 客户端补丁
# 作用: 关闭"多网卡检测"的弹窗+踢下线动作, 并让 VirtualBox 网卡在筛查中被跳过
# 适用: 锐捷认证客户端 5.0.2014.108 (8021x.exe, 2337088 字节)
# 可重复运行: 已打过会提示"已是补丁状态"; 客户端升级/重装后重跑一次即可。
# 运行前请先退出锐捷客户端; 需要管理员权限。
$exe = 'C:\Program Files\Ruijie Networks\Ruijie Supplicant\8021x.exe'
$bak = $exe + '.orig'
function Main {
$admin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $admin) {
Write-Host '[X] 需要管理员权限。请关闭本窗口, 右键 patch-ruijie.cmd 选择"以管理员身份运行"。' -ForegroundColor Red
return 1
}
if (Get-Process -Name '8021x' -ErrorAction SilentlyContinue) {
Write-Host '[X] 锐捷客户端正在运行。请先在托盘右键退出它, 再运行本补丁。' -ForegroundColor Red
return 1
}
if (-not (Test-Path -LiteralPath $exe)) {
Write-Host ('[X] 找不到: ' + $exe) -ForegroundColor Red
return 1
}
if (-not (Test-Path -LiteralPath $bak)) {
Copy-Item -LiteralPath $exe -Destination $bak
Write-Host ('[OK] 已备份原文件 -> ' + $bak)
} else {
Write-Host ('[i] 备份已存在(未覆盖): ' + $bak)
}
$bytes = [IO.File]::ReadAllBytes($exe)
if ($bytes.Length -ne 2337088) {
Write-Host ('[X] 文件大小 ' + $bytes.Length + ' 与预期 2337088 不符, 版本可能已更新, 已中止。') -ForegroundColor Red
return 2
}
$patches = @(
@{ Off = 0x434DE; Orig = [byte[]](0x0F,0x84,0x91,0x00,0x00,0x00); New = [byte[]](0xE9,0x92,0x00,0x00,0x00,0x90); Name = '多网卡名单路径: 不再弹提示/踢下线' },
@{ Off = 0x43579; Orig = [byte[]](0x74,0x73); New = [byte[]](0xEB,0x73); Name = '多网卡兜底路径: 不再弹提示/踢下线' },
@{ Off = 0x1B88D0; Orig = [byte[]](0x76,0x69,0x64,0x65,0x6F,0x00); New = [byte[]](0x76,0x69,0x72,0x74,0x75,0x00); Name = '网卡筛查关键词 video -> virtu (VirtualBox 网卡被直接跳过)' }
)
$apply = @()
$done = 0
foreach ($p in $patches) {
$isOrig = $true
$isNew = $true
for ($i = 0; $i -lt $p.Orig.Count; $i++) {
if ($bytes[$p.Off + $i] -ne $p.Orig[$i]) { $isOrig = $false }
if ($bytes[$p.Off + $i] -ne $p.New[$i]) { $isNew = $false }
}
if ($isNew) { $done++; continue }
if (-not $isOrig) {
$expect = ($p.Orig | ForEach-Object { '{0:X2}' -f $_ }) -join ' '
Write-Host ('[X] 偏移 0x{0:X} 的字节与预期不符 (应为 {1}), 文件可能已被改动或是其它版本, 已中止。' -f $p.Off, $expect) -ForegroundColor Red
return 2
}
$apply += $p
}
if ($apply.Count -eq 0) {
Write-Host ''
Write-Host '[i] 3 处补丁均已是生效状态, 无需重复打补丁。'
Write-Host '[完成] 现在可以直接打开锐捷客户端登录。' -ForegroundColor Green
Write-Host ' [还原] 如需还原: 运行 restore-ruijie.cmd。'
return 0
}
foreach ($p in $apply) {
for ($i = 0; $i -lt $p.New.Count; $i++) { $bytes[$p.Off + $i] = $p.New[$i] }
Write-Host ('[OK] {0} (0x{1:X})' -f $p.Name, $p.Off) -ForegroundColor Green
}
if ($done -gt 0) { Write-Host ('[i] 另有 ' + $done + ' 处此前已生效。') }
[IO.File]::WriteAllBytes($exe, $bytes)
$v = [IO.File]::ReadAllBytes($exe)
$ok = $true
foreach ($p in $patches) {
for ($i = 0; $i -lt $p.New.Count; $i++) {
if ($v[$p.Off + $i] -ne $p.New[$i]) { $ok = $false }
}
}
if (-not $ok) {
Write-Host '[X] 写入后校验失败! 请运行 restore-ruijie.cmd 还原。' -ForegroundColor Red
return 3
}
Write-Host ''
Write-Host '[完成] 补丁已写入并校验通过。现在可以重新打开锐捷客户端登录了。' -ForegroundColor Green
Write-Host ' [提示] 客户端升级/重装后补丁会失效, 重新运行本脚本即可。'
Write-Host ' [还原] 运行 restore-ruijie.cmd, 或把 8021x.exe.orig 复制回 8021x.exe。'
return 0
}
$r = Main
Write-Host ''
Read-Host '按回车键关闭'
exit $r
启动器 patch-ruijie.cmd(双击后弹 UAC 提权):
@echo off
cd /d "%~dp0"
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process powershell.exe -Verb RunAs -ArgumentList @('-NoProfile','-ExecutionPolicy','Bypass','-File','%~dp0patch-ruijie.ps1')"
还原脚本核心两行:
Copy-Item -LiteralPath ($exe + '.orig') -Destination $exe -Force # 前提: 先退出客户端, 管理员运行
手动核对补丁是否生效:
$exe='C:\Program Files\Ruijie Networks\Ruijie Supplicant\8021x.exe'
$b=[IO.File]::ReadAllBytes($exe)
'{0:X2} {1:X2} {2:X2} {3:X2} {4:X2} {5:X2}' -f $b[0x434DE..0x434E3]
# 期望输出: E9 92 00 00 00 90
4. 使用、验证与局限
使用步骤:
- 托盘右键退出锐捷客户端(补丁需要独占文件;会短暂断网);
- 右键
patch-ruijie.cmd→ 以管理员身份运行; - 重新打开客户端登录。
验证点:
- 挂上 VirtualBox Host-Only 网卡不再被踢、不再弹「多个IP」提示;
logs\wireless.log中该网卡会被标为strDescription: virtualbox host-only ethernet adapter - skip(隐身生效);- 认证、DHCP、无线、VMware 均照常。
还原:运行 restore-ruijie.cmd,或把 8021x.exe.orig 覆盖回去。
局限与风险:
- 补丁只对 2337088 字节的这一版有效;客户端升级/重装后偏移会变,脚本会检测到字节不符并中止——别硬打,按第 2 节方法重新定位即可(搜字符串 → 算 VA → grep
push→ 读函数,套路不变)。 - 这种探测实现(bind + connect)对虚拟网卡本就不可靠;补丁等效于「拆掉处罚动作」,任何探测结果都不会再触发下线。
- 本文仅供逆向学习与兼容性研究(如让本机实验环境的虚拟机网卡不被误判)。校园网大都有明确的网络使用规定,是否使用、如何使用,风险自负。
原文 https://blog.csdn.net/2301_79518550/article/details/166646481