delete more unused stuff

This commit is contained in:
Akash Mozumdar 2018-05-10 18:05:54 -04:00
parent 011fec97cf
commit 6b63b91326
14 changed files with 0 additions and 2123 deletions

View File

@ -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

View File

@ -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 <QtCore/QDebug>
#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<TextThread *, TextThreadDelegate *> Ihf::threadDelegates_;
//QHash<TextThreadDelegate *, TextThreadDelegate *> Ihf::linkedDelegates_;
QHash<QString, ulong> 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<Hook *>(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<TextThreadDelegate *>(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<char *>(data), dataLength, space);
//QString text = QString::fromLocal8Bit(reinterpret_cast<LPCSTR>(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<qint32> Ihf::whitelist()
{
QList<qint32> ret;
const qint32 *p = whitelist_;
while (*p)
ret.append(*p++);
return ret;
}
void Ihf::clearWhitelist() { *whitelist_= 0; }
void Ihf::setWhitelist(const QList<qint32> &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 <cstdlib>
#include <cstring>
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<TextThread *>(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;
//}

View File

@ -1,117 +0,0 @@
#pragma once
// ihf_p.h
// 10/15/2011 jichi
// Internal header.
// Wrapper of IHF functions.
#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtGui/qwindowdefs.h> // 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<TextThread *, TextThreadDelegate *> threadDelegates_;
//static QHash<TextThreadDelegate *, TextThreadDelegate *> linkedDelegates_;
static QHash<QString, ulong> 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<qint32> whitelist();
static void setWhitelist(const QList<qint32> &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

View File

@ -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 <string>
#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:" <<hp->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

View File

@ -1,20 +0,0 @@
#pragma once
// ith_p.h
// 10/15/2011 jichi
// Internal header.
// Wrapper of functions from ITH.
#include <QtCore/QString>
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

View File

@ -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 <QtCore>
//#define DEBUG "texthook.cc"
#include "sakurakit/skdebug.h"
//#include <ITH/IHF_SYS.h>
//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<ulong> TextHook::attachedProcesses(bool checkActive) const
//{
// if (isEmpty() || !checkActive)
// return d_->pids;
//
// QList<ulong> 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<qint32> TextHook::threadWhitelist() const { return Ihf::whitelist(); }
void TextHook::setThreadWhitelist(const QList<qint32> &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<QString, QString> 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<uint> 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<uint> 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();
}
*/

View File

@ -1,101 +0,0 @@
#pragma once
// texthook.h
// 10/14/2011 jichi
#include "texthook_config.h"
#include "sakurakit/skglobal.h"
#include <QtCore/QByteArray>
#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtGui/qwindowdefs.h> // 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<ulong> 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<qint32> threadWhitelist() const;
void setThreadWhitelist(const QList<qint32> &signatures);
void clearThreadWhitelist();
// Note: len(v) must be smaller than 0x200
void setKeptThreadName(const QString &v);
QString keptThreadName() const;
};
// EOF

View File

@ -1,38 +0,0 @@
/*
* texthook.rc
* 10/20/2011 jichi
*/
#if defined(UNDER_CE)
# include <winbase.h>
#else
# include <winver.h>
#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 */

View File

@ -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

View File

@ -1,39 +0,0 @@
#pragma once
// texthook_p.h
// 10/14/2011 jichi
// Internal header.
// Defines TextHook private data.
#include "texthook/texthook.h"
#include <QtCore/QHash>
#include <QtCore/QSet>
// - Private -
class TextHookPrivate
{
SK_CLASS(TextHookPrivate)
SK_DECLARE_PUBLIC(TextHook)
static Self *instance_; // global instance
bool enabled;
QString source;
QSet<ulong> pids;
QHash<ulong, QString> 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

View File

@ -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 <QtCore/QRegExp>
//#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::mutex_type> d_lock(D::globalMutex) // Synchronized scope for accessing private data
class TextThreadDelegatePrivate
{
SK_CLASS(TextThreadDelegatePrivate)
SK_DISABLE_COPY(TextThreadDelegatePrivate)
public:
typedef win_mutex<CRITICAL_SECTION> 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
}
*/

View File

@ -1,81 +0,0 @@
#pragma once
// textthread_p.h
// 6/6/2012 jichi
// Internal header.
// Defines TextHook delegate class.
#include "sakurakit/skglobal.h"
#include <QtGui/qwindowdefs.h>
//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

View File

@ -1,21 +0,0 @@
// apiwin_p.cc
// 10/6/2012 jichi
#include "texthook/winapi_p.h"
#include <windows.h>
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

View File

@ -1,18 +0,0 @@
#pragma once
// winapi_p.h
// 10/5/2012 jichi
// Internal header.
// Wrapper of <windows.h>
#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