Leaked source code of windows server 2003
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.
 
 
 
 
 
 

671 lines
19 KiB

#include "stdinc.h"
#include "detours.h"
#include "user32detours.h"
#define NUMBER_OF(x) (sizeof(x)/sizeof(*x))
namespace User32Trampolines
{
bool fInitialized = false;
CSimpleMap<CString, bool> m_ItemMap;
HKEY g_hkLocalMachine = NULL;
HKEY g_hkClasses = NULL;
HKEY g_hkCurrentUser = NULL;
HKEY g_hkRedirectionRoot = NULL;
HKEY g_hkUsers = NULL;
GUID g_uuidRedirection;
HKEY RemapRegKey(HKEY);
extern "C" {
DETOUR_TRAMPOLINE(
ATOM WINAPI Real_RegisterClassW(CONST WNDCLASSW *lpWndClass),
RegisterClassW);
DETOUR_TRAMPOLINE(
ATOM WINAPI Real_RegisterClassA(CONST WNDCLASSA *lpWndClass),
RegisterClassA);
DETOUR_TRAMPOLINE(
ATOM WINAPI Real_RegisterClassExW(CONST WNDCLASSEXW *),
RegisterClassExW);
DETOUR_TRAMPOLINE(
ATOM WINAPI Real_RegisterClassExA(CONST WNDCLASSEXA *),
RegisterClassExA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegOpenKeyW ( IN HKEY hKey, IN LPCWSTR lpSubKey, OUT PHKEY phkResult ),
RegOpenKeyW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegOpenKeyA ( IN HKEY hKey, IN LPCSTR lpSubKey, OUT PHKEY phkResult ),
RegOpenKeyA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegOpenKeyExW ( IN HKEY hKey, IN LPCWSTR lpSubKey, DWORD, REGSAM, PHKEY),
RegOpenKeyExW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegOpenKeyExA ( IN HKEY hKey, IN LPCSTR lpSubKey, DWORD, REGSAM, PHKEY),
RegOpenKeyExA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegSetValueExA (HKEY,LPCSTR,DWORD,DWORD,CONST BYTE*,DWORD),
RegSetValueExA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegSetValueExW (HKEY,LPCWSTR,DWORD,DWORD,CONST BYTE*,DWORD),
RegSetValueExW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegSetValueW(HKEY,LPCWSTR,DWORD,LPCWSTR,DWORD),
RegSetValueW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegSetValueA(HKEY,LPCSTR,DWORD,LPCSTR,DWORD),
RegSetValueA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegQueryValueExA(HKEY,LPCSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD),
RegQueryValueExA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegQueryValueExW(HKEY,LPCWSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD),
RegQueryValueExW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegQueryValueA(HKEY,LPCSTR,LPSTR,PLONG),
RegQueryValueA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegQueryValueW(HKEY,LPCWSTR,LPWSTR,PLONG),
RegQueryValueW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegCreateKeyW(HKEY, PWSTR, PHKEY),
RegCreateKeyW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegCreateKeyA(HKEY, PSTR, PHKEY),
RegCreateKeyA);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegCreateKeyExW(HKEY, PCWSTR, DWORD, PCWSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, PDWORD),
RegCreateKeyExW);
DETOUR_TRAMPOLINE(
LONG APIENTRY Real_RegCreateKeyExA(HKEY, PCSTR, DWORD, PCSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, PDWORD),
RegCreateKeyExA);
}
};
//
// Remap from a well-known registry value to our internal ones.
//
HKEY
User32Trampolines::RemapRegKey(HKEY hKey)
{
if (hKey == HKEY_CLASSES_ROOT) return User32Trampolines::g_hkClasses;
else if (hKey == HKEY_CURRENT_USER) return User32Trampolines::g_hkCurrentUser;
else if (hKey == HKEY_LOCAL_MACHINE) return User32Trampolines::g_hkLocalMachine;
else if (hKey == HKEY_USERS) return User32Trampolines::g_hkUsers;
else return hKey;
}
LONG APIENTRY
User32Trampolines::InternalRegSetValueA (
IN HKEY hKey,
IN PCSTR lpSubKey,
IN DWORD dwType,
IN PCSTR lpData,
IN DWORD cbData
)
{
hKey = User32Trampolines::RemapRegKey(hKey);
return Real_RegSetValueA(hKey, lpSubKey, dwType, lpData, cbData);
}
LONG APIENTRY
User32Trampolines::InternalRegSetValueW (
IN HKEY hKey,
IN PCWSTR lpSubKey,
IN DWORD dwType,
IN PCWSTR lpData,
IN DWORD cbData
)
{
hKey = User32Trampolines::RemapRegKey(hKey);
return Real_RegSetValueW(hKey, lpSubKey, dwType, lpData, cbData);
}
LONG
APIENTRY
User32Trampolines::InternalRegSetValueExA (
IN HKEY hKey,
IN LPCSTR lpValueName,
IN DWORD Reserved,
IN DWORD dwType,
IN CONST BYTE* lpData,
IN DWORD cbData
)
{
//
// Always translate on a set.
//
hKey = User32Trampolines::RemapRegKey(hKey);
return Real_RegSetValueExA(hKey, lpValueName, Reserved, dwType, lpData, cbData);
}
LONG
APIENTRY
User32Trampolines::InternalRegSetValueExW (
IN HKEY hKey,
IN LPCWSTR lpValueName,
IN DWORD Reserved,
IN DWORD dwType,
IN CONST BYTE* lpData,
IN DWORD cbData
)
{
hKey = User32Trampolines::RemapRegKey(hKey);
return Real_RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, cbData);
}
LONG APIENTRY User32Trampolines::InternalRegOpenKeyA (
IN HKEY hKey,
IN LPCSTR lpSubKey,
OUT PHKEY phkResult
)
{
//
// Opening a key remaps the hKey to our set of values if possible first. If that
// fails, then try the unremapped version to read from the 'real' registry.
//
ULONG ulResult;
ulResult = Real_RegOpenKeyA(RemapRegKey(hKey), lpSubKey, phkResult);
if (ulResult != 0)
{
ulResult = Real_RegOpenKeyA(hKey, lpSubKey, phkResult);
}
return ulResult;
}
LONG APIENTRY User32Trampolines::InternalRegOpenKeyW (
IN HKEY hKey,
IN LPCWSTR lpSubKey,
OUT PHKEY phkResult
)
{
//
// Opening a key remaps the hKey to our set of values if possible first. If that
// fails, then try the unremapped version to read from the 'real' registry.
//
ULONG ulResult;
ulResult = Real_RegOpenKeyW(RemapRegKey(hKey), lpSubKey, phkResult);
if (ulResult != 0)
{
ulResult = Real_RegOpenKeyW(hKey, lpSubKey, phkResult);
}
return ulResult;
}
LONG APIENTRY User32Trampolines::InternalRegCreateKeyA(HKEY hk, PSTR ps, PHKEY phk)
{
return Real_RegCreateKeyA(RemapRegKey(hk), ps, phk);
}
LONG APIENTRY User32Trampolines::InternalRegCreateKeyExA(HKEY a, PCSTR b, DWORD c, PCSTR d, DWORD e, REGSAM f, LPSECURITY_ATTRIBUTES g, PHKEY h, PDWORD i)
{
return Real_RegCreateKeyExA(RemapRegKey(a), b, c, d, e, f, g, h, i);
}
LONG APIENTRY User32Trampolines::InternalRegCreateKeyW(HKEY hk, PWSTR ps, PHKEY phk)
{
return Real_RegCreateKeyW(RemapRegKey(hk), ps, phk);
}
LONG APIENTRY User32Trampolines::InternalRegCreateKeyExW(HKEY a, PCWSTR b, DWORD c, PCWSTR d, DWORD e, REGSAM f, LPSECURITY_ATTRIBUTES g, PHKEY h, PDWORD i)
{
return Real_RegCreateKeyExW(RemapRegKey(a), b, c, d, e, f, g, h, i);
}
LONG APIENTRY User32Trampolines::InternalRegOpenKeyExA (
IN HKEY hKey,
IN LPCSTR lpSubKey,
IN DWORD ulOptions,
IN REGSAM samDesired,
OUT PHKEY phkResult
)
{
//
// Opening a key remaps the hKey to our set of values if possible first. If that
// fails, then try the unremapped version to read from the 'real' registry.
//
ULONG ulResult;
ulResult = Real_RegOpenKeyExA(RemapRegKey(hKey), lpSubKey, ulOptions, samDesired, phkResult);
if (ulResult != 0)
{
ulResult = Real_RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}
return ulResult;
}
LONG APIENTRY User32Trampolines::InternalRegOpenKeyExW (
IN HKEY hKey,
IN LPCWSTR lpSubKey,
IN DWORD ulOptions,
IN REGSAM samDesired,
OUT PHKEY phkResult
)
{
//
// Opening a key remaps the hKey to our set of values if possible first. If that
// fails, then try the unremapped version to read from the 'real' registry.
//
ULONG ulResult;
ulResult = Real_RegOpenKeyExW(RemapRegKey(hKey), lpSubKey, ulOptions, samDesired, phkResult);
if (ulResult != 0)
{
ulResult = Real_RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}
return ulResult;
}
LONG APIENTRY User32Trampolines::InternalRegQueryValueA(
HKEY hKey,
LPCSTR lpSubKey,
LPSTR lpValue,
PLONG pcbData)
{
ULONG ulResult;
ulResult = Real_RegQueryValueA(RemapRegKey(hKey), lpSubKey, lpValue, pcbData);
if (ulResult != 0)
{
ulResult = Real_RegQueryValueA(hKey, lpSubKey, lpValue, pcbData);
}
return ulResult;
}
LONG APIENTRY User32Trampolines::InternalRegQueryValueW(
HKEY hKey,
LPCWSTR lpSubKey,
LPWSTR lpValue,
PLONG pcbData)
{
ULONG ulResult;
ulResult = Real_RegQueryValueW(RemapRegKey(hKey), lpSubKey, lpValue, pcbData);
if (ulResult != 0)
{
ulResult = Real_RegQueryValueW(hKey, lpSubKey, lpValue, pcbData);
}
return ulResult;
}
LONG APIENTRY User32Trampolines::InternalRegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD pdwData
)
{
ULONG ulResult;
ulResult = Real_RegQueryValueExA(RemapRegKey(hKey), lpValueName, lpReserved, lpType, lpData, pdwData);
if (ulResult != 0)
{
ulResult = Real_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, pdwData);
}
return ulResult;
}
LONG APIENTRY User32Trampolines::InternalRegQueryValueExW(
HKEY hKey,
LPCWSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD pdwData
)
{
ULONG ulResult;
ulResult = Real_RegQueryValueExW(RemapRegKey(hKey), lpValueName, lpReserved, lpType, lpData, pdwData);
if (ulResult != 0)
{
ulResult = Real_RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, pdwData);
}
return ulResult;
}
BOOL
User32Trampolines::GetRedirectedStrings(CSimpleList<CString>& Strings)
{
CSimpleList<CString> FoundStrings;
m_ItemMap.GetKeys(FoundStrings);
for ( SIZE_T sz = 0; sz < FoundStrings.Size(); sz++ )
{
SIZE_T c = 0;
for ( c = 0; c < Strings.Size(); c++ )
{
if ( lstrcmpiW(Strings[c], FoundStrings[sz]) == 0 )
break;
}
//
// Not found?
//
if ( c == Strings.Size() )
Strings.Append(FoundStrings[sz]);
}
return TRUE;
}
void
User32Trampolines::ClearRedirections()
{
m_ItemMap.Clear();
}
BOOL
User32Trampolines::Initialize()
{
if ( fInitialized )
return TRUE;
fInitialized = TRUE;
//
// Set up registry redirection before actually doing redirection. Generate
// a virtual-root that all calls will be rerouted to first. Do this by
// generating a GUIDized path off of HKCU.
//
LPOLESTR pstrGuid;
WCHAR wchRegPath[MAX_PATH];
ULONG ulResult;
HKEY hkDump;
if (FAILED(CoCreateGuid(&g_uuidRedirection)))
return FALSE;
StringFromCLSID(g_uuidRedirection, &pstrGuid);
_snwprintf(wchRegPath, MAX_PATH, L"ManBuilderRedirect\\%ls", pstrGuid);
//
// Create root key. For purposes of argument, we'll allow all access to all
// subchildren, no matter what. If we were a real app, we'd take into account
// propagating security down the heirarchy, but for now, we don't really care.
//
ulResult = ::RegCreateKeyExW(
HKEY_CURRENT_USER,
wchRegPath,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&User32Trampolines::g_hkRedirectionRoot,
NULL);
if (ulResult != 0) return FALSE;
//
// Generate all the pseudo-roots for the various keys
//
struct {
HKEY* phkTarget;
PCWSTR pcwszKeyName;
} s_KeyRedirections[] = {
{ &User32Trampolines::g_hkClasses, L"HKEY_CLASSES_ROOT" },
{ &User32Trampolines::g_hkCurrentUser, L"HKEY_CURRENT_USER" },
{ &User32Trampolines::g_hkLocalMachine, L"HKEY_LOCAL_MACHINE" },
{ &User32Trampolines::g_hkUsers, L"HKEY_USERS" }
};
for (ULONG ul = 0; ul < NUMBER_OF(s_KeyRedirections); ul++)
{
ulResult = RegCreateKeyExW(
g_hkRedirectionRoot,
s_KeyRedirections[ul].pcwszKeyName,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
s_KeyRedirections[ul].phkTarget,
NULL);
if (ulResult != 0) return FALSE;
}
//
// Let's also create (but close) the following 'special' keys for COM:
// - CLSID
// - Interface
//
ulResult = RegCreateKeyExW(User32Trampolines::g_hkClasses, L"CLSID", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkDump, NULL);
if (ulResult != 0)
RegCloseKey(hkDump);
ulResult = RegCreateKeyExW(User32Trampolines::g_hkClasses, L"Interface", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkDump, NULL);
if (ulResult != 0)
RegCloseKey(hkDump);
ulResult = RegCreateKeyExW(User32Trampolines::g_hkClasses, L"TypeLib", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkDump, NULL);
if (ulResult != 0)
RegCloseKey(hkDump);
#define MAP(f) { (PBYTE)Real_##f, (PBYTE)Internal##f }
PBYTE Remapping[][2] = {
MAP(RegisterClassW),
MAP(RegisterClassExW),
MAP(RegisterClassA),
MAP(RegisterClassExA),
MAP(RegOpenKeyW),
MAP(RegOpenKeyA),
MAP(RegOpenKeyExW),
MAP(RegOpenKeyExA),
MAP(RegSetValueExA),
MAP(RegSetValueExW),
MAP(RegSetValueA),
MAP(RegSetValueW),
MAP(RegQueryValueExA),
MAP(RegQueryValueExW),
MAP(RegQueryValueW),
MAP(RegQueryValueA),
MAP(RegCreateKeyA),
MAP(RegCreateKeyW),
MAP(RegCreateKeyExA),
MAP(RegCreateKeyExW)
};
//
// All redirections
//
for (int i = 0; i < NUMBER_OF(Remapping); i++)
{
DetourFunctionWithTrampoline(Remapping[i][0], Remapping[i][1]);
}
return TRUE;
}
ATOM WINAPI
User32Trampolines::InternalRegisterClassA(CONST WNDCLASSA * lpWndClass)
{
m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
return Real_RegisterClassA(lpWndClass);
}
ATOM WINAPI
User32Trampolines::InternalRegisterClassW(CONST WNDCLASSW * lpWndClass)
{
m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
return Real_RegisterClassW(lpWndClass);
}
ATOM WINAPI
User32Trampolines::InternalRegisterClassExA(CONST WNDCLASSEXA * lpWndClass)
{
m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
return Real_RegisterClassExA(lpWndClass);
}
ATOM WINAPI
User32Trampolines::InternalRegisterClassExW(CONST WNDCLASSEXW * lpWndClass)
{
m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
return Real_RegisterClassExW(lpWndClass);
}
namespace User32Trampolines {
void RegDestroyKeyTree(HKEY hk, PWSTR pwszBuffer)
{
bool fCreatedBuffer = false;
PWSTR strKeyName;
if (pwszBuffer == NULL)
{
fCreatedBuffer = true;
pwszBuffer = new WCHAR[MAX_PATH];
}
pwszBuffer[0] = UNICODE_NULL;
while (1)
{
HKEY hkSub;
if (ERROR_SUCCESS == RegEnumKeyW(hk, 0, pwszBuffer, MAX_PATH))
{
if ((strKeyName = new WCHAR[lstrlenW(pwszBuffer) + 1]) == NULL)
break;
lstrcpyW(strKeyName, pwszBuffer);
if (ERROR_SUCCESS == RegOpenKeyW(hk, pwszBuffer, &hkSub))
{
RegDestroyKeyTree(hkSub, pwszBuffer);
}
RegDeleteKeyW(hk, strKeyName);
delete[] strKeyName;
}
else
{
break;
}
}
if (fCreatedBuffer && pwszBuffer)
{
delete [] pwszBuffer;
pwszBuffer = NULL;
fCreatedBuffer = false;
}
}
BOOL Stop()
{
PHKEY hkToClose[] = {
&g_hkClasses,
&g_hkLocalMachine,
&g_hkUsers,
&g_hkCurrentUser,
};
PBYTE Remapping[][2] = {
MAP(RegisterClassW),
MAP(RegisterClassExW),
MAP(RegisterClassA),
MAP(RegisterClassExA),
MAP(RegOpenKeyW),
MAP(RegOpenKeyA),
MAP(RegOpenKeyExW),
MAP(RegOpenKeyExA),
MAP(RegSetValueExA),
MAP(RegSetValueExW),
MAP(RegSetValueA),
MAP(RegSetValueW),
MAP(RegQueryValueExA),
MAP(RegQueryValueExW),
MAP(RegQueryValueW),
MAP(RegQueryValueA),
MAP(RegCreateKeyA),
MAP(RegCreateKeyW),
MAP(RegCreateKeyExA),
MAP(RegCreateKeyExW)
};
int i;
//
// Close open keys
//
for (i = 0; i < NUMBER_OF(hkToClose); i++)
{
if (*hkToClose[i] != NULL)
{
RegCloseKey(*hkToClose[i]);
*hkToClose[i] = NULL;
}
}
//
// Undo detours
//
for (int i = 0; i < NUMBER_OF(Remapping); i++)
{
DetourRemove(Remapping[i][0], Remapping[i][1]);
}
LPOLESTR psz;
WCHAR wchKeyNameBuffer[MAX_PATH];
if (SUCCEEDED(StringFromCLSID(User32Trampolines::g_uuidRedirection, &psz)))
{
_snwprintf(wchKeyNameBuffer, MAX_PATH, L"ManBuilderRedirect\\%ls", psz);
// Destroy the tree pointed at
RegDestroyKeyTree(User32Trampolines::g_hkRedirectionRoot, NULL);
// Close our handle
RegCloseKey(User32Trampolines::g_hkRedirectionRoot);
// And try to delete the key
RegDeleteKeyW(HKEY_CURRENT_USER, wchKeyNameBuffer);
// And maybe delete the parent key
RegDeleteKeyW(HKEY_CURRENT_USER, L"ManBuilderRedirect");
// Free guid string memory, too
CoTaskMemFree(psz);
}
return TRUE;
}
}