【发布时间】:2018-06-09 02:31:06
【问题描述】:
我正在尝试使用 Windows API 在 Windows 10 中创建一个新的注册表项,即 RegCreateKeyEx 函数,然后使用 GetSecurityInfo 获取其 DACL。所有的断言都顺利进行,直到我到达所说的GetSecurityInfo 函数调用,它给出了一个无效的句柄值错误(错误 6)。我做错了什么?
这是一个更复杂的项目的一部分,所以我只会在这里给出(或我认为的,但我也可以添加其余部分)相关部分:
RegCreateKeyEx 的包装器,使输出更易于使用并设置遇到的任何错误:
inline extern auto RegCreateKeyEx_safe(
_In_ const HKEY hKey,
_In_ const LPCTSTR lpSubKey,
_Reserved_ const DWORD Reserved,
_In_opt_ const LPTSTR lpClass,
_In_ const DWORD dwOptions,
_In_ const REGSAM samDesired,
_In_opt_ const LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_Out_ const PHKEY phkResult,
_Out_opt_ const LPDWORD lpdwDisposition)
{
const auto result =
RegCreateKeyEx(
hKey,
lpSubKey,
Reserved,
lpClass,
dwOptions,
samDesired,
lpSecurityAttributes,
phkResult,
lpdwDisposition);
if (result != ERROR_SUCCESS)
SetLastError(result);
return result == ERROR_SUCCESS;
}
上述函数的包装器,在检查是否有效后应返回创建的键的句柄:
inline extern auto CreateNewRegKey(
HKEY hKey,
LPCTSTR lpSubKey,
DWORD Reserved,
LPTSTR lpClass,
DWORD dwOptions,
REGSAM samDesired,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
LPDWORD lpdwDisposition)
{
auto createdKey = static_cast<PHKEY>(malloc(sizeof HKEY));
assert(
RegCreateKeyEx_safe(
hKey,
lpSubKey,
Reserved,
lpClass,
dwOptions,
samDesired,
lpSecurityAttributes,
createdKey,
lpdwDisposition));
assert(createdKey != INVALID_HANDLE_VALUE);
return createdKey;
}
还有一个 GetSecurityInfo 的包装器,原因和功能与 RegCreateKey 版本相同:
inline extern auto GetSecurityInfo_safe(
_In_ const HANDLE handle,
_In_ const SE_OBJECT_TYPE ObjectType,
_In_ const SECURITY_INFORMATION SecurityInfo,
_Out_opt_ PSID* ppsidOwner,
_Out_opt_ PSID* ppsidGroup,
_Out_opt_ PACL* ppDacl,
_Out_opt_ PACL* ppSacl,
_Out_opt_ PSECURITY_DESCRIPTOR* ppSecurityDescriptor)
{
const auto result =
GetSecurityInfo(
handle,
ObjectType,
SecurityInfo,
ppsidOwner,
ppsidGroup,
ppDacl,
ppSacl,
ppSecurityDescriptor);
if (result != ERROR_SUCCESS)
SetLastError(result);
return result == EXIT_SUCCESS;
}
现在调用这些函数的代码如下:
const auto newRegKey =
CreateNewRegKey(
HKEY_CURRENT_USER,
SUBKEY_PATH,
NULL,
nullptr,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL, //securityAttributes,
nullptr);
assert(
GetSecurityInfo_safe(
newRegKey,
SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
oldDacl,
NULL,
NULL));
输出很清楚问题出在哪里(我实现了一个稍微冗长的断言,在检查条件后,它会打印它,以及错误文本以防条件失败):
SUCCESS: RegCreateKeyEx_safe( hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, createdKey, lpdwDisposition)
SUCCESS: createdKey != INVALID_HANDLE_VALUE
FAILURE: GetSecurityInfo_safe( newRegKey, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL, oldDacl, NULL, NULL)
ERROR-6: The handle is invalid.
断言:
#define _VERBOSE (1)
#define assert(cond) if((cond) == TRUE) \
{ if (_VERBOSE) cout << "SUCCESS:\t" << #cond << endl; } \
else \
{cout << "FAILURE:\t" << #cond << "\n\nERROR-" << GetLastError() << ":\t" << GetLastErrorAsString() << "\n\n"; exit(EXIT_FAILURE); }
提前谢谢你!
【问题讨论】:
-
这个包装器有什么意义?
SetLastError这里不需要 - Reg api 只返回错误代码而不是 true/false,这确实更好的设计和易于使用 -
@RbMm 需要它们,因为代码是更复杂项目的一部分,并且一致性使得使用更大的代码库变得更加容易:)
-
使用返回错误代码的函数 - 比使用返回真/假并设置最后一个错误的函数容易得多
-
Windwes API 中的一些函数使用“经典”方式返回错误代码,而其他函数返回 winapi BOOL,没有内在的一致性,所以我不得不自己破解它。
标签: c++ windows security winapi registry