forked from Public-Mirror/Textractor
added string offsets to hook codes and searches, fixed stack alignment bug, fixed inaccurate documentation on x64 registers, fixed bug with search signature cache, imrpvoed hook search string detection
This commit is contained in:
parent
7964623ec8
commit
5e27de842b
@ -108,11 +108,14 @@ namespace
|
||||
{
|
||||
auto info = *(HookFoundNotif*)buffer;
|
||||
auto& OnHookFound = processRecordsByIds->at(processId).OnHookFound;
|
||||
OnHookFound(info.hp, processId, info.text);
|
||||
std::wstring wide = info.text;
|
||||
if (wide.size() > STRING) OnHookFound(info.hp, processId, info.text);
|
||||
info.hp.type = USING_STRING;
|
||||
if (auto converted = Util::StringToWideString((char*)info.text, Host::defaultCodepage)) if (converted->size() > 12) OnHookFound(info.hp, processId, converted.value());
|
||||
if (auto converted = Util::StringToWideString((char*)info.text, Host::defaultCodepage))
|
||||
if (converted->size() > STRING) OnHookFound(info.hp, processId, converted.value());
|
||||
info.hp.codepage = CP_UTF8;
|
||||
if (auto converted = Util::StringToWideString((char*)info.text, CP_UTF8)) if (converted->size() > 12) OnHookFound(info.hp, processId, converted.value());
|
||||
if (auto converted = Util::StringToWideString((char*)info.text, CP_UTF8))
|
||||
if (converted->size() > STRING) OnHookFound(info.hp, processId, converted.value());
|
||||
}
|
||||
break;
|
||||
case HOST_NOTIFICATION_RMVHOOK:
|
||||
|
@ -41,15 +41,6 @@ namespace
|
||||
RCode.erase(0, match[0].length());
|
||||
}
|
||||
|
||||
// [*deref_offset]
|
||||
if (RCode[0] == L'0') RCode.erase(0, 1); // Legacy
|
||||
if (std::regex_search(RCode, match, std::wregex(L"^\\*(-?[[:xdigit:]]+)")))
|
||||
{
|
||||
hp.type |= DATA_INDIRECT;
|
||||
hp.index = std::stoi(match[1], nullptr, 16);
|
||||
RCode.erase(0, match[0].length());
|
||||
}
|
||||
|
||||
// @addr
|
||||
if (!std::regex_match(RCode, match, std::wregex(L"@([[:xdigit:]]+)"))) return {};
|
||||
hp.address = std::stoull(match[1], nullptr, 16);
|
||||
@ -132,6 +123,13 @@ namespace
|
||||
HCode.erase(0, match[0].length());
|
||||
}
|
||||
|
||||
// [padding+]
|
||||
if (std::regex_search(HCode, match, std::wregex(L"^([[:xdigit:]]+)\\+")))
|
||||
{
|
||||
hp.padding = std::stoull(match[1], nullptr, 16);
|
||||
HCode.erase(0, match[0].length());
|
||||
}
|
||||
|
||||
// data_offset
|
||||
if (!std::regex_search(HCode, match, std::wregex(L"^-?[[:xdigit:]]+"))) return {};
|
||||
hp.offset = std::stoi(match[0], nullptr, 16);
|
||||
@ -206,8 +204,6 @@ namespace
|
||||
|
||||
RCode << std::uppercase << std::hex;
|
||||
|
||||
if (hp.type & DATA_INDIRECT) RCode << "*" << HexString(hp.index);
|
||||
|
||||
RCode << "@" << hp.address;
|
||||
|
||||
return RCode.str();
|
||||
@ -239,6 +235,8 @@ namespace
|
||||
|
||||
HCode << std::uppercase << std::hex;
|
||||
|
||||
if (hp.padding) HCode << hp.padding << "+";
|
||||
|
||||
if (hp.offset < 0) hp.offset += 4;
|
||||
if (hp.split < 0) hp.split += 4;
|
||||
|
||||
@ -338,7 +336,7 @@ namespace Util
|
||||
assert(StringToWideString(u8"こんにちは").value() == L"こんにちは"),
|
||||
assert(ParseCode(L"/HQN936#-c*C:C*1C@4AA:gdi.dll:GetTextOutA")),
|
||||
assert(ParseCode(L"HB4@0")),
|
||||
assert(ParseCode(L"/RS*10@44")),
|
||||
assert(ParseCode(L"/RS65001#@44")),
|
||||
assert(!ParseCode(L"HQ@4")),
|
||||
assert(!ParseCode(L"/RW@44")),
|
||||
assert(!ParseCode(L"/HWG@33"))
|
||||
|
@ -33,6 +33,7 @@ extern const char* SEARCH_DURATION;
|
||||
extern const char* PATTERN_OFFSET;
|
||||
extern const char* MIN_ADDRESS;
|
||||
extern const char* MAX_ADDRESS;
|
||||
extern const char* STRING_OFFSET;
|
||||
extern const char* HOOK_SEARCH_FILTER;
|
||||
extern const char* START_HOOK_SEARCH;
|
||||
extern const char* SAVE_SEARCH_RESULTS;
|
||||
@ -353,6 +354,7 @@ void MainWindow::FindHooks()
|
||||
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 }
|
||||
})
|
||||
{
|
||||
auto input = new QLineEdit(QString::number(value, 16), this);
|
||||
|
@ -4,7 +4,7 @@
|
||||
// 8/23/2013 jichi
|
||||
// Branch: ITH/common.h, rev 128
|
||||
|
||||
enum Misc { MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 2000, SHIFT_JIS = 932, MAX_MODULE_SIZE = 120, HOOK_NAME_SIZE = 30, FIXED_SPLIT_VALUE = 0x10001 };
|
||||
enum Misc { STRING = 12, MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 2000, SHIFT_JIS = 932, MAX_MODULE_SIZE = 120, HOOK_NAME_SIZE = 30, FIXED_SPLIT_VALUE = 0x10001 };
|
||||
|
||||
enum HostCommandType { HOST_COMMAND_NEW_HOOK, HOST_COMMAND_REMOVE_HOOK, HOST_COMMAND_FIND_HOOK, HOST_COMMAND_MODIFY_HOOK, HOST_COMMAND_HIJACK_PROCESS, HOST_COMMAND_DETACH };
|
||||
|
||||
|
@ -40,6 +40,7 @@ struct HookParam
|
||||
DWORD type; // flags
|
||||
UINT codepage; // text encoding
|
||||
short length_offset; // index of the string length
|
||||
uintptr_t padding; // padding
|
||||
DWORD user_value; // 7/20/2014: jichi additional parameters for PSP games
|
||||
|
||||
void(*text_fun)(DWORD stack, HookParam* hp, BYTE obsoleteAlwaysZero, DWORD* data, DWORD* split, DWORD* len);
|
||||
@ -64,7 +65,7 @@ struct SearchParam
|
||||
int length, // length of pattern
|
||||
offset, // offset from start of pattern to add hook
|
||||
searchTime; // ms
|
||||
uintptr_t minAddress, maxAddress;
|
||||
uintptr_t padding, minAddress, maxAddress;
|
||||
};
|
||||
|
||||
struct InsertHookCmd // From host
|
||||
|
9
text.cpp
9
text.cpp
@ -23,19 +23,21 @@ const char* CODE_INFODUMP = u8R"(Search for text
|
||||
S[codepage#]text
|
||||
OR
|
||||
Enter read code
|
||||
R{S|Q|V}[null_length<][codepage#][*deref_offset]@addr
|
||||
R{S|Q|V}[null_length<][codepage#]@addr
|
||||
OR
|
||||
Enter hook code
|
||||
H{A|B|W|S|Q|V}[null_length<][N][codepage#]data_offset[*deref_offset1][:split_offset[*deref_offset2]]@addr[:module[:func]]
|
||||
H{A|B|W|S|Q|V}[null_length<][N][codepage#][padding+]data_offset[*deref_offset][:split_offset[*deref_offset]]@addr[:module[:func]]
|
||||
All numbers except codepage/null_length in hexadecimal
|
||||
Default codepage is 932 (Shift-JIS) but this can be changed in settings
|
||||
A/B: codepage char little/big endian
|
||||
W: UTF-16 char
|
||||
S/Q/V: codepage/UTF-16/UTF-8 string
|
||||
N: don't use context
|
||||
null_length: length of null terminator used for string
|
||||
padding: length of padding data before string (C struct { int64_t size; char string[500]; } needs padding = 8)
|
||||
Negatives for data_offset/split_offset refer to registers
|
||||
-4 for EAX, -8 for ECX, -C for EDX, -10 for EBX, -14 for ESP, -18 for EBP, -1C for ESI, -20 for EDI
|
||||
-4 for RAX, -C for RBX, -14 for RCX, -1C for RDX, and so on for RSP, RBP, RSI, RDI, R8-R15
|
||||
-C for RAX, -14 for RBX, -1C for RCX, -24 for RDX, and so on for RSP, RBP, RSI, RDI, R8-R15
|
||||
* means dereference pointer+deref_offset)";
|
||||
const char* SAVE_SETTINGS = u8"Save settings";
|
||||
const char* EXTEN_WINDOW_INSTRUCTIONS = u8R"(Drag and drop extension (.dll) files here from your computer to add them
|
||||
@ -53,6 +55,7 @@ const char* SEARCH_DURATION = u8"Search duration (ms)";
|
||||
const char* PATTERN_OFFSET = u8"Offset from pattern start";
|
||||
const char* MIN_ADDRESS = u8"Minimum address (hex)";
|
||||
const char* MAX_ADDRESS = u8"Maximum address (hex)";
|
||||
const char* STRING_OFFSET = u8"String offset (hex)";
|
||||
const char* HOOK_SEARCH_FILTER = u8"Results must match this regex";
|
||||
const char* START_HOOK_SEARCH = u8"Start hook search";
|
||||
const char* SAVE_SEARCH_RESULTS = u8"Save search results";
|
||||
|
@ -11,22 +11,32 @@ extern WinMutex viewMutex;
|
||||
|
||||
namespace
|
||||
{
|
||||
SearchParam current;
|
||||
|
||||
constexpr int CACHE_SIZE = 500'000;
|
||||
struct HookRecord
|
||||
{
|
||||
HookRecord() : address(0) {}
|
||||
~HookRecord() { if (address) NotifyHookFound(address, offset, text); }
|
||||
uint64_t address;
|
||||
int offset;
|
||||
wchar_t text[200];
|
||||
~HookRecord()
|
||||
{
|
||||
if (!address) return;
|
||||
HookParam hp = {};
|
||||
hp.offset = offset;
|
||||
hp.type = USING_UNICODE | USING_STRING;
|
||||
hp.address = address;
|
||||
hp.padding = current.padding;
|
||||
NotifyHookFound(hp, (wchar_t*)text);
|
||||
}
|
||||
uint64_t address = 0;
|
||||
int offset = 0;
|
||||
char text[500] = {};
|
||||
};
|
||||
std::unique_ptr<HookRecord[]> records;
|
||||
long recordsAvailable;
|
||||
uint64_t addressCharCache[CACHE_SIZE] = {};
|
||||
uint64_t signatureCache[CACHE_SIZE] = {};
|
||||
long sumCache[CACHE_SIZE] = {};
|
||||
|
||||
#ifndef _WIN64
|
||||
BYTE trampoline[32] =
|
||||
BYTE trampoline[] =
|
||||
{
|
||||
0x9c, // pushfd
|
||||
0x60, // pushad
|
||||
@ -43,7 +53,7 @@ namespace
|
||||
};
|
||||
constexpr int addr_offset = 3, send_offset = 13, original_offset = 25, registers = 8;
|
||||
#else
|
||||
BYTE trampoline[128] = {
|
||||
BYTE trampoline[] = {
|
||||
0x9c, // push rflags
|
||||
0x50, // push rax
|
||||
0x53, // push rbx
|
||||
@ -69,7 +79,10 @@ namespace
|
||||
0x48, 0x8d, 0x8c, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rcx,[rsp+0xa8]
|
||||
0x48, 0xba, 0,0,0,0,0,0,0,0, // mov rcx,@addr
|
||||
0x48, 0xb8, 0,0,0,0,0,0,0,0, // mov rax,@Send
|
||||
0x48, 0x89, 0xe3, // mov rbx,rsp
|
||||
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
|
||||
0xff, 0xd0, // call rax
|
||||
0x48, 0x89, 0xdc, // mov rsp,rbx
|
||||
0xc5, 0xfa, 0x6f, 0x6c, 0x24, 0x10, // vmovdqu xmm5,XMMWORD PTR[rsp + 0x10]
|
||||
0xc5, 0xfa, 0x6f, 0x24, 0x24, // vmovdqu xmm4,XMMWORD PTR[rsp]
|
||||
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
|
||||
@ -93,11 +106,11 @@ namespace
|
||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [0] ; relative to next instruction (i.e. jmp @original)
|
||||
0,0,0,0,0,0,0,0 // @original
|
||||
};
|
||||
constexpr int addr_offset = 50, send_offset = 60, original_offset = 116, registers = 16;
|
||||
constexpr int addr_offset = 50, send_offset = 60, original_offset = 126, registers = 16;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Send(wchar_t** stack, uintptr_t address)
|
||||
void Send(char** stack, uintptr_t address)
|
||||
{
|
||||
// it is unsafe to call ANY external functions from this, as they may have been hooked (if called the hook would call this function making an infinite loop)
|
||||
// the exceptions are compiler intrinsics like _InterlockedDecrement
|
||||
@ -105,16 +118,17 @@ void Send(wchar_t** stack, uintptr_t address)
|
||||
for (int i = -registers; i < 6; ++i)
|
||||
{
|
||||
int length = 0, sum = 0;
|
||||
__try { for (wchar_t* str = stack[i]; str[length] && length < 200; ++length) sum += str[length]; }
|
||||
char* str = stack[i] + current.padding;
|
||||
__try { for (; (str[length] || str[length + 1]) && length < 500; length += 2) sum += str[length] + str[length + 1]; }
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {}
|
||||
if (length > 7 && length < 199)
|
||||
if (length > STRING && length < 499)
|
||||
{
|
||||
__try
|
||||
{
|
||||
// many duplicate results with same address and second character will be found: filter them out
|
||||
uint64_t addressAndChar = (((uint64_t)stack[i][1]) << 48) | address;
|
||||
if (addressCharCache[addressAndChar % CACHE_SIZE] == addressAndChar) continue;
|
||||
addressCharCache[addressAndChar % CACHE_SIZE] = addressAndChar;
|
||||
// many duplicate results with same address, offset, and third/fourth character will be found: filter them out
|
||||
uint64_t signature = ((uint64_t)i << 56) | ((uint64_t)(str[2] + str[3]) << 48) | address;
|
||||
if (signatureCache[signature % CACHE_SIZE] == signature) continue;
|
||||
signatureCache[signature % CACHE_SIZE] = signature;
|
||||
// if there are huge amount of strings that are the same, it's probably garbage: filter them out
|
||||
// can't store all the strings, so use sum as heuristic instead
|
||||
if (_InterlockedIncrement(sumCache + (sum % CACHE_SIZE)) > 25) continue;
|
||||
@ -127,8 +141,8 @@ void Send(wchar_t** stack, uintptr_t address)
|
||||
if (n > 0)
|
||||
{
|
||||
records[n].address = address;
|
||||
records[n].offset = i * sizeof(wchar_t*);
|
||||
for (int j = 0; j < length; ++j) records[n].text[j] = stack[i][j];
|
||||
records[n].offset = i * sizeof(char*);
|
||||
for (int j = 0; j < length; ++j) records[n].text[j] = str[j];
|
||||
records[n].text[length] = 0;
|
||||
}
|
||||
}
|
||||
@ -145,12 +159,11 @@ void SearchForHooks(SearchParam sp)
|
||||
static std::mutex m;
|
||||
std::scoped_lock lock(m);
|
||||
|
||||
try
|
||||
{
|
||||
records = std::make_unique<HookRecord[]>(recordsAvailable = CACHE_SIZE);
|
||||
}
|
||||
try { records = std::make_unique<HookRecord[]>(recordsAvailable = CACHE_SIZE); }
|
||||
catch (std::bad_alloc&) { return ConsoleOutput("Textractor: SearchForHooks ERROR (out of memory)"); }
|
||||
|
||||
current = sp;
|
||||
|
||||
uintptr_t moduleStartAddress = (uintptr_t)GetModuleHandleW(ITH_DLL);
|
||||
uintptr_t moduleStopAddress = moduleStartAddress;
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
@ -162,12 +175,9 @@ void SearchForHooks(SearchParam sp)
|
||||
moduleStopAddress -= info.RegionSize;
|
||||
|
||||
ConsoleOutput(STARTING_SEARCH);
|
||||
std::vector<uint64_t> addresses = Util::SearchMemory(sp.pattern, sp.length);
|
||||
std::vector<uint64_t> addresses = Util::SearchMemory(sp.pattern, sp.length, PAGE_EXECUTE, sp.minAddress, sp.maxAddress);
|
||||
for (auto& addr : addresses) addr += sp.offset;
|
||||
addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](uint64_t addr)
|
||||
{
|
||||
return (addr > moduleStartAddress && addr < moduleStopAddress) || addr > sp.maxAddress || addr < sp.minAddress;
|
||||
}), addresses.end());
|
||||
addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [&](uint64_t addr) { return addr > moduleStartAddress && addr < moduleStopAddress; }), addresses.end());
|
||||
*(void**)(trampoline + send_offset) = Send;
|
||||
auto trampolines = (decltype(trampoline)*)VirtualAlloc(NULL, sizeof(trampoline) * addresses.size(), MEM_COMMIT, PAGE_READWRITE);
|
||||
VirtualProtect(trampolines, addresses.size() * sizeof(trampoline), PAGE_EXECUTE_READWRITE, DUMMY);
|
||||
@ -189,7 +199,7 @@ void SearchForHooks(SearchParam sp)
|
||||
for (auto addr : addresses) MH_RemoveHook((void*)addr);
|
||||
records.reset();
|
||||
VirtualFree(trampolines, 0, MEM_RELEASE);
|
||||
for (int i = 0; i < CACHE_SIZE; ++i) addressCharCache[i] = sumCache[i] = 0;
|
||||
for (int i = 0; i < CACHE_SIZE; ++i) signatureCache[i] = sumCache[i] = 0;
|
||||
ConsoleOutput(HOOK_SEARCH_FINISHED, CACHE_SIZE - recordsAvailable);
|
||||
}).detach();
|
||||
}
|
||||
|
@ -102,12 +102,8 @@ void ConsoleOutput(LPCSTR text, ...)
|
||||
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
||||
}
|
||||
|
||||
void NotifyHookFound(uint64_t addr, int offset, wchar_t* text)
|
||||
void NotifyHookFound(HookParam hp, wchar_t* text)
|
||||
{
|
||||
HookParam hp = {};
|
||||
hp.offset = offset;
|
||||
hp.type = USING_UNICODE | USING_STRING;
|
||||
hp.address = addr;
|
||||
HookFoundNotif buffer(hp, text);
|
||||
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
void TextOutput(ThreadParam tp, BYTE* text, int len);
|
||||
void ConsoleOutput(LPCSTR text, ...);
|
||||
void NotifyHookFound(uint64_t addr, int offset, wchar_t* text);
|
||||
void NotifyHookFound(HookParam hp, wchar_t* text);
|
||||
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);
|
||||
|
@ -63,7 +63,10 @@ namespace { // unnamed
|
||||
0x48, 0x8d, 0x94, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rdx,[rsp+0xa8]
|
||||
0x48, 0xb9, 0,0,0,0,0,0,0,0, // mov rcx,@this
|
||||
0x48, 0xb8, 0,0,0,0,0,0,0,0, // mov rax,@TextHook::Send
|
||||
0x48, 0x89, 0xe3, // mov rbx,rsp
|
||||
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
|
||||
0xff, 0xd0, // call rax
|
||||
0x48, 0x89, 0xdc, // mov rsp,rbx
|
||||
0xc5, 0xfa, 0x6f, 0x6c, 0x24, 0x10, // vmovdqu xmm5,XMMWORD PTR[rsp + 0x10]
|
||||
0xc5, 0xfa, 0x6f, 0x24, 0x24, // vmovdqu xmm4,XMMWORD PTR[rsp]
|
||||
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
|
||||
@ -87,7 +90,7 @@ namespace { // unnamed
|
||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [0] ; relative to next instruction (i.e. jmp @original)
|
||||
0,0,0,0,0,0,0,0 // @original
|
||||
};
|
||||
int this_offset = 50, send_offset = 60, original_offset = 116;
|
||||
int this_offset = 50, send_offset = 60, original_offset = 126;
|
||||
#endif
|
||||
|
||||
bool trigger = false;
|
||||
@ -142,6 +145,7 @@ void TextHook::Send(uintptr_t dwDataBase)
|
||||
if (hp.type & SPLIT_INDIRECT) dwSplit = *(DWORD *)(dwSplit + hp.split_index);
|
||||
}
|
||||
if (hp.type & DATA_INDIRECT) dwDataIn = *(DWORD *)(dwDataIn + hp.index);
|
||||
dwDataIn += hp.padding;
|
||||
dwCount = GetLength(dwDataBase, dwDataIn);
|
||||
}
|
||||
|
||||
@ -173,6 +177,7 @@ void TextHook::Send(uintptr_t dwDataBase)
|
||||
}
|
||||
if (hp.type & DATA_INDIRECT) data = *(uintptr_t*)(data + hp.index);
|
||||
|
||||
data += hp.padding;
|
||||
count = GetLength(dwDataBase, data);
|
||||
if (count == 0) return;
|
||||
if (count > TEXT_BUFFER_SIZE) count = TEXT_BUFFER_SIZE;
|
||||
@ -225,18 +230,15 @@ bool TextHook::InsertHookCode()
|
||||
return MH_EnableHook(location) == MH_OK;
|
||||
}
|
||||
|
||||
DWORD WINAPI TextHook::Reader(LPVOID hookPtr)
|
||||
void TextHook::Read()
|
||||
{
|
||||
TextHook* This = (TextHook*)hookPtr;
|
||||
BYTE buffer[TEXT_BUFFER_SIZE] = {};
|
||||
int changeCount = 0, dataLen = 1;
|
||||
__try
|
||||
{
|
||||
uint64_t currentAddress = This->address;
|
||||
while (WaitForSingleObject(This->readerEvent, 500) == WAIT_TIMEOUT)
|
||||
while (WaitForSingleObject(readerEvent, 500) == WAIT_TIMEOUT)
|
||||
{
|
||||
if (This->hp.type & DATA_INDIRECT) currentAddress = *(uintptr_t*)This->address + This->hp.index;
|
||||
if (memcmp(buffer, (void*)currentAddress, dataLen) == 0)
|
||||
if (memcmp(buffer, location, dataLen) == 0)
|
||||
{
|
||||
changeCount = 0;
|
||||
continue;
|
||||
@ -244,26 +246,25 @@ DWORD WINAPI TextHook::Reader(LPVOID hookPtr)
|
||||
if (++changeCount > 10)
|
||||
{
|
||||
ConsoleOutput(GARBAGE_MEMORY);
|
||||
This->Clear();
|
||||
Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
dataLen = min(This->HookStrlen((BYTE*)currentAddress), TEXT_BUFFER_SIZE);
|
||||
memcpy(buffer, (void*)currentAddress, dataLen);
|
||||
TextOutput({ GetCurrentProcessId(), This->address, 0, 0 }, buffer, dataLen);
|
||||
dataLen = min(HookStrlen((BYTE*)location), TEXT_BUFFER_SIZE);
|
||||
memcpy(buffer, location, dataLen);
|
||||
TextOutput({ GetCurrentProcessId(), address, 0, 0 }, buffer, dataLen);
|
||||
}
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
ConsoleOutput(READ_ERROR);
|
||||
This->Clear();
|
||||
Clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TextHook::InsertReadCode()
|
||||
{
|
||||
readerThread = CreateThread(nullptr, 0, Reader, this, 0, nullptr);
|
||||
readerThread = CreateThread(nullptr, 0, [](void* This) { ((TextHook*)This)->Read(); return 0UL; }, this, 0, nullptr);
|
||||
readerEvent = CreateEventW(nullptr, FALSE, FALSE, NULL);
|
||||
return true;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
static DWORD WINAPI Reader(LPVOID hookPtr);
|
||||
void Read();
|
||||
bool InsertHookCode();
|
||||
bool InsertReadCode();
|
||||
void Send(uintptr_t dwDatabase);
|
||||
@ -40,7 +40,7 @@ private:
|
||||
|
||||
HANDLE readerThread, readerEvent;
|
||||
bool err;
|
||||
BYTE trampoline[130];
|
||||
BYTE trampoline[x64 ? 140 : 40];
|
||||
|
||||
};
|
||||
|
||||
|
@ -301,7 +301,7 @@ bool SearchResourceString(LPCWSTR str)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect)
|
||||
std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect, uintptr_t minAddr, uintptr_t maxAddr)
|
||||
{
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
@ -316,15 +316,16 @@ std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protec
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.Protect >= protect && !(info.Protect & PAGE_GUARD)) validMemory.push_back({ (uint64_t)info.BaseAddress, info.RegionSize });
|
||||
if ((uint64_t)info.BaseAddress + info.RegionSize >= minAddr && info.Protect >= protect && !(info.Protect & PAGE_GUARD))
|
||||
validMemory.push_back({ (uint64_t)info.BaseAddress, info.RegionSize });
|
||||
probe += info.RegionSize;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint64_t> ret;
|
||||
for (auto memory : validMemory)
|
||||
for (uint64_t addr = memory.first; true;)
|
||||
if (addr = SafeSearchMemory(addr, memory.first + memory.second, (const BYTE*)bytes, length))
|
||||
for (uint64_t addr = max(memory.first, minAddr); true;)
|
||||
if (addr < maxAddr && (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 void* bytes, short length, DWORD protect = PAGE_EXECUTE);
|
||||
std::vector<uint64_t> SearchMemory(const void* bytes, short length, DWORD protect = PAGE_EXECUTE, uintptr_t minAddr = 0, uintptr_t maxAddr = -1ULL);
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user