Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i#803: Cross-arch Windows injection #4653

Merged
merged 7 commits into from
Jan 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion api/docs/release.dox
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ******************************************************************************
* Copyright (c) 2010-2020 Google, Inc. All rights reserved.
* Copyright (c) 2010-2021 Google, Inc. All rights reserved.
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* ******************************************************************************/
Expand Down Expand Up @@ -159,6 +159,10 @@ compatibility changes:

Further non-compatibility-affecting changes include:

- On x86 Windows, different-bitwidth child processes are now followed into.
The default injection method has also changed to a new method relying on
an image entry hook in some cases. The old behavior can be requested by
passing "-late" to drrun or calling dr_inject_use_late_injection().
- Added drmgr_register_opcode_instrumentation_event() and
drmgr_unregister_opcode_instrumentation_event() so that drmgr supports
opcode event instrumentation.
Expand Down
8 changes: 4 additions & 4 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# **********************************************************
# Copyright (c) 2010-2020 Google, Inc. All rights reserved.
# Copyright (c) 2010-2021 Google, Inc. All rights reserved.
# Copyright (c) 2009-2010 VMware, Inc. All rights reserved.
# **********************************************************

Expand Down Expand Up @@ -399,8 +399,8 @@ else (UNIX)
win32/syscall.c
win32/callback.c
win32/drmarker.c
win32/ntdll.c
win32/ntdll_shared.c
win32/ntdll.c
win32/inject.c
win32/inject_shared.c
win32/module.c
Expand All @@ -424,8 +424,8 @@ else (UNIX)
)
set(PRELOAD_SRCS
win32/pre_inject.c
win32/ntdll.c
win32/ntdll_shared.c
win32/ntdll.c
win32/inject_shared.c
win32/drmarker.c
${preinject_asm_src}
Expand All @@ -439,10 +439,10 @@ else (UNIX)
set(INJECTOR_SRCS
win32/injector.c
win32/inject.c
win32/ntdll.c
win32/inject_shared.c
win32/module_shared.c
win32/ntdll_shared.c
win32/ntdll.c
win32/resources.rc
config.c
win32/os.c
Expand Down
2 changes: 1 addition & 1 deletion core/arch/arch.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2010-2020 Google, Inc. All rights reserved.
* Copyright (c) 2010-2021 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down
12 changes: 8 additions & 4 deletions core/arch/x86/x86.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2001-2010 VMware, Inc. All rights reserved.
* ********************************************************** */

Expand Down Expand Up @@ -2695,11 +2695,15 @@ dynamorio_earliest_init_repeatme:
cmp ebx, 0
jg dynamorio_earliest_init_repeat_outer
# endif
/* args are pointed at by xax */
/* Load earliest_args_t.app_xax, written by our gencode. */
mov REG_XCX, PTRSZ [REG_XAX]
/* Store into xax slot on stack. */
mov PTRSZ [PUSHGPR_XAX_OFFS + REG_XSP], REG_XCX
/* Args are pointed at by xax. */
CALLC1(GLOBAL_REF(dynamorio_earliest_init_takeover_C), REG_XAX)
/* we will either be under DR control or running natively at this point */
/* We will either be under DR control or running natively at this point. */

/* restore */
/* Restore. */
POPGPR
ret
END_FUNC(dynamorio_earliest_init_takeover)
Expand Down
3 changes: 2 additions & 1 deletion core/arch/x86/x86_asm_defines.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2001-2010 VMware, Inc. All rights reserved.
* ********************************************************** */

Expand Down Expand Up @@ -124,6 +124,7 @@
#endif
/* offsetof(dcontext_t, is_exiting) */
#define is_exiting_OFFSET (dstack_OFFSET+1*ARG_SZ)
#define PUSHGPR_XAX_OFFS (7*ARG_SZ)
#define PUSHGPR_XSP_OFFS (3*ARG_SZ)
#define MCONTEXT_XSP_OFFS (PUSHGPR_XSP_OFFS)
#define MCONTEXT_XCX_OFFS (MCONTEXT_XSP_OFFS + 3*ARG_SZ)
Expand Down
19 changes: 18 additions & 1 deletion core/drlibc/drlibc.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -131,6 +131,23 @@ find_script_interpreter(OUT script_interpreter_t *result, IN const char *fname,
*/
void
d_r_set_ss_selector();

typedef struct {
uint64 func;
uint64 arg1;
uint64 arg2;
uint64 arg3;
uint64 arg4;
uint64 arg5;
uint64 arg6;
} invoke_func64_t;

/* Switches from 32-bit mode to 64-bit mode and invokes func, passing
* arg1, arg2, arg3, arg4, and arg5. Works fine when func takes fewer
* than 5 args as well.
*/
int
switch_modes_and_call(invoke_func64_t *info);
#endif

#endif /* _DR_LIBC_H_ */
51 changes: 31 additions & 20 deletions core/drlibc/drlibc_x86.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2001-2010 VMware, Inc. All rights reserved.
* ********************************************************** */

Expand Down Expand Up @@ -530,20 +530,19 @@ GLOBAL_LABEL(FUNCNAME:)
END_FUNC(FUNCNAME)

/*
* int switch_modes_and_call(uint64 func, void *arg1, void *arg2, void *arg3)
* int switch_modes_and_call(invoke_uint64_t *args)
*/
# undef FUNCNAME
# define FUNCNAME switch_modes_and_call
DECLARE_FUNC(FUNCNAME)
GLOBAL_LABEL(FUNCNAME:)
mov eax, esp /* get.. */
add eax, ARG_SZ /* ...address of func */
mov ecx, ARG3 /* arg1 */
mov edx, ARG4 /* arg2 */
/* save callee-saved registers */
mov eax, ARG1
/* Save callee-saved registers. */
push ebx
mov ebx, ARG6 /* really ARG5==arg3, but we have 1 push */
/* far jmp to next instr w/ 64-bit switch: jmp 0033:<smc_transfer_to_64> */
push esi
push edi
push ebp
/* Far jmp to next instr w/ 64-bit switch: jmp 0033:<smc_transfer_to_64>. */
RAW(ea)
DD offset smc_transfer_to_64
DB CS64_SELECTOR
Expand All @@ -552,26 +551,34 @@ smc_transfer_to_64:
/* Below here is executed in 64-bit mode, but with guarantees that
* no address is above 4GB, as this is a WOW64 process.
*/
/* save WOW64 state */
/* Save WOW64 calee-saved registers. */
RAW(41) push esp /* push r12 */
RAW(41) push ebp /* push r13 */
RAW(41) push esi /* push r14 */
RAW(41) push edi /* push r15 */
RAW(44) mov eax, ebx /* mov arg3 from ebx to r8d (3rd arg slot) */
/* align the stack pointer */
/* Align the stack pointer. */
mov ebx, esp /* save esp in callee-preserved reg */
sub esp, 32 /* call conv */
and esp, HEX(fffffff0) /* align to 16-byte boundary */
/* arg1 is already in rcx, arg2 in rdx, and arg3 now in r8 */
RAW(48) mov eax, DWORD [eax] /* mov rax, qword ptr [rax] */
/* Set up args on the stack. */
RAW(48) mov ecx, DWORD [eax + 8*6] /* load args.arg6 */
push ecx /* push args.arg6 */
RAW(48) mov ecx, DWORD [eax + 8*5] /* load args.arg5 */
push ecx /* push args.arg5 */
sub esp, 32 /* Leave slots for args 1-4. */
/* arg1 is already in rcx, arg2 in rdx, arg3 in r8, arg4 in r9 */
RAW(4c) mov ecx, DWORD [eax + 8*4] /* load args.arg4 into r9 */
RAW(4c) mov eax, DWORD [eax + 8*3] /* load args.arg3 into r8 */
RAW(48) mov edx, DWORD [eax + 8*2] /* load args.arg2 into rdx */
RAW(48) mov ecx, DWORD [eax + 8*1] /* load args.arg1 into rcx */
RAW(48) mov eax, DWORD [eax] /* load args.func into rax */
call eax /* call rax */
mov esp, ebx /* restore esp */
/* restore WOW64 state */
mov esp, ebx /* restore rsp */
/* Restore WOW64 callee-saved regs. */
RAW(41) pop edi /* pop r15 */
RAW(41) pop esi /* pop r14 */
RAW(41) pop ebp /* pop r13 */
RAW(41) pop esp /* pop r12 */
/* far jmp to next instr w/ 32-bit switch: jmp 0023:<smc_return_to_32> */
/* Far jmp to next instr w/ 32-bit switch: jmp 0023:<smc_return_to_32>. */
push offset smc_return_to_32 /* 8-byte push */
mov dword ptr [esp + 4], CS32_SELECTOR /* top 4 bytes of prev push */
jmp fword ptr [esp]
Expand All @@ -586,8 +593,12 @@ smc_return_to_32:
*/
mov ebx, DWORD SYMREF(d_r_ss_value)
mov ss, ebx
pop ebx /* restore callee-saved reg */
ret /* return value already in eax */
/* Restore callee-saved regs. */
pop ebp
pop edi
pop esi
pop ebx
ret /* return value already in eax */
END_FUNC(FUNCNAME)

#endif /* WINDOWS && !X64 */
Expand Down
16 changes: 15 additions & 1 deletion core/lib/dr_inject.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2013-2015 Google, Inc. All rights reserved.
* Copyright (c) 2013-2021 Google, Inc. All rights reserved.
* Copyright (c) 2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -180,6 +180,20 @@ dr_inject_prepare_new_process_group(void *data);

#endif /* UNIX */

#ifdef WINDOWS
DR_EXPORT
/**
* Specifies that late injection should be used for the process created by
* dr_inject_process_create().
*
* \param[in] data The pointer returned by dr_inject_process_create()
*
* \return Whether successful.
*/
bool
dr_inject_use_late_injection(void *data);
#endif

DR_EXPORT
/**
* Injects DynamoRIO into a process created by dr_inject_process_create(), or
Expand Down
4 changes: 2 additions & 2 deletions core/module_shared.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -376,7 +376,7 @@ get_proc_address_resolve_forward(module_base_t lib, const char *name);
#endif /* WINDOWS */

#ifdef WINDOWS
void *
uint64
get_remote_process_entry(HANDLE process_handle, OUT bool *x86_code);
#endif

Expand Down
41 changes: 22 additions & 19 deletions core/optionsx.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* *******************************************************************************
* Copyright (c) 2010-2020 Google, Inc. All rights reserved.
* Copyright (c) 2010-2021 Google, Inc. All rights reserved.
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2003-2010 VMware, Inc. All rights reserved.
* *******************************************************************************/
Expand Down Expand Up @@ -566,6 +566,11 @@ OPTION_DEFAULT_INTERNAL(bool, mangle_app_seg,
"mangle application's segment usage.")
#endif /* X86 */
#ifdef X64
# ifdef WINDOWS
/* TODO i#49: This option is still experimental and is not fully tested/supported yet. */
OPTION_DEFAULT(bool, inject_x64, false,
"Inject 64-bit DynamoRIO into 32-bit child processes.")
# endif
OPTION_COMMAND(bool, x86_to_x64, false, "x86_to_x64",
{
/* i#1494: to avoid decode_fragment messing up the 32-bit/64-bit mode,
Expand Down Expand Up @@ -1694,10 +1699,12 @@ DYNAMIC_OPTION_DEFAULT(
* even _init is run needs to have a non-early default.
* Thus we turn this on in privload_early_inject.
*/
OPTION_COMMAND(bool, early_inject,
IF_WINDOWS_ELSE
/* i#980: too early for kernel32 so we disable */
(IF_CLIENT_INTERFACE_ELSE(false, true), false),
/* On Windows this does *not* imply early injection anymore: it just enables control
* over where to inject via a hook and alternate injection methods, rather than using
* the old thread injection.
* XXX: Clean up by removing this option and thread injection completely?
*/
OPTION_COMMAND(bool, early_inject, IF_UNIX_ELSE(false /*see above*/, true),
"early_inject",
{
if (options->early_inject) {
Expand All @@ -1706,20 +1713,16 @@ OPTION_COMMAND(bool, early_inject,
}
},
"inject early", STATIC, OP_PCACHE_GLOBAL)
#if 0 /* FIXME i#234 NYI: not ready to enable just yet */
OPTION_DEFAULT(bool, early_inject_map, true, "inject earliest via map")
/* see enum definition is os_shared.h for notes on what works with which
* os version */
OPTION_DEFAULT(uint, early_inject_location, 5 /* INJECT_LOCATION_KiUserApc */,
"where to hook for early_injection. default is earliest injection: anything else will be later.")
#else
OPTION_DEFAULT(bool, early_inject_map, false, "inject earliest via map")
/* see enum definition is os_shared.h for notes on what works with which
* os version */
OPTION_DEFAULT(uint, early_inject_location, 4 /* INJECT_LOCATION_LdrDefault */,
"where to hook for early_injection. default is earliest injection: "
"anything else will be later.")
#endif
/* To support cross-arch follow-children injection we need to use the map option. */
OPTION_DEFAULT(bool, early_inject_map, true, "inject earliest via map")
/* See enum definition is os_shared.h for notes on what works with which
* os version. Our default is late injection to make it easier on clients
* (as noted in i#980, we don't want to be too early for a private kernel32).
*/
OPTION_DEFAULT(uint, early_inject_location, 8 /* INJECT_LOCATION_ThreadStart */,
"where to hook for early_injection. Use 5 =="
"INJECT_LOCATION_KiUserApcdefault for earliest injection; use "
"4 == INJECT_LOCATION_LdrDefault for easier-but-still-early.")
OPTION_DEFAULT(uint_addr, early_inject_address, 0,
"specify the address to hook at for INJECT_LOCATION_LdrCustom")
#ifdef WINDOWS /* probably the surrounding options should also be under this ifdef */
Expand Down
12 changes: 8 additions & 4 deletions core/os_shared.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2010-2020 Google, Inc. All rights reserved.
* Copyright (c) 2010-2021 Google, Inc. All rights reserved.
* Copyright (c) 2003-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -636,6 +636,7 @@ typedef struct _dr_mem_info_t {
* It uses a function call so be careful where performance is critical.
*/
#define PAGE_START(x) (((ptr_uint_t)(x)) & ~(os_page_size() - 1))
#define PAGE_START64(x) (((uint64)(x)) & ~((uint64)os_page_size() - 1))

size_t
os_page_size(void);
Expand Down Expand Up @@ -1256,11 +1257,9 @@ enum {
JMP_REL32_OPCODE = 0xe9,
JMP_REL32_SIZE = 5, /* size in bytes of 32-bit rel jmp */
CALL_REL32_OPCODE = 0xe8,
# ifdef X64
JMP_ABS_IND64_OPCODE = 0xff,
JMP_ABS_IND64_SIZE = 6, /* size in bytes of a 64-bit abs ind jmp */
JMP_ABS_MEM_IND64_MODRM = 0x25,
# endif
};
#elif defined(AARCHXX)
enum {
Expand Down Expand Up @@ -1315,7 +1314,12 @@ enum {
* on some app libraries being initialized
*/
INJECT_LOCATION_ImageEntry = 7,
INJECT_LOCATION_MAX = INJECT_LOCATION_ImageEntry,
/* Similar in lateness to ImageEntry, but is more robust in that it does not
* rely on reaching the image entry, which not all apps do (e.g., .NET).
* This is equivalent to RtlUserThreadStart.
*/
INJECT_LOCATION_ThreadStart = 8,
INJECT_LOCATION_MAX = INJECT_LOCATION_ThreadStart,
};
#endif

Expand Down
Loading