【问题标题】:Why RegSaveKey() fails with an error code 5 (access is denied) if the key to be saved is HKEY_LOCAL_MACHINE?如果要保存的密钥是 HKEY_LOCAL_MACHINE,为什么 RegSaveKey() 会失败并显示错误代码 5(访问被拒绝)?
【发布时间】:2018-05-28 19:40:51
【问题描述】:

这个问题与所使用的编程语言无关。

在 Windows 7 SP1 和 Windows 10 版本 1803 中测试。

症状

如果要保存的密钥是HKEY_LOCAL_MACHINE

RegSaveKey() 会失败并返回错误代码 5(访问被拒绝)。

如果指定了子键,则不会发生此错误,例如HKEY_LOCAL_MACHINE\SYSTEM.

如果密钥为HKEY_CURRENT_USER,也不会发生此错误。

第一个样本

在这里,我使用 AutoIt 快速编写 a sample code 以重现错误。我还把示例代码编译成.EXE,方便大家看问题。

第二个样本

REG.EXE,这是一个内置的Windows工具使用Visual C++编写(这就是为什么标签包含C),与上面提到的完全相同的问题.这并不奇怪,因为根据我的调查,REG.EXE SAVE 命令实际上使用了未记录的 NtSaveKey()。顺便说一句,RegSaveKey() 在内部调用 NtSaveKey()

REG.EXE SAVE "HKLM" "HKLM.hiv" /Y

上述命令失败并出现错误“访问被拒绝”。请注意,我以 Administrator 身份运行命令。

问题

这个错误的原因是什么?有没有办法让 RegSaveKey() 适用于HKEY_LOCAL_MACHINE(不指定子键)?

更新

我进一步的测试表明regedit.exe和上面提到的一样。

  • HKEY_LOCAL_MACHINE 导出到.HIV 文件失败;但是,将其导出到 .REG 文件会成功。
  • HKEY_LOCAL_MACHINE\<subkey> 导出到.HIV 文件成功。
  • HKEY_CURRENT_USER 导出到.HIV 文件成功。
  • HKEY_CURRENT_USER\<subkey> 导出到.HIV 文件成功。

【问题讨论】:

  • 我认为错误隐藏了真正的问题:HKEY_LOCAL_MACHINE 不是实际存在的密钥。
  • NtSaveKey 内部调用CmSaveKey。这个 api 最开始Disallow attempts to "save" the master hive - 并在这个line 返回给你STATUS_ACCESS_DENIED
  • 你有什么可能的原因想要保存整个 HKEY_LOCAL_MACHINE 配置单元?
  • @CareyGregory,原因是如果我们将整个 HKLM 密钥导出到 .REG 文件中,regedit.exe 可以毫无问题地做到这一点。我的进一步测试表明,如果我们将整个 HKLM 密钥导出到 .HIV 文件中,regedit.exe 也会失败。
  • 这是因为 regedit 不会尝试从 .reg 文件重新创建 HKLM 密钥本身。它只是枚举 .reg 文件并单独恢复每个键/值。我认为@PaulStelian 是正确的,HKLM 不是您可以直接操作的物理密钥。

标签: c windows winapi


【解决方案1】:

所有保存注册表项的 API 在内部调用 CmSaveKey。在这个函数的源代码中,我们看到开头有以下block of code

    //
    // Disallow attempts to "save" the master hive
    //
    Hive = KeyControlBlock->KeyHive;

    if (Hive == &CmpMasterHive->Hive) {
        return STATUS_ACCESS_DENIED;
    }

HKEY_LOCAL_MACHINE(即“\Registry\Machine”)在主配置单元中,所以CmSaveKeySTATUS_ACCESS_DENIED(0xc0000022)返回给调用者。 Windows 子系统将此状态代码转换为ERROR_ACCESS_DENIED (5)。

【讨论】:

  • @eryksun 我查看我自己的调试器 - prnt.sc/jnse1a - 我打开 "\\registry\\machine" 键,查看对象指针 (CM_KEY_BODY) 并从中获取指向 KeyControlBlock->KeyHive 值的指针 (@987654335 @ 在我的具体情况下)与&CmpMasterHive->Hive 完全相同
  • @eryksun - 好吧,我的英语真的不是很好,但我只是检查了不同的键 - 对于\registry\machine 键,我得到了KeyBody->KeyControlBlock->KeyHive == &CmpMasterHive->Hive。而在另一个键上没有。这也是我在用户模式调试器中查看的)
  • @eryksun - 在调试器中查找几个键。 i.imgur.com/enso9xd.png 只是我想说的,对于 HKLM 我们在这次检查中被拒绝访问 Hive == &CmpMasterHive->Hive
  • @eryksun - 更准确地说,密钥更快CM_KEY_CONTROL_BLOCK 不是HHIVE,但它位于同一个HHIVEhandle -> CM_KEY_BODY -> CM_KEY_CONTROL_BLOCK -> HHIVE
  • 仅供参考,对于那些不熟悉此模式的人,每个引用特定键的 Key 对象的 KeyControlBlock 字段将引用相同的键控制块(即 CM_KEY_CONTROL_BLOCK 记录)。文件系统的实现方式类似。文件系统中特定文件/流的 File 对象有一个 FsContext 字段,该字段引用公共文件/流控制块(FCB 或 SCB)。另请注意,Key/File 对象可能被多个进程中的多个句柄引用。所以每个对象可以有多个句柄,每个控制块可以有多个对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 2017-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-06
相关资源
最近更新 更多