/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: RegistryChecks.cpp Abstract: Warn the app when it's trying to read from or write to inappropriate places in the registry. Notes: This is a general purpose shim. History: 03/09/2001 maonis Created 09/04/2001 maonis Since none of the paths we compare with exceed MAX_PATH - 1 characters, we only examine at most that many characters of the key paths to make sure there's no buffer overflow in the paths of open keys. 02/20/2002 rparsons Implemented strsafe functions. 02/25/2002 rparsons Modified critical section code to be thread safe. --*/ #include "precomp.h" IMPLEMENT_SHIM_BEGIN(RegistryChecks) #include "ShimHookMacro.h" #include "RegistryChecks.h" // // verifier log entries // BEGIN_DEFINE_VERIFIER_LOG(RegistryChecks) VERIFIER_LOG_ENTRY(VLOG_HKCU_Console_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_ControlPanel_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_Environment_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_Identities_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_KeyboardLayout_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_Printers_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_RemoteAccess_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_SessionInformation_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_UNICODEProgramGroups_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_VolatileEnvironment_READ) VERIFIER_LOG_ENTRY(VLOG_HKCU_Windows31MigrationStatus_READ) VERIFIER_LOG_ENTRY(VLOG_HKLM_HARDWARE_READ) VERIFIER_LOG_ENTRY(VLOG_HKLM_SAM_READ) VERIFIER_LOG_ENTRY(VLOG_HKLM_SECURITY_READ) VERIFIER_LOG_ENTRY(VLOG_HKLM_SYSTEM_READ) VERIFIER_LOG_ENTRY(VLOG_HKCC_READ) VERIFIER_LOG_ENTRY(VLOG_HKUS_READ) VERIFIER_LOG_ENTRY(VLOG_NON_HKCU_WRITE) END_DEFINE_VERIFIER_LOG(RegistryChecks) INIT_VERIFIER_LOG(RegistryChecks); const RCWARNING g_warnNoDirectRead[] = { {HKCU_Console_STR, VLOG_HKCU_Console_READ, NUM_OF_CHAR(HKCU_Console_STR)}, {HKCU_ControlPanel_STR, VLOG_HKCU_ControlPanel_READ, NUM_OF_CHAR(HKCU_ControlPanel_STR)}, {HKCU_Environment_STR, VLOG_HKCU_Environment_READ, NUM_OF_CHAR(HKCU_Environment_STR)}, {HKCU_Identities_STR, VLOG_HKCU_Identities_READ, NUM_OF_CHAR(HKCU_Identities_STR)}, {HKCU_KeyboardLayout_STR, VLOG_HKCU_KeyboardLayout_READ, NUM_OF_CHAR(HKCU_KeyboardLayout_STR)}, {HKCU_Printers_STR, VLOG_HKCU_Printers_READ, NUM_OF_CHAR(HKCU_Printers_STR)}, {HKCU_RemoteAccess_STR, VLOG_HKCU_RemoteAccess_READ, NUM_OF_CHAR(HKCU_RemoteAccess_STR)}, {HKCU_SessionInformation_STR, VLOG_HKCU_SessionInformation_READ, NUM_OF_CHAR(HKCU_SessionInformation_STR)}, {HKCU_UNICODEProgramGroups_STR, VLOG_HKCU_UNICODEProgramGroups_READ, NUM_OF_CHAR(HKCU_UNICODEProgramGroups_STR)}, {HKCU_VolatileEnvironment_STR, VLOG_HKCU_VolatileEnvironment_READ, NUM_OF_CHAR(HKCU_VolatileEnvironment_STR)}, {HKCU_Windows31MigrationStatus_STR, VLOG_HKCU_Windows31MigrationStatus_READ,NUM_OF_CHAR(HKCU_Windows31MigrationStatus_STR)}, {HKLM_HARDWARE_STR, VLOG_HKLM_HARDWARE_READ, NUM_OF_CHAR(HKLM_HARDWARE_STR)}, {HKLM_SAM_STR, VLOG_HKLM_SAM_READ, NUM_OF_CHAR(HKLM_SAM_STR)}, {HKLM_SECURITY_STR, VLOG_HKLM_SECURITY_READ, NUM_OF_CHAR(HKLM_SECURITY_STR)}, {HKLM_SYSTEM_STR, VLOG_HKLM_SYSTEM_READ, NUM_OF_CHAR(HKLM_SYSTEM_STR)}, {HKCC_STR, VLOG_HKCC_READ, NUM_OF_CHAR(HKCC_STR)}, {HKUS_STR, VLOG_HKUS_READ, NUM_OF_CHAR(HKUS_STR)}, }; const UINT g_cWarnNDirectRead = sizeof(g_warnNoDirectRead) / sizeof(RCWARNING); // // Critical section that keeps us safe while using linked-lists, etc. // CCriticalSection g_csCritSec; VOID MakePathW( IN RCOPENKEY* key, IN HKEY hKey, IN LPCWSTR lpSubKey, IN OUT LPWSTR lpPath ) { if (key) { if (key->wszPath[0]) { // // We only care about at most MAX_PATH - 1 characters. // wcsncpy(lpPath, key->wszPath, MAX_PATH - 1); } } else { if (hKey == HKEY_CLASSES_ROOT) { StringCchCopy(lpPath, MAX_PATH - 1, L"HKCR"); } else if (hKey == HKEY_CURRENT_CONFIG) { StringCchCopy(lpPath, MAX_PATH - 1, L"HKCC"); } else if (hKey == HKEY_CURRENT_USER) { StringCchCopy(lpPath, MAX_PATH - 1, L"HKCU"); } else if (hKey == HKEY_LOCAL_MACHINE) { StringCchCopy(lpPath, MAX_PATH - 1, L"HKLM"); } else if (hKey == HKEY_USERS) { StringCchCopy(lpPath, MAX_PATH - 1, L"HKUS"); } else { StringCchCopy(lpPath, MAX_PATH - 1, L"Not recongized"); } } if (lpSubKey && *lpSubKey) { DWORD cLen = wcslen(lpPath); // // We only care about at most MAX_PATH - 1 characters. // if (cLen < MAX_PATH - 1) { lpPath[cLen] = L'\\'; wcsncpy(lpPath + cLen + 1, lpSubKey, MAX_PATH - cLen - 2); } } lpPath[MAX_PATH - 1] = L'\0'; } VOID CheckReading( IN LPCWSTR pwszPath ) { RCWARNING warn; for (UINT ui = 0; ui < g_cWarnNDirectRead; ++ui) { warn = g_warnNoDirectRead[ui]; if (!_wcsnicmp(pwszPath, warn.wszPath, warn.cLen)) { VLOG(VLOG_LEVEL_ERROR, warn.dwAVStatus, "Read from dangerous registry entry '%ls'.", pwszPath); } } } // We warn for every tempt of writing to anything besides keys under HKCU. // Note this applies to both Users and Admins/Power Users because when an // app is running it shouldn't write anything to non HKCU keys, which should // be done during the installation time. VOID CheckWriting( IN REGSAM samDesired, IN LPCWSTR pwszPath ) { if ((samDesired &~ STANDARD_RIGHTS_WRITE) & KEY_WRITE) { if (_wcsnicmp(pwszPath, L"HKCU", 4)) { VLOG(VLOG_LEVEL_ERROR, VLOG_NON_HKCU_WRITE, "Write to non-HKCU registry entry '%ls'.", pwszPath); } } } // // Implementation of the CRegistryChecks class. // RCOPENKEY* CRegistryChecks::FindKey( HKEY hKey ) { RCOPENKEY* key = keys; while (key) { if (key->hkBase == hKey) { return key; } key = key->next; } return NULL; } // We add the key to the front of the list because the most // recently added keys are usually used/deleted first. BOOL CRegistryChecks::AddKey( HKEY hKey, LPCWSTR pwszPath ) { RCOPENKEY* key = new RCOPENKEY; if (!key) { return FALSE; } key->hkBase = hKey; // // None of the key paths we need to check exceed MAX_PATH - 1 characters so // we only need to copy at most that many characters. // wcsncpy(key->wszPath, pwszPath, MAX_PATH - 1); key->wszPath[MAX_PATH - 1] = L'\0'; key->next = keys; keys = key; return TRUE; } VOID CRegistryChecks::Check( HKEY hKey, LPCSTR lpSubKey, BOOL fCheckRead, BOOL fCheckWrite, REGSAM samDesired ) { LPWSTR pwszSubKey = NULL; if (pwszSubKey = ToUnicode(lpSubKey)) { Check(hKey, pwszSubKey, fCheckRead, fCheckWrite); free(pwszSubKey); } else { DPFN(eDbgLevelError, "Failed to convert %s to unicode", lpSubKey); } } VOID CRegistryChecks::Check( HKEY hKey, LPCWSTR lpSubKey, BOOL fCheckRead, BOOL fCheckWrite, REGSAM samDesired ) { RCOPENKEY* key = FindKey(hKey); WCHAR wszPath[MAX_PATH] = L""; MakePathW(key, hKey, lpSubKey, wszPath); if (fCheckRead) { CheckReading(wszPath); } if (fCheckWrite) { CheckWriting(samDesired, wszPath); } } LONG CRegistryChecks::OpenKeyExOriginalW( HKEY hKey, LPCWSTR lpSubKey, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition, BOOL bCreate ) { if (bCreate) { return ORIGINAL_API(RegCreateKeyExW)( hKey, lpSubKey, 0, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition); } else { return ORIGINAL_API(RegOpenKeyExW)( hKey, lpSubKey, 0, samDesired, phkResult); } } LONG CRegistryChecks::OpenKeyExA( HKEY hKey, LPCSTR lpSubKey, LPSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition, BOOL bCreate ) { LONG lRet; LPWSTR pwszSubKey = NULL; LPWSTR pwszClass = NULL; if (lpSubKey) { if (!(pwszSubKey = ToUnicode(lpSubKey))) { DPFN(eDbgLevelError, "Failed to convert %s to unicode", lpSubKey); return ERROR_NOT_ENOUGH_MEMORY; } } if (lpClass) { if (!(pwszClass = ToUnicode(lpClass))) { free(pwszSubKey); DPFN(eDbgLevelError, "Failed to convert %s to unicode", lpClass); return ERROR_NOT_ENOUGH_MEMORY; } } lRet = OpenKeyExW( hKey, pwszSubKey, pwszClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition, bCreate); free(pwszSubKey); free(pwszClass); return lRet; } LONG CRegistryChecks::OpenKeyExW( HKEY hKey, LPCWSTR lpSubKey, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition, BOOL bCreate ) { RCOPENKEY* key = FindKey(hKey); WCHAR wszPath[MAX_PATH] = L""; MakePathW(key, hKey, lpSubKey, wszPath); CheckReading(wszPath); CheckWriting(samDesired, wszPath); LONG lRes = OpenKeyExOriginalW( hKey, lpSubKey, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition, bCreate); if (lRes == ERROR_SUCCESS) { if (AddKey(*phkResult, wszPath)) { DPFN(eDbgLevelInfo, "[OpenKeyExW] success - adding key 0x%08X", *phkResult); } else { lRes = ERROR_INVALID_HANDLE; } } return lRes; } LONG CRegistryChecks::QueryValueA( HKEY hKey, LPCSTR lpSubKey, LPSTR lpValue, PLONG lpcbValue ) { Check(hKey, lpSubKey, TRUE, FALSE); return ORIGINAL_API(RegQueryValueA)( hKey, lpSubKey, lpValue, lpcbValue); } LONG CRegistryChecks::QueryValueW( HKEY hKey, LPCWSTR lpSubKey, LPWSTR lpValue, PLONG lpcbValue ) { Check(hKey, lpSubKey, TRUE, FALSE); return ORIGINAL_API(RegQueryValueW)( hKey, lpSubKey, lpValue, lpcbValue); } LONG CRegistryChecks::QueryValueExA( HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegQueryValueExA)( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } LONG CRegistryChecks::QueryValueExW( HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegQueryValueExW)( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } LONG CRegistryChecks::QueryInfoKeyA( HKEY hKey, LPSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegQueryInfoKeyA)( hKey, lpClass, lpcbClass, lpReserved, lpcSubKeys, lpcbMaxSubKeyLen, lpcbMaxClassLen, lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen, lpcbSecurityDescriptor, lpftLastWriteTime); } LONG CRegistryChecks::QueryInfoKeyW( HKEY hKey, LPWSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegQueryInfoKeyW)( hKey, lpClass, lpcbClass, lpReserved, lpcSubKeys, lpcbMaxSubKeyLen, lpcbMaxClassLen, lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen, lpcbSecurityDescriptor, lpftLastWriteTime); } LONG CRegistryChecks::SetValueA( HKEY hKey, LPCSTR lpSubKey, DWORD dwType, LPCSTR lpData, DWORD cbData ) { Check(hKey, lpSubKey, FALSE, TRUE, KEY_WRITE); return ORIGINAL_API(RegSetValueA)( hKey, lpSubKey, dwType, lpData, cbData); } LONG CRegistryChecks::SetValueW( HKEY hKey, LPCWSTR lpSubKey, DWORD dwType, LPCWSTR lpData, DWORD cbData ) { Check(hKey, lpSubKey, FALSE, TRUE, KEY_WRITE); return ORIGINAL_API(RegSetValueW)( hKey, lpSubKey, dwType, lpData, cbData); } LONG CRegistryChecks::SetValueExA( HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE * lpData, DWORD cbData ) { Check(hKey, L"", FALSE, TRUE, KEY_WRITE); return ORIGINAL_API(RegSetValueExA)( hKey, lpValueName, Reserved, dwType, lpData, cbData); } LONG CRegistryChecks::SetValueExW( HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE * lpData, DWORD cbData ) { Check(hKey, L"", FALSE, TRUE, KEY_WRITE); return ORIGINAL_API(RegSetValueExW)( hKey, lpValueName, Reserved, dwType, lpData, cbData); } LONG CRegistryChecks::EnumValueA( HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegEnumValueA)( hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); } // If the key was not originated from HKCU, // we enum at the original location. LONG CRegistryChecks::EnumValueW( HKEY hKey, DWORD dwIndex, LPWSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegEnumValueW)( hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); } LONG CRegistryChecks::EnumKeyExA( HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass, PFILETIME lpftLastWriteTime ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegEnumKeyExA)( hKey, dwIndex, lpName, lpcbName, lpReserved, lpClass, lpcbClass, lpftLastWriteTime); } // If the key was not originated from HKCU, // we enum at the original location. LONG CRegistryChecks::EnumKeyExW( HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved, LPWSTR lpClass, LPDWORD lpcbClass, PFILETIME lpftLastWriteTime ) { Check(hKey, L"", TRUE, FALSE); return ORIGINAL_API(RegEnumKeyExW)( hKey, dwIndex, lpName, lpcbName, lpReserved, lpClass, lpcbClass, lpftLastWriteTime); } // Remove the key from the list. LONG CRegistryChecks::CloseKey( HKEY hKey ) { RCOPENKEY* key = keys; RCOPENKEY* last = NULL; while (key) { if (key->hkBase == hKey) { if (last) { last->next = key->next; } else { keys = key->next; } delete key; break; } last = key; key = key->next; } DPFN(eDbgLevelInfo, "[CloseKey] closing key 0x%08X", hKey); return ORIGINAL_API(RegCloseKey)(hKey); } LONG CRegistryChecks::DeleteKeyA( HKEY hKey, LPCSTR lpSubKey ) { Check(hKey, lpSubKey, FALSE, TRUE, KEY_WRITE); return ORIGINAL_API(RegDeleteKeyA)( hKey, lpSubKey); } LONG CRegistryChecks::DeleteKeyW( HKEY hKey, LPCWSTR lpSubKey ) { Check(hKey, lpSubKey, FALSE, TRUE, KEY_WRITE); return ORIGINAL_API(RegDeleteKeyW)( hKey, lpSubKey); } CRegistryChecks RRegistry; // // Hook APIs. // LONG APIHOOK(RegOpenKeyA)( HKEY hKey, LPSTR lpSubKey, PHKEY phkResult ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExA( hKey, lpSubKey, 0, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkResult, NULL, FALSE); } LONG APIHOOK(RegOpenKeyW)( HKEY hKey, LPWSTR lpSubKey, PHKEY phkResult ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExW( hKey, lpSubKey, 0, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkResult, NULL, FALSE); } LONG APIHOOK(RegOpenKeyExA)( HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExA( hKey, lpSubKey, 0, REG_OPTION_NON_VOLATILE, samDesired, NULL, phkResult, NULL, FALSE); } LONG APIHOOK(RegOpenKeyExW)( HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExW( hKey, lpSubKey, 0, REG_OPTION_NON_VOLATILE, samDesired, NULL, phkResult, NULL, FALSE); } LONG APIHOOK(RegCreateKeyA)( HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExA( hKey, lpSubKey, 0, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkResult, NULL, TRUE); } LONG APIHOOK(RegCreateKeyW)( HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExW( hKey, lpSubKey, 0, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkResult, NULL, TRUE); } LONG APIHOOK(RegCreateKeyExA)( HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExA( hKey, lpSubKey, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition, TRUE); } LONG APIHOOK(RegCreateKeyExW)( HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition ) { CLock cLock(g_csCritSec); return RRegistry.OpenKeyExW( hKey, lpSubKey, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition, TRUE); } LONG APIHOOK(RegQueryValueA)( HKEY hKey, LPCSTR lpSubKey, LPSTR lpValue, PLONG lpcbValue ) { CLock cLock(g_csCritSec); return RRegistry.QueryValueA( hKey, lpSubKey, lpValue, lpcbValue); } LONG APIHOOK(RegQueryValueW)( HKEY hKey, LPCWSTR lpSubKey, LPWSTR lpValue, PLONG lpcbValue ) { CLock cLock(g_csCritSec); return RRegistry.QueryValueW( hKey, lpSubKey, lpValue, lpcbValue); } LONG APIHOOK(RegQueryValueExA)( HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { CLock cLock(g_csCritSec); return RRegistry.QueryValueExA( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } LONG APIHOOK(RegQueryValueExW)( HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { CLock cLock(g_csCritSec); return RRegistry.QueryValueExW( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } LONG APIHOOK(RegQueryInfoKeyA)( HKEY hKey, LPSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ) { CLock cLock(g_csCritSec); return RRegistry.QueryInfoKeyA( hKey, lpClass, lpcbClass, lpReserved, lpcSubKeys, lpcbMaxSubKeyLen, lpcbMaxClassLen, lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen, lpcbSecurityDescriptor, lpftLastWriteTime); } LONG APIHOOK(RegQueryInfoKeyW)( HKEY hKey, LPWSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ) { CLock cLock(g_csCritSec); return RRegistry.QueryInfoKeyW( hKey, lpClass, lpcbClass, lpReserved, lpcSubKeys, lpcbMaxSubKeyLen, lpcbMaxClassLen, lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen, lpcbSecurityDescriptor, lpftLastWriteTime); } LONG APIHOOK(RegSetValueA)( HKEY hKey, LPCSTR lpSubKey, DWORD dwType, LPCSTR lpData, DWORD cbData ) { CLock cLock(g_csCritSec); return RRegistry.SetValueA( hKey, lpSubKey, dwType, lpData, cbData); } LONG APIHOOK(RegSetValueW)( HKEY hKey, LPCWSTR lpSubKey, DWORD dwType, LPCWSTR lpData, DWORD cbData ) { CLock cLock(g_csCritSec); return RRegistry.SetValueW( hKey, lpSubKey, dwType, lpData, cbData); } LONG APIHOOK(RegSetValueExA)( HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, DWORD dwType, CONST BYTE * lpData, DWORD cbData ) { CLock cLock(g_csCritSec); return RRegistry.SetValueExA( hKey, lpSubKey, Reserved, dwType, lpData, cbData); } LONG APIHOOK(RegSetValueExW)( HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, DWORD dwType, CONST BYTE * lpData, DWORD cbData ) { CLock cLock(g_csCritSec); return RRegistry.SetValueExW( hKey, lpSubKey, Reserved, dwType, lpData, cbData); } LONG APIHOOK(RegEnumValueA)( HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { CLock cLock(g_csCritSec); return RRegistry.EnumValueA( hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); } LONG APIHOOK(RegEnumValueW)( HKEY hKey, DWORD dwIndex, LPWSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { CLock cLock(g_csCritSec); return RRegistry.EnumValueW( hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); } LONG APIHOOK(RegEnumKeyA)( HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cbName ) { CLock cLock(g_csCritSec); return RRegistry.EnumKeyExA( hKey, dwIndex, lpName, &cbName, NULL, NULL, NULL, NULL); // can this be null??? } LONG APIHOOK(RegEnumKeyW)( HKEY hKey, DWORD dwIndex, LPWSTR lpName, DWORD cbName ) { CLock cLock(g_csCritSec); return RRegistry.EnumKeyExW( hKey, dwIndex, lpName, &cbName, NULL, NULL, NULL, NULL); } LONG APIHOOK(RegEnumKeyExA)( HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass, PFILETIME lpftLastWriteTime ) { CLock cLock(g_csCritSec); return RRegistry.EnumKeyExA( hKey, dwIndex, lpName, lpcbName, lpReserved, lpClass, lpcbClass, lpftLastWriteTime); } LONG APIHOOK(RegEnumKeyExW)( HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved, LPWSTR lpClass, LPDWORD lpcbClass, PFILETIME lpftLastWriteTime ) { CLock cLock(g_csCritSec); return RRegistry.EnumKeyExW( hKey, dwIndex, lpName, lpcbName, lpReserved, lpClass, lpcbClass, lpftLastWriteTime); } LONG APIHOOK(RegCloseKey)(HKEY hKey) { CLock cLock(g_csCritSec); return RRegistry.CloseKey(hKey); } LONG APIHOOK(RegDeleteKeyA)( HKEY hKey, LPCSTR lpSubKey ) { CLock cLock(g_csCritSec); return RRegistry.DeleteKeyA(hKey, lpSubKey); } LONG APIHOOK(RegDeleteKeyW)( HKEY hKey, LPCWSTR lpSubKey ) { CLock cLock(g_csCritSec); return RRegistry.DeleteKeyW(hKey, lpSubKey); } SHIM_INFO_BEGIN() SHIM_INFO_DESCRIPTION(AVS_REGISTRYCHECKS_DESC) SHIM_INFO_FRIENDLY_NAME(AVS_REGISTRYCHECKS_FRIENDLY) SHIM_INFO_VERSION(1, 3) SHIM_INFO_FLAGS(AVRF_FLAG_EXTERNAL_ONLY) SHIM_INFO_INCLUDE_EXCLUDE("E:msi.dll sxs.dll comctl32.dll ole32.dll oleaut32.dll") SHIM_INFO_END() /*++ Register hooked functions Note we purposely ignore the cleanup because some apps call registry functions during process detach. --*/ HOOK_BEGIN DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_Console_READ, AVS_HKCU_Console_READ, AVS_HKCU_Console_READ_R, AVS_HKCU_Console_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_ControlPanel_READ, AVS_HKCU_ControlPanel_READ, AVS_HKCU_ControlPanel_READ_R, AVS_HKCU_ControlPanel_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_Environment_READ, AVS_HKCU_Environment_READ, AVS_HKCU_Environment_READ_R, AVS_HKCU_Environment_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_Identities_READ, AVS_HKCU_Identities_READ, AVS_HKCU_Identities_READ_R, AVS_HKCU_Identities_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_KeyboardLayout_READ, AVS_HKCU_KeyboardLayout_READ, AVS_HKCU_KeyboardLayout_READ_R, AVS_HKCU_KeyboardLayout_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_Printers_READ, AVS_HKCU_Printers_READ, AVS_HKCU_Printers_READ_R, AVS_HKCU_Printers_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_RemoteAccess_READ, AVS_HKCU_RemoteAccess_READ, AVS_HKCU_RemoteAccess_READ_R, AVS_HKCU_RemoteAccess_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_SessionInformation_READ, AVS_HKCU_SessionInformation_READ, AVS_HKCU_SessionInformation_READ_R, AVS_HKCU_SessionInformation_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_UNICODEProgramGroups_READ, AVS_HKCU_UNICODEProgramGroups_READ, AVS_HKCU_UNICODEProgramGroups_READ_R, AVS_HKCU_UNICODEProgramGroups_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_VolatileEnvironment_READ, AVS_HKCU_VolatileEnvironment_READ, AVS_HKCU_VolatileEnvironment_READ_R, AVS_HKCU_VolatileEnvironment_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCU_Windows31MigrationStatus_READ, AVS_HKCU_Windows31MigrationStatus_READ, AVS_HKCU_Windows31MigrationStatus_READ_R, AVS_HKCU_Windows31MigrationStatus_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKLM_HARDWARE_READ, AVS_HKLM_HARDWARE_READ, AVS_HKLM_HARDWARE_READ_R, AVS_HKLM_HARDWARE_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKLM_SAM_READ, AVS_HKLM_SAM_READ, AVS_HKLM_SAM_READ_R, AVS_HKLM_SAM_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKLM_SECURITY_READ, AVS_HKLM_SECURITY_READ, AVS_HKLM_SECURITY_READ_R, AVS_HKLM_SECURITY_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKLM_SYSTEM_READ, AVS_HKLM_SYSTEM_READ, AVS_HKLM_SYSTEM_READ_R, AVS_HKLM_SYSTEM_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKCC_READ, AVS_HKCC_READ, AVS_HKCC_READ_R, AVS_HKCC_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_HKUS_READ, AVS_HKUS_READ, AVS_HKUS_READ_R, AVS_HKUS_READ_URL) DUMP_VERIFIER_LOG_ENTRY(VLOG_NON_HKCU_WRITE, AVS_NON_HKCU_WRITE, AVS_NON_HKCU_WRITE_R, AVS_NON_HKCU_WRITE_URL) APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyA) APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyW) APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExA) APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExW) APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyA) APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyW) APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExA) APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExW) APIHOOK_ENTRY(ADVAPI32.DLL, RegCloseKey) APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueA) APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueW) APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExA) APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExW) APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryInfoKeyA) APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryInfoKeyW) APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueA) APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueW) APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueExA) APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueExW) APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumValueA) APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumValueW) APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyA) APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyW) APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyExA) APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyExW) APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteKeyA) APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteKeyW) HOOK_END IMPLEMENT_SHIM_END