blob: f3ec0b67b7b3592abb7c9a7a405727d4d0a12d1a [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011 Google, Inc. All rights reserved.
* Copyright (c) 2005-2008 VMware, Inc. 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.
*/
/* Copyright (c) 2005-2007 Determina Corp. */
/*
* drmarker.c
*
* shared between core/gui nodemgr, functions to tell if a process is running
* under dr and pass information out of the running process
*
*/
#include "configure.h"
#if !defined(NOT_DYNAMORIO_CORE) && !defined(NOT_DYNAMORIO_CORE_PROPER)
# include "../globals.h"
# include "os_private.h"
# include "../nudge.h"
# include "../module_shared.h"
#else /* NOT_DYNAMORIO_CORE */
# define WIN32_LEAN_AND_MEAN
# include <windows.h> /* no longer included in globals_shared.h */
# include "globals_shared.h"
#endif
#include "ntdll.h"
#include "drmarker.h"
#if !defined(NOT_DYNAMORIO_CORE) && !defined(NOT_DYNAMORIO_CORE_PROPER)
# define READ_FUNC nt_read_virtual_memory
# define DR_MARKER_VERSION_CURRENT DR_MARKER_VERSION_2
#else /* NOT_DYNAMORIO_CORE */
# pragma warning( disable : 4054) /* from function pointer 'void (__cdecl *)(void )' to data pointer 'unsigned char *' */
/* complains about size_t* vs SIZE_T* */
# pragma warning( disable : 4057) /* 'function' : 'unsigned long *' differs in indirection to slightly different base types from 'int *' */
# pragma warning( disable : 4100) /* 'envp' : unreferenced formal parameter */
# ifndef byte
typedef unsigned char byte;
# endif
# define PAGE_START(x) (((ptr_uint_t)(x)) & ~((PAGE_SIZE)-1))
# define PAGE_SIZE (4*1024)
# define READ_FUNC ReadProcessMemory
#endif
#define OP_jmp_byte 0xe9
#ifdef NOT_DYNAMORIO_CORE
/* avoid having to link in ntdll.c */
bool
is_wow64_process(HANDLE hProcess)
{
/* IsWow64Pocess is only available on XP+ */
typedef DWORD (WINAPI *IsWow64Process_Type)(HANDLE hProcess,
PBOOL isWow64Process);
static HANDLE kernel32_handle;
static IsWow64Process_Type IsWow64Process;
if (kernel32_handle == NULL)
kernel32_handle = GetModuleHandle(L"kernel32.dll");
if (IsWow64Process == NULL && kernel32_handle != NULL) {
IsWow64Process = (IsWow64Process_Type)
GetProcAddress(kernel32_handle, "IsWow64Process");
}
if (IsWow64Process == NULL) {
/* should be NT or 2K */
return false;
} else {
BOOL res;
if (!IsWow64Process(hProcess, &res))
return false;
return CAST_TO_bool(res);
}
}
#endif
/* For 32-bit build, supports looking for x64 marker (in WOW64 process).
* For 64-bit build, only supports looking for x64 marker.
*/
static int
read_and_verify_dr_marker_common(HANDLE process, dr_marker_t *marker, bool x64)
{
byte buf[8]; /* only needs to be 5, but dword pad just in case */
size_t res;
void *target, *landing_pad;
#if !defined(NOT_DYNAMORIO_CORE) && !defined(NOT_DYNAMORIO_CORE_PROPER)
GET_NTDLL(DR_MARKER_HOOKED_FUNCTION, DR_MARKER_HOOKED_FUNCTION_ARGS);
void *hook_func = (void *)DR_MARKER_HOOKED_FUNCTION;
#else
void *hook_func;
# ifndef X64
if (x64) {
hook_func = (void *) get_proc_address_64
(get_module_handle_64(L_DR_MARKER_HOOKED_DLL),
DR_MARKER_HOOKED_FUNCTION_STRING);
} else
# endif
hook_func = (void *)GetProcAddress(GetModuleHandle(DR_MARKER_HOOKED_DLL),
DR_MARKER_HOOKED_FUNCTION_STRING);
#endif
if (IF_X64_ELSE(!x64, x64 && !is_wow64_process(NT_CURRENT_PROCESS)))
return DR_MARKER_ERROR;
if (hook_func == NULL)
return DR_MARKER_ERROR;
if (!READ_FUNC(process, hook_func, buf, 5, &res) || res != 5)
return DR_MARKER_ERROR;
if (buf[0] != OP_jmp_byte)
return DR_MARKER_NOT_FOUND;
/* jmp offset + EIP (after jmp = hook_func + size of jmp (5 bytes)) */
landing_pad = (void *)(*(int *)&buf[1] + (ptr_int_t)hook_func + 5);
/* for 64-bit, the target is stored in front of the trampoline */
if (x64)
landing_pad = (byte *)landing_pad - 8;
/* see emit_landing_pad_code() for layout of landing pad */
if (!READ_FUNC(process, landing_pad, buf, (x64 ? 8 : 5), &res) ||
res != (x64 ? 8U : 5U))
return DR_MARKER_ERROR;
if (x64) {
/* trampoline address is stored at the top of the landing pad for 64-bit */
target = (void *)PAGE_START(*(ptr_int_t *)buf);
} else {
/* jmp offset + EIP (after jmp = landing_pad + size of jmp (5 bytes)) */
target = (void *)PAGE_START(*(int *)&buf[1] + (ptr_int_t)landing_pad + 5);
}
if (!READ_FUNC(process, target, marker, sizeof(dr_marker_t), &res) ||
res != sizeof(dr_marker_t)) {
return DR_MARKER_NOT_FOUND;
}
if (dr_marker_verify(process, marker)) {
return DR_MARKER_FOUND;
}
return DR_MARKER_NOT_FOUND; /* probably some other hooker */
}
#ifndef X64
int
read_and_verify_dr_marker_64(HANDLE process, dr_marker_t *marker)
{
return read_and_verify_dr_marker_common(process, marker, true);
}
#endif
int
read_and_verify_dr_marker(HANDLE process, dr_marker_t *marker)
{
return read_and_verify_dr_marker_common(process, marker, IF_X64_ELSE(true, false));
}
/* FIXME : in the future we may want to obfuscate so is not a constant? */
/* generated by dropping hand on number keypad and converting to hex */
/* we pass in the process handle to dr_marker_verify and dr_marker_magic_init
* in case we decide to make the magic numbers process specific (xor w/pid or
* something similar) */
#define DR_MARKER_MAGIC1 0xB1D2AE58
#define DR_MARKER_MAGIC2 0xCA50C356
#define DR_MARKER_MAGIC3 0x63000089
#define DR_MARKER_MAGIC4 0x3FA898F0
bool
dr_marker_verify(HANDLE process, dr_marker_t *marker)
{
return (marker->magic1 == DR_MARKER_MAGIC1 &&
marker->magic2 == DR_MARKER_MAGIC2 &&
marker->magic3 == DR_MARKER_MAGIC3 &&
marker->magic4 == DR_MARKER_MAGIC4);
}
#if !defined(NOT_DYNAMORIO_CORE) && !defined(NOT_DYNAMORIO_CORE_PROPER)
/* takes a dr marker with all non magic fields filled in and fills in the
* magic fields */
static void
dr_marker_magic_init(HANDLE process, dr_marker_t *marker)
{
marker->magic1 = DR_MARKER_MAGIC1;
marker->magic2 = DR_MARKER_MAGIC2;
marker->magic3 = DR_MARKER_MAGIC3;
marker->magic4 = DR_MARKER_MAGIC4;
}
# ifdef HOT_PATCHING_INTERFACE
/* FIXME: Including hotpatch.h here breaks the share module because it doesn't
* define a whole bunch of types like app_pc. Once that is fixed, this
* extern declaration should be removed and hotpatch.h included; see
* case 4999.
*/
extern void *hotp_policy_status_table; /* See FIXME above. */
extern read_write_lock_t *hotp_get_lock(void); /* See FIXME above. */
# endif
void
init_dr_marker(dr_marker_t *marker)
{
/* not calling memset b/c windbg_cmds is large */
# ifdef DEBUG
marker->flags = DR_MARKER_DEBUG_BUILD;
# else
marker->flags = DR_MARKER_RELEASE_BUILD;
# endif
# ifdef PROFILE
marker->flags = DR_MARKER_PROFILE_BUILD;
# endif
/* make sure we set one of the above flags and not more then one */
ASSERT(TESTANY(DR_MARKER_BUILD_TYPES, marker->flags) &&
((DR_MARKER_BUILD_TYPES & marker->flags) &
((DR_MARKER_BUILD_TYPES & marker->flags) - 1)) == 0);
/* TODO : add any additional flags? */
marker->build_num = BUILD_NUMBER;
marker->dr_base_addr = get_module_base((app_pc)init_dr_marker);
marker->dr_generic_nudge_target = (void *)generic_nudge_target;
# ifdef HOT_PATCHING_INTERFACE
marker->dr_hotp_policy_status_table = (void *)hotp_policy_status_table;
# else
marker->dr_hotp_policy_status_table = NULL;
# endif
marker->dr_marker_version = DR_MARKER_VERSION_CURRENT;
marker->stats = get_dr_stats();
dr_marker_magic_init(NT_CURRENT_PROCESS, marker);
marker->windbg_cmds[0] = '\0';
}
# ifdef HOT_PATCHING_INTERFACE
void*
get_drmarker_hotp_policy_status_table()
{
dr_marker_t *dr_marker = get_drmarker();
ASSERT_OWN_READWRITE_LOCK(true, hotp_get_lock());
if (dr_marker == NULL) /* dr_marker_t has been initialized. */
return NULL;
return dr_marker->dr_hotp_policy_status_table;
}
void
set_drmarker_hotp_policy_status_table(void *new_table)
{
dr_marker_t *dr_marker = get_drmarker();
ASSERT_OWN_WRITE_LOCK(true, hotp_get_lock());
/* We don't want to write to the dr_marker_t before it is initialized; we
* could get an exception.
*/
if (dr_marker == NULL) /* Part of fix for case 5367. */
return;
/* Ok, dr_marker_t has been initialized. */
/* It is ok to do this memory protection change here even though this can
* be any arbitrary time due to the nature of nudge. This is because
* once initialized, the dr_marker_t isn't touched by any one except the hot
* patch nudge.
*
* TODO: In future other parts of the core may need to change the dr_marker_t.
* It might be a good idea to introduce a lock for the dr_marker_t and
* generic accessor functions.
*/
make_writable((byte*)dr_marker, INTERCEPTION_CODE_SIZE);
dr_marker->dr_hotp_policy_status_table = new_table;
make_unwritable((byte*)dr_marker, INTERCEPTION_CODE_SIZE);
}
# endif /* HOT_PATCHING_INTERFACE */
#endif /* !NOT_DYNAMORIO_CORE && !NOT_DYNAMORIO_CORE_PROPER */