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/exception.cpp
host/host.cpp host/host.cpp
host/textthread.cpp host/textthread.cpp
host/util.cpp host/hookcode.cpp
Textractor.rc Textractor.rc
Textractor.ico Textractor.ico
) )

View File

@ -1,5 +1,5 @@
#include "host.h" #include "host.h"
#include "util.h" #include "hookcode.h"
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
#include <iostream> #include <iostream>
@ -12,7 +12,16 @@ int main()
fflush(stdout); fflush(stdout);
Host::Start([](auto) {}, [](auto) {}, [](auto&) {}, [](auto&) {}, [](TextThread& thread, std::wstring& output) 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); fflush(stdout);
return false; return false;
}); });
@ -24,7 +33,7 @@ int main()
if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0); if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0);
if (_wcsicmp(command, L"attach") == 0) Host::InjectProcess(processId); if (_wcsicmp(command, L"attach") == 0) Host::InjectProcess(processId);
else if (_wcsicmp(command, L"detach") == 0) Host::DetachProcess(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); else ExitProcess(0);
} }
ExitProcess(0); ExitProcess(0);

View File

@ -1,4 +1,5 @@
#include "util.h" #include "common.h"
#include "module.h"
#include <sstream> #include <sstream>
namespace namespace
@ -36,7 +37,7 @@ namespace
errorMsg << std::uppercase << std::hex << errorMsg << std::uppercase << std::hex <<
L"Error code: " << exception->ExceptionRecord->ExceptionCode << std::endl << L"Error code: " << exception->ExceptionRecord->ExceptionCode << std::endl <<
L"Error address: " << exception->ExceptionRecord->ExceptionAddress << 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; L"Additional info: " << info.AllocationBase << std::endl;
if (exception->ExceptionRecord->ExceptionCode == 0xE06D7363) if (exception->ExceptionRecord->ExceptionCode == 0xE06D7363)

View File

@ -1,5 +1,5 @@
#include "util.h" #include "hookcode.h"
#include <Psapi.h> #include "module.h"
namespace namespace
{ {
@ -250,7 +250,7 @@ namespace
if (processId && !(hp.type & MODULE_OFFSET)) if (processId && !(hp.type & MODULE_OFFSET))
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId)) 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 (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.type |= MODULE_OFFSET;
hp.address -= (uint64_t)info.AllocationBase; 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::optional<HookParam> Parse(std::wstring code)
{
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)
{ {
if (code[0] == L'/') code.erase(0, 1); // legacy/AGTH compatibility if (code[0] == L'/') code.erase(0, 1); // legacy/AGTH compatibility
if (code[0] == L'R') return ParseRCode(code.erase(0, 1)); if (code[0] == L'R') return ParseRCode(code.erase(0, 1));
@ -319,7 +275,7 @@ namespace Util
return {}; 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); 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 "host.h"
#include "defs.h" #include "defs.h"
#include "util.h" #include "hookcode.h"
#include "../texthook/texthook.h" #include "../texthook/texthook.h"
extern const wchar_t* ALREADY_INJECTED; extern const wchar_t* ALREADY_INJECTED;
@ -48,7 +48,7 @@ namespace
Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text) Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text)
{ {
Host::AddConsoleOutput(Util::GenerateCode(hp) + L": " + text); Host::AddConsoleOutput(HookCode::Generate(hp) + L": " + text);
}; };
private: private:
@ -107,9 +107,9 @@ namespace
std::wstring wide = info.text; std::wstring wide = info.text;
if (wide.size() > STRING) OnHookFound(info.hp, std::move(info.text)); if (wide.size() > STRING) OnHookFound(info.hp, std::move(info.text));
info.hp.type &= ~USING_UNICODE; 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 (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())); if (converted->size() > STRING) OnHookFound(info.hp, std::move(converted.value()));
} }
break; break;
@ -122,7 +122,7 @@ namespace
case HOST_NOTIFICATION_TEXT: case HOST_NOTIFICATION_TEXT:
{ {
auto info = *(ConsoleOutputNotif*)buffer; auto info = *(ConsoleOutputNotif*)buffer;
Host::AddConsoleOutput(Util::StringToWideString(info.message).value()); Host::AddConsoleOutput(StringToWideString(info.message));
} }
break; break;
default: 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 for (int retry = 0; !clipboardText && retry < 3; ++retry) // retry loop in case something else is using the clipboard
{ {
Sleep(10); 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; throw;
}).detach(); }).detach();

View File

@ -1,6 +1,5 @@
#include "textthread.h" #include "textthread.h"
#include "host.h" #include "host.h"
#include "util.h"
extern const wchar_t* INVALID_CODEPAGE; 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) : TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) :
handle(threadCounter++), handle(threadCounter++),
name(name.value_or(Util::StringToWideString(hp.name).value())), name(name.value_or(StringToWideString(hp.name))),
tp(tp), tp(tp),
hp(hp) 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))); 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 (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); else Host::AddConsoleOutput(INVALID_CODEPAGE);
if (hp.type & FULL_STRING) buffer.push_back(L'\n'); if (hp.type & FULL_STRING) buffer.push_back(L'\n');
lastPushTime = GetTickCount(); 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 "mainwindow.h"
#include "host/util.h" #include "module.h"
#include <winhttp.h> #include <winhttp.h>
#include <QApplication> #include <QApplication>
@ -24,7 +24,7 @@ int main(int argc, char *argv[])
} }
}).detach(); }).detach();
QDir::setCurrent(QFileInfo(S(Util::GetModuleFilename().value())).absolutePath()); QDir::setCurrent(QFileInfo(S(GetModuleFilename().value())).absolutePath());
QApplication app(argc, argv); QApplication app(argc, argv);
app.setFont(QFont("MS Shell Dlg 2", 10)); app.setFont(QFont("MS Shell Dlg 2", 10));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
#include "qtcommon.h" #include "qtcommon.h"
#include "extension.h" #include "extension.h"
#include "defs.h" #include "defs.h"
#include "util.h"
#include "blockmarkup.h" #include "blockmarkup.h"
#include "network.h" #include "network.h"
#include <map> #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) #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> 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); } 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;
}