#include "stdafx.h" #include "Process.h" #include "Path.h" #include "Environment.h" #include "Directory.h" #include #include // // Internal routine for getting system information // typedef LONG (NTAPI *NtSuspendProcess)(HANDLE); typedef LONG (NTAPI *NtResumeProcess)(HANDLE); typedef struct _THREAD_BASIC_INFORMATION { NTSTATUS ExitStatus; PVOID TebBaseAddress; CLIENT_ID ClientId; KAFFINITY AffinityMask; KPRIORITY Priority; KPRIORITY BasePriority; } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; #pragma comment(lib, "ntdll.lib") namespace Diagnostics { Process::Process() : _Handle(nullptr), _HasLoaded(false), _Access(PROCESS_ALL_ACCESS), _ProcessInfo() { } Process::Process(ProcessInfo Pi) : _Handle(nullptr), _HasLoaded(true), _Access(PROCESS_ALL_ACCESS) { this->_ProcessInfo = Pi; } Process::~Process() { this->Close(); } Process::Process(const Process& Rhs) : _Handle(nullptr), _HasLoaded(false), _Access(PROCESS_ALL_ACCESS) { this->_HasLoaded = Rhs._HasLoaded; this->_ProcessInfo = Rhs._ProcessInfo; } Process::Process(Process&& Rhs) { this->_Handle = Rhs._Handle; this->_HasLoaded = Rhs._HasLoaded; this->_Access = Rhs._Access; this->_ProcessInfo = Rhs._ProcessInfo; Rhs._Handle = nullptr; Rhs._Access = PROCESS_ALL_ACCESS; Rhs._HasLoaded = false; Rhs._ProcessInfo = {}; } void Process::Close() { if (this->_Handle) CloseHandle(this->_Handle); this->_Handle = nullptr; } void Process::CloseMainWindow() { auto mWindow = this->GetProcessMainWindowHandle(); if (!mWindow) return; PostMessageA(mWindow, WM_CLOSE, NULL, NULL); } bool Process::IsAlive() { if (!this->AquireProcessHandle()) return false; return (WaitForSingleObject(this->_Handle, 0) == WAIT_TIMEOUT); } void Process::Kill() { if (!this->AquireProcessHandle()) return; TerminateProcess(this->_Handle, -1); } void Process::Suspend() { if (!this->AquireProcessHandle()) return; auto pSuspend = (NtSuspendProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtSuspendProcess"); pSuspend(this->_Handle); } void Process::Resume() { if (!this->AquireProcessHandle()) return; auto pResume = (NtResumeProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtResumeProcess"); pResume(this->_Handle); } void Process::WaitForExit() { if (!this->AquireProcessHandle()) return; WaitForSingleObject(this->_Handle, INFINITE); } void Process::WaitForInputIdle() { if (!this->AquireProcessHandle()) return; ::WaitForInputIdle(this->_Handle, INFINITE); } bool Process::InjectModule(const String& ModulePath) { if (!this->AquireProcessHandle()) return false; BOOL Is32BitProcess = false; if (!IsWow64Process(this->_Handle, &Is32BitProcess)) return false; auto PathBuffer = VirtualAllocEx(this->_Handle, NULL, (SIZE_T)(ModulePath.Length() + 1), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (PathBuffer == NULL) return false; auto WriteResult = WriteProcessMemory(this->_Handle, PathBuffer, (const char*)ModulePath, (SIZE_T)(ModulePath.Length() + 1), NULL); if (WriteResult == FALSE) return false; auto LoadLibraryProc = this->ResolveInjectionAddress(Is32BitProcess); if (LoadLibraryProc == nullptr) return false; DWORD ThreadID = 0; auto ThreadHandle = CreateRemoteThread(this->_Handle, NULL, 0, LoadLibraryProc, PathBuffer, 0, &ThreadID); if (ThreadHandle == NULL) return false; WaitForSingleObject(ThreadHandle, INFINITE); return true; } const String& Process::GetProcessName() const { return this->_ProcessInfo.ProcessName; } const uint32_t Process::GetBasePriority() const { return this->_ProcessInfo.BasePriority; } const uint32_t Process::GetId() const { return this->_ProcessInfo.ProcessId; } const uint32_t Process::GetHandleCount() const { return this->_ProcessInfo.HandleCount; } const uint64_t Process::GetPagedSystemMemorySize() const { return this->_ProcessInfo.PoolPagedBytes; } const uint64_t Process::GetNonPagedSystemMemorySize() const { return this->_ProcessInfo.PoolNonPagedBytes; } const uint64_t Process::GetVirtualMemorySize() const { return this->_ProcessInfo.VirtualBytes; } const uint64_t Process::GetPeakVirtualMemorySize() const { return this->_ProcessInfo.VirtualBytesPeak; } const uint64_t Process::GetWorkingSet() const { return this->_ProcessInfo.WorkingSet; } const uint64_t Process::GetPeakWorkingSet() const { return this->_ProcessInfo.WorkingSetPeak; } const uint64_t Process::GetPagedMemorySize() const { return this->_ProcessInfo.PageFileBytes; } const uint64_t Process::GetPeakPagedMemorySize() const { return this->_ProcessInfo.PageFileBytesPeak; } const uint64_t Process::GetPrivateMemorySize() const { return this->_ProcessInfo.PrivateBytes; } const uint32_t Process::GetSessionId() const { return this->_ProcessInfo.SessionId; } const HANDLE Process::GetHandle() { if (!this->AquireProcessHandle()) return nullptr; return this->_Handle; } const HWND Process::GetMainWindowHandle() { return this->GetProcessMainWindowHandle(); } const String Process::GetMainWindowTitle() { auto mHandle = this->GetProcessMainWindowHandle(); if (!mHandle) return ""; char Buffer[MAX_PATH + 1]{}; auto mResult = GetWindowTextA(mHandle, Buffer, MAX_PATH); return String(Buffer, mResult); } const uint32_t Process::GetExitCode() { if (!this->AquireProcessHandle()) return -1; DWORD eCode = -1; GetExitCodeProcess(this->_Handle, &eCode); return eCode; } const List Process::GetProcessModules() { auto Result = List(); if (!this->AquireProcessHandle()) return Result; HMODULE ModHandles[1024]; DWORD ResultRead; if (!EnumProcessModulesEx(this->_Handle, ModHandles, sizeof(ModHandles), &ResultRead, LIST_MODULES_ALL)) return Result; for (uint32_t i = 0; i < (ResultRead / sizeof(HMODULE)); i++) { auto ModuleInfo = ProcessModule(); MODULEINFO ModInfo{}; GetModuleInformation(this->_Handle, ModHandles[i], &ModInfo, sizeof(ModInfo)); ModuleInfo.ModuleMemorySize = ModInfo.SizeOfImage; ModuleInfo.EntryPointAddress = (uint64_t)ModInfo.EntryPoint; ModuleInfo.BaseAddress = (uint64_t)ModInfo.lpBaseOfDll; char Buffer[1024]{}; GetModuleBaseNameA(this->_Handle, ModHandles[i], Buffer, 1024); ModuleInfo.ModuleName = String(Buffer); std::memset(Buffer, 0, 1024); GetModuleFileNameExA(this->_Handle, ModHandles[i], Buffer, 1024); ModuleInfo.FileName = String(Buffer); Result.EmplaceBack(std::move(ModuleInfo)); } return Result; } const List Process::GetProcessThreads() { auto Result = List(); if (!this->AquireProcessHandle()) return Result; auto hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hSnapshot == INVALID_HANDLE_VALUE) return Result; THREADENTRY32 TInfo{}; TInfo.dwSize = sizeof(THREADENTRY32); if (!Thread32First(hSnapshot, &TInfo)) { CloseHandle(hSnapshot); return Result; } do { if (TInfo.th32OwnerProcessID == this->_ProcessInfo.ProcessId) { auto ThreadInfo = ProcessThread(); ThreadInfo.Id = TInfo.th32ThreadID; ThreadInfo.BasePriority = TInfo.tpBasePri; auto hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, TInfo.th32ThreadID); if (hThread == NULL) continue; THREAD_BASIC_INFORMATION ExThreadInfo{}; uint64_t ExThreadStart = 0; NtQueryInformationThread(hThread, (THREADINFOCLASS)0x0, &ExThreadInfo, sizeof(ExThreadInfo), NULL); NtQueryInformationThread(hThread, (THREADINFOCLASS)0x9, &ExThreadStart, sizeof(uint64_t), NULL); ThreadInfo.CurrentPriority = ExThreadInfo.Priority; ThreadInfo.StartAddress = ExThreadStart; CloseHandle(hThread); Result.EmplaceBack(std::move(ThreadInfo)); } } while (Thread32Next(hSnapshot, &TInfo)); CloseHandle(hSnapshot); return Result; } Process Process::GetProcessById(uint32_t Pid) { uint32_t OurId[1] = { Pid }; auto ProcessInfo = Process::GetProcessInfos({ OurId }); if (ProcessInfo.Count() == 0) return Process(); return Process(ProcessInfo[0]); } List Process::GetProcessesByName(const String& Name) { auto ProcessInfos = Process::GetProcessInfos({}); auto Result = List(); auto NameCompare = Name.ToLower(); // Iterate and filter for (uint32_t i = 0; i < ProcessInfos.Count(); i++) { if (ProcessInfos[i].ProcessName.ToLower() == NameCompare) Result.EmplaceBack(ProcessInfos[i]); } return Result; } List Process::GetProcesses() { auto ProcessInfos = Process::GetProcessInfos({}); auto Result = List(ProcessInfos.Count()); // Iterate and setup for (uint32_t i = 0; i < ProcessInfos.Count(); i++) Result.EmplaceBack(ProcessInfos[i]); return Result; } Process Process::GetCurrentProcess() { uint32_t OurId[1] = { ::GetCurrentProcessId() }; return Process(Process::GetProcessInfos({ OurId })[0]); } Process Process::Start(const String& FileName) { return Process::Start(ProcessStartInfo(FileName)); } Process Process::Start(const String& FileName, const String& Arguments) { return Process::Start(ProcessStartInfo(FileName, Arguments)); } Process Process::Start(const ProcessStartInfo& Start) { // Create it depending on launch type if (Start.UseShellExecute) { SHELLEXECUTEINFOA StartInfo{}; StartInfo.fMask = SEE_MASK_NOCLOSEPROCESS; StartInfo.cbSize = sizeof(StartInfo); switch (Start.WindowStyle) { case ProcessWindowStyle::Hidden: StartInfo.nShow = SW_HIDE; break; case ProcessWindowStyle::Minimized: StartInfo.nShow = SW_SHOWMINIMIZED; break; case ProcessWindowStyle::Maximized: StartInfo.nShow = SW_SHOWMAXIMIZED; break; default: StartInfo.nShow = SW_SHOWNORMAL; break; } if (Start.FileName.Length() != 0) StartInfo.lpFile = (char*)Start.FileName; if (Start.Verb.Length() != 0) StartInfo.lpVerb = (char*)Start.Verb; if (Start.Arguments.Length() != 0) StartInfo.lpParameters = (char*)Start.Arguments; if (Start.WorkingDirectory.Length() != 0) StartInfo.lpDirectory = (char*)Start.WorkingDirectory; StartInfo.fMask |= SEE_MASK_FLAG_DDEWAIT; if (!ShellExecuteExA(&StartInfo)) return Process(); return GetProcessById(GetProcessId(StartInfo.hProcess)); } else { STARTUPINFOA StartInfo{}; PROCESS_INFORMATION ProcessInfo{}; String CommandLine; if (Start.FileName.StartsWith("\"") && Start.FileName.EndsWith("\"")) CommandLine += Start.FileName; else CommandLine = "\"" + Start.FileName + "\""; if (!String::IsNullOrWhiteSpace(Start.Arguments)) { CommandLine += " " + Start.Arguments; } DWORD CreationFlags = 0; if (Start.CreateNoWindow) CreationFlags |= CREATE_NO_WINDOW; auto WorkingDirectory = (Start.WorkingDirectory.Length() == 0) ? IO::Directory::GetCurrentDirectory() : Start.WorkingDirectory; if (!CreateProcessA(NULL, (char*)CommandLine, NULL, NULL, TRUE, CreationFlags, NULL, (const char*)WorkingDirectory, &StartInfo, &ProcessInfo)) return Process(); return GetProcessById(ProcessInfo.dwProcessId); } } void Process::EnterDebugMode() { Process::SetPrivilage("SeDebugPrivilege", true); } void Process::LeaveDebugMode() { Process::SetPrivilage("SeDebugPrivilege", false); } Process& Process::operator=(const Process& Rhs) { this->_Access = Rhs._Access; this->_HasLoaded = Rhs._HasLoaded; this->_ProcessInfo = Rhs._ProcessInfo; this->_Handle = nullptr; return *this; } bool Process::operator==(const nullptr_t Rhs) const { if (this->_Handle == nullptr && this->_HasLoaded == false && this->_ProcessInfo.ProcessId == 0) return true; return false; } bool Process::operator!=(const nullptr_t Rhs) const { return !(*this == Rhs); } void Process::SetPrivilage(const String& PrivilegeName, bool Enabled) { HANDLE hToken = nullptr; if (!OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { if (GetLastError() == ERROR_NO_TOKEN) { if (!ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation)) return; if (!OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return; } else { return; } } TOKEN_PRIVILEGES tp; LUID luid; TOKEN_PRIVILEGES tpPrevious; DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); if (!LookupPrivilegeValueA(NULL, (const char*)PrivilegeName, &luid)) return; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = 0; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious); if (GetLastError() != ERROR_SUCCESS) return; tpPrevious.PrivilegeCount = 1; tpPrevious.Privileges[0].Luid = luid; if (Enabled) tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); else tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); AdjustTokenPrivileges(hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL); } List Process::GetProcessInfos(const List& ProcessIdMatch) { auto Result = List(68); ULONG Required = 0; NTSTATUS Status = 0; std::unique_ptr ProcessInfoBuffer = nullptr; do { Status = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS::SystemProcessInformation, (PVOID)ProcessInfoBuffer.get(), Required, &Required); if (Status == Process::StatusInfoLengthMismatch) ProcessInfoBuffer.reset(new uint8_t[Required]); } while (Status == Process::StatusInfoLengthMismatch); uint64_t CurrentOffset = 0; while (true) { auto NProcessInfo = (SYSTEM_PROCESS_INFORMATION*)(ProcessInfoBuffer.get() + CurrentOffset); auto NProcessId = (uint32_t)(uint64_t)NProcessInfo->UniqueProcessId; ProcessInfo Pi; Pi.ProcessId = NProcessId; Pi.HandleCount = (uint32_t)NProcessInfo->HandleCount; Pi.SessionId = (uint32_t)NProcessInfo->SessionId; Pi.PoolPagedBytes = (uint64_t)NProcessInfo->QuotaPagedPoolUsage;; Pi.PoolNonPagedBytes = (uint64_t)NProcessInfo->QuotaNonPagedPoolUsage; Pi.VirtualBytes = (uint64_t)NProcessInfo->VirtualSize; Pi.VirtualBytesPeak = (uint64_t)NProcessInfo->PeakVirtualSize; Pi.WorkingSetPeak = (uint64_t)NProcessInfo->PeakWorkingSetSize; Pi.WorkingSet = (uint64_t)NProcessInfo->WorkingSetSize; Pi.PageFileBytesPeak = (uint64_t)NProcessInfo->PeakPagefileUsage; Pi.PageFileBytes = (uint64_t)NProcessInfo->PagefileUsage; Pi.PrivateBytes = (uint64_t)NProcessInfo->PrivatePageCount; Pi.BasePriority = (uint32_t)NProcessInfo->BasePriority; if (NProcessInfo->ImageName.Buffer == NULL) { if (NProcessId == 0x4) { Pi.ProcessName = "System"; } else if (NProcessId == 0x0) { Pi.ProcessName = "Idle"; } else { Pi.ProcessName = String::Format("Process_%d", NProcessId); } } else { Pi.ProcessName = Process::GetProcessShortName(WString(NProcessInfo->ImageName.Buffer, NProcessInfo->ImageName.Length / sizeof(WCHAR)).ToString()); } if (!ProcessIdMatch.Empty() && ProcessIdMatch.Contains(NProcessId)) Result.EmplaceBack(std::move(Pi)); else if (ProcessIdMatch.Empty()) Result.EmplaceBack(std::move(Pi)); if (NProcessInfo->NextEntryOffset == 0) break; CurrentOffset += NProcessInfo->NextEntryOffset; } return Result; } String Process::GetProcessShortName(const String& Name) { int32_t Slash = -1, Period = -1; for (uint32_t i = 0; i < Name.Length(); i++) { if (Name[i] == '\\') Slash = i; else if (Name[i] == '.') Period = i; } if (Period == -1) Period = Name.Length() - 1; else { auto Ext = Name.SubString(Period); if (Ext.ToLower() == ".exe") Period--; else Period = Name.Length() - 1; } if (Slash == -1) Slash = 0; else Slash++; return Name.SubString(Slash, Period - Slash + 1); } LPTHREAD_START_ROUTINE Process::ResolveInjectionAddress(BOOL Is32BitProcess) { if (!Is32BitProcess && sizeof(uintptr_t) == 8) return (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA"); else if (Is32BitProcess && sizeof(uintptr_t) == 4) return (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA"); // // Get the base address of kernel32.dll // HMODULE ModHandles[1024]; DWORD ResultRead; if (!EnumProcessModulesEx(this->_Handle, ModHandles, sizeof(ModHandles), &ResultRead, LIST_MODULES_32BIT)) return nullptr; HMODULE Kernel32Wow = nullptr; for (uint32_t i = 0; i < (ResultRead / sizeof(HMODULE)); i++) { char ModNameTemp[MAX_PATH]; if (GetModuleFileNameExA(this->_Handle, ModHandles[i], ModNameTemp, sizeof(ModNameTemp))) { auto NameLen = strlen(ModNameTemp); auto K32Len = strlen("kernel32.dll"); if (NameLen >= K32Len && _stricmp(ModNameTemp + (NameLen - K32Len), "kernel32.dll") == 0) { Kernel32Wow = ModHandles[i]; break; } } } if (Kernel32Wow == nullptr) return nullptr; // // We have the base address, now, parse the module for the export // auto ModulePath = IO::Path::Combine(System::Environment::GetFolderPath(System::SpecialFolder::SystemX86), "kernel32.dll"); HANDLE ExeHandle = CreateFileA((const char*)ModulePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (ExeHandle == INVALID_HANDLE_VALUE) return nullptr; HANDLE ExeMapping = CreateFileMappingA(ExeHandle, NULL, PAGE_READONLY, 0, 0, NULL); if (ExeMapping == NULL) { CloseHandle(ExeHandle); return nullptr; } LPVOID ExeBuffer = MapViewOfFile(ExeMapping, FILE_MAP_READ, 0, 0, 0); if (ExeBuffer == NULL) { CloseHandle(ExeMapping); CloseHandle(ExeHandle); return nullptr; } PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)ExeBuffer; PIMAGE_NT_HEADERS32 NTHeader = (PIMAGE_NT_HEADERS32)((uintptr_t)ExeBuffer + (uintptr_t)DosHeader->e_lfanew); PIMAGE_SECTION_HEADER FirstSectionHeader = (PIMAGE_SECTION_HEADER)((PBYTE)&NTHeader->OptionalHeader + NTHeader->FileHeader.SizeOfOptionalHeader); PIMAGE_EXPORT_DIRECTORY ExportDirectory = nullptr; PULONG Functions = nullptr, Names = nullptr; PUSHORT Ordinals = nullptr; uint32_t SectionIndex = 0; for (SectionIndex = 0; SectionIndex < NTHeader->FileHeader.NumberOfSections; SectionIndex++) { if (FirstSectionHeader[SectionIndex].VirtualAddress <= NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress && NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress < (FirstSectionHeader[SectionIndex].VirtualAddress + FirstSectionHeader[SectionIndex].Misc.VirtualSize)) { ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)ExeBuffer + FirstSectionHeader[SectionIndex].PointerToRawData + NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress - FirstSectionHeader[SectionIndex].VirtualAddress); // Resolve each segment (Fn, Name, Ordinal) from the directory Functions = (PULONG)((PBYTE)ExeBuffer + FirstSectionHeader[SectionIndex].PointerToRawData + ExportDirectory->AddressOfFunctions - FirstSectionHeader[SectionIndex].VirtualAddress); Names = (PULONG)((PBYTE)ExeBuffer + FirstSectionHeader[SectionIndex].PointerToRawData + ExportDirectory->AddressOfNames - FirstSectionHeader[SectionIndex].VirtualAddress); Ordinals = (PUSHORT)((PBYTE)ExeBuffer + FirstSectionHeader[SectionIndex].PointerToRawData + ExportDirectory->AddressOfNameOrdinals - FirstSectionHeader[SectionIndex].VirtualAddress); break; } } if (ExportDirectory == nullptr) { UnmapViewOfFile(ExeBuffer); CloseHandle(ExeMapping); CloseHandle(ExeHandle); return nullptr; } LPTHREAD_START_ROUTINE ResultAddress = nullptr; for (uint32_t ordinal = 0; (ordinal < ExportDirectory->NumberOfFunctions) && (ResultAddress == nullptr); ordinal++) { for (uint32_t i = 0; i < ExportDirectory->NumberOfNames; i++) { if (ordinal == Ordinals[i]) { auto FunctionName = (char*)((PBYTE)ExeBuffer + FirstSectionHeader[SectionIndex].PointerToRawData + Names[i] - FirstSectionHeader[SectionIndex].VirtualAddress); if (_strnicmp(FunctionName, "LoadLibraryA", strlen("LoadLibraryA")) == 0) { ResultAddress = (LPTHREAD_START_ROUTINE)((uintptr_t)Kernel32Wow + Functions[Ordinals[i]]); break; } } } } UnmapViewOfFile(ExeBuffer); CloseHandle(ExeMapping); CloseHandle(ExeHandle); return ResultAddress; } HWND Process::GetProcessMainWindowHandle() { if (!this->_HasLoaded) return nullptr; struct params { HWND hWnd; DWORD pId; } Params; Params.hWnd = nullptr; Params.pId = this->_ProcessInfo.ProcessId; auto eResult = EnumWindows([](HWND hWnd, LPARAM lParam) -> BOOL { auto pParams = (params*)(lParam); DWORD ProcessId; if (GetWindowThreadProcessId(hWnd, &ProcessId) && ProcessId == pParams->pId) { pParams->hWnd = hWnd; return FALSE; } return TRUE; }, (LPARAM)&Params); return Params.hWnd; } bool Process::AquireProcessHandle() { if (!this->_HasLoaded) return false; if (this->_Handle != nullptr) return true; // Default to all access if we can get it, required for injection this->_Access = PROCESS_ALL_ACCESS; auto Handle = OpenProcess(this->_Access, FALSE, this->_ProcessInfo.ProcessId); if (Handle == NULL) { this->_Access = (PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_VM_READ | PROCESS_TERMINATE); Handle = OpenProcess(this->_Access, FALSE, this->_ProcessInfo.ProcessId); } // TODO: insert error handling / exceptions when the process no longer exists... if (Handle == NULL) return false; this->_Handle = Handle; return true; } }