build/win32/crashinject.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * Given a PID, this program attempts to inject a DLL into the process
michael@0 7 * with that PID. The DLL it attempts to inject, "crashinjectdll.dll",
michael@0 8 * must exist alongside this exe. The DLL will then crash the process.
michael@0 9 */
michael@0 10 #include <stdio.h>
michael@0 11 #include <stdlib.h>
michael@0 12 #include <string.h>
michael@0 13 #include <windows.h>
michael@0 14
michael@0 15 int main(int argc, char** argv)
michael@0 16 {
michael@0 17 if (argc != 2) {
michael@0 18 fprintf(stderr, "Usage: crashinject <PID>\n");
michael@0 19 return 1;
michael@0 20 }
michael@0 21
michael@0 22 int pid = atoi(argv[1]);
michael@0 23 if (pid <= 0) {
michael@0 24 fprintf(stderr, "Usage: crashinject <PID>\n");
michael@0 25 return 1;
michael@0 26 }
michael@0 27
michael@0 28 // find our DLL to inject
michael@0 29 wchar_t filename[_MAX_PATH];
michael@0 30 if (GetModuleFileNameW(nullptr, filename,
michael@0 31 sizeof(filename) / sizeof(wchar_t)) == 0)
michael@0 32 return 1;
michael@0 33
michael@0 34 wchar_t* slash = wcsrchr(filename, L'\\');
michael@0 35 if (slash == nullptr)
michael@0 36 return 1;
michael@0 37
michael@0 38 slash++;
michael@0 39 wcscpy(slash, L"crashinjectdll.dll");
michael@0 40
michael@0 41 // now find our target process
michael@0 42 HANDLE targetProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION,
michael@0 43 FALSE,
michael@0 44 pid);
michael@0 45 if (targetProc == nullptr) {
michael@0 46 fprintf(stderr, "Error %d opening target process\n", GetLastError());
michael@0 47 return 1;
michael@0 48 }
michael@0 49
michael@0 50 /*
michael@0 51 * This is sort of insane, but we're implementing a technique described here:
michael@0 52 * http://www.codeproject.com/KB/threads/winspy.aspx#section_2
michael@0 53 *
michael@0 54 * The gist is to use CreateRemoteThread to create a thread in the other
michael@0 55 * process, but cheat and make the thread function kernel32!LoadLibrary,
michael@0 56 * so that the only remote data we have to pass to the other process
michael@0 57 * is the path to the library we want to load. The library we're loading
michael@0 58 * will then do its dirty work inside the other process.
michael@0 59 */
michael@0 60 HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
michael@0 61 // allocate some memory to hold the path in the remote process
michael@0 62 void* pLibRemote = VirtualAllocEx(targetProc, nullptr, sizeof(filename),
michael@0 63 MEM_COMMIT, PAGE_READWRITE);
michael@0 64 if (pLibRemote == nullptr) {
michael@0 65 fprintf(stderr, "Error %d in VirtualAllocEx\n", GetLastError());
michael@0 66 CloseHandle(targetProc);
michael@0 67 return 1;
michael@0 68 }
michael@0 69
michael@0 70 if (!WriteProcessMemory(targetProc, pLibRemote, (void*)filename,
michael@0 71 sizeof(filename), nullptr)) {
michael@0 72 fprintf(stderr, "Error %d in WriteProcessMemory\n", GetLastError());
michael@0 73 VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
michael@0 74 CloseHandle(targetProc);
michael@0 75 return 1;
michael@0 76 }
michael@0 77 // Now create a thread in the target process that will load our DLL
michael@0 78 HANDLE hThread = CreateRemoteThread(
michael@0 79 targetProc, nullptr, 0,
michael@0 80 (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32,
michael@0 81 "LoadLibraryW"),
michael@0 82 pLibRemote, 0, nullptr);
michael@0 83 if (hThread == nullptr) {
michael@0 84 fprintf(stderr, "Error %d in CreateRemoteThread\n", GetLastError());
michael@0 85 VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
michael@0 86 CloseHandle(targetProc);
michael@0 87 return 1;
michael@0 88 }
michael@0 89 WaitForSingleObject(hThread, INFINITE);
michael@0 90 // Cleanup, not that it's going to matter at this point
michael@0 91 CloseHandle(hThread);
michael@0 92 VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
michael@0 93 CloseHandle(targetProc);
michael@0 94
michael@0 95 return 0;
michael@0 96 }

mercurial