move utility functions into common.h and module.h

This commit is contained in:
Akash Mozumdar 2020-02-28 00:34:34 -07:00
parent 200c01f4ab
commit 16540bfe69
19 changed files with 122 additions and 130 deletions

View File

@ -9,7 +9,7 @@ add_executable(Textractor WIN32
host/exception.cpp
host/host.cpp
host/textthread.cpp
host/util.cpp
host/hookcode.cpp
Textractor.rc
Textractor.ico
)

View File

@ -1,5 +1,5 @@
#include "host.h"
#include "util.h"
#include "hookcode.h"
#include <io.h>
#include <fcntl.h>
#include <iostream>
@ -12,7 +12,16 @@ int main()
fflush(stdout);
Host::Start([](auto) {}, [](auto) {}, [](auto&) {}, [](auto&) {}, [](TextThread& thread, std::wstring& output)
{
wprintf_s(L"[%I64X:%I32X:%I64X:%I64X:%I64X:%s:%s] %s\n", thread.handle, thread.tp.processId, thread.tp.addr, thread.tp.ctx, thread.tp.ctx2, thread.name.c_str(), Util::GenerateCode(thread.hp, thread.tp.processId).c_str(), output.c_str());
wprintf_s(L"[%I64X:%I32X:%I64X:%I64X:%I64X:%s:%s] %s\n",
thread.handle,
thread.tp.processId,
thread.tp.addr,
thread.tp.ctx,
thread.tp.ctx2,
thread.name.c_str(),
HookCode::Generate(thread.hp, thread.tp.processId).c_str(),
output.c_str()
);
fflush(stdout);
return false;
});
@ -24,7 +33,7 @@ int main()
if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0);
if (_wcsicmp(command, L"attach") == 0) Host::InjectProcess(processId);
else if (_wcsicmp(command, L"detach") == 0) Host::DetachProcess(processId);
else if (auto hp = Util::ParseCode(command)) Host::InsertHook(processId, hp.value());
else if (auto hp = HookCode::Parse(command)) Host::InsertHook(processId, hp.value());
else ExitProcess(0);
}
ExitProcess(0);

View File

@ -1,4 +1,5 @@
#include "util.h"
#include "common.h"
#include "module.h"
#include <sstream>
namespace
@ -36,7 +37,7 @@ namespace
errorMsg << std::uppercase << std::hex <<
L"Error code: " << exception->ExceptionRecord->ExceptionCode << std::endl <<
L"Error address: " << exception->ExceptionRecord->ExceptionAddress << std::endl <<
L"Error in module: " << Util::GetModuleFilename((HMODULE)info.AllocationBase).value_or(L"Could not find") << std::endl <<
L"Error in module: " << GetModuleFilename((HMODULE)info.AllocationBase).value_or(L"Could not find") << std::endl <<
L"Additional info: " << info.AllocationBase << std::endl;
if (exception->ExceptionRecord->ExceptionCode == 0xE06D7363)

View File

@ -1,5 +1,5 @@
#include "util.h"
#include <Psapi.h>
#include "hookcode.h"
#include "module.h"
namespace
{
@ -250,7 +250,7 @@ namespace
if (processId && !(hp.type & MODULE_OFFSET))
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))
if (MEMORY_BASIC_INFORMATION info = {}; VirtualQueryEx(process, (LPCVOID)hp.address, &info, sizeof(info)))
if (auto moduleName = Util::GetModuleFilename(processId, (HMODULE)info.AllocationBase))
if (auto moduleName = GetModuleFilename(processId, (HMODULE)info.AllocationBase))
{
hp.type |= MODULE_OFFSET;
hp.address -= (uint64_t)info.AllocationBase;
@ -265,53 +265,9 @@ namespace
}
}
namespace Util
namespace HookCode
{
std::optional<std::wstring> GetModuleFilename(DWORD processId, HMODULE module)
{
std::vector<wchar_t> buffer(MAX_PATH);
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))
if (GetModuleFileNameExW(process, module, buffer.data(), MAX_PATH)) return buffer.data();
return {};
}
std::optional<std::wstring> GetModuleFilename(HMODULE module)
{
std::vector<wchar_t> buffer(MAX_PATH);
if (GetModuleFileNameW(module, buffer.data(), MAX_PATH)) return buffer.data();
return {};
}
std::vector<std::pair<DWORD, std::optional<std::wstring>>> GetAllProcesses()
{
std::vector<DWORD> processIds(10000);
DWORD spaceUsed = 0;
EnumProcesses(processIds.data(), 10000 * sizeof(DWORD), &spaceUsed);
std::vector<std::pair<DWORD, std::optional<std::wstring>>> processes;
for (int i = 0; i < spaceUsed / sizeof(DWORD); ++i) processes.push_back({ processIds[i], Util::GetModuleFilename(processIds[i]) });
return processes;
}
std::optional<std::wstring> GetClipboardText()
{
if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return {};
if (!OpenClipboard(NULL)) return {};
std::optional<std::wstring> text;
if (AutoHandle<Functor<GlobalUnlock>> clipboard = GetClipboardData(CF_UNICODETEXT)) text = (wchar_t*)GlobalLock(clipboard);
CloseClipboard();
return text;
}
std::optional<std::wstring> StringToWideString(const std::string& text, UINT encoding)
{
std::vector<wchar_t> buffer(text.size() + 1);
if (int length = MultiByteToWideChar(encoding, 0, text.c_str(), text.size() + 1, buffer.data(), buffer.size()))
return std::wstring(buffer.data(), length - 1);
return {};
}
std::optional<HookParam> ParseCode(std::wstring code)
std::optional<HookParam> Parse(std::wstring code)
{
if (code[0] == L'/') code.erase(0, 1); // legacy/AGTH compatibility
if (code[0] == L'R') return ParseRCode(code.erase(0, 1));
@ -319,7 +275,7 @@ namespace Util
return {};
}
std::wstring GenerateCode(HookParam hp, DWORD processId)
std::wstring Generate(HookParam hp, DWORD processId)
{
return hp.type & DIRECT_READ ? GenerateRCode(hp) : GenerateHCode(hp, processId);
}

10
GUI/host/hookcode.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "common.h"
#include "types.h"
namespace HookCode
{
std::optional<HookParam> Parse(std::wstring code);
std::wstring Generate(HookParam hp, DWORD processId = 0);
}

View File

@ -1,6 +1,6 @@
#include "host.h"
#include "defs.h"
#include "util.h"
#include "hookcode.h"
#include "../texthook/texthook.h"
extern const wchar_t* ALREADY_INJECTED;
@ -48,7 +48,7 @@ namespace
Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text)
{
Host::AddConsoleOutput(Util::GenerateCode(hp) + L": " + text);
Host::AddConsoleOutput(HookCode::Generate(hp) + L": " + text);
};
private:
@ -107,9 +107,9 @@ namespace
std::wstring wide = info.text;
if (wide.size() > STRING) OnHookFound(info.hp, std::move(info.text));
info.hp.type &= ~USING_UNICODE;
if (auto converted = Util::StringToWideString((char*)info.text, info.hp.codepage))
if (auto converted = StringToWideString((char*)info.text, info.hp.codepage))
if (converted->size() > STRING) OnHookFound(info.hp, std::move(converted.value()));
if (auto converted = Util::StringToWideString((char*)info.text, info.hp.codepage = CP_UTF8))
if (auto converted = StringToWideString((char*)info.text, info.hp.codepage = CP_UTF8))
if (converted->size() > STRING) OnHookFound(info.hp, std::move(converted.value()));
}
break;
@ -122,7 +122,7 @@ namespace
case HOST_NOTIFICATION_TEXT:
{
auto info = *(ConsoleOutputNotif*)buffer;
Host::AddConsoleOutput(Util::StringToWideString(info.message).value());
Host::AddConsoleOutput(StringToWideString(info.message));
}
break;
default:
@ -179,8 +179,12 @@ namespace Host
for (int retry = 0; !clipboardText && retry < 3; ++retry) // retry loop in case something else is using the clipboard
{
Sleep(10);
if (clipboardText = Util::GetClipboardText()) GetThread(clipboard).AddSentence(std::move(clipboardText.value()));
if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) continue;
if (!OpenClipboard(NULL)) continue;
if (AutoHandle<Functor<GlobalUnlock>> clipboard = GetClipboardData(CF_UNICODETEXT)) clipboardText = (wchar_t*)GlobalLock(clipboard);
CloseClipboard();
}
if (clipboardText) GetThread(clipboard).AddSentence(std::move(clipboardText.value()));
}
throw;
}).detach();

View File

@ -1,6 +1,5 @@
#include "textthread.h"
#include "host.h"
#include "util.h"
extern const wchar_t* INVALID_CODEPAGE;
@ -16,7 +15,7 @@ static bool RemoveRepetition(std::wstring& text)
TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) :
handle(threadCounter++),
name(name.value_or(Util::StringToWideString(hp.name).value())),
name(name.value_or(StringToWideString(hp.name))),
tp(tp),
hp(hp)
{}
@ -48,7 +47,7 @@ void TextThread::Push(BYTE* data, int length)
if (hp.type & HEX_DUMP) for (int i = 0; i < length; i += sizeof(short)) buffer.append(FormatString(L"%04hX ", *(short*)(data + i)));
else if (hp.type & USING_UNICODE) buffer.append((wchar_t*)data, length / sizeof(wchar_t));
else if (auto converted = Util::StringToWideString(std::string((char*)data, length), hp.codepage ? hp.codepage : Host::defaultCodepage)) buffer.append(converted.value());
else if (auto converted = StringToWideString(std::string((char*)data, length), hp.codepage ? hp.codepage : Host::defaultCodepage)) buffer.append(converted.value());
else Host::AddConsoleOutput(INVALID_CODEPAGE);
if (hp.type & FULL_STRING) buffer.push_back(L'\n');
lastPushTime = GetTickCount();

View File

@ -1,15 +0,0 @@
#pragma once
#include "common.h"
#include "types.h"
namespace Util
{
std::optional<std::wstring> GetModuleFilename(DWORD processId, HMODULE module = NULL);
std::optional<std::wstring> GetModuleFilename(HMODULE module = NULL);
std::vector<std::pair<DWORD, std::optional<std::wstring>>> GetAllProcesses();
std::optional<std::wstring> GetClipboardText();
std::optional<std::wstring> StringToWideString(const std::string& text, UINT encoding = CP_UTF8);
std::optional<HookParam> ParseCode(std::wstring code);
std::wstring GenerateCode(HookParam hp, DWORD processId = 0);
}

View File

@ -1,5 +1,5 @@
#include "mainwindow.h"
#include "host/util.h"
#include "module.h"
#include <winhttp.h>
#include <QApplication>
@ -24,7 +24,7 @@ int main(int argc, char *argv[])
}
}).detach();
QDir::setCurrent(QFileInfo(S(Util::GetModuleFilename().value())).absolutePath());
QDir::setCurrent(QFileInfo(S(GetModuleFilename().value())).absolutePath());
QApplication app(argc, argv);
app.setFont(QFont("MS Shell Dlg 2", 10));

View File

@ -1,7 +1,8 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "defs.h"
#include "host/util.h"
#include "module.h"
#include "host/hookcode.h"
#include <shellapi.h>
#include <QStringListModel>
#include <QScrollBar>
@ -113,7 +114,7 @@ MainWindow::MainWindow(QWidget *parent) :
AttachConsole(ATTACH_PARENT_PROCESS);
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), CL_OPTIONS, wcslen(CL_OPTIONS), DUMMY, NULL);
auto processes = Util::GetAllProcesses();
auto processes = GetAllProcesses();
int argc;
std::unique_ptr<LPWSTR[], Functor<LocalFree>> argv(CommandLineToArgvW(GetCommandLineW(), &argc));
for (int i = 0; i < argc; ++i)
@ -136,7 +137,7 @@ MainWindow::MainWindow(QWidget *parent) :
attachTargets.insert(S(process.split(" , ")[0]));
if (!attachTargets.empty())
for (auto [processId, processName] : Util::GetAllProcesses())
for (auto [processId, processName] : GetAllProcesses())
if (processName && attachTargets.count(processName.value()) > 0 && alreadyAttached.count(processId) == 0) Host::InjectProcess(processId);
}
}).detach();
@ -159,7 +160,7 @@ void MainWindow::ProcessConnected(DWORD processId)
{
alreadyAttached.insert(processId);
QString process = S(Util::GetModuleFilename(processId).value_or(L"???"));
QString process = S(GetModuleFilename(processId).value_or(L"???"));
QMetaObject::invokeMethod(this, [this, process, processId]
{
ui->processCombo->addItem(QString::number(processId, 16).toUpper() + ": " + QFileInfo(process).fileName());
@ -173,7 +174,7 @@ void MainWindow::ProcessConnected(DWORD processId)
auto hookList = std::find_if(allProcesses.rbegin(), allProcesses.rend(), [&](QString hookList) { return hookList.contains(process); });
if (hookList != allProcesses.rend())
for (auto hookInfo : hookList->split(" , "))
if (auto hp = Util::ParseCode(S(hookInfo))) Host::InsertHook(processId, hp.value());
if (auto hp = HookCode::Parse(S(hookInfo))) Host::InsertHook(processId, hp.value());
else swscanf_s(S(hookInfo).c_str(), L"|%I64d:%I64d:%[^\n]", &savedThreadCtx, &savedThreadCtx2, savedThreadCode, (unsigned)std::size(savedThreadCode));
}
@ -187,7 +188,7 @@ void MainWindow::ProcessDisconnected(DWORD processId)
void MainWindow::ThreadAdded(TextThread& thread)
{
std::wstring threadCode = Util::GenerateCode(thread.hp, thread.tp.processId);
std::wstring threadCode = HookCode::Generate(thread.hp, thread.tp.processId);
bool savedMatch = savedThreadCtx == thread.tp.ctx && savedThreadCtx2 == thread.tp.ctx2 && savedThreadCode == threadCode;
if (savedMatch) savedThreadCtx = savedThreadCtx2 = savedThreadCode[0] = 0;
QMetaObject::invokeMethod(this, [this, savedMatch, ttString = TextThreadString(thread) + S(FormatString(L" (%s)", threadCode))]
@ -290,7 +291,7 @@ std::optional<std::wstring> MainWindow::UserSelectedProcess()
void MainWindow::AttachProcess()
{
QMultiHash<QString, DWORD> allProcesses;
for (auto [processId, processName] : Util::GetAllProcesses())
for (auto [processId, processName] : GetAllProcesses())
if (processName && (showSystemProcesses || processName->find(L":\\Windows\\") == std::wstring::npos))
allProcesses.insert(QFileInfo(S(processName.value())).fileName(), processId);
@ -348,7 +349,7 @@ void MainWindow::DetachProcess()
void MainWindow::ForgetProcess()
{
std::optional<std::wstring> processName = Util::GetModuleFilename(GetSelectedProcessId());
std::optional<std::wstring> processName = GetModuleFilename(GetSelectedProcessId());
if (!processName) processName = UserSelectedProcess();
DetachProcess();
if (!processName) return;
@ -369,7 +370,7 @@ void MainWindow::AddHook(QString hook)
{
if (QString hookCode = QInputDialog::getText(this, ADD_HOOK, CODE_INFODUMP, QLineEdit::Normal, hook, &ok, Qt::WindowCloseButtonHint); ok)
if (hookCode.startsWith("S") || hookCode.startsWith("/S")) FindHooks();
else if (auto hp = Util::ParseCode(S(hookCode))) try { Host::InsertHook(GetSelectedProcessId(), hp.value()); } catch (std::out_of_range) {}
else if (auto hp = HookCode::Parse(S(hookCode))) try { Host::InsertHook(GetSelectedProcessId(), hp.value()); } catch (std::out_of_range) {}
else Host::AddConsoleOutput(INVALID_CODE);
}
@ -403,7 +404,7 @@ void MainWindow::RemoveHooks()
void MainWindow::SaveHooks()
{
auto processName = Util::GetModuleFilename(GetSelectedProcessId());
auto processName = GetModuleFilename(GetSelectedProcessId());
if (!processName) return;
QHash<uint64_t, QString> hookCodes;
for (int i = 0; i < ui->ttCombo->count(); ++i)
@ -412,12 +413,12 @@ void MainWindow::SaveHooks()
if (tp.processId == GetSelectedProcessId())
{
HookParam hp = Host::GetThread(tp).hp;
if (!(hp.type & HOOK_ENGINE)) hookCodes[tp.addr] = S(Util::GenerateCode(hp, tp.processId));
if (!(hp.type & HOOK_ENGINE)) hookCodes[tp.addr] = S(HookCode::Generate(hp, tp.processId));
}
}
auto hookInfo = QStringList() << S(processName.value()) << hookCodes.values();
ThreadParam tp = current->tp;
if (tp.processId == GetSelectedProcessId()) hookInfo << QString("|%1:%2:%3").arg(tp.ctx).arg(tp.ctx2).arg(S(Util::GenerateCode(current->hp, tp.processId)));
if (tp.processId == GetSelectedProcessId()) hookInfo << QString("|%1:%2:%3").arg(tp.ctx).arg(tp.ctx2).arg(S(HookCode::Generate(current->hp, tp.processId)));
QTextFile(HOOK_SAVE_FILE, QIODevice::WriteOnly | QIODevice::Append).write((hookInfo.join(" , ") + "\n").toUtf8());
}
@ -489,7 +490,7 @@ void MainWindow::FindHooks()
layout.addRow(label, spinBox);
connect(spinBox, qOverload<int>(&QSpinBox::valueChanged), [&value](int newValue) { value = newValue; });
}
QLineEdit boundInput(QFileInfo(S(Util::GetModuleFilename(GetSelectedProcessId()).value_or(L""))).fileName(), &dialog);
QLineEdit boundInput(QFileInfo(S(GetModuleFilename(GetSelectedProcessId()).value_or(L""))).fileName(), &dialog);
layout.addRow(SEARCH_MODULE, &boundInput);
for (auto [value, label] : Array<uintptr_t&, const char*>{
{ sp.minAddress, MIN_ADDRESS },
@ -530,7 +531,7 @@ void MainWindow::FindHooks()
try
{
Host::FindHooks(processId, sp,
[hooks, filter](HookParam hp, std::wstring text) { if (std::regex_search(text, filter)) *hooks << sanitize(S(Util::GenerateCode(hp) + L" => " + text)); });
[hooks, filter](HookParam hp, std::wstring text) { if (std::regex_search(text, filter)) *hooks << sanitize(S(HookCode::Generate(hp) + L" => " + text)); });
}
catch (std::out_of_range) { return; }
std::thread([this, hooks]

View File

@ -2,7 +2,6 @@
#include "extension.h"
#include "ui_extrawindow.h"
#include "defs.h"
#include "util.h"
#include "blockmarkup.h"
#include <fstream>
#include <process.h>

View File

@ -1,6 +1,5 @@
#include "extension.h"
#include "network.h"
#include "util.h"
#include <ctime>
#include <QStringList>

View File

@ -1,6 +1,5 @@
#include "qtcommon.h"
#include "extension.h"
#include "util.h"
#include <fstream>
#include <QPlainTextEdit>

View File

@ -1,5 +1,4 @@
#include "network.h"
#include "util.h"
HttpRequest::HttpRequest(
const wchar_t* agentName,

View File

@ -2,34 +2,34 @@
std::vector<int> GenerateSuffixArray(const std::wstring& text)
{
std::vector<int> identity(text.size());
for (int i = 0; i < text.size(); ++i) identity[i] = i;
std::vector<int> suffixArray = identity;
std::vector<int> suffixArray(text.size());
for (int i = 0; i < text.size(); ++i) suffixArray[i] = i;
// The below code is a more efficient way of doing this:
// std::sort(suffixArray.begin(), suffixArray.end(), [&](int a, int b) { return wcscmp(text.c_str() + a, text.c_str() + b) > 0; });
std::stable_sort(suffixArray.begin(), suffixArray.end(), [&](int a, int b) { return text[a] > text[b]; });
std::vector<int> classes(text.begin(), text.end());
std::vector<int> eqClasses(text.begin(), text.end());
std::vector<int> count(text.size());
for (int length = 1; length < text.size(); length *= 2)
{
// Determine equivalence class up to length, by checking length / 2 equivalence of suffixes and their following length / 2 suffixes
std::vector<int> oldClasses = classes;
classes[suffixArray[0]] = 0;
std::vector<int> prevEqClasses = eqClasses;
eqClasses[suffixArray[0]] = 0;
for (int i = 1; i < text.size(); ++i)
{
int currentSuffix = suffixArray[i];
int lastSuffix = suffixArray[i - 1];
if (currentSuffix + length < text.size() && oldClasses[currentSuffix] == oldClasses[lastSuffix] &&
oldClasses[currentSuffix + length / 2] == oldClasses.at(lastSuffix + length / 2)) // not completely certain that this will stay in range
classes[currentSuffix] = classes[lastSuffix];
else classes[currentSuffix] = i;
if (currentSuffix + length < text.size() && prevEqClasses[currentSuffix] == prevEqClasses[lastSuffix] &&
prevEqClasses[currentSuffix + length / 2] == prevEqClasses.at(lastSuffix + length / 2)) // not completely certain that this will stay in range
eqClasses[currentSuffix] = eqClasses[lastSuffix];
else eqClasses[currentSuffix] = i;
}
// Sort within equivalence class based on order of following suffix after length (orders up to length * 2)
std::vector<int> count = identity;
for (int i = 0; i < text.size(); ++i) count[i] = i;
for (auto suffix : std::vector(suffixArray))
{
int precedingSuffix = suffix - length;
if (precedingSuffix >= 0) suffixArray[count[classes[precedingSuffix]]++] = precedingSuffix;
if (precedingSuffix >= 0) suffixArray[count[eqClasses[precedingSuffix]]++] = precedingSuffix;
}
}
for (int i = 0; i + 1 < text.size(); ++i)

View File

@ -1,7 +1,6 @@
#include "qtcommon.h"
#include "extension.h"
#include "defs.h"
#include "util.h"
#include "blockmarkup.h"
#include "network.h"
#include <map>

View File

@ -1,17 +0,0 @@
#pragma once
#include "common.h"
inline std::wstring StringToWideString(const std::string& text)
{
std::vector<wchar_t> buffer(text.size() + 1);
MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, buffer.data(), buffer.size());
return buffer.data();
}
inline std::string WideStringToString(const std::wstring& text)
{
std::vector<char> buffer((text.size() + 1) * 4);
WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, buffer.data(), buffer.size(), nullptr, nullptr);
return buffer.data();
}

View File

@ -114,6 +114,28 @@ inline std::wstring FormatString(const wchar_t* format, const Args&... args)
}
#pragma warning(pop)
inline std::optional<std::wstring> StringToWideString(const std::string& text, UINT encoding)
{
std::vector<wchar_t> buffer(text.size() + 1);
if (int length = MultiByteToWideChar(encoding, 0, text.c_str(), text.size() + 1, buffer.data(), buffer.size()))
return std::wstring(buffer.data(), length - 1);
return {};
}
inline std::wstring StringToWideString(const std::string& text)
{
std::vector<wchar_t> buffer(text.size() + 1);
MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, buffer.data(), buffer.size());
return buffer.data();
}
inline std::string WideStringToString(const std::wstring& text)
{
std::vector<char> buffer((text.size() + 1) * 4);
WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, buffer.data(), buffer.size(), nullptr, nullptr);
return buffer.data();
}
template <typename... Args>
inline void TEXTRACTOR_MESSAGE(const wchar_t* format, const Args&... args) { MessageBoxW(NULL, FormatString(format, args...).c_str(), L"Textractor", MB_OK); }

27
include/module.h Normal file
View File

@ -0,0 +1,27 @@
#include "common.h"
#include <Psapi.h>
inline std::optional<std::wstring> GetModuleFilename(DWORD processId, HMODULE module = NULL)
{
std::vector<wchar_t> buffer(MAX_PATH);
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))
if (GetModuleFileNameExW(process, module, buffer.data(), MAX_PATH)) return buffer.data();
return {};
}
inline std::optional<std::wstring> GetModuleFilename(HMODULE module = NULL)
{
std::vector<wchar_t> buffer(MAX_PATH);
if (GetModuleFileNameW(module, buffer.data(), MAX_PATH)) return buffer.data();
return {};
}
inline std::vector<std::pair<DWORD, std::optional<std::wstring>>> GetAllProcesses()
{
std::vector<DWORD> processIds(10000);
DWORD spaceUsed = 0;
EnumProcesses(processIds.data(), 10000 * sizeof(DWORD), &spaceUsed);
std::vector<std::pair<DWORD, std::optional<std::wstring>>> processes;
for (int i = 0; i < spaceUsed / sizeof(DWORD); ++i) processes.push_back({ processIds[i], GetModuleFilename(processIds[i]) });
return processes;
}