use a default searchparam unless user specifies they want custom settings

This commit is contained in:
Akash Mozumdar 2019-06-16 15:28:59 -04:00
parent ef90382bbb
commit 88b797cd33
10 changed files with 174 additions and 141 deletions

View File

@ -105,7 +105,7 @@ namespace
auto& OnHookFound = processRecordsByIds->at(processId).OnHookFound; auto& OnHookFound = processRecordsByIds->at(processId).OnHookFound;
std::wstring wide = info.text; std::wstring wide = info.text;
if (wide.size() > STRING) OnHookFound(info.hp, info.text); if (wide.size() > STRING) OnHookFound(info.hp, info.text);
info.hp.type = USING_STRING; info.hp.type &= ~USING_UNICODE;
if (auto converted = Util::StringToWideString((char*)info.text, Host::defaultCodepage)) if (auto converted = Util::StringToWideString((char*)info.text, Host::defaultCodepage))
if (converted->size() > STRING) OnHookFound(info.hp, converted.value()); if (converted->size() > STRING) OnHookFound(info.hp, converted.value());
info.hp.codepage = CP_UTF8; info.hp.codepage = CP_UTF8;

View File

@ -11,6 +11,7 @@
#include <QCheckBox> #include <QCheckBox>
#include <QSpinBox> #include <QSpinBox>
#include <QListWidget> #include <QListWidget>
#include <QDialogButtonBox>
#include <QMessageBox> #include <QMessageBox>
#include <QInputDialog> #include <QInputDialog>
#include <QFileDialog> #include <QFileDialog>
@ -21,7 +22,7 @@ extern const char* DETACH;
extern const char* ADD_HOOK; extern const char* ADD_HOOK;
extern const char* REMOVE_HOOKS; extern const char* REMOVE_HOOKS;
extern const char* SAVE_HOOKS; extern const char* SAVE_HOOKS;
extern const char* FIND_HOOKS; extern const char* SEARCH_FOR_HOOKS;
extern const char* SETTINGS; extern const char* SETTINGS;
extern const char* EXTENSIONS; extern const char* EXTENSIONS;
extern const char* SELECT_PROCESS; extern const char* SELECT_PROCESS;
@ -30,6 +31,7 @@ extern const char* SEARCH_GAME;
extern const char* PROCESSES; extern const char* PROCESSES;
extern const char* CODE_INFODUMP; extern const char* CODE_INFODUMP;
extern const char* HOOK_SEARCH_UNSTABLE_WARNING; extern const char* HOOK_SEARCH_UNSTABLE_WARNING;
extern const char* SEARCH_CJK;
extern const char* SEARCH_PATTERN; extern const char* SEARCH_PATTERN;
extern const char* SEARCH_DURATION; extern const char* SEARCH_DURATION;
extern const char* PATTERN_OFFSET; extern const char* PATTERN_OFFSET;
@ -59,14 +61,14 @@ MainWindow::MainWindow(QWidget *parent) :
extenWindow(new ExtenWindow(this)) extenWindow(new ExtenWindow(this))
{ {
ui->setupUi(this); ui->setupUi(this);
for (auto[text, slot] : Array<std::tuple<QString, void(MainWindow::*)()>>{ for (auto [text, slot] : Array<std::tuple<QString, void(MainWindow::*)()>>{
{ ATTACH, &MainWindow::AttachProcess }, { ATTACH, &MainWindow::AttachProcess },
{ LAUNCH, &MainWindow::LaunchProcess }, { LAUNCH, &MainWindow::LaunchProcess },
{ DETACH, &MainWindow::DetachProcess }, { DETACH, &MainWindow::DetachProcess },
{ ADD_HOOK, &MainWindow::AddHook }, { ADD_HOOK, &MainWindow::AddHook },
{ REMOVE_HOOKS, &MainWindow::RemoveHooks }, { REMOVE_HOOKS, &MainWindow::RemoveHooks },
{ SAVE_HOOKS, &MainWindow::SaveHooks }, { SAVE_HOOKS, &MainWindow::SaveHooks },
{ FIND_HOOKS, &MainWindow::FindHooks }, { SEARCH_FOR_HOOKS, &MainWindow::FindHooks },
{ SETTINGS, &MainWindow::Settings }, { SETTINGS, &MainWindow::Settings },
{ EXTENSIONS, &MainWindow::Extensions } { EXTENSIONS, &MainWindow::Extensions }
}) })
@ -325,9 +327,10 @@ void MainWindow::RemoveHooks()
} }
auto hookList = new QListWidget(this); auto hookList = new QListWidget(this);
hookList->setWindowFlags(Qt::Window | Qt::WindowCloseButtonHint); hookList->setWindowFlags(Qt::Window | Qt::WindowCloseButtonHint);
hookList->setAttribute(Qt::WA_DeleteOnClose);
hookList->setMinimumSize({ 300, 50 }); hookList->setMinimumSize({ 300, 50 });
hookList->setWindowTitle(DOUBLE_CLICK_TO_REMOVE_HOOK); hookList->setWindowTitle(DOUBLE_CLICK_TO_REMOVE_HOOK);
for (auto[address, hp] : hooks) for (auto [address, hp] : hooks)
new QListWidgetItem(QString(hp.name) + "@" + QString::number(address, 16), hookList); new QListWidgetItem(QString(hp.name) + "@" + QString::number(address, 16), hookList);
connect(hookList, &QListWidget::itemDoubleClicked, [processId, hookList](QListWidgetItem* item) connect(hookList, &QListWidget::itemDoubleClicked, [processId, hookList](QListWidgetItem* item)
{ {
@ -364,120 +367,123 @@ void MainWindow::SaveHooks()
void MainWindow::FindHooks() void MainWindow::FindHooks()
{ {
QMessageBox::information(this, FIND_HOOKS, HOOK_SEARCH_UNSTABLE_WARNING); QMessageBox::information(this, SEARCH_FOR_HOOKS, HOOK_SEARCH_UNSTABLE_WARNING);
struct : QDialog
{
using QDialog::QDialog;
void launch()
{
auto layout = new QFormLayout(this);
auto patternInput = new QLineEdit(x64 ? "CC CC 48 89" : "CC CC 55 8B EC", this);
layout->addRow(SEARCH_PATTERN, patternInput);
for (auto[value, label] : Array<std::tuple<int&, const char*>>{
{ sp.searchTime = 20000, SEARCH_DURATION },
{ sp.offset = 2, PATTERN_OFFSET },
})
{
auto spinBox = new QSpinBox(this);
spinBox->setMaximum(INT_MAX);
spinBox->setValue(value);
layout->addRow(label, spinBox);
connect(spinBox, qOverload<int>(&QSpinBox::valueChanged), [=, &value] { value = spinBox->value(); });
}
for (auto[value, label] : Array<std::tuple<uintptr_t&, const char*>>{
{ sp.minAddress = 0, MIN_ADDRESS },
{ sp.maxAddress = -1ULL, MAX_ADDRESS },
{ sp.padding = 0, STRING_OFFSET }
})
{
auto input = new QLineEdit(QString::number(value, 16), this);
layout->addRow(label, input);
connect(input, &QLineEdit::textEdited, [&value](QString input)
{
bool ok;
if (uintptr_t newValue = input.toULongLong(&ok, 16); ok) value = newValue;
});
}
auto filterInput = new QLineEdit(this);
layout->addRow(HOOK_SEARCH_FILTER, filterInput);
auto save = new QPushButton(START_HOOK_SEARCH, this);
layout->addWidget(save);
connect(save, &QPushButton::clicked, this, &QDialog::accept);
connect(save, &QPushButton::clicked, [this, patternInput, filterInput]
{
QByteArray pattern = QByteArray::fromHex(patternInput->text().replace("??", QString::number(XX, 16)).toUtf8());
if (pattern.size() < 3) return;
std::wregex filter(L".");
if (!filterInput->text().isEmpty()) try { filter = std::wregex(S(filterInput->text())); } catch (std::regex_error) {};
memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), 25));
auto hooks = std::make_shared<QString>();
DWORD processId = this->processId;
try
{
Host::FindHooks(processId, sp, [processId, hooks, filter](HookParam hp, const std::wstring& text)
{
if (std::regex_search(text, filter)) hooks->append(S(Util::GenerateCode(hp, processId)) + ": " + S(text) + "\n");
});
}
catch (std::out_of_range) { return; }
QString fileName = QFileDialog::getSaveFileName(this, SAVE_SEARCH_RESULTS, "./Hooks.txt", TEXT_FILES);
if (fileName.isEmpty()) fileName = "Hooks.txt";
std::thread([hooks, fileName]
{
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size();
QTextFile(fileName, QIODevice::WriteOnly | QIODevice::Truncate).write(hooks->toUtf8());
hooks->clear();
}).detach();
});
setWindowTitle(FIND_HOOKS);
exec();
}
SearchParam sp = {}; DWORD processId = GetSelectedProcessId();
DWORD processId; SearchParam sp = {};
} searchDialog(this, Qt::WindowCloseButtonHint); bool customSettings = false;
searchDialog.processId = GetSelectedProcessId(); std::wregex filter(L".");
searchDialog.launch();
QDialog dialog(this, Qt::WindowCloseButtonHint);
QFormLayout layout(&dialog);
QCheckBox cjkCheckbox(&dialog);
layout.addRow(SEARCH_CJK, &cjkCheckbox);
QDialogButtonBox confirm(QDialogButtonBox::Ok | QDialogButtonBox::Help, &dialog);
layout.addRow(&confirm);
confirm.button(QDialogButtonBox::Ok)->setText(START_HOOK_SEARCH);
confirm.button(QDialogButtonBox::Help)->setText(SETTINGS);
connect(&confirm, &QDialogButtonBox::helpRequested, [&customSettings] { customSettings = true; });
connect(&confirm, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(&confirm, &QDialogButtonBox::helpRequested, &dialog, &QDialog::accept);
dialog.setWindowTitle(SEARCH_FOR_HOOKS);
if (dialog.exec() == QDialog::Rejected) return;
if (customSettings)
{
QDialog dialog(this, Qt::WindowCloseButtonHint);
QFormLayout layout(&dialog);
QLineEdit patternInput(x64 ? "CC CC 48 89" : "CC CC 55 8B EC", &dialog);
layout.addRow(SEARCH_PATTERN, &patternInput);
for (auto [value, label] : Array<std::tuple<int&, const char*>>{
{ sp.searchTime = 20000, SEARCH_DURATION },
{ sp.offset = 2, PATTERN_OFFSET },
})
{
auto spinBox = new QSpinBox(&dialog);
spinBox->setMaximum(INT_MAX);
spinBox->setValue(value);
layout.addRow(label, spinBox);
connect(spinBox, qOverload<int>(&QSpinBox::valueChanged), [&value] (int newValue) { value = newValue; });
}
for (auto [value, label] : Array<std::tuple<uintptr_t&, const char*>>{
{ sp.minAddress = 0, MIN_ADDRESS },
{ sp.maxAddress = -1ULL, MAX_ADDRESS },
{ sp.padding = 0, STRING_OFFSET }
})
{
auto input = new QLineEdit(QString::number(value, 16), &dialog);
layout.addRow(label, input);
connect(input, &QLineEdit::textEdited, [&value](QString input)
{
bool ok;
if (uintptr_t newValue = input.toULongLong(&ok, 16); ok) value = newValue;
});
}
QLineEdit filterInput(".", &dialog);
layout.addRow(HOOK_SEARCH_FILTER, &filterInput);
QPushButton startButton(START_HOOK_SEARCH, &dialog);
layout.addWidget(&startButton);
connect(&startButton, &QPushButton::clicked, &dialog, &QDialog::accept);
if (dialog.exec() == QDialog::Rejected) return;
QByteArray pattern = QByteArray::fromHex(patternInput.text().replace("??", QString::number(XX, 16)).toUtf8());
memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), 25));
try { filter = std::wregex(S(filterInput.text())); } catch (std::regex_error) {};
}
else
{
// sp.length is 0 in this branch, so default will be used
filter = cjkCheckbox.isChecked() ? std::wregex(L"[\\u3000-\\ua000]{4,}") : std::wregex(L"[\\u0020-\\u1000]{4,}");
}
auto hooks = std::make_shared<QString>();
try
{
Host::FindHooks(processId, sp, [processId, hooks, filter](HookParam hp, const std::wstring& text)
{
if (std::regex_search(text, filter)) hooks->append(S(Util::GenerateCode(hp, processId)) + ": " + S(text) + "\n");
});
} catch (std::out_of_range) { return; }
QString saveFile = QFileDialog::getSaveFileName(this, SAVE_SEARCH_RESULTS, "./Hooks.txt", TEXT_FILES);
if (saveFile.isEmpty()) saveFile = "Hooks.txt";
std::thread([hooks, saveFile]
{
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size();
QTextFile(saveFile, QIODevice::WriteOnly | QIODevice::Truncate).write(hooks->toUtf8());
hooks->clear();
}).detach();
} }
void MainWindow::Settings() void MainWindow::Settings()
{ {
struct : QDialog QDialog dialog(this, Qt::WindowCloseButtonHint);
QSettings settings(CONFIG_FILE, QSettings::IniFormat, &dialog);
QFormLayout layout(&dialog);
QPushButton saveButton(SAVE_SETTINGS, &dialog);
layout.addWidget(&saveButton);
for (auto [value, label] : Array<std::tuple<int&, const char*>>{
{ Host::defaultCodepage, DEFAULT_CODEPAGE },
{ TextThread::maxBufferSize, MAX_BUFFER_SIZE },
{ TextThread::flushDelay, FLUSH_DELAY },
})
{ {
using QDialog::QDialog; auto spinBox = new QSpinBox(&dialog);
void launch() spinBox->setMaximum(INT_MAX);
{ spinBox->setValue(value);
auto settings = new QSettings(CONFIG_FILE, QSettings::IniFormat, this); layout.insertRow(0, label, spinBox);
auto layout = new QFormLayout(this); connect(&saveButton, &QPushButton::clicked, [spinBox, label, &settings, &value] { settings.setValue(label, value = spinBox->value()); });
auto save = new QPushButton(SAVE_SETTINGS, this); }
layout->addWidget(save); for (auto [value, label] : Array<std::tuple<bool&, const char*>>{
for (auto[value, label] : Array<std::tuple<int&, const char*>>{ { TextThread::filterRepetition, FILTER_REPETITION },
{ Host::defaultCodepage, DEFAULT_CODEPAGE }, })
{ TextThread::maxBufferSize, MAX_BUFFER_SIZE }, {
{ TextThread::flushDelay, FLUSH_DELAY }, auto checkBox = new QCheckBox(&dialog);
}) checkBox->setChecked(value);
{ layout.insertRow(0, label, checkBox);
auto spinBox = new QSpinBox(this); connect(&saveButton, &QPushButton::clicked, [checkBox, label, &settings, &value] { settings.setValue(label, value = checkBox->isChecked()); });
spinBox->setMaximum(INT_MAX); }
spinBox->setValue(value); connect(&saveButton, &QPushButton::clicked, &dialog, &QDialog::accept);
layout->insertRow(0, label, spinBox); dialog.setWindowTitle(SETTINGS);
connect(save, &QPushButton::clicked, [=, &value] { settings->setValue(label, value = spinBox->value()); }); dialog.exec();
}
for (auto[value, label] : Array<std::tuple<bool&, const char*>>{
{ TextThread::filterRepetition, FILTER_REPETITION },
})
{
auto checkBox = new QCheckBox(this);
checkBox->setChecked(value);
layout->insertRow(0, label, checkBox);
connect(save, &QPushButton::clicked, [=, &value] { settings->setValue(label, value = checkBox->isChecked()); });
}
connect(save, &QPushButton::clicked, this, &QDialog::accept);
setWindowTitle(SETTINGS);
exec();
}
} settingsDialog(this, Qt::WindowCloseButtonHint);
settingsDialog.launch();
} }
void MainWindow::Extensions() void MainWindow::Extensions()

View File

@ -61,11 +61,12 @@ struct ThreadParam
struct SearchParam struct SearchParam
{ {
BYTE pattern[25] = {}; // pattern in memory to search for BYTE pattern[25]; // pattern in memory to search for
int length, // length of pattern int length, // length of pattern (zero means this SearchParam is invalid and the default should be used)
offset, // offset from start of pattern to add hook offset, // offset from start of pattern to add hook
searchTime; // ms searchTime; // ms
uintptr_t padding, minAddress, maxAddress; uintptr_t padding, minAddress, maxAddress;
void(*hookPostProcesser)(HookParam&);
}; };
struct InsertHookCmd // From host struct InsertHookCmd // From host

View File

@ -12,7 +12,7 @@ const char* DETACH = u8"Detach from game";
const char* ADD_HOOK = u8"Add hook"; const char* ADD_HOOK = u8"Add hook";
const char* REMOVE_HOOKS = u8"Remove hook(s)"; const char* REMOVE_HOOKS = u8"Remove hook(s)";
const char* SAVE_HOOKS = u8"Save hook(s)"; const char* SAVE_HOOKS = u8"Save hook(s)";
const char* FIND_HOOKS = u8"Find hooks"; const char* SEARCH_FOR_HOOKS = u8"Search for hooks";
const char* SETTINGS = u8"Settings"; const char* SETTINGS = u8"Settings";
const char* EXTENSIONS = u8"Extensions"; const char* EXTENSIONS = u8"Extensions";
const char* SELECT_PROCESS = u8"Select process"; const char* SELECT_PROCESS = u8"Select process";
@ -51,6 +51,7 @@ const char* CONFIRM_EXTENSION_OVERWRITE = u8"Another version of this extension a
const char* EXTENSION_WRITE_ERROR = u8"Failed to save extension"; const char* EXTENSION_WRITE_ERROR = u8"Failed to save extension";
const char* USE_JP_LOCALE = u8"Emulate japanese locale?"; const char* USE_JP_LOCALE = u8"Emulate japanese locale?";
const char* HOOK_SEARCH_UNSTABLE_WARNING = u8"Searching for hooks is unstable! Be prepared for your game to crash!"; const char* HOOK_SEARCH_UNSTABLE_WARNING = u8"Searching for hooks is unstable! Be prepared for your game to crash!";
const char* SEARCH_CJK = u8"Search for Chinese/Japanese/Korean";
const char* SEARCH_PATTERN = u8"Search pattern (hex byte array)"; const char* SEARCH_PATTERN = u8"Search pattern (hex byte array)";
const char* SEARCH_DURATION = u8"Search duration (ms)"; const char* SEARCH_DURATION = u8"Search duration (ms)";
const char* PATTERN_OFFSET = u8"Offset from pattern start"; const char* PATTERN_OFFSET = u8"Offset from pattern start";

View File

@ -16818,7 +16818,7 @@ bool InsertVanillawareGCHook()
/** Artikash 6/7/2019 /** Artikash 6/7/2019
* PPSSPP JIT code has pointers, but they are all added to an offset before being used. * PPSSPP JIT code has pointers, but they are all added to an offset before being used.
Find that offset and report it to user so they can search for hooks properly. Find that offset so that hook searching works properly.
To find the offset, find a page of mapped memory with size 0x1f00000, read and write permissions, take its address and subtract 0x8000000. To find the offset, find a page of mapped memory with size 0x1f00000, read and write permissions, take its address and subtract 0x8000000.
The above is useful for emulating PSP hardware, so unlikely to change between versions. The above is useful for emulating PSP hardware, so unlikely to change between versions.
*/ */
@ -16839,7 +16839,13 @@ bool FindPPSSPP()
if (info.RegionSize == 0x1f00000 && info.Protect == PAGE_READWRITE && info.Type == MEM_MAPPED) if (info.RegionSize == 0x1f00000 && info.Protect == PAGE_READWRITE && info.Type == MEM_MAPPED)
{ {
found = true; found = true;
ConsoleOutput("Textractor: PPSSPP memory found: use pattern 79 0F C7 85 and pattern offset 0 and string offset 0x%p to search for hooks", probe - 0x8000000); ConsoleOutput("Textractor: PPSSPP memory found: searching for hooks should yield working hook codes");
memcpy(spDefault.pattern, Array<BYTE>{ 0x79, 0x0f, 0xc7, 0x85 }, spDefault.length = 4);
spDefault.offset = 0;
spDefault.minAddress = 0;
spDefault.maxAddress = -1ULL;
spDefault.padding = (uintptr_t)probe - 0x8000000;
spDefault.hookPostProcesser = [](HookParam& hp) { hp.type |= NO_CONTEXT; };
} }
probe += info.RegionSize; probe += info.RegionSize;
} }

View File

@ -37,22 +37,25 @@ namespace Engine
void Hijack() void Hijack()
{ {
static bool hijacked = false; static auto _ = []
if (hijacked) return;
GetModuleFileNameW(nullptr, processPath, MAX_PATH);
processName = wcsrchr(processPath, L'\\') + 1;
processStartAddress = processStopAddress = (uintptr_t)GetModuleHandleW(nullptr);
MEMORY_BASIC_INFORMATION info;
do
{ {
VirtualQuery((void*)processStopAddress, &info, sizeof(info)); GetModuleFileNameW(nullptr, processPath, MAX_PATH);
processStopAddress = (uintptr_t)info.BaseAddress + info.RegionSize; processName = wcsrchr(processPath, L'\\') + 1;
} while (info.Protect > PAGE_NOACCESS);
processStopAddress -= info.RegionSize;
DetermineEngineType(); processStartAddress = processStopAddress = (uintptr_t)GetModuleHandleW(nullptr);
hijacked = true; MEMORY_BASIC_INFORMATION info;
ConsoleOutput("Textractor: finished hijacking process located from 0x%p to 0x%p", processStartAddress, processStopAddress); do
{
VirtualQuery((void*)processStopAddress, &info, sizeof(info));
processStopAddress = (uintptr_t)info.BaseAddress + info.RegionSize;
} while (info.Protect > PAGE_NOACCESS);
processStopAddress -= info.RegionSize;
spDefault.minAddress = processStartAddress;
spDefault.maxAddress = processStopAddress;
ConsoleOutput("Textractor: hijacking process located from 0x%p to 0x%p", processStartAddress, processStopAddress);
DetermineEngineType();
return NULL;
}();
} }
} }

View File

@ -8,7 +8,7 @@ namespace Engine
{ {
/** Artikash 6/7/2019 /** Artikash 6/7/2019
* PPSSPP JIT code has pointers, but they are all added to an offset before being used. * PPSSPP JIT code has pointers, but they are all added to an offset before being used.
Find that offset and report it to user so they can search for hooks properly. Find that offset so that hook searching works properly.
To find the offset, find a page of mapped memory with size 0x1f00000, read and write permissions, take its address and subtract 0x8000000. To find the offset, find a page of mapped memory with size 0x1f00000, read and write permissions, take its address and subtract 0x8000000.
The above is useful for emulating PSP hardware, so unlikely to change between versions. The above is useful for emulating PSP hardware, so unlikely to change between versions.
*/ */
@ -29,7 +29,13 @@ namespace Engine
if (info.RegionSize == 0x1f00000 && info.Protect == PAGE_READWRITE && info.Type == MEM_MAPPED) if (info.RegionSize == 0x1f00000 && info.Protect == PAGE_READWRITE && info.Type == MEM_MAPPED)
{ {
found = true; found = true;
ConsoleOutput("Textractor: PPSSPP memory found: use pattern 79 10 41 C7 and pattern offset 0 and string offset 0x%p to search for hooks", probe - 0x8000000); ConsoleOutput("Textractor: PPSSPP memory found: searching for hooks should yield working hook codes");
memcpy(spDefault.pattern, Array<BYTE>{ 0x79, 0x10, 0x41, 0xc7 }, spDefault.length = 4);
spDefault.offset = 0;
spDefault.minAddress = 0;
spDefault.maxAddress = -1ULL;
spDefault.padding = (uintptr_t)probe - 0x8000000;
spDefault.hookPostProcesser = [](HookParam& hp) { hp.type |= NO_CONTEXT; };
} }
probe += info.RegionSize; probe += info.RegionSize;
} }

View File

@ -11,7 +11,7 @@ extern WinMutex viewMutex;
namespace namespace
{ {
SearchParam current; SearchParam sp;
constexpr int CACHE_SIZE = 500'000; constexpr int CACHE_SIZE = 500'000;
struct HookRecord struct HookRecord
@ -23,7 +23,8 @@ namespace
hp.offset = offset; hp.offset = offset;
hp.type = USING_UNICODE | USING_STRING; hp.type = USING_UNICODE | USING_STRING;
hp.address = address; hp.address = address;
hp.padding = current.padding; hp.padding = sp.padding;
if (sp.hookPostProcesser) sp.hookPostProcesser(hp);
NotifyHookFound(hp, (wchar_t*)text); NotifyHookFound(hp, (wchar_t*)text);
} }
uint64_t address = 0; uint64_t address = 0;
@ -118,7 +119,7 @@ void Send(char** stack, uintptr_t address)
for (int i = -registers; i < 6; ++i) for (int i = -registers; i < 6; ++i)
{ {
int length = 0, sum = 0; int length = 0, sum = 0;
char* str = stack[i] + current.padding; char* str = stack[i] + sp.padding;
__try { for (; (str[length] || str[length + 1]) && length < 500; length += 2) sum += str[length] + str[length + 1]; } __try { for (; (str[length] || str[length + 1]) && length < 500; length += 2) sum += str[length] + str[length + 1]; }
__except (EXCEPTION_EXECUTE_HANDLER) {} __except (EXCEPTION_EXECUTE_HANDLER) {}
if (length > STRING && length < 499) if (length > STRING && length < 499)
@ -152,7 +153,7 @@ void Send(char** stack, uintptr_t address)
} }
} }
void SearchForHooks(SearchParam sp) void SearchForHooks(SearchParam spUser)
{ {
std::thread([=] std::thread([=]
{ {
@ -162,7 +163,7 @@ void SearchForHooks(SearchParam sp)
try { records = std::make_unique<HookRecord[]>(recordsAvailable = CACHE_SIZE); } try { records = std::make_unique<HookRecord[]>(recordsAvailable = CACHE_SIZE); }
catch (std::bad_alloc) { return ConsoleOutput("Textractor: SearchForHooks ERROR (out of memory)"); } catch (std::bad_alloc) { return ConsoleOutput("Textractor: SearchForHooks ERROR (out of memory)"); }
current = sp; sp = spUser.length == 0 ? spDefault : spUser;
uintptr_t moduleStartAddress = (uintptr_t)GetModuleHandleW(ITH_DLL); uintptr_t moduleStartAddress = (uintptr_t)GetModuleHandleW(ITH_DLL);
uintptr_t moduleStopAddress = moduleStartAddress; uintptr_t moduleStopAddress = moduleStartAddress;

View File

@ -165,7 +165,7 @@ void NewHook(HookParam hp, LPCSTR lpname, DWORD flag)
WideCharToMultiByte(hp.codepage, 0, hp.text, MAX_MODULE_SIZE, codepageText, MAX_MODULE_SIZE * 4, nullptr, nullptr); WideCharToMultiByte(hp.codepage, 0, hp.text, MAX_MODULE_SIZE, codepageText, MAX_MODULE_SIZE * 4, nullptr, nullptr);
if (strlen(utf8Text) < 8 || strlen(codepageText) < 8 || wcslen(hp.text) < 4) return ConsoleOutput(NOT_ENOUGH_TEXT); if (strlen(utf8Text) < 8 || strlen(codepageText) < 8 || wcslen(hp.text) < 4) return ConsoleOutput(NOT_ENOUGH_TEXT);
ConsoleOutput(STARTING_SEARCH); ConsoleOutput(STARTING_SEARCH);
for (auto[addrs, type] : Array<std::tuple<std::vector<uint64_t>, HookParamType>>{ for (auto [addrs, type] : Array<std::tuple<std::vector<uint64_t>, HookParamType>>{
{ Util::SearchMemory(utf8Text, strlen(utf8Text), PAGE_READWRITE), USING_UTF8 }, { Util::SearchMemory(utf8Text, strlen(utf8Text), PAGE_READWRITE), USING_UTF8 },
{ Util::SearchMemory(codepageText, strlen(codepageText), PAGE_READWRITE), USING_STRING }, { Util::SearchMemory(codepageText, strlen(codepageText), PAGE_READWRITE), USING_STRING },
{ Util::SearchMemory(hp.text, wcslen(hp.text) * 2, PAGE_READWRITE), USING_UNICODE } { Util::SearchMemory(hp.text, wcslen(hp.text) * 2, PAGE_READWRITE), USING_UNICODE }

View File

@ -14,6 +14,15 @@ void NotifyHookRemove(uint64_t addr, LPCSTR name);
void NewHook(HookParam hp, LPCSTR name, DWORD flag = HOOK_ENGINE); void NewHook(HookParam hp, LPCSTR name, DWORD flag = HOOK_ENGINE);
void RemoveHook(uint64_t addr, int maxOffset = 9); void RemoveHook(uint64_t addr, int maxOffset = 9);
inline SearchParam spDefault = []
{
SearchParam sp = {};
memcpy(sp.pattern, x64 ? Array<BYTE>{ 0xcc, 0xcc, 0x48, 0x89 } : Array<BYTE>{ 0xcc, 0xcc, 0x55, 0x8b, 0xec }, sp.length = x64 ? 4 : 5);
sp.offset = 2;
sp.searchTime = 20000;
return sp;
}();
extern "C" // minhook library extern "C" // minhook library
{ {
enum MH_STATUS enum MH_STATUS