limit hook searches to a named module, also make 0 CCs default for x86 due to perf/stability improvements

This commit is contained in:
Akash Mozumdar 2019-11-10 14:13:54 -05:00
parent bf2838f3fc
commit 3db37ac450
6 changed files with 33 additions and 18 deletions

View File

@ -31,6 +31,7 @@ extern const char* HOOK_SEARCH_UNSTABLE_WARNING;
extern const char* SEARCH_CJK; 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* SEARCH_MODULE;
extern const char* PATTERN_OFFSET; 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;
@ -471,7 +472,7 @@ 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" : "55 8B EC", &dialog);
assert(QByteArray::fromHex(patternInput.text().toUtf8()) == QByteArray((const char*)sp.pattern, sp.length)); 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*>>{
@ -487,6 +488,8 @@ void MainWindow::FindHooks()
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; });
} }
QLineEdit boundInput(QFileInfo(S(Util::GetModuleFilename(GetSelectedProcessId()).value_or(L""))).fileName(), &dialog);
layout.addRow(SEARCH_MODULE, &boundInput);
for (auto [value, label] : Array<std::tuple<uintptr_t&, const char*>>{ for (auto [value, label] : Array<std::tuple<uintptr_t&, const char*>>{
{ sp.minAddress, MIN_ADDRESS }, { sp.minAddress, MIN_ADDRESS },
{ sp.maxAddress, MAX_ADDRESS }, { sp.maxAddress, MAX_ADDRESS },
@ -505,7 +508,7 @@ void MainWindow::FindHooks()
if (!dialog.exec()) return; if (!dialog.exec()) return;
if (patternInput.text().contains('.')) if (patternInput.text().contains('.'))
{ {
wcsncpy_s(sp.module, S(patternInput.text()).c_str(), MAX_MODULE_SIZE - 1); wcsncpy_s(sp.exportModule, S(patternInput.text()).c_str(), MAX_MODULE_SIZE - 1);
sp.length = 1; sp.length = 1;
} }
else else
@ -513,6 +516,7 @@ void MainWindow::FindHooks()
QByteArray pattern = QByteArray::fromHex(patternInput.text().replace("??", QString::number(XX, 16)).toUtf8()); QByteArray pattern = QByteArray::fromHex(patternInput.text().replace("??", QString::number(XX, 16)).toUtf8());
memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), PATTERN_SIZE)); memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), PATTERN_SIZE));
} }
wcsncpy_s(sp.boundaryModule, S(boundInput.text()).c_str(), MAX_MODULE_SIZE - 1);
try { filter = S(filterInput.text()); } catch (std::regex_error) {} try { filter = S(filterInput.text()); } catch (std::regex_error) {}
} }
else else

View File

@ -60,14 +60,16 @@ struct ThreadParam
struct SearchParam struct SearchParam
{ {
BYTE pattern[PATTERN_SIZE] = { 0xcc, 0xcc, x64 ? 0x48 : 0x55, x64 ? 0x89 : 0x8b, 0xec }; // pattern in memory to search for BYTE pattern[PATTERN_SIZE] = { x64 ? 0xcc : 0x55, x64 ? 0xcc : 0x8b, x64 ? 0x48 : 0xec, 0x89 }; // 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) int length = x64 ? 4 : 3, // 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 offset = x64 ? 2 : 0, // offset from start of pattern to add hook
searchTime = 20000, // ms searchTime = 20000, // ms
maxRecords = 100000, maxRecords = 100000,
codepage = SHIFT_JIS; codepage = SHIFT_JIS;
uintptr_t padding = 0, minAddress = 0, maxAddress = (uintptr_t)-1; uintptr_t padding = 0, // same as hook param padding
wchar_t module[MAX_MODULE_SIZE] = {}; minAddress = 0, maxAddress = (uintptr_t)-1; // hook all functions between these addresses (used only if both modules empty)
wchar_t boundaryModule[MAX_MODULE_SIZE] = {}; // hook all functions within this module (middle priority)
wchar_t exportModule[MAX_MODULE_SIZE] = {}; // hook the exports of this module (highest priority)
wchar_t text[PATTERN_SIZE] = {}; // text to search for wchar_t text[PATTERN_SIZE] = {}; // text to search for
void(*hookPostProcessor)(HookParam&) = nullptr; void(*hookPostProcessor)(HookParam&) = nullptr;
}; };

View File

@ -53,6 +53,7 @@ const char* HOOK_SEARCH_UNSTABLE_WARNING = u8"Searching for hooks is unstable! B
const char* SEARCH_CJK = u8"Search for Chinese/Japanese/Korean"; 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* SEARCH_MODULE = u8"Search within module";
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* MAX_HOOK_SEARCH_RECORDS = u8"Search result cap";
const char* MIN_ADDRESS = u8"Minimum address (hex)"; const char* MIN_ADDRESS = u8"Minimum address (hex)";

View File

@ -200,19 +200,12 @@ void SearchForHooks(SearchParam spUser)
ConsoleOutput(STARTING_SEARCH); ConsoleOutput(STARTING_SEARCH);
std::vector<uint64_t> addresses; std::vector<uint64_t> addresses;
if (*sp.module) addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.module)); if (*sp.boundaryModule) std::tie(sp.minAddress, sp.maxAddress) = Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
if (*sp.exportModule) addresses = GetFunctions((uintptr_t)GetModuleHandleW(sp.exportModule));
else for (auto& addr : addresses = Util::SearchMemory(sp.pattern, sp.length, PAGE_EXECUTE, sp.minAddress, sp.maxAddress)) addr += sp.offset; else for (auto& addr : addresses = Util::SearchMemory(sp.pattern, sp.length, PAGE_EXECUTE, sp.minAddress, sp.maxAddress)) addr += sp.offset;
uintptr_t moduleStartAddress = (uintptr_t)GetModuleHandleW(ITH_DLL); auto limits = Util::QueryModuleLimits(GetModuleHandleW(ITH_DLL));
uintptr_t moduleStopAddress = moduleStartAddress; addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](uint64_t addr) { return addr > limits.first && addr < limits.second; }), addresses.end());
MEMORY_BASIC_INFORMATION info;
do
{
VirtualQuery((void*)moduleStopAddress, &info, sizeof(info));
moduleStopAddress = (uintptr_t)info.BaseAddress + info.RegionSize;
} while (info.Protect >= PAGE_EXECUTE);
moduleStopAddress -= info.RegionSize;
addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](uint64_t addr) { return addr > moduleStartAddress && addr < moduleStopAddress; }), addresses.end());
auto trampolines = (decltype(trampoline)*)VirtualAlloc(NULL, sizeof(trampoline) * addresses.size(), MEM_COMMIT, PAGE_READWRITE); auto trampolines = (decltype(trampoline)*)VirtualAlloc(NULL, sizeof(trampoline) * addresses.size(), MEM_COMMIT, PAGE_READWRITE);
VirtualProtect(trampolines, addresses.size() * sizeof(trampoline), PAGE_EXECUTE_READWRITE, DUMMY); VirtualProtect(trampolines, addresses.size() * sizeof(trampoline), PAGE_EXECUTE_READWRITE, DUMMY);

View File

@ -301,6 +301,20 @@ bool SearchResourceString(LPCWSTR str)
return false; return false;
} }
std::pair<uint64_t, uint64_t> QueryModuleLimits(HMODULE module)
{
uintptr_t moduleStartAddress = (uintptr_t)module + 0x1000;
uintptr_t moduleStopAddress = moduleStartAddress;
MEMORY_BASIC_INFORMATION info;
do
{
VirtualQuery((void*)moduleStopAddress, &info, sizeof(info));
moduleStopAddress = (uintptr_t)info.BaseAddress + info.RegionSize;
} while (info.Protect >= PAGE_EXECUTE);
moduleStopAddress -= info.RegionSize;
return { moduleStartAddress, moduleStopAddress };
}
std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect, uintptr_t minAddr, uintptr_t maxAddr) std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect, uintptr_t minAddr, uintptr_t maxAddr)
{ {
SYSTEM_INFO systemInfo; SYSTEM_INFO systemInfo;

View File

@ -22,6 +22,7 @@ bool CheckFile(LPCWSTR name);
bool SearchResourceString(LPCWSTR str); bool SearchResourceString(LPCWSTR str);
std::pair<uint64_t, uint64_t> QueryModuleLimits(HMODULE module);
std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect = PAGE_EXECUTE, uintptr_t minAddr = 0, uintptr_t maxAddr = -1ULL); std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect = PAGE_EXECUTE, uintptr_t minAddr = 0, uintptr_t maxAddr = -1ULL);
} // namespace Util } // namespace Util