dialog for hook results and customize max result count

This commit is contained in:
Akash Mozumdar 2019-07-16 21:55:40 +05:30
parent f85e3a3841
commit b098a05a23
10 changed files with 54 additions and 40 deletions

View File

@ -33,6 +33,7 @@ extern const char* PATTERN_OFFSET;
extern const char* MIN_ADDRESS;
extern const char* MAX_ADDRESS;
extern const char* STRING_OFFSET;
extern const char* MAX_HOOK_SEARCH_RECORDS;
extern const char* HOOK_SEARCH_FILTER;
extern const char* START_HOOK_SEARCH;
extern const char* SAVE_SEARCH_RESULTS;
@ -429,22 +430,24 @@ void MainWindow::FindHooks()
QDialog dialog(this, Qt::WindowCloseButtonHint);
QFormLayout layout(&dialog);
QLineEdit patternInput(x64 ? "CC CC 48 89" : "CC CC 55 8B EC", &dialog);
assert(QByteArray::fromHex(patternInput.text().toUtf8()) == QByteArray((const char*)sp.pattern, sp.length));
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 },
{ sp.searchTime, SEARCH_DURATION },
{ sp.offset, PATTERN_OFFSET },
{ sp.maxRecords, MAX_HOOK_SEARCH_RECORDS },
})
{
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; });
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 }
{ sp.minAddress, MIN_ADDRESS },
{ sp.maxAddress, MAX_ADDRESS },
{ sp.padding, STRING_OFFSET },
})
{
auto input = new QLineEdit(QString::number(value, 16), &dialog);
@ -463,7 +466,7 @@ void MainWindow::FindHooks()
}
else
{
// sp.length is 0 in this branch, so default will be used
sp.length = 0; // use default
filter = std::wregex(cjkCheckbox.isChecked() ? L"[\\u3000-\\ua000]{4,}" : L"[\\u0020-\\u1000]{4,}");
}
@ -476,13 +479,25 @@ void MainWindow::FindHooks()
});
}
catch (std::out_of_range) { return; }
QString saveFile = QFileDialog::getSaveFileName(this, SAVE_SEARCH_RESULTS, "./Hooks.txt", TEXT_FILES);
QString saveFile = QFileDialog::getSaveFileName(this, SAVE_SEARCH_RESULTS, "./Hooks.txt", TEXT_FILES, nullptr, QFileDialog::DontConfirmOverwrite);
if (saveFile.isEmpty()) saveFile = "Hooks.txt";
std::thread([hooks, saveFile]
std::thread([this, 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());
DWORD64 cleanupTime = GetTickCount64() + 500'000;
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000))
if (GetTickCount64() > cleanupTime) return;
else lastSize = hooks->size();
QMetaObject::invokeMethod(this, [this, hooks, saveFile]
{
auto hookList = new QPlainTextEdit(*hooks, this);
hooks->clear();
hookList->setWindowFlags(Qt::Window | Qt::WindowCloseButtonHint);
hookList->setAttribute(Qt::WA_DeleteOnClose);
hookList->resize({ 750, 300 });
hookList->setWindowTitle(SEARCH_FOR_HOOKS);
hookList->show();
});
QTextFile(saveFile, QIODevice::WriteOnly | QIODevice::Truncate).write(hooks->toUtf8());
}).detach();
}

View File

@ -111,9 +111,3 @@ inline std::wstring FormatString(const wchar_t* format, const Args&... args)
#else
#define TEST(...)
#endif
#ifdef _DEBUG
#define TEST_SYNC(...) static auto _ = [] { __VA_ARGS__; return 0UL; }();
#else
#define TEST_SYNC(...)
#endif

View File

@ -62,12 +62,13 @@ struct ThreadParam
struct SearchParam
{
BYTE pattern[25]; // pattern in memory to search for
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
searchTime; // ms
uintptr_t padding, minAddress, maxAddress;
void(*hookPostProcesser)(HookParam&);
BYTE pattern[25] = { 0xcc, 0xcc, x64 ? 0x48 : 0x55, x64 ? 0x89 : 0x8b, 0xec }; // pattern in memory to search for
int length = x64 ? 4 : 5, // length of pattern (zero means this SearchParam is invalid and the default should be used)
offset = 2, // offset from start of pattern to add hook
searchTime = 20000, // ms
maxRecords = 100000;
uintptr_t padding = 0, minAddress = 0, maxAddress = (uintptr_t)-1;
void(*hookPostProcessor)(HookParam&) = nullptr;
};
struct InsertHookCmd // From host

View File

@ -1 +1,7 @@
include(QtUtils)
msvc_registry_search()
find_qt5(Core Widgets)
add_executable(Test WIN32 main.cpp resource.rc)
target_link_libraries(Test Qt5::Widgets)

View File

@ -4,16 +4,19 @@
#include <filesystem>
#include <fstream>
#include <sstream>
#include <QApplication>
wchar_t buffer[1000] = {};
std::array<int, 10> vars = {};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int _)
{
QApplication a(_ = 0, DUMMY);
static std::vector<AutoHandle<Functor<(void(__stdcall *)(void*))FreeLibrary>>> extensions;
for (auto file : std::filesystem::directory_iterator(std::filesystem::current_path()))
if (file.path().extension() == L".dll"
&& (std::stringstream() << std::ifstream(file.path(), std::ios::binary).rdbuf()).str().find("OnNewSentence") != std::string::npos)
LoadLibraryW(file.path().c_str());
extensions.emplace_back(LoadLibraryW(file.path().c_str()));
ShowWindow(CreateDialogParamW(hInstance, MAKEINTRESOURCEW(IDD_DIALOG1), NULL, [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> INT_PTR
{
@ -36,6 +39,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
GetWindowTextW((HWND)lParam, buffer, std::size(buffer));
try { vars.at(LOWORD(wParam) - IDC_EDIT1) = std::stoi(buffer); }
catch (...) {}
if (vars.at(1)) extensions.clear();
}
}
break;

View File

@ -57,6 +57,7 @@ const char* SEARCH_CJK = u8"Search for Chinese/Japanese/Korean";
const char* SEARCH_PATTERN = u8"Search pattern (hex byte array)";
const char* SEARCH_DURATION = u8"Search duration (ms)";
const char* PATTERN_OFFSET = u8"Offset from pattern start";
const char* MAX_HOOK_SEARCH_RECORDS = u8"Search result cap";
const char* MIN_ADDRESS = u8"Minimum address (hex)";
const char* MAX_ADDRESS = u8"Maximum address (hex)";
const char* STRING_OFFSET = u8"String offset (hex)";

View File

@ -16845,7 +16845,7 @@ bool FindPPSSPP()
spDefault.minAddress = 0;
spDefault.maxAddress = -1ULL;
spDefault.padding = (uintptr_t)probe - 0x8000000;
spDefault.hookPostProcesser = [](HookParam& hp) { hp.type |= NO_CONTEXT; };
spDefault.hookPostProcessor = [](HookParam& hp) { hp.type |= NO_CONTEXT; };
}
probe += info.RegionSize;
}

View File

@ -38,7 +38,7 @@ namespace Engine
spDefault.minAddress = 0;
spDefault.maxAddress = -1ULL;
spDefault.padding = (uintptr_t)probe - 0x8000000;
spDefault.hookPostProcesser = [](HookParam& hp) { hp.type |= NO_CONTEXT; };
spDefault.hookPostProcessor = [](HookParam& hp) { hp.type |= NO_CONTEXT; };
}
probe += info.RegionSize;
}

View File

@ -24,7 +24,7 @@ namespace
hp.type = USING_UNICODE | USING_STRING;
hp.address = address;
hp.padding = sp.padding;
if (sp.hookPostProcesser) sp.hookPostProcesser(hp);
if (sp.hookPostProcessor) sp.hookPostProcessor(hp);
NotifyHookFound(hp, (wchar_t*)text);
}
uint64_t address = 0;
@ -160,11 +160,11 @@ void SearchForHooks(SearchParam spUser)
static std::mutex m;
std::scoped_lock lock(m);
try { records = std::make_unique<HookRecord[]>(recordsAvailable = CACHE_SIZE); }
catch (std::bad_alloc) { return ConsoleOutput("Textractor: SearchForHooks ERROR (out of memory)"); }
sp = spUser.length == 0 ? spDefault : spUser;
try { records = std::make_unique<HookRecord[]>(recordsAvailable = sp.maxRecords); }
catch (std::bad_alloc) { return ConsoleOutput("Textractor: SearchForHooks ERROR (out of memory)"); }
uintptr_t moduleStartAddress = (uintptr_t)GetModuleHandleW(ITH_DLL);
uintptr_t moduleStopAddress = moduleStartAddress;
MEMORY_BASIC_INFORMATION info;
@ -201,6 +201,6 @@ void SearchForHooks(SearchParam spUser)
records.reset();
VirtualFree(trampolines, 0, MEM_RELEASE);
for (int i = 0; i < CACHE_SIZE; ++i) signatureCache[i] = sumCache[i] = 0;
ConsoleOutput(HOOK_SEARCH_FINISHED, CACHE_SIZE - recordsAvailable);
ConsoleOutput(HOOK_SEARCH_FINISHED, sp.maxRecords - recordsAvailable);
}).detach();
}

View File

@ -14,14 +14,7 @@ void NotifyHookRemove(uint64_t addr, LPCSTR name);
void NewHook(HookParam hp, LPCSTR name, DWORD flag = HOOK_ENGINE);
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;
}();
inline SearchParam spDefault;
extern "C" // minhook library
{