[2022]逃离Windows注册表回调重定向与链接的地狱 huoji C++ 2022-12-05 328 次浏览 0 次点赞 如果你开发过Windows的注册表回调相关的内容,比如hips、edr.那你一定会被里面的各种由于历史造成的 软连接、重定向、wow64等等等措施折磨的无法脱身. 如WOW6432Node这个东西本来就是个WOW32兼容重定向假路径: https://learn.microsoft.com/zh-cn/windows/win32/winprog64/shared-registry-keys?redirectedfrom=MSDN  又臭又长的SID完全没有软用:  currentControlset和controlset00X 顺便说一句这如何来的: > 默认情况下,ControlSet001是系统真实的配置信息,但是为了避免序号混乱,windows启动时会从ControlSet001复制一份副 本,作为操作系统当前的配置信息,也就是CurrentControlSet。我们对于计算机配置所作的修改都是直接写入到 CurrentControlSet,在重启过程中,windows会用CurrentControlSet的内容覆盖掉ControlSet001,以 保证这两个控件组一致。 当操作系统每成功启动一次(指成功登录),它都将CurrentControlSet和ControlSet001中的数据复制到 ControlSet002中。这样,ControlSet002就成了“最近一次成功启动的配置信息”(很熟悉吧?在启动windows前按下F8所调 出的菜单中有这个选项)。所以我们一般系统注册表中都只是有这三个控件组,并且序号都是current、001和002。(此后均用简称) 但是,这个顺序和数目不是一成不变的,改变就发生在使用过“最近一次的正确配置”之后。这个时候,系统会把002当作系统真实的配置信息,而001这个存 在问题的控件组会被备份封存起来。系统启动时会从002复制副本到current,启动成功后又会把002和current的信息复制一份到一个新的控件 组作为新的“最近一次的正确配置”,也就是003。这个时候系统就存在4个控件组:current、002、003和备份的001,这里的001是一个存 在问题的组,除非我们想把系统恢复到上次使用“最近一次正确配置”之前的状态,否则001的内容将不再被使用。  这些让人非常的头疼.现在是时候一劳永逸的解决他了,这里是我花了一点时间写的处理函数.作为家庭作业,他有隐藏的anti-paste.不要直接cv,但是效果很好: > 去掉所有wow64node 去掉\\registry\\user\\一大坨SID\\xxxx 去掉controlset00X ```cpp /* users不需要带sid \\registry\\machine\\system\\controlset 固定不需要管001或者002 \\wow6432node 不用看 \\user不需要看 sid */ auto normalizeRegKeyName(wchar_t* inputPath) -> void { static const wchar_t* wow64Keys[] = {L"\\wow6432node", L"\\wowaa32node"}; static const UNICODE_STRING hkupreFix = RTL_CONSTANT_STRING(L"\\registry\\user"); static const UNICODE_STRING hkmpreFix = RTL_CONSTANT_STRING(L"\\registry\\machine\\system"); static const UNICODE_STRING hkmControlSetFix = RTL_CONSTANT_STRING(L"\\registry\\machine\\system\\controlset"); static const UNICODE_STRING hkmCurrentSetFix = RTL_CONSTANT_STRING(L"\\registry\\machine\\system\\currentcontrolset"); wchar_t* result = inputPath; for (auto& usWow64Key : wow64Keys) { const auto wow64PosPtr = wcsstr(result, usWow64Key); if (wow64PosPtr == nullptr) { continue; } const auto usWow64KeyLength = wcslen(usWow64Key); const auto endPos = (wow64PosPtr - result) + usWow64KeyLength; if (result[endPos] != L'\\') { continue; } // Remove wow64 key memmove(wow64PosPtr, wow64PosPtr + usWow64KeyLength, (wcslen(wow64PosPtr + usWow64KeyLength) + 1) * sizeof(wchar_t)); return; } // Process HKU if (wcsncmp(result, hkupreFix.Buffer, hkupreFix.Length / sizeof(wchar_t)) == 0) { // registry\user\S-1-5-20\EUDC\932 to registry\user\EUDC\932 if (wcslen(result) > (hkmControlSetFix.Length / sizeof(wchar_t)) + 1) { const auto pos = wcschr(result + hkupreFix.Length / sizeof(wchar_t), L'\\'); if (pos != nullptr) { const auto pos2 = wcschr(pos + 1, L'\\'); if (pos2 != nullptr) { memmove(pos, pos2, (wcslen(pos2) + 1) * sizeof(wchar_t)); return; } } } } // Process HKLM\System if (wcsncmp(result, hkmpreFix.Buffer, hkmpreFix.Length / sizeof(wchar_t)) == 0) { // registry\machine\system\ControlSet001 earse 001 // registry\machine\system\ControlSet // 一般来说 001就是 currentcontrolset // 也有可能出现002、003、004这些(当你选择 最近一次成功启动的配置信息 // 这个东西的时候) if (wcsncmp(result, hkmControlSetFix.Buffer, hkmControlSetFix.Length / sizeof(wchar_t)) == 0) { const auto pos = result + hkmControlSetFix.Length / sizeof(wchar_t); // check length if (wcslen(result) > (hkmControlSetFix.Length / sizeof(wchar_t)) + 1) { const auto pos2 = wcschr(pos + 1, L'\\'); if (pos2 != nullptr) { memmove(pos, pos2, (wcslen(pos2) + 1) * sizeof(wchar_t)); return; } } } } } ``` 这是效果:  wow64node:  本文由 huoji 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。 点赞 0
还不快抢沙发