implement searching for read codes
This commit is contained in:
parent
b06dc8ff82
commit
f5d8d43149
36
GUI/misc.cpp
36
GUI/misc.cpp
@ -18,10 +18,10 @@ namespace
|
||||
case L'S':
|
||||
break;
|
||||
case L'Q':
|
||||
hp.type |= USING_STRING | USING_UNICODE;
|
||||
hp.type |= USING_UNICODE;
|
||||
break;
|
||||
case L'V':
|
||||
hp.type |= USING_STRING | USING_UTF8;
|
||||
hp.type |= USING_UTF8;
|
||||
break;
|
||||
default:
|
||||
return {};
|
||||
@ -36,7 +36,7 @@ namespace
|
||||
RCode.remove(0, codepage.captured(0).length());
|
||||
}
|
||||
|
||||
// [*deref_offset|0]
|
||||
// [*deref_offset]
|
||||
if (RCode.at(0).unicode() == L'0') RCode.remove(0, 1); // Legacy
|
||||
QRegularExpressionMatch deref = QRegularExpression("^\\*(\\-?[[:xdigit:]]+)").match(RCode);
|
||||
if (deref.hasMatch())
|
||||
@ -53,6 +53,24 @@ namespace
|
||||
return hp;
|
||||
}
|
||||
|
||||
std::optional<HookParam> ParseSCode(QString SCode)
|
||||
{
|
||||
HookParam hp = {};
|
||||
hp.type |= READ_SEARCH;
|
||||
|
||||
// [codepage#]
|
||||
QRegularExpressionMatch codepage = QRegularExpression("^([0-9]+)#").match(SCode);
|
||||
if (codepage.hasMatch())
|
||||
{
|
||||
hp.codepage = codepage.captured(1).toInt();
|
||||
SCode.remove(0, codepage.captured(0).length());
|
||||
}
|
||||
|
||||
wcscpy_s<MAX_MODULE_SIZE>(hp.text, S(SCode).c_str());
|
||||
|
||||
return hp;
|
||||
}
|
||||
|
||||
std::optional<HookParam> ParseHCode(QString HCode)
|
||||
{
|
||||
HookParam hp = {};
|
||||
@ -157,7 +175,7 @@ namespace
|
||||
|
||||
QString GenerateRCode(HookParam hp)
|
||||
{
|
||||
QString RCode = "/R";
|
||||
QString RCode = "R";
|
||||
QTextStream codeBuilder(&RCode);
|
||||
|
||||
if (hp.type & USING_UNICODE) codeBuilder << "Q";
|
||||
@ -178,7 +196,7 @@ namespace
|
||||
|
||||
QString GenerateHCode(HookParam hp, DWORD processId)
|
||||
{
|
||||
QString HCode = "/H";
|
||||
QString HCode = "H";
|
||||
QTextStream codeBuilder(&HCode);
|
||||
|
||||
if (hp.type & USING_UNICODE)
|
||||
@ -229,8 +247,10 @@ namespace
|
||||
|
||||
std::optional<HookParam> ParseCode(QString code)
|
||||
{
|
||||
if (code.startsWith("/H")) return ParseHCode(code.remove(0, 2));
|
||||
else if (code.startsWith("/R")) return ParseRCode(code.remove(0, 2));
|
||||
if (code.startsWith("/")) code.remove(0, 1); // legacy/AGTH compatibility
|
||||
if (code.startsWith("R")) return ParseRCode(code.remove(0, 1));
|
||||
else if (code.startsWith("S")) return ParseSCode(code.remove(0, 1));
|
||||
else if (code.startsWith("H")) return ParseHCode(code.remove(0, 1));
|
||||
else return {};
|
||||
}
|
||||
|
||||
@ -242,7 +262,7 @@ QString GenerateCode(HookParam hp, DWORD processId)
|
||||
|
||||
TEST(
|
||||
assert(ParseCode("/HQN936#-c*C:C*1C@4AA:gdi.dll:GetTextOutA")),
|
||||
assert(ParseCode("/HB4@0")),
|
||||
assert(ParseCode("HB4@0")),
|
||||
assert(ParseCode("/RS*10@44")),
|
||||
assert(!ParseCode("HQ@4")),
|
||||
assert(!ParseCode("/RW@44")),
|
||||
|
@ -35,6 +35,7 @@ enum HookParamType : unsigned long
|
||||
MODULE_OFFSET = 0x40, // address is relative to module
|
||||
FUNCTION_OFFSET = 0x80, // address is relative to function
|
||||
USING_UTF8 = 0x100,
|
||||
READ_SEARCH = 0x200, // unspecified address: search for text instead
|
||||
NO_CONTEXT = 0x400,
|
||||
HOOK_EMPTY = 0x800,
|
||||
FIXING_SPLIT = 0x1000,
|
||||
|
@ -14,10 +14,13 @@ constexpr auto SELECT_PROCESS = u8"Select Process";
|
||||
constexpr auto ATTACH_INFO = u8"If you don't see the process you want to attach, try running with admin rights\r\n"
|
||||
u8"You can also type in the process id";
|
||||
constexpr auto CODE_INFODUMP = u8"Enter hook code\r\n"
|
||||
u8"/H{A|B|W|S|Q|V}[N][codepage#]data_offset[*deref_offset1][:split_offset[*deref_offset2]]@addr[:module[:func]]\r\n"
|
||||
u8"H{A|B|W|S|Q|V}[N][codepage#]data_offset[*deref_offset1][:split_offset[*deref_offset2]]@addr[:module[:func]]\r\n"
|
||||
u8"OR\r\n"
|
||||
u8"Enter read code\r\n"
|
||||
u8"/R{S|Q|V}[codepage#][*deref_offset|0]@addr\r\n"
|
||||
u8"R{S|Q|V}[codepage#][*deref_offset]@addr\r\n"
|
||||
u8"OR\r\n"
|
||||
u8"Search for read code\r\n"
|
||||
u8"S[codepage#]text\r\n"
|
||||
u8"All numbers except codepage in hexadecimal\r\n"
|
||||
u8"A/B: Shift-JIS char little/big endian\r\n"
|
||||
u8"W: UTF-16 char\r\n"
|
||||
@ -50,6 +53,7 @@ constexpr auto INSERTING_HOOK = u8"Textractor: inserting hook: %s";
|
||||
constexpr auto REMOVING_HOOK = u8"Textractor: removing hook: %s";
|
||||
constexpr auto HOOK_FAILED = u8"Textractor: failed to insert hook";
|
||||
constexpr auto TOO_MANY_HOOKS = u8"Textractor: too many hooks: can't insert";
|
||||
constexpr auto NOT_ENOUGH_TEXT = u8"Textractor: not enough text to search accurately";
|
||||
constexpr auto FUNC_MISSING = u8"Textractor: function not present";
|
||||
constexpr auto MODULE_MISSING = u8"Textractor: module not present";
|
||||
constexpr auto GARBAGE_MEMORY = u8"Textractor: memory constantly changing, useless to read";
|
||||
|
@ -54,7 +54,11 @@ struct HookParam
|
||||
index, // deref_offset1
|
||||
split, // offset of the split character
|
||||
split_index; // deref_offset2
|
||||
union
|
||||
{
|
||||
wchar_t module[MAX_MODULE_SIZE];
|
||||
wchar_t text[MAX_MODULE_SIZE];
|
||||
};
|
||||
char function[MAX_MODULE_SIZE];
|
||||
DWORD type; // flags
|
||||
UINT codepage; // text encoding
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "MinHook.h"
|
||||
#include "engine/match.h"
|
||||
#include "texthook.h"
|
||||
#include "util.h"
|
||||
|
||||
std::unique_ptr<WinMutex> viewMutex;
|
||||
|
||||
@ -132,6 +133,29 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
|
||||
}
|
||||
|
||||
void NewHook(HookParam hp, LPCSTR lpname, DWORD flag)
|
||||
{
|
||||
if (hp.type & READ_SEARCH)
|
||||
{
|
||||
char utf8Text[MAX_MODULE_SIZE * 4] = {};
|
||||
WideCharToMultiByte(CP_UTF8, 0, hp.text, MAX_MODULE_SIZE, utf8Text, MAX_MODULE_SIZE * 4, nullptr, nullptr);
|
||||
char codepageText[MAX_MODULE_SIZE * 4] = {};
|
||||
WideCharToMultiByte(hp.codepage ? hp.codepage : SHIFT_JIS, 0, hp.text, MAX_MODULE_SIZE, codepageText, MAX_MODULE_SIZE * 4, nullptr, nullptr);
|
||||
if (strlen(utf8Text) < 8 || strlen(codepageText) < 8 || wcslen(hp.text) < 4) return ConsoleOutput(NOT_ENOUGH_TEXT);
|
||||
for (auto[addrs, type] : Array<std::tuple<std::vector<uint64_t>, HookParamType>>{
|
||||
{ Util::SearchMemory(utf8Text, strlen(utf8Text), PAGE_READWRITE), USING_UTF8 },
|
||||
{ Util::SearchMemory(codepageText, strlen(codepageText), PAGE_READWRITE), (HookParamType)0 },
|
||||
{ Util::SearchMemory(hp.text, wcslen(hp.text) * 2, PAGE_READWRITE), USING_UNICODE }
|
||||
})
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
HookParam h = {};
|
||||
h.type = DIRECT_READ | type;
|
||||
h.address = addr;
|
||||
h.codepage = hp.codepage;
|
||||
NewHook(h, lpname, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++currentHook >= MAX_HOOK) return ConsoleOutput(TOO_MANY_HOOKS);
|
||||
if (lpname && *lpname) strcpy_s<HOOK_NAME_SIZE>(hp.name, lpname);
|
||||
@ -139,6 +163,7 @@ void NewHook(HookParam hp, LPCSTR lpname, DWORD flag)
|
||||
RemoveHook(hp.address, 0);
|
||||
if (!hooks[currentHook].Insert(hp, flag)) ConsoleOutput(HOOK_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveHook(uint64_t addr, int maxOffset)
|
||||
{
|
||||
|
@ -302,7 +302,7 @@ bool SearchResourceString(LPCWSTR str)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> SearchMemory(const BYTE* bytes, short length, DWORD protect)
|
||||
std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect)
|
||||
{
|
||||
std::vector<std::pair<uint64_t, uint64_t>> validMemory;
|
||||
for (BYTE* probe = NULL; (uint64_t)probe < 0x80000000;) // end of user memory space
|
||||
@ -323,7 +323,7 @@ std::vector<uint64_t> SearchMemory(const BYTE* bytes, short length, DWORD protec
|
||||
std::vector<uint64_t> ret;
|
||||
for (auto memory : validMemory)
|
||||
for (uint64_t addr = memory.first; true;)
|
||||
if (addr = SafeSearchMemory(addr, memory.first + memory.second, bytes, length))
|
||||
if (addr = SafeSearchMemory(addr, memory.first + memory.second, (const BYTE*)bytes, length))
|
||||
ret.push_back(addr++);
|
||||
else break;
|
||||
|
||||
|
@ -22,7 +22,7 @@ bool CheckFile(LPCWSTR name);
|
||||
|
||||
bool SearchResourceString(LPCWSTR str);
|
||||
|
||||
std::vector<uint64_t> SearchMemory(const BYTE* bytes, short length, DWORD protect = PAGE_EXECUTE);
|
||||
std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect = PAGE_EXECUTE);
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user