blob: 5123c8267e8191afafb6125d9a51693827eda2c1 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2014 Google, Inc. All rights reserved.
* Copyright (c) 2009-2010 Derek Bruening All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* kernel32 and kernelbase redirection routines */
#include "kernel32_redir.h" /* must be included first */
#include "../../globals.h"
#include "drwinapi.h"
#include "drwinapi_private.h"
#ifndef WINDOWS
# error Windows-only
#endif
/* We use a hashtale for faster lookups than a linear walk */
static strhash_table_t *kernel32_table;
static const redirect_import_t redirect_kernel32[] = {
/* Process and thread-related routines */
{"GetCurrentProcess", (app_pc)redirect_GetCurrentProcess},
{"GetCurrentProcessId", (app_pc)redirect_GetCurrentProcessId},
{"GetCurrentThread", (app_pc)redirect_GetCurrentThread},
{"GetCurrentThreadId", (app_pc)redirect_GetCurrentThreadId},
{"ExitProcess", (app_pc)redirect_ExitProcess},
/* To avoid the FlsCallback being interpreted, and to avoid hangs
* and other issues with Fls locks (i#875).
*/
{"FlsAlloc", (app_pc)redirect_FlsAlloc},
{"FlsFree", (app_pc)redirect_FlsFree},
{"FlsGetValue", (app_pc)redirect_FlsGetValue},
{"FlsSetValue", (app_pc)redirect_FlsSetValue},
/* Library routines */
/* As an initial interception of loader queries, but simpler than
* intercepting Ldr*: plus, needed to intercept FlsAlloc called by msvcrt
* init routine.
* XXX i#235: redirect GetModuleHandle{ExA,ExW} as well
*/
{"GetModuleHandleA", (app_pc)redirect_GetModuleHandleA},
{"GetModuleHandleW", (app_pc)redirect_GetModuleHandleW},
{"GetProcAddress", (app_pc)redirect_GetProcAddress},
{"LoadLibraryA", (app_pc)redirect_LoadLibraryA},
{"LoadLibraryW", (app_pc)redirect_LoadLibraryW},
{"LoadLibraryExA", (app_pc)redirect_LoadLibraryExA},
{"LoadLibraryExW", (app_pc)redirect_LoadLibraryExW},
{"FreeLibrary", (app_pc)redirect_FreeLibrary},
{"GetModuleFileNameA", (app_pc)redirect_GetModuleFileNameA},
{"GetModuleFileNameW", (app_pc)redirect_GetModuleFileNameW},
/* Memory-related routines */
{"DecodePointer", (app_pc)redirect_DecodePointer},
{"EncodePointer", (app_pc)redirect_EncodePointer},
{"GetProcessHeap", (app_pc)redirect_GetProcessHeap},
{"HeapAlloc", (app_pc)redirect_HeapAlloc},
{"HeapCompact", (app_pc)redirect_HeapCompact},
{"HeapCreate", (app_pc)redirect_HeapCreate},
{"HeapDestroy", (app_pc)redirect_HeapDestroy},
{"HeapFree", (app_pc)redirect_HeapFree},
{"HeapReAlloc", (app_pc)redirect_HeapReAlloc},
{"HeapSetInformation ", (app_pc)redirect_HeapSetInformation},
{"HeapSize", (app_pc)redirect_HeapSize},
{"HeapValidate", (app_pc)redirect_HeapValidate},
{"HeapWalk", (app_pc)redirect_HeapWalk},
{"IsBadReadPtr", (app_pc)redirect_IsBadReadPtr},
{"LocalAlloc", (app_pc)redirect_LocalAlloc},
{"LocalFree", (app_pc)redirect_LocalFree},
{"LocalReAlloc", (app_pc)redirect_LocalReAlloc},
{"LocalLock", (app_pc)redirect_LocalLock},
{"LocalHandle", (app_pc)redirect_LocalHandle},
{"LocalUnlock", (app_pc)redirect_LocalUnlock},
{"LocalSize", (app_pc)redirect_LocalSize},
{"LocalFlags", (app_pc)redirect_LocalFlags},
{"ReadProcessMemory", (app_pc)redirect_ReadProcessMemory},
{"VirtualAlloc", (app_pc)redirect_VirtualAlloc},
{"VirtualFree", (app_pc)redirect_VirtualFree},
{"VirtualProtect", (app_pc)redirect_VirtualProtect},
{"VirtualQuery", (app_pc)redirect_VirtualQuery},
{"VirtualQueryEx", (app_pc)redirect_VirtualQueryEx},
/* File-related routines */
{"CreateDirectoryA", (app_pc)redirect_CreateDirectoryA},
{"CreateDirectoryW", (app_pc)redirect_CreateDirectoryW},
{"RemoveDirectoryA", (app_pc)redirect_RemoveDirectoryA},
{"RemoveDirectoryW", (app_pc)redirect_RemoveDirectoryW},
{"GetCurrentDirectoryA", (app_pc)redirect_GetCurrentDirectoryA},
{"GetCurrentDirectoryW", (app_pc)redirect_GetCurrentDirectoryW},
{"SetCurrentDirectoryA", (app_pc)redirect_SetCurrentDirectoryA},
{"SetCurrentDirectoryW", (app_pc)redirect_SetCurrentDirectoryW},
{"CreateFileA", (app_pc)redirect_CreateFileA},
{"CreateFileW", (app_pc)redirect_CreateFileW},
{"DeleteFileA", (app_pc)redirect_DeleteFileA},
{"DeleteFileW", (app_pc)redirect_DeleteFileW},
{"ReadFile", (app_pc)redirect_ReadFile},
#if 0 /* FIXME i#1089: disabling until we have console support */
{"WriteFile", (app_pc)redirect_WriteFile},
#endif
{"CreateFileMappingA", (app_pc)redirect_CreateFileMappingA},
{"CreateFileMappingW", (app_pc)redirect_CreateFileMappingW},
{"MapViewOfFile", (app_pc)redirect_MapViewOfFile},
{"MapViewOfFileEx", (app_pc)redirect_MapViewOfFileEx},
{"UnmapViewOfFile", (app_pc)redirect_UnmapViewOfFile},
{"FlushViewOfFile", (app_pc)redirect_FlushViewOfFile},
{"CreatePipe", (app_pc)redirect_CreatePipe},
{"DeviceIoControl", (app_pc)redirect_DeviceIoControl},
{"CloseHandle", (app_pc)redirect_CloseHandle},
{"DuplicateHandle", (app_pc)redirect_DuplicateHandle},
{"FileTimeToLocalFileTime", (app_pc)redirect_FileTimeToLocalFileTime},
{"LocalFileTimeToFileTime", (app_pc)redirect_LocalFileTimeToFileTime},
{"FileTimeToSystemTime", (app_pc)redirect_FileTimeToSystemTime},
{"SystemTimeToFileTime", (app_pc)redirect_SystemTimeToFileTime},
{"GetSystemTimeAsFileTime", (app_pc)redirect_GetSystemTimeAsFileTime},
{"GetFileTime", (app_pc)redirect_GetFileTime},
{"SetFileTime", (app_pc)redirect_SetFileTime},
{"FindClose", (app_pc)redirect_FindClose},
{"FindFirstFileA", (app_pc)redirect_FindFirstFileA},
{"FindFirstFileW", (app_pc)redirect_FindFirstFileW},
{"FindNextFileA", (app_pc)redirect_FindNextFileA},
{"FindNextFileW", (app_pc)redirect_FindNextFileW},
{"FlushFileBuffers", (app_pc)redirect_FlushFileBuffers},
{"GetDiskFreeSpaceA", (app_pc)redirect_GetDiskFreeSpaceA},
{"GetDiskFreeSpaceW", (app_pc)redirect_GetDiskFreeSpaceW},
{"GetDriveTypeA", (app_pc)redirect_GetDriveTypeA},
{"GetDriveTypeW", (app_pc)redirect_GetDriveTypeW},
{"GetFileAttributesA", (app_pc)redirect_GetFileAttributesA},
{"GetFileAttributesW", (app_pc)redirect_GetFileAttributesW},
{"GetFileInformationByHandle", (app_pc)redirect_GetFileInformationByHandle},
{"GetFileSize", (app_pc)redirect_GetFileSize},
{"GetFileType", (app_pc)redirect_GetFileType},
/* skipped a few in alpha order, to focus on those invoked by dbghelp */
{"GetStdHandle", (app_pc)redirect_GetStdHandle},
/* Synchronization routines */
{"InitializeCriticalSectionAndSpinCount",
(app_pc)redirect_InitializeCriticalSectionAndSpinCount},
{"InitializeCriticalSectionEx", (app_pc)redirect_InitializeCriticalSectionEx},
{"DeleteCriticalSection", (app_pc)redirect_DeleteCriticalSection},
{"EnterCriticalSection", (app_pc)redirect_EnterCriticalSection},
{"LeaveCriticalSection", (app_pc)redirect_LeaveCriticalSection},
{"InterlockedCompareExchange ", (app_pc)redirect_InterlockedCompareExchange },
{"InterlockedDecrement", (app_pc)redirect_InterlockedDecrement},
{"InterlockedExchange", (app_pc)redirect_InterlockedExchange},
{"InterlockedIncrement", (app_pc)redirect_InterlockedIncrement},
{"WaitForSingleObject", (app_pc)redirect_WaitForSingleObject},
/* Miscellaneous routines */
{"GetLastError", (app_pc)redirect_GetLastError},
{"SetLastError", (app_pc)redirect_SetLastError},
};
#define REDIRECT_KERNEL32_NUM (sizeof(redirect_kernel32)/sizeof(redirect_kernel32[0]))
void
kernel32_redir_init(void)
{
uint i;
kernel32_table =
strhash_hash_create(GLOBAL_DCONTEXT,
hashtable_num_bits(REDIRECT_KERNEL32_NUM*2),
80 /* load factor: not perf-critical, plus static */,
HASHTABLE_SHARED | HASHTABLE_PERSISTENT,
NULL _IF_DEBUG("kernel32 redirection table"));
TABLE_RWLOCK(kernel32_table, write, lock);
for (i = 0; i < REDIRECT_KERNEL32_NUM; i++) {
strhash_hash_add(GLOBAL_DCONTEXT, kernel32_table, redirect_kernel32[i].name,
(void *) redirect_kernel32[i].func);
}
TABLE_RWLOCK(kernel32_table, write, unlock);
kernel32_redir_init_proc();
kernel32_redir_init_mem();
kernel32_redir_init_file();
}
void
kernel32_redir_exit(void)
{
kernel32_redir_exit_file();
kernel32_redir_exit_mem();
kernel32_redir_exit_proc();
strhash_hash_destroy(GLOBAL_DCONTEXT, kernel32_table);
}
void
kernel32_redir_onload(privmod_t *mod)
{
if (!dynamo_initialized)
SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT);
/* Rather than statically linking to real kernel32 we want to invoke
* routines in the private kernel32 so we look them up here.
*/
/* We give sub-modules a chance to remove entries from the table (i#1385) */
TABLE_RWLOCK(kernel32_table, write, lock);
kernel32_redir_onload_proc(mod, kernel32_table);
kernel32_redir_onload_lib(mod);
kernel32_redir_onload_file(mod);
TABLE_RWLOCK(kernel32_table, write, unlock);
if (!dynamo_initialized)
SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT);
}
/* We assume the caller has already ruled out kernel32 calling into kernelbase,
* which we do not want to redirect.
*/
app_pc
kernel32_redir_lookup(const char *name)
{
app_pc res;
TABLE_RWLOCK(kernel32_table, read, lock);
res = strhash_hash_lookup(GLOBAL_DCONTEXT, kernel32_table, name);
TABLE_RWLOCK(kernel32_table, read, unlock);
return res;
}