Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Very secure method to save and restore registry

0.00/5 (No votes)
23 Aug 2004 1  
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.

Contents

Introduction

In a previous article: How to save and restore Registry Keys, I have provided a command-line tool to save/restore registry keys to/from data files. That's why I invite you if you are not familiar with this topic, to read first the previous article to have an idea about the subject. The provided tool in that article suffers from the fact that restoring keys from data files is not secure at all, except if we know exactly that the following two conditions are met:

  1. The data file corresponds exactly to the key we want to restore.
  2. The data file is exactly the same as the one that has been saved, i.e., has not been modified or corrupted.

The present article does not only respect the previous two conditions, but also provides a more general tool that can be used in two modes: in scripts as a command-line tool, and in UI mode as shown in the image above. In order to respond to these two conditions, we have to provide a registry configuration file (don't confuse with the program configuration file as indicated in the sequel, they are not necessarily the same) in which we add during saving stage, two important pieces of information:

  1. The correspondence between the data file location and the registry key path.
  2. A CRC32 value (Cyclic Redundancy Checksum in a 32-bit number) corresponding to the saved data file.

When it's time to restore data, we have to check data integrity, i.e., two things:

  1. Correspondence Key/File: we look for the data file in the configuration file corresponding to the key we want to restore (already done in save stage).
  2. File integrity check: we compute its CRC32, we compare it with the reported CRC32 (in save stage). If the two CRCs are the same, then we proceed to the restore action, otherwise the data file is not restored.

Basically, two Windows APIs have been used in the project: RegSaveKey and RegRestoreKey. There is no way by using these two API functions to ensure that saving and restoring registry keys is secure. It is said in MSDN:

"If RegSaveKey fails part way through its operation, the file will be corrupt, and subsequent calls to RegLoadKey, RegReplaceKey, or RegRestoreKey for the file will fail."

In order to use the tool accompanying this article, the calling process has to use an account in the Administrators group. The tool adds necessary privileges for saving and restoring registry, namely SE_BACKUP_NAME (SeBackupPrivilege) or/and SE_RESTORE_NAME (SeRestorePrivilege) respectively. It will be a good exercise to test for real privileges to achieve these two tasks without being in the Administrators group.

I have to express my thanks to:

  • Brian Friesen for his excellent article CRC32: Generating a checksum for a file from which I have picked all functions to provide CCRC32 class used in the project.
  • Pavel Antonov for his excellent parser class CCmdLineParser in his article Command line parser used to parse the tool command-line.

How to use the provided tool

UI mode Command-line mode
RegSR /UI RegSR /S|/R /H:ROOT /K:KEY /P:FILE [/C:CONFIG_FILE]

/S
/R
ROOT
KEY
FILE
CONF_FILE

To save a registry key to file.
To restore a registry key from file.
Take HKCU, HKLM, HKUSERS, or HKCURCFG.
Subkey path.
Input file in restore mode or output file in save mode.
Program configuration file used to secure restoring data. It contains also other information.

ROOT values meaning:
HKCU HKEY_CURRENT_USER
HKLM HKEY_LOCAL_MACHINE
HKUSERS HKEY_USERS
HKCURCFG HKEY_CURRENT_CONFIG

Remark: The program configuration file CONF_FILE is the file indicating the server name where the registry save/restore configuration file should be located as the value of ServerPath key and the configuration file name as the value of ConfigFile key. Following are two examples of such a file:

Example 1 Example 2

[SETTINGS]
;The Server path is in the same directory as the program RegSR.exe
ServerPath =.
;The config file name
ConfigFile =RegConfig.ini

[SETTINGS]
;The Server path is on the machine whose name MyServer in the share called MyShare
ServerPath =\\MyServer\MyShare
;The config file name
ConfigFile =MyRegConfigFile.ini


In Example 1, the program will save key and file data including file CRC32 information in the file .\RegConfig.ini.

In Example 2, the program will save key and file data including file CRC32 information in the file \\MyServer\MyShare\RegConfig.ini.

Note that the program configuration file may be the same as the registry save/restore configuration file. In this case, we have to make the parameter CONFIG_FILE to be the same as ServerPath\ConfigFile.

When can we use the provided tool

The provided tool can be used in many contexts such as:

  • To manage users profiles with respect to the registry.
  • To configure software with respect to the registry at any time not necessarily during installation process.
  • To configure hardware as printers, scanners, etc.

Context use

If you are running the tool in a a different context than the current user, like as in a service context, you cannot use HKCU (HKEY_CURRENT_USER) since you don't have the registry visibility of the logged-on user. In such a case, you can accede HKCU by the main of its SID under the registry hive HKUSERS (HKEY_USERS) with the condition that the SID value can be obtained. This is an example:

RegSr /R /H:HKUSERS /K:S-1-5-21-861567501-842925246-854245398-1004\Microsoft\Office /P:C:\Office.dat

Here, we restore the data file C:\Office.dat to the user whose SID=S-1-5-21-861567501-842925246-854245398-1004 to its key Microsoft\Office. The example above is equivalent to the following line but in the context of the current user:

RegSr /R /H:HKCU /K:Microsoft\Office /P:C:\Office.dat

How can we use the provided tool

There is a generic VBScript RegSr.vbs as shown below using the provided tool to save/restore registry keys. You can customize it with respect to your requirements. It generates a log file RegSR.log in the temporary directory containing the exit code of the program RegSR.exe. The returned codes are:

1 Non valid arguments
2 File not found
else Returned code from RegSR.exe. It can be also 2.

To use the script, you have just to use the same syntax as that of the tool, i.e.,

RegSR.vbs /S|/R /H:ROOT /K:KEY /P:FILE [/C:CONFIG_FILE]

Example: RegSR.vbs /S /H:HKCU /K:software\test /P:c:\test.dat

RegSr.vbs listing:

'////////////////////////////////////////////////////////

' Purpose:    Registry Save/Restore 

' Author:        A. YEZZA ' Date:        August 2004 

'//////////////////////////////////////////////////////// 


Option Explicit 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

'CONSTANTS 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

Const LOG_FILE="RegSR.LOG" 
Const REG_SR="RegSR.exe" 
Const SEPARATOR="===================================================" 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

'Global variables 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

Dim ScriptArgs:    Set ScriptArgs = WScript.Arguments Dim WSHShell : _
                   Set WSHShell = WScript.CreateObject("WScript.Shell") 
Dim fso:           Set fso = CreateObject("Scripting.FileSystemObject") 
Dim EnvObject:     Set EnvObject = WshShell.Environment("PROCESS") 
Dim TempDir: TEMPDir = EnvObject.Item("TEMP") 
Dim WScriptJet: WScriptJet = _
                      EnvObject.Item("WINDIR") &"\System32\WScript.exe" 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

'Command-line Arguments variables 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

Dim Op 
Dim Root 
Dim Key 
Dim InOutFile Dim ConfigFile '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

'MAIN 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

Call MAIN()  


'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

'> PROCEDURES > 

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

Sub MAIN() 
    Dim Ret WriteToFile LOG_FILE,vbcrlf+SEPARATOR+vbcrlf+"BEGIN:<" 
    If GetParameters()=False Then 
        ExitScript(1) 
    Else 
        If ConfigFile<>"" Then 
           WriteToFile LOG_FILE,"Launching : "&_
             CurrentDir()& REG_SR & " "& _
             Op&" /H:"&Root&" /K:"&Key&_
             " /P:"&InOutFile&" /C:" & _
             ConfigFile Ret=LaunchEXE(CurrentDir() _
             & REG_SR, Op&" /H:"&Root&_
             " /K:"&Key& " /P:"&InOutFile&_
             " /C:"&ConfigFile,True) 
        Else 
           WriteToFile LOG_FILE,"Launching : "& _
             CurrentDir() & REG_SR & " "& _
             Op&" /H:"&Root&" /K:"&Key&_
             " /P:" & InOutFile Ret=LaunchEXE(CurrentDir() _
             & REG_SR, Op&" /H:"&Root&_
             " /K:"&Key& " /P:"&InOutFile,True) 
        End If 
    End If ExitScript(Ret) 
End Sub 


Function CurrentDir() CurrentDir=Mid(WScript.ScriptFullName,_
         1,Len(WScript.ScriptFullName)-Len(WScript.ScriptName)) 
End Function 

Sub ExitScript(ErrCode) 
    if ErrCode=0 Then WriteToFile LOG_FILE, _
       "END:>Normal termination"+vbcrlf+_
       SEPARATOR Else WriteToFile LOG_FILE, _
       "END:>Error Code: " & CStr(ErrCode)+_
       vbcrlf+SEPARATOR End If 
    Set fso=Nothing 
    Set WSHShell=Nothing 
    Set EnvObject=Nothing WScript.Quit(ErrCode) 
End Sub 

Sub WriteToFile(File, Text) 
    Dim TextFile File=TEMPDir+"\"+File 
    If Not IsFileExist(File) Then 
        Set TextFile=fso.CreateTextFile(File, True) 
    Else 
        Set TextFile=fso.OpenTextFile(File, 8) 
    End If
    TextFile.WriteLine(Text)
    TextFile.Close
    Set TextFile=Nothing 
End Sub 

Function IsFileExist(File) IsFileExist=fso.FileExists(File) 
End Function 

Function IsDirExist(Fldr) IsDirExist=fso.FolderExists(Fldr) 
End Function 

Function LaunchEXE(EXE, Args, IsWait) 
    If (IsFileExist(EXE)) Then 
        If InStr(1, EXE, " ")>1 Then 
           LaunchEXE=WshShell.Run (Chr(34)& EXE _
              & " " & Args&Chr(34), 1, IsWait) 
        Else 
           LaunchEXE=WshShell.Run (EXE & _
                     " " & Args, 1, IsWait) 
        End If 
    Else MsgBox(EXE & " Not found.") 
        ExitScript(2) 
    End If 
End Function 

Function GetArgument(Arg,TheSwitch,Value) _
  GetArgument=False Arg=LCase(Arg):TheSwitch=LCase(TheSwitch) 
    If Mid(Arg,1,Len(TheSwitch))=TheSwitch Then 
        Value=Mid(Arg,Len(TheSwitch)+1,Len(Arg)) 
        Value=Trim(Value) GetArgument=True 
    End If 
End Function 

Function GetParameters() GetParameters=False 
    Dim Value 
    If ScriptArgs.Count >=4 Then 
        'Get operation (save or restore) 
        If GetArgument(ScriptArgs(0),"/R",Value)=True Then 
            Op="/R"
        ElseIf GetArgument(ScriptArgs(0), "/S",Value)=True Then 
            Op="/S" 
        Else GetParameters=False: Exit Function 
        End If 

        'Get Root 
        If GetArgument(ScriptArgs(1),"/H:",Value)=True Then 
            Root=Value 
        Else GetParameters=False: Exit Function 
        End If 

        'Get Key path 
        If GetArgument(ScriptArgs(2),"/K:",Value)=True Then 
            Key=Value 
        Else 
            GetParameters=False: Exit Function 
        End If 

        'Get InOutFile
        If GetArgument(ScriptArgs(3),"/P:",Value)=True Then
            InOutFile=Value 
        Else 
            GetParameters=False: Exit Function 
        End If
        GetParameters=True 

        'Get ConfigFile
        If ScriptArgs.Count=5 Then 
            If GetArgument(ScriptArgs(4),"/C:",Value)=True Then 
              ConfigFile=Value 
            End If 
        End If 
    End If 
End Function

Using the code

The program is based on a WIN32 project. It contains the following classes:

CRegSRApp (RegSR.h) Application class. I leave to the reader to extract a class not necessarily based on the application class (CRegSRApp) which can be used in any project to save/restore registry.
CMainDlg (MainDlg.h) Main dialog class shown in UI mode.
CCRC32 (CRC32.h) Used to compute files' CRC32.

The trick to be able to call save/restore functions from the dialog implementation is to use the intermediate CWinApp member theApp by which we can call the unique non-constructor application two public functions:

void SetParams(CmdParams &P, int &PNum) Set parameters from command-line or from main dialog if the program is called in UI mode.
void DoSaveRestore(DWORD &RetErr) That's the function which really does the registry save or restore job.

I invite the reader to see inside the project for details about these two functions in particular. One private function worth to be explained is the function called to check for data integrity in restore stage, that's where we ensure that the data to restore is the right data and we don't risk shattering the registry.

//    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 information 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;
}

Points of Interest

This article has shown the following facts:

  • How to provide in one project a command-line and UI tool with minimum work.
  • How to make saving registry to data file and especially restoring registry from data file very safe, by providing a registry configuration file.

In order to take more advantage of this work, we can easily extract an application-independent class to save/restore registry keys.

History

First version: August 2004.

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