C++ 32位程序枚举64位系统注册表子项,含关闭重定向和提权

MSDN:http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms724256(v=vs.85).aspx


原英文注释对应翻译了,方便朋友们阅读

在VS2013中通过测试。增加了权限,可解决访问部分需要高权限的注册项,无法取得项名和值名的问题。

也可用“RtlAdjustPrivilege”函数提权,具体使用百度一下吧。


//	QueryKey - 枚举注册表子项和其关联的值.
//	hKey - 被枚举的注册表子项和值.

//	如何以 TrustedInstaller 用户权限修改注册表
//	通过代码将当前权限提升到 TrustedInstaller 很麻烦, 但是可以通过获取备份还原权限来绕过DACL的监测机制.

#pragma comment(lib,"advapi32")
#include <stdio.h>
#include <tchar.h>
#include <windows.h>

#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383

#define KEY_ALL_WOW64 (KEY_QUERY_VALUE | KEY_WOW64_64KEY)

bool EnablePriviledge(LPCTSTR lpSystemName) {
	HANDLE hToken;
	TOKEN_PRIVILEGES tkp = { 1 };
	if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
		if (LookupPrivilegeValue(NULL, lpSystemName, &tkp.Privileges[0].Luid)) {
			tkp.PrivilegeCount = 1;
			tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
			AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
			if (GetLastError() != ERROR_SUCCESS) {
				CloseHandle(hToken);
				return false;
			}
		}
		CloseHandle(hToken);
	}
	return true;
}

void QueryKey(HKEY hKey)
{
	TCHAR    achKey[MAX_KEY_LENGTH];			// 注册表子项名称缓冲区
	DWORD    cbName;							// 名称字符串大小
	TCHAR    achClass[MAX_PATH] = TEXT("");		// 类名缓冲区
	DWORD    cchClassName = MAX_PATH;			// 类字符串大小
	DWORD    cSubKeys = 0;						// 注册表子项数量
	DWORD    cbMaxSubKey;						// 最长注册表子项大小
	DWORD    cchMaxClass;						// 最长类字符串 
	DWORD    cValues;							// 项值数量(项内有多少个值)
	DWORD    cchMaxValue;						// 最长值名称
	DWORD    cbMaxValueData;					// 最长值数据
	DWORD    cbSecurityDescriptor;				// 安全描述符大小
	FILETIME ftLastWriteTime;					// 最后写入时间

	DWORD i, retCode;

	TCHAR	achValue[MAX_VALUE_NAME];
	DWORD	cchValue = MAX_VALUE_NAME;

	// 获取类名和值数.
	retCode = RegQueryInfoKey(
		hKey,                    // 一个已打开项的句柄(由 RegOpenKeyEx 或 RegCreateKeyEx 得到)
		achClass,                // 类名缓冲区
		&cchClassName,           // 类字符串大小 
		NULL,                    // 保留值, 设为 NULL
		&cSubKeys,               // 注册表子项数量
		&cbMaxSubKey,            // 最长注册表子项大小
		&cchMaxClass,            // 最长类字符串
		&cValues,                // 项值数量
		&cchMaxValue,            // 最长值名称
		&cbMaxValueData,         // 最长值数据
		&cbSecurityDescriptor,   // 安全描述符
		&ftLastWriteTime);       // 最后写入时间

	// 枚举注册表子项, 直到 RegEnumKeyEx 方法失败.
	if (cSubKeys)
	{
		printf("\n子项数量: %d\n", cSubKeys);
		for (i = 0; i < cSubKeys; i++)
		{
			cbName = MAX_KEY_LENGTH;
			retCode = RegEnumKeyEx(	// 调用 RegEnumKeyExA 时 如果老返回 5 访问拒绝, 可尝试 RegCreateKeyEx
				hKey,
				i,
				achKey,
				&cbName,
				NULL,
				NULL,
				NULL,	// 调用 RegEnumKeyExA 时, 此值设为 MAX_PATH 可解决方法返回 234 错误问题.(貌似非 NULL 都可以)
				// 例如 DWORD cNameLen [MAX_PATH]; RegEnumKeyExA(hKey, i, achKey, cbName, NULL, NULL, cNameLen, &ftLastWriteTime);
				&ftLastWriteTime);
			if (retCode == ERROR_SUCCESS)
			{
				_tprintf(TEXT("(%d) %s\n"), i + 1, achKey);
			}
		}
	}

	// 枚举项值.

	if (cValues)
	{
		printf("\n值数量: %d\n", cValues);

		for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
		{
			cchValue = MAX_VALUE_NAME;
			achValue[0] = '\0';
			retCode = RegEnumValue(
				hKey,
				i,
				achValue,
				&cchValue,
				NULL,
				NULL,
				NULL,
				NULL);
			if (retCode == ERROR_SUCCESS)
			{
				_tprintf(TEXT("(%d) %s\n"), i + 1, achValue);
			}
		}
	}
}

int __cdecl _tmain() {
	bool bRet;
	LONG lResult;
	PVOID oldWow64State = NULL;	// 无类型指针
	bRet = EnablePriviledge(SE_BACKUP_NAME);	// 这个函数让当前进程具有备份/还原的特权.
	if (bRet) {
		bRet = EnablePriviledge(SE_RESTORE_NAME);
		if (bRet) {
			HKEY hResult = NULL;
			DWORD dwDisposition;
			if (Wow64DisableWow64FsRedirection(&oldWow64State)){

				/*lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,	// 使用 RegOpenKeyEx 会因为权限不够无法访问部分需要高权限的注册项
				TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles"),
				0,
				KEY_ALL_WOW64,
				&hResult
				);
				*/

				lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
					TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles"),
					0,
					NULL,
					REG_OPTION_BACKUP_RESTORE,		// 这个是重点, 传入这个参数可以直接忽视 KEY_ALL_ACCESS 这个参数的作用, 直接以备份/还原的特权去操作注册表
					KEY_ALL_WOW64,					// 64位系统用 KEY_ALL_ACCESS 会无法访问 64 位注册项, 关闭重定向也会失败
					NULL,
					&hResult,
					&dwDisposition);

				RegDisableReflectionKey(hResult);
				QueryKey(hResult);
				RegCloseKey(hResult);
				RegEnableReflectionKey(hResult);
			}
			Wow64RevertWow64FsRedirection(oldWow64State);
			if (lResult != ERROR_SUCCESS) {
				return 3;
			}
			getchar();
			return 0;
		}
		else return 2;
	}
	else return 1;
}


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

至天

看心情啦,最好留着自己喝奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值