extern "C" int main(int argc, char* argv[]){ if(argc < 2){ std::cout << "No exe specified!\n\n"; std::cout << "Usage: winheaptrack <exe path> [target working dir]\n\n" " The first argument specifies the exe to launch.\n" " The second optional argument specifies the working directory\n" " of the exe to launch (this defaults to directory of exe.)\n"; return -1; } char *injectionTarget = argv[1]; std::string injectionTargetWorkingDirectory; if(argc > 2) injectionTargetWorkingDirectory = argv[2]; else injectionTargetWorkingDirectory = getDirectoryOfFile(injectionTarget); bool win64 = false; #ifdef _WIN64 win64 = true; #endif // Select correct dll name depending on whether x64 or win32 version launched. std::string winheaptrackInjectDllName; if(win64) winheaptrackInjectDllName = "winheaptrack_inject_x64.dll"; else winheaptrackInjectDllName = "winheaptrack_inject_Win32.dll"; // Assume that the injection payload dll is in the same directory as the exe. std::string exePath(argv[0]); std::string dllPath = getDirectoryOfFile(exePath) + "\\" + winheaptrackInjectDllName; // Start our new process with a suspended main thread. std::cout << "Starting process with heap profiling enabled..." << std::endl; std::cout << "Target exe path: " << injectionTarget << std::endl; std::cout << "Working directory: " << injectionTargetWorkingDirectory << std::endl; std::cout << "Dll to inject: " << dllPath << std::endl; DWORD flags = CREATE_SUSPENDED; PROCESS_INFORMATION pi; STARTUPINFOA si; GetStartupInfoA(&si); if(CreateProcessA(NULL, injectionTarget, NULL, NULL, 0, flags, NULL, (LPSTR)injectionTargetWorkingDirectory.c_str(), &si, &pi) == 0){ std::cerr << "Error creating process " << injectionTarget << " with working directory " << injectionTargetWorkingDirectory << std::endl; return -1; } // Inject our dll. // This method returns only when injection thread returns. try{ if(!LoadLibraryInjection(pi.hProcess, dllPath.c_str())){ throw std::runtime_error("LoadLibrary failed!"); } }catch(const std::exception &e){ std::cerr << "\n"; std::cerr << "Error while injecting process: " << e.what() << "\n\n"; std::cerr << "Check that the hook dll (" << dllPath << " is in the correct location.\n\n"; std::cerr << "Are you trying to inject a " << (win64 ? " 32 bit " : " 64 bit ") << " application using the " << (win64 ? " 64 bit " : " 32 bit ") << " injector?\n\n"; // TODO: figure out how to terminate thread. This does not always work. TerminateProcess(pi.hProcess, 0); return -1; } // Once the injection thread has returned it is safe to resume the main thread. ResumeThread(pi.hThread); // Wait for the target application to exit. // This doesn't matter to much, but makes winheaptrack nicer to use in test scripts. // (Like the ProfileTestApplication project.) WaitForSingleObject(pi.hProcess, INFINITE); return 0; }
/** @brief herp derp. @private @bug Sometimes on windows XP, if a process is started up to be injected into, the process will exit before completing startup if the DLL unloads itself before process startup is complete. **/ int main(int argc, CHAR* argv[]) { char *dllArg = NULL; char *programPath = NULL; char *procArgs = NULL; WCHAR procNameBuffer[MAX_PATH] = {0}; PWCHAR procName = NULL; DWORD pid = 0; DWORD waitMs = 0; BOOL startProcess; DWORD injectionMethod = 0; unsigned char dllCount = 0; char *dllList[128]; if(argc==1){ Usage(); } // Get Windows Version Information. OSVERSIONINFOEX OsInfo = {0}; OsInfo.dwOSVersionInfoSize = sizeof(OsInfo); GetVersionEx((LPOSVERSIONINFO)&OsInfo); // These are used later to make decisions on how to do things. BOOL is2kOrAbove = FALSE; BOOL isXpOrAbove = FALSE; BOOL isVistaOrAbove = FALSE; BOOL is7OrAbove = FALSE; if(OsInfo.dwMajorVersion >= 6){ isVistaOrAbove = TRUE; if(OsInfo.dwMinorVersion >= 1){ is7OrAbove = TRUE; } } if(OsInfo.dwMajorVersion >= 5){ is2kOrAbove = TRUE; if(OsInfo.dwMinorVersion >= 1){ isXpOrAbove = TRUE; } } // This really wont event get shown, the program just crashes when run. if(isXpOrAbove == FALSE){ printf("ERROR: Injex is not compatible with this version of windows."); ExitProcess(-1); } for(int i=1;i<argc;i++){ if(strcmp(argv[i],"-d") == 0){ // Add the DLL list dllList[dllCount] = (char*)malloc(MAX_PATH); // Get the full path to the DLL to inject, the application loading will need this. GetFullPathNameA(argv[++i],MAX_PATH,dllList[dllCount],NULL); // Inc the dll count. dllCount++; } else if(strcmp(argv[i],"-b") == 0) { programPath = argv[++i]; startProcess = TRUE; } else if(strcmp(argv[i],"-p") == 0) { if(isNumeric(argv[i+1])) pid = atoi(argv[++i]); else{ printf("ERROR: Invalid Process Id specified \"%s\"; Process Id should be numeric.\n",argv[i+1]); Usage(); } startProcess = FALSE; } else if(strcmp(argv[i],"-a") == 0) { procArgs = argv[++i]; } else if(strcmp(argv[i],"-h") == 0) { Usage(); } else if(strcmp(argv[i],"-w") == 0) { if(isXpOrAbove == FALSE){ printf("ERROR: Process suspension is only supported on Windows XP/2003 or above.\n"); Usage(); } waitMs = atoi(argv[++i]); } else if (strcmp(argv[i],"-n") == 0) { if(isXpOrAbove == FALSE){ printf("ERROR: Selecting a process by name is only supported on Windows XP or above. Please use process id instead.\n"); Usage(); } i++; procName = procNameBuffer; MultiByteToWideChar(CP_UTF8, 0, argv[i], INT(strlen(argv[i])), procName, MAX_PATH); startProcess = FALSE; } else if (strcmp(argv[i],"-i") == 0) { if(isNumeric(argv[i+1])) injectionMethod = atoi(argv[++i]); else{ printf("ERROR: Invalid injection method, injection methods are provided by number.\n"); Usage(); } } else { printf("ERROR: Unknown command line option \"%s\"\n",argv[i]); Usage(); } } // Validate their command line options. if(pid == 0 && programPath == NULL && procName == 0){ printf("ERROR: Please specify either a Process ID, a binary to launch, or the name of a running process.\n"); Usage(); } // Check to make sure the specified a DLL. if(dllCount == 0){ printf("ERROR: Please specify a DLL to inject.\n"); Usage(); } // Ensure that they selected an injection method that is within range. if(injectionMethod>1){ printf("ERROR: Invalid injection method selected.\n"); Usage(); } // The handle of the process we will inject into. HANDLE proc=INVALID_HANDLE_VALUE; // Used for keeping track of the suspended threads. DWORD threadCount = 0; // Assuming 1MB stacks, 2048*1MB =~ 2GB. I am ASSUMING that the thread count in an application will never exceed this due to hardware contraints. #define MAX_THREADS 2048 HANDLE threads[MAX_THREADS]; // Get the handle to the process to inject into and store it in proc. if(startProcess){ // startProcess means that we need to start it up... PROCESS_INFORMATION pi; STARTUPINFOA si; GetStartupInfoA(&si); // Assemble the command line to start the process. char CommandLine[8191] = {0}; sprintf(CommandLine,"\"%s\"", programPath); if(procArgs != NULL){ strcat(CommandLine, " "); strcat(CommandLine, procArgs); } DWORD dwFlags = 0; if(waitMs) dwFlags |= CREATE_SUSPENDED; printf("Starting new process to inject into:\n%s\n",CommandLine); if(CreateProcessA(NULL,CommandLine,NULL,NULL,0,dwFlags,NULL,NULL,&si,&pi) == 0) { ErrorExit(TEXT("CreateProcessA"), "Check your process path."); } if(waitMs){ threadCount = 1; threads[0] = pi.hThread; } proc = pi.hProcess; } else{ // The process is already running, we need to get a handle to it with the correct permissions. if(procName != NULL){ // Open a handle to the process if they specified it with a name. proc = GetProcessHandleFromName(procName); if(proc == NULL){ printf("ERROR: Failed to find a process by the name of '%S' that we have permissions to inject into. Make sure that your have proper permissions and the process is running.\n", procName); ExitProcess(-1); } } else { // Open a handle to the process specified by PID. proc = GetProcessHandleFromPid(pid); if(proc == NULL) { ErrorExit(TEXT("OpenProcess"), "Check the Process Id that you provided."); } } if(waitMs){ /** @todo Add the ability to suspend already running processes. */ } } // Inject each dll listed. for(DWORD i=0;i<dllCount;i++){ printf("Injecting %s into pid %d.\n", dllList[i], GetProcessId(proc)); DWORD dwThreadExitCode; switch(injectionMethod){ case 0: printf("Using LoadLibrary injection (Richter Method).\n"); dwThreadExitCode = LoadLibraryInjection(proc, dllList[i]); break; case 1: printf("Using Thread Hijacking...\n"); dwThreadExitCode = ThreadHijackInjection(proc, dllList[i]); break; } if(dwThreadExitCode == 0){ printf("ERROR: The target process failed to load %s. Check the DLL path you specified.\n",dllList[i]); printf("DLL Injection Failed!"); } else { printf("%s Injection Successful!\n",dllList[i]); } // Free up that memory... free(dllList[i]); } if(waitMs && startProcess){ printf("Waiting %ims for DLL to lay hooks before resuming the process.\n",waitMs); Sleep(waitMs); for(DWORD i=0;i<threadCount;i++){ printf("Resuming threads in process %d...\n", GetProcessId(proc)); ResumeThread(threads[i]); CloseHandle(threads[i]); } } // No need for this handle anymore. CloseHandle(proc); return 0; }
extern "C" int main(int argc, char* argv[]){ if(argc < 2){ std::cout << "No exe specified!\n\n"; std::cout << "Usage: Heapy <exe path> [args to pass to exe]\n\n" " The first argument specifies the exe to launch.\n" " Subsequent arguments are passed to launched exe.\n"; return -1; } char *injectionTarget = argv[1]; bool win64 = false; #ifdef _WIN64 win64 = true; #endif // Select correct dll name depending on whether x64 or win32 version launched. std::string heapyInjectDllName; if(win64) heapyInjectDllName = "HeapyInject_x64.dll"; else heapyInjectDllName = "HeapyInject_Win32.dll"; // Assume that the injection payload dll is in the same directory as the exe. CHAR exePath[MAX_PATH]; GetModuleFileNameA(NULL, exePath, MAX_PATH ); std::string dllPath = getDirectoryOfFile(std::string(exePath)) + "\\" + heapyInjectDllName; std::string commandLine = injectionTarget; for(int i = 2; i < argc; ++i){ commandLine += " " + std::string(argv[i]); } // Start our new process with a suspended main thread. std::cout << "Starting process with heap profiling enabled..." << std::endl; std::cout << "Target exe path: " << injectionTarget << std::endl; std::cout << "Target execommand line: " << commandLine; std::cout << "Dll to inject: " << dllPath << std::endl; DWORD flags = CREATE_SUSPENDED; PROCESS_INFORMATION pi; STARTUPINFOA si; GetStartupInfoA(&si); // CreatePRocessA can modify input arg so do this to be safe. std::vector<char> commandLineMutable(commandLine.begin(), commandLine.end()); if(CreateProcessA(NULL, commandLineMutable.data(), NULL, NULL, 0, flags, NULL, (LPSTR)".", &si, &pi) == 0){ std::cerr << "Error creating process " << injectionTarget << std::endl; return -1; } // Inject our dll. // This method returns only when injection thread returns. try{ if(!LoadLibraryInjection(pi.hProcess, dllPath.c_str())){ throw std::runtime_error("LoadLibrary failed!"); } }catch(const std::exception &e){ std::cerr << "\n"; std::cerr << "Error while injecting process: " << e.what() << "\n\n"; std::cerr << "Check that the hook dll (" << dllPath << " is in the correct location.\n\n"; std::cerr << "Are you trying to inject a " << (win64 ? " 32 bit " : " 64 bit ") << " application using the " << (win64 ? " 64 bit " : " 32 bit ") << " injector?\n\n"; // TODO: figure out how to terminate thread. This does not always work. TerminateProcess(pi.hProcess, 0); return -1; } // Once the injection thread has returned it is safe to resume the main thread. ResumeThread(pi.hThread); // Wait for the target application to exit. // This doesn't matter to much, but makes heapy nicer to use in test scripts. // (Like the ProfileTestApplication project.) WaitForSingleObject(pi.hProcess, INFINITE); return 0; }
int main(int argc, const char* argv[]) { if (argc < 6) { printf("Usage: hookfunction [executableName|pid] moduleName hookAddress libraryPath functionName\r\n"); return 3; } char* temp; int pid = (int)strtol(argv[1], &temp, 10); if (errno == ERANGE || temp != '\0') { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (hSnapshot == INVALID_HANDLE_VALUE) return 1; PROCESSENTRY32 processEntry; memset(&processEntry, 0, sizeof(processEntry)); processEntry.dwSize = sizeof(processEntry); if (!Process32First(hSnapshot, &processEntry)) return 2; do { if (strcmp(processEntry.szExeFile, argv[1]) == 0) pid = processEntry.th32ProcessID; } while (Process32Next(hSnapshot, &processEntry)); CloseHandle(hSnapshot); } HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProcess == NULL) return 5; char libraryPath[MAX_PATH]; _getcwd(libraryPath, sizeof(libraryPath)); strcat(libraryPath, "\\HookFunctionDll.dll"); DWORD hRemoteModule = GetModuleHandleInjection(hProcess, libraryPath); if (hRemoteModule == NULL) LoadLibraryInjection(hProcess, libraryPath); hRemoteModule = GetModuleHandleInjection(hProcess, libraryPath); if (hRemoteModule == NULL) return 6; HookInformation hookInformation; memset(&hookInformation, 0, sizeof(hookInformation)); char moduleName[MAX_PATH]; strcpy(moduleName, argv[2]); hookInformation.HookAddress = strtol(argv[3], NULL, 16) + GetModuleHandleInjection(hProcess, NULL); strcpy(hookInformation.LibraryPath, argv[4]); strcpy(hookInformation.FunctionName, argv[5]); if (sizeof(hookInformation.AdditionalParameters) > 0) { for (int i = 0; i < sizeof(hookInformation.AdditionalParameters) / sizeof(hookInformation.AdditionalParameters[0]) && 6 + i < argc; i++) strcpy_s(hookInformation.AdditionalParameters[i], argv[6 + i]); } void* data = VirtualAllocEx(hProcess, NULL, sizeof(hookInformation), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); SIZE_T bytesWritten; WriteProcessMemory(hProcess, data, &hookInformation, sizeof(hookInformation), &bytesWritten); int hookFunctionOffset = GetFunctionOffset(libraryPath, "Hook"); HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)(hRemoteModule + hookFunctionOffset), data, 0, NULL); DWORD dwThreadExitCode = 0; WaitForSingleObject(hThread, 10000); GetExitCodeThread(hThread, &dwThreadExitCode); CloseHandle(hThread); //Don't free leave it because it is being used actively by python hooks //VirtualFree(data, NULL, MEM_FREE); /*printf("Unhook? (y/n)\r\n"); std::string answer; std::cin >> answer; if (strcmp(answer.c_str(), "y") == 0) { int unhookFunctionOffset = GetFunctionOffset(libraryPath, "Unhook"); hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)(hRemoteModule + unhookFunctionOffset), data, 0, NULL); WaitForSingleObject(hThread, 10000); CloseHandle(hThread); }*/ return 0; }