实现比较简单,是通过修改注册表:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/SafeBoot的子项Minimal和Network的名字实现的。
1、提权
CAccessToken token;
token.GetProcessToken(TOKEN_ALL_ACCESS);
token.EnablePrivilege(SE_TAKE_OWNERSHIP_NAME);
2、修改注册表权限
调用TreeSetNamedSecurityInfo实现,这个函数可以设置注册表和子项的权限;网上很多教程调用的SetNameSecurityInfo,不能设置子项的权限,修改名字会失败。
3、修改注册表子项名字
RegRenameKey(hKey, NULL, newName); // hKey为minimal或者network项,newName为新名字
完整代码如下:
#include "stdafx.h"
#include <Windows.h>
#include <WinSvc.h>
#include <WinIoCtl.h>
#include <minwindef.h>
#include <fltUser.h>
#include <malloc.h>
#include <tchar.h>
#include <Aclapi.h>
#include <atlsecurity.h>
#include <Winreg.h>
#define REG_SAFE_BOOT_PATH _T("SYSTEM\\CurrentControlSet\\Control\\SafeBoot")
#define REG_SAFE_BOOT_MINIMAL_NAME _T("Minimal")
#define REG_SAFE_BOOT_NETWORK_NAME _T("Network")
#define REG_SAFE_BOOT_MINIMAL_RENAME _T("Minimal_Bak")
#define REG_SAFE_BOOT_NETWORK_RENAME _T("Network_Bak")
#define
static LPCTSTR GetPrimaryKeyName(HKEY hKey)
{
if (HKEY_LOCAL_MACHINE == hKey)
{
return _T("MACHINE");
}
else if (HKEY_CLASSES_ROOT == hKey)
{
return _T("CLASSES_ROOT");
}
else if (HKEY_USERS == hKey)
{
return _T("USERS");
}
else if (HKEY_CURRENT_USER == hKey)
{
return _T("CURRENT_USER");
}
return NULL;
}
static BOOL SetPrivilege(
BOOL bEnablePrivilege
)
{
CAccessToken token;
token.GetProcessToken(TOKEN_ALL_ACCESS);
token.EnablePrivilege(SE_TAKE_OWNERSHIP_NAME);
return TRUE;
}
static BOOLEAN RenameRegistry(HKEY priKey, LPTCH parentPath, LPTCH subName, LPTCH newName)
{
int ret;
HKEY hKey;
TCHAR regPath[MAX_PATH] = { 0 };
_tcscpy_s(regPath, parentPath);
_tcscat_s(regPath, _T("\\"));
_tcscat_s(regPath, subName);
ret = RegOpenKeyEx(priKey, regPath, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, &hKey);
if (ret != ERROR_SUCCESS)
{
_tprintf(_T("MdmRenameReg: RegOpenKeyEx failed: name = %s, newname = %s, ret = %d, lasterr = %d\n"),
subName, newName, ret, GetLastError());
return FALSE;
}
ret = RegRenameKey(hKey, NULL, newName);
if (ret != ERROR_SUCCESS)
{
_tprintf(_T("MdmRenameReg: RegRenameKey failed: name = %s, newname = %s, ret = %d, lasterr = %d\n"),
subName, newName, ret, GetLastError());
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
static BOOLEAN RequestPermissionAndRenameRegistry(HKEY priKey, LPTCH parentPath, LPTCH subName, LPTCH newName)
{
DWORD ret;
BOOLEAN status = TRUE;
BOOLEAN renamed = FALSE;
CDacl dacl;
TCHAR regOldPath[MAX_PATH] = { 0 };
TCHAR regNewPath[MAX_PATH] = { 0 };
_tcscpy_s(regOldPath, GetPrimaryKeyName(priKey));
_tcscat_s(regOldPath, _T("\\"));
_tcscat_s(regOldPath, parentPath);
_tcscat_s(regOldPath, _T("\\"));
_tcscat_s(regOldPath, subName);
_tcscpy_s(regNewPath, GetPrimaryKeyName(priKey));
_tcscat_s(regNewPath, _T("\\"));
_tcscat_s(regNewPath, parentPath);
_tcscat_s(regNewPath, _T("\\"));
_tcscat_s(regNewPath, newName);
ret = TreeSetNamedSecurityInfo(regOldPath,
SE_REGISTRY_KEY,
OWNER_SECURITY_INFORMATION,
(PSID)Sids::Admins().GetPSID(),
NULL,
NULL,
NULL,
TREE_SEC_INFO_SET,
NULL,
ProgressInvokeNever,
NULL);
if (ret != ERROR_SUCCESS)
{
_tprintf(_T("TreeSetNamedSecurityInfo: OWNER_SECURITY_INFORMATION Error: %d\n"), ret);
status = FALSE;
goto EXIT;
}
dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL);
ret = TreeSetNamedSecurityInfo(regOldPath,
SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
(PACL)dacl.GetPACL(),
NULL,
TREE_SEC_INFO_SET,
NULL,
ProgressInvokeNever,
NULL);
if (ret != ERROR_SUCCESS)
{
_tprintf(_T("TreeSetNamedSecurityInfo: DACL_SECURITY_INFORMATION Error: %d\n"), ret);
status = FALSE;
goto EXIT;
}
if (!(renamed = RenameRegistry(priKey, parentPath, subName, newName)))
{
status = FALSE;
goto EXIT;
}
EXIT:
if (ret == ERROR_SUCCESS)
{
// TODO: 恢复DACL
if (renamed)
{
}
else
{
}
}
return status;
}
INT DLL_API EnableSafeBoot()
{
INT status = SUCCESS;
if (!SetPrivilege(TRUE))
{
_tprintf(_T("EnableSafeBoot: SetPrivilege failed\n"));
return ERR_API_BASE;
}
if (!RequestPermissionAndRenameRegistry(HKEY_LOCAL_MACHINE, REG_SAFE_BOOT_PATH,
REG_SAFE_BOOT_MINIMAL_RENAME, REG_SAFE_BOOT_MINIMAL_NAME))
{
_tprintf(_T("EnableSafeBoot: RequestPermissionAndRenameRegistry minimal failed\n"));
return ERR_API_BASE;
}
if (!RequestPermissionAndRenameRegistry(HKEY_LOCAL_MACHINE, REG_SAFE_BOOT_PATH,
REG_SAFE_BOOT_NETWORK_RENAME, REG_SAFE_BOOT_NETWORK_NAME))
{
_tprintf(_T("EnableSafeBoot: RequestPermissionAndRenameRegistry network failed\n"));
return ERR_API_BASE;
}
return status;
}
INT DLL_API DisableSafeBoot()
{
INT status = SUCCESS;
if (!SetPrivilege(TRUE))
{
_tprintf(_T("DisableSafeBoot: SetPrivilege failed\n"));
return ERR_API_BASE;
}
if (!RequestPermissionAndRenameRegistry(HKEY_LOCAL_MACHINE, REG_SAFE_BOOT_PATH,
REG_SAFE_BOOT_MINIMAL_NAME, REG_SAFE_BOOT_MINIMAL_RENAME))
{
_tprintf(_T("DisableSafeBoot: RequestPermissionAndRenameRegistry minimal failed\n"));
return ERR_API_BASE;
}
if (!RequestPermissionAndRenameRegistry(HKEY_LOCAL_MACHINE, REG_SAFE_BOOT_PATH,
REG_SAFE_BOOT_NETWORK_NAME, REG_SAFE_BOOT_NETWORK_RENAME))
{
_tprintf(_T("DisableSafeBoot: RequestPermissionAndRenameRegistry network failed\n"));
return ERR_API_BASE;
}
return status;
}