windows-nt/Source/XPSP1/NT/base/wow64/regremap/regmisc.c
2020-09-26 16:20:57 +08:00

1339 lines
35 KiB
C

/*++
Copyright (c) 1999-2001 Microsoft Corporation
Module Name:
regmisc.c
Abstract:
This module implement some function used in the registry redirector.
Author:
ATM Shafiqul Khalid (askhalid) 29-Oct-1999
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <ntregapi.h>
#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_
#include "regremap.h"
#include "wow64reg.h"
ASSERTNAME;
//#define LOG_REGISTRY
const WCHAR IsnNodeListPath[]={WOW64_REGISTRY_SETUP_KEY_NAME};
#define KEY_NAME(x) {x,((sizeof (x) / sizeof (WCHAR))-1)}
typedef struct _REGKEY_LIST {
WCHAR KeyPath[256];
DWORD Len;
} REGKEY_LIST;
//
// Table that will have the list of ISN node. Need to allocate runtime.
//
#define WOW64_ISN_NODE_MAX_NUM 12 // this is internal to wow64 setup might use different size of table
NODETYPE IsnNode[WOW64_ISN_NODE_MAX_NUM]={
{L"\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES"},
{L"\\REGISTRY\\MACHINE\\SOFTWARE"},
{L"\\REGISTRY\\USER\\*\\SOFTWARE\\CLASSES"}, // ISN node table is always upcase.
{L"\\REGISTRY\\USER\\*_CLASSES"},
{L"\\REGISTRY\\MACHINE\\SYSTEM\\TEST"},
{L""}
};
//
// 64bit IE load mail client dll inproc breaking interop functionality.
// The are some Dll get loaded Inproc {L"\\REGISTRY\\MACHINE\\SOFTWARE\\Clients\\mail"}, //Email Client Key
//
// Must keep 32-bit and 64-bit uninstall keys separate to ensure the correct environment
// variables are used for REG_EXPAND_SZ and to make sure we run the correct bitness of rundll32.exe.
// {L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\UnInstall"}, // UnInstall Key
//
REGKEY_LIST ExemptRedirectedKey[]={
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\SystemCertificates"), // Certificate Key
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Services"), // Cryptography Service
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\HCP"), // HelpCenter Key
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\EnterpriseCertificates"), // Enterprise Service
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\MSMQ"), // MSMQ registry
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), // Profiles
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"), // Performance counters
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"), // Spooler Printers
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports"), // Spooler Ports
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Policies"), // policie keys
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies"), //Policy Keys
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager"), //OC Manager Keys
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Software\\Microsoft\\Shared Tools\\MSInfo"), //share MSinfo Key
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"), //Share setup Keys
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\CTF\\TIP"), //CTF\TIP Key
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\CTF\\SystemShared"),
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), //Share fonts
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\RAS"), // RAS keys need to be shared
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Driver Signing"), // Share Driver signing Keys
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Non-Driver Signing"), // Share Driver signing Keys
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Calais\\Current"), // SmartCard subsytem pipe name
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Calais\\Readers"), // SmartCard installed readers
KEY_NAME(L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"), // Share time zone key
KEY_NAME(L""), // Two additional NULL String for additional space.
KEY_NAME(L"")
};
//
// A note about PerfLib... in ntos\config, the init code creates a special
// key called PerfLib\009 and if you call NtOpenKey on that path, it returns
// back HKEY_PERFORMANCE_DATA, not a regular kernel registry handle to
// \\REGISTRY\\MACHINE\\stuff. Instead, HKEY_PERFORMANCE_DATA is intercepted
// in usermode by advapi32.dll. The Counters and Help REG_MULTI_SZ values
// don't really exist - they are synthesized by advapi32 based on the
// contents of the perf*.dat files in system32. This works OK for 32-bit
// advapi32 on WOW64 as advapi opens the *.dat files using NtOpenFile
// with an OBJECT_ATTRIBUTES containing "\SystemRoot\System32\..." which
// doesn't get intercepted by the system32 remapper.
//
PWCHAR
wcsistr(
PWCHAR string1,
PWCHAR string2
)
{
PWCHAR p1;
PWCHAR p2;
if ((NULL == string2) || (NULL == string1))
{
// do whatever wcsstr would do
return wcsstr(string1, string2);
}
while (*string1)
{
for (p1 = string1, p2 = string2;
*p1 && *p2 && towlower(*p1) == towlower(*p2);
++p1, ++p2)
{
// nothing
}
if (!*p2)
{
// we found a match!
return (PWCHAR)string1; // cast away const!
}
++string1;
}
return NULL;
}
PWCHAR
wcsstrWow6432Node (
PWCHAR pSrc
)
{
return wcsistr (pSrc, NODE_NAME_32BIT);
}
PWCHAR
wcsstrWithWildCard (
PWCHAR srcStr,
PWCHAR destIsnNode
)
/*++
Routine Description:
a customised version of wcsstr with wild card support. For example the
substring might have '*' character which can be matched with any key name.
Arguments:
srcStr - The string where the substring need to be searched for.
destIsnNode - the string to search.
Return Value:
TRUE if the operation succeed, FALSE otherwise.
--*/
{
//multiple wildcard isn't allowed?
PWCHAR src = srcStr;
PWCHAR dest = destIsnNode;
PWCHAR p, t;
DWORD count;
for (;;) {
if (*dest == UNICODE_NULL)
return ( *src == UNICODE_NULL)? src : src+1; //source might point to SLASH
if (*src == UNICODE_NULL)
return NULL;
count = wcslen (dest);
if ( ( p = wcschr( dest,'*') ) == NULL ) {
if ( _wcsnicmp (src, dest, count) == 0 ){
//
// xx\Test shouldn't show xx\test345 as an ISN node.
//
if ( src [ count ] != UNICODE_NULL && src [ count ] != L'\\' ) //terminator need tobe NULL or slash
return NULL;
return (*(src+count) != UNICODE_NULL ) ? src+count+1: src+count; // xx\test return pointer at test if dest is xx.
}
else
return NULL;
}
count = (DWORD) (p-dest);
// LOGPRINT( (ERRORLOG, "\nFinding [%S] withing %S, p=%S Val%d",dest, src, p, count ));
if (_wcsnicmp (src, dest, count) !=0) // checking the initial state
return NULL;
//
// need to check *_Classes type ISN Node
//
p++; //skip the wild card
t=src+count;
while ( *t != L'\\' && *t != UNICODE_NULL )
t++;
if ( *p != UNICODE_NULL || *p != L'\\') { //*_Classes form
for ( count=0;*p != L'\\' && *p != UNICODE_NULL; p++, count++)
;
if (_wcsnicmp (p-count, t-count, count) != 0)
return NULL;
}
// LOGPRINT( (ERRORLOG, "\nFinding 2nd[%S] withing %S, p=%S",dest, src, p ));
src = t;
dest = p;
}
return NULL;
}
HKEY
OpenNode (
PWCHAR NodeName
)
/*++
Routine Description:
Open a given key for generic access.
Arguments:
NodeName - name of the key to check.
Return Value:
NULL in case of failure.
Valid handle otherwise.
--*/
{
NTSTATUS st;
HKEY hKey;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING KeyName;
RtlInitUnicodeString (&KeyName, NodeName);
InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
st = NtOpenKey (&hKey, KEY_ALL_ACCESS, &Obja);
if (!NT_SUCCESS(st))
return NULL;
return hKey;
}
VOID
CloseNode (
HANDLE Key
)
{
NtClose (Key);
}
NTSTATUS
IsNodeExist (
PWCHAR NodeName
)
/*++
Routine Description:
Check if the given key exist if not create the key.
Arguments:
NodeName - name of the key to check.
Return Value:
TRUE if the operation succeed, FALSE otherwise.
--*/
{
NTSTATUS st;
HANDLE hKey;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING KeyName;
RtlInitUnicodeString (&KeyName, NodeName);
InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
st = NtOpenKey (&hKey, KEY_READ, &Obja);
if (!NT_SUCCESS(st))
return st;
NtClose (hKey);
//LOGPRINT( (ERRORLOG, "\nValid IsnNode [%S]",NodeName ));
return st;
}
BOOL
CreateNode (
PWCHAR Path
)
/*++
Routine Description:
Create all the node along the path if missing. Called by background
thread working on the setup.
Arguments:
Path - name of path to the key.
Return Value:
TRUE if the operation succeed, FALSE otherwise.
--*/
{
//
// isolate individual nodes and backtrack
//
NTSTATUS st;
HANDLE hKey;
HANDLE hKeyCreate;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING KeyName;
PWCHAR pTrace;
PWCHAR p;
pTrace = Path+wcslen (Path); //pTrace point at the end of path
p=pTrace;
for (;;) {
RtlInitUnicodeString (&KeyName, Path);
InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
st = NtOpenKey (&hKey, KEY_WRITE | KEY_READ, &Obja);
if ( st == STATUS_OBJECT_NAME_NOT_FOUND ) {
//backtrack until you hit the line
while ( *p != L'\\' && p!= Path)
p--;
//LOGPRINT( (ERRORLOG, "\nTest Code[%S]",p ));
if ( p == Path ) break;
*p = UNICODE_NULL;
continue;
}
break;
}
if (!NT_SUCCESS(st)) {
//fixup the string and return
for ( ;p != pTrace;p++ )
if ( *p == UNICODE_NULL) *p=L'\\';
return FALSE;
}
//
// now create key from point p until p hit pTrace
//
while ( p != pTrace ) {
*p = L'\\'; //added the char back
p++; //p will point a non NULL string
RtlInitUnicodeString (&KeyName, p);
InitializeObjectAttributes (&Obja, &KeyName, OBJ_CASE_INSENSITIVE, hKey, NULL );
st = NtCreateKey(
&hKeyCreate,
KEY_WRITE | KEY_READ,
&Obja,
0,
NULL ,
REG_OPTION_NON_VOLATILE,
NULL
);
if (!NT_SUCCESS(st)) {
LOGPRINT( (ERRORLOG, "\nCouldn't create Key named[%S]",p ));
break;
}
NtClose (hKey);
hKey = hKeyCreate;
while ( *p != UNICODE_NULL ) p++;
}
NtClose (hKey);
if (!NT_SUCCESS(st)) {
for ( ;p != pTrace;p++ )
if ( *p == UNICODE_NULL) *p=L'\\';
return FALSE;
}
return TRUE;
}
BOOL
CheckAndCreateNode (
IN PWCHAR Name
)
/*++
Routine Description:
Check if the given key exist if not create the key. called by background
thread working on the setup.
Arguments:
Name - name of the key to check.
Return Value:
TRUE if the operation succeed, FALSE otherwise.
--*/
{
ISN_NODE_TYPE Node;
PWCHAR p;
//
// if parent doesn't exist you shouldn't create the child
//
if (!NT_SUCCESS(IsNodeExist (Name)) ) {
p = wcsstrWow6432Node (Name);
if ( p != NULL ) {
wcsncpy (Node.NodeValue, Name, p-Name-1);
Node.NodeValue[p-Name-1] = UNICODE_NULL;
}
else
return FALSE;
if (NT_SUCCESS(IsNodeExist (Node.NodeValue)) )
return CreateNode (Name);
}
return TRUE;
}
//
// Opaque field might contain some information about the key on the 32bit side.
//
BOOL
IsIsnNode (
PWCHAR wStr,
PWCHAR *pwStrIsn
)
/*++
Routine Description:
Will determine if the given path has any ISN node.
Arguments:
wStr - string to that might contain some ISN node.
pwStrDest - point to the node after ISN node.
Return Value:
TRUE if the string has any ISN node, FALSE otherwise
--*/
{
int Index=0;
//
// Check if the provided string is already on the 32 bit tree, if so we can
// just ignore that
//
//
// check if input string has any known symbolic link like \registry\user\sid_Classes that need to remap to a different location
//
for (;;) {
if ( IsnNode [Index][0]==UNICODE_NULL ) break;
if ( (*pwStrIsn = wcsstrWithWildCard (wStr, IsnNode[Index] ) ) != NULL )
return TRUE;
Index++;
};
*pwStrIsn = NULL;
return FALSE;
}
NTSTATUS
ObjectAttributesToKeyName (
POBJECT_ATTRIBUTES ObjectAttributes,
PWCHAR AbsPath,
DWORD AbsPathLenIn,
BOOL *bPatched,
DWORD *ParentLen
)
/*++
Routine Description:
Determine the text equivalent for key handle
Arguments:
ObjectAttributes define the object attribute Keyname need to be constracted.
AbsPath Unicode string to receive the Name of the key.
bPatched - TRUE if the Name has been compressed/expanded that
the original object can't refer. Caller need to construct
a new obj attribute.
unchanged otherwise.
ParentLen - Length of the parent name.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
ULONG Length;
ULONG AbsPathLen = 0;
BYTE *pAbsPath = (PBYTE)AbsPath;
POBJECT_NAME_INFORMATION ObjectName = (POBJECT_NAME_INFORMATION)AbsPath; //Smartly use user buffer
if (ParentLen)
*ParentLen = 0;
if (ObjectAttributes->RootDirectory) {
Status = NtQueryObject(ObjectAttributes->RootDirectory,
ObjectNameInformation,
ObjectName,
AbsPathLenIn,
&Length
);
if ( !NT_SUCCESS(Status) )
return Status;
} else {
AbsPathLen = ObjectAttributes->ObjectName->Length;
if (AbsPathLenIn <= AbsPathLen)
return STATUS_BUFFER_OVERFLOW;
memcpy ( pAbsPath, (PBYTE)ObjectAttributes->ObjectName->Buffer, AbsPathLen );
*(WCHAR *)(pAbsPath+AbsPathLen) = UNICODE_NULL;
if (ParentLen)
*ParentLen = AbsPathLen; // length of the parent handle
return STATUS_SUCCESS;
}
//
// copy the root and sub path
//
AbsPathLen = ObjectName->Name.Length;
memcpy ( pAbsPath, (PBYTE)ObjectName->Name.Buffer, AbsPathLen);
if ( ObjectAttributes->ObjectName->Length > 1 ) { // Valid object name need to be greater
*(WCHAR *)(pAbsPath+AbsPathLen) = L'\\';
AbsPathLen += sizeof ( L'\\');
if (AbsPathLenIn <= (AbsPathLen+ObjectAttributes->ObjectName->Length))
return STATUS_BUFFER_OVERFLOW;
memcpy (
pAbsPath+AbsPathLen,
ObjectAttributes->ObjectName->Buffer,
ObjectAttributes->ObjectName->Length
);
AbsPathLen += ObjectAttributes->ObjectName->Length;
}
*(WCHAR *)(pAbsPath+AbsPathLen) = UNICODE_NULL;
//
// Compress the path in case multiple wow6432node exist
//
for (;;) {
PWCHAR p, t;
if ( (p=wcsstrWow6432Node (AbsPath)) != NULL ) {
if ( (t=wcsstrWow6432Node(p+1)) != NULL) {
wcscpy (p,t);
*bPatched = TRUE;
}
else break;
} else break;
}
return STATUS_SUCCESS;
}
BOOL
HandleToKeyName (
HANDLE Key,
PWCHAR KeyName,
DWORD * dwLen
)
/*++
Routine Description:
Determine the text equivalent for key handle
Arguments:
Key - is key handle for which to obtain its text
KeyName - Unicode string to receive the Name of the key.
dwLen - Length of the buffer pointed by KeyName. (Number of unicode char)
Return Value:
TRUE if the handle text is fetched OK. FALSE if not (ie. error or
Key is an illegal handle, etc.)
--*/
{
NTSTATUS Status;
ULONG Length;
DWORD NameLen;
POBJECT_NAME_INFORMATION ObjectName;
ObjectName = (POBJECT_NAME_INFORMATION)KeyName; //use the user buffer to make the call to save space on stack.
KeyName[0]= UNICODE_NULL;
if (Key == NULL) {
KeyName[0]= UNICODE_NULL;
return FALSE;
}
Status = NtQueryObject(Key,
ObjectNameInformation,
ObjectName,
*dwLen-8,
&Length
);
NameLen = ObjectName->Name.Length/sizeof(WCHAR);
if (!NT_SUCCESS(Status) || !Length || Length >= (*dwLen-8)) {
DbgPrint ("\nHandleToKeyName: NtQuery Object failed St:%x, Handle: %x", Status, Key);
KeyName[0]= UNICODE_NULL;
return FALSE;
}
//
// buffer overflow condition check
//
if (*dwLen < ( NameLen + 8+ 2) ) {
*dwLen = 2 + NameLen + 8;
DbgPrint ("\nHandleToKeyName: Buffer over flow.");
KeyName[0]= UNICODE_NULL;
return FALSE; //buffer overflow
}
wcsncpy(KeyName, ObjectName->Name.Buffer, NameLen);
KeyName[NameLen]=UNICODE_NULL;
return TRUE;
}
BOOL
Map32bitTo64bitKeyName (
IN PWCHAR Name32Key,
OUT PWCHAR Name64Key
)
/*++
Routine Description:
Return a key name valid in the 64-bit registry side. It's the caller responsibility
to give enough space in the output buffer. Its internal routine and no boundary
checking is done here.
Arguments:
Name32Key - Input 32bit/64 bit Key name.
Name64Key - Receiving Buffer that will hold the equivalent 64bit Key.
Return Value:
TRUE if the remapping become successful.
FALSE otherwise.
--*/
{
//
// just remove 32bit related patch from the name if anything like that exist.
// If the key is already on the 64bit side don't bother return the whole copy.
//
PWCHAR NodeName32Bit;
DWORD Count;
try {
if ( ( NodeName32Bit = wcsstrWow6432Node (Name32Key)) == NULL) { // nothing to remap
wcscpy (Name64Key, Name32Key);
return TRUE;
}
Count = (DWORD)(NodeName32Bit - Name32Key);
wcsncpy (Name64Key, Name32Key, Count-1);
Name64Key[Count-1]=UNICODE_NULL;
if (NodeName32Bit[NODE_NAME_32BIT_LEN] == L'\\')
wcscpy (
Name64Key + Count-1,
NodeName32Bit + NODE_NAME_32BIT_LEN); //One if to skip the char'/'
} except( NULL, EXCEPTION_EXECUTE_HANDLER){
return FALSE;
}
return TRUE; //any complete path can have only one instance of NODE_NAME_32BIT
}
BOOL
IsExemptRedirectedKey (
IN PWCHAR SrcKey,
OUT PWCHAR DestKey
)
/*++
Routine Description:
Check if the the source key point to the list of exempt key from redirection.
If so DestKey will have the right value.
Arguments:
Name64Key - Input 32bit/64 bit Key name.
Name32Key - Receiving Buffer that will hold the equivalent 32bit Key.
Return Value:
TRUE if the Key is on the list of exempt key from redirection.
FALSE otherwise.
--*/
{
//
// Make 64bit only path
//
PWCHAR NodeName32Bit;
DWORD dwIndex =0;
wcscpy (DestKey, SrcKey);
if ( ( NodeName32Bit = wcsstrWow6432Node (DestKey)) != NULL) { // nothing to remap patch is already there
NodeName32Bit--;
wcscpy (NodeName32Bit, NodeName32Bit+sizeof (NODE_NAME_32BIT)/sizeof (WCHAR));
}
for ( dwIndex = 0; ExemptRedirectedKey[dwIndex].KeyPath[0] != UNICODE_NULL; dwIndex++ )
if (_wcsnicmp (DestKey, ExemptRedirectedKey[dwIndex].KeyPath, ExemptRedirectedKey[dwIndex].Len ) == 0)
return TRUE;
return FALSE;
}
BOOL
Map64bitTo32bitKeyName (
IN PWCHAR Name64Key,
OUT PWCHAR Name32Key
)
/*++
Routine Description:
Return a key name valid in the 32-bit registry side. It's the caller responsibility
to give enough space in the output buffer. Its internal routine and no boundary
checking is done here.
Arguments:
Name64Key - Input 32bit/64 bit Key name.
Name32Key - Receiving Buffer that will hold the equivalent 32bit Key.
Return Value:
TRUE if the remapping become successful.
FALSE otherwise.
--*/
{
//
// just add 32bit related patch from the name if anything like that exist.
// or fall under the ISN nodes.
//
PWCHAR NodeName32Bit;
DWORD Count;
try {
if (IsExemptRedirectedKey (Name64Key, Name32Key) )
return TRUE;
if ( ( NodeName32Bit = wcsstrWow6432Node (Name64Key)) != NULL) { // nothing to remap patch is already there
wcscpy (Name32Key, Name64Key);
return TRUE;
}
if (!IsIsnNode ( Name64Key, &NodeName32Bit)) {
wcscpy (Name32Key, Name64Key);
return TRUE;
}
Count = (DWORD)(NodeName32Bit - Name64Key); // Displacement offset where the patch shoud go.
//
// consider the case when 32bit apps need to create/open the real ISN node which doesn't exist
//
wcsncpy (Name32Key,Name64Key, Count);
if (Name32Key[Count-1] != L'\\') {
Name32Key[Count] = L'\\';
Count++;
}
wcscpy (Name32Key+Count, NODE_NAME_32BIT);
if ( *NodeName32Bit != UNICODE_NULL ) {
wcscat (Name32Key, L"\\");
wcscat (Name32Key, NodeName32Bit);
}
} except( NULL, EXCEPTION_EXECUTE_HANDLER){
return FALSE;
}
return TRUE; //any complete path can have only one instance of NODE_NAME_32BIT
}
NTSTATUS
OpenIsnNodeByObjectAttributes (
POBJECT_ATTRIBUTES ObjectAttributes,
ACCESS_MASK DesiredAccess,
PHANDLE phPatchedHandle
)
/*++
Routine Description:
If this Keyhandle is an open handle to an ISN node then this function
return a handle to the node on the 32 bit tree. If not then we create the whole
path and see if any ISN node is there. If so we Get the path on the 32bit tree and
return Open that key.
Scenario:
1. Absolute path made from Directory root and relative path don't contain any ISN node.
-Open that normally.
2. Directory Handle point to the immediate parent of ISN node and the relative path is
just an ISN node.
-if 32 bit equivalent of ISN node exist open that and return that. If the 32 bit node
doesn't exist create one and return that. [Problem open Directory Handle might not
have create access.
3 Directory Handle point to an ISN node and relative path is just an immediate chield.
- This can never happen. If we follow the algorithm, directory handly can't point on
to an ISN node but on 32 bit equivalent node.
4. Same as 2 but relative path might be grand child or far bellow.
- If 32 bit equivalent node isn't there just create that and open the rest.
How 32 bit Apps can open an ISN node:
<TBD> the proposal is a s follows:
1. Redirector will maintain a list of exempt handle that were created to access ISN node.
2. Any open call relative to those handle will also be on the exemped list.
3. NtClose thunk will remove
Arguments:
KeyHandle - Handle to the node on the 64 bit tree.
phPatchedHandle - receive the appropriate handle if this function succeed.
Return Value:
NTSTATUS;
--*/
{
UNICODE_STRING Parent;
NTSTATUS st;
OBJECT_ATTRIBUTES Obja;
WCHAR PatchedIsnNode[WOW64_MAX_PATH+256];
WCHAR AbsPath[WOW64_MAX_PATH+256];
BOOL bPatched;
DWORD ParentLen;
//
// Make the complete path in a AbsPath
//
*phPatchedHandle=NULL;
st = ObjectAttributesToKeyName (
ObjectAttributes,
AbsPath,
sizeof (AbsPath),
&bPatched,
&ParentLen );
if (!NT_SUCCESS(st)) {
LOGPRINT( (ERRORLOG, "\nWow64:Extremely Bad!!!!!!!!!!!!!!! Couldn't retrieve object name"));
return st;
}
if (DesiredAccess & KEY_WOW64_64KEY) {
if (!Map32bitTo64bitKeyName ( AbsPath, PatchedIsnNode ))
return -1; //severe problem shouldn't happen
} else {
PWCHAR p;
if (!Map64bitTo32bitKeyName ( AbsPath, PatchedIsnNode ))
return -1; //severe problem shouldn't happen
//
// If parent root immediately point just before or anywhere after the patch don't patch
//
/*if (!(DesiredAccess & KEY_WOW64_32KEY ) ) {
p = wcsstr (PatchedIsnNode, NODE_NAME_32BIT);
if (p) {
DWORD Len;
p--; //back one step to ignore slash before Wow6432Node
Len = (DWORD) (p-PatchedIsnNode);
Len *= sizeof (WCHAR); //get byte
if (Len >= ParentLen ) {
Wow64RegDbgPrint (( "\nRemapNtOpenKeyEx OUT: Will not patch %S", PatchedIsnNode));
return STATUS_SUCCESS;
}
}
} */
}
DesiredAccess = DesiredAccess & (~KEY_WOW64_RES);
//
// Handle the hardlink we have HKLM\Software\wow6432node\classes ==>HKCR\Classes
//
/*if (_wcsnicmp (PatchedIsnNode, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Classes", 19+27) == 0) {
wcsncpy (PatchedIsnNode+27, L"Classes\\Wow6432Node", 19); //sizeof (L"Wow6432Node\\Classes")/2);
bPatched = TRUE;
}*/
//
// no change can be optimize by returning different value from Map64bitTo32bitKeyName
// Caller need to handle this
//
if ( !bPatched)
if ( !wcscmp (AbsPath, PatchedIsnNode ))
return STATUS_SUCCESS;
RtlInitUnicodeString (&Parent, PatchedIsnNode);
InitializeObjectAttributes (&Obja, &Parent, ObjectAttributes->Attributes, NULL, ObjectAttributes->SecurityDescriptor ); //you have to use caller's context
st = NtOpenKey (phPatchedHandle, DesiredAccess, &Obja);
#ifdef WOW64_LOG_REGISTRY
if (!NT_SUCCESS (st))
Wow64RegDbgPrint (( "\nRemapNtOpenKeyEx OUT: couldn't open %S", PatchedIsnNode));
#endif
return st;
}
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
)
/*++
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>
--*/
{
UNICODE_STRING Parent;
NTSTATUS st;
OBJECT_ATTRIBUTES Obja;
WCHAR PatchedIsnNode[WOW64_MAX_PATH];
WCHAR AbsPath[WOW64_MAX_PATH];
BOOL bPatched=FALSE;
DWORD ParentLen;
//
// Make the complete path in a AbsPath
//
if (ARGUMENT_PRESENT(phPatchedHandle)){
*phPatchedHandle=NULL;
}
st = ObjectAttributesToKeyName (
ObjectAttributes,
AbsPath,
sizeof (AbsPath),
&bPatched,
&ParentLen);
if (!NT_SUCCESS(st)) {
WOWASSERT(FALSE );
return st;
}
if (DesiredAccess & KEY_WOW64_64KEY) {
if (!Map32bitTo64bitKeyName ( AbsPath, PatchedIsnNode )) {
WOWASSERT(FALSE );
return STATUS_SUCCESS; //severe problem shouldn't happen
}
} else {
PWCHAR p;
if (!Map64bitTo32bitKeyName ( AbsPath, PatchedIsnNode )){
WOWASSERT(FALSE );
return STATUS_SUCCESS; //severe problem shouldn't happen
}
//
// If parent root immediately point just before or anywhere after the patch don't patch
//
/*
if (!(DesiredAccess & KEY_WOW64_32KEY ) ) { //implied 32bit access
p = wcsstr (PatchedIsnNode, NODE_NAME_32BIT);
if (p) {
DWORD Len;
p--; //back one step to ignore slash before Wow6432Node
Len = (DWORD) (p-PatchedIsnNode);
Len *= sizeof (WCHAR); //get byte
if (Len >= ParentLen ) {
Wow64RegDbgPrint (( "\nRemapNtOpenKeyEx OUT: Will not patch %S", PatchedIsnNode));
return STATUS_SUCCESS;
}
}
}*/
}
DesiredAccess = DesiredAccess & (~KEY_WOW64_RES);
//
// Handle the hardlink we have HKLM\Software\wow6432node\classes ==>HKCR\Classes
//
/*if (_wcsnicmp (PatchedIsnNode, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node\\Classes", 19+27) == 0) {
bPatched = TRUE;
wcsncpy (PatchedIsnNode+27, L"Classes\\Wow6432Node", 19); //sizeof (L"Wow6432Node\\Classes")/2);
}*/
if (!bPatched) // the abspath hasn't been patched
if ( !wcscmp (AbsPath, PatchedIsnNode ))
return STATUS_SUCCESS; // no change can be optimize by returning different value from Map64bitTo32bitKeyName
RtlInitUnicodeString (&Parent, PatchedIsnNode);
InitializeObjectAttributes (&Obja,
&Parent,
ObjectAttributes->Attributes,
NULL,
ObjectAttributes->SecurityDescriptor
); //you have to use caller's context
st = NtCreateKey(
phPatchedHandle,
DesiredAccess,
&Obja,
TitleIndex,
Class ,
CreateOptions,
Disposition
);
return st;
}
NTSTATUS
Wow64NtPreUnloadKeyNotify(
IN POBJECT_ATTRIBUTES TargetKey
)
/*++
Routine Description:
This call will notify Wow64 service that wow64 need to release any open handle
to the hive that is going to be unloaded.
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.
--*/
{
//todo
return 0;
}
NTSTATUS
Wow64NtPostLoadKeyNotify(
IN POBJECT_ATTRIBUTES TargetKey
)
/*++
Routine Description:
If Load operation succeed, it will notify wow64 service that it
can listen to the registry operation on the given hive.
This function can be invoked from NtLoadKey and NtLoadKey2 APIs.
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.
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>"
Return Value:
NTSTATUS - values TBS.
--*/
{
//todo
return 0;
}