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* MIN_ADDRESS;
extern const char* MAX_ADDRESS; extern const char* MAX_ADDRESS;
extern const char* STRING_OFFSET; extern const char* STRING_OFFSET;
extern const char* MAX_HOOK_SEARCH_RECORDS;
extern const char* HOOK_SEARCH_FILTER; extern const char* HOOK_SEARCH_FILTER;
extern const char* START_HOOK_SEARCH; extern const char* START_HOOK_SEARCH;
extern const char* SAVE_SEARCH_RESULTS; extern const char* SAVE_SEARCH_RESULTS;
@ -429,10 +430,12 @@ void MainWindow::FindHooks()
QDialog dialog(this, Qt::WindowCloseButtonHint); QDialog dialog(this, Qt::WindowCloseButtonHint);
QFormLayout layout(&dialog); QFormLayout layout(&dialog);
QLineEdit patternInput(x64 ? "CC CC 48 89" : "CC CC 55 8B EC", &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); layout.addRow(SEARCH_PATTERN, &patternInput);
for (auto [value, label] : Array<std::tuple<int&, const char*>>{ for (auto [value, label] : Array<std::tuple<int&, const char*>>{
{ sp.searchTime = 20000, SEARCH_DURATION }, { sp.searchTime, SEARCH_DURATION },
{ sp.offset = 2, PATTERN_OFFSET }, { sp.offset, PATTERN_OFFSET },
{ sp.maxRecords, MAX_HOOK_SEARCH_RECORDS },
}) })
{ {
auto spinBox = new QSpinBox(&dialog); auto spinBox = new QSpinBox(&dialog);
@ -442,9 +445,9 @@ void MainWindow::FindHooks()
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*>>{ for (auto [value, label] : Array<std::tuple<uintptr_t&, const char*>>{
{ sp.minAddress = 0, MIN_ADDRESS }, { sp.minAddress, MIN_ADDRESS },
{ sp.maxAddress = -1ULL, MAX_ADDRESS }, { sp.maxAddress, MAX_ADDRESS },
{ sp.padding = 0, STRING_OFFSET } { sp.padding, STRING_OFFSET },
}) })
{ {
auto input = new QLineEdit(QString::number(value, 16), &dialog); auto input = new QLineEdit(QString::number(value, 16), &dialog);
@ -463,7 +466,7 @@ void MainWindow::FindHooks()
} }
else 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,}"); 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; } 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"; 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(); DWORD64 cleanupTime = GetTickCount64() + 500'000;
QTextFile(saveFile, QIODevice::WriteOnly | QIODevice::Truncate).write(hooks->toUtf8()); 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(); 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(); }).detach();
} }

View File

@ -111,9 +111,3 @@ inline std::wstring FormatString(const wchar_t* format, const Args&... args)
#else #else
#define TEST(...) #define TEST(...)
#endif #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 struct SearchParam
{ {
BYTE pattern[25]; // pattern in memory to search for BYTE pattern[25] = { 0xcc, 0xcc, x64 ? 0x48 : 0x55, x64 ? 0x89 : 0x8b, 0xec }; // pattern in memory to search for
int length, // length of pattern (zero means this SearchParam is invalid and the default should be used) int length = x64 ? 4 : 5, // 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 = 2, // offset from start of pattern to add hook
searchTime; // ms searchTime = 20000, // ms
uintptr_t padding, minAddress, maxAddress; maxRecords = 100000;
void(*hookPostProcesser)(HookParam&); uintptr_t padding = 0, minAddress = 0, maxAddress = (uintptr_t)-1;
void(*hookPostProcessor)(HookParam&) = nullptr;
}; };
struct InsertHookCmd // From host 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) add_executable(Test WIN32 main.cpp resource.rc)
target_link_libraries(Test Qt5::Widgets)

View File

@ -4,16 +4,19 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <QApplication>
wchar_t buffer[1000] = {}; wchar_t buffer[1000] = {};
std::array<int, 10> vars = {}; 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())) for (auto file : std::filesystem::directory_iterator(std::filesystem::current_path()))
if (file.path().extension() == L".dll" if (file.path().extension() == L".dll"
&& (std::stringstream() << std::ifstream(file.path(), std::ios::binary).rdbuf()).str().find("OnNewSentence") != std::string::npos) && (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 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)); GetWindowTextW((HWND)lParam, buffer, std::size(buffer));
try { vars.at(LOWORD(wParam) - IDC_EDIT1) = std::stoi(buffer); } try { vars.at(LOWORD(wParam) - IDC_EDIT1) = std::stoi(buffer); }
catch (...) {} catch (...) {}
if (vars.at(1)) extensions.clear();
} }
} }
break; 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_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";
const char* MAX_HOOK_SEARCH_RECORDS = u8"Search result cap";
const char* MIN_ADDRESS = u8"Minimum address (hex)"; const char* MIN_ADDRESS = u8"Minimum address (hex)";
const char* MAX_ADDRESS = u8"Maximum address (hex)"; const char* MAX_ADDRESS = u8"Maximum address (hex)";
const char* STRING_OFFSET = u8"String offset (hex)"; const char* STRING_OFFSET = u8"String offset (hex)";

View File

@ -16845,7 +16845,7 @@ bool FindPPSSPP()
spDefault.minAddress = 0; spDefault.minAddress = 0;
spDefault.maxAddress = -1ULL; spDefault.maxAddress = -1ULL;
spDefault.padding = (uintptr_t)probe - 0x8000000; 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; probe += info.RegionSize;
} }

View File

@ -38,7 +38,7 @@ namespace Engine
spDefault.minAddress = 0; spDefault.minAddress = 0;
spDefault.maxAddress = -1ULL; spDefault.maxAddress = -1ULL;
spDefault.padding = (uintptr_t)probe - 0x8000000; 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; probe += info.RegionSize;
} }

View File

@ -24,7 +24,7 @@ namespace
hp.type = USING_UNICODE | USING_STRING; hp.type = USING_UNICODE | USING_STRING;
hp.address = address; hp.address = address;
hp.padding = sp.padding; hp.padding = sp.padding;
if (sp.hookPostProcesser) sp.hookPostProcesser(hp); if (sp.hookPostProcessor) sp.hookPostProcessor(hp);
NotifyHookFound(hp, (wchar_t*)text); NotifyHookFound(hp, (wchar_t*)text);
} }
uint64_t address = 0; uint64_t address = 0;
@ -160,11 +160,11 @@ void SearchForHooks(SearchParam spUser)
static std::mutex m; static std::mutex m;
std::scoped_lock lock(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; 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 moduleStartAddress = (uintptr_t)GetModuleHandleW(ITH_DLL);
uintptr_t moduleStopAddress = moduleStartAddress; uintptr_t moduleStopAddress = moduleStartAddress;
MEMORY_BASIC_INFORMATION info; MEMORY_BASIC_INFORMATION info;
@ -201,6 +201,6 @@ void SearchForHooks(SearchParam spUser)
records.reset(); records.reset();
VirtualFree(trampolines, 0, MEM_RELEASE); VirtualFree(trampolines, 0, MEM_RELEASE);
for (int i = 0; i < CACHE_SIZE; ++i) signatureCache[i] = sumCache[i] = 0; 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(); }).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 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 = [] 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
{ {