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
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;
|
|
}
|
|
|
|
}
|