windows-nt/Source/XPSP1/NT/windows/appcompat/shims/layer/handleregexpandszregistrykeys.cpp
2020-09-26 16:20:57 +08:00

309 lines
7.2 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
HandleRegExpandSzRegistryKeys.cpp
Abstract:
This DLL catches REG_EXPAND_SZ registry keys and converts them to REG_SZ by
expanding the embedded environment strings.
History:
04/05/2000 markder Created
10/30/2000 maonis Bug fix
--*/
#include "precomp.h"
IMPLEMENT_SHIM_BEGIN(HandleRegExpandSzRegistryKeys)
#include "ShimHookMacro.h"
APIHOOK_ENUM_BEGIN
APIHOOK_ENUM_ENTRY(RegQueryValueExA)
APIHOOK_ENUM_ENTRY(RegQueryValueExW)
APIHOOK_ENUM_END
/*++
Expand REG_EXPAND_SZ strings.
--*/
LONG
APIHOOK(RegQueryValueExA)(
HKEY hKey, // handle to key
LPCSTR lpValueName, // value name
LPDWORD lpReserved, // reserved
LPDWORD lpType, // dwType buffer
LPBYTE lpData, // data buffer
LPDWORD lpcbData // size of data buffer
)
{
DWORD dwType;
LONG uRet;
DWORD cbPassedInBuffer = 0, cbExpandedBuffer = 0;
LPSTR szLocalBuffer = NULL;
if (lpcbData) {
cbPassedInBuffer = *lpcbData;
cbExpandedBuffer = *lpcbData;
}
uRet = ORIGINAL_API(RegQueryValueExA)(
hKey, lpValueName, lpReserved, &dwType, lpData, &cbExpandedBuffer);
if (lpcbData) {
*lpcbData = cbExpandedBuffer;
}
if (lpType) {
*lpType = dwType;
}
if (dwType != REG_EXPAND_SZ) {
return uRet;
}
//
// The type is REG_EXPAND_SZ. Change to REG_SZ so app doesn't try to expand
// the string itself.
//
if (lpType) {
*lpType = REG_SZ;
}
if ((uRet != ERROR_SUCCESS) && (uRet != ERROR_MORE_DATA)) {
return uRet;
}
LOGN(
eDbgLevelInfo,
"[RegQueryValueExA] Caught REG_EXPAND_SZ key: \"%s\".", lpValueName);
//
// Allocate a local buffer and get the value.
//
szLocalBuffer = (LPSTR) malloc(cbExpandedBuffer);
if (!szLocalBuffer) {
LOGN( eDbgLevelError, "Out of memory.\n");
// The shim failed, so revert to the original behavior
*lpType = REG_EXPAND_SZ;
return uRet;
}
ORIGINAL_API(RegQueryValueExA)(
hKey, lpValueName, lpReserved, NULL, (LPBYTE) szLocalBuffer,
&cbExpandedBuffer);
DPFN(
eDbgLevelInfo,
"[RegQueryValueExA] Value: \"%s\"", szLocalBuffer);
//
// Query for length of expanded string.
//
cbExpandedBuffer = ExpandEnvironmentStringsA((LPSTR)szLocalBuffer, NULL, 0);
if (lpcbData) {
*lpcbData = cbExpandedBuffer;
}
if (lpData != NULL) {
if (cbExpandedBuffer > cbPassedInBuffer) {
//
// Buffer not big enough.
//
LOGN(
eDbgLevelError,
"[RegQueryValueExA] Buffer too small - Passed in: %d Needed: %d",
cbPassedInBuffer, cbExpandedBuffer );
free(szLocalBuffer);
//
// We're pretending the value is already expanded, so to be
// consistent, we must fail as if that were the case. If we simply
// returned uRet here, the app would get inconsistent return
// values, e.g. if the buffer is big enough then REG_SZ is returned
// otherwise REG_EXPAND_SZ is returned - this doesn't make sense.
//
return ERROR_MORE_DATA;
}
//
// If data buffer was passed in (and is big enough), copy the data into it.
//
ExpandEnvironmentStringsA(szLocalBuffer, (LPSTR)lpData, cbPassedInBuffer);
DPFN(
eDbgLevelInfo,
"[RegQueryValueExA] Expanded to: \"%s\"\n",
lpData);
uRet = ERROR_SUCCESS;
}
free(szLocalBuffer);
return uRet;
}
/*++
Expand REG_EXPAND_SZ strings.
--*/
LONG
APIHOOK(RegQueryValueExW)(
HKEY hKey, // handle to key
LPCWSTR lpValueName, // value name
LPDWORD lpReserved, // reserved
LPDWORD lpType, // dwType buffer
LPBYTE lpData, // data buffer
LPDWORD lpcbData // size of data buffer
)
{
DWORD dwType;
LONG uRet;
DWORD cbPassedInBuffer = 0, cbExpandedBuffer = 0;
LPWSTR szLocalBuffer = NULL;
if (lpcbData) {
cbPassedInBuffer = *lpcbData;
cbExpandedBuffer = *lpcbData;
}
uRet = ORIGINAL_API(RegQueryValueExW)(
hKey, lpValueName, lpReserved, &dwType, lpData, &cbExpandedBuffer);
if (lpcbData) {
*lpcbData = cbExpandedBuffer;
}
if (lpType) {
*lpType = dwType;
}
if (dwType != REG_EXPAND_SZ) {
return uRet;
}
//
// The type is REG_EXPAND_SZ. Change to REG_SZ so app doesn't try to expand
// the string itself.
//
if (lpType) {
*lpType = REG_SZ;
}
if ((uRet != ERROR_SUCCESS) && (uRet != ERROR_MORE_DATA)) {
return uRet;
}
LOGN(
eDbgLevelInfo,
"[RegQueryValueExW] Caught REG_EXPAND_SZ key: \"%ws\".",
lpValueName);
//
// Allocate a local buffer and get the value.
//
szLocalBuffer = (LPWSTR) malloc(cbExpandedBuffer);
if (!szLocalBuffer) {
LOGN( eDbgLevelError, "Out of memory.\n");
// The shim failed, so revert to the original behavior
*lpType = REG_EXPAND_SZ;
return uRet;
}
ORIGINAL_API(RegQueryValueExW)(
hKey, lpValueName, lpReserved, NULL, (LPBYTE) szLocalBuffer,
&cbExpandedBuffer);
DPFN(
eDbgLevelInfo,
"[RegQueryValueExW] Value: \"%ws\".\n",
szLocalBuffer);
//
// Query for length of expanded string.
//
cbExpandedBuffer = ExpandEnvironmentStringsW((LPWSTR)szLocalBuffer, NULL, 0) * sizeof(WCHAR);
if (lpcbData) {
*lpcbData = cbExpandedBuffer;
}
if (lpData != NULL) {
if (cbExpandedBuffer > cbPassedInBuffer) {
//
// Buffer not big enough.
//
LOGN(
eDbgLevelInfo,
"[RegQueryValueExW] Buffer too small - Passed in: %d Needed: %d",
cbPassedInBuffer, cbExpandedBuffer);
free(szLocalBuffer);
//
// We're pretending the value is already expanded, so to be
// consistent, we must fail as if that were the case. If we simply
// returned uRet here, the app would get inconsistent return
// values, e.g. if the buffer is big enough then REG_SZ is returned
// otherwise REG_EXPAND_SZ is returned - this doesn't make sense.
//
return ERROR_MORE_DATA;
}
//
// If data buffer was passed in (and is big enough), copy the data into it.
//
ExpandEnvironmentStringsW(szLocalBuffer, (LPWSTR)lpData, cbPassedInBuffer / sizeof(WCHAR));
DPFN(
eDbgLevelInfo,
"[RegQueryValueExW] Expanded to: \"%ws\".\n",
lpData);
uRet = ERROR_SUCCESS;
}
free(szLocalBuffer);
return uRet;
}
/*++
Register hooked functions
--*/
HOOK_BEGIN
APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExA)
APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExW)
HOOK_END
IMPLEMENT_SHIM_END