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