forked from Public-Mirror/Textractor
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* 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();
|
||||
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());
|
||||
hooks->clear();
|
||||
}).detach();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
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_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)";
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user