尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

windows 驱动实例分析系列: HidHide 驱动分析 - HidHide 篇(二)

windows 驱动实例分析系列: HidHide 驱动分析 - HidHide 篇(二) HidHide 驱动分析 - HidHide 篇二核心过滤逻辑与进程追踪一、核心过滤决策流程Logic.cLogic.c是整个驱动的大脑它实现了访问控制的完整决策树并协调设备创建、控制请求处理和配置管理等核心事务。1.1 OnDriverCreate驱动初始化钩子驱动在DriverEntry中调用此函数完成以下关键初始化NTSTATUSOnDriverCreate(WDFDRIVER wdfDriver){// 1. 二叉搜索树自检ntstatusHidHideVerifyInternalConsistency();// 2. 创建控制设备ntstatusHidHideControlDeviceCreate(wdfDriver,s_wdfControlDevice);// 3. 创建同步锁WdfWaitLockCreate(wdfObjectAttributes,s_criticalSectionLock);// 4. 注册进程创建/终止回调ntstatusPsSetCreateProcessNotifyRoutine(OnSystemProcessChange,FALSE);// 5. 注册镜像加载回调ntstatusPsSetLoadImageNotifyRoutine(OnSystemLoadImage);returnSTATUS_SUCCESS;}PsSetCreateProcessNotifyRoutine和PsSetLoadImageNotifyRoutine是构建进程-路径映射缓存的基础。这些回调运行在系统上下文需保持高效。1.2 进程追踪机制Config.c1.2.1 问题背景在OnDeviceFileCreate中驱动需要知道当前进程的完整镜像路径如\Device\HarddiskVolume1\Windows\notepad.exe以比对白名单。然而在 DISPATCH_LEVEL IRQL 下无法安全调用ZwQueryInformationProcess可能导致死锁或分页错误。1.2.2 解决方案异步缓存二叉搜索树驱动利用系统回调异步构建缓存镜像加载时注册VOIDOnSystemLoadImage(PUNICODE_STRING fullImageName,HANDLE processId,PIMAGE_INFO imageInfo){if((NULL!fullImageName)(NULL!processId)){HidHideProcessIdRegister(s_criticalSectionLock,processId,fullImageName);}}当任何进程加载主镜像时HidHideProcessIdRegister将 PID 和完整路径插入 BST。进程终止时注销VOIDOnSystemProcessChange(HANDLE parentId,HANDLE processId,BOOLEAN create){if(FALSEcreate){HidHideProcessIdUnregister(s_criticalSectionLock,processId);}}进程退出时从 BST 中移除对应节点。1.2.3 BST 数据结构与操作节点定义typedefstruct_PROCESSIDTREE{ULONG pid;WCHAR fullImageName[NTSTRSAFE_UNICODE_STRING_MAX_CCH];UNICODE_STRING fullImageNameUnicodeString;EvaluationCache evaluationCache;// 缓存命中状态struct_PROCESSIDTREE*left;struct_PROCESSIDTREE*right;}PROCESSIDTREE;缓存状态枚举typedefenum{EvaluationCacheEmpty0,// 未评估EvaluationCacheFound,// 已找到匹配白名单EvaluationCacheNotFound// 已找到不匹配白名单}EvaluationCache;节点一旦评估过后续请求直接使用缓存结果避免重复字符串比较。插入与查找BstInsert按 PID 大小递归插入左小右大。BstLookupO(log n) 查找。BstDelete删除节点处理三种情况左空、右空、双子节点并重新组织树结构。1.2.4 自检机制HidHideVerifyInternalConsistency在驱动启动时执行向 BST 插入预定义的测试 PID 序列如 {5, 11, 15, 10, 8, 9, 3, 4, 1, 2}验证插入、查找、删除和节点计数的正确性。若自检失败驱动加载将中止这是一种极具防御性的设计。1.3 白名单匹配与缓存HidHideProcessIdCheckFullImageNameAgainstWhitelist执行实际匹配NTSTATUSHidHideProcessIdCheckFullImageNameAgainstWhitelist(...,HANDLE processId,WDFCOLLECTION wdfCollection,BOOLEAN*cacheHit){nodeBstLookup(s_ProcessIdToFullLoadImageNameMappingTree,processId);if(NULLnode)returnSTATUS_SUCCESS;// PID 未知// 使用缓存结果if(EvaluationCacheFoundnode-evaluationCache)returnSTATUS_PROCESS_IN_JOB;if(EvaluationCacheNotFoundnode-evaluationCache)returnSTATUS_PROCESS_NOT_IN_JOB;// 遍历白名单集合进行字符串比较for(ULONG index0;indexWdfCollectionGetCount(wdfCollection);index){WdfStringGetUnicodeString(WdfCollectionGetItem(wdfCollection,index),fullImageName);if(0RtlCompareUnicodeString(fullImageName,node-fullImageNameUnicodeString,TRUE)){node-evaluationCacheEvaluationCacheFound;returnSTATUS_PROCESS_IN_JOB;}}node-evaluationCacheEvaluationCacheNotFound;returnSTATUS_PROCESS_NOT_IN_JOB;}RtlCompareUnicodeString的TRUE参数指定大小写不敏感比较符合 Windows 路径匹配惯例。1.4 黑名单与会话隔离Blacklisted函数不仅检查设备路径还支持会话隔离voidSplitDeviceData(PUNICODE_STRING input,PUNICODE_STRING deviceInstancePath,ULONG*sessionId){// 解析 设备路径!会话ID 格式WCHAR delimiterL!;// 查找 ! 分隔符// 设置 deviceInstancePath 为分隔符前部分// 设置 sessionId 为分隔符后部分转换为 ULONG}BOOLEANBlacklisted(PUNICODE_STRING deviceInstancePath,ULONG sessionId){foreach blacklistedEntry{SplitDeviceData(blacklistedEntry,blacklistedDeviceInstancePath,jailSessionId);if(0RtlCompareUnicodeString(blacklistedDeviceInstancePath,deviceInstancePath,TRUE)){// 若黑名单条目指定了会话ID则仅当会话ID匹配时才隐藏return(sessionId!0jailSessionId!0sessionIdjailSessionId?FALSE:TRUE);}}returnFALSE;}此机制允许在多用户环境如快速用户切换、远程桌面中不同会话拥有不同的设备可见性策略避免全局隐藏影响其他用户。1.5 白名单与反转模式Whitelisted函数封装了逻辑判断BOOLEANWhitelisted(HANDLE processId,BOOLEAN*cacheHit){BOOLEAN result(STATUS_PROCESS_IN_JOBHidHideProcessIdCheckFullImageNameAgainstWhitelist(...));returnGetInverse()?!result:result;}当反转模式WhitelistedInverse启用时白名单逻辑取反——白名单中的应用被禁止访问隐藏设备而非白名单的应用则被允许。这提供了一种允许所有禁止少数的灵活模式。二、配置的双缓冲与热更新2.1 控制设备上下文结构CONTROL_DEVICE_CONTEXT存储所有运行时配置typedefstruct_CONTROL_DEVICE_CONTEXT{WDFCOLLECTION whitelistedFullImageNames;// 白名单集合WDFCOLLECTION blacklistedDeviceInstancePaths;// 黑名单集合BOOLEAN active;// 总开关BOOLEAN whitelistedInverse;// 反转模式BOOLEAN shutdownPending;// 关机标志INT32 numberOfDevicesCreated;// 设备引用计数}CONTROL_DEVICE_CONTEXT;2.2 集合的原子替换以SetWhitelist为例NTSTATUSSetWhitelist(LPWSTR buffer,size_t bufferSizeInCharacters){// 1. 持久化到注册表HidHideDriverSetMultiStringProperty(parameterName,buffer,bufferSizeInCharacters);// 2. 创建新集合HidHideDriverCreateCollectionForMultiStringProperty(parameterName,newCollection);// 3. 加锁交换指针WdfWaitLockAcquire(s_criticalSectionLock,NULL);WdfObjectDelete(pControlDeviceContext-whitelistedFullImageNames);pControlDeviceContext-whitelistedFullImageNamesnewCollection;WdfWaitLockRelease(s_criticalSectionLock);// 4. 刷新缓存HidHideProcessIdsFlushWhitelistEvaluationCache(s_criticalSectionLock);returnSTATUS_SUCCESS;}这种先创建新集合加锁交换最后释放旧集合的模式保证了无锁读取所有正在进行的 I/O 请求在交换前持有的旧集合指针依然有效交换后新请求自动使用新集合。2.3 注册表持久化配置存储在HKLM\SYSTEM\CurrentControlSet\Services\HidHide\Parameters下Active(REG_DWORD)WhitelistedInverse(REG_DWORD)WhitelistedFullImageNames(REG_MULTI_SZ)BlacklistedDeviceInstancePaths(REG_MULTI_SZ)HidHideDriverGetBooleanProperty和HidHideDriverSetBooleanProperty封装了注册表读写使用WdfDriverOpenParametersRegistryKey获取 Parameters 键句柄。
返回列表