dialog for hook results and customize max result count
This commit is contained in:
parent
f85e3a3841
commit
b098a05a23
@ -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,22 +430,24 @@ 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);
|
||||||
spinBox->setMaximum(INT_MAX);
|
spinBox->setMaximum(INT_MAX);
|
||||||
spinBox->setValue(value);
|
spinBox->setValue(value);
|
||||||
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; });
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
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());
|
QTextFile(saveFile, QIODevice::WriteOnly | QIODevice::Truncate).write(hooks->toUtf8());
|
||||||
hooks->clear();
|
|
||||||
}).detach();
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
1
text.cpp
1
text.cpp
@ -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)";
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user