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

866 lines
17 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
EmulateHeap.cpp
Abstract:
This SHIM is for the layer and it emulates the Win9x heap manager. In fact,
much of the code is adapted from the Win9x sources .\heap.c and .\lmem.c.
This SHIM hooks all the heap allocation/deallocation functions including
the local/global functions.
Notes:
This is a general purpose shim.
History:
11/16/2000 prashkud & linstev Created
--*/
#include "precomp.h"
IMPLEMENT_SHIM_BEGIN(EmulateHeap)
#include "ShimHookMacro.h"
APIHOOK_ENUM_BEGIN
APIHOOK_ENUM_ENTRY(HeapCreate)
APIHOOK_ENUM_ENTRY(HeapDestroy)
APIHOOK_ENUM_ENTRY(HeapValidate)
APIHOOK_ENUM_ENTRY(HeapCompact)
APIHOOK_ENUM_ENTRY(HeapWalk)
APIHOOK_ENUM_ENTRY(HeapLock)
APIHOOK_ENUM_ENTRY(HeapUnlock)
APIHOOK_ENUM_ENTRY(GetProcessHeap)
APIHOOK_ENUM_ENTRY(LocalAlloc)
APIHOOK_ENUM_ENTRY(LocalFree)
APIHOOK_ENUM_ENTRY(LocalReAlloc)
APIHOOK_ENUM_ENTRY(LocalLock)
APIHOOK_ENUM_ENTRY(LocalUnlock)
APIHOOK_ENUM_ENTRY(LocalHandle)
APIHOOK_ENUM_ENTRY(LocalSize)
APIHOOK_ENUM_ENTRY(LocalFlags)
APIHOOK_ENUM_ENTRY(GlobalAlloc)
APIHOOK_ENUM_ENTRY(GlobalFree)
APIHOOK_ENUM_ENTRY(GlobalReAlloc)
APIHOOK_ENUM_ENTRY(GlobalLock)
APIHOOK_ENUM_ENTRY(GlobalUnlock)
APIHOOK_ENUM_ENTRY(GlobalHandle)
APIHOOK_ENUM_ENTRY(GlobalSize)
APIHOOK_ENUM_ENTRY(GlobalFlags)
APIHOOK_ENUM_ENTRY(RtlAllocateHeap)
APIHOOK_ENUM_ENTRY(RtlReAllocateHeap)
APIHOOK_ENUM_ENTRY(RtlFreeHeap)
APIHOOK_ENUM_ENTRY(RtlSizeHeap)
APIHOOK_ENUM_END
extern "C" {
BOOL _HeapInit();
HANDLE _HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize);
BOOL _HeapDestroy(HANDLE hHeap);
LPVOID _HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
LPVOID _HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);
BOOL _HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
DWORD _HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);
HLOCAL APIENTRY _LocalAlloc(UINT dwFlags, UINT dwBytes);
HLOCAL APIENTRY _LocalFree(HLOCAL hMem);
LPVOID _LocalReAlloc(LPVOID lpMem, SIZE_T dwBytes, UINT uFlags);
LPVOID _LocalLock(HLOCAL hMem);
BOOL _LocalUnlock(HLOCAL hMem);
HANDLE _LocalHandle(LPCVOID hMem);
UINT _LocalSize(HLOCAL hMem);
UINT _LocalFlags(HLOCAL hMem);
HANDLE _GetProcessHeap(void);
BOOL _IsOurHeap(HANDLE hHeap);
BOOL _IsOurLocalHeap(HANDLE hMem);
BOOL _IsOnOurHeap(LPCVOID lpMem);
}
/*++
Helper functions so as not to bloat the stubs.
--*/
BOOL UseOurHeap(HANDLE hHeap, LPCVOID lpMem)
{
return (_IsOurHeap(hHeap) || ((hHeap == RtlProcessHeap()) && _IsOnOurHeap(lpMem)));
}
BOOL ValidateNTHeap(HANDLE hHeap, LPCVOID lpMem)
{
BOOL bRet = FALSE;
__try
{
bRet = ORIGINAL_API(HeapValidate)(hHeap, 0, lpMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError, "[ValidateHeap] %08lx:%08lx is invalid", hHeap, lpMem);
}
return bRet;
}
/*++
Stub APIs.
--*/
LPVOID
APIHOOK(RtlAllocateHeap)(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes
)
{
if (_IsOurHeap(hHeap))
{
return _HeapAlloc(hHeap, dwFlags, dwBytes);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: RtlAllocateHeap");
return ORIGINAL_API(RtlAllocateHeap)(hHeap, dwFlags, dwBytes);
}
}
HANDLE
APIHOOK(HeapCreate)(
DWORD flOptions,
SIZE_T dwInitialSize,
SIZE_T dwMaximumSize
)
{
return _HeapCreate(flOptions, dwInitialSize, dwMaximumSize);
}
LPVOID
APIHOOK(RtlReAllocateHeap)(
HANDLE hHeap,
DWORD dwFlags,
LPVOID lpMem,
SIZE_T dwBytes
)
{
LPVOID uRet = FALSE;
if (UseOurHeap(hHeap, lpMem))
{
uRet = _HeapReAlloc(hHeap, dwFlags, lpMem, dwBytes);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: RtlReAllocateHeap");
if (ValidateNTHeap(hHeap, lpMem))
{
uRet = ORIGINAL_API(RtlReAllocateHeap)(hHeap, dwFlags, lpMem, dwBytes);
}
}
return uRet;
}
BOOL
APIHOOK(RtlFreeHeap)(
HANDLE hHeap,
DWORD dwFlags,
LPVOID lpMem
)
{
BOOL bRet = FALSE;
if (UseOurHeap(hHeap, lpMem))
{
bRet = _HeapFree(hHeap, dwFlags, lpMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: RtlFreeHeap");
if (ValidateNTHeap(hHeap, lpMem))
{
bRet = ORIGINAL_API(RtlFreeHeap)(hHeap, dwFlags, lpMem);
}
}
return bRet;
}
HANDLE
APIHOOK(GetProcessHeap)(VOID)
{
return _GetProcessHeap();
}
BOOL
APIHOOK(HeapDestroy)(HANDLE hHeap)
{
if (_IsOurHeap(hHeap))
{
return _HeapDestroy(hHeap);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: HeapDestroy");
return ORIGINAL_API(HeapDestroy)(hHeap);
}
}
DWORD
APIHOOK(RtlSizeHeap)(
HANDLE hHeap,
DWORD dwFlags,
LPCVOID lpMem
)
{
BOOL bRet = FALSE;
if (UseOurHeap(hHeap, lpMem))
{
bRet = _HeapSize(hHeap, dwFlags, lpMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: RtlSizeHeap");
if (ValidateNTHeap(hHeap, lpMem))
{
bRet = ORIGINAL_API(RtlSizeHeap)(hHeap, dwFlags, lpMem);
}
}
return bRet;
}
BOOL
APIHOOK(HeapValidate)(
HANDLE hHeap,
DWORD dwFlags,
LPCVOID lpMem
)
{
BOOL bRet = FALSE;
if (UseOurHeap(hHeap, lpMem))
{
// Win9x return values
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
bRet = -1;
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: HeapValidate");
__try
{
bRet = ORIGINAL_API(HeapValidate)(hHeap, dwFlags, lpMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError, "[HeapValidate] %08lx:%08lx is invalid", hHeap, lpMem);
}
}
return bRet;
}
HLOCAL
APIHOOK(LocalAlloc)(
UINT uFlags,
SIZE_T uBytes
)
{
return _LocalAlloc(uFlags, uBytes);
}
HLOCAL
APIHOOK(LocalFree)(
HLOCAL hMem
)
{
HLOCAL hRet = NULL;
if (_IsOurLocalHeap(hMem))
{
hRet = _LocalFree(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: LocalFree %08lx", hMem);
__try
{
hRet = ORIGINAL_API(LocalFree)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[LocalFree] Exception: Invalid Pointer %08lx", hMem);
}
}
return hRet;
}
HLOCAL
APIHOOK(LocalReAlloc)(
HLOCAL hMem,
SIZE_T uBytes,
UINT uFlags
)
{
HLOCAL hRet = NULL;
if (_IsOurLocalHeap(hMem))
{
hRet = _LocalReAlloc(hMem, uBytes, uFlags);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: LocalReAlloc %08lx", hMem);
__try
{
hRet = ORIGINAL_API(LocalReAlloc)(hMem, uBytes, uFlags);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[LocalReAlloc] Exception: Invalid Pointer %08lx", hMem);
}
}
return hRet;
}
LPVOID
APIHOOK(LocalLock)(
HLOCAL hMem
)
{
LPVOID pRet = NULL;
if (_IsOurLocalHeap(hMem))
{
pRet = _LocalLock(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: LocalLock %08lx", hMem);
__try
{
pRet = ORIGINAL_API(LocalLock)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[LocalLock] Exception: Invalid Pointer %08lx", hMem);
}
}
return pRet;
}
BOOL
APIHOOK(LocalUnlock)(
HLOCAL hMem
)
{
BOOL bRet = FALSE;
if (_IsOurLocalHeap(hMem))
{
bRet = _LocalUnlock(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: LocalUnlock %08lx", hMem);
__try
{
bRet = ORIGINAL_API(LocalUnlock)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[LocalUnLock] Exception: Invalid Pointer %08lx", hMem);
}
}
return bRet;
}
HANDLE
APIHOOK(LocalHandle)(
LPCVOID hMem
)
{
HANDLE hRet = NULL;
if (_IsOurLocalHeap((HANDLE)hMem))
{
hRet = _LocalHandle(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: LocalHandle %08lx", hMem);
__try
{
hRet = ORIGINAL_API(LocalHandle)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[LocalHandle] Exception: Invalid Pointer %08lx", hMem);
}
}
return hRet;
}
UINT
APIHOOK(LocalSize)(
HLOCAL hMem
)
{
UINT uRet = 0;
if (_IsOurLocalHeap(hMem))
{
uRet = _LocalSize(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: LocalSize %08lx", hMem);
__try
{
uRet = ORIGINAL_API(LocalSize)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[LocalSize] Exception: Invalid Pointer %08lx", hMem);
}
}
return uRet;
}
UINT
APIHOOK(LocalFlags)(
HLOCAL hMem
)
{
UINT uRet = 0;
if (_IsOurLocalHeap(hMem))
{
uRet = _LocalFlags(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: LocalFlags %08lx", hMem);
__try
{
uRet = ORIGINAL_API(LocalFlags)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[LocalFlags] Exception: Invalid Pointer %08lx", hMem);
}
}
return uRet;
}
HGLOBAL
APIHOOK(GlobalAlloc)(
UINT uFlags,
SIZE_T uBytes
)
{
uFlags = (((uFlags & GMEM_ZEROINIT) ? LMEM_ZEROINIT : 0 ) |
((uFlags & GMEM_MOVEABLE) ? LMEM_MOVEABLE : 0 ) |
((uFlags & GMEM_FIXED) ? LMEM_FIXED : 0 ));
return _LocalAlloc(uFlags, uBytes);
}
HGLOBAL
APIHOOK(GlobalFree)(
HGLOBAL hMem
)
{
HGLOBAL hRet = NULL;
if (_IsOurLocalHeap(hMem))
{
hRet = _LocalFree(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: GlobalFree %08lx", hMem);
__try
{
hRet = ORIGINAL_API(GlobalFree)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[GlobalFree] Exception: Invalid Pointer %08lx", hMem);
}
}
return hRet;
}
HGLOBAL
APIHOOK(GlobalReAlloc)(
HGLOBAL hMem,
SIZE_T uBytes,
UINT uFlags
)
{
UINT uLocalFlags =
(((uFlags & GMEM_ZEROINIT) ? LMEM_ZEROINIT : 0 ) |
((uFlags & GMEM_MOVEABLE) ? LMEM_MOVEABLE : 0 ) |
((uFlags & GMEM_FIXED) ? LMEM_FIXED : 0 ));
HLOCAL hRet = NULL;
if (_IsOurLocalHeap(hMem))
{
hRet = _LocalReAlloc(hMem, uBytes, uLocalFlags);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: GlobalReAlloc %08lx", hMem);
__try
{
hRet = ORIGINAL_API(GlobalReAlloc)(hMem, uBytes, uFlags);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[GlobalReAlloc] Exception: Invalid Pointer %08lx", hMem);
}
}
return hRet;
}
LPVOID
APIHOOK(GlobalLock)(
HGLOBAL hMem
)
{
LPVOID pRet = NULL;
if (_IsOurLocalHeap(hMem))
{
pRet = _LocalLock(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: GlobalLock %08lx", hMem);
__try
{
pRet = ORIGINAL_API(GlobalLock)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[GlobalLock] Exception: Invalid Pointer %08lx", hMem);
}
}
return pRet;
}
BOOL
APIHOOK(GlobalUnlock)(
HGLOBAL hMem
)
{
BOOL bRet = FALSE;
if (_IsOurLocalHeap(hMem))
{
bRet = _LocalUnlock(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: GlobalUnlock %08lx", hMem);
__try
{
bRet = ORIGINAL_API(GlobalUnlock)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[GlobalUnLock] Exception: Invalid Pointer %08lx", hMem);
}
}
return bRet;
}
HANDLE
APIHOOK(GlobalHandle)(
LPCVOID hMem
)
{
HANDLE hRet = NULL;
if (_IsOurLocalHeap((HANDLE)hMem))
{
hRet = _LocalHandle(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: GlobalHandle %08lx", hMem);
__try
{
hRet = ORIGINAL_API(GlobalHandle)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[GlobalHandle] Exception: Invalid Pointer %08lx for Heap",
hMem);
}
}
return hRet;
}
UINT
APIHOOK(GlobalSize)(
HGLOBAL hMem
)
{
UINT uRet = 0;
if (_IsOurLocalHeap(hMem))
{
uRet = _LocalSize(hMem);
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: GlobalSize %08lx", hMem);
__try
{
uRet = ORIGINAL_API(GlobalSize)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[GlobalSize] Exception: Invalid Pointer %08lx for Heap",
hMem);
}
}
return uRet;
}
UINT
APIHOOK(GlobalFlags)(
HGLOBAL hMem
)
{
UINT uRet = 0;
if (_IsOurLocalHeap(hMem))
{
uRet = _LocalFlags(hMem);
// Convert the flags
UINT uNewRet = uRet;
uRet = 0;
if (uNewRet & LMEM_DISCARDABLE)
{
uRet |= GMEM_DISCARDABLE;
}
if (uNewRet & LMEM_DISCARDED)
{
uRet |= GMEM_DISCARDED;
}
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: GlobalFlags %08lx", hMem);
__try
{
uRet = ORIGINAL_API(GlobalFlags)(hMem);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LOGN( eDbgLevelError,
"[GlobalFlags] Exception: Invalid Pointer %08lx for Heap",
hMem);
}
}
return uRet;
}
UINT
APIHOOK(HeapCompact)(
HANDLE hHeap,
DWORD dwFlags
)
{
if (_IsOurHeap(hHeap))
{
// Win9x return values
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: HeapCompact");
return ORIGINAL_API(HeapCompact)(hHeap, dwFlags);
}
}
BOOL
APIHOOK(HeapWalk)(
HANDLE hHeap,
LPPROCESS_HEAP_ENTRY pEntry
)
{
if (_IsOurHeap(hHeap))
{
// Win9x return values
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: HeapWalk");
return ORIGINAL_API(HeapWalk)(hHeap, pEntry);
}
}
BOOL
APIHOOK(HeapLock)(
HANDLE hHeap
)
{
if (_IsOurHeap(hHeap))
{
// Win9x return values
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: HeapLock");
return ORIGINAL_API(HeapLock)(hHeap);
}
}
BOOL
APIHOOK(HeapUnlock)(
HANDLE hHeap
)
{
if (_IsOurHeap(hHeap))
{
// Win9x return values
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
else
{
DPFN( eDbgLevelInfo, "NTHEAP: HeapUnlock");
return ORIGINAL_API(HeapUnlock)(hHeap);
}
}
/*++
Register hooked functions
--*/
BOOL
NOTIFY_FUNCTION(
DWORD fdwReason
)
{
BOOL bRet = TRUE;
if (fdwReason == DLL_PROCESS_ATTACH)
{
bRet = _HeapInit();
if (bRet)
{
LOGN(eDbgLevelInfo, "[NotifyFn] Win9x heap manager initialized");
}
else
{
LOGN(eDbgLevelError, "[NotifyFn] Win9x heap manager initialization failed!");
}
}
return bRet;
}
HOOK_BEGIN
CALL_NOTIFY_FUNCTION
APIHOOK_ENTRY(KERNEL32.DLL, HeapCreate)
APIHOOK_ENTRY(KERNEL32.DLL, HeapDestroy)
APIHOOK_ENTRY(KERNEL32.DLL, HeapValidate)
APIHOOK_ENTRY(KERNEL32.DLL, HeapCompact)
APIHOOK_ENTRY(KERNEL32.DLL, HeapWalk)
APIHOOK_ENTRY(KERNEL32.DLL, HeapLock)
APIHOOK_ENTRY(KERNEL32.DLL, HeapUnlock)
APIHOOK_ENTRY(KERNEL32.DLL, GetProcessHeap)
APIHOOK_ENTRY(KERNEL32.DLL, LocalAlloc)
APIHOOK_ENTRY(KERNEL32.DLL, LocalFree)
APIHOOK_ENTRY(KERNEL32.DLL, LocalReAlloc)
APIHOOK_ENTRY(KERNEL32.DLL, LocalLock)
APIHOOK_ENTRY(KERNEL32.DLL, LocalUnlock)
APIHOOK_ENTRY(KERNEL32.DLL, LocalHandle)
APIHOOK_ENTRY(KERNEL32.DLL, LocalSize)
APIHOOK_ENTRY(KERNEL32.DLL, LocalFlags)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalAlloc)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalFree)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalReAlloc)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalLock)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalUnlock)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalHandle)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalSize)
APIHOOK_ENTRY(KERNEL32.DLL, GlobalFlags)
APIHOOK_ENTRY(NTDLL.DLL, RtlAllocateHeap)
APIHOOK_ENTRY(NTDLL.DLL, RtlReAllocateHeap)
APIHOOK_ENTRY(NTDLL.DLL, RtlFreeHeap)
APIHOOK_ENTRY(NTDLL.DLL, RtlSizeHeap)
HOOK_END
IMPLEMENT_SHIM_END