diff --git a/vnr/texthook/ihf.txt b/vnr/texthook/ihf.txt deleted file mode 100644 index f52a835..0000000 --- a/vnr/texthook/ihf.txt +++ /dev/null @@ -1,20 +0,0 @@ -# 6/6/2012 -# IHF.dll -# Skip swprintf and MessageBox statements in GetDebugPriv -# -# SVN checkout: 2012/6/6 -# - IHF/main.cpp: 2012/4/8 -# - IHF.{dll,lib}: 2012/6/5 - -6F753055 CALL DWORD PTR DS:ntdll.ZwAdjustPrivilegesTOken -6F75305B TEST EAX,EAX -6F75305B JNE SHORT 6F753077 => JNE SHORT 6F75309F -... -6F753077 PUSH EAX -... -6F75309F MOVE EAX,DWORD PTR SS:[ESP] -6F7530A2 PUSH EAX -6F7530A3 CALL DWORD PTR DS:ntdll.NtClose -... - -# EOF diff --git a/vnr/texthook/ihf_p.cc b/vnr/texthook/ihf_p.cc deleted file mode 100644 index b456c4f..0000000 --- a/vnr/texthook/ihf_p.cc +++ /dev/null @@ -1,583 +0,0 @@ -// Host_p.cc -// 10/15/2011 jichi - -#include "texthook/ihf_p.h" -#include "texthook/ith_p.h" -#include "texthook/textthread_p.h" -#include "host/host.h" -#include "vnrhook/include/types.h" -#include "ithsys/ithsys.h" -#include "wintimer/wintimer.h" -#include - -#ifdef WITH_LIB_WINMAKER -# include "winmaker/winmaker.h" -#endif // WITH_LIB_WINMAKER - -//#define ITH_RUNNING_EVENT L"ITH_PIPE_EXIST" -//#define ITH_RUNNING_MUTEX L"ITH_RUNNING" -//#define ITH_MUTEX_NAME L"ITH_MAIN_RUNNING" - -//#define DEBUG "ihf_p.cc" -#include "sakurakit/skdebug.h" - -//#define ITH_WITH_LINK - -// - Construction - - -//bool Ihf::debug_ = true; -bool Ihf::enabled_ = true; - -//Settings *Ihf::settings_; -HookManager *Ihf::hookManager_; -qint64 Ihf::messageInterval_ = 250; // 0.25 secs by default, larger than the split_time (0.2sec) in ITH::setman -WId Ihf::parentWindow_; - -QHash Ihf::threadDelegates_; -//QHash Ihf::linkedDelegates_; -QHash Ihf::hookAddresses_; - -char Ihf::keptThreadName_[ITH_THREAD_NAME_CAPACITY]; - -bool Ihf::whitelistEnabled_; -qint32 Ihf::whitelist_[Ihf::WhitelistSize]; - -// Debugging output -//void Ihf::consoleOutput(const char *text) -//{ if (debug_) qDebug() << "texthook:console:" << text; } - -//void Ihf::consoleOutputW(const wchar_t *text) -//{ if (debug_) qDebug() << "texthook:console:" << QString::fromWCharArray(text); } - -void Ihf::init() -{ - IthInitSystemService(); - Host_Init(); -} -void Ihf::destroy() -{ - Host_Destroy(); - IthCloseSystemService(); -} - -// See also: HelloITH/main.cpp -bool Ihf::load() -{ - // 12/20/2013: This would crash the error of failure to create QTimer - //if (!parentWindow_) - - //::wm_register_hidden_class("vnrtexthook.class"); - //parentWindow_ = (WId)::wm_create_hidden_window("vnrtexthook.class", "vnrtexthook"); - - DOUT("enter"); - if (hookManager_) { - DOUT("leave: already loaded"); - return true; - } - - // Single instance protection - //HANDLE hMutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, ITH_MUTEX_NAME); // in kernel32.dll - //if (hMutex != 0 || ::GetLastError() != ERROR_FILE_NOT_FOUND) { - // ::CloseHandle(hMutex); - // return false; - //} - - // See: ITH/main.cpp - //if (!IthInitSystemService()) { - // DOUT("leave: error: failed to init system service"); - // return false; - //} - - if (::Host_Open()) { -#ifdef WITH_LIB_WINMAKER - if (!parentWindow_) - parentWindow_ = (WId)::wm_create_hidden_window("vnrtexthook"); -#endif // WITH_LIB_WINMAKER - WinTimer::setGlobalWindow(parentWindow_); - ::Host_GetHookManager(&hookManager_); - if (hookManager_) { - //::Host_GetSettings(&settings_); - //settings_->debug = debug_; - - //hookManager_->RegisterConsoleCallback(consoleOutput); - //hookManager_->RegisterConsoleWCallback(consoleOutputW); - //hookManager_->RegisterProcessAttachCallback(processAttach); - //hookManager_->RegisterProcessDetachCallback(processDetach); - //hookManager_->RegisterProcessNewHookCallback(processNewHook); - //hookManager_->RegisterThreadResetCallback(threadReset); - hookManager_->RegisterThreadCreateCallback(threadCreate); - hookManager_->RegisterThreadRemoveCallback(threadRemove); - - ::Host_Start(); - } - } else - ::Host_Close(); - DOUT("leave: hook manager =" << hookManager_); - return hookManager_; -} - -void Ihf::unload() -{ - DOUT("enter: hook manager =" << hookManager_); - if (hookManager_) { - //hookManager_->RegisterProcessAttachCallback(nullptr); - //hookManager_->RegisterProcessDetachCallback(nullptr); - //hookManager_->RegisterProcessNewHookCallback(nullptr); - //hookManager_->RegisterThreadResetCallback(nullptr); - hookManager_->RegisterThreadCreateCallback(nullptr); - hookManager_->RegisterThreadRemoveCallback(nullptr); - // Console output is not unregisterd to avoid segmentation fault - //hookManager_->RegisterConsoleCallback(nullptr); - - ::Host_Close(); - hookManager_ = nullptr; - //settings_ = nullptr; - -#ifdef WITH_LIB_WINMAKER - if (parentWindow_) { - wm_destroy_window(parentWindow_); - parentWindow_ = nullptr; - } -#endif // WITH_LIB_WINMAKER - } - //if (parentWindow_) { - // wm_destroy_window(parentWindow_); - // parentWindow_ = nullptr; - //} - DOUT("leave"); -} - -// - Callbacks - - -//DWORD Ihf::processAttach(DWORD pid) -//{ -// DOUT("enter"); -// Q_UNUSED(pid); -// DOUT("leave"); -// return 0; -//} - -//DWORD Ihf::processDetach(DWORD pid) -//{ -// DOUT("enter"); -// Q_UNUSED(pid); -// DOUT("leave"); -// return 0; -//} - -//DWORD Ihf::processNewHook(DWORD pid) -//{ -// DOUT("enter"); -// Q_UNUSED(pid); -// DOUT("leave"); -// return 0; -//} - -// See: HelloITH/main.cpp -// See: ThreadCreate in ITH/window.cpp -DWORD Ihf::threadCreate(TextThread *t) -{ - Q_ASSERT(t); - DOUT("enter: pid =" << t->PID()); - Q_ASSERT(hookManager_); - - // Propagate UNICODE - // See: ThreadCreate in ITH/window.cpp - //if (ProcessRecord *pr = hookManager_->GetProcessRecord(t->PID())) { - // NtWaitForSingleObject(pr->hookman_mutex, 0, 0); - // Hook *hk = static_cast(pr->hookman_map); - // Q_ASSERT(!hk&&!MAX_HOOK || hk&&MAX_HOOK); - // for (int i = 0; i < MAX_HOOK; i++) { - // if (hk[i].Address() == t->Addr()) { - // if (hk[i].Type() & USING_UNICODE) - // t->Status() |= USING_UNICODE; - // break; - // } - // } - // NtReleaseMutant(pr->hookman_mutex, 0); - //} - auto d = new TextThreadDelegate(t); - bool init = true; - foreach (TextThreadDelegate *it, threadDelegates_) - if (d->signature() == it->signature()) { - TextThreadDelegate::release(d); - d = it; - d->retain(); - init = false; - break; - } - if (init) { - d->setInterval(messageInterval_); - d->setParentWindow(parentWindow_); - updateLinkedDelegate(d); - } - threadDelegates_[t] = d; - t->RegisterOutputCallBack(threadOutput, d); - //t->RegisterFilterCallBack(threadFilter, d); - DOUT("leave"); - return 0; -} - -// See also: HelloITH/main.cpp -DWORD Ihf::threadRemove(TextThread *t) -{ - DOUT("enter"); - Q_ASSERT(t); - - auto p = threadDelegates_.find(t); - if (p != threadDelegates_.end()) { - auto d = p.value(); - //if (!linkedDelegates_.isEmpty()) { - // linkedDelegates_.remove(d); - // while (auto k = linkedDelegates_.key(d)) - // linkedDelegates_.remove(k); - //} - threadDelegates_.erase(p); - TextThreadDelegate::release(d); - } - -#ifdef ITH_WITH_LINK - ::Host_UnLinkAll(t->Number()); -#endif // ITH_WITH_LINK - - DOUT("leave"); - return 0; -} - -// See: HelloITH/main.cpp -DWORD Ihf::threadOutput(TextThread *t, BYTE *data, DWORD dataLength, DWORD newLine, PVOID pUserData, bool space) -{ - DOUT("newLine =" << newLine << ", dataLength =" << dataLength << ", space =" << space); - Q_UNUSED(t) - Q_ASSERT(data); - Q_ASSERT(pUserData); - - auto d = static_cast(pUserData); - //if (TextThreadDelegate *link = findLinkedDelegate(d)) - // d = link; - Q_ASSERT(d); - if (!enabled_ || - whitelistEnabled_ && - !whitelistContains(d->signature()) && - !(keptThreadName_[0] && d->nameEquals(keptThreadName_))) { - DOUT("leave: ignored"); - return dataLength; - } - if (newLine) - d->touch(); - //d->flush(); // new line data are ignored - else if (dataLength || space) - d->append(reinterpret_cast(data), dataLength, space); - //QString text = QString::fromLocal8Bit(reinterpret_cast(data), len); - DOUT("leave"); - return dataLength; -} - -//TextThreadDelegate *Ihf::findLinkedDelegate(TextThreadDelegate *d) -//{ -// Q_ASSERT(d); -// if (!linkedDelegates_.isEmpty()) { -// auto p = linkedDelegates_.find(d); -// if (p != linkedDelegates_.end()) -// return p.value(); -// } -// return nullptr; -//} - -void Ihf::updateLinkedDelegate(TextThreadDelegate *d) -{ -#ifdef ITH_WITH_LINK - Q_ASSERT(t); - foreach (TextThreadDelegate *it, threadDelegates_) - if (it->delegateOf(d)) - ::Host_AddLink(d->threadNumber(), it->threadNumber()); - else if (d->delegateOf(it)) - ::Host_AddLink(it->threadNumber(), d->threadNumber()); -#else - Q_UNUSED(d); -#endif // ITH_WITH_LINK -} - -// - Injection - - -// See: Host_InjectByPID in IHF/main.cpp -// See: InjectThread in ITH/profile.cpp -bool Ihf::attachProcess(DWORD pid) -{ - DOUT("enter: pid =" << pid); - bool ok = ::Host_InjectByPID(pid); - - //enum { AttachDelay = 500 }; // in msec - //::Sleep(AttachDelay); - - DOUT("leave: ret =" << ok); - return ok; -} - -// See: Host_ActiveDetachProcess in IHF/main.cpp -bool Ihf::detachProcess(DWORD pid) { return ::Host_ActiveDetachProcess(pid); } -bool Ihf::hijackProcess(DWORD pid) { return ::Host_HijackProcess(pid); } - -// - Hook - - -// See: Host_ModifyHook in IHF/main.cpp -bool Ihf::updateHook(ulong pid, const QString &code) -{ - DOUT("enter: pid =" << pid << ", code =" << code); - Q_ASSERT(pid); - HookParam hp = {}; - if (!Ith::parseHookCode(code, &hp)) { - DOUT("leave: failed to parse hook code"); - return false; - } - - DWORD hh = ::Host_ModifyHook(pid, &hp); - bool ok = ~hh; - DOUT("leave: ret =" << ok); - return ok; -} - -// See: Host_InsertHook in IHF/main.cpp -bool Ihf::addHook(ulong pid, const QString &code, const QString &name, bool verbose) -{ - DOUT("enter: pid =" << pid << ", name =" << name << ", code =" << code); - Q_ASSERT(pid); - if (hookAddresses_.contains(code)) { - DOUT("leave: already added"); - return false; - } - - HookParam hp = {}; - if (!Ith::parseHookCode(code, &hp, verbose)) { - DOUT("leave: failed to parse hook code"); - return false; - } - - DWORD hh = ::Host_InsertHook(pid, &hp, name.toAscii()); - //DWORD hh = ::NewHook(hp, nameBuf); - bool ok = ~hh; - if (ok && hp.address) { - DOUT("hook address =" << hp.address); - hookAddresses_[code] = hp.address; - } - DOUT("leave: ok =" << ok); - return ok; -} - -// See: Host_RemoveHook in IHF/main.cpp -bool Ihf::removeHook(ulong pid, const QString &code) -{ - DOUT("enter: pid =" << pid << ", code =" << code); - Q_ASSERT(pid); - auto p = hookAddresses_.find(code); - if (p == hookAddresses_.end()) { - DOUT("leave: hook not added"); - return false; - } - DWORD addr = p.value(); - Q_ASSERT(addr); - hookAddresses_.erase(p); - - DWORD hh = ::Host_RemoveHook(pid, addr); - bool ok = ~hh; - DOUT("leave: ret =" << ok); - return ok; -} - -bool Ihf::verifyHookCode(const QString &code) -{ return Ith::verifyHookCode(code); } - -// - Whitelist - - -QList Ihf::whitelist() -{ - QList ret; - const qint32 *p = whitelist_; - while (*p) - ret.append(*p++); - return ret; -} - -void Ihf::clearWhitelist() { *whitelist_= 0; } - -void Ihf::setWhitelist(const QList &l) -{ - qint32 *p = whitelist_; - if (!l.isEmpty()) - foreach (qint32 it, l) { - *p++ = it; - if (p >= whitelist_ + WhitelistSize) - break; - } - whitelist_[qMin(l.size(), WhitelistSize -1)] = 0; -} - -bool Ihf::whitelistContains(qint32 signature) -{ - const qint32 *p = whitelist_; - while (*p) - if (signature == *p++) - return true; - return false; -} - -// EOF - -/* -BYTE LeadByteTable[0x100] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1 -}; - -DWORD Ihf::threadFilter(TextThread *thread, BYTE *out, DWORD len, DWORD new_line, PVOID data) -{ - DWORD status = thread->Status(); - - if (!new_line && thread->Number() != 0) - { - if (status & USING_UNICODE) - { - DWORD i, j; - len >>= 1; - WCHAR c, *str = (LPWSTR)out; - for (i = 0, j = 0; i < len; i++) - { - c = str[i]; - //if (!uni_filter->Check(c)) - str[j++] = c; - - } - memset(str + j, 0, (len - j) << 1); - len = j << 1; - } - else - { - WORD c; - DWORD i, j; - for (i = 0, j = 0; i < len; i++) - { - c = out[i]; - if (LeadByteTable[c] == 1) - { - //if (!mb_filter->Check(c)) - out[j++] = c & 0xFF; - } - else if (i + 1 < len) - { - - c = out[i + 1]; - c <<= 8; - c |= out[i]; - //if (!mb_filter->Check(c)) - { - out[j++] = c & 0xFF; - out[j++] = c >> 8; - } - i++; - } - } - memset(out + j, 0, len - j); - len = j; - } - } - return len; -} -*/ - - -/* -// jichi: 10/15/2011: FIXME: This overload will infect the entire program, -// even source files that exclude this header, which is unexpected. -// No idea what is the trade off of this behavior on performance and liability. -// Lots of Qt stuff doesn't work such as QString::toStdString. -// I have to use dynamic linkage to avoid being polluted by this module. -// -// original author: HEAP_ZERO_MEMORY flag is critical. All new object are assumed with zero initialized. -// jichi: 10/20/2011: I think the only reason to use Rtl heap here is to ensure HEAP_ZERO_MEMORY, -// which is really a bad programming style and incur unstability on heap memory allocation. -// ::RtlFreeHeap crash on DLL debug mode. Replace it with standard malloc/free. -// ::hHeap handle is also removed from ith/sys.c.cc - -inline void * __cdecl operator new(size_t lSize) -{ return ::RtlAllocateHeap(::hHeap, HEAP_ZERO_MEMORY, lSize); } - -inline void * __cdecl operator new[](size_t lSize) -{ return ::RtlAllocateHeap(::hHeap, HEAP_ZERO_MEMORY, lSize); } - -inline void __cdecl operator delete(void *pBlock) -{ ::RtlFreeHeap(::hHeap, 0, pBlock); } - -inline void __cdecl operator delete[](void* pBlock) -{ ::RtlFreeHeap(::hHeap, 0, pBlock); } - - -#include -#include -inline void * __cdecl operator new(size_t size) throw() -{ - if (!size) // When the value of the expression in a direct-new-declarator is zero, - size = 4; // the allocation function is called to allocatean array with no elements.(ISO) - - void *p = malloc(size); - if (p) - memset(p, 0, size); - return p; -} - -inline void * __cdecl operator new[](size_t size) throw() -{ - if (!size) // When the value of the expression in a direct-new-declarator is zero, - size = 4; // the allocation function is called to allocatean array with no elements.(ISO) - - void *p = malloc(size); - if (p) - memset(p, 0, size); - return p; -} - -inline void __cdecl operator delete(void *p) throw() { free(p); } -inline void __cdecl operator delete[](void *p) throw() { free(p); } -*/ - - -//QString -//Ihf::getHookNameById(ulong hookId) -//{ -// QString ret; -// if (hookId) { -// auto p = reinterpret_cast(hookId); -// if (p->good()) -// ret = p->name(); -// } -// return ret; -//} - -//DWORD ProcessAttach(DWORD pid) -//{ -// DOUT("process attached, pid =" << pid); -// return 0; -//} -//DWORD ProcessDetach(DWORD pid) -//{ -// DOUT("process detached, pid =" << pid); -// return 0; -//} -//DWORD ProcessNewHook(DWORD pid) -//{ -// DOUT("process has new hook inserted, pid =" << pid); -// return 0; -//} diff --git a/vnr/texthook/ihf_p.h b/vnr/texthook/ihf_p.h deleted file mode 100644 index 2d3e2b8..0000000 --- a/vnr/texthook/ihf_p.h +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once - -// ihf_p.h -// 10/15/2011 jichi -// Internal header. -// Wrapper of IHF functions. - -#include -#include -#include -#include // for WId - -//struct Settings; // opaque in ith/host/settings.h -class HookManager; // opaque in ith/host/hookman.h -class TextThread; // opaque in ith/host/textthread.h -class TextThreadDelegate; - -enum { ITH_THREAD_NAME_CAPACITY = 0x200 }; // used internally by ITH - -class Ihf -{ - Ihf() {} // Singleton - - static bool enabled_; - - //static Settings *settings_; - static HookManager *hookManager_; - static qint64 messageInterval_; - static WId parentWindow_; - - static QHash threadDelegates_; - //static QHash linkedDelegates_; - static QHash hookAddresses_; - - enum { WhitelistSize = 0x20 + 1 }; // ITH capacity is 0x20 - static qint32 whitelist_[WhitelistSize]; // List of signatures. The last element is zero. I.e., at most BlackSize-1 threads. - static bool whitelistEnabled_; - static char keptThreadName_[ITH_THREAD_NAME_CAPACITY]; - //static QString userDefinedThreadName_; - -public: - - // - Initialization - - static void init(); - static void destroy(); - - static bool load(); - static bool isLoaded() { return hookManager_; } - static void unload(); - - // - Properties - - - static bool isEnabled() { return enabled_; } - static void setEnabled(bool t) { enabled_ = t; } - - /// A valid window handle is required to make ITH work - static WId parentWindow() { return parentWindow_; } - static void setParentWindow(WId hwnd) { parentWindow_ = hwnd; } - - /// Timeout (msecs) for a text message - static qint64 messageInterval() { return messageInterval_; } - static void setMessageInterval(qint64 msecs) { messageInterval_ = msecs; } - - // - Injection - - static bool attachProcess(ulong pid); - static bool detachProcess(ulong pid); - static bool hijackProcess(ulong pid); - - /// Add hook code - static bool addHook(ulong pid, const QString &code, const QString &name = QString(), bool verbose = true); - static bool updateHook(ulong pid, const QString &code); // not used - static bool removeHook(ulong pid, const QString &code); - static bool verifyHookCode(const QString &code); - - // - Whitelist - - static bool isWhitelistEnabled() { return whitelistEnabled_; } - static void setWhitelistEnabled(bool t) { whitelistEnabled_ = t; } - - static QList whitelist(); - static void setWhitelist(const QList &l); - static void clearWhitelist(); - - //static QString userDefinedThreadName() { return userDefinedThreadName_; } - //static void setUserDefinedThreadName(const QString &val) { userDefinedThreadName_ = val; } - static const char *keptThreadName() { return keptThreadName_; } - - static void setKeptThreadName(const QString &v) - { - if (v.size() < ITH_THREAD_NAME_CAPACITY) - ::strcpy(keptThreadName_, v.toAscii()); - else - setKeptThreadName(v.left(ITH_THREAD_NAME_CAPACITY - 1)); - } - -private: - static bool whitelistContains(qint32 signature); - - // - Callbacks - - //static ulong processAttach(ulong pid); - //static ulong processDetach(ulong pid); - //static ulong processNewHook(ulong pid); - - static ulong threadCreate(_In_ TextThread *t); - static ulong threadRemove(_In_ TextThread *t); - static ulong threadOutput(_In_ TextThread *t, _In_ uchar *data, _In_ ulong dataLength, _In_ ulong bNewLine, _In_ void *pUserData, _In_ bool space); - //static ulong threadFilter(_In_ TextThread *t, _Out_ uchar *data, _In_ ulong dataLength, _In_ ulong bNewLine, _In_ void *pUserData); - //static ulong threadReset(TextThread *t); - //static void consoleOutput(const char *text); - //static void consoleOutputW(const wchar_t *text); - - // - Linked threasds - -private: - //static TextThreadDelegate *findLinkedDelegate(TextThreadDelegate *d); - static void updateLinkedDelegate(TextThreadDelegate *d); -}; - -// EOF diff --git a/vnr/texthook/ith_p.cc b/vnr/texthook/ith_p.cc deleted file mode 100644 index 7a7d3d7..0000000 --- a/vnr/texthook/ith_p.cc +++ /dev/null @@ -1,275 +0,0 @@ -// ith_p.cc -// 10/15/2011 jichi - -#include "texthook/ith_p.h" -#include "vnrhook/include/const.h" -#include "vnrhook/include/types.h" -#include - -#define DEBUG "ith_p.cc" -#include "sakurakit/skdebug.h" - -// HookParam copied from ITH/common.h: -// struct HookParam // size = 40 (0x24) -// { -// typedef void (*DataFun)(DWORD, HookParam*, DWORD*, DWORD*, DWORD*); -// -// DWORD addr; // 4 -// DWORD off, // 8 -// ind, // 12 -// split, // 16 -// split_ind; // 20 -// DWORD module, // 24 -// function; // 28 -// DataFun text_fun; // 32, jichi: is this the same in x86 and x86_64? -// DWORD type; // 36 -// WORD length_offset; // 38 -// BYTE hook_len, // 39 -// recover_len; // 40 -// }; - - -// - Implementation Details - - -namespace { namespace detail { // unnamed - -// ITH ORIGINAL CODE BEGIN - -// See: ITH/ITH.h -// Revision: 133 -inline DWORD Hash(_In_ LPWSTR module, int length = -1) -{ - bool flag = length == -1; - DWORD hash = 0; - for (; *module && (flag || length--); module++) - hash = _rotr(hash,7) + *module; //hash=((hash>>7)|(hash<<25))+(*module); - return hash; -} - -// See: ITH/command.cpp -// Revision: 133 -// -// jichi note: str[0xF] will be modified and restored. -// So, the buffer of str must be larger than 0xF. -int Convert(_In_ LPWSTR str, _Out_ DWORD *num, _In_ LPWSTR delim) -{ - if (!num) - return -1; - WCHAR t = *str, - tc = *(str + 0xF); - WCHAR temp[0x10] = {}; - LPWSTR it = temp, - istr = str, - id = temp; - if (delim) { - id = wcschr(delim, t); - str[0xF] = delim[0]; // reset str[0xF] in case of out-of-bound iteration - } - else - str[0xF] = 0; // reset str[0xF] in case of out-of-bound iteration - while (!id && t) { - *it = t; - it++; istr++; - t = *istr; - if (delim) - id = wcschr(delim, t); - } - swscanf(temp, L"%x", num); - str[0xF] = tc; // restore the str[0xF] - if (!id || istr - str == 0xF) - return -1; - - if (!t) - return istr - str; // >= 0 - else - return id - delim; // >= 0 -} - -// See: ITH/command.cpp -// Revision: 133 -// -// jichi note: str[0xF] will be modified and restored. -// So, the buffer of cmd must be larger than 0xF*2 = 0x1F. -bool Parse(_In_ LPWSTR cmd, _Out_ HookParam &hp) -{ - ::memset(&hp, 0, sizeof(hp)); - - int t; - bool accept = false; - DWORD *data = &hp.offset; // - LPWSTR offset = cmd + 1; - LPWSTR delim_str = L":*@!"; - LPWSTR delim = delim_str; - if (*offset == L'n' || *offset == 'N') { - offset++; - hp.type |= NO_CONTEXT; - } - // jichi 4/25/2015: Add support for fixing hook - if (*offset == L'f' || *offset == 'F') { - offset++; - hp.type |= FIXING_SPLIT; - } - if (*offset == L'j' || *offset == 'J') { // 11/22/2015: J stands for Japanese only - offset++; - hp.type |= NO_ASCII; - } - while (!accept) { - t = Convert(offset, data, delim); - if (t < 0) - return false; //ConsoleOutput(L"Syntax error."); - offset = ::wcschr(offset , delim[t]); - if (offset) - offset++; // skip the current delim - else //goto _error; - return false; //ConsoleOutput(L"Syntax error."); - switch (delim[t]) { - case L':': - data = &hp.split; - delim = delim_str + 1; - hp.type |= USING_SPLIT; - break; - case L'*': - if (hp.split) { - data = &hp.split_index; - delim = delim_str + 2; - hp.type |= SPLIT_INDIRECT; - } - else { - hp.type |= DATA_INDIRECT; - data = &hp.index; - } - break; - case L'@': - accept = true; - break; - } - } - t = Convert(offset, &hp.address, delim_str); - if (t < 0) - return false; - if (hp.offset & 0x80000000) - hp.offset -= 4; - if (hp.split & 0x80000000) - hp.split -= 4; - LPWSTR temp = offset; - offset = ::wcschr(offset, L':'); - if (offset) { - hp.type |= MODULE_OFFSET; - offset++; - delim = ::wcschr(offset, L':'); - - if (delim) { - *delim = 0; - delim++; - _wcslwr(offset); - hp.function = Hash(delim); - hp.module = Hash(offset, delim - offset - 1); - hp.type |= FUNCTION_OFFSET; - } - else - hp.module = Hash(_wcslwr(offset)); - - } else { - offset = ::wcschr(temp, L'!'); - if (offset) { - hp.type |= MODULE_OFFSET; - swscanf(offset + 1, L"%x", &hp.module); - offset = ::wcschr(offset + 1, L'!'); - if (offset) { - hp.type |= FUNCTION_OFFSET; - swscanf(offset + 1, L"%x", &hp.function); - } - } - } - switch (*cmd) { - case L's': - case L'S': - hp.type |= USING_STRING; - break; - case L'e': - case L'E': - hp.type |= STRING_LAST_CHAR; - case L'a': - case L'A': - hp.type |= BIG_ENDIAN; - hp.length_offset = 1; - break; - case L'b': - case L'B': - hp.length_offset = 1; - break; - // jichi 12/7/2014: Disabled - //case L'h': - //case L'H': - // hp.type |= PRINT_DWORD; - case L'q': - case L'Q': - hp.type |= USING_STRING | USING_UNICODE; - break; - case L'l': - case L'L': - hp.type |= STRING_LAST_CHAR; - case L'w': - case L'W': - hp.type |= USING_UNICODE; - hp.length_offset = 1; - break; - default: ; - } - //ConsoleOutput(L"Try to insert additional hook."); - return true; -} - -// ITH ORIGINAL CODE END - -}} // unnamed detail - -// - ITH API - - -// Sample code: L"/HS-4:-14@4383C0" (WHITE ALBUM 2) -bool Ith::parseHookCode(const QString &code, HookParam *hp, bool verbose) -{ -#define HCODE_PREFIX "/H" - enum { HCODE_PREFIX_LEN = sizeof(HCODE_PREFIX) -1 }; // 2 - if (!hp || !code.startsWith(HCODE_PREFIX)) - return false; - if (verbose) - DOUT("enter: code =" << code); - else - DOUT("enter"); - - size_t bufsize = qMax(0xFF, code.size() + 1); // in case detail::Convert modify the buffer - auto buf = new wchar_t[bufsize]; - code.toWCharArray(buf); - buf[code.size()] = 0; - - bool ret = detail::Parse(buf + HCODE_PREFIX_LEN, *hp); - delete[] buf; -#ifdef DEBUG - if (ret && verbose) - qDebug() - << "addr:" << hp->address - << ", text_fun:" << hp->text_fun - << ", function:"<< hp->function - << ", hook_len:" << hp->hook_len - << ", ind:" << hp->index - << ", length_offset:" << hp->length_offset - << ", module:" << hp->module - << ", off:" <offset - << ", recover_len:" << hp->recover_len - << ", split:" << hp->split - << ", split_ind:" << hp->split_index - << ", type:" << hp->type; -#endif // DEBUG - DOUT("leave: ret =" << ret); - return ret; -#undef HOOK_CODE_PREFIX -} - -bool Ith::verifyHookCode(const QString &code) -{ - HookParam hp = {}; - return parseHookCode(code, &hp); -} - -// EOF diff --git a/vnr/texthook/ith_p.h b/vnr/texthook/ith_p.h deleted file mode 100644 index 66fbd64..0000000 --- a/vnr/texthook/ith_p.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -// ith_p.h -// 10/15/2011 jichi -// Internal header. -// Wrapper of functions from ITH. - -#include - -struct HookParam; // opaque, declared in ITH/common.h - -namespace Ith { - -/// Parse hook code, and save the result to hook param if succeeded. -bool parseHookCode(_In_ const QString &code, _Out_ HookParam *hp, bool verbose = true); -bool verifyHookCode(_In_ const QString &code); - -} // namespace Ith - -// EOF diff --git a/vnr/texthook/texthook.cc b/vnr/texthook/texthook.cc deleted file mode 100644 index 0d4aae6..0000000 --- a/vnr/texthook/texthook.cc +++ /dev/null @@ -1,414 +0,0 @@ -// texthook.cc -// 10/14/2011 jichi - -#include "texthook/texthook.h" -#include "texthook/texthook_p.h" -#include "texthook/ihf_p.h" -#include "texthook/textthread_p.h" -#include "texthook/winapi_p.h" -#include - -//#define DEBUG "texthook.cc" -#include "sakurakit/skdebug.h" - -//#include -//namespace { int _ = IthInitSystemService(); } - -/** Private class */ - -TextHookPrivate *TextHookPrivate::instance_; - -/** Public class */ - -// - Construction - - -//TextHook *TextHook::g_; -//TextHook *TextHook::globalInstance() { static Self g; return &g; } - -//TextHook::TextHook(QObject *parent) -// : Base(parent), d_(new D) -//{} - -TextHook::TextHook(QObject *parent) - : Base(parent), d_(new D(this)) -{ - Ihf::init(); - //Ihf::setUserDefinedThreadName(d_->source); - DOUT("pass"); -} - -TextHook::~TextHook() -{ - DOUT("enter"); - if (isActive()) - stop(); - delete d_; - - Ihf::destroy(); - DOUT("leave"); -} - -// - Properties - - -int TextHook::dataCapacity() const -{ return TextThreadDelegate::capacity(); } - -void TextHook::setDataCapacity(int value) -{ TextThreadDelegate::setCapacity(value); } - -bool TextHook::removesRepeat() const -{ return TextThreadDelegate::removesRepeat(); } - -void TextHook::setRemovesRepeat(bool value) -{ TextThreadDelegate::setRemovesRepeat(value); } - -bool TextHook::keepsSpace() const -{ return TextThreadDelegate::keepsSpace(); } - -void TextHook::setKeepsSpace(bool value) -{ TextThreadDelegate::setKeepsSpace(value); } - -bool TextHook::wideCharacter() const -{ return TextThreadDelegate::wideCharacter(); } - -void TextHook::setWideCharacter(bool value) -{ TextThreadDelegate::setWideCharacter(value); } - -// see: ITH/common.h -int TextHook::capacity() const -{ return 0x20; } - -QString TextHook::defaultHookName() const -{ return d_->source; } - -void TextHook::setDefaultHookName(const QString &name) -{ - d_->source = name; - //Ihf::setUserDefinedThreadName(name); -} - -bool TextHook::isEnabled() const -{ return d_->enabled; } - -void TextHook::setEnabled(bool t) -{ - d_->enabled = t; - Ihf::setEnabled(t); -} - -bool TextHook::isActive() const -{ return Ihf::isLoaded(); } - -void TextHook::start() -{ Ihf::load(); } - -void TextHook::stop() -{ - if (!isEmpty()) - clear(); - Ihf::unload(); -} - -WId TextHook::parentWinId() const { return Ihf::parentWindow(); } -void TextHook::setParentWinId(WId hwnd) { Ihf::setParentWindow(hwnd); } - -int TextHook::interval() const -{ return Ihf::messageInterval(); } - -void TextHook::setInterval(int msecs) -{ Ihf::setMessageInterval(msecs); } - -// - Injection - - -void TextHook::clear() -{ - DOUT("enter"); - foreach (ulong pid, d_->pids) - detachProcess(pid); - if (!d_->hooks.isEmpty()) - d_->hooks.clear(); - clearThreadWhitelist(); - DOUT("leave"); -} - -bool TextHook::containsProcess(ulong pid) const { return d_->pids.contains(pid); } -bool TextHook::isEmpty() const { return d_->pids.isEmpty(); } - -//QList TextHook::attachedProcesses(bool checkActive) const -//{ -// if (isEmpty() || !checkActive) -// return d_->pids; -// -// QList ret; -// foreach (ulong pid, d_->pids) -// if (winapi::IsProcessActiveWithId(pid)) -// ret.append(pid); -// return ret; -//} - -//ulong TextHook::currentProccess() const -//{ return anyAttachedProcess(true); } // check active = true - -//ulong TextHook::anyAttachedProcess(bool checkActive) const -//{ -// if (isEmpty()) -// return 0; -// if (!checkActive) -// return d_->pids.first(); -// -// foreach (ulong pid, d_->pids) -// if (winapi::IsProcessActiveWithId(pid)) -// return pid; -// return 0; -//} - -//bool TextHook::attachOneProcess(ulong pid, bool checkActive) -//{ -// DOUT("enter: pid =" << pid); -// DOUT("isAttached =" << containsProcess(pid)); -// if (!isActive()) -// start(); -// -// if (checkActive && !winapi::IsProcessActiveWithId(pid)) { -// DOUT("leave: ret = false, isActive = false"); -// return false; -// } -// -// if (containsProcess(pid)) { -// DOUT("leave: pid already attached"); -// return true; -// } -// -// detachAllProcesses(); -// -// bool ret = Ihf::attachProcess(pid); -// if (ret && !containsProcess(pid)) { -// d_->pids.removeAll(pid); -// d_->pids.append(pid); -// emit processAttached(pid); -// } -// -// DOUT("leave: ret =" << ret); -// return ret; -//} - -bool TextHook::attachProcess(ulong pid, bool checkActive) -{ - DOUT("enter: pid =" << pid << ", isAttached =" << containsProcess(pid)); - if (!isActive()) - start(); - Q_ASSERT(isActive()); - DOUT("isActive =" << isActive()); - - if (checkActive && !winapi::IsProcessActiveWithId(pid)) { - DOUT("leave: ret = false, isActive = false"); - return false; - } - - bool ret = Ihf::attachProcess(pid); - if (ret) { - d_->pids.insert(pid); - emit processAttached(pid); - } - - DOUT("leave: ret =" << ret); - return ret; -} - -bool TextHook::detachProcess(ulong pid, bool checkActive) -{ - DOUT("enter: pid =" << pid << ", isAttached =" << containsProcess(pid)); - Q_ASSERT(isActive()); - - auto it = d_->pids.find(pid); - if (it == d_->pids.end()) { - DOUT("leave: ret = false, not attached"); - return false; - } - d_->pids.erase(it); - d_->hooks.remove(pid); - - if (checkActive && !winapi::IsProcessActiveWithId(pid)) { - emit processDetached(pid); - DOUT("leave: ret = false, isActive = false"); - return false; - } - - bool ret = Ihf::detachProcess(pid); - //try { - // ret = Ihf::detachProcess(pid); - //} catch (...) { - // DOUT("warning: detach exception"); - //} - - emit processDetached(pid); - DOUT("leave: ret =" << ret); - return ret; -} - -bool TextHook::hijackProcess(ulong pid) -{ - DOUT("enter: pid =" << pid); - Q_ASSERT(isActive()); - - if (!containsProcess(pid)) { - DOUT("leave: aborted, process not attached"); - return false; - } - - // 7/12/2015: Function disabled - return true; - - //bool ret = Ihf::hijackProcess(pid); - //DOUT("leave: ret =" << ret); - //return ret; -} - -//void TextHook::detachAllProcesses() -//{ -// DOUT("enter"); -// foreach (ulong pid, d_->pids) -// detachProcess(pid); -// if (!d_->hooks.isEmpty()) -// d_->hooks.clear(); -// DOUT("leave"); -//} - -// - Hook - - -//bool TextHook::containsHook(ulong pid) const -//{ return d_->hooks.contains(pid); } -// -//bool TextHook::containsHook(ulong pid, const QString &code) const -//{ return processHook(pid) == code; } - -bool TextHook::addHookCode(ulong pid, const QString &code, const QString &name, bool verbose) -{ - DOUT("enter: pid =" << pid << ", code =" << code); - if (isEmpty() || !containsProcess(pid)) { - DOUT("leave: failed, process not attached"); - return false; - } - if (d_->hooks.contains(pid)) { - DOUT("leave: failed, hook already exists"); - return false; - } - bool ok = Ihf::addHook(pid, code, - name.isEmpty() ? defaultHookName() : name, - verbose); - if (ok) - d_->hooks[pid] = code; - DOUT("leave: ret =" << ok); - return ok; -} - -bool TextHook::verifyHookCode(const QString &code) { return Ihf::verifyHookCode(code); } - -bool TextHook::removeHookCode(ulong pid) -{ - DOUT("enter"); - auto p = d_->hooks.find(pid); - if (p == d_->hooks.end()) { - DOUT("leave: not hooked"); - return false; - } - - //DOUT("remove existing hook, THIS SHOULD NOT HAPPEN"); - bool ok = Ihf::removeHook(pid, p.value()); - d_->hooks.erase(p); - DOUT("leave: ret =" << ok); - return ok; -} - -//QString TextHook::processHook(ulong pid) const -//{ -// auto p = d_->hooks.find(pid); -// return p == d_->hooks.end() ? QString() : p.value(); -//} - -bool TextHook::isThreadWhitelistEnabled() const { return Ihf::isWhitelistEnabled(); } - -void TextHook::setThreadWhitelistEnabled(bool t) { Ihf::setWhitelistEnabled(t); } - -QList TextHook::threadWhitelist() const { return Ihf::whitelist(); } - -void TextHook::setThreadWhitelist(const QList &sigs) { Ihf::setWhitelist(sigs); } - -void TextHook::clearThreadWhitelist() { Ihf::clearWhitelist(); } - -QString TextHook::keptThreadName() const { return Ihf::keptThreadName(); } - -void TextHook::setKeptThreadName(const QString &v) { Ihf::setKeptThreadName(v); } - -// EOF - -/* -QString -TextHook::guessEncodingForFile(const QString &fileName) -{ - static QHash db; - if (db.isEmpty()) { - db["malie.exe"] = "UTF-16"; - } - auto p = db.find(fileName); - return p == db.end() ? QString() : p.value(); -} - -// - Helpers - - -bool -TextHook::isStandardHookName(const QString &name) const -{ - static QSet hashes; - if (hashes.isEmpty()) { -#define ADD(_text) hashes.insert(qHash(QString(_text))) - ADD("ConsoleOutput"); - ADD("GetTextExtentPoint32A"); - ADD("GetGlyphOutlineA"); - ADD("ExtTextOutA"); - ADD("TextOutA"); - ADD("GetCharABCWidthsA"); - ADD("DrawTextA"); - ADD("DrawTextExA"); - ADD("GetTextExtentPoint32W"); - ADD("GetGlyphOutlineW"); - ADD("ExtTextOutW"); - ADD("TextOutW"); - ADD("GetCharABCWidthsW"); - ADD("DrawTextW"); - ADD("DrawTextExW"); -#undef ADD - } - uint h = qHash(name); - return hashes.contains(h); -} - -bool -TextHook::isKnownHookForProcess(const QString &hook, const QString &proc) const -{ - // TODO: update database on line periodically - qDebug() << "qth::isKnownHookForProcess: hook =" << hook << ", proc =" << proc; - - static QSet hashes; - if (hashes.isEmpty()) { -#define ADD(_hook, _proc) hashes.insert(qHash(QString(_hook) + "\n" + _proc)) - //ADD("Malie", "malie"); // light - ADD("GetGlyphOutlineA", "STEINSGATE"); - ADD("StuffScriptEngine", "EVOLIMIT"); -#undef ADD - } - uint h = qHash(hook + "\n" + proc); - return hashes.contains(h); -} - -QString -TextHook::hookNameById(ulong hookId) const -{ - //return Ihf::getHookNameById(hookId); - // FIXME: supposed to be the engine name, unimplemented - Q_UNUSED(hookId) - return QString(); -} - - -*/ diff --git a/vnr/texthook/texthook.h b/vnr/texthook/texthook.h deleted file mode 100644 index 465040b..0000000 --- a/vnr/texthook/texthook.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -// texthook.h -// 10/14/2011 jichi - -#include "texthook_config.h" -#include "sakurakit/skglobal.h" -#include -#include -#include -#include -#include // for WId - -class TextHookPrivate; -/// Singleton class. Only one instance is allowed. -class TEXTHOOK_EXPORT TextHook : public QObject -{ - Q_OBJECT - Q_DISABLE_COPY(TextHook) - SK_EXTEND_CLASS(TextHook, QObject) - SK_DECLARE_PRIVATE(TextHookPrivate) - - // - Construction - -public: - explicit TextHook(QObject *parent = nullptr); - ~TextHook(); - -signals: - void dataReceived(QByteArray raw, QByteArray rendered, qint32 signature, QString source); - void processAttached(qint64 pid); - void processDetached(qint64 pid); - - // - Properties - -public: - /// Limited by ITH - int capacity() const; - - bool isEnabled() const; - void setEnabled(bool t); - - WId parentWinId() const; ///< Must be set to a valid window so that ::SetTimer works - void setParentWinId(WId hwnd); - - int interval() const; ///< Time to differentiate sentences - void setInterval(int msecs); - - int dataCapacity() const; ///< Maximum text length - void setDataCapacity(int value); - - bool removesRepeat() const; - void setRemovesRepeat(bool value); - - bool keepsSpace() const; - void setKeepsSpace(bool value); - - bool wideCharacter() const; - void setWideCharacter(bool value); - - QString defaultHookName() const; ///< The default one is "H-code" - void setDefaultHookName(const QString &name); - - bool isActive() const; - void start(); - void stop(); - void clear(); - - // - Injection - -public: - //bool attachOneProcess(ulong pid, bool checkActive = false); - bool attachProcess(ulong pid, bool checkActive = false); - bool detachProcess(ulong pid, bool checkActive = false); - bool hijackProcess(ulong pid); - //void detachAllProcesses(); - //QList attachedProcesses(bool checkActive = false) const; - //ulong anyAttachedProcess(bool checkActive = false) const; - //ulong currentProccess() const; - - bool containsProcess(ulong pid) const; - bool isEmpty() const; ///< Return true if at least one process is attached - - bool addHookCode(ulong pid, const QString &code, const QString &name = QString(), bool verbose = true); - static bool verifyHookCode(const QString &code); ///< Return if hcode is valid - //bool containsHook(ulong pid) const; - //bool containsHook(ulong pid, const QString &code) const; - //QString processHook(ulong pid) const; - //QString currentHook() const { return processHook(currentProccess()); } - bool removeHookCode(ulong pid); ///< Assume atmost one hcode per process - - // - Whitelist - -public: - bool isThreadWhitelistEnabled() const; - void setThreadWhitelistEnabled(bool t); - QList threadWhitelist() const; - void setThreadWhitelist(const QList &signatures); - void clearThreadWhitelist(); - // Note: len(v) must be smaller than 0x200 - void setKeptThreadName(const QString &v); - QString keptThreadName() const; -}; - -// EOF diff --git a/vnr/texthook/texthook.rc b/vnr/texthook/texthook.rc deleted file mode 100644 index 9344b78..0000000 --- a/vnr/texthook/texthook.rc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * texthook.rc - * 10/20/2011 jichi - */ -#if defined(UNDER_CE) -# include -#else -# include -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE 0x0L - BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904B0" - BEGIN - VALUE "CompanyName", "Sakuradite\0" - VALUE "FileDescription", "Text Hook\0" - VALUE "FileVersion", "1.0.0.0\0" - VALUE "LegalCopyright", "Copyright (C) 2012.\0" - VALUE "OriginalFilename", "texthook.dll\0" - VALUE "ProductName", "texthook\0" - END - END - END - -/* End of Version info */ diff --git a/vnr/texthook/texthook_config.h b/vnr/texthook/texthook_config.h deleted file mode 100644 index 467e8f9..0000000 --- a/vnr/texthook/texthook_config.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -// texthook_config.h -// 10/20/2011 jichi - -//#define TEXTHOOK_EXPORT - -#ifndef TEXTHOOK_EXPORT -# ifdef TEXTHOOK_STATIC_LIB -# define TEXTHOOK_EXPORT -# elif defined(TEXTHOOK_BUILD_LIB) -# define TEXTHOOK_EXPORT Q_DECL_EXPORT -# else -# define TEXTHOOK_EXPORT Q_DECL_IMPORT -# endif -#endif // TEXTHOOK_EXPORT - -#define TEXTHOOK_DEFAULT_NAME "H-code" - -// EOF diff --git a/vnr/texthook/texthook_p.h b/vnr/texthook/texthook_p.h deleted file mode 100644 index 44e34de..0000000 --- a/vnr/texthook/texthook_p.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -// texthook_p.h -// 10/14/2011 jichi -// Internal header. -// Defines TextHook private data. - -#include "texthook/texthook.h" -#include -#include - -// - Private - - -class TextHookPrivate -{ - SK_CLASS(TextHookPrivate) - SK_DECLARE_PUBLIC(TextHook) - - static Self *instance_; // global instance - - bool enabled; - QString source; - QSet pids; - QHash hooks; // ITH hook code, indexed by pid - - explicit TextHookPrivate(Q *q) - : q_(q), enabled(true), source(TEXTHOOK_DEFAULT_NAME) { instance_ = this; } - - ~TextHookPrivate() { instance_ = nullptr; } - -public: - static void sendData(const QByteArray &rawData, const QByteArray &renderedData, qint32 signature, const QString &name) - { - if (instance_ && instance_->q_->isEnabled()) - emit instance_->q_->dataReceived(rawData, renderedData, signature, name); - } -}; - -// EOF diff --git a/vnr/texthook/textthread_p.cc b/vnr/texthook/textthread_p.cc deleted file mode 100644 index 9c9454f..0000000 --- a/vnr/texthook/textthread_p.cc +++ /dev/null @@ -1,376 +0,0 @@ -// textthread_p.cc -// 6/6/2012 jichi - -#include "texthook/textthread_p.h" -#include "texthook/texthook_p.h" -#include "winmutex/winmutex.h" -#include "wintimer/wintimer.h" -#include "host/textthread.h" -#include - -//#define DEBUG "textthread_p.cc" -#include "sakurakit/skdebug.h" - -enum { ITH_THREAD_NAME_CAPACITY = 0x200 }; // used internally by ITH - -#define REPEAT_RX_1 "(.{2,})\\1+$" // The pattern has at least 2 bytes, and repeats at least once - -/** Private class */ - -#define D_LOCK win_mutex_lock d_lock(D::globalMutex) // Synchronized scope for accessing private data - -class TextThreadDelegatePrivate -{ - SK_CLASS(TextThreadDelegatePrivate) - SK_DISABLE_COPY(TextThreadDelegatePrivate) - -public: - typedef win_mutex mutex_type; - - static mutex_type globalMutex; // Used only in public class. Because ITH is running in another single thread - static int globalCapacity; // maximum text size - static bool globalRemovesRepeat; - static bool globalKeepsSpace; - static bool globalWideCharacter; - - TextThread *t; - WinTimer flushTimer; // as QTimer does not work with windows remote thread, use native WM_TIMER instead - - ulong signature; // buffered - char sourceBuffer[ITH_THREAD_NAME_CAPACITY]; // buffered - QString source; // buffered - - int bufferSize; - int bufferCapacity; - char *buffer; - bool removesRepeat; - - QByteArray spaceBuffer; - int spaceCount; - - struct Repeat - { - QRegExp rx; // cached - char *buffer; // repeated string - int size; - int pos; // >= 0, current pos of repeating string - int offset; // offset of repeated string - - Repeat() : rx(REPEAT_RX_1), buffer(nullptr), size(0), pos(0), offset(-1) {} - ~Repeat() { if (buffer) delete[] buffer; } - - void clear() - { - size = pos = 0; - offset = -1; - } - - bool isRepeating(const char *data, int len) const - { - if (!size || !buffer) - return false; - switch (len) { - case 1: return pos < size && buffer[pos] == *data; - case 2: return pos < size + 1 && buffer[pos] == data[0] && buffer[pos +1] == data[1]; - default: - if (pos + len >= size) - return false; - for (int i = 0; i < len; i++) - if (buffer[pos + i] != data[i]) - return false; - return true; - } - } - } repeat; - - // - Construction - -public: - explicit TextThreadDelegatePrivate(TextThread *thread) : t(thread), - bufferSize(0), bufferCapacity(globalCapacity), buffer(new char[globalCapacity]), - spaceCount(0), - removesRepeat(false) - { - signature = signatureOf(t); - - //size_t size = - t->GetThreadString(sourceBuffer, ITH_THREAD_NAME_CAPACITY); - source = sourceBuffer; - } - - ~TextThreadDelegatePrivate() { delete[] buffer; } - - // - Properties - -public: - //QString text() const { return QString::fromLocal8Bit(buffer); } - //ulong context() const { return t->GetThreadParameter()->retn; } - //ulong subcontext() const { return t->GetThreadParameter()->spl; } - - //ulong processId() const { return t->PID(); } - - // - Actions - -public: - void flush() - { - if (flushTimer.isActive()) - flushTimer.stop(); - if (bufferSize) { - send(); - bufferSize = 0; - } - if (!spaceBuffer.isEmpty()) - spaceBuffer.clear(); - spaceCount = 0; - } - - void syncGlobal() - { - if (bufferCapacity < globalCapacity) { - delete[] buffer; - bufferCapacity = globalCapacity; - buffer = new char[bufferCapacity]; - if (repeat.buffer) { - delete[] repeat.buffer; - if (!removesRepeat) - repeat.buffer = nullptr; - else { - char *largerBuffer = new char[bufferCapacity]; - if (repeat.size) - qMemCopy(largerBuffer, repeat.buffer, repeat.size); - repeat.buffer = largerBuffer; - } - } - //bufferSize = repeatOffset = 0; // already reset in flush - //if (removesRepeat) - // repeat.reset(); - } - if (removesRepeat != globalRemovesRepeat) { - removesRepeat = globalRemovesRepeat; - if (removesRepeat) - repeat.clear(); - } - } - - void appendSpace() - { - flushTimer.start(); - spaceCount++; - if (spaceBuffer.isEmpty()) - spaceBuffer.append(buffer, bufferSize); - spaceBuffer.append(' '); - if (globalWideCharacter) - spaceBuffer.append('\0'); // L' ' = {'\x20', '\0'}; - } - - void append(const char *data, int len) - { - flushTimer.start(); - if (bufferSize < qMin(bufferCapacity, globalCapacity)) - switch (len) { - case 1: buffer[bufferSize++] = *data; break; - case 2: buffer[bufferSize++] = *data; - if (bufferSize < bufferCapacity) - buffer[bufferSize++] = data[1]; - break; - default: - { - int diff = qMin(len, bufferCapacity - bufferSize); - qMemCopy(buffer + bufferSize, data, diff); - bufferSize += diff; - } - } - if (!spaceBuffer.isEmpty()) - spaceBuffer.append(data, len); - } - - void appendRepeat(const char *data, int len) - { - if (bufferSize + len >= qMin(bufferCapacity, globalCapacity)) // overflow - return; - if (repeat.isRepeating(data, len)) { - repeat.pos += len; - if (repeat.pos >= repeat.size) - repeat.pos = 0; - return; - } - repeat.clear(); - - append(data, len); - - if (bufferSize >= 6) { // at least 2 characters - // Use fromLatin1 to prevent the data from being decoded - QString t = QString::fromLatin1(buffer, bufferSize); - repeat.offset = repeat.rx.indexIn(t); - if (repeat.offset >= 0) { - repeat.size = repeat.rx.cap(1).size(); - if (!repeat.buffer) - repeat.buffer = new char[bufferCapacity]; - qMemCopy(repeat.buffer, buffer + repeat.offset, repeat.size); - //bufferSize = repeat.offset repeat.size; - } - } - } - -private: - void send() - { - int size; - if (removesRepeat && repeat.offset >= 0 && repeat.size) - size = repeat.offset + repeat.size; - else - size = bufferSize; - if (!spaceBuffer.isEmpty() && spaceBuffer.size() != size) - spaceBuffer.truncate(size + spaceCount); - TextHookPrivate::sendData( - QByteArray(buffer, size), spaceBuffer, - signature, source); - } - - static qint32 signatureOf(TextThread *t) - { - qint32 ret = - (t->GetThreadParameter()->retn & 0xffff) | // context - (t->GetThreadParameter()->spl & 0xffff) << 16; // subcontext - return ret ? ret : t->Addr(); - } - - //static QString sourceOf(TextThread *t); - -public: - static ulong contextOf(TextThread *t) - { return t->GetThreadParameter()->retn; } - - static ulong subcontextOf(TextThread *t) - { return t->GetThreadParameter()->spl; } -}; - -TextThreadDelegatePrivate::mutex_type TextThreadDelegatePrivate::globalMutex; -int TextThreadDelegatePrivate::globalCapacity = 512; -bool TextThreadDelegatePrivate::globalRemovesRepeat = false; -bool TextThreadDelegatePrivate::globalKeepsSpace = false; -bool TextThreadDelegatePrivate::globalWideCharacter = false; - -//QString TextThreadDelegatePrivate::sourceOf(TextThread *t) -//{ -// Q_ASSERT(t); -// QString ret; -// enum { buf_size = 0x200 }; // 0x200 is used by ITH internally -// wchar_t buf[buf_size]; -// ulong len = t->GetThreadString(buf, buf_size); -// if (len) -// ret = QString::fromWCharArray(buf, len); -// return ret; -//} - -/** Public class */ - -// - Constructions - - -TextThreadDelegate::TextThreadDelegate(TextThread *t) - : d_(new D(t)) -{ - d_->flushTimer.setMethod(this, &Self::flush); - d_->flushTimer.setSingleShot(true); -} - -TextThreadDelegate::~TextThreadDelegate() -{ - if (d_->flushTimer.isActive()) - d_->flushTimer.stop(); - delete d_; -} - -bool TextThreadDelegate::delegateOf(const Self *that) const -{ - Q_ASSERT(t); - // Both have no context, and my subcontext is smaller - return that - && !D::contextOf(that->d_->t) && !D::contextOf(d_->t) - && D::subcontextOf(that->d_->t) >= D::subcontextOf(d_->t) - && ::strcmp(d_->sourceBuffer, that->d_->sourceBuffer) == 0 - && nameEquals("Malie"); -} - -// - Properties - - -//TextThread *TextThreadDelegate::t() const { return d_->t; } -int TextThreadDelegate::threadNumber() const -{ return d_->t->Number(); } - -qint32 TextThreadDelegate::signature() const -{ return d_->signature; } - -QString TextThreadDelegate::name() const -{ return d_->source; } - -bool TextThreadDelegate::nameEquals(const char *that) const -{ return !::strcmp(d_->sourceBuffer, that); } - -int TextThreadDelegate::capacity() { return D::globalCapacity; } -void TextThreadDelegate::setCapacity(int value) { D::globalCapacity = value; } - -bool TextThreadDelegate::removesRepeat() { return D::globalRemovesRepeat; } -void TextThreadDelegate::setRemovesRepeat(bool value) { D::globalRemovesRepeat = value; } - -bool TextThreadDelegate::wideCharacter() { return D::globalWideCharacter; } -void TextThreadDelegate::setWideCharacter(bool value) { D::globalWideCharacter = value; } - -bool TextThreadDelegate::keepsSpace() { return D::globalKeepsSpace; } -void TextThreadDelegate::setKeepsSpace(bool value) { D::globalKeepsSpace = value; } - -void TextThreadDelegate::setInterval(int msecs) -{ d_->flushTimer.setInterval(msecs); } - -void TextThreadDelegate::setParentWindow(WId winId) -{ d_->flushTimer.setParentWindow(winId); } - -// - Actions - - -void TextThreadDelegate::flush() -{ - D_LOCK; - d_->flush(); - d_->syncGlobal(); -} - -void TextThreadDelegate::touch() -{ - D_LOCK; - d_->flushTimer.start(); -} - -void TextThreadDelegate::append(const char *data, int len, bool space) -{ - D_LOCK; - if (space && D::globalKeepsSpace) - d_->appendSpace(); - if (data && len) { - if (d_->removesRepeat) - d_->appendRepeat(data, len); - else - d_->append(data, len); - } -} - -// EOF -/* -void TextThreadDelegate::append(const QByteArray &data) -{ - D::mutex_lock_type locker(D::mutex); - - d_->flushTimer.start(); - if (d_->buffer.size() <= D::capacity) - d_->buffer.append(data); -} -void TextThreadDelegatePrivate::send() -{ -#ifdef DEBUG - qDebug()<< source() - << t->Number() - << t->PID() - << QString::number(t->Addr(), 16) - << QString::number(t->GetThreadParameter()->retn, 16) - << QString::number(t->GetThreadParameter()->spl, 16) - << QTextCodec::codecForName("SHIFT-JIS")->makeDecoder()->toUnicode(buffer); -#endif // DEBUG -} -*/ diff --git a/vnr/texthook/textthread_p.h b/vnr/texthook/textthread_p.h deleted file mode 100644 index 6e02939..0000000 --- a/vnr/texthook/textthread_p.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -// textthread_p.h -// 6/6/2012 jichi -// Internal header. -// Defines TextHook delegate class. - -#include "sakurakit/skglobal.h" -#include - -//QT_FORWARD_DECLARE_CLASS(QByteArray) - -class SharedRef -{ - SK_CLASS(SharedRef) - int count_; -public: - SharedRef(): count_(1) {} - int retainCount() const { return count_; } - void retain() { count_++; } - //void release() { count_--; } - static void release(Self *x) { if (--x->count_ <= 0) delete x; } -}; - -// FIXME: This class is not thread-safe! -class TextThread; -class TextThreadDelegatePrivate; -class TextThreadDelegate : public SharedRef -{ - SK_EXTEND_CLASS(TextThreadDelegate, SharedRef) - SK_DISABLE_COPY(TextThreadDelegate) - SK_DECLARE_PRIVATE(TextThreadDelegatePrivate) -public: - explicit TextThreadDelegate(TextThread *t); - ~TextThreadDelegate(); - - bool delegateOf(const Self *t) const; - - // - Properties - - - //TextThread *t() const; - int threadNumber() const; - qint32 signature() const; - QString name() const; - bool nameEquals(const char *that) const; // optimized - - // Maximum text size - static int capacity(); - static void setCapacity(int value); - - static bool wideCharacter(); - static void setWideCharacter(bool value); - - static bool removesRepeat(); - static void setRemovesRepeat(bool value); - - static bool keepsSpace(); - static void setKeepsSpace(bool value); - - //TextThread *t() const; - - //int interval() const; - void setInterval(int msecs); - - //WId parentWindow() const; - void setParentWindow(WId winId); - - // - Actions - - - //void append(const QByteArray &data); - /** Add data to the text thread - * @param data raw data - * @param len length of the data - * @param space Whether have LEADING space - */ - void append(const char *data, int len, bool space=false); - void flush(); - void touch(); // keep timer running -}; - -// EOF diff --git a/vnr/texthook/winapi_p.cc b/vnr/texthook/winapi_p.cc deleted file mode 100644 index 11ca6e2..0000000 --- a/vnr/texthook/winapi_p.cc +++ /dev/null @@ -1,21 +0,0 @@ -// apiwin_p.cc -// 10/6/2012 jichi -#include "texthook/winapi_p.h" -#include - -WINAPI_BEGIN_NAMESPACE - -bool IsProcessActiveWithId(DWORD dwProcessId) -{ - bool ret = false; - if (HANDLE hProc = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId)) { - DWORD dwExitCode; - ret = ::GetExitCodeProcess(hProc, &dwExitCode) && (dwExitCode == STILL_ACTIVE); - ::CloseHandle(hProc); - } - return ret; -} - -WINAPI_END_NAMESPACE - -// EOF diff --git a/vnr/texthook/winapi_p.h b/vnr/texthook/winapi_p.h deleted file mode 100644 index 6e35a27..0000000 --- a/vnr/texthook/winapi_p.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -// winapi_p.h -// 10/5/2012 jichi -// Internal header. -// Wrapper of - -#ifndef WINAPI_BEGIN_NAMESPACE -# define WINAPI_BEGIN_NAMESPACE namespace winapi { -#endif -#ifndef WINAPI_END_NAMESPACE -# define WINAPI_END_NAMESPACE } // namespace winapi -#endif - -WINAPI_BEGIN_NAMESPACE -bool IsProcessActiveWithId(unsigned long dwProcessId); -WINAPI_END_NAMESPACE - -// EOF