windows-nt/Source/XPSP1/NT/windows/appcompat/shims/layer/handleapiexceptions.cpp

395 lines
8.7 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
HandleAPIExceptions.cpp
Abstract:
Handle exceptions thrown by APIs that used to simply fail on Win9x. So far
we have:
1. BackupSeek: AVs if hFile == NULL
2. CreateEvent passed bad lpEventAttributes and/or lpName
3. GetFileAttributes
Also emulate the win9x behavior for VirtualProtect, whereby the last
parameter can be NULL.
GetTextExtentPoint32 AV's when a large/uninitialized value is passed for
the string length. This API now emulates Win9x.
Add sanity checks to pointers in the call to GetMenuItemInfo. This is to match 9x, as
some apps to pass bogus pointers and it AV on NT.
When wsprintf receives lpFormat argument as NULL, no AV on 9x.
But it AV on XP.Shim verifies format string, if it is NULL return the call don't forward
Notes:
This is a general purpose shim.
History:
04/03/2000 linstev Created
04/01/2001 linstev Munged with other exception handling shims
07/11/2001 prashkud Added handling for GetTextExtentPoint32
04/24/2002 v-ramora Added handling for wsprintfA
--*/
#include "precomp.h"
#include "LegalStr.h"
IMPLEMENT_SHIM_BEGIN(HandleAPIExceptions)
#include "ShimHookMacro.h"
APIHOOK_ENUM_BEGIN
APIHOOK_ENUM_ENTRY(BackupSeek)
APIHOOK_ENUM_ENTRY(CreateEventA)
APIHOOK_ENUM_ENTRY(CreateEventW)
APIHOOK_ENUM_ENTRY(GetFileAttributesA)
APIHOOK_ENUM_ENTRY(GetFileAttributesW)
APIHOOK_ENUM_ENTRY(VirtualProtect)
APIHOOK_ENUM_ENTRY(GetTextExtentPoint32A)
APIHOOK_ENUM_ENTRY(GetMenuItemInfoA)
APIHOOK_ENUM_ENTRY(wsprintfA)
APIHOOK_ENUM_END
#define MAX_WIN9X_STRSIZE 8192
/*++
Stub returns for bad parameters.
--*/
BOOL
APIHOOK(BackupSeek)(
HANDLE hFile,
DWORD dwLowBytesToSeek,
DWORD dwHighBytesToSeek,
LPDWORD lpdwLowBytesSeeked,
LPDWORD lpdwHighBytesSeeked,
LPVOID *lpContext
)
{
if (!hFile) {
LOGN(
eDbgLevelError,
"[BackupSeek] Bad parameter, returning NULL");
return NULL;
}
DWORD dwLowSeeked, dwHighSeeked;
if (IsBadWritePtr(lpdwLowBytesSeeked, 4)) {
LOGN(
eDbgLevelError,
"[BackupSeek] Bad parameter, fixing");
lpdwLowBytesSeeked = &dwLowSeeked;
}
if (IsBadWritePtr(lpdwHighBytesSeeked, 4)) {
LOGN(
eDbgLevelError,
"[BackupSeek] Bad parameter, fixing");
lpdwHighBytesSeeked = &dwHighSeeked;
}
return ORIGINAL_API(BackupSeek)(hFile, dwLowBytesToSeek, dwHighBytesToSeek,
lpdwLowBytesSeeked, lpdwHighBytesSeeked, lpContext);
}
/*++
Validate parameters
--*/
HANDLE
APIHOOK(CreateEventA)(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCSTR lpName
)
{
if (lpEventAttributes &&
IsBadReadPtr(lpEventAttributes, sizeof(*lpEventAttributes))) {
LOGN(
eDbgLevelError,
"[CreateEventA] Bad parameter, returning NULL");
return NULL;
}
if (lpName &&
IsBadStringPtrA(lpName, MAX_PATH)) {
LOGN(
eDbgLevelError,
"[CreateEventA] Bad parameter, returning NULL");
return NULL;
}
return (ORIGINAL_API(CreateEventA)(lpEventAttributes, bManualReset,
bInitialState, lpName));
}
/*++
Validate parameters
--*/
HANDLE
APIHOOK(CreateEventW)(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCWSTR lpName
)
{
if (lpEventAttributes &&
IsBadReadPtr(lpEventAttributes, sizeof(*lpEventAttributes))) {
LOGN(
eDbgLevelError,
"[CreateEventW] Bad parameter, returning NULL");
return NULL;
}
if (lpName &&
IsBadStringPtrW(lpName, MAX_PATH)) {
LOGN(
eDbgLevelError,
"[CreateEventW] Bad parameter, returning NULL");
return NULL;
}
return (ORIGINAL_API(CreateEventW)(lpEventAttributes, bManualReset,
bInitialState, lpName));
}
/*++
This function to emulate Win9x behaviour when getting file attributes.
--*/
DWORD
APIHOOK(GetFileAttributesA)(
LPCSTR lpFileName
)
{
DWORD dwFileAttributes = INVALID_FILE_ATTRIBUTES;
if (!IsBadStringPtrA(lpFileName, MAX_PATH)) {
dwFileAttributes = ORIGINAL_API(GetFileAttributesA)(
lpFileName);
} else {
LOGN(
eDbgLevelError,
"[GetFileAttributesA] Bad parameter - returning INVALID_FILE_ATTRIBUTES.");
}
return dwFileAttributes;
}
/*++
This function is used to emulate Win9x behaviour when getting file attributes.
--*/
DWORD
APIHOOK(GetFileAttributesW)(
LPCWSTR lpFileName
)
{
DWORD dwFileAttributes = INVALID_FILE_ATTRIBUTES;
if (!IsBadStringPtrW(lpFileName, MAX_PATH)) {
dwFileAttributes = ORIGINAL_API(GetFileAttributesW)(
lpFileName);
} else {
LOGN(
eDbgLevelError,
"[GetFileAttributesW] Bad parameter - returning INVALID_FILE_ATTRIBUTES.");
}
return dwFileAttributes;
}
/*++
Win9x allowed the last parameter to be NULL.
--*/
BOOL
APIHOOK(VirtualProtect)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
)
{
DWORD dwOldProtect = 0;
if (!lpflOldProtect) {
//
// Detected a bad last parameter, fix it.
//
LOGN(eDbgLevelError, "[VirtualProtect] Bad parameter - fixing");
lpflOldProtect = &dwOldProtect;
}
return ORIGINAL_API(VirtualProtect)(lpAddress, dwSize, flNewProtect, lpflOldProtect);
}
/*++
Win9x only allows 8192 for the size of the string
--*/
BOOL
APIHOOK(GetTextExtentPoint32A)(
HDC hdc,
LPCSTR lpString,
int cbString,
LPSIZE lpSize
)
{
if (cbString > MAX_WIN9X_STRSIZE) {
//
// Detected a bad string size, fix it.
//
if (!IsBadStringPtrA(lpString, cbString)) {
cbString = strlen(lpString);
LOGN(eDbgLevelError, "[GetTextExtentPoint32A] Bad parameter - fixing");
} else {
LOGN(eDbgLevelError, "[GetTextExtentPoint32A] Bad parameter - returning FALSE");
return FALSE;
}
}
return ORIGINAL_API(GetTextExtentPoint32A)(hdc, lpString, cbString, lpSize);
}
/*++
Emulate Win9x bad pointer protection.
--*/
BOOL
APIHOOK(GetMenuItemInfoA)(
HMENU hMenu, // handle to menu
UINT uItem, // menu item
BOOL fByPosition, // meaning of uItem
LPMENUITEMINFO lpmii // menu item information
)
{
if (IsBadWritePtr(lpmii, sizeof(*lpmii))) {
LOGN(eDbgLevelInfo, "[GetMenuItemInfoA] invalid lpmii pointer, returning FALSE");
return FALSE;
}
if ((lpmii->fMask & MIIM_STRING || lpmii->fMask & MIIM_TYPE) && (lpmii->cch !=0)) {
MENUITEMINFO MyMII={0};
ULONG cch;
MyMII.cbSize = sizeof(MyMII);
MyMII.fMask = MIIM_STRING;
if (ORIGINAL_API(GetMenuItemInfoA)(hMenu, uItem, fByPosition, &MyMII)) {
cch = min(lpmii->cch, MyMII.cch + 1);
if (IsBadWritePtr(lpmii->dwTypeData, cch)) {
LOGN(eDbgLevelInfo, "[GetMenuItemInfoA] invalid pointer for string, clearing it");
lpmii->dwTypeData = 0;
}
} else {
DPFN(eDbgLevelError, "[GetMenuItemInfoA] Internal call to find string size fail (%08X)", GetLastError());
}
}
return ORIGINAL_API(GetMenuItemInfoA)(hMenu, uItem, fByPosition, lpmii);
}
/*++
Make sure format string for wsprintfA is not NULL
--*/
//Avoid wvsprintfA deprecated warning/error
#pragma warning(disable : 4995)
int
APIHOOK(wsprintfA)(
LPSTR lpOut,
LPCSTR lpFmt,
...)
{
int iRet = 0;
//
// lpFmt can't be NULL, wvsprintfA throw AV
//
if (lpFmt == NULL) {
if (!IsBadWritePtr(lpOut, 1)) {
*lpOut = '\0';
}
DPFN( eDbgLevelInfo, "[wsprintfA] received NULL as format string");
return iRet;
}
va_list arglist;
va_start(arglist, lpFmt);
iRet = wvsprintfA(lpOut, lpFmt, arglist);
va_end(arglist);
return iRet;
}
//Enable back deprecated warning/error
#pragma warning(default : 4995)
/*++
Register hooked functions
--*/
HOOK_BEGIN
APIHOOK_ENTRY(KERNEL32.DLL, BackupSeek)
APIHOOK_ENTRY(KERNEL32.DLL, CreateEventA)
APIHOOK_ENTRY(KERNEL32.DLL, CreateEventW)
APIHOOK_ENTRY(KERNEL32.DLL, GetFileAttributesA)
APIHOOK_ENTRY(KERNEL32.DLL, GetFileAttributesW)
APIHOOK_ENTRY(KERNEL32.DLL, VirtualProtect)
APIHOOK_ENTRY(GDI32.DLL, GetTextExtentPoint32A)
APIHOOK_ENTRY(USER32.DLL, GetMenuItemInfoA)
APIHOOK_ENTRY(USER32.DLL, wsprintfA)
HOOK_END
IMPLEMENT_SHIM_END