mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
490 lines
15 KiB
490 lines
15 KiB
/*
|
|
|
|
regback.c - registry backup program
|
|
|
|
this program allows the user to back up active registry hives,
|
|
while the system is running.
|
|
|
|
a user with a tape drive should use ntbackup instead.
|
|
|
|
regrest is used to restore these backups. do NOT use the Restore
|
|
command in regedit, that actually does something else.
|
|
|
|
this program does some doofy looking stuff to ensure that
|
|
RegSaveKey is applied only to the root of a hive, this prevents
|
|
creating a backup file that cannot be used later. don't copy this
|
|
code into things other than a backup program.
|
|
|
|
basic structure:
|
|
|
|
DoFullBackup ennumerate entries in HiveList, computes which
|
|
ones to save and where, and calls DoSpecificBackup.
|
|
|
|
Two argument case of app is just a call to DoSpecificBackup.
|
|
|
|
All real work done by RegSaveKey()
|
|
|
|
*/
|
|
#undef _UNICODE
|
|
#undef UNICODE
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <direct.h>
|
|
#include <conio.h>
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <process.h>
|
|
|
|
char *UsageMessage[] = {
|
|
"Regback allows you to back up pieces of the registry, known as hives, ",
|
|
"while the system is running and has them open. ",
|
|
" ",
|
|
"SeBackupPrivilege is required to make use of this program. ",
|
|
" ",
|
|
"Will fail if the hives don't all fit on the target device, so often ",
|
|
"best to back up to a harddisk and then use backup.exe or the like ",
|
|
"to write to floppy. ",
|
|
" ",
|
|
"Does NOT copy the files in config which are not open by the registry. ",
|
|
"Use xcopy or the like for the inactive hives. ",
|
|
" ",
|
|
"Will NOT overwrite existing files, but will report an error. ",
|
|
" ",
|
|
"Use Regrest if you ever need to use the backed up version of a hive. ",
|
|
" ",
|
|
"Error exit will be 0 if success, 1 if hive that requires manual backup ",
|
|
"was encountered, 2 for all other errors. ",
|
|
"Notes to do manual backups on stdout. ",
|
|
"Error messages on stderr. ",
|
|
" ",
|
|
"If you have a tape drive, use NtBackup instead. ",
|
|
" ",
|
|
"regback ",
|
|
" Print this help screen. ",
|
|
" ",
|
|
"regback <directory argument> ",
|
|
" Back up all of the registry hives, whose files reside in the config ",
|
|
" directory, to the named directory. (This is normally all hives.) ",
|
|
" Warn of hives that must be backed up manually, or of errors. ",
|
|
" (Use form below for \"manual\" backup) ",
|
|
" ",
|
|
" regback c:\\monday.bku ",
|
|
" if ERRORLEVEL 1 echo Error! ",
|
|
" ",
|
|
"regback <filename> <hivetype> <hivename> ",
|
|
" Back up the named hive to the named file. Will fail if the ",
|
|
" hiventype isn't \"machine\" or \"users\" or hivename isn't a hive root.",
|
|
" ",
|
|
" Hive type is either \"machine\" or \"users\". Hivename is the name of ",
|
|
" an immediate subtree of HKEY_LOCAL_MACHINE or HKEY_LOCAL_USERS. ",
|
|
" ",
|
|
" regback c:\\special.sav\\system machine system ",
|
|
" regback c:\\savedir\\prof users s-1-0000-0000-1234 ",
|
|
" if ERRORLEVEL 1 echo Error! ",
|
|
" ",
|
|
"regback | more - to see help 1 screen at a time ",
|
|
NULL
|
|
};
|
|
|
|
#define MACH_NAME "machine"
|
|
#define USERS_NAME "users"
|
|
|
|
#define BUF_SIZE (32 * 1024) -1
|
|
#define MAX_KEY 512
|
|
|
|
char ConfigPath[BUF_SIZE];
|
|
char ProfilePath[BUF_SIZE];
|
|
char HivePath[BUF_SIZE];
|
|
char HiveName[BUF_SIZE];
|
|
char FilePath[BUF_SIZE];
|
|
|
|
void usage();
|
|
|
|
void
|
|
AdjustPrivilege();
|
|
|
|
int
|
|
DoFullBackup(
|
|
char *dirname
|
|
);
|
|
|
|
int
|
|
DoSpecificBackup(
|
|
char *filepath,
|
|
char *hivebranch,
|
|
char *hivename
|
|
);
|
|
|
|
|
|
void
|
|
_CRTAPI1 main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
int result;
|
|
|
|
if (argc == 2) {
|
|
|
|
AdjustPrivilege();
|
|
result = DoFullBackup(argv[1]);
|
|
exit(result);
|
|
|
|
} else if (argc == 4) {
|
|
|
|
AdjustPrivilege();
|
|
result = DoSpecificBackup(argv[1], argv[2], argv[3]);
|
|
exit(result);
|
|
|
|
} else {
|
|
|
|
usage();
|
|
exit(2);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
usage()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; UsageMessage[i] != NULL; i++) {
|
|
printf("%s\n", UsageMessage[i]);
|
|
|
|
}
|
|
exit(2);
|
|
}
|
|
|
|
|
|
int
|
|
DoFullBackup(
|
|
char *dirname
|
|
)
|
|
/*
|
|
Scan the hivelist, for each hive which has a file (i.e. not hardware)
|
|
if the file is in the config dir (e.g. not some remote profile) call
|
|
DoSpecificBackup to save the hive out.
|
|
*/
|
|
{
|
|
HKEY HiveListKey;
|
|
DWORD result = 0;
|
|
DWORD ValueType;
|
|
DWORD BufferSize;
|
|
DWORD BufferSize2;
|
|
DWORD index;
|
|
char *branch;
|
|
char *wp;
|
|
int status = 0;
|
|
char *filename;
|
|
char *name;
|
|
|
|
//
|
|
// get handle to hivelist key
|
|
//
|
|
result = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
"System\\CurrentControlSet\\Control\\hivelist",
|
|
0L,
|
|
KEY_READ,
|
|
&HiveListKey
|
|
);
|
|
if (result != ERROR_SUCCESS) {
|
|
fprintf(stderr, "Failed to open hivelist, result = 0x%08lx\n", result);
|
|
return(2);
|
|
}
|
|
|
|
//
|
|
// get path data for system hive, which will allow us to compute
|
|
// path name to config dir in form that hivelist uses.
|
|
// (an NT internal form of path) this is NOT the way the path to
|
|
// the config directory should generally be computed.
|
|
//
|
|
BufferSize = BUF_SIZE;
|
|
result = RegQueryValueEx(
|
|
HiveListKey,
|
|
"\\registry\\machine\\system",
|
|
0L,
|
|
&ValueType,
|
|
ConfigPath,
|
|
&BufferSize
|
|
);
|
|
if (result != ERROR_SUCCESS) {
|
|
fprintf(stderr, "Failed to query 'system' result = 0x%08lx\n", result);
|
|
return(2);
|
|
}
|
|
|
|
wp = strrchr(ConfigPath, L'\\');
|
|
*wp = '\0';
|
|
|
|
strcpy(ProfilePath, ConfigPath);
|
|
wp = strrchr(ProfilePath, L'\\');
|
|
*wp = '\0';
|
|
wp = strrchr(ProfilePath, L'\\');
|
|
*wp = '\0';
|
|
strcpy(wp+1, "Profiles");
|
|
|
|
//
|
|
// ennumerate entries in hivelist. for each entry, find it's hive file
|
|
// path. if it's file path matches ConfigPath, then save it.
|
|
// else, print a message telling the user that it must be saved
|
|
// manually, unless the file name is of the form ....\username\ntuser.dat
|
|
// in which case save it as username.dat
|
|
//
|
|
for (index = 0; TRUE; index++) {
|
|
|
|
BufferSize = BUF_SIZE;
|
|
BufferSize2 = BUF_SIZE;
|
|
result = RegEnumValue(
|
|
HiveListKey,
|
|
index,
|
|
HiveName,
|
|
&BufferSize2,
|
|
0L,
|
|
&ValueType,
|
|
HivePath,
|
|
&BufferSize
|
|
);
|
|
|
|
if (result == ERROR_NO_MORE_ITEMS) {
|
|
return status; // we are done
|
|
}
|
|
|
|
if (result != ERROR_SUCCESS) {
|
|
fprintf(stderr, "Error in enum = 0x%08lx", result);
|
|
return 2;
|
|
}
|
|
|
|
BufferSize = strlen(HivePath);
|
|
|
|
/*
|
|
printf("hivename = '%s'\n", HiveName);
|
|
printf("hivepath = '%ws'\n", HivePath);
|
|
printf("buffersize = %d\n", BufferSize);
|
|
printf("buffersize = %d\n", BufferSize);
|
|
*/
|
|
|
|
if (BufferSize != 0) {
|
|
|
|
//
|
|
// there's a file, compute it's path, hive branch, etc
|
|
//
|
|
|
|
wp = strrchr(HivePath, '\\');
|
|
filename = wp + 1;
|
|
*wp = '\0';
|
|
|
|
wp = strrchr(HiveName, '\\');
|
|
name = wp + 1;
|
|
*wp = '\0';
|
|
|
|
wp = strrchr(HiveName, L'\\');
|
|
wp++;
|
|
if ((*wp == 'm') || (*wp == 'M')) {
|
|
branch = MACH_NAME;
|
|
} else {
|
|
branch = USERS_NAME;
|
|
}
|
|
|
|
if (strcmp(ConfigPath, HivePath) == 0) {
|
|
|
|
//
|
|
// hive's file is in config dir, we can back it up
|
|
// without fear of collision
|
|
//
|
|
FilePath[0] = '\0';
|
|
strcat(FilePath, dirname);
|
|
strcat(FilePath, "\\");
|
|
strcat(FilePath, filename);
|
|
|
|
|
|
/*
|
|
printf("name (hivename) = '%s'\n", name);
|
|
printf("branch = '%s'\n", branch);
|
|
printf("FilePath = '%s'\n", &FilePath);
|
|
*/
|
|
|
|
result = DoSpecificBackup(
|
|
FilePath,
|
|
branch,
|
|
name
|
|
);
|
|
|
|
if (result != 0) {
|
|
return(result);
|
|
}
|
|
|
|
} else if (_strnicmp(ProfilePath, HivePath, strlen(ProfilePath)) == 0) {
|
|
|
|
//
|
|
// hive's file is in config dir, we can back it up
|
|
// without fear of collision
|
|
//
|
|
FilePath[0] = '\0';
|
|
strcat(FilePath, dirname);
|
|
strcat(FilePath, "\\");
|
|
wp = strrchr(HivePath, '\\');
|
|
filename = wp + 1;
|
|
strcat(FilePath, filename);
|
|
strcat(FilePath, ".dat");
|
|
|
|
/*
|
|
printf("name (hivename) = '%s'\n", name);
|
|
printf("branch = '%s'\n", branch);
|
|
printf("FilePath = '%s'\n", &FilePath);
|
|
*/
|
|
|
|
result = DoSpecificBackup(
|
|
FilePath,
|
|
branch,
|
|
name
|
|
);
|
|
|
|
if (result != 0) {
|
|
return(result);
|
|
}
|
|
} else {
|
|
status = 1;
|
|
|
|
printf("\n***Hive = '%s'\\'%s'\nStored in file '%s'\\'%s'\n",
|
|
HiveName, name, HivePath, filename);
|
|
printf("Must be backed up manually\n");
|
|
printf("regback <filename you choose> %s %s\n\n",
|
|
branch, name);
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
int
|
|
DoSpecificBackup(
|
|
char *filepath,
|
|
char *hivebranch,
|
|
char *hivename
|
|
)
|
|
/*
|
|
Do backup of one hive to one file. Any valid hive and any
|
|
valid file will do. RegSaveKey does all the real work.
|
|
|
|
Arguments:
|
|
filepath - file name to pass directly to OS
|
|
|
|
hivebranch - machine -> hkey_local_machine,
|
|
users -> hkey_users,
|
|
else -> error
|
|
|
|
hivename - 1st level subkey under machine or users
|
|
*/
|
|
{
|
|
HKEY RootKey;
|
|
HKEY HiveKey;
|
|
DWORD result;
|
|
|
|
//
|
|
// compute/check out branch and name of hive
|
|
//
|
|
if (_stricmp(hivebranch, MACH_NAME) == 0) {
|
|
RootKey = HKEY_LOCAL_MACHINE;
|
|
} else if (_stricmp(hivebranch, USERS_NAME) == 0) {
|
|
RootKey = HKEY_USERS;
|
|
} else {
|
|
printf("bad hive branch type '%s'\n", hivebranch);
|
|
return(2);
|
|
}
|
|
|
|
if (strchr(hivename, '\\') != NULL) {
|
|
printf("'%s' is not a hive name\n", hivename);
|
|
return(2);
|
|
}
|
|
|
|
//
|
|
// print some status
|
|
//
|
|
printf("saving %s to %s\n", hivename, filepath);
|
|
|
|
//
|
|
// get a handle to the hive. use special create call what will
|
|
// use privileges
|
|
//
|
|
result = RegCreateKeyEx(RootKey, hivename, 0L, NULL,
|
|
REG_OPTION_BACKUP_RESTORE,
|
|
KEY_READ, NULL, &HiveKey, NULL);
|
|
if (result != ERROR_SUCCESS) {
|
|
printf("open of hivebranch='%s', hive='%s' failed result='0x%08lx'\n",
|
|
hivebranch, hivename, result);
|
|
return(2);
|
|
}
|
|
|
|
result = RegSaveKey(HiveKey, filepath, NULL);
|
|
if (result != ERROR_SUCCESS) {
|
|
printf("Save failed\n");
|
|
printf("hivebranch='%s', hive='%s', result='0x%08lx'\nfile='%s'\n",
|
|
hivebranch, hivename, result, filepath);
|
|
RegCloseKey(HiveKey);
|
|
return(2);
|
|
}
|
|
|
|
RegCloseKey(HiveKey);
|
|
return(0);
|
|
}
|
|
|
|
|
|
void
|
|
AdjustPrivilege()
|
|
/*
|
|
|
|
Attempt to assert SeBackupPrivilege. Print message and
|
|
exit if we fail.
|
|
|
|
*/
|
|
{
|
|
HANDLE TokenHandle;
|
|
LUID_AND_ATTRIBUTES LuidAndAttributes;
|
|
|
|
TOKEN_PRIVILEGES TokenPrivileges;
|
|
PTSTR Privilege = SE_BACKUP_NAME;
|
|
|
|
|
|
if( !OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&TokenHandle ) ) {
|
|
printf("OpenProcessToken failed\n" );
|
|
printf("Could not obtain needed privilege\n");
|
|
exit(2);
|
|
}
|
|
|
|
|
|
if( !LookupPrivilegeValue( NULL,
|
|
Privilege, // (LPWSTR)SE_SECURITY_NAME,
|
|
&( LuidAndAttributes.Luid ) ) ) {
|
|
printf("LookupPrivilegeValue failed, Error = %#d \n", GetLastError());
|
|
printf("Could not obtain needed privilege\n");
|
|
exit(2);
|
|
}
|
|
|
|
LuidAndAttributes.Attributes = SE_PRIVILEGE_ENABLED;
|
|
TokenPrivileges.PrivilegeCount = 1;
|
|
TokenPrivileges.Privileges[0] = LuidAndAttributes;
|
|
|
|
if( !AdjustTokenPrivileges( TokenHandle,
|
|
FALSE,
|
|
&TokenPrivileges,
|
|
0,
|
|
NULL,
|
|
NULL ) ) {
|
|
printf("AdjustTokenPrivileges failed, Error = %#x \n", GetLastError());
|
|
printf("Could not obtain needed privilege\n");
|
|
exit(2);
|
|
}
|
|
|
|
if( GetLastError() != NO_ERROR ) {
|
|
printf("Could not obtain needed privilege\n");
|
|
exit(2);
|
|
}
|
|
return;
|
|
}
|