move utility functions into common.h and module.h
This commit is contained in:
parent
200c01f4ab
commit
16540bfe69
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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
10
GUI/host/hookcode.h
Normal 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);
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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));
|
||||||
|
@ -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]
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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();
|
|
||||||
}
|
|
@ -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
27
include/module.h
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user