Click here to Skip to main content
15,884,298 members
Articles / Desktop Programming / MFC

Very secure method to save and restore registry

Rate me:
Please Sign up or sign in to vote.
4.18/5 (10 votes)
23 Aug 20047 min read 70.9K   988   20  
This article gives a very secure method to save and restore registry keys. It provides a ready to use tool in both command-line and UI modes.
// RegSR.cpp : Defines the class behaviors for the application.
//
// RegSR.h : main header file for the REGSR application
//	Author:		A.YEZZA
//	Date:		August 2004
//	Subject:	Save/Restore registry keys in very safe mode
//	Comment:	Use with your own risk
//	Licence:	This code and application are free. The unique 
//				condition is preserving author name			
///////////////////////////////////////////////////////////////////////////////////////


#include "stdafx.h"
#include "RegSR.h"
#include "MainDlg.h"
#include "CmdLineParser.h"
#include "Winreg.h"
#include <Sddl.h>	//This means: "Security Descriptor Definition Language" 
					//introduced since Win2K
#include "CRC32.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CRegSRApp

BEGIN_MESSAGE_MAP(CRegSRApp, CWinApp)
	//{{AFX_MSG_MAP(CRegSRApp)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG
	ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRegSRApp construction

CRegSRApp::CRegSRApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CRegSRApp object

CRegSRApp theApp;




CString		CRegSRApp::GetFileDirectory(CString &FilePathName)
{
	CString Temp=FilePathName;
	int		Pos=Temp.ReverseFind('\\');
	if ( Pos>0 ) 
		return FilePathName.Mid(0, Pos); 
	else return "";
	
}

CString		CRegSRApp::AddBackSlash(CString &strPath)
{
	if (strPath.Right(1)!="\\")
		return strPath+CString("\\");
	return strPath;
}

//	Get settings
void CRegSRApp::GetSettings()
{
	DWORD	dw=GetPrivateProfileString(SEC_SETTINGS, DATA_SERVER_PATH, "", 
									ServerPath.GetBuffer(255), 20, Params.ConfigFile);
	ServerPath.ReleaseBuffer(); 
	if ( (dw<=0) || (ServerPath==".") ) {
		//set ServerPath as to be in the program directory 
		TCHAR	Temp[MAX_PATH];
		GetModuleFileName(GetModuleHandle(NULL), Temp, MAX_PATH);	
		ServerPath=GetFileDirectory(CString(Temp));					
	}
	dw=GetPrivateProfileString(SEC_SETTINGS, DATA_CONFIG_FILE, "", 
							ConfigFile.GetBuffer(255), 20, Params.ConfigFile);
	ConfigFile.ReleaseBuffer(); 
	//set ConfigFile as to be the same as the config file passed as parameter
	if (dw<=0) 	ConfigFile=Params.ConfigFile; 						
	
}


HKEY	CRegSRApp::GetHiveFromString(LPCSTR strHive)
{
	if (stricmp(strHive,HKCU)==0)
		return HKEY_CURRENT_USER;
	else if (stricmp(strHive,HKLM)==0)
		return HKEY_LOCAL_MACHINE;
	else if (stricmp(strHive,HKUSERS)==0)
		return HKEY_USERS;
	else if (stricmp(strHive,HKCURCFG)==0)
		return HKEY_CURRENT_CONFIG;
	else return 0;
}


BOOL CRegSRApp::Get_CRC32()
{
	BOOL	ret=TRUE;
	CString	strCRC32="";
	CCRC32	ClassCRC32;
	ClassCRC32.InitTable();
	ret=(ClassCRC32.FileCrc32String(SavResFile.FileName, strCRC32)==0)?TRUE:FALSE;
	ClassCRC32.FreeTable();
	SavResFile.CRC32=strCRC32;	
	return ret;
}


//	Set privilege lpszPrivilege to the current user to Enabled or Disabled
//	depending on bEnablePrivilege if it is TRUE or FALSE
BOOL	CRegSRApp::SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
	TOKEN_PRIVILEGES tp;
	LUID luid;
	HANDLE hToken; 

	OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
	if ( !LookupPrivilegeValue(NULL, lpszPrivilege, &luid) )    
		return FALSE; 
	
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	
	if (bEnablePrivilege)
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	else
	    tp.Privileges[0].Attributes = 0;

	AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES) NULL, 0); 

	return ( (GetLastError()!=ERROR_SUCCESS)?FALSE:TRUE);
}


//	Test if the key KeyPath exist
//	Return TRUE if it exists, otherwise return FALSE
BOOL	CRegSRApp::IsKeyExist(HKEY hRoot, LPCSTR KeyPath)
{
	HKEY		hKey;
	BOOL		ret;

	if ( hRoot == NULL ) return FALSE;
	if ( KeyPath == NULL || (!lstrlen(KeyPath)) ) return FALSE;
	
	if ( (RegOpenKeyEx (hRoot, KeyPath, 0, KEY_EXECUTE, &hKey)==ERROR_FILE_NOT_FOUND) ||
		  (RegOpenKeyEx (hRoot, KeyPath, 0, KEY_EXECUTE, &hKey)!=ERROR_SUCCESS) )
		  ret=FALSE;
	else ret=TRUE;
	
	if (hKey) RegCloseKey (hKey);

	return ret;
}

//	Test if the file/directory FilePath exist
//	Return TRUE if it exists, otherwise return FALSE
BOOL	CRegSRApp::IsFileExist(LPCSTR FilePath)
{
	HANDLE			hSearch;
	WIN32_FIND_DATA FileData;

	hSearch = FindFirstFile(FilePath, &FileData); 
	return (hSearch != INVALID_HANDLE_VALUE);
}


void CRegSRApp::SetSavResFile()
{
	SavResFile.ConfigFile=Params.ConfigFile;
	SavResFile.FileName=Params.InOutFile;
	SavResFile.KeyPath=Params.KeyPath;
	SavResFile.hHive=Params.Root;
}



//	This function checks 2 things:
//	1.The fact that the file from which we restore the key 
//	  has the right CRC32 already reported to config file
//	2.The fact that the file corresponds exactly to the key 
//	  to restore from the file
//	NOTE: These 2 informations have been written in the save stage
//	Return TRUE if OKAY else FALSE
BOOL	CRegSRApp::CheckIntegrity(CString &Root, CString &SubKey, 
							   CString &InFile)
{
	BOOL	ret=TRUE;
	CString	KeyPath=AddBackSlash(Root)+SubKey;
	if (Get_CRC32()!=FALSE) {
		CString RetCRC32;
		DWORD dw=GetPrivateProfileString(SEC_CRC32, SavResFile.FileName, 
									"", RetCRC32.GetBuffer(128), 128, 
									AddBackSlash(ServerPath)+ConfigFile);
		RetCRC32.ReleaseBuffer();
		if (dw>0) {
			//Compare calculated CRC32 and the reported one
			if (RetCRC32.CompareNoCase(SavResFile.CRC32)==0){
				//Get the corresponding key	and compare
				CString	strKeyPath;
				DWORD dw=GetPrivateProfileString(SEC_KEYS_FILES, SavResFile.FileName, 
									"", strKeyPath.GetBuffer(255), 255, 
									AddBackSlash(ServerPath)+ConfigFile);
				strKeyPath.ReleaseBuffer();
				ret = (strKeyPath.CompareNoCase(KeyPath)==0)?TRUE:FALSE;
			} else ret=FALSE;
		} else ret=FALSE;
	} else ret=FALSE;

	return ret;
}

//	Restore registry key Root\SubKey from file InFile
//	Return TRUE if success, otherwise it returns FALSE
BOOL CRegSRApp::RestoreRegKeyPath(CString &Root, CString &SubKey, 
							   CString &InFile, DWORD	&RetError)
{
	SetSavResFile();

	//Before restoring data, we have to ensure that:
	//	1-InFile corresponds to Root\SubKey
	//	2-InFile has the right already saved CRC32
	if (CheckIntegrity(Root, SubKey,InFile)==FALSE){
		MessageBox(NULL, "Check data integrity failled.\nRestoring Data is impossible.","",MB_OK|MB_ICONEXCLAMATION|MB_SYSTEMMODAL); 
		return FALSE;
	}

	BOOL	ret=TRUE;
	DWORD	d=0;
	HKEY	hRoot;
	
	SetPrivilege(SE_RESTORE_NAME,TRUE);
	SetPrivilege(SE_BACKUP_NAME,TRUE);

	hRoot=(HKEY)GetHiveFromString(Root);
	if (!IsFileExist(InFile)) {
		d=ERROR_FILE_NOT_FOUND;
		ret=FALSE;
	}
	else {
		HKEY	hhKey;
		char	lpClass[80];
		DWORD	lpDisposition=0;
		LONG l=RegCreateKeyEx(hRoot,SubKey,0,lpClass, REG_OPTION_BACKUP_RESTORE,
							KEY_WRITE, NULL, &hhKey, &lpDisposition);
		if ( (l==ERROR_SUCCESS) || (l==ERROR_FILE_NOT_FOUND) )  {
			d=RegRestoreKey(hhKey,InFile,REG_NO_LAZY_FLUSH);
			RegCloseKey(hhKey);
			if (d!=ERROR_SUCCESS) 
				ret=FALSE;
		} 
		else {
			d=(DWORD)l;
			ret=FALSE; 
		}
	}	
	
	SetPrivilege(SE_RESTORE_NAME,FALSE);
	SetPrivilege(SE_BACKUP_NAME,FALSE);

	RetError=d;
	return ret;
}




//	Save registry key SubKey to file OutFile
//	Return TRUE if success, otherwise it returns FALSE
BOOL CRegSRApp::SaveRegKeyPath(CString &Root, CString &SubKey, 
							   CString &OutFile, DWORD	&RetError)
{
	BOOL	ret=TRUE;
	HKEY	hKey=NULL;
	DWORD	d=0;
	HKEY	hRoot;

	SetPrivilege(SE_BACKUP_NAME,TRUE);
	
	hRoot=(HKEY)GetHiveFromString(Root);
	if (RegOpenKeyEx(hRoot, SubKey,0,KEY_READ, &hKey)==ERROR_SUCCESS)  {
		if (IsFileExist(OutFile)){
			//we must delete file before saving, otherwise it doesn't work !
			if (DeleteFile(OutFile))	
				d=RegSaveKey(hKey,OutFile,NULL);
		} else d=RegSaveKey(hKey,OutFile,NULL);
		if (d!=ERROR_SUCCESS)
			ret=FALSE;
		else {//Save CRC32 file
			SetSavResFile();
			//save CRC32 file and file name/key path correspondance
			//These 2 informations should be used to secure restoring data
			if (Get_CRC32()!=FALSE) {
				ret=WritePrivateProfileString(SEC_CRC32, SavResFile.FileName, 
											SavResFile.CRC32, AddBackSlash(ServerPath)+ConfigFile);
				ret=WritePrivateProfileString(SEC_KEYS_FILES, SavResFile.FileName, 
											SavResFile.hHive+CString("\\")+SavResFile.KeyPath, 
											AddBackSlash(ServerPath)+ConfigFile);
			}
		}
		RegCloseKey(hKey);	
	} 
	else { 
		if (IsKeyExist(hRoot,SubKey)==FALSE)
			d=ERROR_FILE_NOT_FOUND;
		else d=GetLastError();
		ret=FALSE;
	}
	
	SetPrivilege(SE_BACKUP_NAME,FALSE);

	RetError=d;
	return ret;
}

//	Print how to use it
void CRegSRApp::Usage()
{
	CString	Usage, Example,Copyright;
	if ( (Usage.LoadString(IDS_USAGE)>0) &&
		 (Example.LoadString(IDS_EXAMPLE)>0) &&
		 (Copyright.LoadString(IDS_COPYRIGHT)>0) )
		MessageBox(NULL, Usage+Example+Copyright,"Registry Save/Restore",MB_OK);
}



void CRegSRApp::SetParams(CmdParams &P, int &PNum)
{
	PNum=0;
	Params.Op=P.Op;
	if (Params.Op!="") PNum++;
	Params.Root=P.Root;
	if (Params.Root!="") PNum++;
	Params.KeyPath=P.KeyPath;
	if (Params.KeyPath!="") PNum++;
	Params.InOutFile=P.InOutFile;
	if (Params.InOutFile!="") PNum++;
	Params.ConfigFile=P.ConfigFile;
	if (Params.ConfigFile!="") PNum++;
	SetSavResFile();
}

void CRegSRApp::GetParams(CString& CmdLine, int &ParamsNum)
{
	static CString	Switchs[]={	"S",
						"R",
						"H",
						"K",
						"P",
						"C"
						};
	ParamsNum=0;
	CCmdLineParser	CmdLinePars(CmdLine);
	CCmdLineParser::POSITION pos = CmdLinePars.getFirst();	
	CString sKey,sVal;
	while (!CmdLinePars.isLast(pos)) {
		CmdLinePars.getNext(pos, sKey, sVal);
		sKey.MakeUpper(); sVal.MakeUpper(); 
		if ( (sKey==Switchs[0]) || (sKey==Switchs[1]) ){
			Params.Op=(sKey==Switchs[0])?"S":"R";
			ParamsNum++;
		}else if (sKey==Switchs[2]){
			Params.Root=sVal;
			ParamsNum++;
		}
		else if (sKey==Switchs[3]){
			Params.KeyPath=sVal;
			ParamsNum++;
		}
		else if (sKey==Switchs[4]){
			Params.InOutFile=sVal;
			ParamsNum++;
		}
		else if (sKey==Switchs[5]){
			Params.ConfigFile=sVal;
			ParamsNum++;
		}
	}
}


void CRegSRApp::DoSaveRestore(DWORD	&RetErr)
{
	GetSettings();
	if (Params.Op=="S"){
		SaveRegKeyPath(Params.Root,Params.KeyPath, Params.InOutFile, RetErr);
	}
	else if (Params.Op=="R"){
		RestoreRegKeyPath(Params.Root,Params.KeyPath, Params.InOutFile, RetErr);	
	}
}


/////////////////////////////////////////////////////////////////////////////
// CRegSRApp initialization

BOOL CRegSRApp::InitInstance()
{
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	//  of your final executable, you should remove from the following
	//  the specific initialization routines you do not need.

#ifdef _AFXDLL
	Enable3dControls();			// Call this when using MFC in a shared DLL
#else
	Enable3dControlsStatic();	// Call this when linking to MFC statically
#endif

	
	CString	CmdLine;
	CmdLine=theApp.m_lpCmdLine;
	CmdLine.MakeUpper();

	if 	(CmdLine==""){	
		Usage();
		return FALSE;
	}
	else {
		if (CmdLine=="/UI") {
			CMainDlg dlg;
			m_pMainWnd = &dlg;
			dlg.DoModal();
			return FALSE;
		}
		else {
			int ParamsNum;
			GetParams(CmdLine, ParamsNum);
			if (ParamsNum<4){
				Usage();
				return FALSE;
			}
			else {
				DWORD	RetErr=0;
				DoSaveRestore(RetErr);
				if (RetErr<32736) exit(RetErr);
				else return FALSE;
			}
		}
	}

	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	//return FALSE;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions