blob: 08cd58af1e79c07e909da928baeb1d44f188ef66 [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.
*/
/* Shared redirection code for custom private library loader */
#include "kernel32_redir.h" /* must be included first */
#include "../globals.h"
#include "ntdll_redir.h"
#include "rpcrt4_redir.h"
#include "advapi32_redir.h"
#ifndef WINDOWS
# error Windows-only
#endif
void
drwinapi_init(void)
{
ntdll_redir_init();
kernel32_redir_init();
rpcrt4_redir_init();
advapi32_redir_init();
}
void
drwinapi_exit(void)
{
advapi32_redir_exit();
rpcrt4_redir_exit();
kernel32_redir_exit();
ntdll_redir_exit();
}
void
drwinapi_onload(privmod_t *mod)
{
if (mod->name == NULL)
return;
if (strcasecmp(mod->name, "kernel32.dll") == 0)
kernel32_redir_onload(mod);
else if (strcasecmp(mod->name, "rpcrt4.dll") == 0)
rpcrt4_redir_onload(mod);
else if (strcasecmp(mod->name, "advapi32.dll") == 0)
advapi32_redir_onload(mod);
}
app_pc
drwinapi_redirect_imports(privmod_t *impmod, const char *name, privmod_t *importer)
{
if (strcasecmp(impmod->name, "ntdll.dll") == 0) {
return ntdll_redir_lookup(name);
} else if (strcasecmp(impmod->name, "kernel32.dll") == 0 ||
strcasecmp(impmod->name, "kernelbase.dll") == 0) {
app_pc res = kernel32_redir_lookup(name);
if (res == NULL) {
/* win7 has some Reg* routines in kernel32 so we check advapi */
res = advapi32_redir_lookup(name);
}
if (res != NULL && get_os_version() >= WINDOWS_VERSION_7 &&
importer != NULL && strcasecmp(importer->name, "kernel32.dll") == 0) {
/* We can't redirect kernel32.dll's calls to kernelbase when we ourselves
* call the kernel32.dll routine when our redirection fails.
*
* XXX: we could add a 2nd return val from the lookup, but there are
* only a few of these and as time goes forward this set should ideally
* shrink to zero. Thus we hardcode here.
*
* XXX: might some dlls import from kernelbase instead of kernel32 and
* bypass our redirection altogether? Yet another reason to eliminate
* our redirection routines calling back into the priv libs.
*/
if (strcmp(name, "GetModuleHandleA") == 0 ||
strcmp(name, "GetModuleHandleW") == 0 ||
strcmp(name, "GetProcAddress") == 0 ||
strcmp(name, "LoadLibraryA") == 0 ||
strcmp(name, "LoadLibraryW") == 0)
return NULL;
}
return res;
} else if (strcasecmp(impmod->name, "rpcrt4.dll") == 0) {
return rpcrt4_redir_lookup(name);
} else if (strcasecmp(impmod->name, "advapi32.dll") == 0) {
return advapi32_redir_lookup(name);
}
return NULL;
}
bool
drwinapi_redirect_getprocaddr(app_pc modbase, const char *name, app_pc *res_out OUT)
{
privmod_t *mod;
app_pc res = NULL;
acquire_recursive_lock(&privload_lock);
mod = privload_lookup_by_base((app_pc)modbase);
if (mod != NULL) {
const char *forwarder;
res = drwinapi_redirect_imports(mod, name, NULL);
/* I assume GetProcAddress returns NULL for forwarded exports? */
if (res == NULL)
res = (app_pc) get_proc_address_ex((app_pc)modbase, name, &forwarder);
LOG(GLOBAL, LOG_LOADER, 2, "%s: %s => "PFX"\n", __FUNCTION__, name, res);
}
release_recursive_lock(&privload_lock);
*res_out = res;
return (mod != NULL);
}
DWORD
ntstatus_to_last_error(NTSTATUS status)
{
/* I don't want to rely on RtlNtStatusToDosError not working
* at earliest init time or something so I'm doing my own mapping.
*/
switch (status) {
case STATUS_SUCCESS: return ERROR_SUCCESS;
case STATUS_INVALID_HANDLE: return ERROR_INVALID_HANDLE;
case STATUS_ACCESS_DENIED: return ERROR_ACCESS_DENIED;
case STATUS_INVALID_PARAMETER: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_1: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_2: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_3: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_4: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_5: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_6: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_7: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_8: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_9: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_10: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_11: return ERROR_INVALID_PARAMETER;
case STATUS_INVALID_PARAMETER_12: return ERROR_INVALID_PARAMETER;
case STATUS_OBJECT_NAME_EXISTS: return ERROR_ALREADY_EXISTS;
case STATUS_OBJECT_NAME_COLLISION: return ERROR_ALREADY_EXISTS;
case STATUS_OBJECT_NAME_NOT_FOUND: return ERROR_FILE_NOT_FOUND;
case STATUS_OBJECT_NAME_INVALID: return ERROR_INVALID_NAME;
case STATUS_OBJECT_PATH_INVALID: return ERROR_BAD_PATHNAME;
case STATUS_OBJECT_PATH_NOT_FOUND: return ERROR_PATH_NOT_FOUND;
case STATUS_MAPPED_FILE_SIZE_ZERO: return ERROR_FILE_INVALID;
case STATUS_INVALID_PAGE_PROTECTION: return ERROR_INVALID_PARAMETER;
case STATUS_FILE_LOCK_CONFLICT: return ERROR_LOCK_VIOLATION;
case STATUS_INVALID_FILE_FOR_SECTION: return ERROR_BAD_EXE_FORMAT;
case STATUS_SECTION_TOO_BIG: return ERROR_NOT_ENOUGH_MEMORY;
case STATUS_OBJECT_TYPE_MISMATCH: return ERROR_INVALID_HANDLE;
case STATUS_BUFFER_OVERFLOW: return ERROR_MORE_DATA;
case STATUS_NO_SUCH_FILE: return ERROR_FILE_NOT_FOUND;
case STATUS_NO_MORE_FILES: return ERROR_NO_MORE_FILES;
case STATUS_INFO_LENGTH_MISMATCH: return ERROR_BAD_LENGTH;
case STATUS_NOT_MAPPED_DATA: return ERROR_INVALID_ADDRESS;
case STATUS_THREAD_IS_TERMINATING: return ERROR_ACCESS_DENIED;
case STATUS_PROCESS_IS_TERMINATING: return ERROR_ACCESS_DENIED;
case STATUS_END_OF_FILE: return ERROR_HANDLE_EOF;
case STATUS_PENDING: return ERROR_IO_PENDING;
case STATUS_NOT_A_REPARSE_POINT: return ERROR_NOT_A_REPARSE_POINT;
/* XXX: add more. Variations by function are rare and handled in callers. */
default: return ERROR_INVALID_PARAMETER;
}
}
BOOL WINAPI
redirect_ignore_arg0(void)
{
return TRUE;
}
BOOL WINAPI
redirect_ignore_arg4(void *arg1)
{
return TRUE;
}
BOOL WINAPI
redirect_ignore_arg8(void *arg1, void *arg2)
{
return TRUE;
}
BOOL WINAPI
redirect_ignore_arg12(void *arg1, void *arg2, void *arg3)
{
return TRUE;
}
#ifdef STANDALONE_UNIT_TEST
void unit_test_drwinapi_kernel32_proc(void);
void unit_test_drwinapi_kernel32_mem(void);
void unit_test_drwinapi_kernel32_file(void);
void unit_test_drwinapi_kernel32_sync(void);
void unit_test_drwinapi_kernel32_misc(void);
void unit_test_drwinapi_rpcrt4(void);
void unit_test_drwinapi_advapi32(void);
void
unit_test_drwinapi(void)
{
print_file(STDERR, "testing drwinapi\n");
loader_init(); /* not called by standalone_init */
unit_test_drwinapi_kernel32_proc();
unit_test_drwinapi_kernel32_mem();
unit_test_drwinapi_kernel32_file();
unit_test_drwinapi_kernel32_sync();
unit_test_drwinapi_kernel32_misc();
unit_test_drwinapi_rpcrt4();
unit_test_drwinapi_advapi32();
}
#endif