add function based offset. rewrite hookparam processing while we're at it
This commit is contained in:
parent
3b9ca65e39
commit
f7e3bbeb02
@ -234,7 +234,7 @@ namespace Host
|
||||
WaitForSingleObject(pr.sectionMutex, 0);
|
||||
const TextHook* hooks = (const TextHook*)pr.sectionMap;
|
||||
for (int i = 0; i < MAX_HOOK; ++i)
|
||||
if (hooks[i].hp.address == addr)
|
||||
if (hooks[i].hp.insertion_address == addr)
|
||||
ret = hooks[i].hp;
|
||||
ReleaseMutex(pr.sectionMutex);
|
||||
return ret;
|
||||
@ -252,7 +252,7 @@ namespace Host
|
||||
WaitForSingleObject(pr.sectionMutex, 0);
|
||||
const TextHook* hooks = (const TextHook*)pr.sectionMap;
|
||||
for (int i = 0; i < MAX_HOOK; ++i)
|
||||
if (hooks[i].hp.address == addr)
|
||||
if (hooks[i].hp.insertion_address == addr)
|
||||
{
|
||||
buffer.resize(hooks[i].name_length);
|
||||
ReadProcessMemory(pr.processHandle, hooks[i].hook_name, buffer.data(), hooks[i].name_length, nullptr);
|
||||
|
@ -157,7 +157,7 @@ std::unordered_map<std::string, int64_t> MainWindow::GetInfoForExtensions(TextTh
|
||||
|
||||
QVector<HookParam> MainWindow::GetAllHooks(DWORD processId)
|
||||
{
|
||||
QSet<DWORD> addresses;
|
||||
QSet<uint64_t> addresses;
|
||||
QVector<HookParam> hooks;
|
||||
for (int i = 0; i < ttCombo->count(); ++i)
|
||||
{
|
||||
@ -208,13 +208,13 @@ void MainWindow::on_unhookButton_clicked()
|
||||
QStringList hookList;
|
||||
for (auto hook : hooks)
|
||||
hookList.push_back(
|
||||
QString::fromStdWString(Host::GetHookName(GetSelectedProcessId(), hook.address)) +
|
||||
QString::fromStdWString(Host::GetHookName(GetSelectedProcessId(), hook.insertion_address)) +
|
||||
": " +
|
||||
GenerateCode(hook, GetSelectedProcessId())
|
||||
);
|
||||
bool ok;
|
||||
QString hook = QInputDialog::getItem(this, "Unhook", "Which hook to remove?", hookList, 0, false, &ok);
|
||||
if (ok) Host::RemoveHook(GetSelectedProcessId(), hooks.at(hookList.indexOf(hook)).address);
|
||||
if (ok) Host::RemoveHook(GetSelectedProcessId(), hooks.at(hookList.indexOf(hook)).insertion_address);
|
||||
}
|
||||
|
||||
void MainWindow::on_saveButton_clicked()
|
||||
|
217
GUI/misc.cpp
217
GUI/misc.cpp
@ -1,7 +1,7 @@
|
||||
#include "misc.h"
|
||||
#include "const.h"
|
||||
#include <QRegExp>
|
||||
#include <Psapi.h>
|
||||
#include <QTextStream>
|
||||
|
||||
QString GetFullModuleName(DWORD processId, HMODULE module)
|
||||
{
|
||||
@ -32,18 +32,12 @@ QMultiHash<QString, DWORD> GetAllProcesses()
|
||||
|
||||
namespace
|
||||
{
|
||||
DWORD Hash(QString module)
|
||||
{
|
||||
module = module.toLower();
|
||||
DWORD hash = 0;
|
||||
for (auto i : module) hash = _rotr(hash, 7) + i.unicode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::optional<HookParam> ParseRCode(QString RCode)
|
||||
{
|
||||
HookParam hp = {};
|
||||
hp.type |= DIRECT_READ;
|
||||
|
||||
// {S|Q|V}
|
||||
switch (RCode.at(0).unicode())
|
||||
{
|
||||
case L'S':
|
||||
@ -58,25 +52,32 @@ namespace
|
||||
return {};
|
||||
}
|
||||
RCode.remove(0, 1);
|
||||
if (RCode.at(0).unicode() == L'0') RCode.remove(0, 1);
|
||||
QRegExp stringGap("^\\*(\\-?[\\dA-F]+)");
|
||||
if (stringGap.indexIn(RCode) != -1)
|
||||
|
||||
// [*deref_offset|0]
|
||||
if (RCode.at(0).unicode() == L'0') RCode.remove(0, 1); // Legacy
|
||||
QRegularExpressionMatch deref = QRegularExpression("^\\*(\\-?[[:xdigit:]]+)").match(RCode);
|
||||
if (deref.hasMatch())
|
||||
{
|
||||
hp.index = stringGap.cap(1).toInt(nullptr, 16);
|
||||
RCode.remove(0, stringGap.cap(0).length());
|
||||
hp.type |= DATA_INDIRECT;
|
||||
hp.index = deref.captured(1).toInt(nullptr, 16);
|
||||
RCode.remove(0, deref.captured(0).length());
|
||||
}
|
||||
|
||||
if (RCode.at(0).unicode() != L'@') return {};
|
||||
RCode.remove(0, 1);
|
||||
QRegExp address("[\\dA-F]+$");
|
||||
if (address.indexIn(RCode) == -1) return {};
|
||||
hp.address = address.cap(0).toULongLong(nullptr, 16);
|
||||
|
||||
// @addr
|
||||
QRegularExpressionMatch address = QRegularExpression("^@([[:xdigit:]]+)$").match(RCode);
|
||||
if (!address.hasMatch()) return {};
|
||||
hp.address = address.captured(1).toULongLong(nullptr, 16);
|
||||
return hp;
|
||||
}
|
||||
|
||||
std::optional<HookParam> ParseHCode(QString HCode)
|
||||
{
|
||||
HookParam hp = {};
|
||||
|
||||
// {A|B|W|S|Q|V}
|
||||
switch (HCode.at(0).unicode())
|
||||
{
|
||||
case L'S':
|
||||
@ -103,139 +104,141 @@ namespace
|
||||
return {};
|
||||
}
|
||||
HCode.remove(0, 1);
|
||||
|
||||
// [N]
|
||||
if (HCode.at(0).unicode() == L'N')
|
||||
{
|
||||
hp.type |= NO_CONTEXT;
|
||||
HCode.remove(0, 1);
|
||||
}
|
||||
QRegExp dataOffset("^\\-?[\\dA-F]+");
|
||||
if (dataOffset.indexIn(HCode) == -1) return {};
|
||||
hp.offset = dataOffset.cap(0).toInt(nullptr, 16);
|
||||
HCode.remove(0, dataOffset.cap(0).length());
|
||||
QRegExp dataIndirect("^\\*(\\-?[\\dA-F]+)");
|
||||
if (dataIndirect.indexIn(HCode) != -1)
|
||||
|
||||
// data_offset
|
||||
QRegularExpressionMatch dataOffset = QRegularExpression("^\\-?[[:xdigit:]]+").match(HCode);
|
||||
if (!dataOffset.hasMatch()) return {};
|
||||
hp.offset = dataOffset.captured(0).toInt(nullptr, 16);
|
||||
HCode.remove(0, dataOffset.captured(0).length());
|
||||
|
||||
// [*deref_offset1]
|
||||
QRegularExpressionMatch deref1 = QRegularExpression("^\\*(\\-?[[:xdigit:]]+)").match(HCode);
|
||||
if (deref1.hasMatch())
|
||||
{
|
||||
hp.type |= DATA_INDIRECT;
|
||||
hp.index = dataIndirect.cap(1).toInt(nullptr, 16);
|
||||
HCode.remove(0, dataIndirect.cap(0).length());
|
||||
hp.index = deref1.captured(1).toInt(nullptr, 16);
|
||||
HCode.remove(0, deref1.captured(0).length());
|
||||
}
|
||||
QRegExp split("^\\:(\\-?[\\dA-F]+)");
|
||||
if (split.indexIn(HCode) != -1)
|
||||
|
||||
// [:split_offset[*deref_offset2]]
|
||||
QRegularExpressionMatch splitOffset = QRegularExpression("^\\:(\\-?[[:xdigit:]]+)").match(HCode);
|
||||
if (splitOffset.hasMatch())
|
||||
{
|
||||
hp.type |= USING_SPLIT;
|
||||
hp.split = split.cap(1).toInt(nullptr, 16);
|
||||
HCode.remove(0, split.cap(0).length());
|
||||
QRegExp splitIndirect("^\\*(\\-?[\\dA-F]+)");
|
||||
if (splitIndirect.indexIn(HCode) != -1)
|
||||
hp.split = splitOffset.captured(1).toInt(nullptr, 16);
|
||||
HCode.remove(0, splitOffset.captured(0).length());
|
||||
|
||||
QRegularExpressionMatch deref2 = QRegularExpression("^\\*(\\-?[[:xdigit:]]+)").match(HCode);
|
||||
if (deref2.hasMatch())
|
||||
{
|
||||
hp.type |= SPLIT_INDIRECT;
|
||||
hp.split_index = splitIndirect.cap(1).toInt(nullptr, 16);
|
||||
HCode.remove(0, splitIndirect.cap(0).length());
|
||||
hp.split_index = deref2.captured(1).toInt(nullptr, 16);
|
||||
HCode.remove(0, deref2.captured(0).length());
|
||||
}
|
||||
}
|
||||
if (HCode.at(0).unicode() != L'@') return {};
|
||||
HCode.remove(0, 1);
|
||||
QRegExp address("^([\\dA-F]+):?");
|
||||
if (address.indexIn(HCode) == -1) return {};
|
||||
hp.address = address.cap(1).toULongLong(nullptr, 16);
|
||||
HCode.remove(address.cap(0));
|
||||
if (HCode.length())
|
||||
|
||||
// @addr[:module[:func]]
|
||||
QStringList addressPieces = HCode.split(":");
|
||||
QRegularExpressionMatch address = QRegularExpression("^@([[:xdigit:]]+)$").match(addressPieces.at(0));
|
||||
if (!address.hasMatch()) return {};
|
||||
hp.address = address.captured(1).toULongLong(nullptr, 16);
|
||||
if (addressPieces.size() > 1)
|
||||
{
|
||||
hp.type |= MODULE_OFFSET;
|
||||
hp.module = Hash(HCode);
|
||||
wcscpy_s<MAX_MODULE_SIZE>(hp.module, addressPieces.at(1).toStdWString().c_str());
|
||||
}
|
||||
if (hp.offset < 0)
|
||||
hp.offset -= 4;
|
||||
if (hp.split < 0)
|
||||
hp.split -= 4;
|
||||
if (addressPieces.size() > 2)
|
||||
{
|
||||
hp.type |= FUNCTION_OFFSET;
|
||||
strcpy_s<MAX_MODULE_SIZE>(hp.function, addressPieces.at(2).toStdString().c_str());
|
||||
}
|
||||
|
||||
// ITH has registers offset by 4 vs AGTH: need this to correct
|
||||
if (hp.offset < 0) hp.offset -= 4;
|
||||
if (hp.split < 0) hp.split -= 4;
|
||||
|
||||
return hp;
|
||||
}
|
||||
|
||||
QString GenerateHCode(HookParam hp, DWORD processId)
|
||||
{
|
||||
QString code = "/H";
|
||||
QString HCode = "/H";
|
||||
QTextStream codeBuilder(&HCode);
|
||||
codeBuilder.setIntegerBase(16);
|
||||
codeBuilder.setNumberFlags(QTextStream::UppercaseDigits);
|
||||
|
||||
if (hp.type & USING_UNICODE)
|
||||
{
|
||||
if (hp.type & USING_STRING)
|
||||
code += "Q";
|
||||
else
|
||||
code += "W";
|
||||
if (hp.type & USING_STRING) codeBuilder << "Q";
|
||||
else codeBuilder << "W";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hp.type & USING_UTF8)
|
||||
code += "V";
|
||||
else if (hp.type & USING_STRING)
|
||||
code += "S";
|
||||
else if (hp.type & BIG_ENDIAN)
|
||||
code += "A";
|
||||
else
|
||||
code += "B";
|
||||
if (hp.type & USING_UTF8) codeBuilder << "V";
|
||||
else if (hp.type & USING_STRING) codeBuilder << "S";
|
||||
else if (hp.type & BIG_ENDIAN) codeBuilder << "A";
|
||||
else codeBuilder << "B";
|
||||
}
|
||||
if (hp.type & NO_CONTEXT)
|
||||
code += "N";
|
||||
if (hp.type & NO_CONTEXT) codeBuilder << "N";
|
||||
|
||||
if (hp.offset < 0) hp.offset += 4;
|
||||
if (hp.split < 0) hp.split += 4;
|
||||
if (hp.offset < 0)
|
||||
code += "-" + QString::number(-hp.offset, 16);
|
||||
else
|
||||
code += QString::number(hp.offset, 16);
|
||||
if (hp.type & DATA_INDIRECT)
|
||||
|
||||
codeBuilder << hp.offset;
|
||||
if (hp.type & DATA_INDIRECT) codeBuilder << "*" << hp.index;
|
||||
if (hp.type & USING_SPLIT) codeBuilder << ":" << hp.split;
|
||||
if (hp.type & SPLIT_INDIRECT) codeBuilder << "*" << hp.split_index;
|
||||
|
||||
// Attempt to make the address relative
|
||||
if (!(hp.type & MODULE_OFFSET))
|
||||
{
|
||||
if (hp.index < 0)
|
||||
code += "*-" + QString::number(-hp.index, 16);
|
||||
else
|
||||
code += "*" + QString::number(hp.index, 16);
|
||||
}
|
||||
if (hp.type & USING_SPLIT)
|
||||
{
|
||||
if (hp.split < 0)
|
||||
code += ":-" + QString::number(-hp.split, 16);
|
||||
else
|
||||
code += ":" + QString::number(hp.split, 16);
|
||||
}
|
||||
if (hp.type & SPLIT_INDIRECT)
|
||||
{
|
||||
if (hp.split_index < 0)
|
||||
code += "*-" + QString::number(-hp.split_index, 16);
|
||||
else
|
||||
code += "*" + QString::number(hp.split_index, 16);
|
||||
}
|
||||
code += "@";
|
||||
QString badCode = (code + QString::number(hp.address, 16)).toUpper();
|
||||
HANDLE processHandle;
|
||||
if (!(processHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))) return badCode;
|
||||
if (!(processHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))) goto fin;
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
if (!VirtualQueryEx(processHandle, (LPCVOID)hp.address, &info, sizeof(info))) return badCode;
|
||||
if (!VirtualQueryEx(processHandle, (LPCVOID)hp.address, &info, sizeof(info))) goto fin;
|
||||
QString moduleName = GetModuleName(processId, (HMODULE)info.AllocationBase);
|
||||
if (moduleName.size() == 0) return badCode;
|
||||
code += QString::number(hp.address - (DWORD)info.AllocationBase, 16) + ":";
|
||||
code = code.toUpper();
|
||||
code += moduleName;
|
||||
return code;
|
||||
if (moduleName.size() == 0) goto fin;
|
||||
hp.type |= MODULE_OFFSET;
|
||||
hp.address -= (uint64_t)info.AllocationBase;
|
||||
wcscpy_s<MAX_MODULE_SIZE>(hp.module, moduleName.toStdWString().c_str());
|
||||
}
|
||||
|
||||
fin:
|
||||
codeBuilder << "@" << hp.address;
|
||||
if (hp.type & MODULE_OFFSET) codeBuilder << ":" << QString::fromWCharArray(hp.module);
|
||||
if (hp.type & FUNCTION_OFFSET) codeBuilder << ":" << hp.function;
|
||||
|
||||
return HCode;
|
||||
}
|
||||
|
||||
QString GenerateRCode(HookParam hp)
|
||||
{
|
||||
QString code = "/R";
|
||||
if (hp.type & USING_UNICODE)
|
||||
code += "Q";
|
||||
else if (hp.type & USING_UTF8)
|
||||
code += "V";
|
||||
else
|
||||
code += "S";
|
||||
if (hp.type & DATA_INDIRECT)
|
||||
code += "*" + QString::number(hp.index, 16);
|
||||
//code += QString::number(hp.offset, 16);
|
||||
code += "@";
|
||||
code += QString::number(hp.address, 16);
|
||||
return code.toUpper();
|
||||
QString RCode = "/R";
|
||||
QTextStream codeBuilder(&RCode);
|
||||
codeBuilder.setIntegerBase(16);
|
||||
codeBuilder.setNumberFlags(QTextStream::UppercaseDigits);
|
||||
|
||||
if (hp.type & USING_UNICODE) codeBuilder << "Q";
|
||||
else if (hp.type & USING_UTF8) codeBuilder << "V";
|
||||
else codeBuilder << "S";
|
||||
|
||||
if (hp.type & DATA_INDIRECT) codeBuilder << "*" << hp.index;
|
||||
|
||||
codeBuilder << "@" << hp.address;
|
||||
|
||||
return RCode;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<HookParam> ParseCode(QString code)
|
||||
{
|
||||
code = code.toUpper();
|
||||
if (code.startsWith("/H")) return ParseHCode(code.remove(0, 2));
|
||||
else if (code.startsWith("/R")) return ParseRCode(code.remove(0, 2));
|
||||
else return {};
|
||||
|
@ -13,7 +13,7 @@ QString GenerateCode(HookParam hp, DWORD processId);
|
||||
|
||||
static QString CodeInfoDump =
|
||||
"Enter hook code\r\n\
|
||||
/H{A|B|W|S|Q|V}[N]data_offset[*deref_offset1][:split_offset[*deref_offset2]]@addr[:module]\r\n\
|
||||
/H{A|B|W|S|Q|V}[N]data_offset[*deref_offset1][:split_offset[*deref_offset2]]@addr[:module[:func]]\r\n\
|
||||
OR\r\n\
|
||||
Enter read code\r\n\
|
||||
/R{S|Q|V}[*deref_offset|0]@addr\r\n\
|
||||
|
@ -4,7 +4,7 @@
|
||||
// 8/23/2013 jichi
|
||||
// Branch: ITH/common.h, rev 128
|
||||
|
||||
enum { MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 0x1000, SHIFT_JIS = 932, MAX_THREAD_COUNT };
|
||||
enum { MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 0x1000, SHIFT_JIS = 932, MAX_THREAD_COUNT = 250, MAX_MODULE_SIZE = 120 };
|
||||
|
||||
// jichi 375/2014: Add offset of pusha/pushad
|
||||
// http://faydoc.tripod.com/cpu/pushad.htm
|
||||
@ -50,8 +50,8 @@ enum HookParamType : unsigned long
|
||||
DATA_INDIRECT = 0x8,
|
||||
USING_SPLIT = 0x10, // aware of split time?
|
||||
SPLIT_INDIRECT = 0x20,
|
||||
MODULE_OFFSET = 0x40, // do hash module, and the address is relative to module
|
||||
//FUNCTION_OFFSET = 0x80, // do hash function, and the address is relative to funccion
|
||||
MODULE_OFFSET = 0x40, // address is relative to module
|
||||
FUNCTION_OFFSET = 0x80, // address is relative to function
|
||||
USING_UTF8 = 0x100,
|
||||
NO_CONTEXT = 0x400,
|
||||
HOOK_EMPTY = 0x800,
|
||||
|
@ -11,12 +11,14 @@ struct HookParam
|
||||
typedef bool(*filter_fun_t)(LPVOID str, DWORD *len, HookParam *hp, BYTE index); // jichi 10/24/2014: Add filter function. Return true if skip the text
|
||||
typedef bool(*hook_fun_t)(DWORD esp, HookParam *hp); // jichi 10/24/2014: Add generic hook function, return false if stop execution.
|
||||
|
||||
uint64_t address; // absolute or relative address
|
||||
uint64_t insertion_address; // absolute address
|
||||
uint64_t address; // absolute or relative address (not changed by TextHook)
|
||||
int offset, // offset of the data in the memory
|
||||
index, // deref_offset1
|
||||
split, // offset of the split character
|
||||
split_index; // deref_offset2
|
||||
DWORD module; // hash of the module
|
||||
wchar_t module[MAX_MODULE_SIZE];
|
||||
char function[MAX_MODULE_SIZE];
|
||||
DWORD type; // flags
|
||||
WORD length_offset; // index of the string length
|
||||
DWORD user_value; // 7/20/2014: jichi additional parameters for PSP games
|
||||
@ -24,8 +26,6 @@ struct HookParam
|
||||
text_fun_t text_fun;
|
||||
filter_fun_t filter_fun;
|
||||
hook_fun_t hook_fun;
|
||||
|
||||
HANDLE readerHandle; // Artikash 8/4/2018: handle for reader thread
|
||||
};
|
||||
|
||||
struct ThreadParam // From hook, used internally by host as well
|
||||
|
@ -40,29 +40,6 @@ namespace { // unnamed
|
||||
0xe9 // jmp @original
|
||||
};
|
||||
|
||||
DWORD Hash(std::wstring module)
|
||||
{
|
||||
DWORD hash = 0;
|
||||
for (auto i : module) hash = _rotr(hash, 7) + i;
|
||||
return hash;
|
||||
}
|
||||
|
||||
//copy original instruction
|
||||
//jmp back
|
||||
DWORD GetModuleBase(DWORD hash)
|
||||
{
|
||||
HMODULE allModules[1000];
|
||||
DWORD size;
|
||||
EnumProcessModules(GetCurrentProcess(), allModules, sizeof(allModules), &size);
|
||||
wchar_t name[MAX_PATH];
|
||||
for (int i = 0; i < size / sizeof(HMODULE); ++i)
|
||||
{
|
||||
GetModuleFileNameW(allModules[i], name, MAX_PATH);
|
||||
_wcslwr(name);
|
||||
if (Hash(wcsrchr(name, L'\\') + 1) == hash) return (DWORD)allModules[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__declspec(naked) // jichi 10/2/2013: No prolog and epilog
|
||||
int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to ensure normal execution even bad hook inserted.
|
||||
@ -76,6 +53,7 @@ namespace { // unnamed
|
||||
retn // jichi 12/13/2013: return near, see: http://stackoverflow.com/questions/1396909/ret-retn-retf-how-to-use-them
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
const BYTE common_hook[] = {
|
||||
0x9c, // push rflags
|
||||
@ -160,7 +138,7 @@ DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn)
|
||||
BYTE pbData[PIPE_BUFFER_SIZE];
|
||||
DWORD dwType = hp.type;
|
||||
|
||||
dwAddr = hp.address;
|
||||
dwAddr = hp.insertion_address;
|
||||
|
||||
/** jichi 12/24/2014
|
||||
* @param addr function address
|
||||
@ -254,19 +232,19 @@ bool TextHook::InsertHookCode()
|
||||
|
||||
bool TextHook::UnsafeInsertHookCode()
|
||||
{
|
||||
if (hp.module && (hp.type & MODULE_OFFSET)) // Map hook offset to real address.
|
||||
{
|
||||
if (DWORD base = GetModuleBase(hp.module)) hp.address += base;
|
||||
if (hp.type & MODULE_OFFSET) // Map hook offset to real address.
|
||||
if (hp.type & FUNCTION_OFFSET)
|
||||
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function)) hp.insertion_address += (uint64_t)function;
|
||||
else return ConsoleOutput("Textractor: UnsafeInsertHookCode: FAILED: function not present"), false;
|
||||
else if (HMODULE moduleBase = GetModuleHandleW(hp.module)) hp.insertion_address += (uint64_t)moduleBase;
|
||||
else return ConsoleOutput("Textractor: UnsafeInsertHookCode: FAILED: module not present"), false;
|
||||
hp.type &= ~MODULE_OFFSET;
|
||||
}
|
||||
|
||||
BYTE* original;
|
||||
insert:
|
||||
if (MH_STATUS err = MH_CreateHook((void*)hp.address, (void*)trampoline, (void**)&original))
|
||||
if (MH_STATUS err = MH_CreateHook((void*)hp.insertion_address, (void*)trampoline, (void**)&original))
|
||||
if (err == MH_ERROR_ALREADY_CREATED)
|
||||
{
|
||||
RemoveHook(hp.address);
|
||||
RemoveHook(hp.insertion_address);
|
||||
goto insert; // FIXME: i'm too lazy to do this properly right now...
|
||||
}
|
||||
else
|
||||
@ -293,7 +271,7 @@ bool TextHook::UnsafeInsertHookCode()
|
||||
//memcpy(trampoline + 46, &sendPtr, sizeof(sendPtr));
|
||||
//memcpy(trampoline + sizeof(common_hook) - 8, &original, sizeof(void*));
|
||||
|
||||
if (MH_EnableHook((void*)hp.address) != MH_OK) return false;
|
||||
if (MH_EnableHook((void*)hp.insertion_address) != MH_OK) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -305,15 +283,15 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
|
||||
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
||||
unsigned int changeCount = 0;
|
||||
int dataLen = 0;
|
||||
const void* currentAddress = (void*)hook->hp.address;
|
||||
const void* currentAddress = (void*)hook->hp.insertion_address;
|
||||
while (true)
|
||||
{
|
||||
if (!IthGetMemoryRange((void*)hook->hp.address, nullptr, nullptr))
|
||||
if (!IthGetMemoryRange((void*)hook->hp.insertion_address, nullptr, nullptr))
|
||||
{
|
||||
ConsoleOutput("Textractor: can't read desired address");
|
||||
break;
|
||||
}
|
||||
if (hook->hp.type & DATA_INDIRECT) currentAddress = *((char**)hook->hp.address + hook->hp.index);
|
||||
if (hook->hp.type & DATA_INDIRECT) currentAddress = *((char**)hook->hp.insertion_address + hook->hp.index);
|
||||
if (!IthGetMemoryRange(currentAddress, nullptr, nullptr))
|
||||
{
|
||||
ConsoleOutput("Textractor: can't read desired address");
|
||||
@ -336,7 +314,7 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
|
||||
else
|
||||
dataLen = strlen((const char*)currentAddress);
|
||||
|
||||
*(ThreadParam*)buffer = { GetCurrentProcessId(), hook->hp.address, 0, 0 };
|
||||
*(ThreadParam*)buffer = { GetCurrentProcessId(), hook->hp.insertion_address, 0, 0 };
|
||||
memcpy(buffer + sizeof(ThreadParam), currentAddress, dataLen + 1);
|
||||
DWORD unused;
|
||||
WriteFile(::hookPipe, buffer, dataLen + sizeof(ThreadParam), &unused, nullptr);
|
||||
@ -349,7 +327,7 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
|
||||
bool TextHook::InsertReadCode()
|
||||
{
|
||||
//RemoveHook(hp.address); // Artikash 8/25/2018: clear existing
|
||||
hp.readerHandle = CreateThread(nullptr, 0, ReaderThread, this, 0, nullptr);
|
||||
readerHandle = CreateThread(nullptr, 0, ReaderThread, this, 0, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -357,6 +335,7 @@ void TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag)
|
||||
{
|
||||
WaitForSingleObject(hmMutex, 0);
|
||||
hp = h;
|
||||
hp.insertion_address = hp.address;
|
||||
hp.type |= set_flag;
|
||||
if (name && name != hook_name) SetHookName(name);
|
||||
ReleaseMutex(hmMutex);
|
||||
@ -364,14 +343,14 @@ void TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag)
|
||||
|
||||
void TextHook::RemoveHookCode()
|
||||
{
|
||||
MH_DisableHook((void*)hp.address);
|
||||
MH_RemoveHook((void*)hp.address);
|
||||
MH_DisableHook((void*)hp.insertion_address);
|
||||
MH_RemoveHook((void*)hp.insertion_address);
|
||||
}
|
||||
|
||||
void TextHook::RemoveReadCode()
|
||||
{
|
||||
TerminateThread(hp.readerHandle, 0);
|
||||
CloseHandle(hp.readerHandle);
|
||||
TerminateThread(readerHandle, 0);
|
||||
CloseHandle(readerHandle);
|
||||
}
|
||||
|
||||
void TextHook::ClearHook()
|
||||
@ -380,7 +359,7 @@ void TextHook::ClearHook()
|
||||
if (hook_name) ConsoleOutput(("Textractor: removing hook: " + std::string(hook_name)).c_str());
|
||||
if (hp.type & DIRECT_READ) RemoveReadCode();
|
||||
else RemoveHookCode();
|
||||
NotifyHookRemove(hp.address);
|
||||
NotifyHookRemove(hp.insertion_address);
|
||||
if (hook_name) delete[] hook_name;
|
||||
memset(this, 0, sizeof(TextHook)); // jichi 11/30/2013: This is the original code of ITH
|
||||
ReleaseMutex(hmMutex);
|
||||
|
@ -30,6 +30,7 @@ public:
|
||||
LPSTR hook_name;
|
||||
int name_length;
|
||||
BYTE trampoline[120];
|
||||
HANDLE readerHandle;
|
||||
|
||||
bool InsertHook();
|
||||
void InitHook(const HookParam &hp, LPCSTR name = 0, WORD set_flag = 0);
|
||||
|
@ -49,7 +49,7 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
|
||||
{
|
||||
::running = false;
|
||||
MH_Uninitialize();
|
||||
for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++) if (man->hp.address) man->ClearHook();
|
||||
for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++) if (man->hp.insertion_address) man->ClearHook();
|
||||
//if (ith_has_section)
|
||||
UnmapViewOfFile(::hookman);
|
||||
|
||||
@ -83,7 +83,7 @@ void NewHook(const HookParam &hp, LPCSTR lpname, DWORD flag)
|
||||
void RemoveHook(uint64_t addr)
|
||||
{
|
||||
for (int i = 0; i < MAX_HOOK; i++)
|
||||
if (abs((long long)(::hookman[i].hp.address - addr)) < 9)
|
||||
if (abs((long long)(::hookman[i].hp.insertion_address - addr)) < 9)
|
||||
{
|
||||
::hookman[i].ClearHook();
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user