add function based offset. rewrite hookparam processing while we're at it

This commit is contained in:
Akash Mozumdar 2018-10-11 12:58:30 -04:00
parent 3b9ca65e39
commit f7e3bbeb02
9 changed files with 149 additions and 166 deletions

View File

@ -234,7 +234,7 @@ namespace Host
WaitForSingleObject(pr.sectionMutex, 0); WaitForSingleObject(pr.sectionMutex, 0);
const TextHook* hooks = (const TextHook*)pr.sectionMap; const TextHook* hooks = (const TextHook*)pr.sectionMap;
for (int i = 0; i < MAX_HOOK; ++i) 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; ret = hooks[i].hp;
ReleaseMutex(pr.sectionMutex); ReleaseMutex(pr.sectionMutex);
return ret; return ret;
@ -252,7 +252,7 @@ namespace Host
WaitForSingleObject(pr.sectionMutex, 0); WaitForSingleObject(pr.sectionMutex, 0);
const TextHook* hooks = (const TextHook*)pr.sectionMap; const TextHook* hooks = (const TextHook*)pr.sectionMap;
for (int i = 0; i < MAX_HOOK; ++i) 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); buffer.resize(hooks[i].name_length);
ReadProcessMemory(pr.processHandle, hooks[i].hook_name, buffer.data(), hooks[i].name_length, nullptr); ReadProcessMemory(pr.processHandle, hooks[i].hook_name, buffer.data(), hooks[i].name_length, nullptr);

View File

@ -157,7 +157,7 @@ std::unordered_map<std::string, int64_t> MainWindow::GetInfoForExtensions(TextTh
QVector<HookParam> MainWindow::GetAllHooks(DWORD processId) QVector<HookParam> MainWindow::GetAllHooks(DWORD processId)
{ {
QSet<DWORD> addresses; QSet<uint64_t> addresses;
QVector<HookParam> hooks; QVector<HookParam> hooks;
for (int i = 0; i < ttCombo->count(); ++i) for (int i = 0; i < ttCombo->count(); ++i)
{ {
@ -208,13 +208,13 @@ void MainWindow::on_unhookButton_clicked()
QStringList hookList; QStringList hookList;
for (auto hook : hooks) for (auto hook : hooks)
hookList.push_back( hookList.push_back(
QString::fromStdWString(Host::GetHookName(GetSelectedProcessId(), hook.address)) + QString::fromStdWString(Host::GetHookName(GetSelectedProcessId(), hook.insertion_address)) +
": " + ": " +
GenerateCode(hook, GetSelectedProcessId()) GenerateCode(hook, GetSelectedProcessId())
); );
bool ok; bool ok;
QString hook = QInputDialog::getItem(this, "Unhook", "Which hook to remove?", hookList, 0, false, &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() void MainWindow::on_saveButton_clicked()

View File

@ -1,7 +1,7 @@
#include "misc.h" #include "misc.h"
#include "const.h" #include "const.h"
#include <QRegExp>
#include <Psapi.h> #include <Psapi.h>
#include <QTextStream>
QString GetFullModuleName(DWORD processId, HMODULE module) QString GetFullModuleName(DWORD processId, HMODULE module)
{ {
@ -32,18 +32,12 @@ QMultiHash<QString, DWORD> GetAllProcesses()
namespace 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) std::optional<HookParam> ParseRCode(QString RCode)
{ {
HookParam hp = {}; HookParam hp = {};
hp.type |= DIRECT_READ; hp.type |= DIRECT_READ;
// {S|Q|V}
switch (RCode.at(0).unicode()) switch (RCode.at(0).unicode())
{ {
case L'S': case L'S':
@ -58,25 +52,32 @@ namespace
return {}; return {};
} }
RCode.remove(0, 1); RCode.remove(0, 1);
if (RCode.at(0).unicode() == L'0') RCode.remove(0, 1);
QRegExp stringGap("^\\*(\\-?[\\dA-F]+)"); // [*deref_offset|0]
if (stringGap.indexIn(RCode) != -1) 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.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 {}; if (RCode.at(0).unicode() != L'@') return {};
RCode.remove(0, 1); RCode.remove(0, 1);
QRegExp address("[\\dA-F]+$");
if (address.indexIn(RCode) == -1) return {}; // @addr
hp.address = address.cap(0).toULongLong(nullptr, 16); QRegularExpressionMatch address = QRegularExpression("^@([[:xdigit:]]+)$").match(RCode);
if (!address.hasMatch()) return {};
hp.address = address.captured(1).toULongLong(nullptr, 16);
return hp; return hp;
} }
std::optional<HookParam> ParseHCode(QString HCode) std::optional<HookParam> ParseHCode(QString HCode)
{ {
HookParam hp = {}; HookParam hp = {};
// {A|B|W|S|Q|V}
switch (HCode.at(0).unicode()) switch (HCode.at(0).unicode())
{ {
case L'S': case L'S':
@ -103,139 +104,141 @@ namespace
return {}; return {};
} }
HCode.remove(0, 1); HCode.remove(0, 1);
// [N]
if (HCode.at(0).unicode() == L'N') if (HCode.at(0).unicode() == L'N')
{ {
hp.type |= NO_CONTEXT; hp.type |= NO_CONTEXT;
HCode.remove(0, 1); HCode.remove(0, 1);
} }
QRegExp dataOffset("^\\-?[\\dA-F]+");
if (dataOffset.indexIn(HCode) == -1) return {}; // data_offset
hp.offset = dataOffset.cap(0).toInt(nullptr, 16); QRegularExpressionMatch dataOffset = QRegularExpression("^\\-?[[:xdigit:]]+").match(HCode);
HCode.remove(0, dataOffset.cap(0).length()); if (!dataOffset.hasMatch()) return {};
QRegExp dataIndirect("^\\*(\\-?[\\dA-F]+)"); hp.offset = dataOffset.captured(0).toInt(nullptr, 16);
if (dataIndirect.indexIn(HCode) != -1) HCode.remove(0, dataOffset.captured(0).length());
// [*deref_offset1]
QRegularExpressionMatch deref1 = QRegularExpression("^\\*(\\-?[[:xdigit:]]+)").match(HCode);
if (deref1.hasMatch())
{ {
hp.type |= DATA_INDIRECT; hp.type |= DATA_INDIRECT;
hp.index = dataIndirect.cap(1).toInt(nullptr, 16); hp.index = deref1.captured(1).toInt(nullptr, 16);
HCode.remove(0, dataIndirect.cap(0).length()); 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.type |= USING_SPLIT;
hp.split = split.cap(1).toInt(nullptr, 16); hp.split = splitOffset.captured(1).toInt(nullptr, 16);
HCode.remove(0, split.cap(0).length()); HCode.remove(0, splitOffset.captured(0).length());
QRegExp splitIndirect("^\\*(\\-?[\\dA-F]+)");
if (splitIndirect.indexIn(HCode) != -1) QRegularExpressionMatch deref2 = QRegularExpression("^\\*(\\-?[[:xdigit:]]+)").match(HCode);
if (deref2.hasMatch())
{ {
hp.type |= SPLIT_INDIRECT; hp.type |= SPLIT_INDIRECT;
hp.split_index = splitIndirect.cap(1).toInt(nullptr, 16); hp.split_index = deref2.captured(1).toInt(nullptr, 16);
HCode.remove(0, splitIndirect.cap(0).length()); HCode.remove(0, deref2.captured(0).length());
} }
} }
if (HCode.at(0).unicode() != L'@') return {};
HCode.remove(0, 1); // @addr[:module[:func]]
QRegExp address("^([\\dA-F]+):?"); QStringList addressPieces = HCode.split(":");
if (address.indexIn(HCode) == -1) return {}; QRegularExpressionMatch address = QRegularExpression("^@([[:xdigit:]]+)$").match(addressPieces.at(0));
hp.address = address.cap(1).toULongLong(nullptr, 16); if (!address.hasMatch()) return {};
HCode.remove(address.cap(0)); hp.address = address.captured(1).toULongLong(nullptr, 16);
if (HCode.length()) if (addressPieces.size() > 1)
{ {
hp.type |= MODULE_OFFSET; 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) if (addressPieces.size() > 2)
hp.offset -= 4; {
if (hp.split < 0) hp.type |= FUNCTION_OFFSET;
hp.split -= 4; 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; return hp;
} }
QString GenerateHCode(HookParam hp, DWORD processId) 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_UNICODE)
{ {
if (hp.type & USING_STRING) if (hp.type & USING_STRING) codeBuilder << "Q";
code += "Q"; else codeBuilder << "W";
else
code += "W";
} }
else else
{ {
if (hp.type & USING_UTF8) if (hp.type & USING_UTF8) codeBuilder << "V";
code += "V"; else if (hp.type & USING_STRING) codeBuilder << "S";
else if (hp.type & USING_STRING) else if (hp.type & BIG_ENDIAN) codeBuilder << "A";
code += "S"; else codeBuilder << "B";
else if (hp.type & BIG_ENDIAN)
code += "A";
else
code += "B";
} }
if (hp.type & NO_CONTEXT) if (hp.type & NO_CONTEXT) codeBuilder << "N";
code += "N";
if (hp.offset < 0) hp.offset += 4; if (hp.offset < 0) hp.offset += 4;
if (hp.split < 0) hp.split += 4; if (hp.split < 0) hp.split += 4;
if (hp.offset < 0)
code += "-" + QString::number(-hp.offset, 16); codeBuilder << hp.offset;
else if (hp.type & DATA_INDIRECT) codeBuilder << "*" << hp.index;
code += QString::number(hp.offset, 16); if (hp.type & USING_SPLIT) codeBuilder << ":" << hp.split;
if (hp.type & DATA_INDIRECT) 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; 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; 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); QString moduleName = GetModuleName(processId, (HMODULE)info.AllocationBase);
if (moduleName.size() == 0) return badCode; if (moduleName.size() == 0) goto fin;
code += QString::number(hp.address - (DWORD)info.AllocationBase, 16) + ":"; hp.type |= MODULE_OFFSET;
code = code.toUpper(); hp.address -= (uint64_t)info.AllocationBase;
code += moduleName; wcscpy_s<MAX_MODULE_SIZE>(hp.module, moduleName.toStdWString().c_str());
return code; }
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 GenerateRCode(HookParam hp)
{ {
QString code = "/R"; QString RCode = "/R";
if (hp.type & USING_UNICODE) QTextStream codeBuilder(&RCode);
code += "Q"; codeBuilder.setIntegerBase(16);
else if (hp.type & USING_UTF8) codeBuilder.setNumberFlags(QTextStream::UppercaseDigits);
code += "V";
else if (hp.type & USING_UNICODE) codeBuilder << "Q";
code += "S"; else if (hp.type & USING_UTF8) codeBuilder << "V";
if (hp.type & DATA_INDIRECT) else codeBuilder << "S";
code += "*" + QString::number(hp.index, 16);
//code += QString::number(hp.offset, 16); if (hp.type & DATA_INDIRECT) codeBuilder << "*" << hp.index;
code += "@";
code += QString::number(hp.address, 16); codeBuilder << "@" << hp.address;
return code.toUpper();
return RCode;
} }
} }
std::optional<HookParam> ParseCode(QString code) std::optional<HookParam> ParseCode(QString code)
{ {
code = code.toUpper();
if (code.startsWith("/H")) return ParseHCode(code.remove(0, 2)); if (code.startsWith("/H")) return ParseHCode(code.remove(0, 2));
else if (code.startsWith("/R")) return ParseRCode(code.remove(0, 2)); else if (code.startsWith("/R")) return ParseRCode(code.remove(0, 2));
else return {}; else return {};

View File

@ -13,7 +13,7 @@ QString GenerateCode(HookParam hp, DWORD processId);
static QString CodeInfoDump = static QString CodeInfoDump =
"Enter hook code\r\n\ "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\ OR\r\n\
Enter read code\r\n\ Enter read code\r\n\
/R{S|Q|V}[*deref_offset|0]@addr\r\n\ /R{S|Q|V}[*deref_offset|0]@addr\r\n\

View File

@ -4,7 +4,7 @@
// 8/23/2013 jichi // 8/23/2013 jichi
// Branch: ITH/common.h, rev 128 // 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 // jichi 375/2014: Add offset of pusha/pushad
// http://faydoc.tripod.com/cpu/pushad.htm // http://faydoc.tripod.com/cpu/pushad.htm
@ -50,8 +50,8 @@ enum HookParamType : unsigned long
DATA_INDIRECT = 0x8, DATA_INDIRECT = 0x8,
USING_SPLIT = 0x10, // aware of split time? USING_SPLIT = 0x10, // aware of split time?
SPLIT_INDIRECT = 0x20, SPLIT_INDIRECT = 0x20,
MODULE_OFFSET = 0x40, // do hash module, and the address is relative to module MODULE_OFFSET = 0x40, // address is relative to module
//FUNCTION_OFFSET = 0x80, // do hash function, and the address is relative to funccion FUNCTION_OFFSET = 0x80, // address is relative to function
USING_UTF8 = 0x100, USING_UTF8 = 0x100,
NO_CONTEXT = 0x400, NO_CONTEXT = 0x400,
HOOK_EMPTY = 0x800, HOOK_EMPTY = 0x800,

View File

@ -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(*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. 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 int offset, // offset of the data in the memory
index, // deref_offset1 index, // deref_offset1
split, // offset of the split character split, // offset of the split character
split_index; // deref_offset2 split_index; // deref_offset2
DWORD module; // hash of the module wchar_t module[MAX_MODULE_SIZE];
char function[MAX_MODULE_SIZE];
DWORD type; // flags DWORD type; // flags
WORD length_offset; // index of the string length WORD length_offset; // index of the string length
DWORD user_value; // 7/20/2014: jichi additional parameters for PSP games DWORD user_value; // 7/20/2014: jichi additional parameters for PSP games
@ -24,8 +26,6 @@ struct HookParam
text_fun_t text_fun; text_fun_t text_fun;
filter_fun_t filter_fun; filter_fun_t filter_fun;
hook_fun_t hook_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 struct ThreadParam // From hook, used internally by host as well

View File

@ -40,29 +40,6 @@ namespace { // unnamed
0xe9 // jmp @original 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 __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. 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 retn // jichi 12/13/2013: return near, see: http://stackoverflow.com/questions/1396909/ret-retn-retf-how-to-use-them
} }
} }
#else #else
const BYTE common_hook[] = { const BYTE common_hook[] = {
0x9c, // push rflags 0x9c, // push rflags
@ -160,7 +138,7 @@ DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn)
BYTE pbData[PIPE_BUFFER_SIZE]; BYTE pbData[PIPE_BUFFER_SIZE];
DWORD dwType = hp.type; DWORD dwType = hp.type;
dwAddr = hp.address; dwAddr = hp.insertion_address;
/** jichi 12/24/2014 /** jichi 12/24/2014
* @param addr function address * @param addr function address
@ -254,19 +232,19 @@ bool TextHook::InsertHookCode()
bool TextHook::UnsafeInsertHookCode() bool TextHook::UnsafeInsertHookCode()
{ {
if (hp.module && (hp.type & MODULE_OFFSET)) // Map hook offset to real address. if (hp.type & MODULE_OFFSET) // Map hook offset to real address.
{ if (hp.type & FUNCTION_OFFSET)
if (DWORD base = GetModuleBase(hp.module)) hp.address += base; 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; else return ConsoleOutput("Textractor: UnsafeInsertHookCode: FAILED: module not present"), false;
hp.type &= ~MODULE_OFFSET;
}
BYTE* original; BYTE* original;
insert: 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) 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... goto insert; // FIXME: i'm too lazy to do this properly right now...
} }
else else
@ -293,7 +271,7 @@ bool TextHook::UnsafeInsertHookCode()
//memcpy(trampoline + 46, &sendPtr, sizeof(sendPtr)); //memcpy(trampoline + 46, &sendPtr, sizeof(sendPtr));
//memcpy(trampoline + sizeof(common_hook) - 8, &original, sizeof(void*)); //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; return true;
} }
@ -305,15 +283,15 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
BYTE buffer[PIPE_BUFFER_SIZE] = {}; BYTE buffer[PIPE_BUFFER_SIZE] = {};
unsigned int changeCount = 0; unsigned int changeCount = 0;
int dataLen = 0; int dataLen = 0;
const void* currentAddress = (void*)hook->hp.address; const void* currentAddress = (void*)hook->hp.insertion_address;
while (true) 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"); ConsoleOutput("Textractor: can't read desired address");
break; 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)) if (!IthGetMemoryRange(currentAddress, nullptr, nullptr))
{ {
ConsoleOutput("Textractor: can't read desired address"); ConsoleOutput("Textractor: can't read desired address");
@ -336,7 +314,7 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
else else
dataLen = strlen((const char*)currentAddress); 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); memcpy(buffer + sizeof(ThreadParam), currentAddress, dataLen + 1);
DWORD unused; DWORD unused;
WriteFile(::hookPipe, buffer, dataLen + sizeof(ThreadParam), &unused, nullptr); WriteFile(::hookPipe, buffer, dataLen + sizeof(ThreadParam), &unused, nullptr);
@ -349,7 +327,7 @@ DWORD WINAPI ReaderThread(LPVOID hookPtr)
bool TextHook::InsertReadCode() bool TextHook::InsertReadCode()
{ {
//RemoveHook(hp.address); // Artikash 8/25/2018: clear existing //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; return true;
} }
@ -357,6 +335,7 @@ void TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag)
{ {
WaitForSingleObject(hmMutex, 0); WaitForSingleObject(hmMutex, 0);
hp = h; hp = h;
hp.insertion_address = hp.address;
hp.type |= set_flag; hp.type |= set_flag;
if (name && name != hook_name) SetHookName(name); if (name && name != hook_name) SetHookName(name);
ReleaseMutex(hmMutex); ReleaseMutex(hmMutex);
@ -364,14 +343,14 @@ void TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag)
void TextHook::RemoveHookCode() void TextHook::RemoveHookCode()
{ {
MH_DisableHook((void*)hp.address); MH_DisableHook((void*)hp.insertion_address);
MH_RemoveHook((void*)hp.address); MH_RemoveHook((void*)hp.insertion_address);
} }
void TextHook::RemoveReadCode() void TextHook::RemoveReadCode()
{ {
TerminateThread(hp.readerHandle, 0); TerminateThread(readerHandle, 0);
CloseHandle(hp.readerHandle); CloseHandle(readerHandle);
} }
void TextHook::ClearHook() void TextHook::ClearHook()
@ -380,7 +359,7 @@ void TextHook::ClearHook()
if (hook_name) ConsoleOutput(("Textractor: removing hook: " + std::string(hook_name)).c_str()); if (hook_name) ConsoleOutput(("Textractor: removing hook: " + std::string(hook_name)).c_str());
if (hp.type & DIRECT_READ) RemoveReadCode(); if (hp.type & DIRECT_READ) RemoveReadCode();
else RemoveHookCode(); else RemoveHookCode();
NotifyHookRemove(hp.address); NotifyHookRemove(hp.insertion_address);
if (hook_name) delete[] hook_name; if (hook_name) delete[] hook_name;
memset(this, 0, sizeof(TextHook)); // jichi 11/30/2013: This is the original code of ITH memset(this, 0, sizeof(TextHook)); // jichi 11/30/2013: This is the original code of ITH
ReleaseMutex(hmMutex); ReleaseMutex(hmMutex);

View File

@ -30,6 +30,7 @@ public:
LPSTR hook_name; LPSTR hook_name;
int name_length; int name_length;
BYTE trampoline[120]; BYTE trampoline[120];
HANDLE readerHandle;
bool InsertHook(); bool InsertHook();
void InitHook(const HookParam &hp, LPCSTR name = 0, WORD set_flag = 0); void InitHook(const HookParam &hp, LPCSTR name = 0, WORD set_flag = 0);

View File

@ -49,7 +49,7 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
{ {
::running = false; ::running = false;
MH_Uninitialize(); 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) //if (ith_has_section)
UnmapViewOfFile(::hookman); UnmapViewOfFile(::hookman);
@ -83,7 +83,7 @@ void NewHook(const HookParam &hp, LPCSTR lpname, DWORD flag)
void RemoveHook(uint64_t addr) void RemoveHook(uint64_t addr)
{ {
for (int i = 0; i < MAX_HOOK; i++) 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(); ::hookman[i].ClearHook();
return; return;