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.
328 lines
7.5 KiB
328 lines
7.5 KiB
#include "precomp.h"
|
|
#include "RegAnalyzer.h"
|
|
#include "RegDiffFile.h"
|
|
|
|
#include <process.h>
|
|
|
|
HREGANL
|
|
CreateRegAnalyzer (
|
|
VOID
|
|
)
|
|
{
|
|
HREGANL regAnalyzer = (HREGANL) new CRegAnalyzer;
|
|
return regAnalyzer;
|
|
}
|
|
|
|
BOOL
|
|
CloseRegAnalyzer (
|
|
IN HREGANL RegAnalyzer
|
|
)
|
|
{
|
|
delete (CRegAnalyzer*) RegAnalyzer;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
AddRegistryKey (
|
|
IN HREGANL RegAnalyzer,
|
|
IN PCTSTR RootKeyName,
|
|
IN PCTSTR SubKeyName
|
|
)
|
|
{
|
|
CRegAnalyzer* pRA = (CRegAnalyzer*)RegAnalyzer;
|
|
return pRA->AddKey(RootKeyName, SubKeyName);
|
|
}
|
|
|
|
BOOL
|
|
ExcludeRegistryKey (
|
|
IN HREGANL RegAnalyzer,
|
|
IN PCTSTR RootKeyName,
|
|
IN PCTSTR SubKeyName
|
|
)
|
|
{
|
|
CRegAnalyzer* pRA = (CRegAnalyzer*)RegAnalyzer;
|
|
return pRA->AddKey(RootKeyName, SubKeyName, true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct TakeSnapshotParams
|
|
{
|
|
HREGANL RegAnalyzer;
|
|
PCTSTR SnapshotFile;
|
|
PFNSNAPSHOTPROGRESS ProgressCallback;
|
|
PVOID Context;
|
|
DWORD MaxLevel;
|
|
HANDLE hEvent;
|
|
};
|
|
|
|
|
|
void __cdecl TakeSnapshotThread(void* pParams)
|
|
{
|
|
TakeSnapshotParams* pp = (TakeSnapshotParams*)pParams;
|
|
|
|
if (pp != NULL)
|
|
{
|
|
CRegAnalyzer* pRA = (CRegAnalyzer*)pp->RegAnalyzer;
|
|
|
|
pRA->SaveKeysToFile(pp->SnapshotFile, pp->ProgressCallback, pp->Context, pp->MaxLevel);
|
|
|
|
SetEvent(pp->hEvent);
|
|
|
|
delete pp;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TakeSnapshot (
|
|
IN HREGANL RegAnalyzer,
|
|
IN PCTSTR SnapshotFile,
|
|
IN PFNSNAPSHOTPROGRESS ProgressCallback,
|
|
IN PVOID Context,
|
|
IN DWORD MaxLevel,
|
|
IN HANDLE hEvent
|
|
)
|
|
{
|
|
CRegAnalyzer* pRA = (CRegAnalyzer*)RegAnalyzer;
|
|
|
|
if (hEvent == NULL)
|
|
return pRA->SaveKeysToFile(SnapshotFile, ProgressCallback, Context, MaxLevel);
|
|
else
|
|
{
|
|
TakeSnapshotParams* pParams = new TakeSnapshotParams;
|
|
|
|
if (pParams != NULL)
|
|
{
|
|
pParams->RegAnalyzer=RegAnalyzer;
|
|
pParams->SnapshotFile=SnapshotFile;
|
|
pParams->ProgressCallback=ProgressCallback;
|
|
pParams->Context=Context;
|
|
pParams->MaxLevel=MaxLevel;
|
|
pParams->hEvent=hEvent;
|
|
|
|
_beginthread(TakeSnapshotThread, 0, (void*)pParams);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct ComputeDifferencesParams
|
|
{
|
|
HREGANL RegAnalyzer;
|
|
PCTSTR Snapshot1;
|
|
PCTSTR Snapshot2;
|
|
PCTSTR DiffFile;
|
|
HANDLE hEvent;
|
|
};
|
|
|
|
|
|
void __cdecl ComputeDifferencesThread(void* pParams)
|
|
{
|
|
ComputeDifferencesParams* pp = (ComputeDifferencesParams*)pParams;
|
|
|
|
if (pp != NULL)
|
|
{
|
|
CRegAnalyzer* pRA = (CRegAnalyzer*)pp->RegAnalyzer;
|
|
|
|
pRA->ComputeDifferences1(pp->Snapshot1, pp->Snapshot2, pp->DiffFile);
|
|
|
|
SetEvent(pp->hEvent);
|
|
|
|
delete pp;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ComputeDifferences (
|
|
IN HREGANL RegAnalyzer,
|
|
IN PCTSTR Snapshot1,
|
|
IN PCTSTR Snapshot2,
|
|
IN PCTSTR DiffFile,
|
|
IN HANDLE hEvent
|
|
)
|
|
{
|
|
CRegAnalyzer* pRA = (CRegAnalyzer*)RegAnalyzer;
|
|
//
|
|
// BUGBUG - ISSUE - what about security settings associated with each registry key?
|
|
//
|
|
if (hEvent == NULL)
|
|
return pRA->ComputeDifferences1(Snapshot1, Snapshot2, DiffFile);
|
|
else
|
|
{
|
|
ComputeDifferencesParams* pParams = new ComputeDifferencesParams;
|
|
|
|
if (pParams != NULL)
|
|
{
|
|
pParams->RegAnalyzer=RegAnalyzer;
|
|
pParams->Snapshot1=Snapshot1;
|
|
pParams->Snapshot2=Snapshot2;
|
|
pParams->DiffFile=DiffFile;
|
|
pParams->hEvent=hEvent;
|
|
|
|
_beginthread(ComputeDifferencesThread, 0, (void*)pParams);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
BOOL
|
|
InstallDifferences (
|
|
IN PCTSTR DiffFile,
|
|
IN PCTSTR UndoFile
|
|
)
|
|
{
|
|
CRegDiffFile diff;
|
|
if (!diff.Init(DiffFile, TRUE)) {
|
|
return FALSE;
|
|
}
|
|
return diff.ApplyToRegistry(UndoFile);
|
|
}
|
|
|
|
BOOL
|
|
CountRegSubkeysInternal (
|
|
IN HKEY RootKey,
|
|
IN PCTSTR SubKey,
|
|
IN DWORD MaxLevels,
|
|
OUT PDWORD Nodes
|
|
)
|
|
{
|
|
MYASSERT (MaxLevels > 0);
|
|
|
|
HKEY parentKey;
|
|
DWORD rc = RegOpenKeyEx (RootKey, SubKey, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &parentKey);
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
LOG3 (LOG_ERROR, "Failed to open reg subkey (%x,%s) (rc=%u)", RootKey, SubKey, rc);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL b = FALSE;
|
|
|
|
PTSTR subKeyBuffer = NULL;
|
|
|
|
__try {
|
|
|
|
DWORD subKeys;
|
|
DWORD subKeyMaxLen;
|
|
rc = RegQueryInfoKey (parentKey, NULL, NULL, NULL, &subKeys, &subKeyMaxLen, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
LOG3 (LOG_ERROR, "Failed to query reg subkey (%x,%s) (rc=%u)", RootKey, SubKey, rc);
|
|
__leave;
|
|
}
|
|
subKeyMaxLen++;
|
|
subKeyBuffer = new TCHAR[subKeyMaxLen];
|
|
if (!subKeyBuffer) {
|
|
OOM();
|
|
__leave;
|
|
}
|
|
|
|
if (MaxLevels > 1) {
|
|
|
|
for (DWORD index = 0; index < subKeys; index++) {
|
|
DWORD len = subKeyMaxLen;
|
|
rc = RegEnumKeyEx (parentKey, index, subKeyBuffer, &len, NULL, NULL, NULL, NULL);
|
|
if (rc == ERROR_NO_MORE_ITEMS) {
|
|
break;
|
|
}
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
LOG4 (LOG_ERROR, "Failed to enum reg subkey (%x,%s) at index %u (rc=%u)", RootKey, SubKey, index, rc);
|
|
__leave;
|
|
}
|
|
if (!CountRegSubkeysInternal (parentKey, subKeyBuffer, MaxLevels - 1, Nodes)) {
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
|
|
*Nodes += subKeys;
|
|
|
|
delete []subKeyBuffer;
|
|
subKeyBuffer = NULL;
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
if (!b) {
|
|
rc = GetLastError ();
|
|
}
|
|
if (subKeyBuffer) {
|
|
delete []subKeyBuffer;
|
|
}
|
|
RegCloseKey (parentKey);
|
|
if (!b) {
|
|
SetLastError (rc);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
CountRegSubkeys (
|
|
IN PCTSTR Root,
|
|
IN PCTSTR SubKey,
|
|
IN DWORD MaxLevels,
|
|
OUT PDWORD Nodes
|
|
)
|
|
{
|
|
HKEY rootKey = GetRootKey (Root);
|
|
if (!rootKey) {
|
|
LOG1 (LOG_ERROR, "Invalid root key (%s)", Root);
|
|
return FALSE;
|
|
}
|
|
HKEY parentKey;
|
|
DWORD rc = RegOpenKeyEx (rootKey, SubKey, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &parentKey);
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
LOG3 (LOG_ERROR, "Failed to open reg key (%s\\%s) (rc=%u)", Root, SubKey, rc);
|
|
return FALSE;
|
|
}
|
|
RegCloseKey (parentKey);
|
|
|
|
*Nodes = 1; // the root itself
|
|
return MaxLevels ? CountRegSubkeysInternal (rootKey, SubKey, MaxLevels, Nodes) : TRUE;
|
|
}
|
|
|
|
HKEY
|
|
GetRootKey (
|
|
IN PCTSTR RootStr
|
|
)
|
|
{
|
|
static struct {
|
|
PCTSTR RootStr;
|
|
HKEY RootKey;
|
|
} map[] = {
|
|
{ TEXT("HKLM"), HKEY_LOCAL_MACHINE },
|
|
{ TEXT("HKCU"), HKEY_CURRENT_USER },
|
|
{ TEXT("HKCR"), HKEY_CLASSES_ROOT },
|
|
{ TEXT("HKU"), HKEY_USERS },
|
|
{ TEXT("HKCC"), HKEY_CURRENT_CONFIG },
|
|
{ NULL, 0 }
|
|
}, *entry;
|
|
|
|
for (entry = map; entry->RootStr; entry++) {
|
|
if (_tcsicmp (RootStr, entry->RootStr) == 0) {
|
|
return entry->RootKey;
|
|
}
|
|
}
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|