正确地将字符串添加到 Windows 注册表中的 REG_BINARY 类型

Posted

技术标签:

【中文标题】正确地将字符串添加到 Windows 注册表中的 REG_BINARY 类型【英文标题】:Correctly add string to a REG_BINARY type in Windows Registry 【发布时间】:2017-11-02 18:51:38 【问题描述】:

我正在尝试自动化将软件策略哈希规则添加到 Windows 的过程,但目前在向注册表添加有效哈希时遇到问题。此代码创建一个键并将哈希添加到注册表:

HKEY* m_hKey;
string md5Digest;
string valueName = "ItemData";
vector<BYTE> itemData;

/*
use Crypto++ to get file hash
*/

//convert string to format that can be loaded into registry
for (int i = 1; i < md5Digest.length(); i += 2)
    itemData.push_back('0x' + md5Digest[i - 1] + md5Digest[i]);

// Total data size, in bytes
const DWORD dataSize = static_cast<DWORD>(itemData.size());

::RegSetValueEx(
    m_hKey,
    valueName.c_str(),
    0, // reserved
    REG_BINARY,
    &itemData[0],
    dataSize
);

这工作正常,并将密钥添加到注册表:

但是在将注册表项与组策略添加的规则进行比较时,您会发现一个非常重要的区别:

它们之间的“ItemData”值不同。底部图片的 ItemData 值是正确的输出。在调试程序时,我可以清楚地看到 md5Digest 具有正确的值,因此问题在于将 md5Digest 字符串转换为 BYTE 或无符号字符的 ItemData 向量......

我的代码有什么问题,为什么数据被错误地输入到注册表中?

【问题讨论】:

char_code('x') + char_code('3') + char_code('D') = 0xEF 以来,您似乎在构建矢量错误,但您想要 0x3D。 @JohnnyMopp 那么我该如何正确构建向量呢? 【参考方案1】:

您有一个要转换为字节数组的字符串。您可以编写一个辅助函数将 2 个字符转换为 BYTE:

using BYTE = unsigned char;

BYTE convert(char a, char b)

    // Convert hex char to byte
    // Needs fixin for lower case
    if (a >= '0' && a <= '9') a -= '0';
    else a -= 55;  // 55 = 'A' - 10
    if (b >= '0' && b <= '9') b -= '0';
    else b -= 55;

    return (a << 4) | b;

....
vector<BYTE> v;
string s = "3D65B8EBDD0E";
for (int i = 0; i < s.length(); i+=2) 
    v.push_back(convert(s[i], s[i+1]));

v 现在包含0x3D, 0x65, 0xB8, 0xEB, 0xDD, 0x0E

或者,正如@RbMm 所述,您可以使用CryptStringToBinary Windows 函数:

#include <wincrypt.h>
...
std::string s = "3D65B8EBDD0E";
DWORD hex_len = s.length() / 2;
BYTE *buffer = new BYTE[hex_len];
CryptStringToBinary(s.c_str(),
    s.length(),
    CRYPT_STRING_HEX,
    buffer, 
    &hex_len,
    NULL,
    NULL
    );

【讨论】:

可以这样做,或者可以使用CryptStringToBinaryW 和CRYPT_STRING_HEX 标志 @RbMm 谢谢。我不知道那个功能。我会更新的。 标记为简洁代码和引用 WinAPI 等效函数的答案。【参考方案2】:

您将'0x' 两个字母的字符文字与md5Digest[i - 1] + md5Digest[i] 相加,然后转为BYTE。这看起来像是您试图从中构建“0xFF”字节值。您应该直接存储 md5 字符串:

const DWORD dataSize = static_cast<DWORD>(md5Digest.size());

::RegSetValueEx(
    m_hKey,
    valueName.c_str(),
    0, // reserved
    REG_BINARY,
    reinterpret_cast< BYTE const *>(md5Digest.data()),
    dataSize
);

如果您确实需要存储来自 md5 的十六进制数字的二进制表示,那么您需要将它们转换为如下所示的字节:

BYTE char_to_halfbyte(char const c)

    if(('0' <= c) && (c <= '9'))
    
        return(static_cast<BYTE>(c - `0`));
    
    else
    
        assert(('A' <= c) && (c <= 'F'));
        return(static_cast<BYTE>(10 + c - `A`));
    


for(std::size_t i = 0; i < md5Digest.length(); i += 2)

    assert((i + 1) < md5Digest.length());
    itemData.push_back
    (
       (char_to_halfbyte(md5Digest[i    ]) << 4)
       |
       (char_to_halfbyte(md5Digest[i + 1])     )
    );

【讨论】:

那么我应该删除“0x”部分吗? (编辑)刚试过,它产生的东西与上面两个例子完全不同 @AndrewLeFevre 可以直接存起来。 如何直接存储? 感谢您的回答,但只是尝试了这个,它再次输出与 about 示例不同的内容,并且由于某种原因,输出的长度是原来的两倍。 @AndrewLeFevre 也许您试图将 md5 十六进制数字转换为字节?例如所以存储的值看起来像3D 65 等等?

以上是关于正确地将字符串添加到 Windows 注册表中的 REG_BINARY 类型的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将 UITextField 添加到 UITableViewCell

Git学习系列之如何正确且高效地将本地项目上传到Github(图文详解)

我是不是正确地将对象添加到核心数据?

如何正确地将 Spring 包含到 OSGified 包中

如何正确地将多个片段添加到片段过渡?

如何正确地将安全区域插图添加到 UIStackView?