/*++ Copyright (c) 1999-2000 Microsoft Corporation Module Name: regmisc.c Abstract: This module implement Handle redirection for registry redirection. Author: ATM Shafiqul Khalid (askhalid) 16-June-2000 Revision History: --*/ #include #include #include #include #include #include #define _WOW64REFLECTOR_ #include "regremap.h" #include "wow64reg.h" #include "wow64reg\reflectr.h" #ifdef _WOW64DLLAPI_ #include "wow64.h" #else #define ERRORLOG 1 //this one is completely dummy #define LOGPRINT(x) #define WOWASSERT(p) #endif //_WOW64DLLAPI_ #define REFLECTOR_ENABLE_KEY L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\WOW64\\Reflector Setup" #define REFLECTOR_DISABLE_KEY L"\\Registry\\Machine\\System\\Setup" #define WOW64_REDIRECTOR_CONFIG_KEY L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\WOW64" #ifdef DBG VOID DebugRegistryRedirectionOnClose ( HANDLE KeyHandle, PWCHAR Message ); DWORD LogID = 0; #endif BOOL HandleRunOnce ( WCHAR *SrcNode ); BOOL ReflectClassGuid ( PWCHAR SrcName, DWORD dwDirection ); VOID InitRegistry (); BOOL SyncGuidKey ( HANDLE hSrc, HANDLE hDest, DWORD dwDirection, DWORD __bNewlyCreated ); BOOL Wow64ReflectSecurity ( HKEY SrcKey, HKEY DestKey ); // //IsOnReflectionList: has hardcoded \\registry\\user\\_Classes. // DWORD ReflectListLen[18] ={0}; WCHAR ReflectList[18][128]={ { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes"}, // alias to the classes root on the user hives { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Classes"}, // alias to the classes root on the user hives { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Wow6432Node"}, // alias to the classes root on the user hives { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run"}, // Runonce Key { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce"}, // Runonce Key { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx"}, // Runonce Key { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\COM3"}, // COM+ Key { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\COM3"}, // COM+ Key { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Ole"}, // OLE Key { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Ole"}, // OLE Key { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\EventSystem"}, // EventSystem { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\EventSystem"}, // EventSystem { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\RPC"}, // RPC { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\RPC"}, // RPC { L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\TEST"}, // Test Node { L"\\REGISTRY\\MACHINE\\SOFTWARE\\TEST"}, // Test Node { L""} }; typedef struct { HANDLE hBase; // handle to the original object HANDLE hRemap; // handle to the remapped object DWORD Status; // will have different attribute set. DWORD dwCount; // Handle count- according to dragos, we can ignore because multiple open get different handle. DWORD Attribute; //attribute to hold Key attribute } WOW64_HANDLE; #define TABLE_SEGMENT_MAX 500 #define SEGMENT_SIZE 256 #define DIRECTION_32_TO_64 10 #define DIRECTION_64_TO_32 11 // // Flag while copying value Key. // #define DEFAULT_FLAG 0x00000000 #define DELETE_SRC_VALUEKEY 0x00000010 #define DONT_DELETE_DEST_VALUEKEY 0x00000020 #define PATCH_VALUE_KEY_NAME 0x00000040 #define SYNC_VALUE_IF_REFLECTED_KEYS 0x00000080 #define DONT_SYNC_IF_DLL_SURROGATE 0x00000100 #define WOW64_HANDLE_DIRTY 0x00000001 // some update operation was done using this handle #define WOW64_HANDLE_INUSE 0x00000002 // Tag this handle block not free #define WOW64_HANDLE_POSSIBLE_SHIM 0x00000004 // this key is possible hit for shimming #define HashValue (x) ((((x)>>24) + ((x)>>16) + (x)>>8 + (x)) % SEGMENT_SIZE ) #define MyNtClose(hRemap) if (hRemap != NULL) { NtClose (hRemap); hRemap = NULL;} BOOL bEnableCurrentControlSetProtection = FALSE; RTL_CRITICAL_SECTION HandleTable; BOOL bHandleTableInit=FALSE; // // BUGBUG: This module implement simplifiled version of handle redirection using linear list. // This must have to be implemented by a hash table if possible. // PVOID List[TABLE_SEGMENT_MAX]; WOW64_HANDLE HandleList[SEGMENT_SIZE]; //hopefully this will be good enough for open key handle. It can always allocate dynamically. BOOL bReflectorStatusOn = FALSE; LogMsg ( HANDLE hKey, PWCHAR Msg ) { WCHAR Name[WOW64_MAX_PATH]; DWORD Len = WOW64_MAX_PATH; HandleToKeyName (hKey, Name, &Len); DbgPrint ("\nMsg:%S Key:%S",Msg, Name ); } PVOID RegRemapAlloc ( DWORD dwSize ) /*++ Routine Description: Allocate memory. Arguments: dwSize - size of memory to allocate. Return Value: return appropriate buffer. --*/ { PVOID pBuffer; // // For performance reason you might allocate big chunk and then reuse. // pBuffer = RtlAllocateHeap ( RtlProcessHeap(), 0, dwSize); return pBuffer; } VOID RegRemapFree ( PVOID pBuffer ) /*++ Routine Description: Free allocated mery. Arguments: dwSize - size of memory to allocate. Return Value: None. --*/ { // // For performance reason you might allocate big chunk and then reuse. // if ( pBuffer == NULL) return; RtlFreeHeap ( RtlProcessHeap(), 0, pBuffer ); return; } BOOL InitHandleTable ( ) /*++ Routine Description: Initialize the table with appropriate allocation and value if its not initialized yet. Arguments: None. Return Value: TRUE if the function succeed. FALSE otherwise. this might allocate more memory and free up later. --*/ { HKEY hWowSetupKey; HKEY hKey; OBJECT_ATTRIBUTES Obja; UNICODE_STRING KeyName; UNICODE_STRING ValueName; NTSTATUS Status; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = NULL; BYTE Buff[sizeof (KEY_VALUE_PARTIAL_INFORMATION)+10]; memset (List, 0, sizeof (List)); memset (HandleList, 0, sizeof (HandleList)); List [0]= HandleList; RtlInitUnicodeString (&KeyName, REFLECTOR_DISABLE_KEY); InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey (&hKey, KEY_READ, &Obja); if (NT_SUCCESS(Status)) { DWORD Res; DWORD Len = sizeof (Buff); KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)Buff; RtlInitUnicodeString (&ValueName, L"SystemSetupInProgress"); Status = NtQueryValueKey( hKey, &ValueName, KeyValuePartialInformation, KeyValueInformation, Len, &Len ); NtClose (hKey); // reflection should be disable because setup is on its way. if (NT_SUCCESS(Status)) { if ( *(LONG *)KeyValueInformation->Data != 0) return TRUE; //system setup is in progress no reflection } else return TRUE; } else return TRUE; // // Initialize Internal ISN node table to remap keys. // Status = RtlInitializeCriticalSection( &HandleTable ); if (!NT_SUCCESS (Status)) return FALSE; bHandleTableInit=TRUE; bReflectorStatusOn = TRUE; //Now reflector is on. #ifdef DBG // // Check if the systemwide flag is turned off. // RtlInitUnicodeString (&KeyName, WOW64_REDIRECTOR_CONFIG_KEY); InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey (&hKey, KEY_READ, &Obja); if (NT_SUCCESS(Status)) { DWORD Res; DWORD Len = sizeof (Buff); KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)Buff; RtlInitUnicodeString (&ValueName, L"DisableReflector"); Status = NtQueryValueKey( hKey, &ValueName, KeyValuePartialInformation, KeyValueInformation, Len, &Len ); NtClose (hKey); // reflection should be disable because setup is on its way. if (NT_SUCCESS(Status)) { if ( *(LONG *)KeyValueInformation->Data != 0) bReflectorStatusOn = FALSE; //Now reflector is off if user set the flag for debug purpose. } } #endif //DBG // // Check if CurrentControlSet hive need to be procted // RtlInitUnicodeString (&KeyName, WOW64_REDIRECTOR_CONFIG_KEY); InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey (&hKey, KEY_READ, &Obja); if (NT_SUCCESS(Status)) { DWORD Res; DWORD Len = sizeof (Buff); KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)Buff; RtlInitUnicodeString (&ValueName, L"EnableCurrentControlSetProtection"); Status = NtQueryValueKey( hKey, &ValueName, KeyValuePartialInformation, KeyValueInformation, Len, &Len ); NtClose (hKey); // reflection should be disable because setup is on its way. if (NT_SUCCESS(Status)) { if ( *(LONG *)KeyValueInformation->Data != 0) bEnableCurrentControlSetProtection = TRUE; //Now reflector is off if user set the flag for debug purpose. } } #ifdef _WOW64DLLAPI_ //only linked with wow64 not with advapi32 try { InitWow64Shim (); } except( NULL, EXCEPTION_EXECUTE_HANDLER){ } #endif return TRUE; } WOW64_HANDLE * GetFreeHandleBlock ( HANDLE hKey ) /*++ Routine Description: Return a free block from the handle table. Arguments: hKey - Handle to the key that will be inserted into the table. Return Value: Return a free block on the table. --*/ { WOW64_HANDLE *pList; DWORD i,k; RtlEnterCriticalSection(&HandleTable); for (i=0;ihRemap; } BOOL IsWow64Handle ( HANDLE hKey ) /*++ Routine Description: Check if the handle has been tagged to watch while closing. Arguments: hKey - Handle to the key that need to be checked. Return Value: TRUE if the handle is on the TABLE. FALSE otherwise. --*/ { return GetHandleBlock (hKey) != NULL; } WOW64_HANDLE * InsertWow64Handle ( HANDLE hKeyBase, HANDLE hKeyRemap ) /*++ Routine Description: Allocate some resources so that some manipulation can be done in case of Key changes. Arguments: hKey - Handle to the base key that need to be marked. Return Value: Valid block that refer to the handle. --*/ { WCHAR SrcNode[WOW64_MAX_PATH]; DWORD dwLen = WOW64_MAX_PATH; WOW64_HANDLE *pHandleBlock = NULL; pHandleBlock = GetHandleBlock (hKeyBase); if (hKeyBase == NULL || hKeyRemap == NULL) return NULL; if ( pHandleBlock == NULL ) { // new handle // // Get the path name and if the key is on the reflection list add it. // if (!HandleToKeyName ( hKeyBase, SrcNode, &dwLen )) return NULL; // // Make sure The name is on the List otherwise forget. // if ( !IsOnReflectionList (SrcNode)) return NULL; pHandleBlock = GetFreeHandleBlock (hKeyBase); } if ( pHandleBlock == NULL) return NULL; pHandleBlock->hRemap = hKeyRemap; pHandleBlock->hBase = hKeyBase; return pHandleBlock; } BOOL Wow64RegSetKeyPossibleShim ( HANDLE hKey ) /*++ Routine Description: Tag the handle for future operation. Not same as dirty Arguments: hKey - Handle to the base key that need to be marked. Return Value: TRUE if the key is on the list of reflection. FALSE otherwise. --*/ { WOW64_HANDLE *pHandleBlock; hKey = (HANDLE)((SIZE_T)hKey & ~3); //ignore the last 2 bits if (!bReflectorStatusOn) return TRUE; //reflector isn't enable yet. if (( pHandleBlock = InsertWow64Handle (hKey, hKey)) == NULL) // bugbug: not regular insert return FALSE; pHandleBlock->Status |= WOW64_HANDLE_POSSIBLE_SHIM; return TRUE; } BOOL Wow64RegIsPossibleShimFromTable ( HANDLE hKey ) /*++ Routine Description: Tag the handle for future operation. Not same as dirty Arguments: hKey - Handle to the base key that need to be marked. Return Value: TRUE if the key is on the list of reflection. FALSE otherwise. --*/ { WOW64_HANDLE *pHandleBlock; hKey = (HANDLE)((SIZE_T)hKey & ~3); //ignore the last 2 bits if (!bReflectorStatusOn) return FALSE; //reflector isn't enable yet. if ((pHandleBlock = GetHandleBlock (hKey)) == NULL ) return FALSE; if ( pHandleBlock->Status & WOW64_HANDLE_POSSIBLE_SHIM ) return TRUE; return FALSE; } BOOL Wow64RegSetKeyDirty ( HANDLE hKey ) /*++ Routine Description: Mark the handle dirty, i.e., some value has been changed associated to this Key. Arguments: hKey - Handle to the base key that need to be marked. Return Value: TRUE if the key is on the list of reflection. FALSE otherwise. --*/ { WOW64_HANDLE *pHandleBlock; hKey = (HANDLE)((SIZE_T)hKey & ~3); //ignore the last 2 bits if (!bReflectorStatusOn) return TRUE; //reflector isn't enable yet. if (( pHandleBlock = InsertWow64Handle (hKey, hKey)) == NULL) return FALSE; pHandleBlock->Status |= WOW64_HANDLE_DIRTY; return TRUE; } VOID CloseWow64Handle ( WOW64_HANDLE *pHandleBlock ) { RtlEnterCriticalSection(&HandleTable); pHandleBlock->hBase = NULL; pHandleBlock->hRemap = NULL; pHandleBlock->Status = 0; pHandleBlock->Attribute = 0; RtlLeaveCriticalSection(&HandleTable); } BOOL Wow64RegCloseKey ( HANDLE hKey ) /*++ Routine Description: Remove entry associated with the handle. Arguments: hKey - Handle to the key that is being closed. Return Value: TRUE if function succeed. FALSE otherwise. --*/ { WOW64_HANDLE *pHandleBlock; hKey = (HANDLE)((SIZE_T)hKey & ~3); //ignore the last 2 bits if (!bReflectorStatusOn) return TRUE; //reflector isn't enable yet. if ((pHandleBlock = GetHandleBlock (hKey)) == NULL ) return FALSE; if (pHandleBlock->Status & WOW64_HANDLE_DIRTY) // if the handle is dirty sync the node NtSyncNode ( hKey, NULL, FALSE ); //BUGBUG if ( pHandleBlock->hRemap!= hKey ) MyNtClose ( pHandleBlock->hRemap ); // if Same then just allocating block CloseWow64Handle ( pHandleBlock ); // // Call sync APi. to synchronize the registry reflection // return TRUE; } void CleanupReflector ( DWORD dwFlag ) /*++ Routine Description: This routine is called while apps is shutting down. This will give reflector a chance to reflect any leftover handle than need reflection. This can be called from multiple places, like NtTerminateProcess, Advapi32 dll detach or shutdown routine. Arguments: dwFlag - for future use to track from where this call came from. Return Value: None. --*/ { WOW64_HANDLE *pList; DWORD i,k; for (i=0;i= 69) //sizeof \Registry\user\sid_Classes //if ( wcsncmp (Path+61, L"_Classes", 8) == 0 ) //69 is the size of user classes sid and 61 is for sanity check if ( wcsistr (Path, L"_Classes")) return TRUE; if (ReflectListLen[0]==0) { i=0; while (ReflectList[i][0] != UNICODE_NULL ) { ReflectListLen[i] = wcslen (ReflectList[i]); i++; } } i=0; while (ReflectList[i][0] != UNICODE_NULL ) { if ( _wcsnicmp (ReflectList[i], Path, ReflectListLen[i]) == 0) return TRUE; i++; } return FALSE; } BOOL UpdateKeyTag ( HKEY hBase, DWORD dwAttribute ) /*++ Routine Description: Update a particular Key tag, like written by 32bit apps or its a copy by reflector. Arguments: hBase - handle to a key to operate. dwAttribute - tag value its can be 0x01 written by 32bit apps. 0x02 created by reflector. Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { // // the flag can't be >0x0f i.e., last 4 bits // KEY_USER_FLAGS_INFORMATION sFlag; NTSTATUS st; sFlag.UserFlags = dwAttribute; st = NtSetInformationKey( hBase, KeyUserFlagsInformation, &sFlag, sizeof( KEY_USER_FLAGS_INFORMATION) ); if (!NT_SUCCESS (st)) return FALSE; return TRUE; } BOOL QueryKeyTag ( HKEY hBase, DWORD *dwAttribute ) /*++ Routine Description: Read Key tag, like written by 32bit apps or its a copy by reflector. Arguments: hBase - handle to a key to operate. dwAttribute - receive the TAG 0x01 written by 32bit apps. 0x02 created by reflector. Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { DWORD ResLen; KEY_USER_FLAGS_INFORMATION sFlag; NTSTATUS st; if ( dwAttribute == NULL ) return FALSE; if ( hBase == NULL ) return FALSE; *dwAttribute =0; st = NtQueryKey( hBase, KeyFlagsInformation, (PVOID)&sFlag, sizeof(KEY_FLAGS_INFORMATION), &ResLen); if (!NT_SUCCESS (st)) return FALSE; *dwAttribute = sFlag.UserFlags; return TRUE; } BOOL SyncValue ( HANDLE hBase, HANDLE hRemap, DWORD dwDirection, DWORD dwFlag ) /*++ Routine Description: Synchronize a two node with value Key. Delete from the RemapKey, and copy from Base Arguments: hBase - Handle to the src key. hRemap - Handle to the remap key. dwDirection - SyncDitection DIRECTION_32_TO_64 - 32bit is the source of information DIRECTION_64_TO_32 - 32bit is the source of information dwFlag - determine the behavior of the operation. DELETE_SRC_VALUEKEY delete source value key after coping on the dest. DONT_DELETE_DEST_VALUEKEY don't delete dest before copying from src. DEFAULT_FLAG - this means the default operation. SYNC_VALUE_IF_REFLECTED_KEYS - if either one is reflected key then sync. Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { HANDLE hTimeStampKey; NTSTATUS st= STATUS_SUCCESS; DWORD Index=0; DWORD ResultLength; DWORD LastKnownSize = 0; UNICODE_STRING UnicodeValueName; PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL; BYTE Buff [sizeof(KEY_VALUE_FULL_INFORMATION) + 2048]; WCHAR TmpChar; ULONG Length = sizeof(KEY_VALUE_FULL_INFORMATION) + 2048; KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buff; if ( SYNC_VALUE_IF_REFLECTED_KEYS & dwFlag) { DWORD Attrib1 =0; DWORD Attrib2 =0; QueryKeyTag (hBase, &Attrib1); QueryKeyTag (hRemap, &Attrib2); // // if atleast one is a reflected Key then sync value // if (!( (Attrib1 & TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE) || (Attrib2 & TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE) ) ) // reflector touched this Key return TRUE; } for (Index=0;;Index++) { st = NtEnumerateValueKey( hRemap, Index, KeyValueFullInformation, KeyValueInformation, Length, &ResultLength ); if (!NT_SUCCESS(st)) break; KeyValueInformation->Name[KeyValueInformation->NameLength/2] = UNICODE_NULL; RtlInitUnicodeString( &UnicodeValueName, KeyValueInformation->Name ); if ( !(DONT_DELETE_DEST_VALUEKEY & dwFlag)) if ( NtDeleteValueKey( hRemap, &UnicodeValueName ) == STATUS_SUCCESS ) Index--; } // // Copy all key from the Base. For each copy patch value if applicable // for (Index=0, st= STATUS_SUCCESS;;Index++) { st = NtEnumerateValueKey( hBase, Index, KeyValueFullInformation, KeyValueInformation, Length, &ResultLength ); if (st == STATUS_BUFFER_OVERFLOW ) { //Allocate more Buffer BUGBUG name shouldn't that big DbgPrint ("\nWow64: Will ignore any Key value larger than 2048 byte"); } if (!NT_SUCCESS (st)) break; TmpChar = KeyValueInformation->Name[KeyValueInformation->NameLength/2]; KeyValueInformation->Name[KeyValueInformation->NameLength/2] = UNICODE_NULL; RtlInitUnicodeString( &UnicodeValueName, KeyValueInformation->Name ); // // Check if you need to filter the Value DllSurrogate is such one. // if (dwFlag & DONT_SYNC_IF_DLL_SURROGATE) { if (_wcsnicmp (KeyValueInformation->Name, L"DllSurrogate",12 )==0 && KeyValueInformation->DataLength <=2) // size of UNICODE_NULL continue; } if ( (DELETE_SRC_VALUEKEY & dwFlag)) //delete from source in case of runonce if ( NtDeleteValueKey( hBase, &UnicodeValueName ) == STATUS_SUCCESS ) Index--; if ( (PATCH_VALUE_KEY_NAME & dwFlag) && (DIRECTION_32_TO_64 == dwDirection)) { wcscat (KeyValueInformation->Name, L"_x86"); RtlInitUnicodeString( &UnicodeValueName, KeyValueInformation->Name ); } KeyValueInformation->Name[KeyValueInformation->NameLength/2] = TmpChar; NtSetValueKey( hRemap, &UnicodeValueName, KeyValueInformation->TitleIndex, KeyValueInformation->Type, (PBYTE)(KeyValueInformation)+KeyValueInformation->DataOffset, KeyValueInformation->DataLength ); } // // Now reflect the security attribute // Wow64ReflectSecurity (hBase, hRemap ); return TRUE; } BOOL ReflectDllSurrogateKey ( PWCHAR SrcNode ) /*++ Routine Description: Determine if the DllSurrogateKey under AppID shoule be reflected. //By default this should always be reflected. Except when the key is empty. Arguments: SrcNode - Name of the node to be synced. Return Value: TRUE if the key Should be reflected. FALSE otherwise. --*/ { BYTE KeyBuffer[512]; DWORD KeyBufferSize = sizeof (KeyBuffer); DWORD ResultLength; UNICODE_STRING ValueName; NTSTATUS Status; PWCHAR pStr; HKEY hKey; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = NULL; KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyBuffer; RtlInitUnicodeString (&ValueName, L""); // // Apply special rule of empty AppID key for dll surrogate. // if ( ( pStr = wcsistr (SrcNode, L"\\DllSurrogate") ) == NULL) return TRUE; if ( *(pStr+13) != UNICODE_NULL) { return TRUE; } // // Consider only value in that key // // // if value key isn't empty reflect, i.e., return FALSE. // hKey = OpenNode (SrcNode); *(LONG *)KeyValueInformation->Data = 0; Status = NtQueryValueKey( hKey, &ValueName, KeyValuePartialInformation, KeyValueInformation, KeyBufferSize, &ResultLength); if (NULL != hKey) NtClose (hKey); // reflection should be disable because setup is on its way. if ( *(LONG *)KeyValueInformation->Data == 0) return FALSE; return TRUE; } BOOL ReflectInprocHandler32KeyByHandle ( HKEY hKey ) /*++ Routine Description: Determine if the ReflectInprocHandler32Key under CLSID shoule be reflected. //By default this should always be reflected. Except when the key is empty. Arguments: SrcNode - Name of the node to be synced. Return Value: TRUE if the key Should be reflected. FALSE otherwise. --*/ { BYTE KeyBuffer[512]; DWORD KeyBufferSize = sizeof (KeyBuffer); DWORD ResultLength; UNICODE_STRING ValueName; NTSTATUS Status; PWCHAR pStr; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = NULL; KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyBuffer; RtlInitUnicodeString (&ValueName, L""); //default value Key // // if value key isn't empty reflect, i.e., return FALSE. // //return FALSE; //never reflect *(LONG *)KeyValueInformation->Data = 0; Status = NtQueryValueKey( hKey, &ValueName, KeyValuePartialInformation, KeyValueInformation, KeyBufferSize, &ResultLength ); pStr = (PWCHAR)KeyValueInformation->Data; if ( NT_SUCCESS(Status) && pStr != NULL) { //Need to check type if ( 0 == _wcsnicmp (pStr, L"ole32.dll", 9)) return TRUE; if ( 0 == _wcsnicmp (pStr, L"oleaut32.dll", 12)) return TRUE; } return FALSE; } BOOL ReflectInprocHandler32KeyByName ( PWCHAR SrcNode ) /*++ Routine Description: Determine if the ReflectInprocHandler32Key under CLSID shoule be reflected. //By default this should always be reflected. Except when the key is empty. Arguments: SrcNode - Name of the node to be synced. Return Value: TRUE if the key Should be reflected. FALSE otherwise. --*/ { HKEY hKey; BOOL bRet = FALSE; hKey = OpenNode (SrcNode); if ( NULL != hKey ) { bRet = ReflectInprocHandler32KeyByHandle (hKey); NtClose (hKey); } return bRet; } BOOL TaggedKeyForDelete ( PWCHAR SrcNode ) /*++ Routine Description: Check if the Tagged deletion and noclobber rule should be applicable on this key. Arguments: SrcNode - Name of the node to be checked. Return Value: TRUE if the rule is applicable. FALSE otherwise. --*/ { if ( wcsistr (SrcNode, L"Classes\\CLSID\\{") != NULL ) return TRUE; if ( wcsistr (SrcNode, L"Classes\\Wow6432Node\\CLSID\\{") != NULL ) return TRUE; if ( ( wcsistr (SrcNode, L"Classes\\AppID\\{") != NULL ) || ( wcsistr (SrcNode, L"Classes\\Wow6432Node\\AppID\\{") != NULL ) ) return TRUE; return FALSE; } BOOL IsExemptReflection ( PWCHAR SrcNode ) /*++ Routine Description: Check if the is is on the exempt list from reflection. Arguments: SrcNode - Name of the node to be synced that need to be checked. Return Value: TRUE if the key is on the exempt list. FALSE otherwise. --*/ { // // Use a static list. // if ( wcsistr (SrcNode, L"Classes\\Installer") != NULL ) return TRUE; if ( wcsistr (SrcNode, L"Classes\\Wow6432Node\\Installer") != NULL ) return TRUE; return FALSE; } BOOL IsSpecialNode ( PWCHAR SrcNode, BOOL *Flag, DWORD dwDirection, DWORD *pdwKeyType ) /*++ Routine Description: Check if the node need different treatment. Arguments: SrcNode - Name of the node to be synced. Flag - If this fall in the special node category this flag is set TRUE. dwDirection - SyncDitection DIRECTION_32_TO_64 - 32bit is the source of information DIRECTION_64_TO_32 - 32bit is the source of information Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { *Flag = FALSE; if ( wcsistr (SrcNode, L"Classes\\CLSID\\{") != NULL ) { //guid start with { *Flag = TRUE; ReflectClassGuid ( SrcNode, dwDirection); } if ( wcsistr (SrcNode, L"Classes\\Wow6432Node\\CLSID\\{") != NULL ) { *Flag = TRUE; ReflectClassGuid ( SrcNode, dwDirection); } // // Always merge file association BUGBUG: See how bad it is. // Must handle special case runonce // if ( _wcsnicmp (SrcNode, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run",75 ) == 0 ) { //75 is the size of the string *Flag = TRUE; // // HandleRunOnce (SrcNode); // } if ( wcsistr (SrcNode, L"Classes\\Installer") != NULL ) *Flag = TRUE; if ( wcsistr (SrcNode, L"Classes\\Wow6432Node\\Installer") != NULL ) *Flag = TRUE; //if ( wcsistr (SrcNode, L"\\Classes\\Interface") != NULL ) // *Flag = TRUE; //if ( wcsistr (SrcNode, L"\\Classes\\Wow6432Node\\Interface") != NULL ) // *Flag = TRUE; //if (_wcsnicmp (SrcNode, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\TypeLib", sizeof (L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\TypeLib")/2 -1)==0) // *Flag = TRUE; //if (_wcsnicmp (SrcNode, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Wow6432Node\\TypeLib", sizeof (L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Wow6432Node\\TypeLib")/2 -1)==0) // *Flag = TRUE; if ( ( wcsistr (SrcNode, L"Classes\\AppID\\{") != NULL ) || ( wcsistr (SrcNode, L"Classes\\Wow6432Node\\AppID\\{") != NULL ) ) { *pdwKeyType = DONT_SYNC_IF_DLL_SURROGATE; } return *Flag; } BOOL NtSyncNode ( HANDLE hBase, PWCHAR AbsPath, BOOL bFlag ) /*++ Routine Description: Synchronize a tree based while closing a Key that was dirty. Arguments: hBase - Handle to the open Key. AbsPath - The original path application has created a key. bFlag - specify the sync property. Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { WCHAR DestNode[WOW64_MAX_PATH]; WCHAR SrcNode[WOW64_MAX_PATH]; BOOL bSpecialNode = FALSE; DWORD dwLen = WOW64_MAX_PATH; HKEY hRemap; HKEY hBaseNew; BOOL bRet; DWORD dwDirection; DWORD dwKeyType =0; // // If handle is null try to open the key on the otherside of the registry and pull that in. // if ( hBase != NULL ) { if (!HandleToKeyName ( hBase, SrcNode, &dwLen )) return FALSE; } else wcscpy (SrcNode, AbsPath); if (wcsistr (SrcNode, L"Wow6432Node") != NULL ) { dwDirection = DIRECTION_32_TO_64; Map32bitTo64bitKeyName ( SrcNode, DestNode ); } else { dwDirection = DIRECTION_64_TO_32; Map64bitTo32bitKeyName ( SrcNode, DestNode ); } // // check if both are the same // if (_wcsicmp ( SrcNode, DestNode ) == 0) return TRUE; //source and destination is the same //DbgPrint ("\nSyncing Node %S", SrcNode ); if (! (bFlag & SKIP_SPECIAL_CASE )) if (IsSpecialNode ( SrcNode, &bSpecialNode, dwDirection, &dwKeyType )) //special rule is applicable here. return TRUE; hRemap = OpenNode (DestNode); hBaseNew = OpenNode (SrcNode); // Open source in case user didn't open it with query priviledge. if ( hRemap == NULL && (!( bFlag & DONT_CREATE_DEST_KEY)) ) { //check if you should create this node // // Always create unless GUID or .abc, then you need to do some additional check. // if ( CreateNode (DestNode)) { hRemap = OpenNode (DestNode); UpdateKeyTag ( hRemap, TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE); } } // // SyncValue only, delete all the value from destination and recopy. // Generated Key will be reflected by create key. // if ( hBaseNew!= NULL && hRemap != NULL ) bRet = SyncValue (hBaseNew, hRemap, dwDirection, DEFAULT_FLAG | dwKeyType ); MyNtClose (hRemap); // Close the handle MyNtClose (hBaseNew); // Close the NewHandle return bRet; // // Check for existamce? // } LONGLONG CmpKeyTimeStamp ( HKEY hSrc, HKEY hDest ) /*++ Routine Description: Compare Key time stamp. Arguments: hSrc - handle to the src Key. hDest - Handle to the dest Key. Return Value: 0 - if timestamp of hSrc == timestamp of hDest >0 - if timestamp of hSrc > timestamp of hDest <0 - if timestamp of hSrc < timestamp of hDest FALSE otherwise. --*/ { NTSTATUS st= STATUS_SUCCESS; DWORD Index=0, ResultLength; LONGLONG TimeSrc=0; LONGLONG TimeDest=0; PKEY_BASIC_INFORMATION KeyInformation = NULL; BYTE Buff [sizeof(KEY_BASIC_INFORMATION) + 256]; ULONG Length = sizeof(KEY_BASIC_INFORMATION) + 256; KeyInformation = (PKEY_BASIC_INFORMATION)Buff; st = NtQueryKey( hSrc, KeyBasicInformation, KeyInformation, Length, &ResultLength ); if(NT_SUCCESS (st)) TimeSrc = *(LONGLONG *)&KeyInformation->LastWriteTime; st = NtQueryKey( hDest, KeyBasicInformation, KeyInformation, Length, &ResultLength ); if(NT_SUCCESS (st)) TimeDest = *(LONGLONG *)&KeyInformation->LastWriteTime; if ( TimeDest == 0 || TimeSrc == 0) return 0; return TimeSrc - TimeDest; } BOOL IsPresentLocalServerAppID ( PWCHAR KeyName, PWCHAR pCLSID, PWCHAR DestNode ) /*++ Routine Description: Check if a GUID has localserver32 or AppID than should have been reflected on the other side. Arguments: KeyName - Name of the key. pCLDID - pointer to the end of CLSID DestNode - Destination CLSID Return Value: TRUE if LocalSrever or AppID is there. FALSE otherwise. --*/ { HKEY hKeyTemp = NULL; DWORD Len = wcslen (DestNode); PWCHAR pDest = DestNode+Len; DWORD AttribSrc = 0; DWORD AttribDest = TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE; //if key doesn't exist HKEY hDest = NULL; BYTE KeyBuffer[512]; DWORD KeyBufferSize = sizeof (KeyBuffer); DWORD ResultLength; UNICODE_STRING ValueName; NTSTATUS Status; HKEY hKey; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = NULL; KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyBuffer; RtlInitUnicodeString (&ValueName, L"APPID"); wcscpy (pCLSID-1, L"\\LocalServer32"); hKeyTemp = OpenNode (KeyName); if (hKeyTemp == NULL ) { wcscpy (pCLSID-1, L"\\AppID"); hKeyTemp = OpenNode (KeyName); if (hKeyTemp == NULL ) { // // Check APPID value key associated with the GUID. // *(pCLSID-1)= UNICODE_NULL; hKeyTemp = OpenNode (KeyName); if (hKeyTemp != NULL ) { // query for APPID Status = NtQueryValueKey( hKeyTemp, &ValueName, KeyValuePartialInformation, KeyValueInformation, KeyBufferSize, &ResultLength); if (!NT_SUCCESS (Status)) { MyNtClose(hKeyTemp); return FALSE; } *pDest = UNICODE_NULL; hDest = OpenNode (DestNode); } } wcscpy (pDest, L"\\AppID"); hDest = OpenNode (DestNode); *pDest = UNICODE_NULL; }else { wcscpy (pDest, L"\\LocalServer32"); hDest = OpenNode (DestNode); *pDest = UNICODE_NULL; } QueryKeyTag (hKeyTemp, &AttribSrc); QueryKeyTag (hDest, &AttribDest); MyNtClose (hDest); MyNtClose (hKeyTemp); // // if atleast one is a reflected Key then sync value // if ( (AttribSrc & TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE) || (AttribDest & TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE) ) // reflector touched this Key return TRUE; return FALSE; //Yepp ID is present and the guid can be reflected } BOOL ReflectClassGuid ( PWCHAR SrcName, DWORD dwDirection ) /*++ Routine Description: Synchronize a two node with value Key. Delete from the RemapKey, and copy from Base Arguments: SrcName - Name of the key on CLSID path. dwDirection - SyncDitection DIRECTION_32_TO_64 - 32bit is the source of information DIRECTION_64_TO_32 - 32bit is the source of information Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { PWCHAR pCLSID; DWORD dwLen; WCHAR KeyName[256]; //You don't need this big Key for CLSID WCHAR DestNode[256]; HANDLE hKeyTemp; HANDLE hSrc; HANDLE hDest; BOOL bNewlyCreated = FALSE; // // If Localserver is present for that key, sync from the CLSID. // pCLSID = wcsistr (SrcName, L"\\CLSID\\{"); if ( pCLSID == NULL ) return TRUE; wcscpy (KeyName, SrcName ); pCLSID = &KeyName[(DWORD)(pCLSID - SrcName)]; pCLSID +=7; // point start of guid { // Sanity Check and will be good enough???? if ( pCLSID[9] != L'-' || pCLSID[14] != L'-' || pCLSID[19] != L'-' || pCLSID[24] != L'-' || pCLSID[37] != L'}' ) return FALSE; //DbgPrint ("\nTrying to sync GUID %S", SrcName); // // Initially sync the Key first in case time stamp is same because of resolution. // Cey Creation will be done while syncing Key from GUID // pCLSID +=39; if ( *(pCLSID-1) != UNICODE_NULL ) { //check if following is applicable. if ( _wcsnicmp (pCLSID, L"InprocServer32", 14) == 0 ) //Skip Inproc server return TRUE; if ( _wcsnicmp (pCLSID, L"InprocHandler32", 15) == 0 ) {//Check InprocHandler if (!ReflectInprocHandler32KeyByName (KeyName)) return TRUE; } } // // Get other path. // *(pCLSID-1)= UNICODE_NULL; // Make path only to the GUID if ( dwDirection == DIRECTION_32_TO_64 ) Map32bitTo64bitKeyName ( KeyName, DestNode ); //get 64bit side //BUGBUG: you can optimize this else if ( dwDirection == DIRECTION_64_TO_32 ) Map64bitTo32bitKeyName ( KeyName, DestNode ); //get 32bit side // // If the other hive has InProcHandler ignore this reflection rule // After Beta1 or apply by Tag // if ( !IsPresentLocalServerAppID (KeyName, pCLSID, DestNode) ) return TRUE; // // Now time to reflect everything except InprocServer32 // pCLSID--; pCLSID[0]= UNICODE_NULL; // Make path only to the GUID hSrc = OpenNode (KeyName); if (hSrc == NULL ) return TRUE; hDest = OpenNode (DestNode); if ( hDest == NULL ) { CreateNode (DestNode); hDest = OpenNode (DestNode); if (hDest != NULL) { UpdateKeyTag ( hDest, TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE); bNewlyCreated = TRUE; SyncValue ( hSrc, hDest, dwDirection, 0); } } if (hDest != NULL && hSrc != NULL) { // // Sync Value on current Node // //if ( !bNewlyCreated ) { // // if destination is a copy then update this. // DWORD Attrib1=0; DWORD Attrib2=0; HKEY hSrcKey1; HKEY hDestKey1; if ( dwDirection == DIRECTION_32_TO_64 ) Map32bitTo64bitKeyName ( SrcName, DestNode ); //get 64bit side //BUGBUG: you can optimize this else if ( dwDirection == DIRECTION_64_TO_32 ) Map64bitTo32bitKeyName ( SrcName, DestNode ); //get 32bit side hSrcKey1 = OpenNode (SrcName); hDestKey1 = OpenNode (DestNode); if ( hSrcKey1 != NULL && hDestKey1 != NULL ) //if dest isn't reflected key should you merge? // // 64bit Local Server might get priority // SyncValue ( hSrcKey1, hDestKey1, dwDirection, SYNC_VALUE_IF_REFLECTED_KEYS); MyNtClose ( hSrcKey1 ); MyNtClose ( hDestKey1 ); //} SyncGuidKey (hSrc, hDest, dwDirection, FALSE ); } MyNtClose (hDest); MyNtClose (hSrc); return TRUE; } BOOL SyncGuidKey ( HANDLE hSrc, HANDLE hDest, DWORD dwDirection, DWORD __bNewlyCreated ) /*++ Routine Description: Synchronize a two CLSID Node. Arguments: hSrc - Handle to Source Class GUID. hDest - Handle to dest Class GUID. dwDirection - SyncDitection DIRECTION_32_TO_64 - 32bit is the source of information DIRECTION_64_TO_32 - 32bit is the source of information __bNewlyCreated - if the destination is just created. Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { // // Enumerate every key under src and recursively copy that except InProcServer32 // HANDLE hSrcNew; HANDLE hDestNew; OBJECT_ATTRIBUTES Obja; NTSTATUS st= STATUS_SUCCESS; DWORD Index=0; LONGLONG TimeDiff; BOOL bNewlyCreated = FALSE; DWORD ResultLength; UNICODE_STRING UnicodeKeyName; PKEY_NODE_INFORMATION KeyInformation = NULL; BYTE Buff [sizeof(KEY_NODE_INFORMATION) + 256]; DWORD Length = sizeof (Buff); KeyInformation = (PKEY_NODE_INFORMATION)Buff; // // Sync Value first. // //TimeDiff = CmpKeyTimeStamp ( hSrc, hDest ); //if (TimeDiff > 0 || __bNewlyCreated ) { //for newnly created key always merge. if (__bNewlyCreated ) { //for newnly created key always merge. SyncValue ( hSrc, hDest, dwDirection, DEFAULT_FLAG); //LogMsg (hSrc, L"Copy Guid Keys.."); } // // Enumerate all key from the hRemap and delete. // for (Index=0;;Index++) { st = NtEnumerateKey( hSrc, Index, KeyNodeInformation, KeyInformation, Length, &ResultLength ); if (!NT_SUCCESS(st)) break; KeyInformation->Name[KeyInformation->NameLength/2] = UNICODE_NULL; RtlInitUnicodeString( &UnicodeKeyName, KeyInformation->Name ); if (_wcsnicmp (KeyInformation->Name, L"InprocServer32", 14) == 0 ) //Skip Inproc server continue; InitializeObjectAttributes (&Obja, &UnicodeKeyName, OBJ_CASE_INSENSITIVE, hSrc, NULL ); // // Open source key on the Source Side; // st = NtOpenKey (&hSrcNew, KEY_ALL_ACCESS, &Obja); if (!NT_SUCCESS(st)) continue; if (_wcsnicmp (KeyInformation->Name, L"InprocHandler32", 15) == 0 ) {//Check InprocHandler if (!ReflectInprocHandler32KeyByHandle (hSrcNew)) { NtClose (hSrcNew); continue; } } // // Create or open the key on the dest side. // InitializeObjectAttributes (&Obja, &UnicodeKeyName, OBJ_CASE_INSENSITIVE, hDest, NULL ); bNewlyCreated = FALSE; st = NtOpenKey (&hDestNew, KEY_ALL_ACCESS, &Obja); if (!NT_SUCCESS(st)) { // // Try to create the key here // st = NtCreateKey( &hDestNew, KEY_ALL_ACCESS, &Obja, 0, NULL , REG_OPTION_NON_VOLATILE, NULL ); if (!NT_SUCCESS(st)) { NtClose (hSrcNew); continue; } bNewlyCreated = TRUE; UpdateKeyTag ( hDestNew, TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE ); } // // Sync only when Key is created. // SyncGuidKey ( hSrcNew, hDestNew, dwDirection, bNewlyCreated ); NtClose (hSrcNew); NtClose (hDestNew); } return TRUE; } BOOL SyncKeysOnBoot ( ) /*++ Routine Description: Sync Certain Keys on Boot. We don't have any particular list or way to figure it out what need to be synced but this can be extended as request comes. Arguments: None. Return Value: TRUE on success. FALSE otherwise. --*/ { // // Sync some setup information here. // HKEY hSrc; HKEY hDest; BOOL bRet = FALSE; if ( (hSrc = OpenNode (L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion")) == NULL) return FALSE; if ( (hDest = OpenNode (L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion")) == NULL) { NtClose (hSrc); return FALSE; } bRet = SyncValue ( hSrc, hDest, DIRECTION_64_TO_32, DONT_DELETE_DEST_VALUEKEY ); NtClose (hSrc); NtClose (hDest); return bRet; } BOOL Wow64SyncCLSID () /*++ Routine Description: Synchronize CLSID on the machine hive. Algorithm: 1. Enumerate all guid on 64bit side, if the guid has the local server and the other side don't have the guid, sync this. 2. Apply the same rule for 32bit side as well. 3. This is only applicable for machine hives only. 4. This function will run at the end of setup once to sync some guid. Arguments: None. Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { // // Enumerate every key under src and recursively copy that except InProcServer32 // HANDLE hSrc; HANDLE hSrcTemp; HANDLE hSrcNew; HANDLE hDestNew; OBJECT_ATTRIBUTES Obja; WCHAR Path [256]; NTSTATUS st= STATUS_SUCCESS; DWORD Index=0; DWORD ResultLength; UNICODE_STRING UnicodeKeyName; PKEY_NODE_INFORMATION KeyInformation = NULL; BYTE Buff [sizeof(KEY_NODE_INFORMATION) + 256]; DWORD Length = sizeof (Buff); DWORD dwDirection = DIRECTION_64_TO_32; KeyInformation = (PKEY_NODE_INFORMATION)Buff; for (;;) { if ( dwDirection == DIRECTION_64_TO_32 ) hSrc = OpenNode (L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\CLSID"); else hSrc = OpenNode (L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Wow6432Node\\CLSID"); // // Enumerate all key from the hRemap and delete. // for (Index=0;;Index++) { st = NtEnumerateKey( hSrc, Index, KeyNodeInformation, KeyInformation, Length, &ResultLength ); if (!NT_SUCCESS(st)) break; KeyInformation->Name[KeyInformation->NameLength/2] = UNICODE_NULL; wcscpy (Path, KeyInformation->Name); wcscat ( Path,L"\\LocalServer32"); RtlInitUnicodeString( &UnicodeKeyName, Path ); InitializeObjectAttributes (&Obja, &UnicodeKeyName, OBJ_CASE_INSENSITIVE, hSrc, NULL ); // // Open source key on the Source Side; // st = NtOpenKey (&hSrcTemp, KEY_READ, &Obja); if (!NT_SUCCESS(st)) { // Local Server Key doesn't exist wcscpy (Path, KeyInformation->Name); wcscat ( Path,L"\\AppID"); RtlInitUnicodeString( &UnicodeKeyName, Path ); InitializeObjectAttributes (&Obja, &UnicodeKeyName, OBJ_CASE_INSENSITIVE, hSrc, NULL ); st = NtOpenKey (&hSrcTemp, KEY_READ, &Obja); if (!NT_SUCCESS(st)) // AppID Key doesn't exist continue; else NtClose (hSrcTemp); } else NtClose (hSrcTemp); // // Check if the guid exists on the other side, if so continue. // if ( dwDirection == DIRECTION_64_TO_32 ) wcscpy (Path,L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Wow6432Node\\CLSID\\"); else wcscpy (Path,L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\CLSID\\"); wcscat (Path,KeyInformation->Name ); hSrcTemp = OpenNode (Path); if (hSrcTemp != NULL ) { NtClose (hSrcTemp ); continue; } // // Create or open the key on the dest side. // if ( !CreateNode (Path)) continue; if ( (hDestNew = OpenNode (Path))==NULL) continue; UpdateKeyTag ( hDestNew, TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE ); //Mark the key as reflected. RtlInitUnicodeString( &UnicodeKeyName, KeyInformation->Name ); InitializeObjectAttributes (&Obja, &UnicodeKeyName, OBJ_CASE_INSENSITIVE, hSrc, NULL ); st = NtOpenKey (&hSrcNew, KEY_ALL_ACCESS, &Obja); if (!NT_SUCCESS(st)) { NtClose (hDestNew); continue; } SyncGuidKey ( hSrcNew, hDestNew, dwDirection, 1); NtClose (hSrcNew); NtClose (hDestNew); } //for-loop enumeration all guids NtClose ( hSrc ); if (DIRECTION_32_TO_64 == dwDirection) break; if (dwDirection == DIRECTION_64_TO_32 ) dwDirection = DIRECTION_32_TO_64; } //for loop for direction SyncKeysOnBoot (); //sync some special value keys return TRUE; } VOID PatchPathOnValueKey ( ULONG DataSize, ULONG Type, WCHAR *Data, WCHAR *RetDataBuff, ULONG *pCorrectDataSize ) /*++ Routine Description: Patch the value key while writing on the 32bit side. Arguments: DataSize - Size of data in byte in the buffer. Type - registry value type. Data - data buffer. RetDataBuffer - will contain the patched value. pCorrectDataSide - Will have the updated size. Return Value: TRUE if the function succeed. FALSE otherwise. --*/ { WCHAR ThunkData[256]; PWCHAR pCorrectData = (PWCHAR)Data; *pCorrectDataSize = DataSize; // // thunk %ProgramFiles% ==> %ProgramFiles(x86)% // %commonprogramfiles% ==> %commonprogramfiles(x86)% // if (DataSize < ( sizeof (ThunkData) - 10) && (Type == REG_SZ || Type == REG_EXPAND_SZ ) ) { //(x86)==>10 byte // // do the thunking here. // PWCHAR p; PWCHAR t; memcpy ( (PBYTE ) &ThunkData[0], (PBYTE)Data, DataSize); ThunkData [DataSize/sizeof (WCHAR) ] = UNICODE_NULL; // make sure NULL terminated if ( (p = wcsistr (ThunkData, L"%ProgramFiles%" )) != NULL ){ p +=13; //skip at the end of %ProgramFiles } else if ( (p = wcsistr (ThunkData, L"%commonprogramfiles%")) != NULL ){ p +=19; //skip at the end of %commonprogramfiles } if (p) { t = pCorrectData + (p - ThunkData); wcscpy(p, L"(x86)"); //(x86) wcscat(p, t); //copy rest of the string pCorrectData = ThunkData; *pCorrectDataSize += sizeof (L"(x86)"); } } //if if (DataSize < ( _MAX_PATH if ( pCorrectData == ThunkData ) memcpy ( RetDataBuff, pCorrectData, *pCorrectDataSize ); } BOOL Wow64RegDeleteKey ( HKEY hBase, WCHAR *SubKey ) /*++ Routine Description: Delete mirror Key. Arguments: hBase - handle to the base key. SubKey - Name of the subkey to be deleted. Return Value: TRUE if the key is on the list of reflection. FALSE otherwise. --*/ { // // 1. Get the complete path to base. // 2. Get Check if the key exist on the reflection list. // 3. Delete the mirror. // WCHAR SrcNode[WOW64_MAX_PATH]; WCHAR KeyName[WOW64_MAX_PATH]; PWCHAR pCLSID; BOOL bSpecialNode = FALSE; DWORD dwLen = WOW64_MAX_PATH; HKEY hRemap; DWORD dwDirection; NTSTATUS St; DWORD AttributeMirrorKey; if (!bReflectorStatusOn) return TRUE; //reflector isn't enable yet. if ( hBase == NULL) wcscpy ( SrcNode, SubKey); else if (!HandleToKeyName ( hBase, SrcNode, &dwLen )) return FALSE; if (SubKey != NULL && hBase != NULL) { // wow64 will call with null subkey if (*SubKey != L'\\') wcscat (SrcNode, L"\\"); wcscat (SrcNode, SubKey ); } // // If it's guid then dest mustnot have InprocServer. // /* pCLSID = wcsistr (SrcNode, L"\\CLSID\\{"); if ( pCLSID != NULL ) { HKEY hKeyTemp; wcscpy (KeyName, SrcNode ); pCLSID = &KeyName[(DWORD)(pCLSID - SrcNode)]; pCLSID +=7; // point start of guid { // Sanity Check and will be good enough???? if (!( pCLSID[9] != L'-' || pCLSID[14] != L'-' || pCLSID[19] != L'-' || pCLSID[24] != L'-' || pCLSID[37] != L'}' ) ) { //DbgPrint ("\nTrying to sync GUID %S", SrcName); pCLSID +=38; wcscpy (pCLSID, L"\\InprocServer32"); hKeyTemp = OpenNode (KeyName); if (hKeyTemp != NULL ) { MyNtClose (hKeyTemp); return TRUE; // Shouldn't detele InprocSrver32 } wcscpy (pCLSID, L"\\InprocHandler32"); hKeyTemp = OpenNode (KeyName); if (hKeyTemp != NULL ) { MyNtClose (hKeyTemp); return TRUE; // Shouldn't delete InprocHandler } } // if initial guid check succeed } // if \CLSID\{ is there */ // // The other Key has already been deleted. You can delete this or wait. // if ( TaggedKeyForDelete (SrcNode) ) { DWORD Attrib1 = 0; QueryKeyTag (hBase, &Attrib1); //*** finetune the rule remove key only with reflected tag. //if (!( (Attrib1 & TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE) || // (AttributeMirrorKey & TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE) )) // reflector touched this Key // return TRUE; // One key must have reflected tag to be deleted. if (!(Attrib1 & TAG_KEY_ATTRIBUTE_REFLECTOR_WRITE)) return TRUE; // the isn't tagged as reflected. } // // Delete the key here // St = NtDeleteKey( hBase ); return TRUE; // // Check for existamce? // } BOOL Wow64ReflectSecurity ( HKEY SrcKey, HKEY DestKey ) /*++ Routine Description: Copy security attribute from SrcKey to DestKey. Arguments: SrcKey - Handle to a key.. DestKey - handle to the destination key. Return Value: TRUE if operation succeeded. FALSE otherwise. --*/ { NTSTATUS Status; PSECURITY_DESCRIPTOR SD; BYTE Buffer[2048]; // reflector only manages general purpose keys and will have smaller ACL LONG Ret, Len; LONG BufferLen = sizeof (Buffer); DWORD Count = 0; SD = (PSECURITY_DESCRIPTOR)Buffer; Len = BufferLen; Status = NtQuerySecurityObject( SrcKey, DACL_SECURITY_INFORMATION, SD, Len, &Len ); if ( NT_SUCCESS (Status )) Status = NtSetSecurityObject( DestKey, DACL_SECURITY_INFORMATION, SD ); Len = BufferLen; Status = NtQuerySecurityObject( SrcKey, GROUP_SECURITY_INFORMATION, SD, Len, &Len ); if ( NT_SUCCESS (Status )) Status = NtSetSecurityObject( DestKey, GROUP_SECURITY_INFORMATION, SD ); Len = BufferLen; Status = NtQuerySecurityObject( SrcKey, OWNER_SECURITY_INFORMATION, SD, Len, &Len ); if ( NT_SUCCESS (Status )) Status = NtSetSecurityObject( DestKey, OWNER_SECURITY_INFORMATION, SD ); Len = BufferLen; Status = NtQuerySecurityObject( SrcKey, SACL_SECURITY_INFORMATION, SD, Len, &Len ); if ( NT_SUCCESS (Status )) Status = NtSetSecurityObject( DestKey, SACL_SECURITY_INFORMATION, SD ); return TRUE; } BOOL IsOnReflectionByHandle ( HKEY KeyHandle ) /*++ Routine Description: Check if the key specified by a handle sit on the list of keys of reflection. Arguments: KeyHandle - Handle to a key.. Return Value: TRUE if the key sit on the the list of reflection. FALSE otherwise. --*/ { WCHAR SrcNode[WOW64_MAX_PATH]; DWORD dwLen = WOW64_MAX_PATH; if (!bReflectorStatusOn) return FALSE; //reflector isn't enable yet. if ( KeyHandle == NULL) return FALSE; else if (!HandleToKeyName ( KeyHandle, SrcNode, &dwLen )) return FALSE; return IsOnReflectionList (SrcNode); } HKEY Wow64OpenRemappedKeyOnReflection ( HKEY SrcKey ) /*++ Routine Description: Called from advapi to get an handle to remapped key that is on reflection list. Arguments: SrcKey - Handle to a key.. Return Value: Valid handle to the reflected key. NULL if the function fails. --*/ { PWCHAR DestNode; PWCHAR SrcNode; BOOL bSpecialNode = FALSE; DWORD dwLen = WOW64_MAX_PATH; HKEY hRemap; NTSTATUS St; DestNode = RegRemapAlloc (WOW64_MAX_PATH); SrcNode = RegRemapAlloc (WOW64_MAX_PATH); if ( NULL == DestNode || NULL == SrcNode ) { RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; } if (!bReflectorStatusOn) { RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; //reflector isn't enable yet. } if ( SrcKey == NULL) { RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; } else if (!HandleToKeyName ( SrcKey, SrcNode, &dwLen )) { RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; } if ( !IsOnReflectionList (SrcNode)) { RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; } if (wcsistr (SrcNode, L"Wow6432Node") != NULL ) { Map32bitTo64bitKeyName ( SrcNode, DestNode ); } else { Map64bitTo32bitKeyName ( SrcNode, DestNode ); } // // check if both are the same // if (_wcsicmp ( SrcNode, DestNode ) == 0) { RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; //source and destination is the same } // // Must check the special case, Like Installer/file association.... // if ( IsExemptReflection ( SrcNode )) { RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; } if ( (hRemap = OpenNode (DestNode) ) == NULL ){ RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return NULL; } RegRemapFree ( DestNode ); RegRemapFree ( SrcNode ); return hRemap; } BOOL Wow64InitRegistry( DWORD dwFlag ) /*++ Routine Description: Called from advapi initialization code [possibly from RegInitialize @base\screg\winreg\client\init.c]. This initialize critical section for wow64 registry access. Arguments: dwFlag - No uses at this time, might add functionality later, like who called, AdvAPi32.dll or Wow64.dll so that different thing can be done if needed in the future. Return Value: TRUE if wow64 section can be initialized properly. FALSE otherwise. --*/ { return InitHandleTable (); //Initialize the handle table that also initialize critical section. } BOOL Wow64CloseRegistry( DWORD dwFlag ) /*++ Routine Description: Called from advapi unload code [possibly from RegInitialize @base\screg\winreg\client\init.c]. This cleanup some resources like critical section CleanUp. Arguments: dwFlag - No uses at this time, might add functionality later, like who called, AdvAPi32.dll or Wow64.dll so that different thing can be done if needed in the future. Return Value: TRUE if wow64 section has been cleaned up properly properly. FALSE otherwise. --*/ { // // If there is any key to close please do that. // WOW64_HANDLE *pList; DWORD i,k, OpenHandle=0; bReflectorStatusOn = FALSE; for (i=0;i