diff options
Diffstat (limited to 'build/win32/crashinject.cpp')
-rw-r--r-- | build/win32/crashinject.cpp | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/build/win32/crashinject.cpp b/build/win32/crashinject.cpp new file mode 100644 index 0000000000..076e5a12a2 --- /dev/null +++ b/build/win32/crashinject.cpp @@ -0,0 +1,94 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Given a PID, this program attempts to inject a DLL into the process + * with that PID. The DLL it attempts to inject, "crashinjectdll.dll", + * must exist alongside this exe. The DLL will then crash the process. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <windows.h> + +int main(int argc, char** argv) { + if (argc != 2) { + fprintf(stderr, "Usage: crashinject <PID>\n"); + return 1; + } + + int pid = atoi(argv[1]); + if (pid <= 0) { + fprintf(stderr, "Usage: crashinject <PID>\n"); + return 1; + } + + // find our DLL to inject + wchar_t filename[_MAX_PATH]; + if (GetModuleFileNameW(nullptr, filename, + sizeof(filename) / sizeof(wchar_t)) == 0) + return 1; + + wchar_t* slash = wcsrchr(filename, L'\\'); + if (slash == nullptr) return 1; + + slash++; + wcscpy(slash, L"crashinjectdll.dll"); + + // now find our target process + HANDLE targetProc = + OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | + PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION, + FALSE, pid); + if (targetProc == nullptr) { + fprintf(stderr, "Error %lu opening target process\n", GetLastError()); + return 1; + } + + /* + * This is sort of insane, but we're implementing a technique described here: + * http://www.codeproject.com/KB/threads/winspy.aspx#section_2 + * + * The gist is to use CreateRemoteThread to create a thread in the other + * process, but cheat and make the thread function kernel32!LoadLibrary, + * so that the only remote data we have to pass to the other process + * is the path to the library we want to load. The library we're loading + * will then do its dirty work inside the other process. + */ + HMODULE hKernel32 = GetModuleHandleW(L"Kernel32"); + // allocate some memory to hold the path in the remote process + void* pLibRemote = VirtualAllocEx(targetProc, nullptr, sizeof(filename), + MEM_COMMIT, PAGE_READWRITE); + if (pLibRemote == nullptr) { + fprintf(stderr, "Error %lu in VirtualAllocEx\n", GetLastError()); + CloseHandle(targetProc); + return 1; + } + + if (!WriteProcessMemory(targetProc, pLibRemote, (void*)filename, + sizeof(filename), nullptr)) { + fprintf(stderr, "Error %lu in WriteProcessMemory\n", GetLastError()); + VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE); + CloseHandle(targetProc); + return 1; + } + // Now create a thread in the target process that will load our DLL + HANDLE hThread = CreateRemoteThread( + targetProc, nullptr, 0, + (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW"), + pLibRemote, 0, nullptr); + if (hThread == nullptr) { + fprintf(stderr, "Error %lu in CreateRemoteThread\n", GetLastError()); + VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE); + CloseHandle(targetProc); + return 1; + } + WaitForSingleObject(hThread, INFINITE); + // Cleanup, not that it's going to matter at this point + CloseHandle(hThread); + VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE); + CloseHandle(targetProc); + + return 0; +} |