/*++ Copyright (c) 2001 Microsoft Corporation Module Name: LogRegistryChanges.h Abstract: This AppVerifier shim hooks all the registry APIs that change the state of the system and logs their associated data to a text file. Notes: This is a general purpose shim. History: 08/17/2001 rparsons Created --*/ #ifndef __APPVERIFIER_LOGREGISTRYCHANGES_H_ #define __APPVERIFIER_LOGREGISTRYCHANGES_H_ #include "precomp.h" // // Length (in characters) of our initial buffer for logging data. // #define TEMP_BUFFER_SIZE 1024 // // Length (in characters) of the longest value name we expect. // #define MAX_VALUENAME_SIZE 260 // // Length (in characters) of any empty element used for key modifications. // #define KEY_ELEMENT_SIZE 64 // // Length (in characters) of an empty element used for value modifications. // #define VALUE_ELEMENT_SIZE 640 // // Length (in characters) of a predefined key handle. // #define MAX_ROOT_LENGTH 22 // // Length (in characters) of the longest data type (i.e., REG_EXPAND_SZ) // #define MAX_DATA_TYPE_LENGTH 14 // // Length (in characters) of the longest operation type (i.e., ReplaceKey) // #define MAX_OPERATION_LENGTH 11 // // Count of predefined key handles that we refer to. // #define NUM_PREDEFINED_HANDLES 7 // // Delta for memory allocations. // #define BUFFER_ALLOCATION_DELTA 1024 // // Macros for memory allocation/deallocation. // #define MemAlloc(s) RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, (s)) #define MemReAlloc(b,s) RtlReAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, (b), (s)) #define MemFree(b) RtlFreeHeap(RtlProcessHeap(), 0, (b)) // // Macro that returns TRUE if the given registry handle is predefined. // #define IsPredefinedRegistryHandle( h ) \ (( ( h == HKEY_CLASSES_ROOT ) \ || ( h == HKEY_CURRENT_USER ) \ || ( h == HKEY_LOCAL_MACHINE ) \ || ( h == HKEY_USERS ) \ || ( h == HKEY_CURRENT_CONFIG ) \ || ( h == HKEY_PERFORMANCE_DATA ) \ || ( h == HKEY_DYN_DATA )) \ ? TRUE \ : FALSE ) // // A doubly linked list of all the values associated with a particular key path. // typedef struct _KEY_DATA { LIST_ENTRY Entry; DWORD dwFlags; // flags that relate to the state of the value DWORD dwOriginalValueType; // value type of original key data DWORD dwFinalValueType; // value type of final key data WCHAR wszValueName[MAX_VALUENAME_SIZE]; // value name PVOID pOriginalData; // original key data (stored on the heap) PVOID pFinalData; // final key data (stored on the heap) DWORD cbOriginalDataSize; // original key data buffer size (in bytes) DWORD cbFinalDataSize; // final key data buffer size (in bytes) } KEY_DATA, *PKEY_DATA; // // Maximum number of key handles we can track for a single registry path. // #define MAX_NUM_HANDLES 64 // // We keep a doubly linked list of keys currently open so we know how to // resolve a key handle to a full key path. // typedef struct _LOG_OPEN_KEY { LIST_ENTRY Entry; LIST_ENTRY KeyData; // points to the data (if any) associated with this key HKEY hKeyBase[MAX_NUM_HANDLES]; // array of key handles HKEY hKeyRoot; // handle to predefined key DWORD dwFlags; // flags that relate to the state of the key LPWSTR pwszFullKeyPath; // HKEY_LOCAL_MACHINE\Software\Microsoft\Windows... LPWSTR pwszSubKeyPath; // Software\Microsoft\Windows... UINT cHandles; // number of handles open for this key path } LOG_OPEN_KEY, *PLOG_OPEN_KEY; // // Flags that indicate what state the key is in. // #define LRC_EXISTING_KEY 0x00000001 #define LRC_DELETED_KEY 0x00000002 // // Flags that indicate what state the value is in. // #define LRC_EXISTING_VALUE 0x00000001 #define LRC_DELETED_VALUE 0x00000002 #define LRC_MODIFIED_VALUE 0x00000004 // // Enumeration for updating the key information. // typedef enum { eAddKeyHandle = 0, eRemoveKeyHandle, eDeletedKey, eStartModifyValue, eEndModifyValue, eStartDeleteValue, eEndDeleteValue } UpdateType; // // The reg class that does all the real work. // class CLogRegistry { public: LONG CreateKeyExA( HKEY hKey, LPCSTR pszSubKey, DWORD Reserved, LPSTR pszClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition ); LONG CreateKeyExW( HKEY hKey, LPCWSTR pwszSubKey, DWORD Reserved, LPWSTR pwszClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition ); LONG OpenKeyExA( HKEY hKey, LPCSTR pszSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult ); LONG OpenKeyExW( HKEY hKey, LPCWSTR pwszSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult ); LONG OpenCurrentUser( REGSAM samDesired, PHKEY phkResult ); LONG OpenUserClassesRoot( HANDLE hToken, DWORD dwOptions, REGSAM samDesired, PHKEY phkResult ); LONG SetValueA( HKEY hKey, LPCSTR pszSubKey, DWORD dwType, LPCSTR pszData, DWORD cbData ); LONG SetValueW( HKEY hKey, LPCWSTR pwszSubKey, DWORD dwType, LPCWSTR lpData, DWORD cbData ); LONG SetValueExA( HKEY hKey, LPCSTR pszValueName, DWORD Reserved, DWORD dwType, CONST BYTE* lpData, DWORD cbData ); LONG SetValueExW( HKEY hKey, LPCWSTR pwszValueName, DWORD Reserved, DWORD dwType, CONST BYTE* lpData, DWORD cbData ); LONG CloseKey( HKEY hKey ); LONG DeleteKeyA( HKEY hKey, LPCSTR pszSubKey ); LONG DeleteKeyW( HKEY hKey, LPCWSTR pwszSubKey ); LONG DeleteValueA( HKEY hKey, LPCSTR pszValueName ); LONG DeleteValueW( HKEY hKey, LPCWSTR pwszValueName ); private: BOOL GetOriginalDataForKey( IN PLOG_OPEN_KEY pLogOpenKey, IN PKEY_DATA pKeyData, IN LPCWSTR pwszValueName ); BOOL GetFinalDataForKey( IN PLOG_OPEN_KEY pLogOpenKey, IN PKEY_DATA pKeyData, IN LPCWSTR pwszValueName ); PLOG_OPEN_KEY AddSpecialKeyHandleToList( IN HKEY hKeyRoot, IN HKEY hKeyNew ); PKEY_DATA AddValueNameToList( IN PLOG_OPEN_KEY pLogOpenKey, IN LPCWSTR pwszValueName ); HKEY ForceSubKeyIntoList( IN HKEY hKeyPredefined, IN LPCWSTR pwszSubKey ); PKEY_DATA FindValueNameInList( IN LPCWSTR pwszValueName, IN PLOG_OPEN_KEY pOpenKey ); PLOG_OPEN_KEY FindKeyPathInList( IN LPCWSTR pwszKeyPath ); PLOG_OPEN_KEY RemoveKeyHandleFromArray( IN HKEY hKey ); PLOG_OPEN_KEY FindKeyHandleInArray( IN HKEY hKey ); PLOG_OPEN_KEY AddKeyHandleToList( IN HKEY hKey, IN HKEY hKeyNew, IN LPCWSTR pwszSubKeyPath, IN BOOL fExisting ); PLOG_OPEN_KEY UpdateKeyList( IN HKEY hKeyRoot, IN HKEY hKeyNew, IN LPCWSTR pwszSubKey, IN LPCWSTR pwszValueName, IN BOOL fExisting, IN UpdateType eType ); }; // // Keep us safe while we're playing with linked lists and shared resources. // static BOOL g_bInitialized = FALSE; CRITICAL_SECTION g_csLogging; class CLock { public: CLock() { if (!g_bInitialized) { InitializeCriticalSection(&g_csLogging); g_bInitialized = TRUE; } EnterCriticalSection(&g_csLogging); } ~CLock() { LeaveCriticalSection(&g_csLogging); } }; APIHOOK_ENUM_BEGIN APIHOOK_ENUM_ENTRY(RegOpenKeyA) APIHOOK_ENUM_ENTRY(RegOpenKeyW) APIHOOK_ENUM_ENTRY(RegOpenKeyExA) APIHOOK_ENUM_ENTRY(RegOpenKeyExW) APIHOOK_ENUM_ENTRY(RegOpenCurrentUser) APIHOOK_ENUM_ENTRY(RegOpenUserClassesRoot) APIHOOK_ENUM_ENTRY(RegCreateKeyA) APIHOOK_ENUM_ENTRY(RegCreateKeyW) APIHOOK_ENUM_ENTRY(RegCreateKeyExA) APIHOOK_ENUM_ENTRY(RegCreateKeyExW) APIHOOK_ENUM_ENTRY(RegCloseKey) APIHOOK_ENUM_ENTRY(RegQueryValueA) APIHOOK_ENUM_ENTRY(RegQueryValueW) APIHOOK_ENUM_ENTRY(RegQueryValueExA) APIHOOK_ENUM_ENTRY(RegQueryValueExW) APIHOOK_ENUM_ENTRY(RegQueryInfoKeyA) APIHOOK_ENUM_ENTRY(RegQueryInfoKeyW) APIHOOK_ENUM_ENTRY(RegSetValueA) APIHOOK_ENUM_ENTRY(RegSetValueW) APIHOOK_ENUM_ENTRY(RegSetValueExA) APIHOOK_ENUM_ENTRY(RegSetValueExW) APIHOOK_ENUM_ENTRY(RegDeleteKeyA) APIHOOK_ENUM_ENTRY(RegDeleteKeyW) APIHOOK_ENUM_ENTRY(RegDeleteValueA) APIHOOK_ENUM_ENTRY(RegDeleteValueW) APIHOOK_ENUM_ENTRY(WriteProfileStringA) APIHOOK_ENUM_ENTRY(WriteProfileStringW) APIHOOK_ENUM_ENTRY(WriteProfileSectionA) APIHOOK_ENUM_ENTRY(WriteProfileSectionW) APIHOOK_ENUM_END #endif // __APPVERIFIER_LOGREGISTRYCHANGES_H_