131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | #include <iostream>
 | ||
|  | #include <string>
 | ||
|  | #include <windows.h>
 | ||
|  | #include <detours.h>
 | ||
|  | 
 | ||
|  | #include "payloadguid.hpp"
 | ||
|  | 
 | ||
|  | HANDLE hChildProcess = NULL; | ||
|  | HANDLE hChildThread = NULL; | ||
|  | 
 | ||
|  | __declspec(noreturn) void HandleApiFailure(const char* api) | ||
|  | { | ||
|  |     DWORD lastErr = GetLastError(); | ||
|  |     std::cout << "payload.exe: " << api << " failed (" << lastErr << ')' << std::endl; | ||
|  | 
 | ||
|  |     if (hChildThread != NULL) | ||
|  |     { | ||
|  |         CloseHandle(hChildThread); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (hChildProcess != NULL) | ||
|  |     { | ||
|  |         TerminateProcess(hChildProcess, 1); | ||
|  |         CloseHandle(hChildProcess); | ||
|  |     } | ||
|  | 
 | ||
|  |     ExitProcess(1); | ||
|  | } | ||
|  | 
 | ||
|  | std::wstring GetProcessFileName(HANDLE process) | ||
|  | { | ||
|  |     DWORD exeLocation_size = MAX_PATH + 1; | ||
|  | 
 | ||
|  |     std::wstring exeLocation; | ||
|  |     exeLocation.resize(exeLocation_size); | ||
|  | 
 | ||
|  |     if (!QueryFullProcessImageNameW(process, 0, &exeLocation[0], &exeLocation_size)) | ||
|  |     { | ||
|  |         HandleApiFailure("QueryFullProcessImageNameW"); | ||
|  |     } | ||
|  | 
 | ||
|  |     exeLocation.resize(exeLocation_size); | ||
|  |     return exeLocation; | ||
|  | } | ||
|  | 
 | ||
|  | void StartChild() | ||
|  | { | ||
|  |     std::wstring target = GetProcessFileName(GetCurrentProcess()); | ||
|  |     target.erase(target.rfind(L'\\') + 1); | ||
|  |     target += L"payloadtarget.exe"; | ||
|  | 
 | ||
|  |     STARTUPINFOW si = { sizeof(si) }; | ||
|  |     PROCESS_INFORMATION pi; | ||
|  |     if (!CreateProcessW(target.c_str(), NULL, NULL, NULL, false, | ||
|  |         CREATE_SUSPENDED, NULL, NULL, &si, &pi)) | ||
|  |     { | ||
|  |         HandleApiFailure("CreateProcessW"); | ||
|  |     } | ||
|  | 
 | ||
|  |     hChildProcess = pi.hProcess; | ||
|  |     hChildThread = pi.hThread; | ||
|  | } | ||
|  | 
 | ||
|  | template<typename T> | ||
|  | volatile T* InjectPayload(HANDLE hProcess, T payload, REFGUID guid) | ||
|  | { | ||
|  |     return static_cast<volatile T*>( | ||
|  |         DetourCopyPayloadToProcessEx(hProcess,guid, &payload, sizeof(payload))); | ||
|  | } | ||
|  | 
 | ||
|  | int main() | ||
|  | { | ||
|  |     StartChild(); | ||
|  | 
 | ||
|  |     // give the child a handle to ourself
 | ||
|  |     HANDLE targetHandleToParent; | ||
|  |     if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), | ||
|  |         hChildProcess, &targetHandleToParent, 0, false, DUPLICATE_SAME_ACCESS)) | ||
|  |     { | ||
|  |         HandleApiFailure("DuplicateHandle"); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (!InjectPayload(hChildProcess, targetHandleToParent, PARENT_HANDLE_PAYLOAD)) | ||
|  |     { | ||
|  |         HandleApiFailure("DetourCopyPayloadToProcessEx"); | ||
|  |     } | ||
|  | 
 | ||
|  |     // inject a payload in ourself containing zero data
 | ||
|  |     // the goal is for the child process to find this payload
 | ||
|  |     // and fill it with random data, to test DetourFindRemotePayload
 | ||
|  |     volatile random_payload_t* payloadAddr = | ||
|  |         InjectPayload<random_payload_t>(GetCurrentProcess(), 0, RANDOM_DATA_PAYLOAD); | ||
|  |     if (!payloadAddr) | ||
|  |     { | ||
|  |         HandleApiFailure("DetourCopyPayloadToProcessEx"); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (!ResumeThread(hChildThread)) | ||
|  |     { | ||
|  |         HandleApiFailure("ResumeThread"); | ||
|  |     } | ||
|  | 
 | ||
|  |     CloseHandle(hChildThread); | ||
|  |     hChildThread = NULL; | ||
|  | 
 | ||
|  |     if (WaitForSingleObject(hChildProcess, INFINITE) == WAIT_FAILED) | ||
|  |     { | ||
|  |         HandleApiFailure("WaitForSingleObject"); | ||
|  |     } | ||
|  | 
 | ||
|  |     DWORD exitCode; | ||
|  |     if (!GetExitCodeProcess(hChildProcess, &exitCode)) | ||
|  |     { | ||
|  |         HandleApiFailure("GetExitCodeProcess"); | ||
|  |     } | ||
|  | 
 | ||
|  |     // the exit code should match the random data the child process gave us
 | ||
|  |     random_payload_t payload = *payloadAddr; | ||
|  |     if (exitCode == payload) | ||
|  |     { | ||
|  |         std::cout << "Success, exit code (0x" << std::uppercase << std::hex << exitCode | ||
|  |             << ") matches payload content (0x" << payload << ')' << std::endl; | ||
|  |         return 0; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         std::cout << "Error, exit code (0x" << std::uppercase  << std::hex << exitCode | ||
|  |             << ") does not matches payload content (0x" << payload << ')' << std::endl; | ||
|  |         return 1; | ||
|  |     } | ||
|  | } |