diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..fbf7a8bdd2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +build2/ +.vs/ diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 543bd426f19..afe68cbd2b3 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -320,9 +320,11 @@ endif (WIN32) _DR_get_static_libc_list(static_libc_list) if (WIN32) if (DEBUG) - set(WIN32_C_LIB libcmtd) + set(WIN32_C_LIB libcmtd Psapi) + add_compile_options("-DPSAPI_VERSION=2") else (DEBUG) - set(WIN32_C_LIB libcmt) + set(WIN32_C_LIB libcmt Psapi) + add_compile_options("-DPSAPI_VERSION=2") endif (DEBUG) set(NOLIBC_DLL_ENTRY /entry:DllMain) endif () @@ -994,9 +996,9 @@ target_link_libraries(drdecode drlibc) # It would be nice to be static on Windows to avoid copying the lib into bin dirs, # but duplicate symbol problems make that non-trivial: we need i#1409. if (WIN32) - set(inject_lib_type SHARED) + set(inject_lib_type SHARED) else () - set(inject_lib_type STATIC) + set(inject_lib_type STATIC) endif () add_library(drinjectlib ${inject_lib_type} ${INJECTOR_SRCS}) add_gen_events_deps(drinjectlib) diff --git a/core/globals.h b/core/globals.h index 4f172bca93b..34336a7940c 100644 --- a/core/globals.h +++ b/core/globals.h @@ -53,7 +53,8 @@ * as earlier Windows versions give access denied on unknown flags! */ # define _WIN32_WINNT _WIN32_WINNT_NT4 /* ==0x0400; NTDDI_VERSION is set from this */ - +# undef _WIN32_WINNT +# define _WIN32_WINNT _WIN32_WINNT_WINXP # define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */ @@ -71,7 +72,6 @@ # pragma warning(disable : 4324) // structure was padded due to __declspec(align()) # pragma warning(disable : 4709) // comma operator within array index expression # pragma warning(disable : 4214) // nonstd extension: bit field types other than int - /**************************************************/ /* warnings on compiling with VC 8.0, all on VC or PlatformSDK header files */ diff --git a/core/lib/dr_inject.h b/core/lib/dr_inject.h index cd1a784cbb0..3ef1bb96361 100644 --- a/core/lib/dr_inject.h +++ b/core/lib/dr_inject.h @@ -104,6 +104,21 @@ DR_EXPORT int dr_inject_process_create(const char *app_name, const char **app_cmdline, void **data); +#ifdef WINDOWS +DR_EXPORT +/** + * Attach to a existing process. + * * + * \param[in] pid PID for process to attach. + * + * \param[out] data An opaque pointer that should be passed to + * subsequent dr_inject_* routines to refer to + * this process. + * \return Returns 0 on success. On failure, returns a system error code.` + */ +int +dr_inject_process_attach(process_id_t pid, void **data); +#endif #ifdef UNIX DR_EXPORT diff --git a/core/win32/injector.c b/core/win32/injector.c index 2c3c1db9cd8..d19b7cbab5e 100644 --- a/core/win32/injector.c +++ b/core/win32/injector.c @@ -56,21 +56,24 @@ #define UNICODE #define _UNICODE + #include "../globals.h" #define WIN32_LEAN_AND_MEAN #include +#include #include #include #include #include #include #include - #include "globals_shared.h" #include "ntdll.h" #include "inject_shared.h" #include "os_private.h" #include "dr_inject.h" +#include +#pragma comment(lib, "psapi") #define VERBOSE 0 #if VERBOSE @@ -230,6 +233,7 @@ tchar_to_char(const TCHAR *wstr, OUT char *buf, size_t buflen /*# elements*/) typedef struct _dr_inject_info_t { PROCESS_INFORMATION pi; bool using_debugger_injection; + bool attached; TCHAR wimage_name[MAXIMUM_PATH]; /* We need something to point at for dr_inject_get_image_name so we just * keep a utf8 buffer as well. @@ -749,6 +753,56 @@ append_app_arg_and_space(char *buf, size_t bufsz, size_t *sofar, const char *arg } } +DYNAMORIO_EXPORT +int +dr_inject_process_attach(process_id_t pid, void **data OUT) +{ + dr_inject_info_t *info = HeapAlloc(GetProcessHeap(), 0, sizeof(*info)); + if (!info) { + return ERROR_INVALID_PARAMETER; + } + memset(info, 0, sizeof(*info)); + int errcode = ERROR_SUCCESS; + if (DebugActiveProcess((DWORD)pid)) + { + info->using_debugger_injection = false; + info->attached = true; + DEBUG_EVENT dbgevt = { 0 }; + while (true) + { + dbgevt.dwProcessId = (DWORD)pid; + WaitForDebugEvent(&dbgevt, INFINITE); + ContinueDebugEvent(dbgevt.dwProcessId, dbgevt.dwThreadId, DBG_CONTINUE); + if (dbgevt.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + break; + } + LPWSTR szExePath = malloc(600 * sizeof(wchar_t)); + if (!szExePath) + return ERROR_INVALID_PARAMETER; + char *pExeName = NULL; + GetModuleFileNameExW(dbgevt.u.CreateProcessInfo.hProcess, NULL, szExePath, 600); + char buffer[600]; + wcstombs(buffer, szExePath, 600); + pExeName = strrchr(buffer, '\\'); + if (pExeName == NULL) + return ERROR_INVALID_PARAMETER; + strncpy(info->image_name, pExeName + 1, strlen(pExeName + 1)); + char_to_tchar(info->image_name, info->wimage_name, BUFFER_SIZE_ELEMENTS(info->wimage_name)); + info->pi.dwProcessId = dbgevt.dwProcessId; + info->pi.dwThreadId = dbgevt.dwThreadId; + DuplicateHandle(GetCurrentProcess(), dbgevt.u.CreateProcessInfo.hProcess, + GetCurrentProcess(), &info->pi.hProcess, 0, FALSE, + DUPLICATE_SAME_ACCESS); + DuplicateHandle(GetCurrentProcess(), dbgevt.u.CreateProcessInfo.hThread, + GetCurrentProcess(), &info->pi.hThread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + } + else + errcode = GetLastError(); + *data = info; + return errcode; +} + /* Returns 0 on success. * On failure, returns a Windows API error code. */ @@ -932,9 +986,14 @@ bool dr_inject_process_run(void *data) { dr_inject_info_t *info = (dr_inject_info_t *)data; - /* resume the suspended app process so its main thread can run */ - ResumeThread(info->pi.hThread); - close_handle(info->pi.hThread); + if (info->attached) { + /* detach the debugger */ + DebugActiveProcessStop(info->pi.dwProcessId); + } else { + /* resume the suspended app process so its main thread can run */ + ResumeThread(info->pi.hThread); + close_handle(info->pi.hThread); + } return true; } diff --git a/tools/drdeploy.c b/tools/drdeploy.c index c97725898ed..03cb6020986 100644 --- a/tools/drdeploy.c +++ b/tools/drdeploy.c @@ -296,17 +296,16 @@ const char *options_list_str = " -early Requests early injection (the default).\n" " -late Requests late injection.\n" # endif - " -attach Attach to the process with the given pid. Pass 0\n" - " for pid to launch and inject into a new process.\n" " -logdir Logfiles will be stored in this directory.\n" # endif + " -attach Attach to the process with the given pid. Pass 0\n" " -use_dll Inject given dll instead of configured DR dll.\n" " -force Inject regardless of configuration.\n" " -exit0 Return a 0 exit code instead of the app's exit code.\n" "\n" " Application command line to execute under DR.\n" #endif /* !DRCONFIG */ - ; +; static bool does_file_exist(const char *path) @@ -1107,6 +1106,7 @@ _tmain(int argc, TCHAR *targv[]) bool use_ptrace = false; bool kill_group = false; # endif + process_id_t attach_pid = 0; char *app_name = NULL; char full_app_name[MAXIMUM_PATH]; const char **app_argv; @@ -1397,9 +1397,15 @@ _tmain(int argc, TCHAR *targv[]) } #endif #if defined(DRRUN) || defined(DRINJECT) - else if (strcmp(argv[i], "-pidfile") == 0) { + else if (strcmp(argv[i], "-pidfile") == 0) + { pidfile = argv[++i]; - } else if (strcmp(argv[i], "-use_dll") == 0) { + } + else if (strcmp(argv[i], "-attach") == 0) + { + attach_pid = atoi(argv[++i]); + } + else if (strcmp(argv[i], "-use_dll") == 0) { DR_dll_not_needed = true; /* Support relative path: very useful! */ get_absolute_path(argv[++i], custom_dll, BUFFER_SIZE_ELEMENTS(custom_dll)); @@ -1533,7 +1539,7 @@ _tmain(int argc, TCHAR *targv[]) /* Support no app if the tool has its own frontend, under the assumption * it may have post-processing or other features. */ - if (i < argc || native_tool[0] == '\0') { + if (i < argc || native_tool[0] == '\0' && attach_pid == 0) { # endif if (i >= argc) usage(false, "%s", "no app specified"); @@ -1737,7 +1743,13 @@ _tmain(int argc, TCHAR *targv[]) info("will exec %s", app_name); errcode = dr_inject_prepare_to_exec(app_name, app_argv, &inject_data); } else -# endif /* UNIX */ +# elif defined(WINDOWS) + if (attach_pid != 0) + { + //to delete + errcode = dr_inject_process_attach(attach_pid, &inject_data); + } else +# endif /* WINDOWS */ { errcode = dr_inject_process_create(app_name, app_argv, &inject_data); info("created child with pid " PIDFMT " for %s", @@ -1837,21 +1849,18 @@ _tmain(int argc, TCHAR *targv[]) # endif goto error; } - IF_WINDOWS(start_time = time(NULL);) if (!dr_inject_process_run(inject_data)) { error("unable to run"); goto error; } - # ifdef WINDOWS if (limit == 0 && dr_inject_using_debug_key(inject_data)) { info("%s", "Using debugger key injection"); limit = -1; /* no wait */ } # endif - if (limit >= 0) { # ifdef WINDOWS double wallclock; @@ -1862,6 +1871,7 @@ _tmain(int argc, TCHAR *targv[]) # ifdef WINDOWS end_time = time(NULL); wallclock = difftime(end_time, start_time); + if (showstats || showmem) dr_inject_print_stats(inject_data, (int)wallclock, showstats, showmem); # endif @@ -1872,7 +1882,6 @@ _tmain(int argc, TCHAR *targv[]) } exitcode = dr_inject_process_exit(inject_data, !success /*kill process*/); - if (limit < 0) exitcode = 0; /* Return success if we didn't wait. */ @@ -1884,8 +1893,9 @@ _tmain(int argc, TCHAR *targv[]) /* we created the process suspended so if we later had an error be sure * to kill it instead of leaving it hanging */ - if (inject_data != NULL) + if (inject_data != NULL) { dr_inject_process_exit(inject_data, true /*kill process*/); + } # ifdef DRRUN if (tofree != NULL) free(tofree);