reorganize, everything

This commit is contained in:
Akash Mozumdar 2018-08-23 11:53:23 -04:00
parent 98649ffbcc
commit 446ff71464
52 changed files with 579 additions and 836 deletions

View File

@ -2,7 +2,6 @@
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "extensions.h" #include "extensions.h"
#include "misc.h" #include "misc.h"
#include "../vnrhook/include/const.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QInputDialog> #include <QInputDialog>
#include <QFileDialog> #include <QFileDialog>
@ -78,9 +77,9 @@ void MainWindow::AddThread(TextThread* thread)
{ {
ttCombo->addItem( ttCombo->addItem(
TextThreadString(thread) + TextThreadString(thread) +
QString::fromStdWString(Host::GetHookName(thread->GetThreadParameter().pid, thread->GetThreadParameter().hook)) + QString::fromStdWString(Host::GetHookName(thread->GetThreadParam().pid, thread->GetThreadParam().hook)) +
" (" + " (" +
GenerateCode(Host::GetHookParam(thread->GetThreadParameter()), thread->GetThreadParameter().pid) + GenerateCode(Host::GetHookParam(thread->GetThreadParam()), thread->GetThreadParam().pid) +
")" ")"
); );
thread->RegisterOutputCallBack([&](TextThread* thread, std::wstring output) thread->RegisterOutputCallBack([&](TextThread* thread, std::wstring output)
@ -116,7 +115,7 @@ void MainWindow::ThreadOutput(TextThread* thread, QString output)
QString MainWindow::TextThreadString(TextThread* thread) QString MainWindow::TextThreadString(TextThread* thread)
{ {
ThreadParameter tp = thread->GetThreadParameter(); ThreadParam tp = thread->GetThreadParam();
return QString("%1:%2:%3:%4: ").arg( return QString("%1:%2:%3:%4: ").arg(
QString::number(tp.pid), QString::number(tp.pid),
QString::number(tp.hook, 16), QString::number(tp.hook, 16),
@ -125,7 +124,7 @@ QString MainWindow::TextThreadString(TextThread* thread)
).toUpper(); ).toUpper();
} }
ThreadParameter MainWindow::ParseTextThreadString(QString textThreadString) ThreadParam MainWindow::ParseTextThreadString(QString textThreadString)
{ {
QStringList threadParam = textThreadString.split(":"); QStringList threadParam = textThreadString.split(":");
return { threadParam[0].toUInt(), threadParam[1].toULongLong(nullptr, 16), threadParam[2].toULongLong(nullptr, 16), threadParam[3].toULongLong(nullptr, 16) }; return { threadParam[0].toUInt(), threadParam[1].toULongLong(nullptr, 16), threadParam[2].toULongLong(nullptr, 16), threadParam[3].toULongLong(nullptr, 16) };
@ -149,9 +148,9 @@ std::unordered_map<std::string, int> MainWindow::GetInfoForExtensions(TextThread
{ {
{ "current select", (int)ttCombo->currentText().startsWith(TextThreadString(thread)) }, { "current select", (int)ttCombo->currentText().startsWith(TextThreadString(thread)) },
{ "text number", 0 }, { "text number", 0 },
{ "process id", thread->GetThreadParameter().pid }, { "process id", thread->GetThreadParam().pid },
{ "hook address", (int)thread->GetThreadParameter().hook }, { "hook address", (int)thread->GetThreadParam().hook },
{ "hook address (upper 32 bits)", (int)(thread->GetThreadParameter().hook >> 32) } { "hook address (upper 32 bits)", (int)(thread->GetThreadParam().hook >> 32) }
}; };
} }
@ -161,7 +160,7 @@ QVector<HookParam> MainWindow::GetAllHooks(DWORD processId)
QVector<HookParam> hooks; QVector<HookParam> hooks;
for (int i = 0; i < ttCombo->count(); ++i) for (int i = 0; i < ttCombo->count(); ++i)
{ {
ThreadParameter tp = ParseTextThreadString(ttCombo->itemText(i)); ThreadParam tp = ParseTextThreadString(ttCombo->itemText(i));
if (tp.pid == processId && !addresses.contains(tp.hook)) if (tp.pid == processId && !addresses.contains(tp.hook))
{ {
addresses.insert(tp.hook); addresses.insert(tp.hook);

View File

@ -44,7 +44,7 @@ private slots:
private: private:
QString TextThreadString(TextThread* thread); QString TextThreadString(TextThread* thread);
ThreadParameter ParseTextThreadString(QString textThreadString); ThreadParam ParseTextThreadString(QString textThreadString);
DWORD GetSelectedProcessId(); DWORD GetSelectedProcessId();
void ReloadExtensions(); void ReloadExtensions();
std::unordered_map<std::string, int> GetInfoForExtensions(TextThread* thread); std::unordered_map<std::string, int> GetInfoForExtensions(TextThread* thread);

View File

@ -1,5 +1,5 @@
#include "misc.h" #include "misc.h"
#include "../vnrhook/include/const.h" #include "const.h"
#include <QRegExp> #include <QRegExp>
#include <Psapi.h> #include <Psapi.h>

View File

@ -2,7 +2,7 @@
#define MISC_H #define MISC_H
#include "qtcommon.h" #include "qtcommon.h"
#include "../host/host.h" #include "pipe.h"
QString GetFullModuleName(DWORD processId, HMODULE module = NULL); QString GetFullModuleName(DWORD processId, HMODULE module = NULL);
QString GetModuleName(DWORD processId, HMODULE module = NULL); QString GetModuleName(DWORD processId, HMODULE module = NULL);

View File

@ -1,8 +1,4 @@
set(vnrhost_src set(vnrhost_src
host.h
pipe.h
textthread.h
winmutex.h
host.cc host.cc
pipe.cc pipe.cc
textthread.cc textthread.cc

View File

@ -4,21 +4,33 @@
#include "host.h" #include "host.h"
#include "pipe.h" #include "pipe.h"
#include "winmutex.h" #include "const.h"
#include "../vnrhook/include/const.h" #include "defs.h"
#include "../vnrhook/include/defs.h" #include "../vnrhook/hijack/texthook.h"
#include "../vnrhook/include/types.h"
struct ProcessRecord
struct ThreadParameterHasher
{ {
size_t operator()(const ThreadParameter& tp) const HANDLE processHandle;
{ HANDLE sectionMutex;
return std::hash<__int64>()(tp.pid << 6) + std::hash<__int64>()(tp.hook) + std::hash<__int64>()(tp.retn) + std::hash<__int64>()(tp.spl); HANDLE section;
} LPVOID sectionMap;
HANDLE hostPipe;
}; };
std::unordered_map<ThreadParameter, TextThread*, ThreadParameterHasher> textThreadsByParams; // Artikash 5/31/2018: required for unordered_map to work with struct key
template <> struct std::hash<ThreadParam> { size_t operator()(const ThreadParam& tp) const { return std::hash<__int64>()((tp.pid + tp.hook) ^ (tp.retn + tp.spl)); } };
bool operator==(const ThreadParam& one, const ThreadParam& two) { return memcmp(&one, &two, sizeof(ThreadParam)) == 0; }
// Artikash 7/20/2018: similar to std::lock guard but use Winapi objects for cross process comms
class MutexLocker
{
HANDLE mutex;
public:
MutexLocker(HANDLE mutex) : mutex(mutex) { WaitForSingleObject(mutex, 0); }
~MutexLocker() { if (mutex != INVALID_HANDLE_VALUE && mutex != nullptr) ReleaseMutex(mutex); }
};
std::unordered_map<ThreadParam, TextThread*> textThreadsByParams;
std::unordered_map<DWORD, ProcessRecord> processRecordsByIds; std::unordered_map<DWORD, ProcessRecord> processRecordsByIds;
std::recursive_mutex hostMutex; std::recursive_mutex hostMutex;
@ -28,7 +40,7 @@ ProcessEventCallback OnAttach, OnDetach;
DWORD DUMMY[100]; DWORD DUMMY[100];
ThreadParameter CONSOLE{ 0, -1UL, -1UL, -1UL }; ThreadParam CONSOLE{ 0, -1ULL, -1ULL, -1ULL };
#define HOST_LOCK std::lock_guard<std::recursive_mutex> hostLocker(hostMutex) // Synchronized scope for accessing private data #define HOST_LOCK std::lock_guard<std::recursive_mutex> hostLocker(hostMutex) // Synchronized scope for accessing private data
@ -38,7 +50,7 @@ namespace Host
{ {
OnAttach = onAttach; OnDetach = onDetach; OnCreate = onCreate; OnRemove = onRemove; OnAttach = onAttach; OnDetach = onDetach; OnCreate = onCreate; OnRemove = onRemove;
OnCreate(textThreadsByParams[CONSOLE] = new TextThread(CONSOLE, USING_UNICODE)); OnCreate(textThreadsByParams[CONSOLE] = new TextThread(CONSOLE, USING_UNICODE));
CreateNewPipe(); CreatePipe();
} }
DLLEXPORT void Close() DLLEXPORT void Close()
@ -102,25 +114,20 @@ namespace Host
DLLEXPORT bool DetachProcess(DWORD processId) DLLEXPORT bool DetachProcess(DWORD processId)
{ {
DWORD command = HOST_COMMAND_DETACH; int command = HOST_COMMAND_DETACH;
return WriteFile(processRecordsByIds[processId].hostPipe, &command, sizeof(command), DUMMY, nullptr); return WriteFile(processRecordsByIds[processId].hostPipe, &command, sizeof(command), DUMMY, nullptr);
} }
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name) DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name)
{ {
BYTE buffer[PIPE_BUFFER_SIZE] = {}; auto info = InsertHookCmd(hp, name);
*(DWORD*)buffer = HOST_COMMAND_NEW_HOOK; return WriteFile(processRecordsByIds[pid].hostPipe, &info, sizeof(info), DUMMY, nullptr);
*(HookParam*)(buffer + sizeof(DWORD)) = hp;
if (name.size()) strcpy((char*)buffer + sizeof(DWORD) + sizeof(HookParam), name.c_str());
return WriteFile(processRecordsByIds[pid].hostPipe, buffer, sizeof(DWORD) + sizeof(HookParam) + name.size(), DUMMY, nullptr);
} }
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr) DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr)
{ {
BYTE buffer[sizeof(DWORD) * 2] = {}; auto info = RemoveHookCmd(addr);
*(DWORD*)buffer = HOST_COMMAND_REMOVE_HOOK; return WriteFile(processRecordsByIds[pid].hostPipe, &info, sizeof(info), DUMMY, nullptr);
*(DWORD*)(buffer + sizeof(DWORD)) = addr;
return WriteFile(processRecordsByIds[pid].hostPipe, buffer, sizeof(DWORD) * 2, DUMMY, nullptr);
} }
DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr) DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr)
@ -130,14 +137,14 @@ namespace Host
ProcessRecord pr = processRecordsByIds[pid]; ProcessRecord pr = processRecordsByIds[pid];
if (pr.sectionMap == nullptr) return ret; if (pr.sectionMap == nullptr) return ret;
MutexLocker locker(pr.sectionMutex); MutexLocker locker(pr.sectionMutex);
const Hook* hooks = (const Hook*)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 ((DWORD)hooks[i].Address() == addr) if ((DWORD)hooks[i].Address() == addr)
ret = hooks[i].hp; ret = hooks[i].hp;
return ret; return ret;
} }
DLLEXPORT HookParam GetHookParam(ThreadParameter tp) { return GetHookParam(tp.pid, tp.hook); } DLLEXPORT HookParam GetHookParam(ThreadParam tp) { return GetHookParam(tp.pid, tp.hook); }
DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr) DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr)
{ {
@ -147,7 +154,7 @@ namespace Host
ProcessRecord pr = processRecordsByIds[pid]; ProcessRecord pr = processRecordsByIds[pid];
if (pr.sectionMap == nullptr) return L""; if (pr.sectionMap == nullptr) return L"";
MutexLocker locker(pr.sectionMutex); MutexLocker locker(pr.sectionMutex);
const Hook* hooks = (const Hook*)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 ((DWORD)hooks[i].Address() == addr) if ((DWORD)hooks[i].Address() == addr)
{ {
@ -158,7 +165,7 @@ namespace Host
return std::wstring(A2W(buffer.c_str())); return std::wstring(A2W(buffer.c_str()));
} }
DLLEXPORT TextThread* GetThread(ThreadParameter tp) DLLEXPORT TextThread* GetThread(ThreadParam tp)
{ {
HOST_LOCK; HOST_LOCK;
return textThreadsByParams[tp]; return textThreadsByParams[tp];
@ -171,7 +178,7 @@ namespace Host
} }
} }
void DispatchText(ThreadParameter tp, const BYTE* text, int len) void DispatchText(ThreadParam tp, const BYTE* text, int len)
{ {
if (!text || len <= 0) return; if (!text || len <= 0) return;
HOST_LOCK; HOST_LOCK;
@ -181,10 +188,10 @@ void DispatchText(ThreadParameter tp, const BYTE* text, int len)
it->AddText(text, len); it->AddText(text, len);
} }
void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp) void RemoveThreads(bool(*RemoveIf)(ThreadParam, ThreadParam), ThreadParam cmp)
{ {
HOST_LOCK; HOST_LOCK;
std::vector<ThreadParameter> removedThreads; std::vector<ThreadParam> removedThreads;
for (auto i : textThreadsByParams) for (auto i : textThreadsByParams)
if (RemoveIf(i.first, cmp)) if (RemoveIf(i.first, cmp))
{ {

View File

@ -6,19 +6,9 @@
#include "common.h" #include "common.h"
#include "textthread.h" #include "textthread.h"
#include "../vnrhook/include/types.h"
#define DLLEXPORT __declspec(dllexport) #define DLLEXPORT __declspec(dllexport)
struct ProcessRecord
{
HANDLE processHandle;
HANDLE sectionMutex;
HANDLE section;
LPVOID sectionMap;
HANDLE hostPipe;
};
typedef std::function<void(DWORD)> ProcessEventCallback; typedef std::function<void(DWORD)> ProcessEventCallback;
typedef std::function<void(TextThread*)> ThreadEventCallback; typedef std::function<void(TextThread*)> ThreadEventCallback;
@ -32,15 +22,15 @@ namespace Host
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name = ""); DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name = "");
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr); DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr);
DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr); DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr);
DLLEXPORT HookParam GetHookParam(ThreadParameter tp); DLLEXPORT HookParam GetHookParam(ThreadParam tp);
DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr); DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr);
DLLEXPORT TextThread* GetThread(ThreadParameter tp); DLLEXPORT TextThread* GetThread(ThreadParam tp);
DLLEXPORT void AddConsoleOutput(std::wstring text); DLLEXPORT void AddConsoleOutput(std::wstring text);
} }
void DispatchText(ThreadParameter tp, const BYTE *text, int len); void DispatchText(ThreadParam tp, const BYTE *text, int len);
void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp); void RemoveThreads(bool(*RemoveIf)(ThreadParam, ThreadParam), ThreadParam cmp);
void RegisterProcess(DWORD pid, HANDLE hostPipe); void RegisterProcess(DWORD pid, HANDLE hostPipe);
void UnregisterProcess(DWORD pid); void UnregisterProcess(DWORD pid);

View File

@ -4,10 +4,10 @@
#include "pipe.h" #include "pipe.h"
#include "host.h" #include "host.h"
#include "../vnrhook/include/defs.h" #include "defs.h"
#include "../vnrhook/include/const.h" #include "const.h"
void CreateNewPipe() void CreatePipe()
{ {
std::thread([]() std::thread([]()
{ {
@ -17,7 +17,7 @@ void CreateNewPipe()
// jichi 9/27/2013: why recursion? // jichi 9/27/2013: why recursion?
// Artikash 5/20/2018: Easy way to create a new pipe for another process // Artikash 5/20/2018: Easy way to create a new pipe for another process
CreateNewPipe(); CreatePipe();
BYTE buffer[PIPE_BUFFER_SIZE + 1] = {}; BYTE buffer[PIPE_BUFFER_SIZE + 1] = {};
DWORD bytesRead, processId; DWORD bytesRead, processId;
@ -25,35 +25,30 @@ void CreateNewPipe()
RegisterProcess(processId, hostPipe); RegisterProcess(processId, hostPipe);
while (ReadFile(hookPipe, buffer, PIPE_BUFFER_SIZE, &bytesRead, nullptr)) while (ReadFile(hookPipe, buffer, PIPE_BUFFER_SIZE, &bytesRead, nullptr))
{ switch (*(int*)buffer)
buffer[bytesRead] = 0; {
buffer[bytesRead + 1] = 0; //case HOST_NOTIFICATION_NEWHOOK: // Artikash 7/18/2018: Useless for now, but could be used to implement smth later
//break;
if (*(DWORD*)buffer == HOST_NOTIFICATION) case HOST_NOTIFICATION_RMVHOOK:
switch (*(DWORD*)(buffer + sizeof(DWORD))) // Artikash 7/17/2018: Notification type {
{ auto info = *(HookRemovedNotif*)buffer;
case HOST_NOTIFICATION_NEWHOOK: // Artikash 7/18/2018: Useless for now, but could be used to implement smth later RemoveThreads([](auto one, auto two) { return one.pid == two.pid && one.hook == two.hook; }, { processId, info.address });
break; }
case HOST_NOTIFICATION_RMVHOOK: break;
RemoveThreads([](auto one, auto two) { return one.pid == two.pid && one.hook == two.hook; }, case HOST_NOTIFICATION_TEXT:
{ processId, *(DWORD*)(buffer + sizeof(DWORD) * 2) }); // Address {
break; auto info = *(ConsoleOutputNotif*)buffer;
case HOST_NOTIFICATION_TEXT: USES_CONVERSION;
USES_CONVERSION; Host::AddConsoleOutput(A2W(info.message));
Host::AddConsoleOutput(A2W((LPCSTR)(buffer + sizeof(DWORD) * 2))); // Text }
break; break;
} default:
else DispatchText( {
{ ThreadParam tp = *(ThreadParam*)buffer;
processId, DispatchText(tp, buffer + sizeof(tp), bytesRead - sizeof(tp));
*(DWORD*)buffer, // Hook address }
*(DWORD*)(buffer + sizeof(DWORD)), // Return address break;
*(DWORD*)(buffer + sizeof(DWORD) * 2) // Split }
},
buffer + HEADER_SIZE, // Data
bytesRead - HEADER_SIZE // Data size
);
}
DisconnectNamedPipe(hookPipe); DisconnectNamedPipe(hookPipe);
DisconnectNamedPipe(hostPipe); DisconnectNamedPipe(hostPipe);

View File

@ -1,10 +0,0 @@
#pragma once
// pipe.h
// 7/19/2018 Artikash
#include "common.h"
void CreateNewPipe();
// EOF

View File

@ -1,16 +1,13 @@
// textthread.cc // textthread.cc
// 8/24/2013 jichi // 8/24/2013 jichi
// Branch IHF/TextThread.cpp, rev 133 // Branch IHF/TextThread.cpp, rev 133
#ifdef _MSC_VER
# pragma warning (disable:4100) // C4100: unreference formal parameter
#endif // _MSC_VER
#include "textthread.h" #include "textthread.h"
#include "../vnrhook/include/const.h" #include "const.h"
#define TT_LOCK std::lock_guard<std::recursive_mutex> ttLocker(ttMutex) // Synchronized scope for accessing private data #define TT_LOCK std::lock_guard<std::recursive_mutex> ttLocker(ttMutex) // Synchronized scope for accessing private data
TextThread::TextThread(ThreadParameter tp, DWORD status) : TextThread::TextThread(ThreadParam tp, DWORD status) :
deletionEvent(CreateEventW(nullptr, FALSE, FALSE, NULL)), deletionEvent(CreateEventW(nullptr, FALSE, FALSE, NULL)),
flushThread([&]() { while (WaitForSingleObject(deletionEvent, 100), Flush()); }), flushThread([&]() { while (WaitForSingleObject(deletionEvent, 100), Flush()); }),
timestamp(GetTickCount()), timestamp(GetTickCount()),

View File

@ -5,34 +5,18 @@
// Branch: ITH/TextThread.h, rev 120 // Branch: ITH/TextThread.h, rev 120
#include "common.h" #include "common.h"
#include "pipe.h"
struct ThreadParameter
{
DWORD pid; // jichi: 5/11/2014: The process ID
unsigned __int64 hook; // Artikash 6/6/2018: The insertion address of the hook
unsigned __int64 retn; // jichi 5/11/2014: The return address of the hook
unsigned __int64 spl; // jichi 5/11/2014: the processed split value of the hook paramete
// Artikash 5/31/2018: required for unordered_map to work with struct key
friend bool operator==(const ThreadParameter& one, const ThreadParameter& two)
{
return one.pid == two.pid && one.hook == two.hook && one.retn == two.retn && one.spl == two.spl;
}
};
class TextThread;
typedef std::function<std::wstring(TextThread*, std::wstring)> ThreadOutputCallback;
//extern DWORD split_time,repeat_count,global_filter,cyclic_remove;
class TextThread class TextThread
{ {
typedef std::function<std::wstring(TextThread*, std::wstring)> ThreadOutputCallback;
public: public:
TextThread(ThreadParameter tp, DWORD status); TextThread(ThreadParam tp, DWORD status);
virtual ~TextThread(); virtual ~TextThread();
virtual std::wstring GetStore(); virtual std::wstring GetStore();
ThreadParameter GetThreadParameter() { return tp; } ThreadParam GetThreadParam() { return tp; }
void RegisterOutputCallBack(ThreadOutputCallback cb) { Output = cb; } void RegisterOutputCallBack(ThreadOutputCallback cb) { Output = cb; }
@ -50,7 +34,7 @@ private:
DWORD timestamp; DWORD timestamp;
ThreadOutputCallback Output; ThreadOutputCallback Output;
ThreadParameter tp; ThreadParam tp;
DWORD status; DWORD status;
}; };

View File

@ -1,18 +0,0 @@
#pragma once
// winmutex.h
// 12/11/2011 jichi
#include <windows.h>
#include "common.h"
// Artikash 7/20/2018: similar to std::lock guard but use Winapi objects for cross process comms
class MutexLocker
{
HANDLE mutex;
public:
MutexLocker(HANDLE mutex) : mutex(mutex) { WaitForSingleObject(mutex, 0); }
~MutexLocker() { if (mutex != INVALID_HANDLE_VALUE && mutex != nullptr) ReleaseMutex(mutex); }
};
// EOF

64
include/const.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
// vnrhook/const.h
// 8/23/2013 jichi
// Branch: ITH/common.h, rev 128
enum { MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 0x1000 };
// jichi 375/2014: Add offset of pusha/pushad
// http://faydoc.tripod.com/cpu/pushad.htm
// http://agth.wikia.com/wiki/Cheat_Engine_AGTH_Tutorial
//
// Warning: The offset in ITH has -4 offset comparing to pusha and AGTH
enum pusha_off
{
pusha_eax_off = -0x4,
pusha_ecx_off = -0x8,
pusha_edx_off = -0xc,
pusha_ebx_off = -0x10,
pusha_esp_off = -0x14,
pusha_ebp_off = -0x18,
pusha_esi_off = -0x1c,
pusha_edi_off = -0x20,
pusha_off = -0x24 // pushad offset
};
enum HostCommandType
{
HOST_COMMAND = -1, // null type
HOST_COMMAND_NEW_HOOK = 0,
HOST_COMMAND_REMOVE_HOOK = 1,
HOST_COMMAND_MODIFY_HOOK = 2,
HOST_COMMAND_HIJACK_PROCESS = 3,
HOST_COMMAND_DETACH = 4
};
enum HostNotificationType
{
HOST_NOTIFICATION = -1, // null type
HOST_NOTIFICATION_TEXT = 0,
HOST_NOTIFICATION_NEWHOOK = 1,
HOST_NOTIFICATION_RMVHOOK = 2
};
enum HookParamType : unsigned long
{
USING_STRING = 0x1, // type(data) is char* or wchar_t* and has length
USING_UNICODE = 0x2, // type(data) is wchar_t or wchar_t*
BIG_ENDIAN = 0x4, // type(data) is char
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
USING_UTF8 = 0x100,
NO_CONTEXT = 0x400,
HOOK_EMPTY = 0x800,
FIXING_SPLIT = 0x1000,
DIRECT_READ = 0x2000, // /R read code instead of classic /H hook code
HOOK_ENGINE = 0x4000,
HOOK_ADDITIONAL = 0x8000
};
enum { FIXED_SPLIT_VALUE = 0x10001 }; // 6/1/2014: Fixed split value for hok parameter. Fuse all threads, and prevent floating

View File

@ -3,16 +3,6 @@
// vnrhook/defs.h // vnrhook/defs.h
// 8/23/2013 jichi // 8/23/2013 jichi
// DLL files
//#define ITH_SERVER_DLL L"vnrsrv.dll"
//#define ITH_CLIENT_DLL L"vnrcli.dll"
//#define ITH_CLIENT_XP_DLL L"vnrclixp.dll"
////#define ITH_CLIENT_UX_DLL L"vnrcliux.dll"
//#define ITH_ENGINE_DLL L"vnreng.dll"
//#define ITH_ENGINE_XP_DLL L"vnrengxp.dll"
//#define ITH_ENGINE_UX_DLL L"vnrengux.dll"
#define ITH_DLL L"vnrhook.dll" #define ITH_DLL L"vnrhook.dll"
// Pipes // Pipes

70
include/pipe.h Normal file
View File

@ -0,0 +1,70 @@
#pragma once
#include "common.h"
#include "const.h"
void CreatePipe();
// jichi 3/7/2014: Add guessed comment
struct HookParam
{
// jichi 8/24/2013: For special hooks.
typedef void(*text_fun_t)(DWORD esp, HookParam *hp, BYTE index, DWORD *data, DWORD *split, DWORD *len);
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.
unsigned __int64 address; // absolute or relative address
short 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
DWORD type; // flags
WORD length_offset; // index of the string length
DWORD user_value; // 7/20/2014: jichi additional parameters for PSP games
text_fun_t text_fun;
filter_fun_t filter_fun;
hook_fun_t hook_fun;
BYTE hook_len, // ?
recover_len; // ?
HANDLE readerHandle; // Artikash 8/4/2018: handle for reader thread
};
struct ThreadParam // From hook
{
DWORD pid; // jichi: 5/11/2014: The process ID
unsigned __int64 hook; // Artikash 6/6/2018: The insertion address of the hook
unsigned __int64 retn; // jichi 5/11/2014: The return address of the hook
unsigned __int64 spl; // jichi 5/11/2014: the processed split value of the hook paramete
};
struct InsertHookCmd // From host
{
InsertHookCmd(HookParam hp, std::string name = "") : hp(hp) { strncpy(this->name, name.c_str(), 500); };
int command = HOST_COMMAND_NEW_HOOK;
HookParam hp;
char name[MESSAGE_SIZE] = {};
};
struct RemoveHookCmd // From host
{
RemoveHookCmd(unsigned __int64 address) : address(address) {};
int command = HOST_COMMAND_REMOVE_HOOK;
unsigned __int64 address;
};
struct ConsoleOutputNotif // From hook
{
ConsoleOutputNotif(std::string message = "") { strncpy(this->message, message.c_str(), 500); };
int command = HOST_NOTIFICATION_TEXT;
char message[MESSAGE_SIZE] = {};
};
struct HookRemovedNotif // From hook
{
HookRemovedNotif(unsigned __int64 address) : address(address) {};
int command = HOST_NOTIFICATION_RMVHOOK;
unsigned __int64 address;
};

View File

@ -2,50 +2,27 @@ include_directories(.)
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set(vnrhook_src set(vnrhook_src
include/const.h main.cc
include/defs.h pipe.cc
include/types.h util/ithsys/ithsys.cc
src/main.cc hijack/texthook.cc
src/main.h
src/pipe.cc
src/util/ithsys/ithsys.cc
src/hijack/texthook.cc
) )
else() else()
set(vnrhook_src set(vnrhook_src
include/const.h main.cc
include/defs.h pipe.cc
include/types.h engine/engine.cc
src/except.h engine/match.cc
src/main.cc engine/pchooks.cc
src/main.h hijack/texthook.cc
src/pipe.cc util/util.cc
src/engine/engine.cc util/ithsys/ithsys.cc
src/engine/engine.h util/disasm/disasm.cc
src/engine/hookdefs.h util/memdbg/memsearch.cc
src/engine/match.cc
src/engine/match.h
src/engine/pchooks.cc
src/engine/pchooks.h
src/engine/mono/funcinfo.h
src/engine/mono/types.h
src/engine/ppsspp/funcinfo.h
src/hijack/texthook.cc
src/hijack/texthook.h
src/util/growl.h
src/util/util.cc
src/util/util.h
src/util/ithsys/ithsys.cc
src/util/disasm/disasm.cc
src/util/memdbg/memdbg.h
src/util/memdbg/memsearch.cc
src/util/memdbg/memsearch.h
src/util/mono/monoobject.h
src/util/mono/monotype.h
) )
endif() endif()
include_directories(src/util) include_directories(util)
add_library(vnrhook SHARED ${vnrhook_src}) add_library(vnrhook SHARED ${vnrhook_src})

View File

@ -7,21 +7,21 @@
# pragma warning (disable:4819) # pragma warning (disable:4819)
#endif // _MSC_VER #endif // _MSC_VER
#include "src/engine/engine.h" #include "engine/engine.h"
#include "ntdll/ntdll.h" #include "ntdll/ntdll.h"
#include "src/engine/match.h" #include "engine/match.h"
#include "src/engine/hookdefs.h" #include "util/util.h"
#include "src/util/util.h" #include "main.h"
#include "src/main.h" #include "engine/mono/funcinfo.h"
#include "src/engine/mono/funcinfo.h" #include "engine/ppsspp/funcinfo.h"
#include "src/engine/ppsspp/funcinfo.h" #include "except.h"
#include "src/except.h"
#include "ithsys/ithsys.h" #include "ithsys/ithsys.h"
#include "memdbg/memsearch.h" #include "memdbg/memsearch.h"
#include "disasm/disasm.h" #include "disasm/disasm.h"
#include "cpputil/cppcstring.h" #include "cpputil/cppcstring.h"
#include "mono/monoobject.h" #include "mono/monoobject.h"
#include "growl.h" #include "growl.h"
#include "const.h"
//#include <boost/foreach.hpp> //#include <boost/foreach.hpp>
#include <cstdio> #include <cstdio>
#include <string> #include <string>
@ -38,50 +38,6 @@
enum { VNR_TEXT_CAPACITY = 1500 }; // estimated max number of bytes allowed in VNR, slightly larger than VNR's text limit (1000) enum { VNR_TEXT_CAPACITY = 1500 }; // estimated max number of bytes allowed in VNR, slightly larger than VNR's text limit (1000)
#ifdef DEBUG
# include "src/util/growl.h"
//# include "uniquemap.h"
//# include "uniquemap.cc"
namespace { // unnamed debug functions
// jichi 12/17/2013: Copied from int TextHook::GetLength(DWORD base, DWORD in)
int GetHookDataLength(const HookParam &hp, DWORD base, DWORD in)
{
if (CC_UNLIKELY(!base))
return 0;
int len;
switch (hp.length_offset) {
default: // jichi 12/26/2013: I should not put this default branch to the end
len = *((int *)base + hp.length_offset);
if (len >= 0) {
if (hp.type & USING_UNICODE)
len <<= 1;
break;
}
else if (len != -1)
break;
//len == -1 then continue to case 0.
case 0:
if (hp.type & USING_UNICODE)
len = wcslen((LPCWSTR)in) << 1;
else
len = strlen((LPCSTR)in);
break;
case 1:
if (hp.type & USING_UNICODE)
len = 2;
else {
if (hp.type & BIG_ENDIAN)
in >>= 8;
len = LeadByteTable[in&0xff]; //Slightly faster than IsDBCSLeadByte
}
break;
}
// jichi 12/25/2013: This function originally return -1 if failed
//return len;
return max(0, len);
}
} // unnamed
#endif // DEBUG
namespace { // unnamed helpers namespace { // unnamed helpers

View File

@ -7,13 +7,13 @@
//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler //# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
#endif // _MSC_VER #endif // _MSC_VER
#include "src/engine/match.h" #include "engine/match.h"
#include "src/engine/engine.h" #include "engine/engine.h"
#include "src/engine/pchooks.h" #include "engine/pchooks.h"
#include "src/util/growl.h" #include "util/growl.h"
#include "src/util/util.h" #include "util/util.h"
#include "src/main.h" #include "main.h"
#include "src/except.h" #include "except.h"
#include "ithsys/ithsys.h" #include "ithsys/ithsys.h"
//#define ConsoleOutput(...) (void)0 // jichi 8/18/2013: I don't need ConsoleOutput //#define ConsoleOutput(...) (void)0 // jichi 8/18/2013: I don't need ConsoleOutput

View File

@ -1,8 +1,8 @@
// pchooks.cc // pchooks.cc
// 8/1/2014 jichi // 8/1/2014 jichi
#include "src/engine/pchooks.h" #include "engine/pchooks.h"
#include "src/main.h" #include "main.h"
//#include <gdiplus.h> //#include <gdiplus.h>
#define DEBUG "vnrcli" #define DEBUG "vnrcli"

View File

@ -9,11 +9,11 @@
//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler //# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
#endif // _MSC_VER #endif // _MSC_VER
#include "src/hijack/texthook.h" #include "hijack/texthook.h"
#include "src/engine/match.h" #include "engine/match.h"
#include "src/except.h" #include "except.h"
#include "src/main.h" #include "main.h"
#include "include/const.h" #include "const.h"
#include "ithsys/ithsys.h" #include "ithsys/ithsys.h"
#include "disasm/disasm.h" #include "disasm/disasm.h"
//#include "winseh/winseh.h" //#include "winseh/winseh.h"
@ -293,9 +293,8 @@ DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn)
} }
dwCount = GetLength(dwDataBase, dwDataIn); dwCount = GetLength(dwDataBase, dwDataIn);
} }
// jichi 12/25/2013: validate data size // jichi 12/25/2013: validate data size
if (dwCount == 0 || dwCount > PIPE_BUFFER_SIZE - HEADER_SIZE) if (dwCount == 0 || dwCount > PIPE_BUFFER_SIZE - sizeof(ThreadParam))
return 0; return 0;
if (hp.length_offset == 1) { if (hp.length_offset == 1) {
@ -304,27 +303,27 @@ DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn)
dwDataIn = _byteswap_ushort(dwDataIn & 0xffff); dwDataIn = _byteswap_ushort(dwDataIn & 0xffff);
if (dwCount == 1) if (dwCount == 1)
dwDataIn &= 0xff; dwDataIn &= 0xff;
*(WORD *)(pbData + HEADER_SIZE) = dwDataIn & 0xffff; *(WORD *)(pbData + sizeof(ThreadParam)) = dwDataIn & 0xffff;
} }
else else
::memcpy(pbData + HEADER_SIZE, (void *)dwDataIn, dwCount); ::memcpy(pbData + sizeof(ThreadParam), (void *)dwDataIn, dwCount);
// jichi 10/14/2014: Add filter function // jichi 10/14/2014: Add filter function
if (hp.filter_fun && !hp.filter_fun(pbData + HEADER_SIZE, &dwCount, &hp, 0) || dwCount <= 0) { if (hp.filter_fun && !hp.filter_fun(pbData + sizeof(ThreadParam), &dwCount, &hp, 0) || dwCount <= 0) {
return 0; return 0;
} }
*(DWORD *)pbData = dwAddr;
if (dwType & (NO_CONTEXT|FIXING_SPLIT)) if (dwType & (NO_CONTEXT|FIXING_SPLIT))
dwRetn = 0; dwRetn = 0;
*(ThreadParam*)pbData = { GetCurrentProcessId(), dwAddr, dwRetn, dwSplit };
*((DWORD *)pbData + 1) = dwRetn; *((DWORD *)pbData + 1) = dwRetn;
*((DWORD *)pbData + 2) = dwSplit; *((DWORD *)pbData + 2) = dwSplit;
if (dwCount) { if (dwCount) {
DWORD unused; DWORD unused;
//CliLockPipe(); //CliLockPipe();
WriteFile(::hookPipe, pbData, dwCount + HEADER_SIZE, &unused, nullptr); WriteFile(::hookPipe, pbData, dwCount + sizeof(ThreadParam), &unused, nullptr);
//CliUnlockPipe(); //CliUnlockPipe();
} }
return 0; return 0;
@ -454,7 +453,7 @@ DWORD WINAPI ReaderThread(LPVOID threadParam)
while (true) while (true)
{ {
Sleep(500); Sleep(500);
if (memcmp(buffer + HEADER_SIZE, currentAddress, dataLen) == 0) if (memcmp(buffer + sizeof(ThreadParam), currentAddress, dataLen) == 0)
{ {
changeCount = 0; changeCount = 0;
continue; continue;
@ -471,12 +470,10 @@ DWORD WINAPI ReaderThread(LPVOID threadParam)
else else
dataLen = strlen(currentAddress); dataLen = strlen(currentAddress);
*(DWORD*)buffer = hook->hp.address; *(ThreadParam*)buffer = { GetCurrentProcessId(), hook->hp.address, 0, 0 };
*(DWORD*)(buffer + 4) = 0; memcpy(buffer + sizeof(ThreadParam), currentAddress, dataLen);
*(DWORD*)(buffer + 8) = 0;
memcpy(buffer + HEADER_SIZE, currentAddress, dataLen);
DWORD unused; DWORD unused;
WriteFile(::hookPipe, buffer, dataLen + HEADER_SIZE, &unused, nullptr); WriteFile(::hookPipe, buffer, dataLen + sizeof(ThreadParam), &unused, nullptr);
} }
hook->ClearHook(); hook->ClearHook();
return 0; return 0;

63
vnrhook/hijack/texthook.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
// texthook.h
// 8/24/2013 jichi
// Branch: IHF_DLL/IHF_CLIENT.h, rev 133
//
// 8/24/2013 TODO:
// - Clean up this file
// - Reduce global variables. Use namespaces or singleton classes instead.
#include "common.h"
#include "pipe.h"
extern int currentHook;
extern DWORD trigger;
// jichi 9/25/2013: This class will be used by NtMapViewOfSectionfor
// interprocedure communication, where constructor/destructor will NOT work.
class TextHook
{
int InsertHookCode();
int InsertReadCode();
int UnsafeInsertHookCode();
DWORD UnsafeSend(DWORD dwDataBase, DWORD dwRetn);
int RemoveHookCode();
int RemoveReadCode();
int SetHookName(LPCSTR name);
public:
LPSTR hook_name;
int name_length;
BYTE recover[0x68 - sizeof(HookParam)];
BYTE original[0x10];
HookParam hp;
unsigned __int64 Address() const { return hp.address; }
DWORD Type() const { return hp.type; }
WORD Length() const { return hp.hook_len; }
LPSTR Name() const { return hook_name; }
int NameLength() const { return name_length; }
int InsertHook();
int InitHook(const HookParam &hp, LPCSTR name = 0, WORD set_flag = 0);
DWORD Send(DWORD dwDataBase, DWORD dwRetn);
int ClearHook();
int GetLength(DWORD base, DWORD in); // jichi 12/25/2013: Return 0 if failed
};
// jichi 1/16/2015: Though called max hook, it means max number of text threads
enum { MAX_HOOK = 64 };
enum { HOOK_SECTION_SIZE = MAX_HOOK * sizeof(TextHook) * 2, HOOK_BUFFER_SIZE = MAX_HOOK * sizeof(TextHook) };
extern TextHook *hookman,
*current_available;
extern bool running,
live;
extern HANDLE hookPipe,
hmMutex;
DWORD WINAPI PipeManager(LPVOID unused);
enum : int { yes = 0, no = 1 };
// EOF

View File

@ -1,89 +0,0 @@
#pragma once
#include "types.h"
// vnrhook/const.h
// 8/23/2013 jichi
// Branch: ITH/common.h, rev 128
// jichi 1/16/2015: Though called max hook, it means max number of text threads
enum { MAX_HOOK = 64 }; // must be larger than HOOK_FUN_COUNT
//enum { HOOK_SECTION_SIZE = 0x2000 }; // default ITH value
// jichi 1/16/2015: Change to a very large number to prevent crash
//enum { MAX_HOOK = 0x100 }; // must be larger than HookFunCount
enum { HOOK_SECTION_SIZE = MAX_HOOK * sizeof(Hook) * 2 }; // default ITH value is 0x2000 for 32 hook (0x100 per hook)
// jichi 375/2014: Add offset of pusha/pushad
// http://faydoc.tripod.com/cpu/pushad.htm
// http://agth.wikia.com/wiki/Cheat_Engine_AGTH_Tutorial
//
// Warning: The offset in ITH has -4 offset comparing to pusha and AGTH
enum pusha_off {
pusha_eax_off = -0x4
, pusha_ecx_off = -0x8
, pusha_edx_off = -0xc
, pusha_ebx_off = -0x10
, pusha_esp_off = -0x14
, pusha_ebp_off = -0x18
, pusha_esi_off = -0x1c
, pusha_edi_off = -0x20
, pusha_off = -0x24 // pushad offset
};
enum HostCommandType {
HOST_COMMAND = -1 // null type
, HOST_COMMAND_NEW_HOOK = 0
, HOST_COMMAND_REMOVE_HOOK = 1
, HOST_COMMAND_MODIFY_HOOK = 2
, HOST_COMMAND_HIJACK_PROCESS = 3
, HOST_COMMAND_DETACH = 4
};
enum HostNotificationType {
HOST_NOTIFICATION = -1 // null type
, HOST_NOTIFICATION_TEXT = 0
, HOST_NOTIFICATION_NEWHOOK = 1
, HOST_NOTIFICATION_RMVHOOK = 2
};
// jichi 9/8/2013: The meaning are guessed
// Values must be within DWORD
// Unused values are as follows:
// - 0x100
enum HookParamType : unsigned long {
USING_STRING = 0x1 // type(data) is char* or wchar_t* and has length
, USING_UNICODE = 0x2 // type(data) is wchar_t or wchar_t*
, BIG_ENDIAN = 0x4 // type(data) is char
, 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
, USING_UTF8 = 0x100
//, STRING_LAST_CHAR = 0x200
, NO_CONTEXT = 0x400
, HOOK_EMPTY = 0x800
, FIXING_SPLIT = 0x1000
, DIRECT_READ = 0x2000 // /R read code instead of classic /H hook code
//, HOOK_AUXILIARY = 0x2000 // jichi 12/13/2013: None of known hooks are auxiliary
//, RELATIVE_SPLIT = 0x2000 // Artikash 8/3/2018: does nothing
, HOOK_ENGINE = 0x4000
, HOOK_ADDITIONAL = 0x8000
};
// 6/1/2014: Fixed split value for hok parameter
// Fuse all threads, and prevent floating
enum { FIXED_SPLIT_VALUE = 0x10001 };
enum { PIPE_BUFFER_SIZE = 0x1000};
// jichi 12/25/2013: Header in each message sent to vnrsrv
// There are totally three elements
// - 0x0 dwAddr hook address
// - 0x4 dwRetn return address
// - 0x8 dwSplit split value
#define HEADER_SIZE sizeof(DWORD) * 3
#define TIMEOUT 5000 // 5 seconds
// EOF

View File

@ -1,66 +0,0 @@
#pragma once
// vnrhook/types.h
// 8/23/2013 jichi
// Branch: ITH/common.h, rev 128
#include <windows.h> // needed for windef types
/** jichi 3/7/2014: Add guessed comment
*
* DWORD addr absolute or relative address
* DWORD split esp offset of the split character
*
* http://faydoc.tripod.com/cpu/pushad.htm
* http://agth.wikia.com/wiki/Cheat_Engine_AGTH_Tutorial
* The order is the same as pushd
* EAX, ECX, EDX, EBX, ESP (original value), EBP, ESI, and EDI (if the current operand-size attribute is 32) and AX, CX, DX, BX, SP
* Negative values of 'data_offset' and 'sub_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
*/
struct HookParam {
// jichi 8/24/2013: For special hooks.
typedef void (*text_fun_t)(DWORD esp, HookParam *hp, BYTE index, DWORD *data, DWORD *split, DWORD *len);
// 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 generic hook function, return false if stop execution.
typedef bool (*hook_fun_t)(DWORD esp, HookParam *hp);
unsigned __int64 address; // absolute or relative address
short offset, // offset of the data in the memory
index,
split, // offset of the split character
split_index;
DWORD module; // hash of the module
text_fun_t text_fun;
filter_fun_t filter_fun;
hook_fun_t hook_fun;
DWORD type; // flags
WORD length_offset; // index of the string length
BYTE hook_len, // ?
recover_len; // ?
// 7/20/2014: jichi additional parameters for PSP games
DWORD user_value;
// Artikash 8/4/2018: handle for reader thread
HANDLE readerHandle;
};
struct Hook { // size: 0x80
HookParam hp;
LPSTR hook_name;
int name_length;
BYTE recover[0x68 - sizeof(HookParam)];
BYTE original[0x10];
unsigned __int64 Address() const { return hp.address; }
DWORD Type() const { return hp.type; }
WORD Length() const { return hp.hook_len; }
LPSTR Name() const { return hook_name; }
int NameLength() const { return name_length; }
};
// EOF

128
vnrhook/main.cc Normal file
View File

@ -0,0 +1,128 @@
// main.cc
// 8/24/2013 jichi
// Branch: ITH_DLL/main.cpp, rev 128
// 8/24/2013 TODO: Clean up this file
#ifdef _MSC_VER
# pragma warning (disable:4100) // C4100: unreference formal parameter
//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
#endif // _MSC_VER
#include "main.h"
#include "defs.h"
#include "engine/engine.h"
#include "engine/match.h"
#include "hijack/texthook.h"
#include "util/growl.h"
// Global variables
// jichi 6/3/2014: memory range of the current module
DWORD processStartAddress,
processStopAddress;
WCHAR hm_section[0x100];
HANDLE hSection;
bool running;
int currentHook = 0,
user_hook_count = 0;
DWORD trigger = 0;
HANDLE
hFile,
hMutex,
hmMutex;
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID unused)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
::hmMutex = CreateMutexW(nullptr, FALSE, (ITH_HOOKMAN_MUTEX_ + std::to_wstring(GetCurrentProcessId())).c_str());
if (GetLastError() == ERROR_ALREADY_EXISTS) return FALSE;
DisableThreadLibraryCalls(hModule);
// jichi 9/25/2013: Interprocedural communication with vnrsrv.
hSection = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_EXECUTE_READWRITE, 0, HOOK_SECTION_SIZE, (ITH_SECTION_ + std::to_wstring(GetCurrentProcessId())).c_str());
::hookman = (TextHook*)MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, HOOK_BUFFER_SIZE);
::processStartAddress = ::processStopAddress = (DWORD)GetModuleHandleW(nullptr);
MEMORY_BASIC_INFORMATION info;
do
{
VirtualQuery((void*)::processStopAddress, &info, sizeof(info));
::processStopAddress = (DWORD)info.BaseAddress + info.RegionSize;
} while (info.Protect > PAGE_NOACCESS);
processStopAddress -= info.RegionSize;
::running = true;
::current_available = ::hookman;
CreatePipe();
}
break;
case DLL_PROCESS_DETACH:
{
::running = false;
for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++) man->ClearHook();
//if (ith_has_section)
UnmapViewOfFile(::hookman);
CloseHandle(::hookPipe);
CloseHandle(hSection);
CloseHandle(hMutex);
CloseHandle(hmMutex);
//} ITH_EXCEPT {}
}
break;
}
return TRUE;
}
//extern "C" {
DWORD NewHook(const HookParam &hp, LPCSTR lpname, DWORD flag)
{
std::string name = lpname;
int current = ::current_available - ::hookman;
if (current < MAX_HOOK) {
//flag &= 0xffff;
//if ((flag & HOOK_AUXILIARY) == 0)
flag |= HOOK_ADDITIONAL;
if (name[0] == '\0')
{
name = "UserHook" + std::to_string(user_hook_count++);
}
ConsoleOutput(("vnrcli:NewHook: try inserting hook: " + name).c_str());
// jichi 7/13/2014: This function would raise when too many hooks added
::hookman[current].InitHook(hp, name.c_str(), flag & 0xffff);
if (::hookman[current].InsertHook() == 0) {
ConsoleOutput(("vnrcli:NewHook: inserted hook: " + name).c_str());
NotifyHookInsert(hp, name.c_str());
}
else
ConsoleOutput("vnrcli:NewHook:WARNING: failed to insert hook");
}
return 0;
}
DWORD RemoveHook(DWORD addr)
{
for (int i = 0; i < MAX_HOOK; i++)
if (::hookman[i].Address() == addr) {
::hookman[i].ClearHook();
return 0;
}
return 0;
}
DWORD SwitchTrigger(DWORD t)
{
trigger = t;
return 0;
}
// EOF

View File

@ -4,8 +4,8 @@
// 8/23/2013 jichi // 8/23/2013 jichi
// Branch: ITH/IHF_DLL.h, rev 66 // Branch: ITH/IHF_DLL.h, rev 66
#include "include/const.h" #include "common.h"
#include "include/types.h" #include "pipe.h"
void ConsoleOutput(LPCSTR text); // jichi 12/25/2013: Used to return length of sent text void ConsoleOutput(LPCSTR text); // jichi 12/25/2013: Used to return length of sent text
void NotifyHookInsert(HookParam hp, LPCSTR name); void NotifyHookInsert(HookParam hp, LPCSTR name);

116
vnrhook/pipe.cc Normal file
View File

@ -0,0 +1,116 @@
// pipe.cc
// 8/24/2013 jichi
// Branch: ITH_DLL/pipe.cpp, rev 66
// 8/24/2013 TODO: Clean up this file
#ifdef _MSC_VER
# pragma warning (disable:4100) // C4100: unreference formal parameter
#endif // _MSC_VER
#include "pipe.h"
#include "main.h"
#include "hijack/texthook.h"
#include "engine/match.h"
#include "defs.h"
#include "const.h"
#include "growl.h"
HANDLE hookPipe;
DWORD DUMMY[100];
void CreatePipe()
{
std::thread([]()
{
enum { STANDARD_WAIT = 50 };
while (::running)
{
DWORD count = 0;
BYTE buffer[PIPE_BUFFER_SIZE] = {};
HANDLE hostPipe = ::hookPipe = INVALID_HANDLE_VALUE,
pipeAcquisitionMutex = CreateMutexW(nullptr, TRUE, ITH_GRANTPIPE_MUTEX);
while (::hookPipe == INVALID_HANDLE_VALUE || hostPipe == INVALID_HANDLE_VALUE)
{
if (::hookPipe == INVALID_HANDLE_VALUE)
{
::hookPipe = CreateFileW(ITH_TEXT_PIPE, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
}
if (hostPipe == INVALID_HANDLE_VALUE)
{
hostPipe = CreateFileW(ITH_COMMAND_PIPE, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
}
Sleep(STANDARD_WAIT);
}
*(DWORD*)buffer = GetCurrentProcessId();
WriteFile(::hookPipe, buffer, sizeof(DWORD), &count, nullptr);
ReleaseMutex(pipeAcquisitionMutex);
CloseHandle(pipeAcquisitionMutex);
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
#ifdef _WIN64
ConsoleOutput("Hooks don't work on x64, only read codes work. Engine disabled.");
#else
Engine::Hijack();
#endif
while (::running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
switch (*(int*)buffer)
{
case HOST_COMMAND_NEW_HOOK:
{
auto info = *(InsertHookCmd*)buffer;
NewHook(info.hp, info.name);
}
break;
case HOST_COMMAND_REMOVE_HOOK:
{
auto info = *(RemoveHookCmd*)buffer;
for (int i = 0; i < MAX_HOOK; ++i)
if (::hookman[i].Address() == info.address)
::hookman[i].ClearHook();
}
break;
case HOST_COMMAND_DETACH:
{
::running = false;
}
break;
}
CloseHandle(hostPipe);
}
FreeLibraryAndExitThread(GetModuleHandleW(ITH_DLL), 0);
}).detach();
}
void ConsoleOutput(LPCSTR text)
{
auto info = ConsoleOutputNotif(text);
WriteFile(::hookPipe, &info, strlen(text) + sizeof(info), DUMMY, nullptr);
}
void NotifyHookInsert(HookParam hp, LPCSTR name)
{
//BYTE buffer[PIPE_BUFFER_SIZE];
//*(DWORD*)buffer = HOST_NOTIFICATION;
//*(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_NEWHOOK;
//*(HookParam*)(buffer + sizeof(DWORD) * 2) = hp;
//strcpy((char*)buffer + sizeof(DWORD) * 2 + sizeof(HookParam), name);
//DWORD unused;
//WriteFile(::hookPipe, buffer, strlen(name) + sizeof(DWORD) * 2 + sizeof(HookParam), &unused, nullptr);
//return;
}
void NotifyHookRemove(DWORD addr)
{
auto info = HookRemovedNotif(addr);
WriteFile(::hookPipe, &info, sizeof(info), DUMMY, nullptr);
}
// EOF

View File

@ -1,12 +0,0 @@
#pragma once
// engine/hookdefs.h
// 7/20/2014 jichi
// For HookParam user flags
enum HookParamFlag : unsigned long {
HPF_Null = 0 // never used
, HPF_IgnoreSameAddress = 1 // ignore the last same text address
};
// EOF

View File

@ -1,78 +0,0 @@
#pragma once
// texthook.h
// 8/24/2013 jichi
// Branch: IHF_DLL/IHF_CLIENT.h, rev 133
//
// 8/24/2013 TODO:
// - Clean up this file
// - Reduce global variables. Use namespaces or singleton classes instead.
#include <string>
#include <unordered_map>
#include "include/types.h"
#include <windows.h>
extern int currentHook;
extern WCHAR dll_mutex[];
//extern WCHAR dll_name[];
extern DWORD trigger;
//extern DWORD current_process_id;
// jichi 6/3/2014: Get memory range of the current module
extern DWORD processStartAddress,
processStopAddress;
void InitFilterTable();
// jichi 9/25/2013: This class will be used by NtMapViewOfSectionfor
// interprocedure communication, where constructor/destructor will NOT work.
class TextHook : public Hook
{
int InsertHookCode();
int InsertReadCode();
int UnsafeInsertHookCode();
DWORD UnsafeSend(DWORD dwDataBase, DWORD dwRetn);
int RemoveHookCode();
int RemoveReadCode();
int SetHookName(LPCSTR name);
public:
int InsertHook();
int InitHook(const HookParam &hp, LPCSTR name = 0, WORD set_flag = 0);
DWORD Send(DWORD dwDataBase, DWORD dwRetn);
int ClearHook();
int GetLength(DWORD base, DWORD in); // jichi 12/25/2013: Return 0 if failed
};
extern TextHook *hookman,
*current_available;
//void InitDefaultHook();
struct FilterRange { DWORD lower, upper; };
extern FilterRange *filter;
extern bool running,
live;
extern HANDLE hookPipe,
hmMutex;
DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter);
DWORD WINAPI CommandPipe(LPVOID lpThreadParameter);
DWORD WINAPI PipeManager(LPVOID unused);
//void RequestRefreshProfile();
//typedef DWORD (*InsertHookFun)(DWORD);
//typedef DWORD (*IdentifyEngineFun)();
//typedef DWORD (*InsertDynamicHookFun)(LPVOID addr, DWORD frame, DWORD stack);
//extern IdentifyEngineFun IdentifyEngine;
//extern InsertDynamicHookFun InsertDynamicHook;
// jichi 9/28/2013: Protect pipeline in wine
void CliLockPipe();
void CliUnlockPipe();
enum : int { yes = 0, no = 1 };
// EOF

View File

@ -1,175 +0,0 @@
// main.cc
// 8/24/2013 jichi
// Branch: ITH_DLL/main.cpp, rev 128
// 8/24/2013 TODO: Clean up this file
#ifdef _MSC_VER
# pragma warning (disable:4100) // C4100: unreference formal parameter
//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
#endif // _MSC_VER
#include "src/main.h"
#include "src/engine/engine.h"
#include "src/engine/match.h"
#include "src/hijack/texthook.h"
#include "src/util/growl.h"
#include "src/except.h"
#include "include/const.h"
#include "include/defs.h"
#include "ithsys/ithsys.h"
#include "util/util.h"
#include <cstdio> // for swprintf
//#include "ntinspect/ntinspect.h"
//#include "winseh/winseh.h"
//#include <boost/foreach.hpp>
//#include "md5.h"
//#include <ITH\AVL.h>
//#include <ITH\ntdll.h>
// Global variables
// jichi 6/3/2014: memory range of the current module
DWORD processStartAddress,
processStopAddress;
enum { HOOK_BUFFER_SIZE = MAX_HOOK * sizeof(TextHook) };
WCHAR hm_section[0x100];
HANDLE hSection;
bool running;
int currentHook = 0,
user_hook_count = 0;
DWORD trigger = 0;
HANDLE
hFile,
hMutex,
hmMutex;
HMODULE currentModule;
//DWORD current_process_id;
extern DWORD enter_count;
//extern LPWSTR current_dir;
extern DWORD engine_type;
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID unused)
{
static HANDLE pipeThread;
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
{
static bool attached_ = false;
if (attached_) // already attached
{
return TRUE;
}
attached_ = true;
DisableThreadLibraryCalls(hModule);
swprintf(hm_section, ITH_SECTION_ L"%d", GetCurrentProcessId());
// jichi 9/25/2013: Interprocedural communication with vnrsrv.
hSection = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_EXECUTE_READWRITE, 0, HOOK_SECTION_SIZE, hm_section);
::hookman = (TextHook*)MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, HOOK_BUFFER_SIZE);
::processStartAddress = ::processStopAddress = (DWORD)GetModuleHandleW(nullptr);
#ifndef _WIN64
MEMORY_BASIC_INFORMATION info;
do
{
VirtualQuery((void*)::processStopAddress, &info, sizeof(info));
::processStopAddress = (DWORD)info.BaseAddress + info.RegionSize;
} while (info.Protect > PAGE_NOACCESS);
processStopAddress -= info.RegionSize;
#endif
{
wchar_t hm_mutex[0x100];
swprintf(hm_mutex, ITH_HOOKMAN_MUTEX_ L"%d", GetCurrentProcessId());
::hmMutex = CreateMutexW(nullptr, FALSE, hm_mutex);
if (GetLastError() == ERROR_ALREADY_EXISTS)
return FALSE;
}
::running = true;
::current_available = ::hookman;
::currentModule = hModule;
pipeThread = CreateThread(nullptr, 0, PipeManager, 0, 0, nullptr);
} break;
case DLL_PROCESS_DETACH:
{
static bool detached_ = false;
if (detached_) // already detached
return TRUE;
detached_ = true;
// jichi 10/2/2103: Cannot use __try in functions that require object unwinding
//ITH_TRY {
::running = false;
if (pipeThread) {
WaitForSingleObject(pipeThread, TIMEOUT);
CloseHandle(pipeThread);
}
for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++)
man->ClearHook();
//if (ith_has_section)
UnmapViewOfFile(::hookman);
CloseHandle(hSection);
CloseHandle(hMutex);
CloseHandle(hmMutex);
//} ITH_EXCEPT {}
} break;
}
return TRUE;
}
//extern "C" {
DWORD NewHook(const HookParam &hp, LPCSTR lpname, DWORD flag)
{
std::string name = lpname;
int current = ::current_available - ::hookman;
if (current < MAX_HOOK) {
//flag &= 0xffff;
//if ((flag & HOOK_AUXILIARY) == 0)
flag |= HOOK_ADDITIONAL;
if (name[0] == '\0')
{
name = "UserHook" + std::to_string(user_hook_count++);
}
ConsoleOutput(("vnrcli:NewHook: try inserting hook: " + name).c_str());
// jichi 7/13/2014: This function would raise when too many hooks added
::hookman[current].InitHook(hp, name.c_str(), flag & 0xffff);
if (::hookman[current].InsertHook() == 0) {
ConsoleOutput(("vnrcli:NewHook: inserted hook: " + name).c_str());
NotifyHookInsert(hp, name.c_str());
} else
ConsoleOutput("vnrcli:NewHook:WARNING: failed to insert hook");
}
return 0;
}
DWORD RemoveHook(DWORD addr)
{
for (int i = 0; i < MAX_HOOK; i++)
if (::hookman[i].Address ()== addr) {
::hookman[i].ClearHook();
return 0;
}
return 0;
}
DWORD SwitchTrigger(DWORD t)
{
trigger = t;
return 0;
}
// EOF

View File

@ -1,138 +0,0 @@
// pipe.cc
// 8/24/2013 jichi
// Branch: ITH_DLL/pipe.cpp, rev 66
// 8/24/2013 TODO: Clean up this file
#ifdef _MSC_VER
# pragma warning (disable:4100) // C4100: unreference formal parameter
#endif // _MSC_VER
#include "src/hijack/texthook.h"
#include "src/engine/match.h"
#include "src/util/util.h"
#include "src/main.h"
#include "include/defs.h"
#include "src/util/growl.h"
#include "ithsys/ithsys.h"
#include <cstdio> // for swprintf
HANDLE hookPipe;
extern HMODULE currentModule;
DWORD WINAPI PipeManager(LPVOID unused)
{
enum { STANDARD_WAIT = 50 };
while (::running)
{
DWORD count;
BYTE buffer[PIPE_BUFFER_SIZE];
HANDLE hostPipe = ::hookPipe = INVALID_HANDLE_VALUE,
pipeAcquisitionMutex = CreateMutexW(nullptr, TRUE, ITH_GRANTPIPE_MUTEX);
while (::hookPipe == INVALID_HANDLE_VALUE || hostPipe == INVALID_HANDLE_VALUE)
{
if (::hookPipe == INVALID_HANDLE_VALUE)
{
::hookPipe = CreateFileW(ITH_TEXT_PIPE, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
}
if (hostPipe == INVALID_HANDLE_VALUE)
{
hostPipe = CreateFileW(ITH_COMMAND_PIPE, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
}
Sleep(STANDARD_WAIT);
}
*(DWORD*)buffer = GetCurrentProcessId();
WriteFile(::hookPipe, buffer, sizeof(DWORD), &count, nullptr);
ReleaseMutex(pipeAcquisitionMutex);
CloseHandle(pipeAcquisitionMutex);
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
#ifdef _WIN64
ConsoleOutput("Hooks don't work on x64, only read codes work. Engine disabled.");
#else
Engine::Hijack();
#endif
while (::running)
{
if (!ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE / 2, &count, nullptr)) // Artikash 5/21/2018: why / 2? wchar_t?
{
break;
}
DWORD command = *(DWORD*)buffer;
switch (command)
{
case HOST_COMMAND_NEW_HOOK:
buffer[count] = 0;
NewHook(*(HookParam *)(buffer + sizeof(DWORD)), // Hook parameter
(LPSTR)(buffer + 4 + sizeof(HookParam)), // Hook name
0
);
break;
case HOST_COMMAND_REMOVE_HOOK:
{
TextHook *in = hookman;
for (int i = 0; i < currentHook; in++)
{
if (in->Address()) i++;
if (in->Address() == *(DWORD *)(buffer + sizeof(DWORD))) // Hook address
{
break;
}
}
if (in->Address())
{
in->ClearHook();
}
}
break;
case HOST_COMMAND_DETACH:
::running = false;
break;
}
}
CloseHandle(::hookPipe);
CloseHandle(hostPipe);
}
FreeLibraryAndExitThread(::currentModule, 0);
return 0;
}
void ConsoleOutput(LPCSTR text)
{
BYTE buffer[PIPE_BUFFER_SIZE];
*(DWORD*)buffer = HOST_NOTIFICATION;
*(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_TEXT;
strcpy((char*)buffer + sizeof(DWORD) * 2, text);
DWORD unused;
WriteFile(::hookPipe, buffer, strlen(text) + sizeof(DWORD) * 2, &unused, nullptr);
}
void NotifyHookInsert(HookParam hp, LPCSTR name)
{
BYTE buffer[PIPE_BUFFER_SIZE];
*(DWORD*)buffer = HOST_NOTIFICATION;
*(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_NEWHOOK;
*(HookParam*)(buffer + sizeof(DWORD) * 2) = hp;
strcpy((char*)buffer + sizeof(DWORD) * 2 + sizeof(HookParam), name);
DWORD unused;
WriteFile(::hookPipe, buffer, strlen(name) + sizeof(DWORD) * 2 + sizeof(HookParam), &unused, nullptr);
return;
}
void NotifyHookRemove(DWORD addr)
{
BYTE buffer[sizeof(DWORD) * 3];
*(DWORD*)buffer = HOST_NOTIFICATION;
*(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_RMVHOOK;
*(DWORD*)(buffer + sizeof(DWORD) * 2) = addr;
DWORD unused;
WriteFile(::hookPipe, buffer, sizeof(DWORD) * 3, &unused, nullptr);
return;
}
// EOF

View File

@ -3,7 +3,7 @@
// Branch: ITH_Engine/engine.cpp, revision 133 // Branch: ITH_Engine/engine.cpp, revision 133
// See: http://ja.wikipedia.org/wiki/プロジェクト:美少女ゲーム系/ゲームエンジン // See: http://ja.wikipedia.org/wiki/プロジェクト:美少女ゲーム系/ゲームエンジン
#include "src/util/util.h" #include "util/util.h"
#include "ithsys/ithsys.h" #include "ithsys/ithsys.h"
namespace { // unnamed namespace { // unnamed