mireado

starting commit

#pragma once
// hook.h
// 8/23/2013 jichi
// Branch: ITH/IHF_DLL.h, rev 66
#include "ith/common/const.h"
#include "ith/common/types.h"
//#ifdef IHF
//# define IHFAPI __declspec(dllexport) __stdcall
//#else
//# define IHFAPI __declspec(dllimport) __stdcall
//#endif // IHF
#define IHFAPI // 9/19/2014 jichi: dummy
//extern "C" {
//DWORD IHFAPI OutputConsole(LPCWSTR text);
void IHFAPI ConsoleOutput(LPCSTR text); // jichi 12/25/2013: Used to return length of sent text
//DWORD IHFAPI OutputDWORD(DWORD d);
//DWORD IHFAPI OutputRegister(DWORD *base);
DWORD IHFAPI NotifyHookInsert(DWORD addr);
DWORD IHFAPI NewHook(const HookParam &hp, LPCWSTR name, DWORD flag = HOOK_ENGINE);
DWORD IHFAPI RemoveHook(DWORD addr);
DWORD IHFAPI SwitchTrigger(DWORD on);
DWORD IHFAPI GetFunctionAddr(const char *name, DWORD *addr, DWORD *base, DWORD *size, LPWSTR *base_name);
//DWORD IHFAPI RegisterEngineModule(DWORD idEngine, DWORD dnHook);
//} // extern "C"
// 10/21/2014 jichi: TODO: Get rid of this global variable
// Defined in pipe.cc
extern bool engine_registered;
// 10/14/2014 jichi: disable GDI hooks
void DisableGDIHooks();
// EOF
# hook.pro
# 8/9/2013 jichi
# Build vnrhook.dll for Windows 7+
CONFIG += eh eha # exception handler to catch all exceptions
#CONFIG += noeh # msvcrt on Windows XP does not has exception handler
include(../dllconfig.pri)
include(../sys/sys.pri)
include($$LIBDIR/disasm/disasm.pri)
include($$LIBDIR/memdbg/memdbg.pri)
include($$LIBDIR/ntinspect/ntinspect.pri)
#include($$LIBDIR/winseh/winseh_safe.pri)
include($$LIBDIR/winversion/winversion.pri)
# 9/27/2013: disable ITH this game engine, only for debugging purpose
#DEFINES += ITH_DISABLE_ENGINE
# jichi 9/22/2013: When ITH is on wine, mutex is needed to protect NtWriteFile
#DEFINES += ITH_WINE
#DEFINES += ITH_SYNC_PIPE
## Libraries
LIBS += -lkernel32 -luser32 -lgdi32
## Sources
TEMPLATE = lib
TARGET = vnrhook
#CONFIG += staticlib
HEADERS += \
config.h \
cli.h \
hook.h \
engine/engine.h \
engine/hookdefs.h \
engine/match.h \
engine/pchooks.h \
engine/util.h \
tree/avl.h
SOURCES += \
main.cc \
rpc/pipe.cc \
hijack/texthook.cc \
engine/engine.cc \
engine/match.cc \
engine/pchooks.cc \
engine/util.cc
#RC_FILE += vnrhook.rc
#OTHER_FILES += vnrhook.rc
# EOF
This diff is collapsed. Click to expand it.
// pipe.cc
// 8/24/2013 jichi
// Branch: ITH_DLL/pipe.cpp, rev 66
// 8/24/2013 TODO: Clean up this file
#ifdef _MSC_VER
# pragma warning (disable:4100) // C4100: unreference formal parameter
#endif // _MSC_VER
#include "cli.h"
#include "engine/match.h"
#include "ith/common/defs.h"
//#include "ith/common/growl.h"
#include "ith/sys/sys.h"
#include "ccutil/ccmacro.h"
//#include <ITH\AVL.h>
//#include <ITH\ntdll.h>
WCHAR mutex[] = ITH_GRANTPIPE_MUTEX;
WCHAR exist[] = ITH_PIPEEXISTS_EVENT;
WCHAR detach_mutex[0x20];
//WCHAR write_event[0x20];
//WCHAR engine_event[0x20];
//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
//WCHAR command[] = L"\\??\\pipe\\ITH_COMMAND";
wchar_t recv_pipe[] = ITH_TEXT_PIPE;
wchar_t command[] = ITH_COMMAND_PIPE;
LARGE_INTEGER wait_time = {-100*10000, -1};
LARGE_INTEGER sleep_time = {-20*10000, -1};
DWORD engine_type;
DWORD module_base;
//DWORD engine_base;
bool engine_registered; // 10/19/2014 jichi: disable engine dll
HANDLE hPipe,
hCommand,
hDetach; //,hLose;
//InsertHookFun InsertHook;
//IdentifyEngineFun IdentifyEngine;
//InsertDynamicHookFun InsertDynamicHook;
bool hook_inserted = false;
// jichi 9/28/2013: protect pipe on wine
// Put the definition in this file so that it might be inlined
void CliUnlockPipe()
{
if (IthIsWine())
IthReleaseMutex(::hmMutex);
}
void CliLockPipe()
{
if (IthIsWine()) {
const LONGLONG timeout = -50000000; // in nanoseconds = 5 seconds
NtWaitForSingleObject(hmMutex, 0, (PLARGE_INTEGER)&timeout);
}
}
HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction)
{
UNICODE_STRING us;
RtlInitUnicodeString(&us,name);
SECURITY_DESCRIPTOR sd = {1};
OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
HANDLE hFile;
IO_STATUS_BLOCK isb;
if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0)))
return hFile;
else
return INVALID_HANDLE_VALUE;
}
DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter) // Dynamically detect ITH main module status.
{
CC_UNUSED(lpThreadParameter);
int i;
TextHook *man;
struct {
DWORD pid;
TextHook *man;
DWORD module;
//DWORD engine;
} u;
HANDLE hMutex,
hPipeExist;
//swprintf(engine_event,L"ITH_ENGINE_%d",current_process_id);
swprintf(detach_mutex, ITH_DETACH_MUTEX_ L"%d", current_process_id);
//swprintf(lose_event,L"ITH_LOSEPIPE_%d",current_process_id);
//hEngine=IthCreateEvent(engine_event);
//NtWaitForSingleObject(hEngine,0,0);
//NtClose(hEngine);
while (!engine_registered)
NtDelayExecution(0, &wait_time);
//LoadEngine(L"ITH_Engine.dll");
u.module = module_base;
u.pid = current_process_id;
u.man = hookman;
//u.engine = engine_base; // jichi 10/19/2014: disable the second dll
hPipeExist = IthOpenEvent(exist);
IO_STATUS_BLOCK ios;
//hLose=IthCreateEvent(lose_event,0,0);
if (hPipeExist != INVALID_HANDLE_VALUE)
while (running) {
hPipe = INVALID_HANDLE_VALUE;
hCommand = INVALID_HANDLE_VALUE;
while (NtWaitForSingleObject(hPipeExist,0,&wait_time) == WAIT_TIMEOUT)
if (!running)
goto _release;
hMutex = IthCreateMutex(mutex,0);
NtWaitForSingleObject(hMutex,0,0);
while (hPipe == INVALID_HANDLE_VALUE||
hCommand == INVALID_HANDLE_VALUE) {
NtDelayExecution(0, &sleep_time);
if (hPipe == INVALID_HANDLE_VALUE)
hPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE);
if (hCommand == INVALID_HANDLE_VALUE)
hCommand = IthOpenPipe(command, GENERIC_READ);
}
//NtClearEvent(hLose);
CliLockPipe();
NtWriteFile(hPipe, 0, 0, 0, &ios, &u, sizeof(u), 0, 0);
CliUnlockPipe();
live = true;
for (man = hookman, i = 0; i < current_hook; man++)
if (man->RecoverHook()) // jichi 9/27/2013: This is the place where built-in hooks like TextOutA are inserted
i++;
//ConsoleOutput(dll_name);
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
//OutputDWORD(tree->Count());
NtReleaseMutant(hMutex,0);
NtClose(hMutex);
if (!hook_inserted && engine_registered) {
hook_inserted = true;
Engine::IdentifyEngine();
}
hDetach = IthCreateMutex(detach_mutex,1);
while (running && NtWaitForSingleObject(hPipeExist, 0, &sleep_time) == WAIT_OBJECT_0)
NtDelayExecution(0, &sleep_time);
live = false;
for (man = hookman, i = 0; i < current_hook; man++)
if (man->RemoveHook())
i++;
if (!running) {
IthCoolDown(); // jichi 9/28/2013: Use cooldown instead of lock pipe to prevent from hanging on exit
//CliLockPipe();
NtWriteFile(hPipe, 0, 0, 0, &ios, man, 4, 0, 0);
//CliUnlockPipe();
IthReleaseMutex(hDetach);
}
NtClose(hDetach);
NtClose(hPipe);
}
_release:
//NtClose(hLose);
NtClose(hPipeExist);
return 0;
}
DWORD WINAPI CommandPipe(LPVOID lpThreadParameter)
{
CC_UNUSED(lpThreadParameter);
DWORD command;
BYTE buff[0x400] = {};
HANDLE hPipeExist;
hPipeExist = IthOpenEvent(exist);
IO_STATUS_BLOCK ios={};
if (hPipeExist!=INVALID_HANDLE_VALUE)
while (running) {
while (!live) {
if (!running)
goto _detach;
NtDelayExecution(0, &sleep_time);
}
// jichi 9/27/2013: Why 0x200 not 0x400? wchar_t?
switch (NtReadFile(hCommand, 0, 0, 0, &ios, buff, 0x200, 0, 0)) {
case STATUS_PIPE_BROKEN:
case STATUS_PIPE_DISCONNECTED:
NtClearEvent(hPipeExist);
continue;
case STATUS_PENDING:
NtWaitForSingleObject(hCommand, 0, 0);
switch (ios.Status) {
case STATUS_PIPE_BROKEN:
case STATUS_PIPE_DISCONNECTED:
NtClearEvent(hPipeExist);
continue;
case 0: break;
default:
if (NtWaitForSingleObject(hDetach, 0, &wait_time) == WAIT_OBJECT_0)
goto _detach;
}
}
if (ios.uInformation && live) {
command = *(DWORD *)buff;
switch(command) {
case IHF_COMMAND_NEW_HOOK:
//IthBreak();
buff[ios.uInformation] = 0;
buff[ios.uInformation + 1] = 0;
NewHook(*(HookParam *)(buff + 4), (LPWSTR)(buff + 4 + sizeof(HookParam)), 0);
break;
case IHF_COMMAND_REMOVE_HOOK:
{
DWORD rm_addr = *(DWORD *)(buff+4);
HANDLE hRemoved = IthOpenEvent(ITH_REMOVEHOOK_EVENT);
TextHook *in = hookman;
for (int i = 0; i < current_hook; in++) {
if (in->Address()) i++;
if (in->Address() == rm_addr) break;
}
if (in->Address())
in->ClearHook();
IthSetEvent(hRemoved);
NtClose(hRemoved);
} break;
case IHF_COMMAND_MODIFY_HOOK:
{
DWORD rm_addr = *(DWORD *)(buff + 4);
HANDLE hModify = IthOpenEvent(ITH_MODIFYHOOK_EVENT);
TextHook *in = hookman;
for (int i = 0; i < current_hook; in++) {
if (in->Address())
i++;
if (in->Address() == rm_addr)
break;
}
if (in->Address())
in->ModifyHook(*(HookParam *)(buff + 4));
IthSetEvent(hModify);
NtClose(hModify);
} break;
case IHF_COMMAND_DETACH:
running = false;
live = false;
goto _detach;
default: ;
}
}
}
_detach:
NtClose(hPipeExist);
NtClose(hCommand);
return 0;
}
//extern "C" {
void IHFAPI ConsoleOutput(LPCSTR text)
{ // jichi 12/25/2013: Rewrite the implementation
if (!live || !text)
return;
enum { buf_size = 0x50 };
BYTE buf[buf_size]; // buffer is needed to append the message header
size_t text_size = strlen(text) + 1;
size_t data_size = text_size + 8;
BYTE *data = (data_size <= buf_size) ? buf : new BYTE[data_size];
*(DWORD *)data = IHF_NOTIFICATION; //cmd
*(DWORD *)(data + 4) = IHF_NOTIFICATION_TEXT; //console
memcpy(data + 8, text, text_size);
IO_STATUS_BLOCK ios;
NtWriteFile(hPipe, 0, 0, 0, &ios, data, data_size, 0, 0);
if (data != buf)
delete[] data;
}
//if (str) {
// int t, len, sum;
// BYTE buffer[0x80];
// BYTE *buff;
// len = wcslen(str) << 1;
// t = swprintf((LPWSTR)(buffer + 8),L"%d: ",current_process_id) << 1;
// sum = len + t + 8;
// if (sum > 0x80) {
// buff = new BYTE[sum];
// memset(buff, 0, sum); // jichi 9/25/2013: zero memory
// memcpy(buff + 8, buffer + 8, t);
// }
// else
// buff = buffer;
// *(DWORD *)buff = IHF_NOTIFICATION; //cmd
// *(DWORD *)(buff + 4) = IHF_NOTIFICATION_TEXT; //console
// memcpy(buff + t + 8, str, len);
// IO_STATUS_BLOCK ios;
// NtWriteFile(hPipe,0,0,0,&ios,buff,sum,0,0);
// if (buff != buffer)
// delete[] buff;
// return len;
//}
//DWORD IHFAPI OutputDWORD(DWORD d)
//{
// WCHAR str[0x10];
// swprintf(str,L"%.8X",d);
// ConsoleOutput(str);
// return 0;
//}
//DWORD IHFAPI OutputRegister(DWORD *base)
//{
// WCHAR str[0x40];
// swprintf(str,L"EAX:%.8X",base[0]);
// ConsoleOutput(str);
// swprintf(str,L"ECX:%.8X",base[-1]);
// ConsoleOutput(str);
// swprintf(str,L"EDX:%.8X",base[-2]);
// ConsoleOutput(str);
// swprintf(str,L"EBX:%.8X",base[-3]);
// ConsoleOutput(str);
// swprintf(str,L"ESP:%.8X",base[-4]);
// ConsoleOutput(str);
// swprintf(str,L"EBP:%.8X",base[-5]);
// ConsoleOutput(str);
// swprintf(str,L"ESI:%.8X",base[-6]);
// ConsoleOutput(str);
// swprintf(str,L"EDI:%.8X",base[-7]);
// ConsoleOutput(str);
// return 0;
//}
//DWORD IHFAPI RegisterEngineModule(DWORD idEngine, DWORD dnHook)
//{
// ::IdentifyEngine = (IdentifyEngineFun)idEngine;
// ::InsertDynamicHook = (InsertDynamicHookFun)dnHook;
// ::engine_registered = true;
// return 0;
//}
DWORD IHFAPI NotifyHookInsert(DWORD addr)
{
if (live) {
BYTE buffer[0x10];
*(DWORD *)buffer = IHF_NOTIFICATION;
*(DWORD *)(buffer + 4) = IHF_NOTIFICATION_NEWHOOK;
*(DWORD *)(buffer + 8) = addr;
*(DWORD *)(buffer + 0xc) = 0;
IO_STATUS_BLOCK ios;
CliLockPipe();
NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0);
CliUnlockPipe();
}
return 0;
}
//} // extern "C"
// EOF
This diff is collapsed. Click to expand it.
# hookxp.pro
# 8/9/2013 jichi
# Build vnrhookxp.dll for Windows XP
CONFIG += noeh # msvcrt on Windows XP does not has exception handler
include(../dllconfig.pri)
include(../sys/sys.pri)
include($$LIBDIR/disasm/disasm.pri)
include($$LIBDIR/memdbg/memdbg.pri)
include($$LIBDIR/ntinspect/ntinspect.pri)
include($$LIBDIR/winseh/winseh_safe.pri)
include($$LIBDIR/winversion/winversion.pri)
VPATH += ../hook
INCLUDEPATH += ../hook
# 9/27/2013: disable ITH this game engine, only for debugging purpose
#DEFINES += ITH_DISABLE_ENGINE
# jichi 9/22/2013: When ITH is on wine, mutex is needed to protect NtWriteFile
#DEFINES += ITH_WINE
#DEFINES += ITH_SYNC_PIPE
## Libraries
LIBS += -lkernel32 -luser32 -lgdi32
## Sources
TEMPLATE = lib
TARGET = vnrhookxp
#CONFIG += staticlib
HEADERS += \
config.h \
cli.h \
hook.h \
engine/engine.h \
engine/hookdefs.h \
engine/match.h \
engine/pchooks.h \
engine/util.h \
tree/avl.h
SOURCES += \
main.cc \
rpc/pipe.cc \
hijack/texthook.cc \
engine/engine.cc \
engine/match.cc \
engine/pchooks.cc \
engine/util.cc
#RC_FILE += vnrhook.rc
#OTHER_FILES += vnrhook.rc
# EOF
# host.pro
# #CONFIG += eha # 3/1/2014: catchlng all exceptions will break pytexthook on Windows XP
# CONFIG += noeh # Needed by pytexthook ONLY on windows xp orz
# include(../dllconfig.pri)
# include(../sys/sys.pri)
# include($$LIBDIR/winmaker/winmaker.pri)
# include($$LIBDIR/winmutex/winmutex.pri)
# config.pri
# CONFIG(noeh) { # No Exception handler
# message(CONFIG noeh)
# QMAKE_CXXFLAGS += /GR-
# QMAKE_CXXFLAGS_RTTI_ON -= /GR
# QMAKE_CXXFLAGS_STL_ON -= /EHsc
# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
# CONFIG(dll) {
# QMAKE_LFLAGS += /ENTRY:"DllMain"
# }
# }
set(vnrhost_src
avl_p.h
config.h
hookman.h
settings.h
srv.h
srv_p.h
textthread.h
textthread_p.h
SettingManager.h
hookman.cc
main.cc
pipe.cc
textthread.cc
${PROJECT_SOURCE_DIR}/winmaker/winmaker.h
${PROJECT_SOURCE_DIR}/winmaker/winmaker.cc
${PROJECT_SOURCE_DIR}/winmutex/winmutex.h
${common_src}
)
source_group("common" FILES ${common_src})
add_library(vnrhost SHARED ${vnrhost_src})
set_target_properties(vnrhost PROPERTIES LINK_FLAGS /SUBSYSTEM:WINDOWS)
target_compile_options(vnrhost PRIVATE
/GR-
$<$<CONFIG:Release>:>
$<$<CONFIG:Debug>:>
)
STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
target_link_libraries(vnrhost
vnrsys
${WDK_HOME}/lib/wxp/i386/ntdll.lib
)
target_compile_definitions(vnrhost PRIVATE
)
install(TARGETS vnrhost RUNTIME
DESTINATION .
CONFIGURATIONS Release
)
/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
* This file is part of the Interactive Text Hooker.
* Interactive Text Hooker is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "config.h"
#include <intrin.h>
#define SETTING_SPLIT_TIME 0
#define SETTING_CYCLIC_REMOVE 1
#define SETTING_REPEAT_COUNT 2
#define SETTING_CLIPFLAG 3
#define SETTING_MAX_INDEX 4
class IHFSERVICE SettingManager
{
public:
SettingManager() {memset(setting_int,0,sizeof(setting_int));}
~SettingManager(){}
unsigned int SetValue(unsigned int index, unsigned int value)
{
if (index < SETTING_MAX_INDEX)
return (unsigned int)_InterlockedExchange((long*)setting_int+index,(long)value);
else return 0;
}
unsigned int GetValue(unsigned int index)
{
if (index < SETTING_MAX_INDEX)
return setting_int[index];
else return 0;
}
private:
unsigned int setting_int[SETTING_MAX_INDEX];
};
\ No newline at end of file
This diff is collapsed. Click to expand it.
#pragma once
// config.h
// 8/23/2013 jichi
// The first header file that are included by all source files.
#define IHF // for dll import
#include "ith/dllconfig.h"
#define IHFAPI __stdcall
#ifdef IHF
# define IHFSERVICE __declspec(dllexport)
#else
# define IHFSERVICE __declspec(dllimport)
#endif
// EOF
This diff is collapsed. Click to expand it.
#pragma once
// hookman.h
// 8/23/2013 jichi
// Branch: ITH/HookManager.h, rev 133
#include "ith/host/avl_p.h"
#include "ith/host/textthread.h"
#include "winmutex/winmutex.h"
enum { MAX_REGISTER = 0xf };
enum { MAX_PREV_REPEAT_LENGTH = 0x20 };
struct ProcessRecord {
DWORD pid_register;
DWORD hookman_register;
DWORD module_register;
//DWORD engine_register; // jichi 10/19/2014: removed
HANDLE process_handle;
HANDLE hookman_mutex;
HANDLE hookman_section;
LPVOID hookman_map;
};
class ThreadTable : public MyVector<TextThread *, 0x40>
{
public:
virtual void SetThread(DWORD number, TextThread *ptr);
virtual TextThread *FindThread(DWORD number);
};
struct TCmp { char operator()(const ThreadParameter *t1,const ThreadParameter *t2); };
struct TCpy { void operator()(ThreadParameter *t1,const ThreadParameter *t2); };
struct TLen { int operator()(const ThreadParameter *t); };
typedef DWORD (*ProcessEventCallback)(DWORD pid);
class IHFSERVICE HookManager : public AVLTree<ThreadParameter, DWORD, TCmp, TCpy, TLen>
{
public:
HookManager();
~HookManager();
// jichi 12/26/2013: remove virtual modifiers
TextThread *FindSingle(DWORD pid, DWORD hook, DWORD retn, DWORD split);
TextThread *FindSingle(DWORD number);
ProcessRecord *GetProcessRecord(DWORD pid);
DWORD GetProcessIDByPath(LPCWSTR str);
void RemoveSingleThread(DWORD number);
void LockHookman();
void UnlockHookman();
void ResetRepeatStatus();
void ClearCurrent();
void AddLink(WORD from, WORD to);
void UnLink(WORD from);
void UnLinkAll(WORD from);
void SelectCurrent(DWORD num);
void DetachProcess(DWORD pid);
void SetCurrent(TextThread *it);
void AddConsoleOutput(LPCWSTR text);
// jichi 10/27/2013: Add const; add space.
void DispatchText(DWORD pid, const BYTE *text, DWORD hook, DWORD retn, DWORD split, int len, bool space);
void ClearText(DWORD pid, DWORD hook, DWORD retn, DWORD split);
void RemoveProcessContext(DWORD pid);
void RemoveSingleHook(DWORD pid, DWORD addr);
void RegisterThread(TextThread*, DWORD);
void RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread);
void RegisterProcess(DWORD pid, DWORD hookman, DWORD module);
void UnRegisterProcess(DWORD pid);
//void SetName(DWORD);
DWORD GetCurrentPID();
HANDLE GetCmdHandleByPID(DWORD pid);
ConsoleCallback RegisterConsoleCallback(ConsoleCallback cf)
{ return (ConsoleCallback)_InterlockedExchange((long*)&console,(long)cf); }
ConsoleWCallback RegisterConsoleWCallback(ConsoleWCallback cf)
{ return (ConsoleWCallback)_InterlockedExchange((long*)&wconsole,(long)cf); }
ThreadEventCallback RegisterThreadCreateCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&create,(long)cf); }
ThreadEventCallback RegisterThreadRemoveCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&remove,(long)cf); }
ThreadEventCallback RegisterThreadResetCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&reset,(long)cf); }
ThreadEventCallback RegisterAddRemoveLinkCallback(ThreadEventCallback cf)
{ return (ThreadEventCallback)_InterlockedExchange((long*)&addRemoveLink, (long)cf); }
ProcessEventCallback RegisterProcessAttachCallback(ProcessEventCallback cf)
{ return (ProcessEventCallback)_InterlockedExchange((long*)&attach,(long)cf); }
ProcessEventCallback RegisterProcessDetachCallback(ProcessEventCallback cf)
{ return (ProcessEventCallback)_InterlockedExchange((long*)&detach,(long)cf); }
ProcessEventCallback RegisterProcessNewHookCallback(ProcessEventCallback cf)
{ return (ProcessEventCallback)_InterlockedExchange((long*)&hook,(long)cf); }
ProcessEventCallback ProcessNewHook() { return hook; }
TextThread *GetCurrentThread() { return current; }
ProcessRecord *Records() { return record; }
ThreadTable *Table() { return thread_table; }
//DWORD& SplitTime() { return split_time; }
//DWORD& RepeatCount() { return repeat_count; }
//DWORD& CyclicRemove() { return cyclic_remove; }
//DWORD& GlobalFilter() { return global_filter; }
void ConsoleOutput(LPCSTR text) { if (console) console(text); } // not thread safe
void ConsoleOutputW(LPCWSTR text) { if (wconsole) wconsole(text); } // not thread safe
private:
typedef win_mutex<CRITICAL_SECTION> mutex_type;
mutex_type hmcs;
TextThread *current;
ConsoleCallback console; // jichi 12/25/2013: add console output callback
ConsoleWCallback wconsole;
ThreadEventCallback create,
remove,
reset,
addRemoveLink;
ProcessEventCallback attach,
detach,
hook;
DWORD current_pid;
ThreadTable *thread_table;
HANDLE destroy_event;
ProcessRecord record[MAX_REGISTER + 1];
HANDLE text_pipes[MAX_REGISTER + 1],
cmd_pipes[MAX_REGISTER + 1],
recv_threads[MAX_REGISTER + 1];
WORD register_count,
new_thread_number;
// jichi 1/16/2014: Stop adding new threads when full
bool IsFull() const; // { return new_thread_number >= MAX_HOOK; }
bool IsEmpty() const { return !new_thread_number; }
};
// EOF
# host.pri
# 8/9/2011 jichi
DEFINES += WITH_LIB_ITH_HOST
DEPENDPATH += $$PWD
LIBS += -lvnrhost
HEADERS += \
$$PWD/avl_p.h \
$$PWD/hookman.h \
$$PWD/settings.h \
$$PWD/srv.h \
$$PWD/textthread.h \
$$PWD/textthread_p.h
# EOF
# host.pro
# 8/9/2013 jichi
# Build vnrhost
#CONFIG += eha # 3/1/2014: catchlng all exceptions will break pytexthook on Windows XP
CONFIG += noeh # Needed by pytexthook ONLY on windows xp orz
include(../dllconfig.pri)
include(../sys/sys.pri)
include($$LIBDIR/winmaker/winmaker.pri)
include($$LIBDIR/winmutex/winmutex.pri)
# 9/22/2013: When ITH is on wine, certain NT functions are replaced
#DEFINES += ITH_WINE
# 9/27/2013: Only for debugging purpose
#DEFINES += ITH_DISABLE_REPEAT # disable repetition elimination
#DEFINES += ITH_DISABLE_FILTER # disable space filter in pipe
## Libraries
LIBS += -lkernel32 -luser32 #-lcomctl32
## Sources
TEMPLATE = lib
#TARGET = IHF # compatible with ITHv3
TARGET = vnrhost
#CONFIG += staticlib
HEADERS += \
avl_p.h \
config.h \
hookman.h \
settings.h \
srv.h \
srv_p.h \
textthread.h \
textthread_p.h
#util.h
SOURCES += \
hookman.cc \
main.cc \
pipe.cc \
textthread.cc
#util.cc
#RC_FILE += engine.rc
#OTHER_FILES += engine.rc
OTHER_FILES += host.pri
# EOF
This diff is collapsed. Click to expand it.
// pipe.cc
// 8/24/2013 jichi
// Branch IHF/pipe.cpp, rev 93
// 8/24/2013 TODO: Clean up this file
#include "srv_p.h"
#include "hookman.h"
#include "ith/common/defs.h"
#include "ith/common/const.h"
//#include "ith/common/growl.h"
#include "ith/sys/sys.h"
//#include "CommandQueue.h"
//DWORD WINAPI UpdateWindows(LPVOID lpThreadParameter);
namespace { // unnamed
enum NamedPipeCommand {
NAMED_PIPE_DISCONNECT = 1
, NAMED_PIPE_CONNECT = 2
};
bool newline = false;
bool detach = false;
// jichi 10/27/2013
// Check if text has leading space
enum { _filter_limit = 0x20 }; // The same as the orignal ITH filter. So, I don't have to check \u3000
//enum { _filter_limit = 0x19 };
inline bool has_leading_space(const BYTE *text, int len)
{
return len == 1 ? *text <= _filter_limit : // 1 byte
*reinterpret_cast<const WORD *>(text) <= _filter_limit; // 2 bytes
}
// jichi 9/28/2013: Skip leading garbage
// Note:
// - Modifying limit will break manual translation. The orignal one is 0x20
// - Eliminating 0x20 will break English-translated games
const BYTE *Filter(const BYTE *str, int len)
{
#ifdef ITH_DISABLE_FILTER // jichi 9/28/2013: only for debugging purpose
return str;
#endif // ITH_DISABLE_FILTER
// if (len && *str == 0x10) // jichi 9/28/2013: garbage on wine, data link escape, or ^P
// return nullptr;
//enum { limit = 0x19 };
while (true)
if (len >= 2) {
if (*(const WORD *)str <= _filter_limit) { // jichi 10/27/2013: two bytes
str += 2;
len -= 2;
} else
break;
} else if (*str <= _filter_limit) { // jichi 10/27/2013: 1 byte
str++;
len--;
} else
break;
return str;
}
} // unnamed namespace
//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
//WCHAR command_pipe[] = L"\\??\\pipe\\ITH_COMMAND";
wchar_t recv_pipe[] = ITH_TEXT_PIPE;
wchar_t command_pipe[] = ITH_COMMAND_PIPE;
CRITICAL_SECTION detach_cs; // jichi 9/27/2013: also used in main
//HANDLE hDetachEvent;
extern HANDLE hPipeExist;
void CreateNewPipe()
{
static DWORD acl[7] = {
0x1C0002,
1,
0x140000,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
0x101,
0x1000000,
0};
static SECURITY_DESCRIPTOR sd = {1, 0, 4, 0, 0, 0, (PACL)acl};
HANDLE hTextPipe, hCmdPipe, hThread;
IO_STATUS_BLOCK ios;
UNICODE_STRING us;
OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
LARGE_INTEGER time = {-500000, -1};
RtlInitUnicodeString(&us, recv_pipe);
if (!NT_SUCCESS(NtCreateNamedPipeFile(
&hTextPipe,
GENERIC_READ | SYNCHRONIZE,
&oa,
&ios,
FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
1, 1, 0, -1,
0x1000,
0x1000,
&time))) {
//ConsoleOutput(ErrorCreatePipe);
ConsoleOutput("vnrhost:CreateNewPipe: failed to create recv pipe");
return;
}
RtlInitUnicodeString(&us, command_pipe);
if (!NT_SUCCESS(NtCreateNamedPipeFile(
&hCmdPipe,
GENERIC_WRITE | SYNCHRONIZE,
&oa,
&ios,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
1, 1, 0, -1,
0x1000,
0x1000,
&time))) {
//ConsoleOutput(ErrorCreatePipe);
ConsoleOutput("vnrhost:CreateNewPipe: failed to create cmd pipe");
return;
}
hThread = IthCreateThread(RecvThread, (DWORD)hTextPipe);
man->RegisterPipe(hTextPipe, hCmdPipe, hThread);
}
void DetachFromProcess(DWORD pid)
{
HANDLE hMutex = INVALID_HANDLE_VALUE,
hEvent = INVALID_HANDLE_VALUE;
//try {
IO_STATUS_BLOCK ios;
ProcessRecord *pr = man->GetProcessRecord(pid);
if (!pr)
return;
//IthBreak();
hEvent = IthCreateEvent(nullptr);
if (STATUS_PENDING == NtFsControlFile(
man->GetCmdHandleByPID(pid),
hEvent,
0,0,
&ios,
CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
0,0,0,0))
NtWaitForSingleObject(hEvent, 0, 0);
NtClose(hEvent);
//hEvent = INVALID_HANDLE_VALUE;
WCHAR mutex[0x20];
swprintf(mutex, ITH_DETACH_MUTEX_ L"%d", pid);
hMutex = IthOpenMutex(mutex);
if (hMutex != INVALID_HANDLE_VALUE) {
NtWaitForSingleObject(hMutex, 0, 0);
NtReleaseMutant(hMutex, 0);
NtClose(hMutex);
//hMutex = INVALID_HANDLE_VALUE;
}
//} catch (...) {
// if (hEvent != INVALID_HANDLE_VALUE)
// NtClose(hEvent);
// else if (hMutex != INVALID_HANDLE_VALUE) {
// NtWaitForSingleObject(hMutex, 0, 0);
// NtReleaseMutant(hMutex, 0);
// NtClose(hMutex);
// }
//}
//NtSetEvent(hDetachEvent, 0);
if (::running)
NtSetEvent(hPipeExist, 0);
}
// jichi 9/27/2013: I don't need this
//void OutputDWORD(DWORD d)
//{
// WCHAR str[0x20];
// swprintf(str, L"%.8X", d);
// ConsoleOutput(str);
//}
DWORD WINAPI RecvThread(LPVOID lpThreadParameter)
{
HANDLE hTextPipe = (HANDLE)lpThreadParameter;
IO_STATUS_BLOCK ios;
NtFsControlFile(hTextPipe,
0, 0, 0,
&ios,
CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_CONNECT, 0, 0),
0, 0, 0, 0);
if (!::running) {
NtClose(hTextPipe);
return 0;
}
BYTE *buff;
enum { PipeBufferSize = 0x1000 };
buff = new BYTE[PipeBufferSize];
ITH_MEMSET_HEAP(buff, 0, PipeBufferSize); // jichi 8/27/2013: zero memory, or it will crash wine on start up
// 10/19/2014 jichi: there are totally three words received
// See: hook/rpc/pipe.cc
// struct {
// DWORD pid;
// TextHook *man;
// DWORD module;
// //DWORD engine;
// } u;
enum { module_struct_size = 12 };
NtReadFile(hTextPipe, 0, 0, 0, &ios, buff, module_struct_size, 0, 0);
DWORD pid = *(DWORD *)buff,
hookman = *(DWORD *)(buff + 0x4),
module = *(DWORD *)(buff + 0x8);
//engine = *(DWORD *)(buff + 0xc);
man->RegisterProcess(pid, hookman, module);
// jichi 9/27/2013: why recursion?
CreateNewPipe();
//NtClose(IthCreateThread(UpdateWindows,0));
while (::running) {
if (!NT_SUCCESS(NtReadFile(hTextPipe,
0, 0, 0,
&ios,
buff,
0xf80,
0, 0)))
break;
enum { data_offset = 0xc }; // jichi 10/27/2013: Seem to be the data offset in the pipe
DWORD RecvLen = ios.uInformation;
if (RecvLen < data_offset)
break;
DWORD hook = *(DWORD *)buff;
union { DWORD retn; DWORD cmd_type; };
union { DWORD split; DWORD new_engine_type; };
retn = *(DWORD *)(buff + 4);
split = *(DWORD *)(buff + 8);
buff[RecvLen] = 0;
buff[RecvLen + 1] = 0;
if (hook == IHF_NOTIFICATION) {
switch (cmd_type) {
case IHF_NOTIFICATION_NEWHOOK:
{
static long lock;
while (InterlockedExchange(&lock, 1) == 1);
ProcessEventCallback new_hook = man->ProcessNewHook();
if (new_hook)
new_hook(pid);
lock = 0;
} break;
case IHF_NOTIFICATION_TEXT:
ConsoleOutput((LPCSTR)(buff + 8));
break;
}
} else {
// jichi 9/28/2013: Debug raw data
//ITH_DEBUG_DWORD9(RecvLen - 0xc,
// buff[0xc], buff[0xd], buff[0xe], buff[0xf],
// buff[0x10], buff[0x11], buff[0x12], buff[0x13]);
const BYTE *data = buff + data_offset; // th
int len = RecvLen - data_offset;
bool space = ::has_leading_space(data, len);
if (space) {
const BYTE *it = ::Filter(data, len);
len -= it - data;
data = it;
}
if (len >> 31) // jichi 10/27/2013: len is too large, which seldom happens
len = 0;
//man->DispatchText(pid, len ? data : nullptr, hook, retn, split, len, space);
man->DispatchText(pid, data, hook, retn, split, len, space);
}
}
EnterCriticalSection(&detach_cs);
HANDLE hDisconnect = IthCreateEvent(nullptr);
if (STATUS_PENDING == NtFsControlFile(
hTextPipe,
hDisconnect,
0, 0,
&ios,
CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
0, 0, 0, 0))
NtWaitForSingleObject(hDisconnect, 0, 0);
NtClose(hDisconnect);
DetachFromProcess(pid);
man->UnRegisterProcess(pid);
//NtClearEvent(hDetachEvent);
LeaveCriticalSection(&detach_cs);
delete[] buff;
if (::running)
ConsoleOutput("vnrhost:DetachFromProcess: detached");
//if (::running) {
// swprintf((LPWSTR)buff, FormatDetach, pid);
// ConsoleOutput((LPWSTR)buff);
// NtClose(IthCreateThread(UpdateWindows, 0));
//}
return 0;
}
// EOF
#pragma once
// settings.h
// 8/24/2013 jichi
struct Settings {
//bool debug; // whether output debug messages using pipes
int splittingInterval;// time to split text into sentences
Settings() : splittingInterval(200) {}
};
// EOF
#pragma once
// srv.h
// 8/23/2013 jichi
// Branch: ITH/IHF.h, rev 105
#include "config.h"
//#include "ith/host/settings.h"
#include "ith/host/hookman.h"
#include "ith/host/SettingManager.h"
struct Settings;
struct HookParam;
// jichi 8/24/2013: Why extern "C"? Any specific reason to use C instead of C++ naming?
extern "C" {
IHFSERVICE DWORD IHFAPI IHF_Init();
IHFSERVICE DWORD IHFAPI IHF_Start();
IHFSERVICE DWORD IHFAPI IHF_Cleanup();
IHFSERVICE DWORD IHFAPI IHF_GetPIDByName(LPCWSTR pwcTarget);
IHFSERVICE DWORD IHFAPI IHF_InjectByPID(DWORD pid);
IHFSERVICE DWORD IHFAPI IHF_ActiveDetachProcess(DWORD pid);
IHFSERVICE DWORD IHFAPI IHF_GetHookManager(HookManager **hookman);
IHFSERVICE DWORD IHFAPI IHF_GetSettingManager(SettingManager** set_man);
IHFSERVICE DWORD IHFAPI IHF_GetSettings(Settings **settings);
IHFSERVICE DWORD IHFAPI IHF_InsertHook(DWORD pid, HookParam *hp, LPCWSTR name = 0);
IHFSERVICE DWORD IHFAPI IHF_ModifyHook(DWORD pid, HookParam *hp);
IHFSERVICE DWORD IHFAPI IHF_RemoveHook(DWORD pid, DWORD addr);
IHFSERVICE DWORD IHFAPI IHF_IsAdmin();
//IHFSERVICE DWORD IHFAPI IHF_GetFilters(PVOID *mb_filter, PVOID *uni_filter);
IHFSERVICE DWORD IHFAPI IHF_AddLink(DWORD from, DWORD to);
IHFSERVICE DWORD IHFAPI IHF_UnLink(DWORD from);
IHFSERVICE DWORD IHFAPI IHF_UnLinkAll(DWORD from);
} // extern "C"
// EOF
#pragma once
// srv_p.h
// 8/24/2013 jichi
// Branch IHF/main.h, rev 111
#include "config.h"
#define GLOBAL extern
#define SHIFT_JIS 0x3A4
class HookManager;
//class CommandQueue;
class SettingManager;
class TextHook;
//class BitMap;
//class CustomFilterMultiByte;
//class CustomFilterUnicode;
//#define TextHook Hook
GLOBAL BOOL running;
//GLOBAL BitMap *pid_map;
//GLOBAL CustomFilterMultiByte *mb_filter;
//GLOBAL CustomFilterUnicode *uni_filter;
GLOBAL HookManager *man;
//GLOBAL CommandQueue *cmdq;
GLOBAL SettingManager *setman;
GLOBAL WCHAR recv_pipe[];
GLOBAL WCHAR command[];
GLOBAL HANDLE hPipeExist;
GLOBAL DWORD split_time,
cyclic_remove,
clipboard_flag,
global_filter;
GLOBAL CRITICAL_SECTION detach_cs;
DWORD WINAPI RecvThread(LPVOID lpThreadParameter);
DWORD WINAPI CmdThread(LPVOID lpThreadParameter);
void ConsoleOutput(LPCSTR text);
void ConsoleOutputW(LPCWSTR text);
DWORD GetCurrentPID();
//DWORD GetProcessIDByPath(LPWSTR str);
HANDLE GetCmdHandleByPID(DWORD pid);
//DWORD Inject(HANDLE hProc);
//DWORD InjectByPID(DWORD pid);
//DWORD PIDByName(LPWSTR target);
//DWORD Hash(LPCWSTR module, int length=-1);
// EOF
This diff is collapsed. Click to expand it.
#pragma once
// textthread.h
// 8/23/2013 jichi
// Branch: ITH/TextThread.h, rev 120
#include "ith/host/textthread_p.h"
#include <intrin.h> // require _InterlockedExchange
struct RepeatCountNode {
short repeat;
short count;
RepeatCountNode *next;
//RepeatCountNode() : repeat(0), count(0), next(nullptr) {}
};
struct ThreadParameter {
DWORD pid; // jichi: 5/11/2014: The process ID
DWORD hook;
DWORD retn; // jichi 5/11/2014: The return address of the hook
DWORD spl; // jichi 5/11/2014: the processed split value of the hook parameter
};
#define CURRENT_SELECT 0x1000
#define REPEAT_NUMBER_DECIDED 0x2000
#define BUFF_NEWLINE 0x4000
#define CYCLIC_REPEAT 0x8000
#define COUNT_PER_FOWARD 0x200
#define REPEAT_DETECT 0x10000
#define REPEAT_SUPPRESS 0x20000
#define REPEAT_NEWLINE 0x40000
class TextThread;
typedef void (* ConsoleCallback)(LPCSTR text);
typedef void (* ConsoleWCallback)(LPCWSTR text);
typedef DWORD (* ThreadOutputFilterCallback)(TextThread *, BYTE *, DWORD, DWORD, PVOID, bool space); // jichi 10/27/2013: Add space
typedef DWORD (* ThreadEventCallback)(TextThread *);
//extern DWORD split_time,repeat_count,global_filter,cyclic_remove;
class TextThread : public MyVector<BYTE, 0x200>
{
public:
TextThread(DWORD pid, DWORD hook, DWORD retn, DWORD spl, WORD num);
~TextThread();
//virtual void CopyLastSentence(LPWSTR str);
//virtual void SetComment(LPWSTR);
//virtual void ExportTextToFile(LPWSTR filename);
virtual bool CheckCycle(TextThread *start);
virtual DWORD GetThreadString(LPWSTR str, DWORD max);
virtual DWORD GetEntryString(LPWSTR str, DWORD max = 0x200);
void Reset();
void AddText(const BYTE *con,int len, bool new_line, bool space); // jichi 10/27/2013: add const; remove console; add space
void RemoveSingleRepeatAuto(const BYTE *con, int &len); // jichi 10/27/2013: add const
void RemoveSingleRepeatForce(BYTE *con, int &len);
void RemoveCyclicRepeat(BYTE *&con, int &len);
void ResetRepeatStatus();
void AddLineBreak();
//void ResetEditText();
void ComboSelectCurrent();
void UnLinkAll();
void CopyLastToClipboard();
//void AdjustPrevRepeat(DWORD len);
//void PrevRepeatLength(DWORD &len);
//bool AddToCombo();
bool RemoveFromCombo();
void SetNewLineFlag();
void SetNewLineTimer();
BYTE *GetStore(DWORD *len) { if (len) *len = used; return storage; }
DWORD LastSentenceLen() { return used - last_sentence; }
DWORD PID() const { return tp.pid; }
DWORD Addr() const {return tp.hook; }
DWORD &Status() { return status; }
WORD Number() const { return thread_number; }
WORD &Last() { return last; }
WORD &LinkNumber() { return link_number; }
UINT_PTR &Timer() { return timer; }
ThreadParameter *GetThreadParameter() { return &tp; }
TextThread *&Link() { return link; }
//LPCWSTR GetComment() { return comment; }
ThreadOutputFilterCallback RegisterOutputCallBack(ThreadOutputFilterCallback cb, PVOID data)
{
app_data = data;
return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&output,(long)cb);
}
ThreadOutputFilterCallback RegisterFilterCallBack(ThreadOutputFilterCallback cb, PVOID data)
{
app_data = data;
return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&filter,(long)cb);
}
void SetRepeatFlag() { status |= CYCLIC_REPEAT; }
void ClearNewLineFlag() { status &= ~BUFF_NEWLINE; }
void ClearRepeatFlag() { status &= ~CYCLIC_REPEAT; }
protected:
void AddTextDirect(const BYTE *con, int len, bool space); // jichi 10/27/2013: add const; add space; change to protected
private:
ThreadParameter tp;
WORD thread_number,
link_number;
WORD last,
align_space;
WORD repeat_single;
WORD repeat_single_current;
WORD repeat_single_count;
WORD repeat_detect_count;
RepeatCountNode *head;
TextThread *link;
ThreadOutputFilterCallback filter; // jichi 10/27/2013: Remove filter
ThreadOutputFilterCallback output;
PVOID app_data;
//LPWSTR comment,
LPWSTR thread_string;
UINT_PTR timer;
DWORD status,repeat_detect_limit;
DWORD last_sentence,
prev_sentence,
sentence_length,
repeat_index,
last_time;
};
// EOF
#pragma once
// textthread_p.h
// 8/14/2013 jichi
// Branch: ITH/main_template.h, rev 66
#include "config.h"
template <typename T>
void Release(const T &p) { delete p; }
// Prevent memory release.
// Used when T is basic types and will be automatically released (on stack).
#define MK_BASIC_TYPE(T) \
template<> \
void Release<T>(const T &p) {}
template<class T>
struct BinaryEqual {
bool operator ()(const T &a, const T &b, DWORD) { return a == b; }
};
template<class T, int default_size, class fComp=BinaryEqual<T> >
class MyVector
{
public:
MyVector() : size(default_size), used(0)
{
InitializeCriticalSection(&cs_store);
storage = new T[size];
// jichi 9/21/2013: zero memory
// This would cause trouble if T is not an atomic type
ITH_MEMSET_HEAP(storage, 0, sizeof(T) * size);
}
virtual ~MyVector()
{
if (storage)
delete[] storage;
DeleteCriticalSection(&cs_store);
storage = 0;
}
void Reset()
{
EnterCriticalSection(&cs_store);
for (int i = 0; i < used; i++) {
Release<T>(storage[i]);
storage[i] = T();
}
used = 0;
LeaveCriticalSection(&cs_store);
}
void Remove(int index)
{
if (index>=used)
return;
Release<T>(storage[index]);
for (int i = index; i < used; i++)
storage[i] = storage[i+1];
used--;
}
void ClearMemory(int offset, int clear_size)
{
if (clear_size < 0)
return;
EnterCriticalSection(&cs_store);
if (offset+clear_size <= size)
memset(storage+offset, 0, clear_size * sizeof(T)); // jichi 11/30/2013: This is the original code of ITH
LeaveCriticalSection(&cs_store);
//else __asm int 3
}
int AddToStore(T *con,int amount)
{
if (amount <= 0 || con == 0)
return 0;
int status = 0;
EnterCriticalSection(&cs_store);
if (amount + used + 2 >= size) {
while (amount + used + 2 >= size)
size<<=1;
T *temp;
if (size * sizeof(T) < 0x1000000) {
temp = new T[size];
if (size > used)
ITH_MEMSET_HEAP(temp, 0, (size - used) * sizeof(T)); // jichi 9/25/2013: zero memory
memcpy(temp, storage, used * sizeof(T));
} else {
size = default_size;
temp = new T[size];
ITH_MEMSET_HEAP(temp, 0, sizeof(T) * size); // jichi 9/25/2013: zero memory
used = 0;
status = 1;
}
delete[] storage;
storage = temp;
}
memcpy(storage+used, con, amount * sizeof(T));
used += amount;
LeaveCriticalSection(&cs_store);
return status;
}
int Find(const T &item, int start = 0, DWORD control = 0)
{
int c = -1;
for (int i=start; i < used; i++)
if (fCmp(storage[i],item,control)) {
c=i;
break;
}
//if (storage[i]==item) {c=i;break;}
return c;
}
int Used() const { return used; }
T *Storage() const { return storage; }
void LockVector() { EnterCriticalSection(&cs_store); }
void UnlockVector() { LeaveCriticalSection(&cs_store); }
protected:
CRITICAL_SECTION cs_store;
int size,
used;
T *storage;
fComp fCmp;
};
// EOF
/*
#ifndef ITH_STACK
#define ITH_STACK
template<class T, int default_size>
class MyStack
{
public:
MyStack(): index(0) {}
void push_back(const T& e)
{
if (index<default_size)
s[index++]=e;
}
void pop_back()
{
index--;
}
T& back()
{
return s[index-1];
}
T& operator[](int i) {return s[i];}
int size() {return index;}
private:
int index;
T s[default_size];
};
#endif
*/
#pragma once
// mono/funcinfo.h
// 12/26/2014
// https://github.com/mono/mono/blob/master/mono/metadata/object.h
// http://api.xamarin.com/index.aspx?link=xhtml%3Adeploy%2Fmono-api-string.html
//#include "ith/import/mono/types.h"
// MonoString* mono_string_new (MonoDomain *domain,
// const char *text);
// MonoString* mono_string_new_len (MonoDomain *domain,
// const char *text,
// guint length);
// MonoString* mono_string_new_size (MonoDomain *domain,
// gint32 len);
// MonoString* mono_string_new_utf16 (MonoDomain *domain,
// const guint16 *text,
// gint32 len);
// MonoString* mono_string_from_utf16 (gunichar2 *data);
// mono_unichar2* mono_string_to_utf16 (MonoString *s);
// char* mono_string_to_utf8 (MonoString *s);
// gboolean mono_string_equal (MonoString *s1,
// MonoString *s2);
// guint mono_string_hash (MonoString *s);
// MonoString* mono_string_intern (MonoString *str);
// MonoString* mono_string_is_interned (MonoString *o);
// MonoString* mono_string_new_wrapper (const char *text);
// gunichar2* mono_string_chars (MonoString *s);
// int mono_string_length (MonoString *s);
// gunichar2* mono_unicode_from_external (const gchar *in, gsize *bytes);
// gchar* mono_unicode_to_external (const gunichar2 *uni);
// gchar* mono_utf8_from_external (const gchar *in);
struct MonoFunction {
const wchar_t *hookName;
const char *functionName;
size_t textIndex; // argument index, starting from 0
size_t lengthIndex; // argument index, start from 0
unsigned long hookType; // HookParam type
void *text_fun; // HookParam::text_fun_t
};
#define MONO_FUNCTIONS_INITIALIZER \
{ L"mono_string_to_utf8", "mono_string_to_utf8", 0, 0, USING_UNICODE, SpecialHookMonoString } \
, { L"mono_string_to_utf16", "mono_string_to_utf16", 0, 0, USING_UNICODE, SpecialHookMonoString } \
, { L"mono_utf8_from_external", "mono_utf8_from_external", 1, 0, USING_STRING|USING_UTF8, nullptr } \
, { L"mono_string_from_utf16", "mono_string_from_utf16", 1, 0, USING_UNICODE, nullptr } \
, { L"mono_unicode_from_external", "mono_unicode_from_external", 1, 2, USING_UNICODE, nullptr } \
, { L"mono_unicode_to_external", "mono_unicode_to_external", 1, 0, USING_UNICODE, nullptr }
// EOF
# mono.pri
# 12/26/2014 jichi
DEPENDPATH += $$PWD
HEADERS += \
$$PWD/funcinfo.h \
$$PWD/types.h
# EOF
#pragma once
// mono/types.h
// 12/26/2014
// https://github.com/mono/mono/blob/master/mono/metadata/object.h
// http://api.xamarin.com/index.aspx?link=xhtml%3Adeploy%2Fmono-api-string.html
#include <cstdint>
// mono/io-layer/uglify.h
typedef int8_t gint8;
typedef int32_t gint32;
typedef wchar_t gunichar2; // either char or wchar_t, depending on how mono is compiled
typedef gint8 mono_byte;
typedef gunichar2 mono_unichar2;
// mono/metadata/object.h
typedef mono_byte MonoBoolean;
struct MonoArray;
struct MonoDelegate;
struct MonoException;
struct MonoString;
struct MonoThreadsSync;
struct MonoThread;
struct MonoVTable;
struct MonoObject {
MonoVTable *vtable;
MonoThreadsSync *synchronisation;
};
struct MonoString {
MonoObject object;
gint32 length;
gunichar2 chars[0];
};
// EOF
#pragma once
//#include "ith/common/const.h"
// ppsspp/funcinfo.h
// 12/26/2014
// See: https://github.com/hrydgard/ppsspp
// Core/HLE (High Level Emulator)
// - sceCcc
// #void sceCccSetTable(u32 jis2ucs, u32 ucs2jis)
// int sceCccUTF8toUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr)
// int sceCccUTF8toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr)
// int sceCccUTF16toUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr)
// int sceCccUTF16toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr)
// int sceCccSJIStoUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr)
// int sceCccSJIStoUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr)
// int sceCccStrlenUTF8(u32 strAddr)
// int sceCccStrlenUTF16(u32 strAddr)
// int sceCccStrlenSJIS(u32 strAddr)
// u32 sceCccEncodeUTF8(u32 dstAddrAddr, u32 ucs)
// void sceCccEncodeUTF16(u32 dstAddrAddr, u32 ucs)
// u32 sceCccEncodeSJIS(u32 dstAddrAddr, u32 jis)
// u32 sceCccDecodeUTF8(u32 dstAddrAddr)
// u32 sceCccDecodeUTF16(u32 dstAddrAddr)
// u32 sceCccDecodeSJIS(u32 dstAddrAddr)
// int sceCccIsValidUTF8(u32 c)
// int sceCccIsValidUTF16(u32 c)
// int sceCccIsValidSJIS(u32 c)
// int sceCccIsValidUCS2(u32 c)
// int sceCccIsValidUCS4(u32 c)
// int sceCccIsValidJIS(u32 c)
// int sceCccIsValidUnicode(u32 c)
// #u32 sceCccSetErrorCharUTF8(u32 c)
// #u32 sceCccSetErrorCharUTF16(u32 c)
// #u32 sceCccSetErrorCharSJIS(u32 c)
// u32 sceCccUCStoJIS(u32 c, u32 alt)
// u32 sceCccJIStoUCS(u32 c, u32 alt)
// - sceFont: search charCode
// int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr)
// int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr)
// int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr)
// int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr)
// int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr)
// int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight)
// #int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode)
// int sceFontGetShadowGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr)
// int sceFontGetShadowGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight)
// - sceKernelInterrupt
// u32 sysclib_strcat(u32 dst, u32 src)
// int sysclib_strcmp(u32 dst, u32 src)
// u32 sysclib_strcpy(u32 dst, u32 src)
// u32 sysclib_strlen(u32 src)
//
// Sample debug string:
// 006EFD8E PUSH PPSSPPWi.00832188 ASCII "sceCccEncodeSJIS(%08x, U+%04x)"
// Corresponding source code in sceCcc:
// ERROR_LOG(HLE, "sceCccEncodeSJIS(%08x, U+%04x): invalid pointer", dstAddrAddr, jis);
struct PPSSPPFunction
{
const wchar_t *hookName; // hook name
size_t argIndex; // argument index
unsigned long hookType; // hook parameter type
unsigned long hookSplit; // hook parameter split, positive: stack, negative: registers
const char *pattern; // debug string used within the function
};
// jichi 7/14/2014: UTF-8 is treated as STRING
// http://867258173.diandian.com/post/2014-06-26/40062099618
// sceFontGetCharGlyphImage_Clip
// Sample game: [KID] Monochrome: sceFontGetCharInfo, sceFontGetCharGlyphImage_Clip
//
// Example: { L"sceFontGetCharInfo", 2, USING_UNICODE, 4, "sceFontGetCharInfo(" }
// Text is at arg2, using arg1 as split
#define PPSSPP_FUNCTIONS_INITIALIZER \
{ L"sceCccStrlenSJIS", 1, USING_STRING, 0, "sceCccStrlenSJIS(" } \
, { L"sceCccStrlenUTF8", 1, USING_UTF8, 0, "sceCccStrlenUTF8(" } \
, { L"sceCccStrlenUTF16", 1, USING_UNICODE, 0, "sceCccStrlenUTF16(" } \
\
, { L"sceCccSJIStoUTF8", 3, USING_UTF8, 0, "sceCccSJIStoUTF8(" } \
, { L"sceCccSJIStoUTF16", 3, USING_STRING, 0, "sceCccSJIStoUTF16(" } \
, { L"sceCccUTF8toSJIS", 3, USING_UTF8, 0, "sceCccUTF8toSJIS(" } \
, { L"sceCccUTF8toUTF16", 3, USING_UTF8, 0, "sceCccUTF8toUTF16(" } \
, { L"sceCccUTF16toSJIS", 3, USING_UNICODE, 0, "sceCccUTF16toSJIS(" } \
, { L"sceCccUTF16toUTF8", 3, USING_UNICODE, 0, "sceCccUTF16toUTF8(" } \
\
, { L"sceFontGetCharInfo", 2, USING_UNICODE, 4, "sceFontGetCharInfo(" } \
, { L"sceFontGetShadowInfo", 2, USING_UNICODE, 4, "sceFontGetShadowInfo("} \
, { L"sceFontGetCharImageRect", 2, USING_UNICODE, 4, "sceFontGetCharImageRect(" } \
, { L"sceFontGetShadowImageRect", 2, USING_UNICODE, 4, "sceFontGetShadowImageRect(" } \
, { L"sceFontGetCharGlyphImage", 2, USING_UNICODE, 4, "sceFontGetCharGlyphImage(" } \
, { L"sceFontGetCharGlyphImage_Clip", 2, USING_UNICODE, 4, "sceFontGetCharGlyphImage_Clip(" } \
, { L"sceFontGetShadowGlyphImage", 2, USING_UNICODE, 4, "sceFontGetShadowGlyphImage(" } \
, { L"sceFontGetShadowGlyphImage_Clip", 2, USING_UNICODE, 4, "sceFontGetShadowGlyphImage_Clip(" } \
\
, { L"sysclib_strcat", 2, USING_STRING, 0, "Untested sysclib_strcat(" } \
, { L"sysclib_strcpy", 2, USING_STRING, 0, "Untested sysclib_strcpy(" } \
, { L"sysclib_strlen", 1, USING_STRING, 0, "Untested sysclib_strlen(" }
// Disabled as I am not sure how to deal with the source string
//, { L"sceCccEncodeSJIS", 2, USING_STRING, 0, "sceCccEncodeSJIS(" }
//, { L"sceCccEncodeUTF8", 2, USING_UTF8, 0, "sceCccEncodeUTF8(" }
//, { L"sceCccEncodeUTF16", 2, USING_UNICODE, 0, "sceCccEncodeUTF16(" }
//, { L"sysclib_strcmp", 2, USING_STRING, 0, "Untested sysclib_strcmp(" }
// EOF