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.
1976 lines
57 KiB
1976 lines
57 KiB
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
regredir.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the APis to redirect 32bit registry calls. All 32bit wow process must
|
|
use following set of wowregistry APIs to manipulate registry so that 32-bit and 64-bit registry
|
|
can co exist in the same system registry.
|
|
|
|
Some functionality hasn't been optimized yet. After successful implementation those need to
|
|
be optimized.
|
|
|
|
Author:
|
|
|
|
ATM Shafiqul Khalid (askhalid) 15-Oct-1999
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <ntregapi.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "regremap.h"
|
|
#include "wow64reg.h"
|
|
#include "wow64reg\reflectr.h"
|
|
|
|
//#include "wow64.h"
|
|
|
|
BOOL
|
|
IsAccessDeniedOnKeyByHandle (
|
|
HANDLE hKey,
|
|
DWORD *FilteredAccess
|
|
);
|
|
|
|
PVOID
|
|
Wow64AllocateTemp(
|
|
SIZE_T Size
|
|
);
|
|
|
|
//#define WOW64_LOG_REGISTRY
|
|
#ifdef WOW64_LOG_REGISTRY
|
|
WCHAR TempBuff[MAX_PATH];
|
|
DWORD TempLen = MAX_PATH;
|
|
#endif
|
|
|
|
#ifdef LOG_REGISTRY
|
|
|
|
void
|
|
LogMsgKeyHandle (
|
|
char *str,
|
|
HANDLE hKey,
|
|
DWORD res
|
|
)
|
|
{
|
|
WCHAR AbsPath[MAX_PATH];
|
|
DWORD Len = MAX_PATH;
|
|
|
|
HandleToKeyName (hKey, AbsPath, &Len);
|
|
LOGPRINT( (ERRORLOG, "\nDEBUG: requested Node:%S Status:%x, Msg:%s", AbsPath, res, str));
|
|
|
|
|
|
};
|
|
#endif
|
|
|
|
BOOL
|
|
ShimRegistryValue (
|
|
HANDLE hKey,
|
|
PWCHAR Value,
|
|
DWORD dwDataSize,
|
|
PWCHAR PatchedValue,
|
|
DWORD *pdwPatchedSize,
|
|
BOOL *bPatched
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Shimming place where registry value will be repatched.
|
|
|
|
Arguments:
|
|
|
|
Handle - Handle to the key that need to be checked for possible shimming.
|
|
|
|
Value - the value that need to repatched.
|
|
|
|
pdwDataSize - size of the data in terms of byte. This also receive new size if
|
|
that changes due to repatching.
|
|
PatchedValue - new value if we patch anything.
|
|
pdwPatchedSize - the new size.
|
|
bPatched - TRUE if the value has been patched, FALUE otherwise.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the operation goes OK.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOL Wow64RegIsPossibleShim ( HANDLE hKey );
|
|
|
|
WCHAR PathName[_MAX_PATH], *t;
|
|
DWORD dwLen = dwDataSize/sizeof (WCHAR);
|
|
|
|
//
|
|
// Check if the handle has special tag for possible shimming.
|
|
//
|
|
|
|
*bPatched = FALSE;
|
|
|
|
//if (dwLen > _MAX_PATH-2) //caller must not pass a pathname bigger than MAX_PATH-6
|
|
// return TRUE;
|
|
|
|
t = (PWCHAR) (Value);
|
|
wcsncpy(PathName, t, dwLen);
|
|
PathName[dwLen] = UNICODE_NULL; //so that string
|
|
PathName[dwLen+1] = UNICODE_NULL; //to remove one check lateron
|
|
|
|
|
|
|
|
|
|
//
|
|
// 1. Shim case one
|
|
//
|
|
// If the key fall under RunKeys and
|
|
// If (x86) is inserted [i.e., Program Files (x86) is present] and
|
|
// the string contains .exe and
|
|
// doesn’t contain “
|
|
// And the path point to a physical file.
|
|
//
|
|
// then add a quote marks.
|
|
//
|
|
|
|
|
|
if ( wcsstr (PathName, L"\\Program Files (x86)\\")) {
|
|
PWCHAR p;
|
|
|
|
if ((p=wcsistr (PathName, L".exe")) != NULL)
|
|
if ((*(p+4) == L' ') || (*(p+4) == UNICODE_NULL) ) {
|
|
|
|
UNICODE_STRING FileNameU;
|
|
HANDLE FileHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
|
|
if (!Wow64RegIsPossibleShim (hKey))
|
|
return TRUE; //return as it is
|
|
|
|
//
|
|
// make sure the file exists on disk.
|
|
//
|
|
*(p+4) = UNICODE_NULL;
|
|
|
|
//
|
|
// Convert the Win32 pathname to an NT pathname
|
|
//
|
|
if (!RtlDosPathNameToNtPathName_U(PathName,
|
|
&FileNameU,
|
|
NULL,
|
|
NULL)) {
|
|
// probably out-of-memory
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Open the file
|
|
//
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FileNameU,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
FILE_READ_DATA,
|
|
&ObjectAttributes,
|
|
&statusBlock,
|
|
FILE_SHARE_READ,
|
|
0);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FileNameU.Buffer);
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// Must shim
|
|
//
|
|
|
|
NtClose (FileHandle);
|
|
*bPatched= TRUE;
|
|
PatchedValue[0] = L'\"';
|
|
wcscpy (&PatchedValue[1], PathName);
|
|
dwLen = wcslen (PatchedValue);
|
|
PatchedValue[dwLen]=L'\"'; // close quote mart
|
|
if (*(p+5)!= UNICODE_NULL) {
|
|
PatchedValue[dwLen+1] = L' '; // additional Space
|
|
//
|
|
// copy rest of the items
|
|
//
|
|
wcscpy (&PatchedValue[dwLen+2], p+5);
|
|
} else
|
|
PatchedValue[dwLen+1]=UNICODE_NULL; // close quote mart
|
|
|
|
*pdwPatchedSize = dwDataSize + 2*sizeof(WCHAR); //size of two double quote
|
|
|
|
}
|
|
}
|
|
} //end of shim case 1.
|
|
|
|
return TRUE;
|
|
}
|
|
//
|
|
// Need to move in the header file
|
|
//
|
|
NTSTATUS
|
|
RemapNtCreateKey(
|
|
OUT PHANDLE phPatchedHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN ULONG TitleIndex,
|
|
IN PUNICODE_STRING Class OPTIONAL,
|
|
IN ULONG CreateOptions,
|
|
OUT PULONG Disposition OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
Wow64NtCreateKey(
|
|
OUT PHANDLE KeyHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN ULONG TitleIndex,
|
|
IN PUNICODE_STRING Class OPTIONAL,
|
|
IN ULONG CreateOptions,
|
|
OUT PULONG Disposition OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
An existing registry key may be opened, or a new one created,
|
|
with NtCreateKey.
|
|
|
|
If the specified key does not exist, an attempt is made to create it.
|
|
For the create attempt to succeed, the new node must be a direct
|
|
child of the node referred to by KeyHandle. If the node exists,
|
|
it is opened. Its value is not affected in any way.
|
|
|
|
Share access is computed from desired access.
|
|
|
|
NOTE:
|
|
|
|
If CreateOptions has REG_OPTION_BACKUP_RESTORE set, then
|
|
DesiredAccess will be ignored. If the caller has the
|
|
privilege SeBackupPrivilege asserted, a handle with
|
|
KEY_READ | ACCESS_SYSTEM_SECURITY will be returned.
|
|
If SeRestorePrivilege, then same but KEY_WRITE rather
|
|
than KEY_READ. If both, then both access sets. If neither
|
|
privilege is asserted, then the call will fail.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Receives a Handle which is used to access the
|
|
specified key in the Registration Database.
|
|
|
|
DesiredAccess - Specifies the access rights desired.
|
|
|
|
ObjectAttributes - Specifies the attributes of the key being opened.
|
|
Note that a key name must be specified. If a Root Directory is
|
|
specified, the name is relative to the root. The name of the
|
|
object must be within the name space allocated to the Registry,
|
|
that is, all names beginning "\Registry". RootHandle, if
|
|
present, must be a handle to "\", or "\Registry", or a key
|
|
under "\Registry".
|
|
|
|
RootHandle must have been opened for KEY_CREATE_SUB_KEY access
|
|
if a new node is to be created.
|
|
|
|
NOTE: Object manager will capture and probe this argument.
|
|
|
|
TitleIndex - Specifies the index of the localized alias for
|
|
the name of the key. The title index specifies the index of
|
|
the localized alias for the name. Ignored if the key
|
|
already exists.
|
|
|
|
Class - Specifies the object class of the key. (To the registry
|
|
this is just a string.) Ignored if NULL.
|
|
|
|
CreateOptions - Optional control values:
|
|
|
|
REG_OPTION_VOLATILE - Object is not to be stored across boots.
|
|
|
|
Disposition - This optional parameter is a pointer to a variable
|
|
that will receive a value indicating whether a new Registry
|
|
key was created or an existing one opened:
|
|
|
|
REG_CREATED_NEW_KEY - A new Registry Key was created
|
|
REG_OPENED_EXISTING_KEY - An existing Registry Key was opened
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS St;
|
|
BOOL bRet = FALSE;
|
|
ULONG Disposition_Temp = 0;
|
|
|
|
try {
|
|
|
|
if ( Disposition == NULL )
|
|
Disposition = &Disposition_Temp;
|
|
|
|
|
|
St = RemapNtCreateKey (
|
|
KeyHandle,
|
|
DesiredAccess,
|
|
ObjectAttributes,
|
|
TitleIndex,
|
|
Class ,
|
|
CreateOptions,
|
|
Disposition
|
|
);
|
|
|
|
|
|
|
|
|
|
//
|
|
// if total failure for thunked key, try if you can pull that key from 64bit hive.
|
|
// May be reflector should be running
|
|
//
|
|
|
|
//
|
|
// 2nd try only if no patch is required.
|
|
// i.e., success with NULL handle returned
|
|
//
|
|
|
|
if ( NT_SUCCESS(St) && *KeyHandle == NULL )
|
|
St = NtCreateKey(
|
|
KeyHandle,
|
|
(~KEY_WOW64_RES) & DesiredAccess,
|
|
ObjectAttributes,
|
|
TitleIndex,
|
|
Class ,
|
|
CreateOptions,
|
|
Disposition
|
|
);
|
|
|
|
#ifdef WOW64_LOG_REGISTRY
|
|
if (NT_SUCCESS(St)) {
|
|
TempLen = MAX_PATH;
|
|
ObjectAttributesToKeyName (
|
|
ObjectAttributes,
|
|
TempBuff,
|
|
TempLen,
|
|
&bRet,
|
|
NULL
|
|
);
|
|
|
|
HandleToKeyName (*KeyHandle, TempBuff, &TempLen);
|
|
if (TempLen > 10 && wcsistr (TempBuff, L"ControlSet"))
|
|
DbgPrint( "\nNtCreateKeyEx OUT:[%S] Status:%x F:%x", TempBuff, DesiredAccess);
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
if (NT_SUCCESS(St))
|
|
Wow64RegSetKeyDirty (*KeyHandle ); // Need some clean/sync up on exit
|
|
|
|
if ( *Disposition == REG_CREATED_NEW_KEY )
|
|
UpdateKeyTag ( *KeyHandle,TAG_KEY_ATTRIBUTE_32BIT_WRITE );
|
|
|
|
} except( NULL, EXCEPTION_EXECUTE_HANDLER){
|
|
|
|
St = GetExceptionCode ();
|
|
}
|
|
return St;
|
|
}
|
|
|
|
NTSTATUS
|
|
Wow64NtDeleteKey(
|
|
IN HANDLE KeyHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A registry key may be marked for delete, causing it to be removed
|
|
from the system. It will remain in the name space until the last
|
|
handle to it is closed.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Specifies the handle of the Key to delete, must have
|
|
been opened for DELETE access.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS St;
|
|
HKEY hRemap;
|
|
|
|
hRemap = Wow64OpenRemappedKeyOnReflection (KeyHandle);
|
|
|
|
St = NtDeleteKey(
|
|
KeyHandle
|
|
);
|
|
if (NT_SUCCESS (St) && ( hRemap != NULL ) )
|
|
Wow64RegDeleteKey (hRemap, NULL);
|
|
|
|
if ( hRemap != NULL )
|
|
NtClose ( hRemap );
|
|
|
|
return St;
|
|
}
|
|
|
|
NTSTATUS
|
|
Wow64NtDeleteValueKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING ValueName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
One of the value entries of a registry key may be removed with this
|
|
call. To remove the entire key, call NtDeleteKey.
|
|
|
|
The value entry with ValueName matching ValueName is removed from the key.
|
|
If no such entry exists, an error is returned.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Specifies the handle of the key containing the value
|
|
entry of interest. Must have been opend for KEY_SET_VALUE access.
|
|
|
|
ValueName - The name of the value to be deleted. NULL is a legal name.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS St;
|
|
|
|
St = NtDeleteValueKey(
|
|
KeyHandle,
|
|
ValueName
|
|
);
|
|
|
|
if (NT_SUCCESS(St))
|
|
Wow64RegSetKeyDirty (KeyHandle ); // Need some clean/sync up on exit
|
|
|
|
return St;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtEnumerateKey(
|
|
IN HANDLE KeyHandle,
|
|
IN ULONG Index,
|
|
IN KEY_INFORMATION_CLASS KeyInformationClass,
|
|
IN PVOID KeyInformation,
|
|
IN ULONG Length,
|
|
IN PULONG ResultLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The sub keys of an open key may be enumerated with NtEnumerateKey.
|
|
|
|
NtEnumerateKey returns the name of the Index'th sub key of the open
|
|
key specified by KeyHandle. The value STATUS_NO_MORE_ENTRIES will be
|
|
returned if value of Index is larger than the number of sub keys.
|
|
|
|
Note that Index is simply a way to select among child keys. Two calls
|
|
to NtEnumerateKey with the same Index are NOT guaranteed to return
|
|
the same results.
|
|
|
|
If KeyInformation is not long enough to hold all requested data,
|
|
STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
|
|
set to the number of bytes actually required.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key whose sub keys are to be enumerated. Must
|
|
be open for KEY_ENUMERATE_SUB_KEY access.
|
|
|
|
Index - Specifies the (0-based) number of the sub key to be returned.
|
|
|
|
KeyInformationClass - Specifies the type of information returned in
|
|
Buffer. One of the following types:
|
|
|
|
KeyBasicInformation - return last write time, title index, and name.
|
|
(see KEY_BASIC_INFORMATION structure)
|
|
|
|
KeyNodeInformation - return last write time, title index, name, class.
|
|
(see KEY_NODE_INFORMATION structure)
|
|
|
|
KeyInformation -Supplies pointer to buffer to receive the data.
|
|
|
|
Length - Length of KeyInformation in bytes.
|
|
|
|
ResultLength - Number of bytes actually written into KeyInformation.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// if the handle is to ISN node then time to enumerate the right one
|
|
//
|
|
|
|
BOOL bRealigned=FALSE;
|
|
PVOID pTempKeyInfo;
|
|
|
|
NTSTATUS RetVal;
|
|
|
|
try {
|
|
|
|
if ( (SIZE_T)(KeyInformation) & (0x07) ) {
|
|
// allocate a buffer with correct alignment, to pass to the Win64 API
|
|
pTempKeyInfo = KeyInformation;
|
|
KeyInformation = Wow64AllocateTemp(Length);
|
|
RtlCopyMemory(KeyInformation, pTempKeyInfo, Length);
|
|
bRealigned = TRUE;
|
|
}
|
|
|
|
RetVal = NtEnumerateKey(
|
|
KeyHandle,
|
|
Index,
|
|
KeyInformationClass,
|
|
KeyInformation,
|
|
Length,
|
|
ResultLength
|
|
);
|
|
|
|
if (!NT_ERROR(RetVal) && bRealigned) {
|
|
RtlCopyMemory((PVOID)pTempKeyInfo, KeyInformation, Length);
|
|
}
|
|
|
|
} except( NULL, EXCEPTION_EXECUTE_HANDLER){
|
|
|
|
RetVal = GetExceptionCode ();
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtEnumerateValueKey(
|
|
IN HANDLE KeyHandle,
|
|
IN ULONG Index,
|
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
|
IN PVOID KeyValueInformation,
|
|
IN ULONG Length,
|
|
IN PULONG ResultLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The value entries of an open key may be enumerated
|
|
with NtEnumerateValueKey.
|
|
|
|
NtEnumerateValueKey returns the name of the Index'th value
|
|
entry of the open key specified by KeyHandle. The value
|
|
STATUS_NO_MORE_ENTRIES will be returned if value of Index is
|
|
larger than the number of sub keys.
|
|
|
|
Note that Index is simply a way to select among value
|
|
entries. Two calls to NtEnumerateValueKey with the same Index
|
|
are NOT guaranteed to return the same results.
|
|
|
|
If KeyValueInformation is not long enough to hold all requested data,
|
|
STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
|
|
set to the number of bytes actually required.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key whose value entries are to be enumerated.
|
|
Must have been opened with KEY_QUERY_VALUE access.
|
|
|
|
Index - Specifies the (0-based) number of the sub key to be returned.
|
|
|
|
KeyValueInformationClass - Specifies the type of information returned
|
|
in Buffer. One of the following types:
|
|
|
|
KeyValueBasicInformation - return time of last write,
|
|
title index, and name. (See KEY_VALUE_BASIC_INFORMATION)
|
|
|
|
KeyValueFullInformation - return time of last write,
|
|
title index, name, class. (See KEY_VALUE_FULL_INFORMATION)
|
|
|
|
KeyValueInformation -Supplies pointer to buffer to receive the data.
|
|
|
|
Length - Length of KeyValueInformation in bytes.
|
|
|
|
ResultLength - Number of bytes actually written into KeyValueInformation.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
return NtEnumerateValueKey(
|
|
KeyHandle,
|
|
Index,
|
|
KeyValueInformationClass,
|
|
KeyValueInformation,
|
|
Length,
|
|
ResultLength
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtFlushKey(
|
|
IN HANDLE KeyHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Changes made by NtCreateKey or NtSetKey may be flushed to disk with
|
|
NtFlushKey.
|
|
|
|
NtFlushKey will not return to its caller until any changed data
|
|
associated with KeyHandle has been written to permanent store.
|
|
|
|
WARNING: NtFlushKey will flush the entire registry tree, and thus will
|
|
burn cycles and I/O.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of open key to be flushed.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
|
|
{
|
|
return NtFlushKey(
|
|
KeyHandle
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtInitializeRegistry(
|
|
IN USHORT BootCondition
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called in 2 situations:
|
|
|
|
1) It is called from SM after autocheck (chkdsk) has
|
|
run and the paging files have been opened. It's function is
|
|
to bind in memory hives to their files, and to open any other
|
|
files yet to be used.
|
|
|
|
2) It is called from SC after the current boot has been accepted
|
|
and the control set used for the boot process should be saved
|
|
as the LKG control set.
|
|
|
|
After this routine accomplishes the work of situation #1 and
|
|
#2, further requests for such work will not be carried out.
|
|
|
|
Arguments:
|
|
|
|
BootCondition -
|
|
|
|
REG_INIT_BOOT_SM - The routine has been called from SM
|
|
in situation #1.
|
|
|
|
REG_INIT_BOOT_SETUP - The routine has been called to perform
|
|
situation #1 work but has been called
|
|
from setup and needs to do some special
|
|
work.
|
|
|
|
REG_INIT_BOOT_ACCEPTED_BASE + Num
|
|
(where 0 < Num < 1000) - The routine has been called
|
|
in situation #2. "Num" is the
|
|
number of the control set
|
|
to which the boot control set
|
|
should be saved.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
STATUS_SUCCESS - it worked
|
|
STATUS_ACCESS_DENIED - the routine has already done the work
|
|
requested and will not do it again.
|
|
|
|
--*/
|
|
{
|
|
return NtInitializeRegistry(
|
|
BootCondition
|
|
);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
Wow64NtNotifyChangeKey(
|
|
IN HANDLE KeyHandle,
|
|
IN HANDLE Event OPTIONAL,
|
|
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
|
IN PVOID ApcContext OPTIONAL,
|
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|
IN ULONG CompletionFilter,
|
|
IN BOOLEAN WatchTree,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
IN BOOLEAN Asynchronous
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Notification of key creation, deletion, and modification may be
|
|
obtained by calling NtNotifyChangeKey.
|
|
|
|
NtNotifyChangeKey monitors changes to a key - if the key or
|
|
subtree specified by KeyHandle are modified, the service notifies
|
|
its caller. It also returns the name(s) of the key(s) that changed.
|
|
All names are specified relative to the key that the handle represents
|
|
(therefore a NULL name represents that key). The service completes
|
|
once the key or subtree has been modified based on the supplied
|
|
CompletionFilter. The service is a "single shot" and therefore
|
|
needs to be reinvoked to watch the key for further changes.
|
|
|
|
The operation of this service begins by opening a key for KEY_NOTIFY
|
|
access. Once the handle is returned, the NtNotifyChangeKey service
|
|
may be invoked to begin watching the values and subkeys of the
|
|
specified key for changes. The first time the service is invoked,
|
|
the BufferSize parameter supplies not only the size of the user's
|
|
Buffer, but also the size of the buffer that will be used by the
|
|
Registry to store names of keys that have changed. Likewise, the
|
|
CompletionFilter and WatchTree parameters on the first call indicate
|
|
how notification should operate for all calls using the supplied
|
|
KeyHandle. These two parameters are ignored on subsequent calls
|
|
to the API with the same instance of KeyHandle.
|
|
|
|
Once a modification is made that should be reported, the Registry will
|
|
complete the service. The names of the files that have changed since
|
|
the last time the service was called will be placed into the caller's
|
|
output Buffer. The Information field of IoStatusBlock will contain
|
|
the number of bytes placed in Buffer, or zero if too many keys have
|
|
changed since the last time the service was called, in which case
|
|
the application must Query and Enumerate the key and sub keys to
|
|
discover changes. The Status field of IoStatusBlock will contain
|
|
the actual status of the call.
|
|
|
|
If Asynchronous is TRUE, then Event, if specified, will be set to
|
|
the Signaled state. If no Event parameter was specified, then
|
|
KeyHandle will be set to the Signaled state. If an ApcRoutine
|
|
was specified, it is invoked with the ApcContext and the address of the
|
|
IoStatusBlock as its arguments. If Asynchronous is FALSE, Event,
|
|
ApcRoutine, and ApcContext are ignored.
|
|
|
|
This service requires KEY_NOTIFY access to the key that was
|
|
actually modified
|
|
|
|
The notify "session" is terminated by closing KeyHandle.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle-- Supplies a handle to an open key. This handle is
|
|
effectively the notify handle, because only one set of
|
|
notify parameters may be set against it.
|
|
|
|
Event - An optional handle to an event to be set to the
|
|
Signaled state when the operation completes.
|
|
|
|
ApcRoutine - An optional procedure to be invoked once the
|
|
operation completes. For more information about this
|
|
parameter see the NtReadFile system service description.
|
|
|
|
If PreviousMode == Kernel, this parameter is an optional
|
|
pointer to a WORK_QUEUE_ITEM to be queued when the notify
|
|
is signaled.
|
|
|
|
ApcContext - A pointer to pass as an argument to the ApcRoutine,
|
|
if one was specified, when the operation completes. This
|
|
argument is required if an ApcRoutine was specified.
|
|
|
|
If PreviousMode == Kernel, this parameter is an optional
|
|
WORK_QUEUE_TYPE describing the queue to be used. This argument
|
|
is required if an ApcRoutine was specified.
|
|
|
|
IoStatusBlock - A variable to receive the final completion status.
|
|
For more information about this parameter see the NtCreateFile
|
|
system service description.
|
|
|
|
CompletionFilter -- Specifies a set of flags that indicate the
|
|
types of operations on the key or its value that cause the
|
|
call to complete. The following are valid flags for this parameter:
|
|
|
|
REG_NOTIFY_CHANGE_NAME -- Specifies that the call should be
|
|
completed if a subkey is added or deleted.
|
|
|
|
REG_NOTIFY_CHANGE_ATTRIBUTES -- Specifies that the call should
|
|
be completed if the attributes (e.g.: ACL) of the key or
|
|
any subkey are changed.
|
|
|
|
REG_NOTIFY_CHANGE_LAST_SET -- Specifies that the call should be
|
|
completed if the lastWriteTime of the key or any of its
|
|
subkeys is changed. (Ie. if the value of the key or any
|
|
subkey is changed).
|
|
|
|
REG_NOTIFY_CHANGE_SECURITY -- Specifies that the call should be
|
|
completed if the security information (e.g. ACL) on the key
|
|
or any subkey is changed.
|
|
|
|
WatchTree -- A BOOLEAN value that, if TRUE, specifies that all
|
|
changes in the subtree of this key should also be reported.
|
|
If FALSE, only changes to this key, its value, and its immediate
|
|
subkeys (but not their values nor their subkeys) are reported.
|
|
|
|
Buffer -- A variable to receive the name(s) of the key(s) that
|
|
changed. See REG_NOTIFY_INFORMATION.
|
|
|
|
BufferSize -- Specifies the length of Buffer.
|
|
|
|
Asynchronous -- If FALSE, call will not return until
|
|
complete (synchronous) if TRUE, call may return STATUS_PENDING.
|
|
|
|
Obs:
|
|
Since NtNotifyChangeMultipleKeys, this routine is kept only for bacwards compatibility
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
|
|
return NtNotifyChangeKey(
|
|
KeyHandle,
|
|
Event ,
|
|
ApcRoutine ,
|
|
ApcContext ,
|
|
IoStatusBlock,
|
|
CompletionFilter,
|
|
WatchTree,
|
|
Buffer,
|
|
BufferSize,
|
|
Asynchronous
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtNotifyChangeMultipleKeys(
|
|
IN HANDLE MasterKeyHandle,
|
|
IN ULONG Count,
|
|
IN OBJECT_ATTRIBUTES SlaveObjects[],
|
|
IN HANDLE Event OPTIONAL,
|
|
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
|
IN PVOID ApcContext OPTIONAL,
|
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|
IN ULONG CompletionFilter,
|
|
IN BOOLEAN WatchTree,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
IN BOOLEAN Asynchronous
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Notificaion of creation, deletion and modification on multiple keys
|
|
may be obtained with NtNotifyChangeMultipleKeys.
|
|
|
|
NtNotifyMultipleKeys monitors changes to any of the MasterKeyHandle
|
|
or one of SlaveObjects and/or their subtrees, whichever occurs first.
|
|
When an event on these keys is triggered, the notification is considered
|
|
fulfilled, and has to be "armed" again, in order to watch for further
|
|
changes.
|
|
|
|
The mechanism is similar to the one described in NtNotifyChangeKey.
|
|
|
|
The MasterKeyHandle key, give the caller control over the lifetime
|
|
of the notification. The notification will live as long as the caller
|
|
keeps the MasterKeyHandle open, or an event is triggered.
|
|
|
|
The caller doesn't have to open the SlaveKeys. He will provide the
|
|
routine with an array of OBJECT_ATTRIBUTES, describing the slave objects.
|
|
The routine will open the objects, and ensure keep a reference on them
|
|
untill the back-end side will close them.
|
|
|
|
The notify "session" is terminated by closing MasterKeyHandle.
|
|
|
|
Obs:
|
|
For the time being, the routine supports only one slave object. When more
|
|
than one slave object is provided, the routine will signal an error of
|
|
STATUS_INVALID_PARAMETER.
|
|
However, the interface is designed for future enhancements (taking an
|
|
array of slave objects), that may be provided with future versions(w2001).
|
|
|
|
When no slave object is supplied (i.e. Count == 0) we have the identical
|
|
behavior as for NtNotifyChangeKey.
|
|
|
|
Arguments:
|
|
|
|
MasterKeyHandle - Supplies a handle to an open key. This handle is
|
|
the "master handle". It has control overthe lifetime of the
|
|
notification.
|
|
|
|
Count - Number of slave objects. For the time being, this should be 1
|
|
|
|
SlaveObjects - Array of slave objects. Only the attributes of the
|
|
objects are provided, so the caller doesn't have to take care
|
|
of them.
|
|
|
|
Event,ApcRoutine,ApcContext,IoStatusBlock,CompletionFilter,WatchTree,
|
|
Buffer,BufferSize,Asynchronous - same as for NtNotifyChangeKey
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
|
|
{
|
|
return NtNotifyChangeMultipleKeys(
|
|
MasterKeyHandle,
|
|
Count,
|
|
SlaveObjects,
|
|
Event,
|
|
ApcRoutine,
|
|
ApcContext,
|
|
IoStatusBlock,
|
|
CompletionFilter,
|
|
WatchTree,
|
|
Buffer,
|
|
BufferSize,
|
|
Asynchronous
|
|
);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
Wow64NtOpenKey(
|
|
OUT PHANDLE KeyHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A registry key which already exists may be opened with NtOpenKey.
|
|
|
|
Share access is computed from desired access.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Receives a Handle which is used to access the
|
|
specified key in the Registration Database.
|
|
|
|
DesiredAccess - Specifies the access rights desired.
|
|
|
|
ObjectAttributes - Specifies the attributes of the key being opened.
|
|
Note that a key name must be specified. If a Root Directory
|
|
is specified, the name is relative to the root. The name of
|
|
the object must be within the name space allocated to the
|
|
Registry, that is, all names beginning "\Registry". RootHandle,
|
|
if present, must be a handle to "\", or "\Registry", or a
|
|
key under "\Registry". If the specified key does not exist, or
|
|
access requested is not allowed, the operation will fail.
|
|
|
|
NOTE: Object manager will capture and probe this argument.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS St;
|
|
|
|
try {
|
|
|
|
St = OpenIsnNodeByObjectAttributes (
|
|
ObjectAttributes,
|
|
DesiredAccess,
|
|
KeyHandle );
|
|
|
|
|
|
if ( NT_SUCCESS(St) && (*KeyHandle == NULL) ) { //should follow the normal route
|
|
|
|
St = NtOpenKey(
|
|
KeyHandle,
|
|
(~KEY_WOW64_RES) & DesiredAccess,
|
|
ObjectAttributes
|
|
);
|
|
}
|
|
|
|
#ifdef WOW64_LOG_REGISTRY
|
|
if (NT_SUCCESS(St)) {
|
|
TempLen = MAX_PATH;
|
|
ObjectAttributesToKeyName (
|
|
ObjectAttributes,
|
|
TempBuff,
|
|
TempLen,
|
|
&bRet,
|
|
NULL
|
|
);
|
|
|
|
HandleToKeyName (*KeyHandle, TempBuff, &TempLen);
|
|
if (TempLen > 10 && wcsistr (TempBuff, L"ControlSet"))
|
|
DbgPrint( "\nNtOpenKeyEx OUT:[%S] Status:%x F:%x", TempBuff, St, DesiredAccess);
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
} except( NULL, EXCEPTION_EXECUTE_HANDLER){
|
|
|
|
St = GetExceptionCode ();
|
|
}
|
|
|
|
return St;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
Wow64NtQueryKey(
|
|
IN HANDLE KeyHandle,
|
|
IN KEY_INFORMATION_CLASS KeyInformationClass,
|
|
IN PVOID KeyInformation,
|
|
IN ULONG Length,
|
|
IN PULONG ResultLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Data about the class of a key, and the numbers and sizes of its
|
|
children and value entries may be queried with NtQueryKey.
|
|
|
|
If KeyValueInformation is not long enough to hold all requested data,
|
|
STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
|
|
set to the number of bytes actually required.
|
|
|
|
NOTE: The returned lengths are guaranteed to be at least as
|
|
long as the described values, but may be longer in
|
|
some circumstances.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key to query data for. Must have been
|
|
opened for KEY_QUERY_KEY access.
|
|
|
|
KeyInformationClass - Specifies the type of information
|
|
returned in Buffer. One of the following types:
|
|
|
|
KeyBasicInformation - return last write time, title index, and name.
|
|
(See KEY_BASIC_INFORMATION)
|
|
|
|
KeyNodeInformation - return last write time, title index, name, class.
|
|
(See KEY_NODE_INFORMATION)
|
|
|
|
KeyFullInformation - return all data except for name and security.
|
|
(See KEY_FULL_INFORMATION)
|
|
|
|
KeyInformation -Supplies pointer to buffer to receive the data.
|
|
|
|
Length - Length of KeyInformation in bytes.
|
|
|
|
ResultLength - Number of bytes actually written into KeyInformation.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
BOOL bRealigned=FALSE;
|
|
PVOID pTempKeyInfo;
|
|
|
|
NTSTATUS RetVal;
|
|
|
|
try {
|
|
|
|
if ( (SIZE_T)(KeyInformation) & (0x07) ) {
|
|
// allocate a buffer with correct alignment, to pass to the Win64 API
|
|
pTempKeyInfo = KeyInformation;
|
|
KeyInformation = Wow64AllocateTemp(Length);
|
|
RtlCopyMemory(KeyInformation, pTempKeyInfo, Length);
|
|
bRealigned = TRUE;
|
|
}
|
|
|
|
RetVal = NtQueryKey(
|
|
KeyHandle,
|
|
KeyInformationClass,
|
|
KeyInformation,
|
|
Length,
|
|
ResultLength
|
|
);
|
|
|
|
if (!NT_ERROR(RetVal) && bRealigned) {
|
|
RtlCopyMemory((PVOID)pTempKeyInfo, KeyInformation, Length);
|
|
}
|
|
|
|
} except( NULL, EXCEPTION_EXECUTE_HANDLER){
|
|
|
|
RetVal = GetExceptionCode ();
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtQueryValueKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING ValueName,
|
|
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
|
IN PVOID KeyValueInformation,
|
|
IN ULONG Length,
|
|
IN PULONG ResultLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The ValueName, TitleIndex, Type, and Data for any one of a key's
|
|
value entries may be queried with NtQueryValueKey.
|
|
|
|
If KeyValueInformation is not long enough to hold all requested data,
|
|
STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
|
|
set to the number of bytes actually required.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key whose value entries are to be
|
|
enumerated. Must be open for KEY_QUERY_VALUE access.
|
|
|
|
Index - Specifies the (0-based) number of the sub key to be returned.
|
|
|
|
ValueName - The name of the value entry to return data for.
|
|
|
|
KeyValueInformationClass - Specifies the type of information
|
|
returned in KeyValueInformation. One of the following types:
|
|
|
|
KeyValueBasicInformation - return time of last write, title
|
|
index, and name. (See KEY_VALUE_BASIC_INFORMATION)
|
|
|
|
KeyValueFullInformation - return time of last write, title
|
|
index, name, class. (See KEY_VALUE_FULL_INFORMATION)
|
|
|
|
KeyValueInformation -Supplies pointer to buffer to receive the data.
|
|
|
|
Length - Length of KeyValueInformation in bytes.
|
|
|
|
ResultLength - Number of bytes actually written into KeyValueInformation.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
TMP: The IopQueryRegsitryValues() routine in the IO system assumes
|
|
STATUS_OBJECT_NAME_NOT_FOUND is returned if the value being queried
|
|
for does not exist.
|
|
|
|
--*/
|
|
{
|
|
BOOL bRealigned=FALSE;
|
|
PVOID pTempKeyInfo;
|
|
|
|
NTSTATUS RetVal;
|
|
|
|
try {
|
|
|
|
if ( (SIZE_T)(KeyValueInformation) & (0x07) ) {
|
|
// allocate a buffer with correct alignment, to pass to the Win64 API
|
|
pTempKeyInfo = KeyValueInformation;
|
|
KeyValueInformation = Wow64AllocateTemp(Length);
|
|
RtlCopyMemory(KeyValueInformation, pTempKeyInfo, Length);
|
|
bRealigned = TRUE;
|
|
}
|
|
|
|
RetVal = NtQueryValueKey(
|
|
KeyHandle,
|
|
ValueName,
|
|
KeyValueInformationClass,
|
|
KeyValueInformation,
|
|
Length,
|
|
ResultLength
|
|
);
|
|
|
|
if (!NT_ERROR(RetVal) && bRealigned) {
|
|
RtlCopyMemory((PVOID)pTempKeyInfo, KeyValueInformation, Length);
|
|
}
|
|
|
|
} except( NULL, EXCEPTION_EXECUTE_HANDLER){
|
|
|
|
RetVal = GetExceptionCode ();
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtRestoreKey(
|
|
IN HANDLE KeyHandle,
|
|
IN HANDLE FileHandle,
|
|
IN ULONG Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A file in the format created by NtSaveKey may be loaded into
|
|
the system's active registry with NtRestoreKey. An entire subtree
|
|
is created in the active registry as a result. All of the
|
|
data for the new sub-tree, including such things as security
|
|
descriptors, will be read from the source file. The data will
|
|
not be interpreted in any way.
|
|
|
|
This call (unlike NtLoadKey, see below) copies the data. The
|
|
system will NOT be using the source file after the call returns.
|
|
|
|
If the flag REG_WHOLE_HIVE_VOLATILE is specified, a new hive
|
|
can be created. It will be a memory only copy. The restore
|
|
must be done to the root of a hive (e.g. \registry\user\<name>)
|
|
|
|
If the flag is NOT set, then the target of the restore must
|
|
be an existing hive. The restore can be done to an arbitrary
|
|
location within an existing hive.
|
|
|
|
Caller must have SeRestorePrivilege privilege.
|
|
|
|
If the flag REG_REFRESH_HIVE is set (must be only flag) then the
|
|
the Hive will be restored to its state as of the last flush.
|
|
|
|
The hive must be marked NOLAZY_FLUSH, and the caller must have
|
|
TCB privilege, and the handle must point to the root of the hive.
|
|
If the refresh fails, the hive will be corrupt, and the system
|
|
will bugcheck. Notifies are flushed. The hive file will be resized,
|
|
the log will not. If there is any volatile space in the hive
|
|
being refreshed, STATUS_UNSUCCESSFUL will be returned. (It's much
|
|
too obscure a failure to warrant a new error code.)
|
|
|
|
If the flag REG_FORCE_RESTORE is set, the restore operation is done
|
|
even if the KeyHandle has open subkeys by other applications
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - refers to the Key in the registry which is to be the
|
|
root of the new tree read from the disk. This key
|
|
will be replaced.
|
|
|
|
FileHandle - refers to file to restore from, must have read access.
|
|
|
|
Flags - If REG_WHOLE_HIVE_VOLATILE is set, then the copy will
|
|
exist only in memory, and disappear when the machine
|
|
is rebooted. No hive file will be created on disk.
|
|
|
|
Normally, a hive file will be created on disk.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS.
|
|
|
|
|
|
--*/
|
|
{
|
|
return NtRestoreKey(
|
|
KeyHandle,
|
|
FileHandle,
|
|
Flags
|
|
);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtSaveKey(
|
|
IN HANDLE KeyHandle,
|
|
IN HANDLE FileHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A subtree of the active registry may be written to a file in a
|
|
format suitable for use with NtRestoreKey. All of the data in the
|
|
subtree, including such things as security descriptors will be written
|
|
out.
|
|
|
|
Caller must have SeBackupPrivilege privilege.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - refers to the Key in the registry which is the
|
|
root of the tree to be written to disk. The specified
|
|
node will be included in the data written out.
|
|
|
|
FileHandle - a file handle with write access to the target file
|
|
of interest.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS
|
|
|
|
--*/
|
|
{
|
|
return NtSaveKey(
|
|
KeyHandle,
|
|
FileHandle
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtSaveMergedKeys(
|
|
IN HANDLE HighPrecedenceKeyHandle,
|
|
IN HANDLE LowPrecedenceKeyHandle,
|
|
IN HANDLE FileHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Two subtrees of the registry can be merged. The resulting subtree may
|
|
be written to a file in a format suitable for use with NtRestoreKey.
|
|
All of the data in the subtree, including such things as security
|
|
descriptors will be written out.
|
|
|
|
Caller must have SeBackupPrivilege privilege.
|
|
|
|
Arguments:
|
|
|
|
HighPrecedenceKeyHandle - refers to the key in the registry which is the
|
|
root of the HighPrecedence tree. I.e., when a key is present in
|
|
both trees headded by the two keys, the key underneath HighPrecedence
|
|
tree will always prevail. The specified
|
|
node will be included in the data written out.
|
|
|
|
LowPrecedenceKeyHandle - referrs to the key in the registry which is the
|
|
root of the "second choice" tree. Keys from this trees get saved
|
|
when there is no equivalent key in the tree headded by HighPrecedenceKey
|
|
|
|
FileHandle - a file handle with write access to the target file
|
|
of interest.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS
|
|
|
|
--*/
|
|
{
|
|
return NtSaveMergedKeys(
|
|
HighPrecedenceKeyHandle,
|
|
LowPrecedenceKeyHandle,
|
|
FileHandle
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtSetValueKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING ValueName,
|
|
IN ULONG TitleIndex OPTIONAL,
|
|
IN ULONG Type,
|
|
IN PVOID Data,
|
|
IN ULONG DataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A value entry may be created or replaced with NtSetValueKey.
|
|
|
|
If a value entry with a Value ID (i.e. name) matching the
|
|
one specified by ValueName exists, it is deleted and replaced
|
|
with the one specified. If no such value entry exists, a new
|
|
one is created. NULL is a legal Value ID. While Value IDs must
|
|
be unique within any given key, the same Value ID may appear
|
|
in many different keys.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key whose for which a value entry is
|
|
to be set. Must be opened for KEY_SET_VALUE access.
|
|
|
|
ValueName - The unique (relative to the containing key) name
|
|
of the value entry. May be NULL.
|
|
|
|
TitleIndex - Supplies the title index for ValueName. The title
|
|
index specifies the index of the localized alias for the ValueName.
|
|
|
|
Type - The integer type number of the value entry.
|
|
|
|
Data - Pointer to buffer with actual data for the value entry.
|
|
|
|
DataSize - Size of Data buffer.
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
WCHAR ThunkData[_MAX_PATH];
|
|
PWCHAR pCorrectData = (PWCHAR)Data;
|
|
ULONG CorrectDataSize = DataSize;
|
|
BOOL bPatched;
|
|
NTSTATUS St = STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// thunk %ProgramFiles% ==> %ProgramFiles(x86)%
|
|
// %commonprogramfiles% ==> %commonprogramfiles(x86)%
|
|
//
|
|
/*
|
|
if (IsAccessDeniedOnKeyByHandle (KeyHandle)){
|
|
WCHAR PatchedIsnNode[WOW64_MAX_PATH];
|
|
WCHAR AbsPath[WOW64_MAX_PATH];
|
|
DWORD Len = WOW64_MAX_PATH;
|
|
|
|
//
|
|
// Create the key at different Location
|
|
//
|
|
|
|
HandleToKeyName (KeyHandle, PatchedIsnNode, &Len);
|
|
|
|
wcscpy (AbsPath, L"\\REGISTRY\\MACHINE\\SYSTEM");
|
|
wcscat (AbsPath, PatchedIsnNode);
|
|
|
|
KeyHandle = OpenNode (AbsPath);
|
|
if ( NULL == KeyHandle ) {
|
|
CreateNode (AbsPath);
|
|
KeyHandle = OpenNode (AbsPath);
|
|
} //BUGBUG: free opened handle
|
|
DbgPrint ("Reopening Keys at: %S\n", AbsPath);
|
|
|
|
//return STATUS_ACCESS_DENIED;
|
|
}
|
|
*/
|
|
try {
|
|
|
|
if ((DataSize > 0) &&
|
|
(DataSize < ( _MAX_PATH*sizeof (WCHAR) - 10) &&
|
|
((Type == REG_SZ) || (Type == REG_EXPAND_SZ) )) ) { //(x86)==>10 byte
|
|
|
|
PWCHAR p;
|
|
PWCHAR t;
|
|
|
|
//
|
|
// do the thunking here.
|
|
//
|
|
|
|
|
|
memcpy ( (PBYTE ) &ThunkData[0], (PBYTE)Data, DataSize);
|
|
ThunkData [DataSize/sizeof (WCHAR) ] = UNICODE_NULL; // make sure NULL terminated
|
|
|
|
if ( (p = wcsstr (ThunkData, L"%ProgramFiles%" )) != NULL ){
|
|
|
|
p +=13; //skip at the end of %ProgramFiles
|
|
|
|
} else if ( (p = wcsstr (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;
|
|
CorrectDataSize += sizeof (L"(x86)");
|
|
|
|
} else if ( (p=wcsistr (Data, L"\\System32\\")) != NULL) {
|
|
|
|
if (IsOnReflectionByHandle ( KeyHandle ) ) {
|
|
wcsncpy (p, L"\\SysWow64\\",10);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Call additional value patching routine here.
|
|
//
|
|
|
|
ShimRegistryValue (
|
|
KeyHandle,
|
|
pCorrectData, //new data
|
|
CorrectDataSize, //new size
|
|
ThunkData,
|
|
&CorrectDataSize,
|
|
&bPatched
|
|
);
|
|
|
|
if (bPatched ) {
|
|
pCorrectData = ThunkData;
|
|
}
|
|
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
St = GetExceptionCode ();
|
|
}
|
|
|
|
//
|
|
// Check if the operation should proceed. The key might be on access denied list.
|
|
//
|
|
|
|
if (NT_SUCCESS (St)) {
|
|
|
|
St = NtSetValueKey(
|
|
KeyHandle,
|
|
ValueName,
|
|
TitleIndex ,
|
|
Type,
|
|
(PVOID)pCorrectData,
|
|
CorrectDataSize
|
|
);
|
|
|
|
if (NT_SUCCESS(St)) {
|
|
Wow64RegSetKeyDirty (KeyHandle ); // Need some clean/sync up on exit
|
|
}
|
|
}
|
|
|
|
return St;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtLoadKey(
|
|
IN POBJECT_ATTRIBUTES TargetKey,
|
|
IN POBJECT_ATTRIBUTES SourceFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A hive (file in the format created by NtSaveKey) may be linked
|
|
into the active registry with this call. UNLIKE NtRestoreKey,
|
|
the file specified to NtLoadKey will become the actual backing
|
|
store of part of the registry (that is, it will NOT be copied.)
|
|
|
|
The file may have an associated .log file.
|
|
|
|
If the hive file is marked as needing a .log file, and one is
|
|
not present, the call will fail.
|
|
|
|
The name specified by SourceFile must be such that ".log" can
|
|
be appended to it to generate the name of the log file. Thus,
|
|
on FAT file systems, the hive file may not have an extension.
|
|
|
|
Caller must have SeRestorePrivilege privilege.
|
|
|
|
This call is used by logon to make the user's profile available
|
|
in the registry. It is not intended for use doing backup,
|
|
restore, etc. Use NtRestoreKey for that.
|
|
|
|
Arguments:
|
|
|
|
TargetKey - specifies the path to a key to link the hive to.
|
|
path must be of the form "\registry\user\<username>"
|
|
|
|
SourceFile - specifies a file. while file could be remote,
|
|
that is strongly discouraged.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS.
|
|
|
|
--*/
|
|
|
|
{
|
|
return NtLoadKey(TargetKey, SourceFile);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtLoadKey2(
|
|
IN POBJECT_ATTRIBUTES TargetKey,
|
|
IN POBJECT_ATTRIBUTES SourceFile,
|
|
IN ULONG Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A hive (file in the format created by NtSaveKey) may be linked
|
|
into the active registry with this call. UNLIKE NtRestoreKey,
|
|
the file specified to NtLoadKey will become the actual backing
|
|
store of part of the registry (that is, it will NOT be copied.)
|
|
|
|
The file may have an associated .log file.
|
|
|
|
If the hive file is marked as needing a .log file, and one is
|
|
not present, the call will fail.
|
|
|
|
The name specified by SourceFile must be such that ".log" can
|
|
be appended to it to generate the name of the log file. Thus,
|
|
on FAT file systems, the hive file may not have an extension.
|
|
|
|
Caller must have SeRestorePrivilege privilege.
|
|
|
|
This call is used by logon to make the user's profile available
|
|
in the registry. It is not intended for use doing backup,
|
|
restore, etc. Use NtRestoreKey for that.
|
|
|
|
Arguments:
|
|
|
|
TargetKey - specifies the path to a key to link the hive to.
|
|
path must be of the form "\registry\user\<username>"
|
|
|
|
SourceFile - specifies a file. while file could be remote,
|
|
that is strongly discouraged.
|
|
|
|
Flags - specifies any flags that should be used for the load operation.
|
|
The only valid flag is REG_NO_LAZY_FLUSH.
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return NtLoadKey2(
|
|
TargetKey,
|
|
SourceFile,
|
|
Flags
|
|
);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtUnloadKey(
|
|
IN POBJECT_ATTRIBUTES TargetKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Drop a subtree (hive) out of the registry.
|
|
|
|
Will fail if applied to anything other than the root of a hive.
|
|
|
|
Cannot be applied to core system hives (HARDWARE, SYSTEM, etc.)
|
|
|
|
Can be applied to user hives loaded via NtRestoreKey or NtLoadKey.
|
|
|
|
If there are handles open to the hive being dropped, this call
|
|
will fail. Terminate relevent processes so that handles are
|
|
closed.
|
|
|
|
This call will flush the hive being dropped.
|
|
|
|
Caller must have SeRestorePrivilege privilege.
|
|
|
|
Arguments:
|
|
|
|
TargetKey - specifies the path to a key to link the hive to.
|
|
path must be of the form "\registry\user\<username>"
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS.
|
|
|
|
--*/
|
|
|
|
{
|
|
return NtUnloadKey(
|
|
TargetKey
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtSetInformationKey(
|
|
IN HANDLE KeyHandle,
|
|
IN KEY_SET_INFORMATION_CLASS KeySetInformationClass,
|
|
IN PVOID KeySetInformation,
|
|
IN ULONG KeySetInformationLength
|
|
)
|
|
|
|
{
|
|
return NtSetInformationKey(
|
|
KeyHandle,
|
|
KeySetInformationClass,
|
|
KeySetInformation,
|
|
KeySetInformationLength
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtReplaceKey(
|
|
IN POBJECT_ATTRIBUTES NewFile,
|
|
IN HANDLE TargetHandle,
|
|
IN POBJECT_ATTRIBUTES OldFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A hive file may be "replaced" under a running system, such
|
|
that the new file will be the one actually used at next
|
|
boot, with this call.
|
|
|
|
This routine will:
|
|
|
|
Open newfile, and verify that it is a valid Hive file.
|
|
|
|
Rename the Hive file backing TargetHandle to OldFile.
|
|
All handles will remain open, and the system will continue
|
|
to use the file until rebooted.
|
|
|
|
Rename newfile to match the name of the hive file
|
|
backing TargetHandle.
|
|
|
|
.log and .alt files are ignored
|
|
|
|
The system must be rebooted for any useful effect to be seen.
|
|
|
|
Caller must have SeRestorePrivilege.
|
|
|
|
Arguments:
|
|
|
|
NewFile - specifies the new file to use. must not be just
|
|
a handle, since NtReplaceKey will insist on
|
|
opening the file for exclusive access (which it
|
|
will hold until the system is rebooted.)
|
|
|
|
TargetHandle - handle to a registry hive root
|
|
|
|
OldFile - name of file to apply to current hive, which will
|
|
become old hive
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS.
|
|
|
|
--*/
|
|
{
|
|
return NtReplaceKey(
|
|
NewFile,
|
|
TargetHandle,
|
|
OldFile
|
|
);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtQueryMultipleValueKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PKEY_VALUE_ENTRY ValueEntries,
|
|
IN ULONG EntryCount,
|
|
OUT PVOID ValueBuffer,
|
|
IN OUT PULONG BufferLength,
|
|
OUT OPTIONAL PULONG RequiredBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Multiple values of any key may be queried atomically with
|
|
this api.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Supplies the key to be queried.
|
|
|
|
ValueNames - Supplies an array of value names to be queried
|
|
|
|
ValueEntries - Returns an array of KEY_VALUE_ENTRY structures, one for each value.
|
|
|
|
EntryCount - Supplies the number of entries in the ValueNames and ValueEntries arrays
|
|
|
|
ValueBuffer - Returns the value data for each value.
|
|
|
|
BufferLength - Supplies the length of the ValueBuffer array in bytes.
|
|
Returns the length of the ValueBuffer array that was filled in.
|
|
|
|
RequiredBufferLength - if present, Returns the length in bytes of the ValueBuffer
|
|
array required to return all the values of this key.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
return NtQueryMultipleValueKey( KeyHandle,
|
|
ValueEntries,
|
|
EntryCount,
|
|
ValueBuffer,
|
|
BufferLength,
|
|
RequiredBufferLength
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Wow64NtQueryOpenSubKeys(
|
|
IN POBJECT_ATTRIBUTES TargetKey,
|
|
OUT PULONG HandleCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps all the subkeys of the target key that are kept open by some other
|
|
process; Returns the number of open subkeys
|
|
|
|
|
|
Arguments:
|
|
|
|
TargetKey - specifies the path to a key to link the hive to.
|
|
path must be of the form "\registry\user\<username>"
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - values TBS.
|
|
|
|
--*/
|
|
{
|
|
return NtQueryOpenSubKeys( TargetKey, HandleCount );
|
|
}
|
|
|
|
NTSTATUS
|
|
Wow64NtSetSecurityObject (
|
|
IN HANDLE Handle,
|
|
IN SECURITY_INFORMATION SecurityInformation,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to invoke an object's security routine. It
|
|
is used to set the object's security state.
|
|
|
|
Arguments:
|
|
|
|
Handle - Supplies the handle for the object being modified
|
|
|
|
SecurityInformation - Indicates the type of information we are
|
|
interested in setting. e.g., owner, group, dacl, or sacl.
|
|
|
|
SecurityDescriptor - Supplies the security descriptor for the
|
|
object being modified.
|
|
|
|
Return Value:
|
|
|
|
An appropriate NTSTATUS value
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Check if the handle points to a particular key, then if the API succeed
|
|
// Reflect that.
|
|
//
|
|
|
|
NTSTATUS St;
|
|
NTSTATUS Status;
|
|
POBJECT_TYPE_INFORMATION pTypeInfo;
|
|
|
|
|
|
CHAR Buffer[1024];
|
|
pTypeInfo = (POBJECT_TYPE_INFORMATION) Buffer;
|
|
|
|
Status = NtQueryObject(Handle,
|
|
ObjectTypeInformation,
|
|
pTypeInfo,
|
|
sizeof (Buffer),
|
|
NULL
|
|
);
|
|
|
|
St = NtSetSecurityObject (
|
|
Handle,
|
|
SecurityInformation,
|
|
SecurityDescriptor
|
|
);
|
|
|
|
//
|
|
// If NT_SUCCESS (St) && the handle point on to a registry Key set the handle for reflection.
|
|
//
|
|
|
|
if (NT_SUCCESS (St) && NT_SUCCESS (Status)){
|
|
|
|
|
|
if ( _wcsnicmp ( pTypeInfo->TypeName.Buffer, L"Key", 3) == 0)
|
|
Wow64RegSetKeyDirty (Handle); // Need some clean/sync up on exit
|
|
}
|
|
|
|
return St;
|
|
}
|
|
|
|
|