windows 驱动实例分析系列: HidHide驱动分析-HidHideCLI 篇(一)
发布时间:2026/9/11 17:40:30 锦皓数字建站
`)
HidHide 驱动分析 - HidHideCLI 篇一整体架构与命令解释器一、项目定位与设计目标HidHideCLI.exe 是 HidHide 解决方案的命令行接口CLI组件面向高级用户、系统管理员以及自动化部署场景。与图形化的 HidHideClient 不同CLI 工具无需图形界面可在脚本、批处理文件或安装程序中静默执行实现无人值守的驱动配置管理。该工具的核心设计目标包括目标描述脚本化支持所有操作均支持无交互模式标准输入/输出可重定向便于集成到 CI/CD 或游戏启动器幂等性重复执行相同命令不会产生副作用配置变更仅在最终提交时生效批量操作支持单次命令行中串联多个命令如--cloak-on --dev-hide xxx减少驱动通信开销机器可读输出设备列表采用 JSON 格式输出便于其他程序解析和处理兼容性与 GUI 工具共享相同的底层通信代理FilterDriverProxy和设备枚举逻辑二、整体模块划分HidHideCLI 的源码目录结构清晰各模块职责分明文件职责HidHideCLI.cpp应用程序入口点wmain负责 ETW 初始化和异常捕获CommandInterpreter.cpp/.h命令解释器核心负责解析命令行、命令注册与分发Commands.cpp/.h具体命令的实现app-reg, dev-hide, cloak-on 等FilterDriverProxy.cpp/.h驱动通信代理封装 DeviceIoControl 调用与 Client 共享设计HID.cpp/.hHID 设备枚举与信息采集输出 JSON 格式设备列表Volume.cpp/.h逻辑盘符与 NT 设备路径的双向转换Utils.cpp/.h通用工具函数字符串处理、权限检测、资源加载等Logging.cpp/.hETW 日志与调试输出CLI 与 Client 的最大区别在于交互模式CLI 支持交互式 Shell 模式无参数启动时进入命令行提示符也支持单次命令模式带参数直接执行后退出这种双重模式设计使得 CLI 既适合调试也适合自动化。三、命令解释器的核心架构3.1 命令注册表RegisteredCommandsCommandInterpreter类维护一个命令注册表m_RegisteredCommands类型为std::mapstd::wstring, RegisteredCommandInfo。每个命令条目包含四个字段structRegisteredCommandInfo{std::wstring syntax;// 命令语法说明用于帮助信息std::wstring description;// 命令功能描述ExecuteFunction execute;// 命令执行函数ValidateFunction validate;// 参数验证函数执行前调用};这种设计将命令的语法定义、参数验证和业务执行三者分离使得添加新命令只需在注册表中增加一个条目无需修改核心解析逻辑。所有命令在CommandInterpreter构造函数中完成注册m_RegisteredCommands{{Lapp-list,{StringTable(IDS_CLI_SYNTAX_NO_ARGUMENTS),StringTable(IDS_CLI_APP_LIST),std::bind(CommandInterpreter::AppList,this,_1),std::bind(CommandInterpreter::ValNoArguments,this,_1)}},{Lapp-reg,{StringTable(IDS_CLI_SYNTAX_APP_PATH),StringTable(IDS_CLI_APP_REG),std::bind(CommandInterpreter::AppReg,this,_1),std::bind(CommandInterpreter::ValOneFullyQualifiedExecutablePath,this,_1)}},// ... 共 18 个命令}3.2 命令行解析的三层抽象命令解释器采用递归下降风格解析命令行定义了三个层次的抽象第一层ExtractKeyword —— 提取关键字std::wstringExtractKeyword(std::wstringvalue){autoitstd::find_if(std::begin(value),std::end(value),[](wchar_tc){returnstd::isspace(c);});autoresultstd::wstring(std::begin(value),it);value.erase(std::begin(value),it1);returnresult;}从字符串开头提取一个单词以空格为界常用于命令名称。第二层ExtractString —— 提取带引号支持的参数std::wstringExtractString(std::wstringvalue){if(Lvalue.at(0)){autoindexvalue.find(L,1);// 检查是否闭合且后续为空格或结束符autoresultvalue.substr(1,index-1);value.erase(0,index1);returnresult;}returnExtractKeyword(value);}支持双引号包裹的路径参数如C:\Program Files\app.exe确保包含空格的路径被正确解析。第三层ExtractCommand —— 提取完整命令及参数ArgsExtractCommand(std::wstringvalue){if(L--value.substr(0,2))value.erase(0,2);autokeywordExtractKeyword(value);Args result{keyword};while(!Trim(value).empty()L--!value.substr(0,2)){autoargExtractString(value);result.emplace_back(arg);}returnresult;}每个命令以--前缀标识参数列表持续读取直到遇到下一个--或字符串结束。3.3 两种执行模式交互模式Interactive Mode当标准输入未重定向且未传入命令行参数时启动。界面显示$提示符用户逐条输入命令支持历史命令由系统控制台提供。该模式下配置变更不会立即写入驱动而是通过ApplyConfigurationChanges()在退出时统一提交提高了批量操作的效率。脚本模式Script Mode当命令行参数非空或标准输入被重定向时触发。命令执行后立即退出输出结果直接写入标准输出stdout便于重定向到文件或管道传递给其他程序。if(m_InteractiveMode)std::wcoutstd::endlStringTable(IDS_DIALOG_APPLICATION)std::endl;do{autoconstcommandsExtractCommands(line);autoconsterrorMessageExecuteCommands(commands);if(!errorMessage.empty())std::wcerrerrorMessagestd::endl;if(m_InteractiveMode)std::wcoutL$ ;}while((m_InteractiveMode||m_ScriptMode)std::getline(std::wcin,line));if(!m_ScriptMode)m_FilterDriverProxy.ApplyConfigurationChanges();四、与 GUI 工具的差异对比维度HidHideClientGUIHidHideCLI命令行交互方式鼠标点击、拖放键盘输入、脚本配置提交写穿透Write-Through攒批提交Batch Commit设备输出树形控件JSON 格式适用场景日常用户管理自动化部署、调试异常处理对话框提示错误码 标准错误输出五、启动流程与 ETW 初始化HidHideCLI.cpp中的wmain是标准入口点。其执行流程ETW 提供者注册LogRegisterProviders()注册Nefarius_Hid_Hide_CLI和Nefarius_Drivers_HidHideCLI两个事件提供者。日志记录启动事件LogEvent(ETW(Started), L%s, _L(BldProductVersion))记录版本信息。调用主逻辑MainApplication()封装命令解释器的启动。ETW 提供者注销LogUnregisterProviders()在退出前清理。MainApplication中的异常处理确保任何未捕获的异常都被转换为标准错误输出和相应的返回码便于脚本判断执行结果。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。