mireado

starting commit

1 +#pragma once
2 +
3 +// hook.h
4 +// 8/23/2013 jichi
5 +// Branch: ITH/IHF_DLL.h, rev 66
6 +
7 +#include "ith/common/const.h"
8 +#include "ith/common/types.h"
9 +
10 +//#ifdef IHF
11 +//# define IHFAPI __declspec(dllexport) __stdcall
12 +//#else
13 +//# define IHFAPI __declspec(dllimport) __stdcall
14 +//#endif // IHF
15 +#define IHFAPI // 9/19/2014 jichi: dummy
16 +
17 +//extern "C" {
18 +//DWORD IHFAPI OutputConsole(LPCWSTR text);
19 +void IHFAPI ConsoleOutput(LPCSTR text); // jichi 12/25/2013: Used to return length of sent text
20 +//DWORD IHFAPI OutputDWORD(DWORD d);
21 +//DWORD IHFAPI OutputRegister(DWORD *base);
22 +DWORD IHFAPI NotifyHookInsert(DWORD addr);
23 +DWORD IHFAPI NewHook(const HookParam &hp, LPCWSTR name, DWORD flag = HOOK_ENGINE);
24 +DWORD IHFAPI RemoveHook(DWORD addr);
25 +DWORD IHFAPI SwitchTrigger(DWORD on);
26 +DWORD IHFAPI GetFunctionAddr(const char *name, DWORD *addr, DWORD *base, DWORD *size, LPWSTR *base_name);
27 +//DWORD IHFAPI RegisterEngineModule(DWORD idEngine, DWORD dnHook);
28 +//} // extern "C"
29 +
30 +// 10/21/2014 jichi: TODO: Get rid of this global variable
31 +// Defined in pipe.cc
32 +extern bool engine_registered;
33 +
34 +
35 +// 10/14/2014 jichi: disable GDI hooks
36 +void DisableGDIHooks();
37 +
38 +// EOF
1 +# hook.pro
2 +# 8/9/2013 jichi
3 +# Build vnrhook.dll for Windows 7+
4 +
5 +CONFIG += eh eha # exception handler to catch all exceptions
6 +#CONFIG += noeh # msvcrt on Windows XP does not has exception handler
7 +include(../dllconfig.pri)
8 +include(../sys/sys.pri)
9 +include($$LIBDIR/disasm/disasm.pri)
10 +include($$LIBDIR/memdbg/memdbg.pri)
11 +include($$LIBDIR/ntinspect/ntinspect.pri)
12 +#include($$LIBDIR/winseh/winseh_safe.pri)
13 +include($$LIBDIR/winversion/winversion.pri)
14 +
15 +# 9/27/2013: disable ITH this game engine, only for debugging purpose
16 +#DEFINES += ITH_DISABLE_ENGINE
17 +
18 +# jichi 9/22/2013: When ITH is on wine, mutex is needed to protect NtWriteFile
19 +#DEFINES += ITH_WINE
20 +#DEFINES += ITH_SYNC_PIPE
21 +
22 +## Libraries
23 +
24 +LIBS += -lkernel32 -luser32 -lgdi32
25 +
26 +## Sources
27 +
28 +TEMPLATE = lib
29 +TARGET = vnrhook
30 +
31 +#CONFIG += staticlib
32 +
33 +HEADERS += \
34 + config.h \
35 + cli.h \
36 + hook.h \
37 + engine/engine.h \
38 + engine/hookdefs.h \
39 + engine/match.h \
40 + engine/pchooks.h \
41 + engine/util.h \
42 + tree/avl.h
43 +
44 +SOURCES += \
45 + main.cc \
46 + rpc/pipe.cc \
47 + hijack/texthook.cc \
48 + engine/engine.cc \
49 + engine/match.cc \
50 + engine/pchooks.cc \
51 + engine/util.cc
52 +
53 +#RC_FILE += vnrhook.rc
54 +#OTHER_FILES += vnrhook.rc
55 +
56 +# EOF
1 +// main.cc
2 +// 8/24/2013 jichi
3 +// Branch: ITH_DLL/main.cpp, rev 128
4 +// 8/24/2013 TODO: Clean up this file
5 +
6 +#ifdef _MSC_VER
7 +# pragma warning (disable:4100) // C4100: unreference formal parameter
8 +//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
9 +#endif // _MSC_VER
10 +
11 +#include "cli.h"
12 +#include "tree/avl.h"
13 +#include "engine/match.h"
14 +#include "ith/common/const.h"
15 +#include "ith/common/defs.h"
16 +#include "ith/common/except.h"
17 +//#include "ith/common/growl.h"
18 +#include "ith/sys/sys.h"
19 +#include "ccutil/ccmacro.h"
20 +//#include "ntinspect/ntinspect.h"
21 +//#include "winseh/winseh.h"
22 +//#include <boost/foreach.hpp>
23 +//#include "md5.h"
24 +//#include <ITH\AVL.h>
25 +//#include <ITH\ntdll.h>
26 +
27 +// Global variables
28 +
29 +// jichi 6/3/2014: memory range of the current module
30 +DWORD processStartAddress,
31 + processStopAddress;
32 +
33 +namespace { // unnamed
34 +wchar_t processName[MAX_PATH];
35 +
36 +inline void GetProcessName(wchar_t *name)
37 +{
38 + //assert(name);
39 + PLDR_DATA_TABLE_ENTRY it;
40 + __asm
41 + {
42 + mov eax,fs:[0x30]
43 + mov eax,[eax+0xc]
44 + mov eax,[eax+0xc]
45 + mov it,eax
46 + }
47 + wcscpy(name, it->BaseDllName.Buffer);
48 +}
49 +} // unmaed namespace
50 +
51 +enum { HOOK_BUFFER_SIZE = MAX_HOOK * sizeof(TextHook) };
52 +//#define MAX_HOOK (HOOK_BUFFER_SIZE/sizeof(TextHook))
53 +DWORD hook_buff_len = HOOK_BUFFER_SIZE;
54 +
55 +namespace { FilterRange _filter[IHF_FILTER_CAPACITY]; }
56 +FilterRange *filter = _filter;
57 +
58 +WCHAR dll_mutex[0x100];
59 +//WCHAR dll_name[0x100];
60 +WCHAR hm_mutex[0x100];
61 +WCHAR hm_section[0x100];
62 +HINSTANCE hDLL;
63 +HANDLE hSection;
64 +bool running,
65 + live = false;
66 +int current_hook = 0,
67 + user_hook_count = 0;
68 +DWORD trigger = 0;
69 +HANDLE
70 + hFile,
71 + hMutex,
72 + hmMutex;
73 +//DWORD current_process_id;
74 +extern DWORD enter_count;
75 +//extern LPWSTR current_dir;
76 +extern DWORD engine_type;
77 +extern DWORD module_base;
78 +AVLTree<char, FunctionInfo, SCMP, SCPY, SLEN> *tree;
79 +
80 +namespace { // unnamed
81 +
82 +void AddModule(DWORD hModule, DWORD size, LPWSTR name)
83 +{
84 + IMAGE_DOS_HEADER *DosHdr;
85 + IMAGE_NT_HEADERS *NtHdr;
86 + IMAGE_EXPORT_DIRECTORY *ExtDir;
87 + UINT uj;
88 + FunctionInfo info = {0, hModule, size, name};
89 + char *pcFuncPtr, *pcBuffer;
90 + DWORD dwReadAddr, dwFuncName, dwExportAddr;
91 + WORD wOrd;
92 + DosHdr = (IMAGE_DOS_HEADER *)hModule;
93 + if (IMAGE_DOS_SIGNATURE==DosHdr->e_magic) {
94 + dwReadAddr = hModule + DosHdr->e_lfanew;
95 + NtHdr = (IMAGE_NT_HEADERS *)dwReadAddr;
96 + if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
97 + dwExportAddr = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
98 + if (dwExportAddr == 0)
99 + return;
100 + dwExportAddr+=hModule;
101 + ExtDir=(IMAGE_EXPORT_DIRECTORY*)dwExportAddr;
102 + dwExportAddr=hModule+ExtDir->AddressOfNames;
103 + for (uj = 0; uj < ExtDir->NumberOfNames; uj++) {
104 + dwFuncName=*(DWORD*)dwExportAddr;
105 + pcBuffer = (char *)(hModule+dwFuncName);
106 + pcFuncPtr=(char *)(hModule+(DWORD)ExtDir->AddressOfNameOrdinals+(uj*sizeof(WORD)));
107 + wOrd = *(WORD *)pcFuncPtr;
108 + pcFuncPtr = (char *)(hModule+(DWORD)ExtDir->AddressOfFunctions+(wOrd*sizeof(DWORD)));
109 + info.addr=hModule+*(DWORD*)pcFuncPtr;
110 + ::tree->Insert(pcBuffer,info);
111 + dwExportAddr+=sizeof(DWORD);
112 + }
113 + }
114 + }
115 +}
116 +
117 +void GetFunctionNames()
118 +{
119 + // jichi 9/26/2013: AVLTree is already zero
120 + PPEB ppeb;
121 + __asm {
122 + mov eax, fs:[0x30]
123 + mov ppeb, eax
124 + }
125 + DWORD temp = *(DWORD *)(&ppeb->Ldr->InLoadOrderModuleList);
126 + PLDR_DATA_TABLE_ENTRY it = (PLDR_DATA_TABLE_ENTRY)temp;
127 + while (it->SizeOfImage) {
128 + AddModule((DWORD)it->DllBase, it->SizeOfImage, it->BaseDllName.Buffer);
129 + it = (PLDR_DATA_TABLE_ENTRY)it->InLoadOrderModuleList.Flink;
130 + if (*(DWORD *)it == temp)
131 + break;
132 + }
133 +}
134 +
135 +void RequestRefreshProfile()
136 +{
137 + if (::live) {
138 + BYTE buffer[0x80] = {}; // 11/14/2013: reset to zero. Shouldn't it be 0x8 instead of 0x80?
139 + *(DWORD *)buffer = -1;
140 + *(DWORD *)(buffer + 4) = 1;
141 + *(DWORD *)(buffer + 8) = 0;
142 + IO_STATUS_BLOCK ios;
143 + CliLockPipe();
144 + NtWriteFile(hPipe, 0, 0, 0, &ios, buffer, HEADER_SIZE, 0, 0);
145 + CliUnlockPipe();
146 + }
147 +}
148 +
149 +} // unnamed namespace
150 +
151 +DWORD IHFAPI GetFunctionAddr(const char *name, DWORD *addr, DWORD *base, DWORD *size, LPWSTR *base_name)
152 +{
153 + TreeNode<char *,FunctionInfo> *node = ::tree->Search(name);
154 + if (node) {
155 + if (addr) *addr = node->data.addr;
156 + if (base) *base = node->data.module;
157 + if (size) *size = node->data.size;
158 + if (base_name) *base_name = node->data.name;
159 + return TRUE;
160 + }
161 + else
162 + return FALSE;
163 +}
164 +
165 +BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved)
166 +{
167 +
168 + static HANDLE hSendThread,
169 + hCmdThread,
170 + hEngineThread;
171 +
172 +
173 + CC_UNUSED(lpReserved);
174 +
175 + //static WCHAR dll_exist[] = L"ITH_DLL_RUNNING";
176 + static WCHAR dll_exist[] = ITH_CLIENT_MUTEX;
177 + static HANDLE hDllExist;
178 +
179 + // jichi 9/23/2013: wine deficenciy on mapping sections
180 + // Whe set to false, do not map sections.
181 + //static bool ith_has_section = true;
182 +
183 + switch (fdwReason) {
184 + case DLL_PROCESS_ATTACH:
185 + {
186 + LdrDisableThreadCalloutsForDll(hModule);
187 + //IthBreak();
188 + ::module_base = (DWORD)hModule;
189 + IthInitSystemService();
190 + swprintf(hm_section, ITH_SECTION_ L"%d", current_process_id);
191 +
192 + // jichi 9/25/2013: Interprocedural communication with vnrsrv.
193 + hSection = IthCreateSection(hm_section, HOOK_SECTION_SIZE, PAGE_EXECUTE_READWRITE);
194 + ::hookman = nullptr;
195 + NtMapViewOfSection(hSection, NtCurrentProcess(),
196 + (LPVOID *)&::hookman, 0, hook_buff_len, 0, &hook_buff_len, ViewUnmap, 0,
197 + PAGE_EXECUTE_READWRITE);
198 + //PAGE_EXECUTE_READWRITE);
199 +
200 + GetProcessName(::processName);
201 + FillRange(::processName, &::processStartAddress, &::processStopAddress);
202 + //NtInspect::getCurrentMemoryRange(&::processStartAddress, &::processStopAddress);
203 +
204 + //if (!::hookman) {
205 + // ith_has_section = false;
206 + // ::hookman = new TextHook[MAX_HOOK];
207 + // memset(::hookman, 0, MAX_HOOK * sizeof(TextHook));
208 + //}
209 +
210 + //LPCWSTR p;
211 + //for (p = GetMainModulePath(); *p; p++);
212 + //for (p = p; *p != L'\\'; p--);
213 + //wcscpy(dll_name, p + 1);
214 + //swprintf(dll_mutex,L"ITH_%.4d_%s",current_process_id,current_dir);
215 + swprintf(dll_mutex, ITH_PROCESS_MUTEX_ L"%d", current_process_id);
216 + swprintf(hm_mutex, ITH_HOOKMAN_MUTEX_ L"%d", current_process_id);
217 + hmMutex = IthCreateMutex(hm_mutex, FALSE);
218 +
219 + DWORD s;
220 + hMutex = IthCreateMutex(dll_mutex, TRUE, &s); // jichi 9/18/2013: own is true
221 + if (s)
222 + return FALSE;
223 +
224 + hDllExist = IthCreateMutex(dll_exist, 0);
225 + hDLL = hModule;
226 + ::running = true;
227 + ::current_available = ::hookman;
228 + ::tree = new AVLTree<char, FunctionInfo, SCMP, SCPY, SLEN>;
229 + GetFunctionNames();
230 + InitFilterTable();
231 + //InitDefaultHook(); // jichi 7/17/2014: Disabled by default
232 + hSendThread = IthCreateThread(WaitForPipe, 0);
233 + hCmdThread = IthCreateThread(CommandPipe, 0);
234 + hEngineThread = IthCreateThread(Engine::match, 0);
235 + }
236 + break;
237 + case DLL_PROCESS_DETACH:
238 + {
239 + // jichi 10/2/2103: Cannot use __try in functions that require object unwinding
240 + //ITH_TRY {
241 + ::running = false;
242 + ::live = false;
243 +
244 + const LONGLONG timeout = -50000000; // in nanoseconds = 5 seconds
245 +
246 + if (hEngineThread) {
247 + NtWaitForSingleObject(hEngineThread, 0, (PLARGE_INTEGER)&timeout);
248 + NtClose(hEngineThread);
249 + }
250 +
251 + if (hSendThread) {
252 + NtWaitForSingleObject(hSendThread, 0, (PLARGE_INTEGER)&timeout);
253 + NtClose(hSendThread);
254 + }
255 +
256 + if (hCmdThread) {
257 + NtWaitForSingleObject(hCmdThread, 0, (PLARGE_INTEGER)&timeout);
258 + NtClose(hCmdThread);
259 + }
260 +
261 + for (TextHook *man = ::hookman; man->RemoveHook(); man++);
262 + //LARGE_INTEGER lint = {-10000, -1};
263 + while (::enter_count)
264 + IthSleep(1); // jichi 9/28/2013: sleep for 1 ms
265 + //NtDelayExecution(0, &lint);
266 + for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++)
267 + man->ClearHook();
268 + //if (ith_has_section)
269 + NtUnmapViewOfSection(NtCurrentProcess(), ::hookman);
270 + //else
271 + // delete[] ::hookman;
272 + NtClose(hSection);
273 + NtClose(hMutex);
274 +
275 + delete ::tree;
276 + IthCloseSystemService();
277 + NtClose(hmMutex);
278 + NtClose(hDllExist);
279 + //} ITH_EXCEPT {}
280 + } break;
281 + }
282 + return TRUE;
283 +}
284 +
285 +//extern "C" {
286 +DWORD IHFAPI NewHook(const HookParam &hp, LPCWSTR name, DWORD flag)
287 +{
288 + WCHAR str[128];
289 + int current = ::current_available - ::hookman;
290 + if (current < MAX_HOOK) {
291 + //flag &= 0xffff;
292 + //if ((flag & HOOK_AUXILIARY) == 0)
293 + flag |= HOOK_ADDITIONAL;
294 + if (name == NULL || name[0] == '\0')
295 + {
296 + swprintf(str, L"UserHook%d", user_hook_count++);
297 + }
298 + else
299 + {
300 + wcscpy(str, name);
301 + }
302 +
303 + ConsoleOutput("vnrcli:NewHook: try inserting hook");
304 +
305 + // jichi 7/13/2014: This function would raise when too many hooks added
306 + ::hookman[current].InitHook(hp, str, flag & 0xffff);
307 +
308 + if (::hookman[current].InsertHook() == 0) {
309 + ConsoleOutput("vnrcli:NewHook: hook inserted");
310 + //ConsoleOutputW(name);
311 + //swprintf(str,L"Insert address 0x%.8X.", hookman[current].Address());
312 + RequestRefreshProfile();
313 + } else
314 + ConsoleOutput("vnrcli:NewHook:WARNING: failed to insert hook");
315 + }
316 + return 0;
317 +}
318 +DWORD IHFAPI RemoveHook(DWORD addr)
319 +{
320 + for (int i = 0; i < MAX_HOOK; i++)
321 + if (::hookman[i].Address ()== addr) {
322 + ::hookman[i].ClearHook();
323 + return 0;
324 + }
325 + return 0;
326 +}
327 +
328 +DWORD IHFAPI SwitchTrigger(DWORD t)
329 +{
330 + trigger = t;
331 + return 0;
332 +}
333 +
334 +//} // extern "C"
335 +
336 +
337 +namespace { // unnamed
338 +
339 +BOOL SafeFillRange(LPCWSTR dll, DWORD *lower, DWORD *upper)
340 +{
341 + BOOL ret = FALSE;
342 + ITH_WITH_SEH(ret = FillRange(dll, lower, upper));
343 + return ret;
344 +}
345 +
346 +} // unnamed namespace
347 +
348 +// jichi 12/13/2013
349 +// Use listdlls from SystemInternals
350 +void InitFilterTable()
351 +{
352 + LPCWSTR l[] = { IHF_FILTER_DLL_LIST };
353 + enum { capacity = sizeof(l)/sizeof(*l) };
354 +
355 + size_t count = 0;
356 + //for (auto p : l)
357 + for (size_t i = 0; i < capacity; i++)
358 + if (SafeFillRange(l[i], &::filter[count].lower, &::filter[count].upper))
359 + count++;
360 +}
361 +
362 +// EOF
363 +/*
364 +
365 +static DWORD recv_esp, recv_addr;
366 +static CONTEXT recover_context;
367 +static __declspec(naked) void MySEH()
368 +{
369 + __asm{
370 + mov eax, [esp+0xC]
371 + mov edi,eax
372 + mov ecx,0xB3
373 + mov esi, offset recover_context
374 + rep movs
375 + mov ecx, [recv_esp]
376 + mov [eax+0xC4],ecx
377 + mov edx, [recv_addr]
378 + mov [eax+0xB8],edx
379 + xor eax,eax
380 + retn
381 + }
382 +}
383 +
384 +EXCEPTION_DISPOSITION ExceptHandler(
385 + EXCEPTION_RECORD *ExceptionRecord,
386 + void * EstablisherFrame,
387 + CONTEXT *ContextRecord,
388 + void * DispatcherContext )
389 +{
390 + ContextRecord->Esp=recv_esp;
391 + ContextRecord->Eip=recv_addr;
392 + return ExceptionContinueExecution;
393 +}
394 +int GuardRange(LPWSTR module, DWORD *a, DWORD *b)
395 +{
396 + int flag=0;
397 + __asm
398 + {
399 + mov eax,seh_recover
400 + mov recv_addr,eax
401 + push ExceptHandler
402 + push fs:[0]
403 + mov recv_esp,esp
404 + mov fs:[0],esp
405 + }
406 + flag = FillRange(module, a, b);
407 + __asm
408 + {
409 +seh_recover:
410 + mov eax,[esp]
411 + mov fs:[0],eax
412 + add esp,8
413 + }
414 + return flag;
415 +}
416 +*/
1 +// pipe.cc
2 +// 8/24/2013 jichi
3 +// Branch: ITH_DLL/pipe.cpp, rev 66
4 +// 8/24/2013 TODO: Clean up this file
5 +
6 +#ifdef _MSC_VER
7 +# pragma warning (disable:4100) // C4100: unreference formal parameter
8 +#endif // _MSC_VER
9 +
10 +#include "cli.h"
11 +#include "engine/match.h"
12 +#include "ith/common/defs.h"
13 +//#include "ith/common/growl.h"
14 +#include "ith/sys/sys.h"
15 +#include "ccutil/ccmacro.h"
16 +
17 +//#include <ITH\AVL.h>
18 +//#include <ITH\ntdll.h>
19 +WCHAR mutex[] = ITH_GRANTPIPE_MUTEX;
20 +WCHAR exist[] = ITH_PIPEEXISTS_EVENT;
21 +WCHAR detach_mutex[0x20];
22 +//WCHAR write_event[0x20];
23 +//WCHAR engine_event[0x20];
24 +
25 +//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
26 +//WCHAR command[] = L"\\??\\pipe\\ITH_COMMAND";
27 +wchar_t recv_pipe[] = ITH_TEXT_PIPE;
28 +wchar_t command[] = ITH_COMMAND_PIPE;
29 +
30 +LARGE_INTEGER wait_time = {-100*10000, -1};
31 +LARGE_INTEGER sleep_time = {-20*10000, -1};
32 +
33 +DWORD engine_type;
34 +DWORD module_base;
35 +
36 +//DWORD engine_base;
37 +bool engine_registered; // 10/19/2014 jichi: disable engine dll
38 +
39 +HANDLE hPipe,
40 + hCommand,
41 + hDetach; //,hLose;
42 +//InsertHookFun InsertHook;
43 +//IdentifyEngineFun IdentifyEngine;
44 +//InsertDynamicHookFun InsertDynamicHook;
45 +
46 +bool hook_inserted = false;
47 +
48 +// jichi 9/28/2013: protect pipe on wine
49 +// Put the definition in this file so that it might be inlined
50 +void CliUnlockPipe()
51 +{
52 + if (IthIsWine())
53 + IthReleaseMutex(::hmMutex);
54 +}
55 +
56 +void CliLockPipe()
57 +{
58 + if (IthIsWine()) {
59 + const LONGLONG timeout = -50000000; // in nanoseconds = 5 seconds
60 + NtWaitForSingleObject(hmMutex, 0, (PLARGE_INTEGER)&timeout);
61 + }
62 +}
63 +
64 +HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction)
65 +{
66 + UNICODE_STRING us;
67 + RtlInitUnicodeString(&us,name);
68 + SECURITY_DESCRIPTOR sd = {1};
69 + OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
70 + HANDLE hFile;
71 + IO_STATUS_BLOCK isb;
72 + if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0)))
73 + return hFile;
74 + else
75 + return INVALID_HANDLE_VALUE;
76 +}
77 +
78 +DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter) // Dynamically detect ITH main module status.
79 +{
80 + CC_UNUSED(lpThreadParameter);
81 + int i;
82 + TextHook *man;
83 + struct {
84 + DWORD pid;
85 + TextHook *man;
86 + DWORD module;
87 + //DWORD engine;
88 + } u;
89 + HANDLE hMutex,
90 + hPipeExist;
91 + //swprintf(engine_event,L"ITH_ENGINE_%d",current_process_id);
92 + swprintf(detach_mutex, ITH_DETACH_MUTEX_ L"%d", current_process_id);
93 + //swprintf(lose_event,L"ITH_LOSEPIPE_%d",current_process_id);
94 + //hEngine=IthCreateEvent(engine_event);
95 + //NtWaitForSingleObject(hEngine,0,0);
96 + //NtClose(hEngine);
97 + while (!engine_registered)
98 + NtDelayExecution(0, &wait_time);
99 + //LoadEngine(L"ITH_Engine.dll");
100 + u.module = module_base;
101 + u.pid = current_process_id;
102 + u.man = hookman;
103 + //u.engine = engine_base; // jichi 10/19/2014: disable the second dll
104 + hPipeExist = IthOpenEvent(exist);
105 + IO_STATUS_BLOCK ios;
106 + //hLose=IthCreateEvent(lose_event,0,0);
107 + if (hPipeExist != INVALID_HANDLE_VALUE)
108 + while (running) {
109 + hPipe = INVALID_HANDLE_VALUE;
110 + hCommand = INVALID_HANDLE_VALUE;
111 + while (NtWaitForSingleObject(hPipeExist,0,&wait_time) == WAIT_TIMEOUT)
112 + if (!running)
113 + goto _release;
114 + hMutex = IthCreateMutex(mutex,0);
115 + NtWaitForSingleObject(hMutex,0,0);
116 + while (hPipe == INVALID_HANDLE_VALUE||
117 + hCommand == INVALID_HANDLE_VALUE) {
118 + NtDelayExecution(0, &sleep_time);
119 + if (hPipe == INVALID_HANDLE_VALUE)
120 + hPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE);
121 + if (hCommand == INVALID_HANDLE_VALUE)
122 + hCommand = IthOpenPipe(command, GENERIC_READ);
123 + }
124 + //NtClearEvent(hLose);
125 + CliLockPipe();
126 + NtWriteFile(hPipe, 0, 0, 0, &ios, &u, sizeof(u), 0, 0);
127 + CliUnlockPipe();
128 + live = true;
129 + for (man = hookman, i = 0; i < current_hook; man++)
130 + if (man->RecoverHook()) // jichi 9/27/2013: This is the place where built-in hooks like TextOutA are inserted
131 + i++;
132 + //ConsoleOutput(dll_name);
133 + ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
134 + //OutputDWORD(tree->Count());
135 + NtReleaseMutant(hMutex,0);
136 + NtClose(hMutex);
137 + if (!hook_inserted && engine_registered) {
138 + hook_inserted = true;
139 + Engine::IdentifyEngine();
140 + }
141 + hDetach = IthCreateMutex(detach_mutex,1);
142 + while (running && NtWaitForSingleObject(hPipeExist, 0, &sleep_time) == WAIT_OBJECT_0)
143 + NtDelayExecution(0, &sleep_time);
144 + live = false;
145 + for (man = hookman, i = 0; i < current_hook; man++)
146 + if (man->RemoveHook())
147 + i++;
148 + if (!running) {
149 + IthCoolDown(); // jichi 9/28/2013: Use cooldown instead of lock pipe to prevent from hanging on exit
150 + //CliLockPipe();
151 + NtWriteFile(hPipe, 0, 0, 0, &ios, man, 4, 0, 0);
152 + //CliUnlockPipe();
153 + IthReleaseMutex(hDetach);
154 + }
155 + NtClose(hDetach);
156 + NtClose(hPipe);
157 + }
158 +_release:
159 + //NtClose(hLose);
160 + NtClose(hPipeExist);
161 + return 0;
162 +}
163 +DWORD WINAPI CommandPipe(LPVOID lpThreadParameter)
164 +{
165 + CC_UNUSED(lpThreadParameter);
166 + DWORD command;
167 + BYTE buff[0x400] = {};
168 + HANDLE hPipeExist;
169 + hPipeExist = IthOpenEvent(exist);
170 + IO_STATUS_BLOCK ios={};
171 + if (hPipeExist!=INVALID_HANDLE_VALUE)
172 + while (running) {
173 + while (!live) {
174 + if (!running)
175 + goto _detach;
176 + NtDelayExecution(0, &sleep_time);
177 + }
178 + // jichi 9/27/2013: Why 0x200 not 0x400? wchar_t?
179 + switch (NtReadFile(hCommand, 0, 0, 0, &ios, buff, 0x200, 0, 0)) {
180 + case STATUS_PIPE_BROKEN:
181 + case STATUS_PIPE_DISCONNECTED:
182 + NtClearEvent(hPipeExist);
183 + continue;
184 + case STATUS_PENDING:
185 + NtWaitForSingleObject(hCommand, 0, 0);
186 + switch (ios.Status) {
187 + case STATUS_PIPE_BROKEN:
188 + case STATUS_PIPE_DISCONNECTED:
189 + NtClearEvent(hPipeExist);
190 + continue;
191 + case 0: break;
192 + default:
193 + if (NtWaitForSingleObject(hDetach, 0, &wait_time) == WAIT_OBJECT_0)
194 + goto _detach;
195 + }
196 + }
197 + if (ios.uInformation && live) {
198 + command = *(DWORD *)buff;
199 + switch(command) {
200 + case IHF_COMMAND_NEW_HOOK:
201 + //IthBreak();
202 + buff[ios.uInformation] = 0;
203 + buff[ios.uInformation + 1] = 0;
204 + NewHook(*(HookParam *)(buff + 4), (LPWSTR)(buff + 4 + sizeof(HookParam)), 0);
205 + break;
206 + case IHF_COMMAND_REMOVE_HOOK:
207 + {
208 + DWORD rm_addr = *(DWORD *)(buff+4);
209 + HANDLE hRemoved = IthOpenEvent(ITH_REMOVEHOOK_EVENT);
210 +
211 + TextHook *in = hookman;
212 + for (int i = 0; i < current_hook; in++) {
213 + if (in->Address()) i++;
214 + if (in->Address() == rm_addr) break;
215 + }
216 + if (in->Address())
217 + in->ClearHook();
218 + IthSetEvent(hRemoved);
219 + NtClose(hRemoved);
220 + } break;
221 + case IHF_COMMAND_MODIFY_HOOK:
222 + {
223 + DWORD rm_addr = *(DWORD *)(buff + 4);
224 + HANDLE hModify = IthOpenEvent(ITH_MODIFYHOOK_EVENT);
225 + TextHook *in = hookman;
226 + for (int i = 0; i < current_hook; in++) {
227 + if (in->Address())
228 + i++;
229 + if (in->Address() == rm_addr)
230 + break;
231 + }
232 + if (in->Address())
233 + in->ModifyHook(*(HookParam *)(buff + 4));
234 + IthSetEvent(hModify);
235 + NtClose(hModify);
236 + } break;
237 + case IHF_COMMAND_DETACH:
238 + running = false;
239 + live = false;
240 + goto _detach;
241 + default: ;
242 + }
243 + }
244 + }
245 +_detach:
246 + NtClose(hPipeExist);
247 + NtClose(hCommand);
248 + return 0;
249 +}
250 +//extern "C" {
251 +void IHFAPI ConsoleOutput(LPCSTR text)
252 +{ // jichi 12/25/2013: Rewrite the implementation
253 + if (!live || !text)
254 + return;
255 + enum { buf_size = 0x50 };
256 + BYTE buf[buf_size]; // buffer is needed to append the message header
257 + size_t text_size = strlen(text) + 1;
258 + size_t data_size = text_size + 8;
259 +
260 + BYTE *data = (data_size <= buf_size) ? buf : new BYTE[data_size];
261 + *(DWORD *)data = IHF_NOTIFICATION; //cmd
262 + *(DWORD *)(data + 4) = IHF_NOTIFICATION_TEXT; //console
263 + memcpy(data + 8, text, text_size);
264 +
265 + IO_STATUS_BLOCK ios;
266 + NtWriteFile(hPipe, 0, 0, 0, &ios, data, data_size, 0, 0);
267 + if (data != buf)
268 + delete[] data;
269 +}
270 + //if (str) {
271 + // int t, len, sum;
272 + // BYTE buffer[0x80];
273 + // BYTE *buff;
274 + // len = wcslen(str) << 1;
275 + // t = swprintf((LPWSTR)(buffer + 8),L"%d: ",current_process_id) << 1;
276 + // sum = len + t + 8;
277 + // if (sum > 0x80) {
278 + // buff = new BYTE[sum];
279 + // memset(buff, 0, sum); // jichi 9/25/2013: zero memory
280 + // memcpy(buff + 8, buffer + 8, t);
281 + // }
282 + // else
283 + // buff = buffer;
284 + // *(DWORD *)buff = IHF_NOTIFICATION; //cmd
285 + // *(DWORD *)(buff + 4) = IHF_NOTIFICATION_TEXT; //console
286 + // memcpy(buff + t + 8, str, len);
287 + // IO_STATUS_BLOCK ios;
288 + // NtWriteFile(hPipe,0,0,0,&ios,buff,sum,0,0);
289 + // if (buff != buffer)
290 + // delete[] buff;
291 + // return len;
292 + //}
293 +
294 +//DWORD IHFAPI OutputDWORD(DWORD d)
295 +//{
296 +// WCHAR str[0x10];
297 +// swprintf(str,L"%.8X",d);
298 +// ConsoleOutput(str);
299 +// return 0;
300 +//}
301 +//DWORD IHFAPI OutputRegister(DWORD *base)
302 +//{
303 +// WCHAR str[0x40];
304 +// swprintf(str,L"EAX:%.8X",base[0]);
305 +// ConsoleOutput(str);
306 +// swprintf(str,L"ECX:%.8X",base[-1]);
307 +// ConsoleOutput(str);
308 +// swprintf(str,L"EDX:%.8X",base[-2]);
309 +// ConsoleOutput(str);
310 +// swprintf(str,L"EBX:%.8X",base[-3]);
311 +// ConsoleOutput(str);
312 +// swprintf(str,L"ESP:%.8X",base[-4]);
313 +// ConsoleOutput(str);
314 +// swprintf(str,L"EBP:%.8X",base[-5]);
315 +// ConsoleOutput(str);
316 +// swprintf(str,L"ESI:%.8X",base[-6]);
317 +// ConsoleOutput(str);
318 +// swprintf(str,L"EDI:%.8X",base[-7]);
319 +// ConsoleOutput(str);
320 +// return 0;
321 +//}
322 +//DWORD IHFAPI RegisterEngineModule(DWORD idEngine, DWORD dnHook)
323 +//{
324 +// ::IdentifyEngine = (IdentifyEngineFun)idEngine;
325 +// ::InsertDynamicHook = (InsertDynamicHookFun)dnHook;
326 +// ::engine_registered = true;
327 +// return 0;
328 +//}
329 +DWORD IHFAPI NotifyHookInsert(DWORD addr)
330 +{
331 + if (live) {
332 + BYTE buffer[0x10];
333 + *(DWORD *)buffer = IHF_NOTIFICATION;
334 + *(DWORD *)(buffer + 4) = IHF_NOTIFICATION_NEWHOOK;
335 + *(DWORD *)(buffer + 8) = addr;
336 + *(DWORD *)(buffer + 0xc) = 0;
337 + IO_STATUS_BLOCK ios;
338 + CliLockPipe();
339 + NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0);
340 + CliUnlockPipe();
341 + }
342 + return 0;
343 +}
344 +//} // extern "C"
345 +
346 +// EOF
1 +#pragma once
2 +
3 +// avl.h
4 +// 8/23/2013 jichi
5 +// Branch: ITH/AVL.h, rev 133
6 +// 8/24/2013 TODO: Clean up this file
7 +
8 +#include "config.h"
9 +
10 +enum { STACK_SIZE = 32 };
11 +
12 +//#ifndef ITH_STACK
13 +//#define ITH_STACK
14 +
15 +template<class T, int stack_size>
16 +class MyStack
17 +{
18 + int index;
19 + T s[stack_size];
20 +
21 +public:
22 + MyStack(): index(0)
23 + { ITH_MEMSET_HEAP(s, 0, sizeof(s)); } // jichi 9/21/2013: assume T is atomic type
24 +
25 + T &back() { return s[index-1]; }
26 + int size() { return index; }
27 +
28 + void push_back(const T &e)
29 + {
30 + if (index < stack_size)
31 + s[index++]=e;
32 + }
33 +
34 + void pop_back() { index--; }
35 +
36 + T &operator[](int i) { return s[i]; }
37 +};
38 +//#endif // ITH_STACK
39 +
40 +// jichi 9/22/2013: T must be a pointer type which can be deleted
41 +template <class T, class D>
42 +struct TreeNode
43 +{
44 + //typedef TreeNode<T, D> Self;
45 + TreeNode() :
46 + Left(nullptr), Right(nullptr), Parent(nullptr)
47 + , rank(1)
48 + , factor('\0'), reserve('\0')
49 + //, key()
50 + //, data()
51 + {
52 + ITH_MEMSET_HEAP(&key, 0, sizeof(key)); // jichi 9/26/2013: zero memory
53 + ITH_MEMSET_HEAP(&data, 0, sizeof(data)); // jichi 9/26/2013: zero memory
54 + }
55 +
56 + TreeNode(const T &k, const D &d) :
57 + Left(nullptr), Right(nullptr), Parent(nullptr)
58 + , rank(1)
59 + , factor('\0'), reserve('\0') // jichi 9/21/2013: zero reserve
60 + , key(k)
61 + , data(d)
62 + {}
63 +
64 + TreeNode *Successor()
65 + {
66 + TreeNode *Node,
67 + *ParentNode;
68 + Node = Right;
69 + if (!Node) {
70 + Node = this;
71 + for (;;) {
72 + ParentNode = Node->Parent;
73 + if (!ParentNode)
74 + return nullptr;
75 + if (ParentNode->Left == Node)
76 + break;
77 + Node = ParentNode;
78 + }
79 + return ParentNode;
80 + }
81 + else
82 + while (Node->Left)
83 + Node = Node->Left;
84 + return Node;
85 + }
86 + TreeNode *Predecessor()
87 + {
88 + TreeNode *Node,
89 + *ParentNode;
90 + Node = Left;
91 + if (!Node) {
92 + Node = this;
93 + for(;;) {
94 + ParentNode = Node->Parent;
95 + if (!ParentNode)
96 + return nullptr;
97 + if (ParentNode->Right == Node)
98 + break;
99 + Node = ParentNode;
100 + }
101 + return ParentNode;
102 + }
103 + else
104 + while (Node->Right)
105 + Node = Node->Right;
106 + return Node;
107 + }
108 + int height()
109 + {
110 + if (!this) // jichi 9/26/2013: what?!
111 + return 0;
112 + int l = Left->height(),
113 + r = Right->height(),
114 + f = factor;
115 + if (l - r + f != 0)
116 + __debugbreak();
117 + f = l > r ? l : r;
118 + return f + 1;
119 + }
120 + TreeNode *Left,
121 + *Right,
122 + *Parent;
123 + unsigned short rank;
124 + char factor,
125 + reserve;
126 + T key;
127 + D data;
128 +};
129 +
130 +template<class T,class D>
131 +struct NodePath
132 +{
133 + NodePath() { memset(this, 0, sizeof(NodePath)); } // jichi 11/30/2013: This is the original code in ITH
134 + NodePath(TreeNode<T,D> *n, int f): Node(n), fact(f) {}
135 + TreeNode<T,D> *Node;
136 + union { char factor; int fact; };
137 +};
138 +
139 +template <class T, class D, class fComp, class fCopy, class fLength>
140 +class AVLTree
141 +{
142 + fComp fCmp;
143 + fCopy fCpy;
144 + fLength fLen;
145 +
146 +protected:
147 + TreeNode<T*, D> head;
148 +
149 +public:
150 + // - Construction -
151 + AVLTree() {}
152 +
153 + virtual ~AVLTree() { DeleteAll(); }
154 +
155 + // - Properties -
156 +
157 + TreeNode<T*, D> *TreeRoot() const { return head.Left; }
158 +
159 + // - Actions -
160 +
161 + void DeleteAll()
162 + {
163 + while (head.Left)
164 + DeleteRoot();
165 + }
166 +
167 + TreeNode<T*, D> *Insert(const T *key, const D &data)
168 + {
169 + if (head.Left) {
170 + MyStack<TreeNode<T*, D> *,STACK_SIZE> path;
171 + TreeNode<T*,D> *DownNode, *ParentNode, *BalanceNode, *TryNode, *NewNode; //P,T,S,Q
172 + ParentNode = &head;
173 + path.push_back(ParentNode);
174 + char factor,f;
175 + BalanceNode = DownNode = head.Left;
176 + for (;;) { //The first part of AVL tree insert. Just do as binary tree insert routine and record some nodes.
177 + factor = fCmp(key,DownNode->key);
178 + if (factor == 0)
179 + return DownNode; //Duplicate key. Return and do nothing.
180 + TryNode = _FactorLink(DownNode, factor);
181 + if (factor == -1)
182 + path.push_back(DownNode);
183 + if (TryNode) { //DownNode has a child.
184 + if (TryNode->factor != 0) { //Keep track of unbalance node and its parent.
185 + ParentNode = DownNode;
186 + BalanceNode = TryNode;
187 + }
188 + DownNode = TryNode;
189 + }
190 + else
191 + break; //Finished binary tree search;
192 + }
193 + while (path.size()) {
194 + path.back()->rank++;
195 + path.pop_back();
196 + }
197 + size_t sz = fLen(key) + 1;
198 + T *new_key = new T[sz];
199 + ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
200 + fCpy(new_key, key);
201 + TryNode = new TreeNode<T*, D>(new_key, data);
202 + _FactorLink(DownNode, factor) = TryNode;
203 + TryNode->Parent = DownNode;
204 + NewNode = TryNode;
205 + //Finished binary tree insert. Next to do is to modify balance factors between
206 + //BalanceNode and the new node.
207 + TreeNode<T*, D> *ModifyNode;
208 + factor = fCmp(key, BalanceNode->key);
209 + //factor=key<BalanceNode->key ? factor=-1:1; //Determine the balance factor at BalanceNode.
210 + ModifyNode = DownNode = _FactorLink(BalanceNode,factor);
211 + //ModifyNode will be the 1st child.
212 + //DownNode will travel from here to the recent inserted node (TryNode).
213 + while (DownNode != TryNode) { //Check if we reach the bottom.
214 + f = fCmp(key,DownNode->key);
215 + //f=_FactorCompare(key,DownNode->key);
216 + DownNode->factor = f;
217 + DownNode = _FactorLink(DownNode, f);//Modify balance factor and travels down.
218 + }
219 + //Finshed modifying balance factor.
220 + //Next to do is check the tree if it's unbalance and recover balance.
221 + if (BalanceNode->factor == 0) { //Tree has grown higher.
222 + BalanceNode->factor = factor;
223 + _IncreaseHeight(); //Modify balance factor and increase the height.
224 + return NewNode;
225 + }
226 + if (BalanceNode->factor + factor == 0) { //Tree has gotten more balanced.
227 + BalanceNode->factor = 0; //Set balance factor to 0.
228 + return NewNode;
229 + }
230 + //Tree has gotten out of balance.
231 + if (ModifyNode->factor == factor) //A node and its child has same factor. Single rotation.
232 + DownNode = _SingleRotation(BalanceNode, ModifyNode, factor);
233 + else //A node and its child has converse factor. Double rotation.
234 + DownNode = _DoubleRotation(BalanceNode, ModifyNode, factor);
235 + //Finished the balancing work. Set child field to the root of the new child tree.
236 + if (BalanceNode == ParentNode->Left)
237 + ParentNode->Left = DownNode;
238 + else
239 + ParentNode->Right = DownNode;
240 + return NewNode;
241 + }
242 + else { //root null?
243 + size_t sz = fLen(key) + 1;
244 + T *new_key = new T[sz];
245 + ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
246 + fCpy(new_key, key);
247 + head.Left = new TreeNode<T *, D>(new_key, data);
248 + head.rank++;
249 + _IncreaseHeight();
250 + return head.Left;
251 + }
252 + }
253 + bool Delete(T *key)
254 + {
255 + NodePath<T*,D> PathNode;
256 + MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
257 + path.push_back(NodePath<T*,D>(&head,-1));
258 + TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
259 + TryNode=head.Left;
260 + char factor;
261 + for (;;) { //Search for the
262 + if (TryNode == 0)
263 + return false; //Not found.
264 + factor = fCmp(key, TryNode->key);
265 + if (factor == 0)
266 + break; //Key found, continue to delete.
267 + //factor = _FactorCompare( key, TryNode->key );
268 + path.push_back(NodePath<T*,D>(TryNode,factor));
269 + TryNode = _FactorLink(TryNode,factor); //Move to left.
270 + }
271 + SuccNode = TryNode->Right; //Find a successor.
272 + factor = 1;
273 + if (SuccNode == 0) {
274 + SuccNode = TryNode->Left;
275 + factor = -1;
276 + }
277 + path.push_back(NodePath<T*,D>(TryNode,factor));
278 + while (SuccNode) {
279 + path.push_back(NodePath<T*,D>(SuccNode, -factor));
280 + SuccNode = _FactorLink(SuccNode,-factor);
281 + }
282 + PathNode = path.back();
283 + delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
284 + TryNode->key = PathNode.Node->key; //Replace key and data field with the successor or predecessor.
285 + PathNode.Node->key = nullptr;
286 + TryNode->data = PathNode.Node->data;
287 + path.pop_back();
288 + _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
289 + delete PathNode.Node; //Remove the successor from the tree and release memory.
290 + PathNode = path.back();
291 + for (int i=0; i<path.size(); i++)
292 + if (path[i].factor==-1)
293 + path[i].Node->rank--;
294 + for (;;) { //Rebalance the tree along the path back to the root.
295 + if (path.size()==1) {
296 + _DecreaseHeight();
297 + break;
298 + }
299 + BalanceNode = PathNode.Node;
300 + if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurve since subtree height stays.
301 + BalanceNode->factor=-PathNode.factor;
302 + break;
303 + }
304 + if (BalanceNode->factor == PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurve.
305 + BalanceNode->factor = 0;
306 + path.pop_back();
307 + PathNode = path.back();
308 + continue;
309 + }
310 + //Node get out of balance. Here raises 3 cases.
311 + ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
312 + if (ChildNode->factor == 0) { // New case different to insert operation.
313 + TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
314 + path.pop_back();
315 + PathNode = path.back();
316 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
317 + break;
318 + }
319 + else {
320 + if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
321 + TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
322 + else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
323 + TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
324 + }
325 + path.pop_back(); //Recurse back along the path.
326 + PathNode = path.back();
327 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
328 + }
329 + return true;
330 + }
331 +
332 + D &operator [](T *key)
333 + { return (Insert(key,D())->data); }
334 +
335 + TreeNode<T*,D> *Search(const T *key)
336 + {
337 + TreeNode<T*,D> *Find=head.Left;
338 + char k;
339 + while (Find != 0) {//&&Find->key!=key)
340 + k=fCmp(key, Find->key);
341 + if (k==0) break;
342 + Find = _FactorLink(Find, k);
343 + }
344 + return Find;
345 + }
346 +
347 + TreeNode<T*,D> *SearchIndex(unsigned int rank)
348 + {
349 + unsigned int r = head.rank;
350 + if (rank == -1)
351 + return 0;
352 + if (++rank>=r)
353 + return 0;
354 + TreeNode<T*,D> *n=&head;
355 + while (r!=rank) {
356 + if (rank>r) {
357 + n=n->Right;
358 + rank-=r;
359 + r=n->rank;
360 + } else {
361 + n=n->Left;
362 + r=n->rank;
363 + }
364 + }
365 + return n;
366 + }
367 +
368 + TreeNode<T*,D> *Begin()
369 + {
370 + TreeNode<T*,D> *Node = head.Left;
371 + if (Node)
372 + while (Node->Left) Node = Node->Left;
373 + return Node;
374 + }
375 +
376 + TreeNode<T*,D> *End()
377 + {
378 + TreeNode<T*,D> *Node=head.Left;
379 + if (Node)
380 + while (Node->Right) Node = Node->Right;
381 + return Node;
382 + }
383 + unsigned int Count() const { return head.rank - 1; }
384 +
385 + template <class Fn>
386 + Fn TraverseTree(Fn &f)
387 + { return TraverseTreeNode(head.Left,f); }
388 +
389 +protected:
390 + bool DeleteRoot()
391 + {
392 + NodePath<T*,D> PathNode;
393 + MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
394 + path.push_back(NodePath<T*,D>(&head,-1));
395 + TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
396 + TryNode=head.Left;
397 + char factor;
398 + SuccNode=TryNode->Right; //Find a successor.
399 + factor=1;
400 + if (SuccNode==0)
401 + {
402 + SuccNode=TryNode->Left;
403 + factor=-1;
404 + }
405 + path.push_back(NodePath<T*,D>(TryNode,factor));
406 + while (SuccNode) {
407 + path.push_back(NodePath<T*,D>(SuccNode,-factor));
408 + SuccNode=_FactorLink(SuccNode,-factor);
409 + }
410 + PathNode=path.back();
411 + delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
412 + TryNode->key=PathNode.Node->key; //Replace key and data field with the successor.
413 + PathNode.Node->key = nullptr;
414 + TryNode->data=PathNode.Node->data;
415 + path.pop_back();
416 + _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
417 + delete PathNode.Node; //Remove the successor from the tree and release memory.
418 + PathNode=path.back();
419 + for (int i=0;i<path.size();i++)
420 + if (path[i].factor==-1)
421 + path[i].Node->rank--;
422 + for (;;) { //Rebalance the tree along the path back to the root.
423 + if (path.size() == 1) {
424 + _DecreaseHeight();
425 + break;
426 + }
427 +
428 + BalanceNode = PathNode.Node;
429 + if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurse since subtree height not changed.
430 + BalanceNode->factor=-PathNode.factor;
431 + break;
432 + }
433 + if (BalanceNode->factor==PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurse.
434 + BalanceNode->factor=0;
435 + path.pop_back();
436 + PathNode=path.back();
437 + continue;
438 + }
439 + //Node get out of balance. Here raises 3 cases.
440 + ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
441 + if (ChildNode->factor == 0) { // New case different to insert operation.
442 + TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
443 + path.pop_back();
444 + PathNode=path.back();
445 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
446 + break;
447 + } else {
448 + if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
449 + TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
450 + else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
451 + TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
452 + }
453 + path.pop_back(); // Recurve back along the path.
454 + PathNode=path.back();
455 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
456 + }
457 + return true;
458 + }
459 + template <class Fn>
460 + Fn TraverseTreeNode(TreeNode<T*,D> *Node, Fn &f)
461 + {
462 + if (Node) {
463 + if (Node->Left)
464 + TraverseTreeNode(Node->Left,f);
465 + f(Node);
466 + if (Node->Right)
467 + TraverseTreeNode(Node->Right,f);
468 + }
469 + return f;
470 + }
471 + TreeNode<T*,D> *_SingleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
472 + {
473 + TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
474 + _FactorLink(BalanceNode, factor) = Node;
475 + _FactorLink(ModifyNode, -factor) = BalanceNode;
476 + if (Node)
477 + Node->Parent = BalanceNode;
478 + ModifyNode->Parent = BalanceNode->Parent;
479 + BalanceNode->Parent = ModifyNode;
480 + BalanceNode->factor = ModifyNode->factor = 0; //After single rotation, set all factor of 3 node to 0.
481 + if (factor == 1)
482 + ModifyNode->rank += BalanceNode->rank;
483 + else
484 + BalanceNode->rank -= ModifyNode->rank;
485 + return ModifyNode;
486 + }
487 + TreeNode<T*,D> *_SingleRotation2(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
488 + {
489 + TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
490 + _FactorLink(BalanceNode, factor) = Node;
491 + _FactorLink(ModifyNode, -factor) = BalanceNode;
492 + if (Node) Node->Parent = BalanceNode;
493 + ModifyNode->Parent = BalanceNode->Parent;
494 + BalanceNode->Parent = ModifyNode;
495 + ModifyNode->factor = -factor;
496 + if (factor == 1)
497 + ModifyNode->rank+=BalanceNode->rank;
498 + else
499 + BalanceNode->rank-=ModifyNode->rank;
500 + return ModifyNode;
501 + }
502 + TreeNode<T*,D> *_DoubleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
503 + {
504 + TreeNode<T*,D> *DownNode = _FactorLink(ModifyNode, -factor);
505 + TreeNode<T*,D> *Node1, *Node2;
506 + Node1 = _FactorLink(DownNode, factor);
507 + Node2 = _FactorLink(DownNode, -factor);
508 + _FactorLink(ModifyNode, -factor) = Node1;
509 + _FactorLink(DownNode, factor) = ModifyNode;
510 + _FactorLink(BalanceNode, factor) = Node2;
511 + _FactorLink(DownNode, -factor) = BalanceNode;
512 + if (Node1)
513 + Node1->Parent = ModifyNode;
514 + if (Node2)
515 + Node2->Parent = BalanceNode;
516 + DownNode->Parent = BalanceNode->Parent;
517 + BalanceNode->Parent = DownNode;
518 + ModifyNode->Parent = DownNode;
519 + //Set factor according to the result.
520 + if (DownNode->factor == factor) {
521 + BalanceNode->factor = -factor;
522 + ModifyNode->factor = 0;
523 + } else if (DownNode->factor == 0)
524 + BalanceNode->factor = ModifyNode->factor = 0;
525 + else {
526 + BalanceNode->factor = 0;
527 + ModifyNode->factor = factor;
528 + }
529 + DownNode->factor = 0;
530 + if (factor==1) {
531 + ModifyNode->rank -= DownNode->rank;
532 + DownNode->rank += BalanceNode->rank;
533 + } else {
534 + DownNode->rank += ModifyNode->rank;
535 + BalanceNode->rank -= DownNode->rank;
536 + }
537 + return DownNode;
538 + }
539 +
540 + TreeNode<T*,D>* &__fastcall _FactorLink(TreeNode<T*,D> *Node, char factor)
541 + //Private helper method to retrieve child according to factor.
542 + //Return right child if factor>0 and left child otherwise.
543 + { return factor>0? Node->Right : Node->Left; }
544 +
545 + void Check()
546 + {
547 + unsigned int k = (unsigned int)head.Right;
548 + unsigned int t = head.Left->height();
549 + if (k != t)
550 + __debugbreak();
551 + }
552 +
553 + void _IncreaseHeight()
554 + {
555 + unsigned int k = (unsigned int)head.Right;
556 + head.Right = (TreeNode<T*,D>*)++k;
557 + }
558 +
559 + void _DecreaseHeight()
560 + {
561 + unsigned int k = (unsigned int)head.Right;
562 + head.Right = (TreeNode<T*,D>*)--k;
563 + }
564 +};
565 +
566 +struct SCMP
567 +{
568 + char operator()(const char *s1,const char *s2)
569 + {
570 + int t = _stricmp(s1, s2);
571 + return t == 0 ? 0 : t > 0 ? 1 :-1;
572 + }
573 +};
574 +
575 +struct SCPY { char *operator()(char *dest, const char *src) { return strcpy(dest, src); } };
576 +struct SLEN { int operator()(const char *str) { return strlen(str); } };
577 +
578 +struct WCMP
579 +{
580 + char operator()(const wchar_t *s1,const wchar_t *s2)
581 + {
582 + int t =_wcsicmp(s1, s2);
583 + return t == 0 ? 0 : t > 0 ? 1 : -1;
584 + }
585 +};
586 +
587 +struct WCPY { wchar_t *operator()(wchar_t *dest, const wchar_t *src) { return wcscpy(dest,src); } };
588 +struct WLEN { int operator()(const wchar_t *str) { return wcslen(str); } };
589 +
590 +// EOF
1 +# hookxp.pro
2 +# 8/9/2013 jichi
3 +# Build vnrhookxp.dll for Windows XP
4 +
5 +CONFIG += noeh # msvcrt on Windows XP does not has exception handler
6 +include(../dllconfig.pri)
7 +include(../sys/sys.pri)
8 +include($$LIBDIR/disasm/disasm.pri)
9 +include($$LIBDIR/memdbg/memdbg.pri)
10 +include($$LIBDIR/ntinspect/ntinspect.pri)
11 +include($$LIBDIR/winseh/winseh_safe.pri)
12 +include($$LIBDIR/winversion/winversion.pri)
13 +
14 +VPATH += ../hook
15 +INCLUDEPATH += ../hook
16 +
17 +# 9/27/2013: disable ITH this game engine, only for debugging purpose
18 +#DEFINES += ITH_DISABLE_ENGINE
19 +
20 +
21 +# jichi 9/22/2013: When ITH is on wine, mutex is needed to protect NtWriteFile
22 +#DEFINES += ITH_WINE
23 +#DEFINES += ITH_SYNC_PIPE
24 +
25 +## Libraries
26 +
27 +LIBS += -lkernel32 -luser32 -lgdi32
28 +
29 +## Sources
30 +
31 +TEMPLATE = lib
32 +TARGET = vnrhookxp
33 +
34 +#CONFIG += staticlib
35 +
36 +HEADERS += \
37 + config.h \
38 + cli.h \
39 + hook.h \
40 + engine/engine.h \
41 + engine/hookdefs.h \
42 + engine/match.h \
43 + engine/pchooks.h \
44 + engine/util.h \
45 + tree/avl.h
46 +
47 +SOURCES += \
48 + main.cc \
49 + rpc/pipe.cc \
50 + hijack/texthook.cc \
51 + engine/engine.cc \
52 + engine/match.cc \
53 + engine/pchooks.cc \
54 + engine/util.cc
55 +
56 +#RC_FILE += vnrhook.rc
57 +#OTHER_FILES += vnrhook.rc
58 +
59 +# EOF
1 +# host.pro
2 +# #CONFIG += eha # 3/1/2014: catchlng all exceptions will break pytexthook on Windows XP
3 +# CONFIG += noeh # Needed by pytexthook ONLY on windows xp orz
4 +# include(../dllconfig.pri)
5 +# include(../sys/sys.pri)
6 +# include($$LIBDIR/winmaker/winmaker.pri)
7 +# include($$LIBDIR/winmutex/winmutex.pri)
8 +
9 +# config.pri
10 +# CONFIG(noeh) { # No Exception handler
11 +# message(CONFIG noeh)
12 +# QMAKE_CXXFLAGS += /GR-
13 +# QMAKE_CXXFLAGS_RTTI_ON -= /GR
14 +# QMAKE_CXXFLAGS_STL_ON -= /EHsc
15 +# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
16 +# CONFIG(dll) {
17 +# QMAKE_LFLAGS += /ENTRY:"DllMain"
18 +# }
19 +# }
20 +
21 +set(vnrhost_src
22 + avl_p.h
23 + config.h
24 + hookman.h
25 + settings.h
26 + srv.h
27 + srv_p.h
28 + textthread.h
29 + textthread_p.h
30 + SettingManager.h
31 + hookman.cc
32 + main.cc
33 + pipe.cc
34 + textthread.cc
35 + ${PROJECT_SOURCE_DIR}/winmaker/winmaker.h
36 + ${PROJECT_SOURCE_DIR}/winmaker/winmaker.cc
37 + ${PROJECT_SOURCE_DIR}/winmutex/winmutex.h
38 + ${common_src}
39 +)
40 +
41 +source_group("common" FILES ${common_src})
42 +
43 +add_library(vnrhost SHARED ${vnrhost_src})
44 +
45 +set_target_properties(vnrhost PROPERTIES LINK_FLAGS /SUBSYSTEM:WINDOWS)
46 +
47 +target_compile_options(vnrhost PRIVATE
48 + /GR-
49 + $<$<CONFIG:Release>:>
50 + $<$<CONFIG:Debug>:>
51 +)
52 +
53 +STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
54 +
55 +target_link_libraries(vnrhost
56 + vnrsys
57 + ${WDK_HOME}/lib/wxp/i386/ntdll.lib
58 +)
59 +
60 +target_compile_definitions(vnrhost PRIVATE
61 +)
62 +
63 +install(TARGETS vnrhost RUNTIME
64 + DESTINATION .
65 + CONFIGURATIONS Release
66 +)
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +
18 +#pragma once
19 +#include "config.h"
20 +#include <intrin.h>
21 +#define SETTING_SPLIT_TIME 0
22 +#define SETTING_CYCLIC_REMOVE 1
23 +#define SETTING_REPEAT_COUNT 2
24 +#define SETTING_CLIPFLAG 3
25 +#define SETTING_MAX_INDEX 4
26 +class IHFSERVICE SettingManager
27 +{
28 +public:
29 + SettingManager() {memset(setting_int,0,sizeof(setting_int));}
30 + ~SettingManager(){}
31 + unsigned int SetValue(unsigned int index, unsigned int value)
32 + {
33 + if (index < SETTING_MAX_INDEX)
34 + return (unsigned int)_InterlockedExchange((long*)setting_int+index,(long)value);
35 + else return 0;
36 + }
37 + unsigned int GetValue(unsigned int index)
38 + {
39 + if (index < SETTING_MAX_INDEX)
40 + return setting_int[index];
41 + else return 0;
42 + }
43 +private:
44 + unsigned int setting_int[SETTING_MAX_INDEX];
45 +
46 +};
...\ No newline at end of file ...\ No newline at end of file
1 +#pragma once
2 +// avl_p.h
3 +// 8/23/2013 jichi
4 +// Branch: ITH/AVL.h, rev 133
5 +
6 +#include "config.h"
7 +
8 +enum { STACK_SIZE = 32 };
9 +
10 +//#ifndef ITH_STACK
11 +//#define ITH_STACK
12 +
13 +template<class T, int stack_size>
14 +class MyStack
15 +{
16 + int index;
17 + T s[stack_size];
18 +
19 +public:
20 + MyStack(): index(0)
21 + { ITH_MEMSET_HEAP(s, 0, sizeof(s)); } // jichi 9/21/2013: assume T is atomic type
22 +
23 + T &back() { return s[index-1]; }
24 + int size() { return index; }
25 +
26 + void push_back(const T &e)
27 + {
28 + if (index < stack_size)
29 + s[index++]=e;
30 + }
31 +
32 + void pop_back() { index--; }
33 +
34 + T &operator[](int i) { return s[i]; }
35 +};
36 +//#endif // ITH_STACK
37 +
38 +// jichi 9/22/2013: T must be a pointer type which can be deleted
39 +template <class T, class D>
40 +struct IHFSERVICE TreeNode
41 +{
42 + //typedef TreeNode<T, D> Self;
43 + TreeNode() :
44 + Left(nullptr), Right(nullptr), Parent(nullptr)
45 + , rank(1)
46 + , factor('\0'), reserve('\0')
47 + //, key()
48 + //, data()
49 + {
50 + ITH_MEMSET_HEAP(&key, 0, sizeof(key)); // jcihi 9/26/2013: zero memory
51 + ITH_MEMSET_HEAP(&data, 0, sizeof(data)); // jcihi 9/26/2013: zero memory
52 + }
53 +
54 + TreeNode(const T &k, const D &d) :
55 + Left(nullptr), Right(nullptr), Parent(nullptr)
56 + , rank(1)
57 + , factor('\0'), reserve('\0') // jichi 9/21/2013: zero reserve
58 + , key(k)
59 + , data(d)
60 + {}
61 +
62 + TreeNode *Successor()
63 + {
64 + TreeNode *Node,
65 + *ParentNode;
66 + Node = Right;
67 + if (!Node) {
68 + Node = this;
69 + for (;;) {
70 + ParentNode = Node->Parent;
71 + if (!ParentNode)
72 + return nullptr;
73 + if (ParentNode->Left == Node)
74 + break;
75 + Node = ParentNode;
76 + }
77 + return ParentNode;
78 + }
79 + else
80 + while (Node->Left)
81 + Node = Node->Left;
82 + return Node;
83 + }
84 + TreeNode *Predecessor()
85 + {
86 + TreeNode *Node,
87 + *ParentNode;
88 + Node = Left;
89 + if (!Node) {
90 + Node = this;
91 + for(;;) {
92 + ParentNode = Node->Parent;
93 + if (!ParentNode)
94 + return nullptr;
95 + if (ParentNode->Right == Node)
96 + break;
97 + Node = ParentNode;
98 + }
99 + return ParentNode;
100 + }
101 + else
102 + while (Node->Right)
103 + Node = Node->Right;
104 + return Node;
105 + }
106 + int height()
107 + {
108 + if (!this) // jichi 9/26/2013: what?!
109 + return 0;
110 + int l = Left->height(),
111 + r = Right->height(),
112 + f = factor;
113 + if (l - r + f != 0)
114 + __debugbreak();
115 + f = l > r ? l : r;
116 + return f + 1;
117 + }
118 + TreeNode *Left,
119 + *Right,
120 + *Parent;
121 + unsigned short rank;
122 + char factor,
123 + reserve;
124 + T key;
125 + D data;
126 +};
127 +
128 +template<class T,class D>
129 +struct NodePath
130 +{
131 + NodePath() { memset(this, 0, sizeof(NodePath)); } // jichi 11/30/2013: This is the original code in ITH
132 + NodePath(TreeNode<T,D> *n, int f): Node(n), fact(f) {}
133 + TreeNode<T,D> *Node;
134 + union { char factor; int fact; };
135 +};
136 +
137 +template <class T, class D, class fComp, class fCopy, class fLength>
138 +class IHFSERVICE AVLTree
139 +{
140 +protected:
141 + TreeNode<T*, D> head;
142 + fComp fCmp;
143 + fCopy fCpy;
144 + fLength fLen;
145 +
146 +public:
147 + // - Construction -
148 + AVLTree() {}
149 +
150 + virtual ~AVLTree() { DeleteAll(); }
151 +
152 + // - Properties -
153 +
154 + TreeNode<T*, D> *TreeRoot() const { return head.Left; }
155 +
156 + // - Actions -
157 +
158 + void DeleteAll()
159 + {
160 + while (head.Left)
161 + DeleteRoot();
162 + }
163 +
164 + TreeNode<T*, D> *Insert(const T *key, const D &data)
165 + {
166 + if (head.Left) {
167 + MyStack<TreeNode<T*, D> *,STACK_SIZE> path;
168 + TreeNode<T*,D> *DownNode, *ParentNode, *BalanceNode, *TryNode, *NewNode; //P,T,S,Q
169 + ParentNode = &head;
170 + path.push_back(ParentNode);
171 + char factor,f;
172 + BalanceNode = DownNode = head.Left;
173 + for (;;) { //The first part of AVL tree insert. Just do as binary tree insert routine and record some nodes.
174 + factor = fCmp(key,DownNode->key);
175 + if (factor == 0)
176 + return DownNode; //Duplicate key. Return and do nothing.
177 + TryNode = _FactorLink(DownNode, factor);
178 + if (factor == -1)
179 + path.push_back(DownNode);
180 + if (TryNode) { //DownNode has a child.
181 + if (TryNode->factor != 0) { //Keep track of unbalance node and its parent.
182 + ParentNode = DownNode;
183 + BalanceNode = TryNode;
184 + }
185 + DownNode = TryNode;
186 + }
187 + else
188 + break; //Finished binary tree search;
189 + }
190 + while (path.size()) {
191 + path.back()->rank++;
192 + path.pop_back();
193 + }
194 + size_t sz = fLen(key) + 1;
195 + T *new_key = new T[sz];
196 + ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
197 + fCpy(new_key, key);
198 + TryNode = new TreeNode<T*, D>(new_key, data);
199 + _FactorLink(DownNode, factor) = TryNode;
200 + TryNode->Parent = DownNode;
201 + NewNode = TryNode;
202 + //Finished binary tree insert. Next to do is to modify balance factors between
203 + //BalanceNode and the new node.
204 + TreeNode<T*, D> *ModifyNode;
205 + factor = fCmp(key, BalanceNode->key);
206 + //factor=key<BalanceNode->key ? factor=-1:1; //Determine the balance factor at BalanceNode.
207 + ModifyNode = DownNode = _FactorLink(BalanceNode,factor);
208 + //ModifyNode will be the 1st child.
209 + //DownNode will travel from here to the recent inserted node (TryNode).
210 + while (DownNode != TryNode) { //Check if we reach the bottom.
211 + f = fCmp(key,DownNode->key);
212 + //f=_FactorCompare(key,DownNode->key);
213 + DownNode->factor = f;
214 + DownNode = _FactorLink(DownNode, f);//Modify balance factor and travels down.
215 + }
216 + //Finshed modifying balance factor.
217 + //Next to do is check the tree if it's unbalance and recover balance.
218 + if (BalanceNode->factor == 0) { //Tree has grown higher.
219 + BalanceNode->factor = factor;
220 + _IncreaseHeight(); //Modify balance factor and increase the height.
221 + return NewNode;
222 + }
223 + if (BalanceNode->factor + factor == 0) { //Tree has gotten more balanced.
224 + BalanceNode->factor = 0; //Set balance factor to 0.
225 + return NewNode;
226 + }
227 + //Tree has gotten out of balance.
228 + if (ModifyNode->factor == factor) //A node and its child has same factor. Single rotation.
229 + DownNode = _SingleRotation(BalanceNode, ModifyNode, factor);
230 + else //A node and its child has converse factor. Double rotation.
231 + DownNode = _DoubleRotation(BalanceNode, ModifyNode, factor);
232 + //Finished the balancing work. Set child field to the root of the new child tree.
233 + if (BalanceNode == ParentNode->Left)
234 + ParentNode->Left = DownNode;
235 + else
236 + ParentNode->Right = DownNode;
237 + return NewNode;
238 + }
239 + else { //root null?
240 + size_t sz = fLen(key) + 1;
241 + T *new_key = new T[sz];
242 + ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
243 + fCpy(new_key, key);
244 + head.Left = new TreeNode<T *, D>(new_key, data);
245 + head.rank++;
246 + _IncreaseHeight();
247 + return head.Left;
248 + }
249 + }
250 + bool Delete(T *key)
251 + {
252 + NodePath<T*,D> PathNode;
253 + MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
254 + path.push_back(NodePath<T*,D>(&head,-1));
255 + TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
256 + TryNode=head.Left;
257 + char factor;
258 + for (;;) { //Search for the
259 + if (TryNode == 0)
260 + return false; //Not found.
261 + factor = fCmp(key, TryNode->key);
262 + if (factor == 0)
263 + break; //Key found, continue to delete.
264 + //factor = _FactorCompare( key, TryNode->key );
265 + path.push_back(NodePath<T*,D>(TryNode,factor));
266 + TryNode = _FactorLink(TryNode,factor); //Move to left.
267 + }
268 + SuccNode = TryNode->Right; //Find a successor.
269 + factor = 1;
270 + if (SuccNode == 0) {
271 + SuccNode = TryNode->Left;
272 + factor = -1;
273 + }
274 + path.push_back(NodePath<T*,D>(TryNode,factor));
275 + while (SuccNode) {
276 + path.push_back(NodePath<T*,D>(SuccNode, -factor));
277 + SuccNode = _FactorLink(SuccNode,-factor);
278 + }
279 + PathNode = path.back();
280 + delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
281 + TryNode->key = PathNode.Node->key; //Replace key and data field with the successor or predecessor.
282 + PathNode.Node->key = nullptr;
283 + TryNode->data = PathNode.Node->data;
284 + path.pop_back();
285 + _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
286 + delete PathNode.Node; //Remove the successor from the tree and release memory.
287 + PathNode = path.back();
288 + for (int i=0; i<path.size(); i++)
289 + if (path[i].factor==-1)
290 + path[i].Node->rank--;
291 + for (;;) { //Rebalance the tree along the path back to the root.
292 + if (path.size()==1) {
293 + _DecreaseHeight();
294 + break;
295 + }
296 + BalanceNode = PathNode.Node;
297 + if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurve since subtree height stays.
298 + BalanceNode->factor=-PathNode.factor;
299 + break;
300 + }
301 + if (BalanceNode->factor == PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurve.
302 + BalanceNode->factor = 0;
303 + path.pop_back();
304 + PathNode = path.back();
305 + continue;
306 + }
307 + //Node get out of balance. Here raises 3 cases.
308 + ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
309 + if (ChildNode->factor == 0) { // New case different to insert operation.
310 + TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
311 + path.pop_back();
312 + PathNode = path.back();
313 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
314 + break;
315 + }
316 + else {
317 + if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
318 + TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
319 + else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
320 + TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
321 + }
322 + path.pop_back(); //Recurse back along the path.
323 + PathNode = path.back();
324 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
325 + }
326 + return true;
327 + }
328 +
329 + D &operator [](T *key)
330 + { return (Insert(key,D())->data); }
331 +
332 + TreeNode<T*,D> *Search(const T *key)
333 + {
334 + TreeNode<T*,D> *Find=head.Left;
335 + char k;
336 + while (Find != 0) {//&&Find->key!=key)
337 + k = fCmp(key, Find->key);
338 + if (k == 0) break;
339 + Find = _FactorLink(Find, k);
340 + }
341 + return Find;
342 + }
343 +
344 + TreeNode<T*,D> *SearchIndex(unsigned int rank)
345 + {
346 + unsigned int r = head.rank;
347 + if (rank == -1)
348 + return 0;
349 + if (++rank>=r)
350 + return 0;
351 + TreeNode<T*,D> *n=&head;
352 + while (r!=rank) {
353 + if (rank>r) {
354 + n=n->Right;
355 + rank-=r;
356 + r=n->rank;
357 + } else {
358 + n=n->Left;
359 + r=n->rank;
360 + }
361 + }
362 + return n;
363 + }
364 +
365 + TreeNode<T*,D> *Begin()
366 + {
367 + TreeNode<T*,D> *Node = head.Left;
368 + if (Node)
369 + while (Node->Left) Node = Node->Left;
370 + return Node;
371 + }
372 +
373 + TreeNode<T*,D> *End()
374 + {
375 + TreeNode<T*,D> *Node=head.Left;
376 + if (Node)
377 + while (Node->Right) Node = Node->Right;
378 + return Node;
379 + }
380 + unsigned int Count() const { return head.rank - 1; }
381 +
382 + template <class Fn>
383 + Fn TraverseTree(Fn &f)
384 + { return TraverseTreeNode(head.Left,f); }
385 +
386 +protected:
387 + bool DeleteRoot()
388 + {
389 + NodePath<T*,D> PathNode;
390 + MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
391 + path.push_back(NodePath<T*,D>(&head,-1));
392 + TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
393 + TryNode=head.Left;
394 + char factor;
395 + SuccNode=TryNode->Right; //Find a successor.
396 + factor=1;
397 + if (SuccNode==0)
398 + {
399 + SuccNode=TryNode->Left;
400 + factor=-1;
401 + }
402 + path.push_back(NodePath<T*,D>(TryNode,factor));
403 + while (SuccNode) {
404 + path.push_back(NodePath<T*,D>(SuccNode,-factor));
405 + SuccNode=_FactorLink(SuccNode,-factor);
406 + }
407 + PathNode=path.back();
408 + delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
409 + TryNode->key=PathNode.Node->key; //Replace key and data field with the successor.
410 + PathNode.Node->key = nullptr;
411 + TryNode->data=PathNode.Node->data;
412 + path.pop_back();
413 + _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
414 + delete PathNode.Node; //Remove the successor from the tree and release memory.
415 + PathNode=path.back();
416 + for (int i=0;i<path.size();i++)
417 + if (path[i].factor==-1)
418 + path[i].Node->rank--;
419 + for (;;) { //Rebalance the tree along the path back to the root.
420 + if (path.size() == 1) {
421 + _DecreaseHeight();
422 + break;
423 + }
424 +
425 + BalanceNode = PathNode.Node;
426 + if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurse since subtree height not changed.
427 + BalanceNode->factor=-PathNode.factor;
428 + break;
429 + }
430 + if (BalanceNode->factor==PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurse.
431 + BalanceNode->factor=0;
432 + path.pop_back();
433 + PathNode=path.back();
434 + continue;
435 + }
436 + //Node get out of balance. Here raises 3 cases.
437 + ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
438 + if (ChildNode->factor == 0) { // New case different to insert operation.
439 + TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
440 + path.pop_back();
441 + PathNode=path.back();
442 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
443 + break;
444 + } else {
445 + if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
446 + TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
447 + else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
448 + TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
449 + }
450 + path.pop_back(); // Recurve back along the path.
451 + PathNode=path.back();
452 + _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
453 + }
454 + return true;
455 + }
456 + template <class Fn>
457 + Fn TraverseTreeNode(TreeNode<T*,D> *Node, Fn &f)
458 + {
459 + if (Node) {
460 + if (Node->Left)
461 + TraverseTreeNode(Node->Left,f);
462 + f(Node);
463 + if (Node->Right)
464 + TraverseTreeNode(Node->Right,f);
465 + }
466 + return f;
467 + }
468 + TreeNode<T*,D> *_SingleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
469 + {
470 + TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
471 + _FactorLink(BalanceNode, factor) = Node;
472 + _FactorLink(ModifyNode, -factor) = BalanceNode;
473 + if (Node)
474 + Node->Parent = BalanceNode;
475 + ModifyNode->Parent = BalanceNode->Parent;
476 + BalanceNode->Parent = ModifyNode;
477 + BalanceNode->factor = ModifyNode->factor = 0; //After single rotation, set all factor of 3 node to 0.
478 + if (factor == 1)
479 + ModifyNode->rank += BalanceNode->rank;
480 + else
481 + BalanceNode->rank -= ModifyNode->rank;
482 + return ModifyNode;
483 + }
484 + TreeNode<T*,D> *_SingleRotation2(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
485 + {
486 + TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
487 + _FactorLink(BalanceNode, factor) = Node;
488 + _FactorLink(ModifyNode, -factor) = BalanceNode;
489 + if (Node) Node->Parent = BalanceNode;
490 + ModifyNode->Parent = BalanceNode->Parent;
491 + BalanceNode->Parent = ModifyNode;
492 + ModifyNode->factor = -factor;
493 + if (factor == 1)
494 + ModifyNode->rank+=BalanceNode->rank;
495 + else
496 + BalanceNode->rank-=ModifyNode->rank;
497 + return ModifyNode;
498 + }
499 + TreeNode<T*,D> *_DoubleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
500 + {
501 + TreeNode<T*,D> *DownNode = _FactorLink(ModifyNode, -factor);
502 + TreeNode<T*,D> *Node1, *Node2;
503 + Node1 = _FactorLink(DownNode, factor);
504 + Node2 = _FactorLink(DownNode, -factor);
505 + _FactorLink(ModifyNode, -factor) = Node1;
506 + _FactorLink(DownNode, factor) = ModifyNode;
507 + _FactorLink(BalanceNode, factor) = Node2;
508 + _FactorLink(DownNode, -factor) = BalanceNode;
509 + if (Node1)
510 + Node1->Parent = ModifyNode;
511 + if (Node2)
512 + Node2->Parent = BalanceNode;
513 + DownNode->Parent = BalanceNode->Parent;
514 + BalanceNode->Parent = DownNode;
515 + ModifyNode->Parent = DownNode;
516 + //Set factor according to the result.
517 + if (DownNode->factor == factor) {
518 + BalanceNode->factor = -factor;
519 + ModifyNode->factor = 0;
520 + } else if (DownNode->factor == 0)
521 + BalanceNode->factor = ModifyNode->factor = 0;
522 + else {
523 + BalanceNode->factor = 0;
524 + ModifyNode->factor = factor;
525 + }
526 + DownNode->factor = 0;
527 + if (factor==1) {
528 + ModifyNode->rank -= DownNode->rank;
529 + DownNode->rank += BalanceNode->rank;
530 + } else {
531 + DownNode->rank += ModifyNode->rank;
532 + BalanceNode->rank -= DownNode->rank;
533 + }
534 + return DownNode;
535 + }
536 +
537 + TreeNode<T*,D>* &__fastcall _FactorLink(TreeNode<T*,D> *Node, char factor)
538 + //Private helper method to retrieve child according to factor.
539 + //Return right child if factor>0 and left child otherwise.
540 + { return factor>0? Node->Right : Node->Left; }
541 +
542 + void Check()
543 + {
544 + unsigned int k = (unsigned int)head.Right;
545 + unsigned int t = head.Left->height();
546 + if (k != t)
547 + __debugbreak();
548 + }
549 +
550 + void _IncreaseHeight()
551 + {
552 + unsigned int k = (unsigned int)head.Right;
553 + head.Right = (TreeNode<T*,D>*)++k;
554 + }
555 +
556 + void _DecreaseHeight()
557 + {
558 + unsigned int k = (unsigned int)head.Right;
559 + head.Right = (TreeNode<T*,D>*)--k;
560 + }
561 +};
562 +
563 +struct SCMP
564 +{
565 + char operator()(const char *s1,const char *s2)
566 + {
567 + int t = _stricmp(s1, s2);
568 + return t == 0 ? 0 : t > 0 ? 1 :-1;
569 + }
570 +};
571 +
572 +struct SCPY { char *operator()(char *dest, const char *src) { return strcpy(dest, src); } };
573 +struct SLEN { int operator()(const char *str) { return strlen(str); } };
574 +
575 +struct WCMP
576 +{
577 + char operator()(const wchar_t *s1,const wchar_t *s2)
578 + {
579 + int t =_wcsicmp(s1, s2);
580 + return t == 0 ? 0 : t > 0 ? 1 : -1;
581 + }
582 +};
583 +
584 +struct WCPY { wchar_t *operator()(wchar_t *dest, const wchar_t *src) { return wcscpy(dest,src); } };
585 +struct WLEN { int operator()(const wchar_t *str) { return wcslen(str); } };
586 +
587 +// EOF
1 +#pragma once
2 +
3 +// config.h
4 +// 8/23/2013 jichi
5 +// The first header file that are included by all source files.
6 +
7 +#define IHF // for dll import
8 +#include "ith/dllconfig.h"
9 +#define IHFAPI __stdcall
10 +#ifdef IHF
11 +# define IHFSERVICE __declspec(dllexport)
12 +#else
13 +# define IHFSERVICE __declspec(dllimport)
14 +#endif
15 +
16 +// EOF
1 +// hookman.cc
2 +// 8/24/2013 jichi
3 +// Branch IHF/HookManager.cpp, rev 133
4 +// 8/24/2013 TODO: Clean up this file
5 +
6 +#ifdef _MSC_VER
7 +# pragma warning (disable:4100) // C4100: unreference formal parameter
8 +# pragma warning (disable:4146) // C4146: unary minus operator applied to unsigned type
9 +#endif // _MSC_VER
10 +
11 +#include "hookman.h"
12 +#include "ith/common/const.h"
13 +#include "ith/common/defs.h"
14 +#include "ith/common/types.h"
15 +//#include "ith/common/growl.h"
16 +#include "ith/sys/sys.h"
17 +//#include <emmintrin.h>
18 +
19 +namespace { // unnamed
20 +//enum { MAX_ENTRY = 0x40 };
21 +
22 +#define HM_LOCK win_mutex_lock<HookManager::mutex_type> d_locker(hmcs) // Synchronized scope for accessing private data
23 +// jichi 9/23/2013: wine deficenciy on mapping sections
24 +// Whe set to false, do not map sections.
25 +//bool ith_has_section = true;
26 +
27 +// jichi 9/28/2013: Remove ConsoleOutput from available hooks
28 +//LPWSTR HookNameInitTable[]={ L"ConsoleOutput" , HOOK_FUN_NAME_LIST };
29 +//LPCWSTR HookNameInitTable[] = {HOOK_FUN_NAME_LIST};
30 +//LPVOID DefaultHookAddr[HOOK_FUN_COUNT];
31 +
32 +//BYTE null_buffer[4]={0,0,0,0};
33 +//BYTE static_small_buffer[0x100];
34 +//DWORD zeros[4]={0,0,0,0};
35 +//WCHAR user_entry[0x40];
36 +
37 +bool GetProcessPath(HANDLE hProc, __out LPWSTR path)
38 +{
39 + PROCESS_BASIC_INFORMATION info;
40 + LDR_DATA_TABLE_ENTRY entry;
41 + PEB_LDR_DATA ldr;
42 + PEB peb;
43 + if (NT_SUCCESS(NtQueryInformationProcess(hProc, ProcessBasicInformation, &info, sizeof(info), 0)))
44 + if (info.PebBaseAddress)
45 + if (NT_SUCCESS(NtReadVirtualMemory(hProc, info.PebBaseAddress, &peb,sizeof(peb), 0)))
46 + if (NT_SUCCESS(NtReadVirtualMemory(hProc, peb.Ldr, &ldr, sizeof(ldr), 0)))
47 + if (NT_SUCCESS(NtReadVirtualMemory(hProc, (LPVOID)ldr.InLoadOrderModuleList.Flink,
48 + &entry, sizeof(LDR_DATA_TABLE_ENTRY), 0)))
49 + if (NT_SUCCESS(NtReadVirtualMemory(hProc, entry.FullDllName.Buffer,
50 + path, MAX_PATH * 2, 0)))
51 + return true;
52 + path = L"";
53 + return false;
54 +}
55 +
56 +bool GetProcessPath(DWORD pid, __out LPWSTR path)
57 +{
58 + CLIENT_ID id;
59 + OBJECT_ATTRIBUTES oa = {};
60 + HANDLE hProc;
61 + id.UniqueProcess = pid;
62 + id.UniqueThread = 0;
63 + oa.uLength = sizeof(oa);
64 + if (NT_SUCCESS(NtOpenProcess(&hProc , PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, &oa, &id))) {
65 + bool flag = GetProcessPath(hProc, path);
66 + NtClose(hProc);
67 + return flag;
68 + }
69 + path = L"";
70 + return false;
71 +}
72 +
73 +} // unnamed namespace
74 +
75 +HookManager *man; // jichi 9/22/2013: initialized in main
76 +//BitMap* pid_map;
77 +DWORD clipboard_flag,
78 + split_time,
79 + repeat_count,
80 + global_filter,
81 + cyclic_remove;
82 +
83 +DWORD GetHookName(LPWSTR str, DWORD pid, DWORD hook_addr, DWORD max)
84 +{
85 + if (!pid)
86 + return 0;
87 +
88 + DWORD len = 0;
89 + max--; //for '\0' magic marker.
90 +
91 + //if (pid == 0) {
92 + // len = wcslen(HookNameInitTable[0]);
93 + // if (len >= max)
94 + // len = max;
95 + // memcpy(str, HookNameInitTable[0], len << 1);
96 + // str[len] = 0;
97 + // return len;
98 + //}
99 +
100 + //::man->LockProcessHookman(pid);
101 + ProcessRecord *pr = ::man->GetProcessRecord(pid);
102 + if (!pr)
103 + return 0;
104 + NtWaitForSingleObject(pr->hookman_mutex, 0, 0);
105 + Hook *hks = (Hook *)pr->hookman_map;
106 + for (int i = 0; i < MAX_HOOK; i++)
107 + if (hks[i].Address() == hook_addr) {
108 + len = hks[i].NameLength();
109 + if (len >= max)
110 + len = max;
111 + NtReadVirtualMemory(pr->process_handle, hks[i].Name(), str, len << 1, &len);
112 + if (str[len - 1] == 0)
113 + len--;
114 + else
115 + str[len] = 0;
116 + break;
117 + }
118 +
119 + // jichi 9/27/2013: The hook man should be consistent with the one defined in vnrcli
120 + //Hook *h = (Hook *)hks;
121 + //for (int i = 0; i < MAX_HOOK; i++)
122 + // if (!h[i].hook_name)
123 + // break;
124 + // else {
125 + // const Hook &hi = h[i];
126 + // wchar_t buffer[1000];
127 + // DWORD len = hi.NameLength();
128 + // NtReadVirtualMemory(pr->process_handle, hi.hook_name, buffer, len << 1, &len);
129 + // buffer[len] = 0;
130 + // ITH_MSG(buffer);
131 + // }
132 +
133 + NtReleaseMutant(pr->hookman_mutex, 0);
134 + //::man->UnlockProcessHookman(pid);
135 + return len;
136 +}
137 +
138 +int GetHookNameByIndex(LPWSTR str, DWORD pid, DWORD index)
139 +{
140 + if (!pid)
141 + return 0;
142 +
143 + //if (pid == 0) {
144 + // wcscpy(str, HookNameInitTable[0]);
145 + // return wcslen(HookNameInitTable[0]);
146 + //}
147 + DWORD len = 0;
148 + //::man->LockProcessHookman(pid);
149 + ProcessRecord *pr = ::man->GetProcessRecord(pid);
150 + if (!pr)
151 + return 0;
152 + //NtWaitForSingleObject(pr->hookman_mutex,0,0); //already locked
153 + Hook *hks = (Hook *)pr->hookman_map;
154 + if (hks[index].Address()) {
155 + NtReadVirtualMemory(pr->process_handle, hks[index].Name(), str, hks[index].NameLength() << 1, &len);
156 + len = hks[index].NameLength();
157 + }
158 + //NtReleaseMutant(pr->hookman_mutex,0);
159 + return len;
160 +}
161 +
162 +//int GetHookString(LPWSTR str, DWORD pid, DWORD hook_addr, DWORD status)
163 +//{
164 +// LPWSTR begin=str;
165 +// str+=swprintf(str,L"%4d:0x%08X:",pid,hook_addr);
166 +// str+=GetHookName(str,pid,hook_addr);
167 +// return str-begin;
168 +//}
169 +
170 +
171 +void ThreadTable::SetThread(DWORD num, TextThread *ptr)
172 +{
173 + int number = num;
174 + if (number >= size) {
175 + while (number >= size)
176 + size <<= 1;
177 + TextThread **temp;
178 + //if (size < 0x10000) {
179 + temp = new TextThread*[size];
180 + if (size > used)
181 + ITH_MEMSET_HEAP(temp, 0, (size - used) * sizeof(TextThread *)); // jichi 9/21/2013: zero memory
182 + memcpy(temp, storage, used * sizeof(TextThread *));
183 + //}
184 + delete[] storage;
185 + storage = temp;
186 + }
187 + storage[number] = ptr;
188 + if (ptr == nullptr) {
189 + if (number == used - 1)
190 + while (storage[used - 1] == 0)
191 + used--;
192 + } else if (number >= used)
193 + used = number + 1;
194 +}
195 +
196 +TextThread *ThreadTable::FindThread(DWORD number)
197 +{ return number <= (DWORD)used ? storage[number] : nullptr; }
198 +
199 +static const char sse_table_eq[0x100]={
200 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
201 + -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
202 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
203 + -1,-1,-1,-1, 1,1,1,1, -1,-1,-1,-1, 1,1,1,1, //3, compare 3
204 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
205 + -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
206 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
207 + -1,-1,-1,-1, -1,-1,-1,-1, 1,1,1,1, 1,1,1,1, //7, compare 4
208 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
209 + -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
210 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
211 + -1,-1,-1,-1, 1,1,1,1, -1,-1,-1,-1, 1,1,1,1, //3, compare 3
212 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
213 + -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
214 + -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
215 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 //f, equal
216 +};
217 +char original_cmp(const ThreadParameter *t1, const ThreadParameter *t2)
218 +{
219 + //Q_ASSERT(t1 && t2);
220 + int t = t1->pid - t2->pid;
221 + if (t == 0) {
222 + t = t1->hook - t2->hook;
223 + if (t == 0) {
224 + t = t1->retn - t2->retn;
225 + if (t == 0) {
226 + t = t1->spl-t2->spl;
227 + if (t == 0) return 0;
228 + return t1->spl > t2->spl ? 1 : -1;
229 + }
230 + else return t1->retn > t2->retn ? 1 : -1;
231 + }
232 + else return t1->hook > t2->hook ? 1: -1;
233 + }
234 + else return t1->pid > t2->pid ? 1 : -1;
235 + //return t>0?1:-1;
236 +}
237 +char TCmp::operator()(const ThreadParameter* t1, const ThreadParameter* t2)
238 + //SSE speed up. Compare four integers in const time without branching.
239 + //The AVL tree branching operation needs 2 bit of information.
240 + //One bit for equality and one bit for "less than" or "greater than".
241 +
242 +{
243 + union{__m128 m0;__m128i i0;};
244 + union{__m128 m1;__m128i i1;};
245 + union{__m128 m2;__m128i i2;};
246 + int k0,k1;
247 + i1 = _mm_loadu_si128((const __m128i*)t1);
248 + i2 = _mm_loadu_si128((const __m128i*)t2);
249 + i0 = _mm_cmpgt_epi32(i1,i2);
250 + k0 = _mm_movemask_ps(m0);
251 + i1 = _mm_cmpeq_epi32(i1,i2);
252 + k1 = _mm_movemask_ps(m1);
253 + return sse_table_eq[k1*16+k0];
254 +}
255 +void TCpy::operator()(ThreadParameter* t1, const ThreadParameter* t2)
256 +{ memcpy(t1,t2,sizeof(ThreadParameter)); }
257 +
258 +int TLen::operator()(const ThreadParameter* t) { return 0; }
259 +
260 +#define NAMED_PIPE_DISCONNECT 1
261 +//Class member of HookManger
262 +HookManager::HookManager() :
263 + // jichi 9/21/2013: Zero memory
264 + //CRITICAL_SECTION hmcs;
265 + current(nullptr)
266 + , console(nullptr)
267 + , wconsole(nullptr)
268 + , create(nullptr)
269 + , remove(nullptr)
270 + , reset(nullptr)
271 + , attach(nullptr)
272 + , detach(nullptr)
273 + , hook(nullptr)
274 + , current_pid(0)
275 + , thread_table(nullptr)
276 + , destroy_event(nullptr)
277 + , register_count(0)
278 + , new_thread_number(0)
279 +{
280 + // jichi 9/21/2013: zero memory
281 + ITH_MEMSET_HEAP(record, 0, sizeof(record));
282 + ITH_MEMSET_HEAP(text_pipes, 0, sizeof(text_pipes));
283 + ITH_MEMSET_HEAP(cmd_pipes, 0, sizeof(cmd_pipes));
284 + ITH_MEMSET_HEAP(recv_threads, 0, sizeof(recv_threads));
285 +
286 + head.key = new ThreadParameter;
287 + head.key->pid = 0;
288 + head.key->hook = -1;
289 + head.key->retn = -1;
290 + head.key->spl = -1;
291 + head.data = 0;
292 + thread_table = new ThreadTable; // jichi 9/26/2013: zero memory in ThreadTable
293 +
294 + TextThread *entry = new TextThread(0, -1,-1,-1, new_thread_number++); // jichi 9/26/2013: zero memory in TextThread
295 + thread_table->SetThread(0, entry);
296 + SetCurrent(entry);
297 + entry->Status() |= USING_UNICODE;
298 + //texts->SetUnicode(true);
299 + //entry->AddToCombo();
300 + //entry->ComboSelectCurrent();
301 +
302 + //if (background==0) entry->AddToStore((BYTE*)BackgroundMsg,wcslen(BackgroundMsg)<<1,0,1);
303 +
304 + //InitializeCriticalSection(&hmcs);
305 + destroy_event = IthCreateEvent(0, 0, 0);
306 +}
307 +
308 +HookManager::~HookManager()
309 +{
310 + //LARGE_INTEGER timeout={-1000*1000,-1};
311 + //IthBreak();
312 + NtWaitForSingleObject(destroy_event, 0, 0);
313 + NtClose(destroy_event);
314 + NtClose(cmd_pipes[0]);
315 + NtClose(recv_threads[0]);
316 + delete thread_table;
317 + delete head.key;
318 + //DeleteCriticalSection(&hmcs);
319 +}
320 +
321 +TextThread *HookManager::FindSingle(DWORD pid, DWORD hook, DWORD retn, DWORD split)
322 +{
323 + if (pid == 0)
324 + return thread_table->FindThread(0);
325 + ThreadParameter tp = {pid, hook, retn, split};
326 + TreeNode<ThreadParameter *,DWORD> *node = Search(&tp);
327 + return node ? thread_table->FindThread(node->data) : nullptr;
328 +}
329 +
330 +TextThread *HookManager::FindSingle(DWORD number)
331 +{ return (number & 0x80008000) ? nullptr : thread_table->FindThread(number); }
332 +
333 +void HookManager::DetachProcess(DWORD pid) {}
334 +
335 +void HookManager::SetCurrent(TextThread *it)
336 +{
337 + if (current)
338 + current->Status() &= ~CURRENT_SELECT;
339 + current = it;
340 + if (it)
341 + it->Status() |= CURRENT_SELECT;
342 +}
343 +void HookManager::SelectCurrent(DWORD num)
344 +{
345 + if (TextThread *st = FindSingle(num)) {
346 + SetCurrent(st);
347 + if (reset)
348 + reset(st);
349 + //st->ResetEditText();
350 + }
351 +}
352 +void HookManager::RemoveSingleHook(DWORD pid, DWORD addr)
353 +{
354 + HM_LOCK;
355 + //ConsoleOutput("vnrhost:RemoveSingleHook: lock");
356 + //EnterCriticalSection(&hmcs);
357 + DWORD max = thread_table->Used();
358 + bool flag = false;
359 + for (DWORD i = 1; i <= max; i++)
360 + if (TextThread *it = thread_table->FindThread(i))
361 + if (it->PID() == pid && it->Addr() == addr) {
362 + flag |= (it == current);
363 + //flag|=it->RemoveFromCombo();
364 + thread_table->SetThread(i, 0);
365 + if (it->Number() < new_thread_number)
366 + new_thread_number = it->Number();
367 + Delete(it->GetThreadParameter());
368 + if (remove)
369 + remove(it);
370 + delete it;
371 + }
372 +
373 + for (DWORD i = 0; i <= max; i++)
374 + if (TextThread *it = thread_table->FindThread(i))
375 + if (it->Link() && thread_table->FindThread(it->LinkNumber()) == nullptr) {
376 + it->LinkNumber() = -1;
377 + it->Link() = nullptr;
378 + }
379 +
380 + if (flag) {
381 + current = nullptr;
382 + DWORD number = head.Left ? head.Left->data : 0;
383 + SetCurrent(thread_table->FindThread(number));
384 + if (reset && current)
385 + reset(current);
386 + //it->ResetEditText();
387 + }
388 + //LeaveCriticalSection(&hmcs);
389 + //ConsoleOutput("vnrhost:RemoveSingleHook: unlock");
390 +}
391 +void HookManager::RemoveSingleThread(DWORD number)
392 +{
393 + if (number == 0)
394 + return;
395 + HM_LOCK;
396 + //ConsoleOutput("vnrhost:RemoveSingleThread: lock");
397 + //EnterCriticalSection(&hmcs);
398 + if (TextThread *it = thread_table->FindThread(number)) {
399 + thread_table->SetThread(number, 0);
400 + Delete(it->GetThreadParameter());
401 + if (remove)
402 + remove(it);
403 + bool flag = (it == current);
404 + if (it->Number() < new_thread_number)
405 + new_thread_number = it->Number();
406 + delete it;
407 + for (int i = 0; i <= thread_table->Used(); i++)
408 + if (TextThread *t = thread_table->FindThread(i))
409 + if (t->LinkNumber() == number) {
410 + t->Link() = 0;
411 + t->LinkNumber() = -1;
412 + }
413 +
414 + if (flag) {
415 + current = nullptr;
416 + number = head.Left ? head.Left->data : 0;
417 + SetCurrent(thread_table->FindThread(number));
418 + if (reset && current)
419 + reset(current);
420 + //it->ResetEditText();
421 + }
422 + }
423 + //LeaveCriticalSection(&hmcs);
424 + //ConsoleOutput("vnrhost:RemoveSingleThread: unlock");
425 +}
426 +
427 +void HookManager::RemoveProcessContext(DWORD pid)
428 +{
429 + HM_LOCK;
430 + bool flag = false;
431 + //ConsoleOutput("vnrhost:RemoveProcessContext: lock");
432 + //EnterCriticalSection(&hmcs);
433 + for (int i = 1; i < thread_table->Used(); i++)
434 + if (TextThread *it = thread_table->FindThread(i))
435 + if (it->PID() == pid) {
436 + Delete(it->GetThreadParameter());
437 + //if (false == Delete(it->GetThreadParameter())) {
438 + // // jichi 11/26/2013: Remove debugging instructions
439 + // //if (debug)
440 + // // __asm int 3
441 + //}
442 + flag |= (it == current);
443 + //flag|=it->RemoveFromCombo();
444 + if (it->Number() <new_thread_number)
445 + new_thread_number = it->Number();
446 + thread_table->SetThread(i,0);
447 + if (remove)
448 + remove(it);
449 + delete it;
450 + }
451 +
452 + for (int i = 0; i < thread_table->Used(); i++)
453 + if (TextThread *it=thread_table->FindThread(i))
454 + if (it->Link() && thread_table->FindThread(it->LinkNumber()) == nullptr) {
455 + it->LinkNumber()=-1;
456 + it->Link() = nullptr;
457 + }
458 +
459 + if (flag) {
460 + current = nullptr;
461 + DWORD number = head.Left ? head.Left->data : 0;
462 + SetCurrent(thread_table->FindThread(number));
463 + if (reset && current)
464 + reset(current);
465 + //if (it) it->ResetEditText();
466 + }
467 + //LeaveCriticalSection(&hmcs);
468 + //ConsoleOutput("vnrhost:RemoveProcessContext: unlock");
469 +}
470 +void HookManager::RegisterThread(TextThread* it, DWORD num)
471 +{ thread_table->SetThread(num, it); }
472 +
473 +void HookManager::RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread)
474 +{
475 + text_pipes[register_count] = text;
476 + cmd_pipes[register_count] = cmd;
477 + recv_threads[register_count] = thread;
478 + register_count++;
479 + if (register_count == 1)
480 + NtSetEvent(destroy_event, 0);
481 + else
482 + NtClearEvent(destroy_event);
483 +}
484 +void HookManager::RegisterProcess(DWORD pid, DWORD hookman, DWORD module)
485 +{
486 + HM_LOCK;
487 + wchar_t str[0x40],
488 + path[MAX_PATH];
489 + //pid_map->Set(pid>>2);
490 + //ConsoleOutput("vnrhost:RegisterProcess: lock");
491 + //EnterCriticalSection(&hmcs);
492 + record[register_count - 1].pid_register = pid;
493 + record[register_count - 1].hookman_register = hookman;
494 + record[register_count - 1].module_register = module;
495 + //record[register_count - 1].engine_register = engine;
496 + swprintf(str, ITH_SECTION_ L"%d", pid);
497 + HANDLE hSection = IthCreateSection(str, HOOK_SECTION_SIZE, PAGE_READONLY);
498 + LPVOID map = nullptr;
499 + //DWORD map_size = 0x1000;
500 + DWORD map_size = HOOK_SECTION_SIZE / 2; // jichi 1/16/2015: Changed to half to hook section size
501 + //if (::ith_has_section)
502 + NtMapViewOfSection(hSection, NtCurrentProcess(),
503 + &map, 0, map_size, 0, &map_size, ViewUnmap, 0,
504 + PAGE_READONLY);
505 +
506 + record[register_count - 1].hookman_section = hSection;
507 + record[register_count - 1].hookman_map = map;
508 +
509 + HANDLE hProc;
510 + CLIENT_ID id;
511 + id.UniqueProcess = pid;
512 + id.UniqueThread = 0;
513 + OBJECT_ATTRIBUTES oa = {};
514 + oa.uLength = sizeof(oa);
515 + if (NT_SUCCESS(NtOpenProcess(&hProc,
516 + PROCESS_QUERY_INFORMATION|
517 + PROCESS_CREATE_THREAD|
518 + PROCESS_VM_READ|
519 + PROCESS_VM_WRITE|
520 + PROCESS_VM_OPERATION,
521 + &oa,&id)))
522 + record[register_count - 1].process_handle = hProc;
523 + else {
524 + ConsoleOutput("failed to open process");
525 + //::man->AddConsoleOutput(ErrorOpenProcess);
526 + //LeaveCriticalSection(&hmcs);
527 + //ConsoleOutput("vnrhost:RegisterProcess: unlock");
528 + return;
529 + }
530 +
531 + // jichi 9/27/2013: The hook man should be consistent with the one defined in vnrcli
532 + //Hook *h = (Hook *)map;
533 + //for (int i = 0; i < MAX_HOOK; i++)
534 + // if (!h[i].hook_name)
535 + // break;
536 + // else {
537 + // const Hook &hi = h[i];
538 + // wchar_t buffer[1000];
539 + // DWORD len = hi.NameLength();
540 + // NtReadVirtualMemory(hProc, hi.hook_name, buffer, len << 1, &len);
541 + // buffer[len] = 0;
542 + // ITH_MSG(buffer);
543 + // }
544 +
545 + swprintf(str, ITH_HOOKMAN_MUTEX_ L"%d", pid);
546 + record[register_count - 1].hookman_mutex = IthOpenMutex(str);
547 + if (!GetProcessPath(pid, path))
548 + path[0] = 0;
549 + //swprintf(str,L"%.4d:%s", pid, wcsrchr(path, L'\\') + 1); // jichi 9/25/2013: this is useless?
550 + current_pid = pid;
551 + if (attach)
552 + attach(pid);
553 + //LeaveCriticalSection(&hmcs);
554 + //ConsoleOutput("vnrhost:RegisterProcess: unlock");
555 +}
556 +
557 +void HookManager::UnRegisterProcess(DWORD pid)
558 +{
559 + HM_LOCK;
560 + //ConsoleOutput("vnrhost:UnRegisterProcess: lock");
561 + //EnterCriticalSection(&hmcs);
562 +
563 + int i;
564 + for (i = 0; i < MAX_REGISTER; i++)
565 + if(record[i].pid_register == pid)
566 + break;
567 +
568 + if (i < MAX_REGISTER) {
569 + NtClose(text_pipes[i]);
570 + NtClose(cmd_pipes[i]);
571 + NtClose(recv_threads[i]);
572 + NtClose(record[i].hookman_mutex);
573 +
574 + //if (::ith_has_section)
575 + NtUnmapViewOfSection(NtCurrentProcess(), record[i].hookman_map);
576 + //else
577 + // delete[] record[i].hookman_map;
578 +
579 + NtClose(record[i].process_handle);
580 + NtClose(record[i].hookman_section);
581 +
582 + for (; i < MAX_REGISTER; i++) {
583 + record[i] = record[i+1];
584 + text_pipes[i] = text_pipes[i+1];
585 + cmd_pipes[i] = cmd_pipes[i+1];
586 + recv_threads[i] = recv_threads[i+1];
587 + if (text_pipes[i] == 0)
588 + break;
589 + }
590 + register_count--;
591 + if (current_pid == pid)
592 + current_pid = register_count ? record[0].pid_register : 0;
593 + RemoveProcessContext(pid);
594 + }
595 + //pid_map->Clear(pid>>2);
596 +
597 + if (register_count == 1)
598 + NtSetEvent(destroy_event, 0);
599 + //LeaveCriticalSection(&hmcs);
600 + //ConsoleOutput("vnrhost:UnRegisterProcess: unlock");
601 + if (detach)
602 + detach(pid);
603 +}
604 +
605 +// jichi 9/28/2013: I do not need this
606 +//void HookManager::SetName(DWORD type)
607 +//{
608 +// WCHAR c;
609 +// if (type & PRINT_DWORD)
610 +// c = L'H';
611 +// else if (type & USING_UNICODE) {
612 +// if (type & STRING_LAST_CHAR)
613 +// c = L'L';
614 +// else if (type & USING_STRING)
615 +// c = L'Q';
616 +// else
617 +// c = L'W';
618 +// } else {
619 +// if (type & USING_STRING)
620 +// c = L'S';
621 +// else if (type & BIG_ENDIAN)
622 +// c = L'A';
623 +// else
624 +// c = L'B';
625 +// }
626 +// //swprintf(user_entry,L"UserHook%c",c);
627 +//}
628 +
629 +void HookManager::AddLink(WORD from, WORD to)
630 +{
631 + HM_LOCK;
632 + //bool flag=false;
633 + //ConsoleOutput("vnrhost:AddLink: lock");
634 + //EnterCriticalSection(&hmcs);
635 + TextThread *from_thread = thread_table->FindThread(from),
636 + *to_thread = thread_table->FindThread(to);
637 + if (to_thread && from_thread) {
638 + if (from_thread->GetThreadParameter()->pid != to_thread->GetThreadParameter()->pid)
639 + ConsoleOutput("vnrhost:AddLink: link to different process");
640 + else if (from_thread->Link()==to_thread)
641 + ConsoleOutput("vnrhost:AddLink: link already exists");
642 + else if (to_thread->CheckCycle(from_thread))
643 + ConsoleOutput("vnrhost:AddLink: cyclic link");
644 + else {
645 + from_thread->Link()=to_thread;
646 + from_thread->LinkNumber()=to;
647 + ConsoleOutput("vnrhost:AddLink: thread linked");
648 + if (addRemoveLink)
649 + addRemoveLink(from_thread);
650 + //WCHAR str[0x40];
651 + //swprintf(str,FormatLink,from,to);
652 + //AddConsoleOutput(str);
653 + }
654 + } else
655 + ConsoleOutput("vnrhost:AddLink: error link");
656 + //else
657 + // AddConsoleOutput(ErrorLink);
658 + //LeaveCriticalSection(&hmcs);
659 + //ConsoleOutput("vnrhost:AddLink: unlock");
660 +}
661 +void HookManager::UnLink(WORD from)
662 +{
663 + HM_LOCK;
664 + //bool flag=false;
665 + //ConsoleOutput("vnrhost:UnLink: lock");
666 + //EnterCriticalSection(&hmcs);
667 + if (TextThread *from_thread = thread_table->FindThread(from)) {
668 + from_thread->Link() = nullptr;
669 + from_thread->LinkNumber() = 0xffff;
670 + ConsoleOutput("vnrhost:UnLink: link deleted");
671 + if (addRemoveLink)
672 + addRemoveLink(from_thread);
673 + }
674 + //else // jichi 12/25/2013: This could happen when the game exist
675 + // ConsoleOutput("vnrhost:UnLink: thread does not exist");
676 + //LeaveCriticalSection(&hmcs);
677 + //ConsoleOutput("vnrhost:UnLink: unlock");
678 +}
679 +void HookManager::UnLinkAll(WORD from)
680 +{
681 + HM_LOCK;
682 + //bool flag=false;
683 + //ConsoleOutput("vnrhost:UnLinkAll: lock");
684 + //EnterCriticalSection(&hmcs);
685 + if (TextThread *from_thread = thread_table->FindThread(from)) {
686 + from_thread->UnLinkAll();
687 + ConsoleOutput("vnrhost:UnLinkAll: link deleted");
688 + }
689 + //else // jichi 12/25/2013: This could happen after the process exists
690 + // ConsoleOutput("vnrhost:UnLinkAll: thread not exist");
691 + //AddConsoleOutput(L"Link deleted.");
692 + //} else
693 + // AddConsoleOutput(L"Thread not exist.");
694 + //LeaveCriticalSection(&hmcs);
695 + //ConsoleOutput("vnrhost:UnLinkAll: unlock");
696 +}
697 +
698 +void HookManager::DispatchText(DWORD pid, const BYTE *text, DWORD hook, DWORD retn, DWORD spl, int len, bool space)
699 +{
700 + // jichi 20/27/2013: When PID is zero, the text comes from console, which I don't need
701 + if (!text || !pid || (len <= 0 && !space))
702 + return;
703 + HM_LOCK;
704 + //bool flag=false;
705 + ThreadParameter tp = {pid, hook, retn, spl};
706 + //ConsoleOutput("vnrhost:DispatchText: lock");
707 + //EnterCriticalSection(&hmcs);
708 + TextThread *it;
709 + //`try {
710 + if (TreeNode<ThreadParameter *,DWORD> *in = Search(&tp)) {
711 + DWORD number = in->data;
712 + it = thread_table->FindThread(number);
713 + } else if (IsFull()) { // jichi 1/16/2015: Skip adding threads when full
714 + static bool once = true; // output only once
715 + if (once) {
716 + once = false;
717 + ConsoleOutput("vnrhost:DispatchText: so many new threads, skip");
718 + }
719 + return;
720 + } else { // New thread
721 + Insert(&tp, new_thread_number);
722 + it = new TextThread(pid, hook, retn, spl, new_thread_number);
723 + RegisterThread(it, new_thread_number);
724 + ConsoleOutput("vnrhost:DispatchText: found new thread");
725 + WCHAR entstr[0x200];
726 + it->GetEntryString(entstr);
727 + ConsoleOutputW(entstr);
728 + while (thread_table->FindThread(++new_thread_number));
729 + if (create)
730 + create(it);
731 + }
732 + if (it)
733 + it->AddText(text, len, false, space); // jichi 10/27/2013: new line is false
734 + //LeaveCriticalSection(&hmcs);
735 + //ConsoleOutput("vnrhost:DispatchText: unlock");
736 + //} catch (...) {
737 + // // ignored
738 + //}
739 +}
740 +
741 +void HookManager::AddConsoleOutput(LPCWSTR text)
742 +{
743 + if (text) {
744 + int len = wcslen(text) << 1;
745 + TextThread *console = thread_table->FindThread(0);
746 + //EnterCriticalSection(&hmcs);
747 + console->AddText((BYTE*)text,len,false,true);
748 + console->AddText((BYTE*)L"\r\n",4,false,true);
749 + //LeaveCriticalSection(&hmcs);
750 + }
751 +}
752 +
753 +void HookManager::ClearText(DWORD pid, DWORD hook, DWORD retn, DWORD spl)
754 +{
755 + HM_LOCK;
756 + //bool flag=false;
757 + //ConsoleOutput("vnrhost:ClearText: lock");
758 + //EnterCriticalSection(&hmcs);
759 + ThreadParameter tp = {pid, hook, retn, spl};
760 + if (TreeNode<ThreadParameter *, DWORD> *in = Search(&tp))
761 + if (TextThread *it = thread_table->FindThread(in->data)) {
762 + it->Reset();
763 + //SetCurrent(it);
764 + if (reset)
765 + reset(it);
766 + //it->ResetEditText();
767 + }
768 +
769 + //LeaveCriticalSection(&hmcs);
770 + //ConsoleOutput("vnrhost:ClearText: unlock");
771 +}
772 +void HookManager::ClearCurrent()
773 +{
774 + HM_LOCK;
775 + //ConsoleOutput("vnrhost:ClearCurrent: lock");
776 + //EnterCriticalSection(&hmcs);
777 + if (current) {
778 + current->Reset();
779 + if (reset)
780 + reset(current);
781 + }
782 + //current->ResetEditText();
783 + //LeaveCriticalSection(&hmcs);
784 + //ConsoleOutput("vnrhost:ClearCurrent: unlock");
785 +}
786 +void HookManager::ResetRepeatStatus()
787 +{
788 + HM_LOCK;
789 + //ConsoleOutput("vnrhost:ResetRepeatStatus: lock");
790 + //EnterCriticalSection(&hmcs);
791 + for (int i = 1; i < thread_table->Used(); i++)
792 + if (TextThread *it = thread_table->FindThread(i))
793 + it->ResetRepeatStatus();
794 +
795 + //LeaveCriticalSection(&hmcs);
796 + //ConsoleOutput("vnrhost:ResetRepeatStatus: unlock");
797 +}
798 +//void HookManager::LockHookman(){ EnterCriticalSection(&hmcs); }
799 +//void HookManager::UnlockHookman(){ LeaveCriticalSection(&hmcs); }
800 +void HookManager::LockHookman(){ hmcs.lock(); }
801 +void HookManager::UnlockHookman(){ hmcs.unlock(); }
802 +
803 +/*void HookManager::SetProcessEngineType(DWORD pid, DWORD type)
804 +{
805 + int i;
806 + for (i=0;i<MAX_REGISTER;i++)
807 + if (record[i].pid_register==pid) break;
808 + if (i<MAX_REGISTER)
809 + {
810 + record[i].engine_register|=type;
811 + }
812 +}*/
813 +
814 +ProcessRecord *HookManager::GetProcessRecord(DWORD pid)
815 +{
816 + HM_LOCK;
817 + //EnterCriticalSection(&hmcs);
818 + for (int i = 0; i < MAX_REGISTER; i++)
819 + if (record[i].pid_register == pid)
820 + return record + i;
821 + return nullptr;
822 + //ProcessRecord *pr = i < MAX_REGISTER ? record + i : nullptr;
823 + //LeaveCriticalSection(&hmcs);
824 + //return pr;
825 +}
826 +
827 +DWORD HookManager::GetProcessIDByPath(LPCWSTR str)
828 +{
829 + WCHAR path[MAX_PATH];
830 + for (int i = 0; i < 8 && record[i].process_handle; i++) {
831 + ::GetProcessPath(record[i].process_handle, path);
832 + if (_wcsicmp(path,str) == 0)
833 + return record[i].pid_register;
834 + }
835 + return 0;
836 +}
837 +
838 +DWORD HookManager::GetCurrentPID() { return current_pid; }
839 +
840 +HANDLE HookManager::GetCmdHandleByPID(DWORD pid)
841 +{
842 + HM_LOCK;
843 + //EnterCriticalSection(&hmcs);
844 + for (int i = 0; i < MAX_REGISTER; i++)
845 + if (record[i].pid_register == pid)
846 + return cmd_pipes[i];
847 + return nullptr;
848 + //HANDLE h = i < MAX_REGISTER ? cmd_pipes[i] : 0;
849 + //LeaveCriticalSection(&hmcs);
850 + //return h;
851 +}
852 +
853 +MK_BASIC_TYPE(DWORD)
854 +MK_BASIC_TYPE(LPVOID)
855 +
856 +//DWORD Hash(LPCWSTR module, int length)
857 +//{
858 +// bool flag = (length==-1);
859 +// DWORD hash = 0;
860 +// for (;*module && (flag || length--); module++)
861 +// hash = ((hash>>7)|(hash<<25)) + *module;
862 +// return hash;
863 +//}
864 +
865 +DWORD GetCurrentPID() { return ::man->GetCurrentPID(); }
866 +
867 +HANDLE GetCmdHandleByPID(DWORD pid) { return ::man->GetCmdHandleByPID(pid); }
868 +
869 +void AddLink(WORD from, WORD to) { ::man->AddLink(from, to); }
870 +
871 +// jichi 9/27/2013: Unparse to hook parameters /H code
872 +void GetCode(const HookParam &hp, LPWSTR buffer, DWORD pid)
873 +{
874 + WCHAR c;
875 + LPWSTR ptr = buffer;
876 + // jichi 12/7/2014: disabled
877 + //if (hp.type&PRINT_DWORD)
878 + // c = L'H';
879 + if (hp.type&USING_UNICODE) {
880 + if (hp.type&USING_STRING)
881 + c = L'Q';
882 + else if (hp.type&STRING_LAST_CHAR)
883 + c = L'L';
884 + else
885 + c = L'W';
886 + } else {
887 + if (hp.type&USING_STRING)
888 + c = L'S';
889 + else if (hp.type&BIG_ENDIAN)
890 + c = L'A';
891 + else if (hp.type&STRING_LAST_CHAR)
892 + c = L'E';
893 + else
894 + c = L'B';
895 + }
896 + ptr += swprintf(ptr, L"/H%c",c);
897 + if (hp.type & NO_CONTEXT)
898 + *ptr++ = L'N';
899 + if (hp.off>>31)
900 + ptr += swprintf(ptr,L"-%X",-(hp.off+4));
901 + else
902 + ptr += swprintf(ptr,L"%X",hp.off);
903 + if (hp.type & DATA_INDIRECT) {
904 + if (hp.ind>>31)
905 + ptr += swprintf(ptr,L"*-%X",-hp.ind);
906 + else
907 + ptr += swprintf(ptr,L"*%X",hp.ind);
908 + }
909 + if (hp.type & USING_SPLIT) {
910 + if (hp.split >> 31)
911 + ptr += swprintf(ptr,L":-%X", -(4 + hp.split));
912 + else
913 + ptr += swprintf(ptr,L":%X", hp.split);
914 + }
915 + if (hp.type & SPLIT_INDIRECT) {
916 + if (hp.split_ind >> 31)
917 + ptr += swprintf(ptr, L"*-%X", -hp.split_ind);
918 + else
919 + ptr += swprintf(ptr, L"*%X", hp.split_ind);
920 + }
921 + if (hp.module) {
922 + if (pid) {
923 + WCHAR path[MAX_PATH];
924 + MEMORY_BASIC_INFORMATION info;
925 + ProcessRecord* pr = ::man->GetProcessRecord(pid);
926 + if (pr) {
927 + HANDLE hProc = pr->process_handle;
928 + if (NT_SUCCESS(NtQueryVirtualMemory(hProc,(PVOID)hp.addr, MemorySectionName, path, MAX_PATH*2, 0)) &&
929 + NT_SUCCESS(NtQueryVirtualMemory(hProc,(PVOID)hp.addr, MemoryBasicInformation, &info, sizeof(info), 0)))
930 + ptr += swprintf(ptr, L"@%X:%s", hp.addr - (DWORD)info. AllocationBase, wcsrchr(path,L'\\') + 1);
931 + }
932 + } else {
933 + ptr += swprintf(ptr, L"@%X!%X", hp.addr, hp.module);
934 + if (hp.function)
935 + ptr += swprintf(ptr, L"!%X", hp.function);
936 + }
937 + }
938 + else
939 + ptr += swprintf(ptr, L"@%X", hp.addr);
940 +}
941 +
942 +// jichi 1/16/2015
943 +bool HookManager::IsFull() const { return new_thread_number >= MAX_HOOK; }
944 +
945 +// EOF
1 +#pragma once
2 +
3 +// hookman.h
4 +// 8/23/2013 jichi
5 +// Branch: ITH/HookManager.h, rev 133
6 +
7 +#include "ith/host/avl_p.h"
8 +#include "ith/host/textthread.h"
9 +#include "winmutex/winmutex.h"
10 +
11 +enum { MAX_REGISTER = 0xf };
12 +enum { MAX_PREV_REPEAT_LENGTH = 0x20 };
13 +
14 +struct ProcessRecord {
15 + DWORD pid_register;
16 + DWORD hookman_register;
17 + DWORD module_register;
18 + //DWORD engine_register; // jichi 10/19/2014: removed
19 + HANDLE process_handle;
20 + HANDLE hookman_mutex;
21 + HANDLE hookman_section;
22 + LPVOID hookman_map;
23 +};
24 +
25 +class ThreadTable : public MyVector<TextThread *, 0x40>
26 +{
27 +public:
28 + virtual void SetThread(DWORD number, TextThread *ptr);
29 + virtual TextThread *FindThread(DWORD number);
30 +};
31 +
32 +struct TCmp { char operator()(const ThreadParameter *t1,const ThreadParameter *t2); };
33 +struct TCpy { void operator()(ThreadParameter *t1,const ThreadParameter *t2); };
34 +struct TLen { int operator()(const ThreadParameter *t); };
35 +
36 +typedef DWORD (*ProcessEventCallback)(DWORD pid);
37 +
38 +class IHFSERVICE HookManager : public AVLTree<ThreadParameter, DWORD, TCmp, TCpy, TLen>
39 +{
40 +public:
41 + HookManager();
42 + ~HookManager();
43 + // jichi 12/26/2013: remove virtual modifiers
44 + TextThread *FindSingle(DWORD pid, DWORD hook, DWORD retn, DWORD split);
45 + TextThread *FindSingle(DWORD number);
46 + ProcessRecord *GetProcessRecord(DWORD pid);
47 + DWORD GetProcessIDByPath(LPCWSTR str);
48 + void RemoveSingleThread(DWORD number);
49 + void LockHookman();
50 + void UnlockHookman();
51 + void ResetRepeatStatus();
52 + void ClearCurrent();
53 + void AddLink(WORD from, WORD to);
54 + void UnLink(WORD from);
55 + void UnLinkAll(WORD from);
56 + void SelectCurrent(DWORD num);
57 + void DetachProcess(DWORD pid);
58 + void SetCurrent(TextThread *it);
59 + void AddConsoleOutput(LPCWSTR text);
60 +
61 + // jichi 10/27/2013: Add const; add space.
62 + void DispatchText(DWORD pid, const BYTE *text, DWORD hook, DWORD retn, DWORD split, int len, bool space);
63 +
64 + void ClearText(DWORD pid, DWORD hook, DWORD retn, DWORD split);
65 + void RemoveProcessContext(DWORD pid);
66 + void RemoveSingleHook(DWORD pid, DWORD addr);
67 + void RegisterThread(TextThread*, DWORD);
68 + void RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread);
69 + void RegisterProcess(DWORD pid, DWORD hookman, DWORD module);
70 + void UnRegisterProcess(DWORD pid);
71 + //void SetName(DWORD);
72 +
73 + DWORD GetCurrentPID();
74 + HANDLE GetCmdHandleByPID(DWORD pid);
75 +
76 + ConsoleCallback RegisterConsoleCallback(ConsoleCallback cf)
77 + { return (ConsoleCallback)_InterlockedExchange((long*)&console,(long)cf); }
78 +
79 + ConsoleWCallback RegisterConsoleWCallback(ConsoleWCallback cf)
80 + { return (ConsoleWCallback)_InterlockedExchange((long*)&wconsole,(long)cf); }
81 +
82 + ThreadEventCallback RegisterThreadCreateCallback(ThreadEventCallback cf)
83 + { return (ThreadEventCallback)_InterlockedExchange((long*)&create,(long)cf); }
84 +
85 + ThreadEventCallback RegisterThreadRemoveCallback(ThreadEventCallback cf)
86 + { return (ThreadEventCallback)_InterlockedExchange((long*)&remove,(long)cf); }
87 +
88 + ThreadEventCallback RegisterThreadResetCallback(ThreadEventCallback cf)
89 + { return (ThreadEventCallback)_InterlockedExchange((long*)&reset,(long)cf); }
90 +
91 + ThreadEventCallback RegisterAddRemoveLinkCallback(ThreadEventCallback cf)
92 + { return (ThreadEventCallback)_InterlockedExchange((long*)&addRemoveLink, (long)cf); }
93 +
94 + ProcessEventCallback RegisterProcessAttachCallback(ProcessEventCallback cf)
95 + { return (ProcessEventCallback)_InterlockedExchange((long*)&attach,(long)cf); }
96 +
97 + ProcessEventCallback RegisterProcessDetachCallback(ProcessEventCallback cf)
98 + { return (ProcessEventCallback)_InterlockedExchange((long*)&detach,(long)cf); }
99 +
100 + ProcessEventCallback RegisterProcessNewHookCallback(ProcessEventCallback cf)
101 + { return (ProcessEventCallback)_InterlockedExchange((long*)&hook,(long)cf); }
102 +
103 + ProcessEventCallback ProcessNewHook() { return hook; }
104 + TextThread *GetCurrentThread() { return current; }
105 + ProcessRecord *Records() { return record; }
106 + ThreadTable *Table() { return thread_table; }
107 +
108 + //DWORD& SplitTime() { return split_time; }
109 + //DWORD& RepeatCount() { return repeat_count; }
110 + //DWORD& CyclicRemove() { return cyclic_remove; }
111 + //DWORD& GlobalFilter() { return global_filter; }
112 + void ConsoleOutput(LPCSTR text) { if (console) console(text); } // not thread safe
113 + void ConsoleOutputW(LPCWSTR text) { if (wconsole) wconsole(text); } // not thread safe
114 +
115 +private:
116 + typedef win_mutex<CRITICAL_SECTION> mutex_type;
117 + mutex_type hmcs;
118 +
119 + TextThread *current;
120 + ConsoleCallback console; // jichi 12/25/2013: add console output callback
121 + ConsoleWCallback wconsole;
122 + ThreadEventCallback create,
123 + remove,
124 + reset,
125 + addRemoveLink;
126 + ProcessEventCallback attach,
127 + detach,
128 + hook;
129 + DWORD current_pid;
130 + ThreadTable *thread_table;
131 + HANDLE destroy_event;
132 + ProcessRecord record[MAX_REGISTER + 1];
133 + HANDLE text_pipes[MAX_REGISTER + 1],
134 + cmd_pipes[MAX_REGISTER + 1],
135 + recv_threads[MAX_REGISTER + 1];
136 + WORD register_count,
137 + new_thread_number;
138 +
139 + // jichi 1/16/2014: Stop adding new threads when full
140 + bool IsFull() const; // { return new_thread_number >= MAX_HOOK; }
141 + bool IsEmpty() const { return !new_thread_number; }
142 +};
143 +
144 +// EOF
1 +# host.pri
2 +# 8/9/2011 jichi
3 +
4 +DEFINES += WITH_LIB_ITH_HOST
5 +
6 +DEPENDPATH += $$PWD
7 +
8 +LIBS += -lvnrhost
9 +
10 +HEADERS += \
11 + $$PWD/avl_p.h \
12 + $$PWD/hookman.h \
13 + $$PWD/settings.h \
14 + $$PWD/srv.h \
15 + $$PWD/textthread.h \
16 + $$PWD/textthread_p.h
17 +
18 +# EOF
1 +# host.pro
2 +# 8/9/2013 jichi
3 +# Build vnrhost
4 +
5 +#CONFIG += eha # 3/1/2014: catchlng all exceptions will break pytexthook on Windows XP
6 +CONFIG += noeh # Needed by pytexthook ONLY on windows xp orz
7 +include(../dllconfig.pri)
8 +include(../sys/sys.pri)
9 +include($$LIBDIR/winmaker/winmaker.pri)
10 +include($$LIBDIR/winmutex/winmutex.pri)
11 +
12 +# 9/22/2013: When ITH is on wine, certain NT functions are replaced
13 +#DEFINES += ITH_WINE
14 +
15 +# 9/27/2013: Only for debugging purpose
16 +#DEFINES += ITH_DISABLE_REPEAT # disable repetition elimination
17 +#DEFINES += ITH_DISABLE_FILTER # disable space filter in pipe
18 +
19 +## Libraries
20 +
21 +LIBS += -lkernel32 -luser32 #-lcomctl32
22 +
23 +## Sources
24 +
25 +TEMPLATE = lib
26 +#TARGET = IHF # compatible with ITHv3
27 +TARGET = vnrhost
28 +
29 +#CONFIG += staticlib
30 +
31 +HEADERS += \
32 + avl_p.h \
33 + config.h \
34 + hookman.h \
35 + settings.h \
36 + srv.h \
37 + srv_p.h \
38 + textthread.h \
39 + textthread_p.h
40 + #util.h
41 +
42 +SOURCES += \
43 + hookman.cc \
44 + main.cc \
45 + pipe.cc \
46 + textthread.cc
47 + #util.cc
48 +
49 +#RC_FILE += engine.rc
50 +#OTHER_FILES += engine.rc
51 +
52 +OTHER_FILES += host.pri
53 +
54 +# EOF
1 +// main.cc
2 +// 8/24/2013 jichi
3 +// Branch IHF/main.cpp, rev 111
4 +// 8/24/2013 TODO: Clean up this file
5 +
6 +//#ifdef _MSC_VER
7 +//# pragma warning(disable:4800) // C4800: forcing value to bool (performance warning)
8 +//#endif // _MSC_VER
9 +
10 +#include "config.h"
11 +//#include "customfilter.h"
12 +#include "srv.h"
13 +#include "srv_p.h"
14 +#include "settings.h"
15 +#include "ith/common/const.h"
16 +#include "ith/common/defs.h"
17 +#include "ith/common/growl.h"
18 +#include "ith/common/types.h"
19 +#include "ith/sys/sys.h"
20 +#include "winmaker/winmaker.h"
21 +#include "ccutil/ccmacro.h"
22 +#include <commctrl.h>
23 +
24 +//#define ITH_WINE
25 +//#define ITH_USE_UX_DLLS IthIsWine()
26 +#define ITH_USE_XP_DLLS (IthIsWindowsXp() && !IthIsWine())
27 +
28 +namespace { // unnamed
29 +
30 +//enum { HOOK_TIMEOUT = -50000000 }; // in nanoseconds = 5 seconds
31 +
32 +CRITICAL_SECTION cs;
33 +//WCHAR exist[] = ITH_PIPEEXISTS_EVENT;
34 +//WCHAR mutex[] = L"ITH_RUNNING";
35 +//WCHAR EngineName[] = ITH_ENGINE_DLL;
36 +//WCHAR EngineNameXp[] = ITH_ENGINE_XP_DLL;
37 +//WCHAR DllName[] = ITH_CLIENT_DLL;
38 +//WCHAR DllNameXp[] = ITH_CLIENT_XP_DLL;
39 +HANDLE hServerMutex; // jichi 9/28/2013: used to guard pipe
40 +HANDLE hHookMutex; // jichi 9/28/2013: used to guard hook modification
41 +DWORD admin;
42 +} // unnamed namespace
43 +
44 +//extern LPWSTR current_dir;
45 +extern CRITICAL_SECTION detach_cs;
46 +
47 +SettingManager* setman;
48 +Settings *settings;
49 +HWND hMainWnd;
50 +HANDLE hPipeExist;
51 +BOOL running;
52 +
53 +#define ITH_SYNC_HOOK IthMutexLocker locker(::hHookMutex)
54 +
55 +namespace { // unnamed
56 +
57 +void GetDebugPriv()
58 +{
59 + HANDLE hToken;
60 + DWORD dwRet;
61 + NTSTATUS status;
62 +
63 + TOKEN_PRIVILEGES Privileges = {1,{0x14,0,SE_PRIVILEGE_ENABLED}};
64 +
65 + NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
66 +
67 + status = NtAdjustPrivilegesToken(hToken, 0, &Privileges, sizeof(Privileges), 0, &dwRet);
68 + admin = 1; // jichi 8/24/2013: ITH do not need admin
69 + //if (STATUS_SUCCESS == status)
70 + //{
71 + // admin = 1;
72 + //}
73 + //else
74 + //{
75 + // WCHAR buffer[0x10];
76 + // swprintf(buffer, L"%.8X",status);
77 + // MessageBox(0, NotAdmin, buffer, 0);
78 + //}
79 + NtClose(hToken);
80 +}
81 +
82 +// jichi 9/22/2013: Change current directory to the same as main module path
83 +// Otherwise NtFile* would not work for files with relative paths.
84 +//BOOL ChangeCurrentDirectory()
85 +//{
86 +// if (const wchar_t *path = GetMainModulePath()) // path to VNR's python exe
87 +// if (const wchar_t *base = wcsrchr(path, L'\\')) {
88 +// size_t len = base - path;
89 +// if (len < MAX_PATH) {
90 +// wchar_t buf[MAX_PATH];
91 +// wcsncpy(buf, path, len);
92 +// buf[len] = 0;
93 +// return SetCurrentDirectoryW(buf);
94 +// }
95 +// }
96 +// return FALSE;
97 +//}
98 +
99 +DWORD Inject(HANDLE hProc)
100 +{
101 + enum : DWORD { error = (DWORD)-1 };
102 + LPVOID lpvAllocAddr = 0;
103 + DWORD dwWrite = 0x1000; //, len = 0;
104 + HANDLE hTH;
105 + //LPWSTR dllname = (IthIsWindowsXp() && !IthIsWine()) ? DllNameXp : DllName;
106 + LPCWSTR dllname = ITH_USE_XP_DLLS ? ITH_DLL_XP : ITH_DLL;
107 + //if (!IthCheckFile(dllname))
108 + // return error;
109 + wchar_t path[MAX_PATH];
110 + size_t len = IthGetCurrentModulePath(path, MAX_PATH);
111 + if (!len)
112 + return error;
113 +
114 + wchar_t *p;
115 + for (p = path + len; *p != L'\\'; p--);
116 + p++; // ending with L"\\"
117 +
118 + //LPCWSTR mp = GetMainModulePath();
119 + //len = wcslen(mp);
120 + //memcpy(path, mp, len << 1);
121 + //memset(path + len, 0, (MAX_PATH - len) << 1);
122 + //LPWSTR p;
123 + //for (p = path + len; *p != L'\\'; p--); // Always a \ after drive letter.
124 + //p++;
125 + wcscpy(p, dllname);
126 + //if (IthIsWine())
127 + // lpvAllocAddr = VirtualAllocEx(hProc, nullptr, dwWrite, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
128 + //else
129 + NtAllocateVirtualMemory(hProc, &lpvAllocAddr, 0, &dwWrite, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
130 + if (!lpvAllocAddr)
131 + return error;
132 +
133 + CheckThreadStart();
134 +
135 + //Copy module path into address space of target process.
136 + //if (IthIsWine())
137 + // WriteProcessMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
138 + //else
139 + NtWriteVirtualMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
140 + hTH = IthCreateThread(LoadLibraryW, (DWORD)lpvAllocAddr, hProc);
141 + if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) {
142 + ConsoleOutput("vnrhost:inject: ERROR: failed to create remote cli thread");
143 + //ConsoleOutput(ErrorRemoteThread);
144 + return -1;
145 + }
146 + // jichi 9/28/2013: no wait as it will not blocked
147 + NtWaitForSingleObject(hTH, 0, nullptr);
148 + THREAD_BASIC_INFORMATION info;
149 + NtQueryInformationThread(hTH, ThreadBasicInformation, &info, sizeof(info), &dwWrite);
150 + NtClose(hTH);
151 +
152 + // jichi 10/19/2014: Disable inject the second dll
153 + //if (info.ExitStatus) {
154 + // //IthCoolDown();
155 + // wcscpy(p, engine);
156 + // //if (IthIsWine())
157 + // // WriteProcessMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
158 + // //else
159 + // NtWriteVirtualMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
160 + // hTH = IthCreateThread(LoadLibraryW, (DWORD)lpvAllocAddr, hProc);
161 + // if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) {
162 + // //ConsoleOutput(ErrorRemoteThread);
163 + // ConsoleOutput("vnrhost:inject: ERROR: failed to create remote eng thread");
164 + // return error;
165 + // }
166 + //
167 + // // jichi 9/28/2013: no wait as it will not blocked
168 + // NtWaitForSingleObject(hTH, 0, nullptr);
169 + // NtClose(hTH);
170 + //}
171 +
172 + dwWrite = 0;
173 + //if (IthIsWine())
174 + // VirtualFreeEx(hProc, lpvAllocAddr, dwWrite, MEM_RELEASE);
175 + //else
176 + NtFreeVirtualMemory(hProc, &lpvAllocAddr, &dwWrite, MEM_RELEASE);
177 + return info.ExitStatus;
178 +}
179 +
180 +
181 +} // unnamed namespace
182 +
183 +void CreateNewPipe();
184 +
185 +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
186 +{
187 + CC_UNUSED(lpvReserved);
188 + switch (fdwReason)
189 + {
190 + case DLL_PROCESS_ATTACH:
191 + LdrDisableThreadCalloutsForDll(hinstDLL);
192 + InitializeCriticalSection(&cs);
193 + IthInitSystemService();
194 + GetDebugPriv();
195 + // jichi 12/20/2013: Since I already have a GUI, I don't have to InitCommonControls()
196 + //Used by timers.
197 + InitCommonControls();
198 + // jichi 8/24/2013: Create hidden window so that ITH can access timer and events
199 + //hMainWnd = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0);
200 + //wm_register_hidden_class("vnrsrv.class");
201 + hMainWnd = (HWND)wm_create_hidden_window(L"vnrsrv", L"Button", hinstDLL);
202 + //ChangeCurrentDirectory();
203 + break;
204 + case DLL_PROCESS_DETACH:
205 + if (::running)
206 + IHF_Cleanup();
207 + DeleteCriticalSection(&cs);
208 + IthCloseSystemService();
209 + wm_destroy_window(hMainWnd);
210 + break;
211 + default:
212 + break;
213 + }
214 + return true;
215 +}
216 +
217 +HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction)
218 +{
219 + UNICODE_STRING us;
220 + RtlInitUnicodeString(&us, name);
221 + SECURITY_DESCRIPTOR sd = {1};
222 + OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
223 + HANDLE hFile;
224 + IO_STATUS_BLOCK isb;
225 + if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0)))
226 + return hFile;
227 + else
228 + return INVALID_HANDLE_VALUE;
229 +}
230 +
231 +void ConsoleOutput(LPCSTR text) { man->ConsoleOutput(text); }
232 +void ConsoleOutputW(LPCWSTR text) { man->ConsoleOutputW(text); }
233 +
234 +enum { IHS_SIZE = 0x80 };
235 +enum { IHS_BUFF_SIZE = IHS_SIZE - sizeof(HookParam) };
236 +
237 +struct InsertHookStruct
238 +{
239 + SendParam sp;
240 + BYTE name_buffer[IHS_SIZE];
241 +};
242 +
243 +IHFSERVICE DWORD IHFAPI IHF_Init()
244 +{
245 + BOOL result = false;
246 + DWORD present;
247 + EnterCriticalSection(&cs);
248 + hServerMutex = IthCreateMutex(ITH_SERVER_MUTEX, 1, &present);
249 + if (present)
250 + //MessageBox(0,L"Already running.",0,0);
251 + // jichi 8/24/2013
252 + ITH_WARN(L"I am sorry that this game is attached by some other VNR ><\nPlease restart the game and try again!");
253 + else if (!::running) {
254 + ::running = true;
255 + ::settings = new Settings;
256 + setman = new SettingManager;
257 + setman->SetValue(SETTING_SPLIT_TIME, 200);
258 + ::man = new HookManager;
259 + //cmdq = new CommandQueue;
260 + InitializeCriticalSection(&detach_cs);
261 +
262 + ::hHookMutex = IthCreateMutex(ITH_SERVER_HOOK_MUTEX, FALSE);
263 + result = true;
264 +
265 + }
266 + LeaveCriticalSection(&cs);
267 + return result;
268 +}
269 +
270 +IHFSERVICE DWORD IHFAPI IHF_Start()
271 +{
272 + //IthBreak();
273 + CreateNewPipe();
274 + hPipeExist = IthCreateEvent(ITH_PIPEEXISTS_EVENT);
275 + NtSetEvent(hPipeExist, nullptr);
276 + return 0;
277 +}
278 +
279 +IHFSERVICE DWORD IHFAPI IHF_Cleanup()
280 +{
281 + BOOL result = FALSE;
282 + EnterCriticalSection(&cs);
283 + if (::running) {
284 + ::running = FALSE;
285 + HANDLE hRecvPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE);
286 + NtClose(hRecvPipe);
287 + NtClearEvent(hPipeExist);
288 + //delete cmdq;
289 + delete man;
290 + delete settings;
291 + NtClose(::hHookMutex);
292 + NtClose(hServerMutex);
293 + NtClose(hPipeExist);
294 + DeleteCriticalSection(&detach_cs);
295 + result = TRUE;
296 + }
297 + LeaveCriticalSection(&cs);
298 + return result;
299 +}
300 +
301 +IHFSERVICE DWORD IHFAPI IHF_GetPIDByName(LPCWSTR pwcTarget)
302 +{
303 + DWORD dwSize = 0x20000,
304 + dwExpectSize = 0;
305 + LPVOID pBuffer = 0;
306 + SYSTEM_PROCESS_INFORMATION *spiProcessInfo;
307 + DWORD dwPid = 0;
308 + DWORD dwStatus;
309 +
310 + NtAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
311 + dwStatus = NtQuerySystemInformation(SystemProcessInformation, pBuffer, dwSize, &dwExpectSize);
312 + if (!NT_SUCCESS(dwStatus)) {
313 + NtFreeVirtualMemory(NtCurrentProcess(),&pBuffer,&dwSize,MEM_RELEASE);
314 + if (dwStatus != STATUS_INFO_LENGTH_MISMATCH || dwExpectSize < dwSize)
315 + return 0;
316 + dwSize = (dwExpectSize | 0xFFF) + 0x4001; //
317 + pBuffer = 0;
318 + NtAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
319 + dwStatus = NtQuerySystemInformation(SystemProcessInformation, pBuffer, dwSize, &dwExpectSize);
320 + if (!NT_SUCCESS(dwStatus)) goto _end;
321 + }
322 +
323 + for (spiProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pBuffer; spiProcessInfo->dNext;) {
324 + spiProcessInfo = (SYSTEM_PROCESS_INFORMATION *)
325 + ((DWORD)spiProcessInfo + spiProcessInfo -> dNext);
326 + if (_wcsicmp(pwcTarget, spiProcessInfo -> usName.Buffer) == 0) {
327 + dwPid = spiProcessInfo->dUniqueProcessId;
328 + break;
329 + }
330 + }
331 + if (!dwPid)
332 + ConsoleOutput("vnrhost:IHF_GetPIDByName: pid not found");
333 + //if (dwPid == 0) ConsoleOutput(ErrorNoProcess);
334 +_end:
335 + NtFreeVirtualMemory(NtCurrentProcess(),&pBuffer,&dwSize,MEM_RELEASE);
336 + return dwPid;
337 +}
338 +
339 +IHFSERVICE DWORD IHFAPI IHF_InjectByPID(DWORD pid)
340 +{
341 + WCHAR str[0x80];
342 + if (!::running)
343 + return 0;
344 + if (pid == current_process_id) {
345 + //ConsoleOutput(SelfAttach);
346 + ConsoleOutput("vnrhost:IHF_InjectByPID: refuse to inject myself");
347 + return -1;
348 + }
349 + if (man->GetProcessRecord(pid)) {
350 + //ConsoleOutput(AlreadyAttach);
351 + ConsoleOutput("vnrhost:IHF_InjectByPID: already attached");
352 + return -1;
353 + }
354 + swprintf(str, ITH_HOOKMAN_MUTEX_ L"%d", pid);
355 + DWORD s;
356 + NtClose(IthCreateMutex(str, 0, &s));
357 + if (s)
358 + return -1;
359 + CLIENT_ID id;
360 + OBJECT_ATTRIBUTES oa = {};
361 + HANDLE hProc;
362 + id.UniqueProcess = pid;
363 + id.UniqueThread = 0;
364 + oa.uLength = sizeof(oa);
365 + if (!NT_SUCCESS(NtOpenProcess(&hProc,
366 + PROCESS_QUERY_INFORMATION|
367 + PROCESS_CREATE_THREAD|
368 + PROCESS_VM_OPERATION|
369 + PROCESS_VM_READ|
370 + PROCESS_VM_WRITE,
371 + &oa, &id))) {
372 + //ConsoleOutput(ErrorOpenProcess);
373 + ConsoleOutput("vnrhost:IHF_InjectByPID: failed to open process");
374 + return -1;
375 + }
376 +
377 + //if (!engine)
378 + // engine = ITH_USE_XP_DLLS ? ITH_ENGINE_XP_DLL : ITH_ENGINE_DLL;
379 + DWORD module = Inject(hProc);
380 + NtClose(hProc);
381 + if (module == -1)
382 + return -1;
383 + //swprintf(str, FormatInject, pid, module);
384 + //ConsoleOutput(str);
385 + ConsoleOutput("vnrhost:IHF_InjectByPID: inject succeed");
386 + return module;
387 +}
388 +
389 +// jichi 7/16/2014: Test if process is valid before creating remote threads
390 +// See: http://msdn.microsoft.com/en-us/library/ms687032.aspx
391 +static bool isProcessTerminated(HANDLE hProc)
392 +{ return WAIT_OBJECT_0 == ::WaitForSingleObject(hProc, 0); }
393 +//static bool isProcessRunning(HANDLE hProc)
394 +//{ return WAIT_TIMEOUT == ::WaitForSingleObject(hProc, 0); }
395 +
396 +// jichi 7/16/2014: Test if process is valid before creating remote threads
397 +//static bool isProcessRunning(DWORD pid)
398 +//{
399 +// bool ret = false;
400 +// HANDLE hProc = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
401 +// if (hProc) {
402 +// DWORD status;
403 +// if (::GetExitCodeProcess(hProc, &status)) {
404 +// ret = status == STILL_ACTIVE;
405 +// ::CloseHandle(hProc);
406 +// } else
407 +// ret = true;
408 +// }
409 +// return ret;
410 +//}
411 +
412 +IHFSERVICE DWORD IHFAPI IHF_ActiveDetachProcess(DWORD pid)
413 +{
414 + ITH_SYNC_HOOK;
415 +
416 + DWORD module;
417 + HANDLE hProc, hThread;
418 + IO_STATUS_BLOCK ios;
419 + //man->LockHookman();
420 + ProcessRecord *pr = man->GetProcessRecord(pid);
421 + HANDLE hCmd = man->GetCmdHandleByPID(pid);
422 + if (pr == 0 || hCmd == 0)
423 + return FALSE;
424 + //hProc = pr->process_handle; //This handle may be closed(thus invalid) during the detach process.
425 + NtDuplicateObject(NtCurrentProcess(), pr->process_handle,
426 + NtCurrentProcess(), &hProc, 0, 0, DUPLICATE_SAME_ACCESS); // Make a copy of the process handle.
427 + module = pr->module_register;
428 + if (module == 0)
429 + return FALSE;
430 +
431 + // jichi 7/15/2014: Process already closed
432 + if (isProcessTerminated(hProc)) {
433 + ConsoleOutput("vnrhost::activeDetach: process has terminated");
434 + return FALSE;
435 + }
436 +
437 + // jichi 10/19/2014: Disable the second dll
438 + //engine = pr->engine_register;
439 + //engine &= ~0xff;
440 +
441 + SendParam sp = {};
442 + sp.type = 4;
443 +
444 + ConsoleOutput("vnrhost:IHF_ActiveDetachProcess: sending cmd");
445 + NtWriteFile(hCmd, 0,0,0, &ios, &sp, sizeof(SendParam), 0,0);
446 + ConsoleOutput("vnrhost:IHF_ActiveDetachProcess: cmd sent");
447 +
448 + //cmdq->AddRequest(sp, pid);
449 +////#ifdef ITH_WINE // Nt series crash on wine
450 +//// hThread = IthCreateThread(FreeLibrary, engine, hProc);
451 +////#else
452 +// hThread = IthCreateThread(LdrUnloadDll, engine, hProc);
453 +////#endif // ITH_WINE
454 +// if (hThread == 0 || hThread == INVALID_HANDLE_VALUE)
455 +// return FALSE;
456 +// // jichi 10/22/2013: Timeout might crash vnrsrv
457 +// //const LONGLONG timeout = HOOK_TIMEOUT;
458 +// //NtWaitForSingleObject(hThread, 0, (PLARGE_INTEGER)&timeout);
459 +// NtWaitForSingleObject(hThread, 0, nullptr);
460 +// NtClose(hThread);
461 +
462 + // jichi 7/15/2014: Process already closed
463 + if (isProcessTerminated(hProc)) {
464 + ConsoleOutput("vnrhost:activeDetach: process has terminated");
465 + return FALSE;
466 + }
467 +
468 + //IthCoolDown();
469 +//#ifdef ITH_WINE // Nt series crash on wine
470 +// hThread = IthCreateThread(FreeLibrary, engine, hProc);
471 +//#else
472 + hThread = IthCreateThread(LdrUnloadDll, module, hProc);
473 +//#endif // ITH_WINE
474 + if (hThread == 0 || hThread == INVALID_HANDLE_VALUE)
475 + return FALSE;
476 + // jichi 10/22/2013: Timeout might crash vnrsrv
477 + //NtWaitForSingleObject(hThread, 0, (PLARGE_INTEGER)&timeout);
478 + NtWaitForSingleObject(hThread, 0, nullptr);
479 + //man->UnlockHookman();
480 + THREAD_BASIC_INFORMATION info;
481 + NtQueryInformationThread(hThread, ThreadBasicInformation, &info, sizeof(info), 0);
482 + NtClose(hThread);
483 + NtSetEvent(hPipeExist, 0);
484 + FreeThreadStart(hProc);
485 + NtClose(hProc);
486 + return info.ExitStatus;
487 +}
488 +
489 +IHFSERVICE DWORD IHFAPI IHF_GetHookManager(HookManager** hookman)
490 +{
491 + if (::running) {
492 + *hookman = man;
493 + return 0;
494 + }
495 + else
496 + return 1;
497 +}
498 +
499 +IHFSERVICE DWORD IHFAPI IHF_GetSettingManager(SettingManager** set_man)
500 +{
501 + if (running)
502 + {
503 + *set_man = setman;
504 + return 0;
505 + }
506 + else return 1;
507 +}
508 +
509 +IHFSERVICE DWORD IHFAPI IHF_GetSettings(Settings **p)
510 +{
511 + if (::running) {
512 + *p = settings;
513 + return 0;
514 + }
515 + else
516 + return 1;
517 +}
518 +
519 +IHFSERVICE DWORD IHFAPI IHF_InsertHook(DWORD pid, HookParam *hp, LPCWSTR name)
520 +{
521 + ITH_SYNC_HOOK;
522 +
523 + HANDLE hCmd = man->GetCmdHandleByPID(pid);
524 + if (hCmd == 0)
525 + return -1;
526 +
527 + InsertHookStruct s;
528 + s.sp.type = IHF_COMMAND_NEW_HOOK;
529 + s.sp.hp = *hp;
530 + DWORD len;
531 + if (name) len = wcslen(name) << 1;
532 + else len = 0;
533 + if (len >= IHS_BUFF_SIZE - 2) len = IHS_BUFF_SIZE - 2;
534 + memcpy(s.name_buffer, name, len);
535 + s.name_buffer[len] = 0;
536 + s.name_buffer[len + 1] = 0;
537 + IO_STATUS_BLOCK ios;
538 + NtWriteFile(hCmd, 0,0,0, &ios, &s, IHS_SIZE, 0, 0);
539 +
540 + //memcpy(&sp.hp,hp,sizeof(HookParam));
541 + //cmdq->AddRequest(sp, pid);
542 + return 0;
543 +}
544 +
545 +IHFSERVICE DWORD IHFAPI IHF_ModifyHook(DWORD pid, HookParam *hp)
546 +{
547 + ITH_SYNC_HOOK;
548 +
549 + SendParam sp;
550 + HANDLE hModify,hCmd;
551 + hCmd = GetCmdHandleByPID(pid);
552 + if (hCmd == 0)
553 + return -1;
554 + hModify = IthCreateEvent(ITH_MODIFYHOOK_EVENT);
555 + sp.type = IHF_COMMAND_MODIFY_HOOK;
556 + sp.hp = *hp;
557 + IO_STATUS_BLOCK ios;
558 + if (NT_SUCCESS(NtWriteFile(hCmd, 0,0,0, &ios, &sp, sizeof(SendParam), 0, 0)))
559 + // jichi 9/28/2013: no wait timeout
560 + //const LONGLONG timeout = HOOK_TIMEOUT;
561 + NtWaitForSingleObject(hModify, 0, nullptr);
562 + NtClose(hModify);
563 + man->RemoveSingleHook(pid, sp.hp.addr);
564 + return 0;
565 +}
566 +
567 +IHFSERVICE DWORD IHFAPI IHF_RemoveHook(DWORD pid, DWORD addr)
568 +{
569 + ITH_SYNC_HOOK;
570 +
571 + HANDLE hRemoved,hCmd;
572 + hCmd = GetCmdHandleByPID(pid);
573 + if (hCmd == 0)
574 + return -1;
575 + hRemoved = IthCreateEvent(ITH_REMOVEHOOK_EVENT);
576 + SendParam sp = {};
577 + IO_STATUS_BLOCK ios;
578 + sp.type = IHF_COMMAND_REMOVE_HOOK;
579 + sp.hp.addr = addr;
580 + //cmdq -> AddRequest(sp, pid);
581 + NtWriteFile(hCmd, 0,0,0, &ios, &sp, sizeof(SendParam),0,0);
582 + // jichi 10/22/2013: Timeout might crash vnrsrv
583 + //const LONGLONG timeout = HOOK_TIMEOUT;
584 + //NtWaitForSingleObject(hRemoved, 0, (PLARGE_INTEGER)&timeout);
585 + NtWaitForSingleObject(hRemoved, 0, nullptr);
586 + NtClose(hRemoved);
587 + man -> RemoveSingleHook(pid, sp.hp.addr);
588 + return 0;
589 +}
590 +
591 +IHFSERVICE DWORD IHFAPI IHF_IsAdmin() { return admin; }
592 +
593 +IHFSERVICE DWORD IHFAPI IHF_AddLink(DWORD from, DWORD to)
594 +{
595 + man->AddLink(from & 0xffff, to & 0xffff);
596 + return 0;
597 +}
598 +
599 +IHFSERVICE DWORD IHFAPI IHF_UnLink(DWORD from)
600 +{
601 + man->UnLink(from & 0xffff);
602 + return 0;
603 +}
604 +
605 +IHFSERVICE DWORD IHFAPI IHF_UnLinkAll(DWORD from)
606 +{
607 + man->UnLinkAll(from & 0xffff);
608 + return 0;
609 +}
610 +
611 +// EOF
1 +// pipe.cc
2 +// 8/24/2013 jichi
3 +// Branch IHF/pipe.cpp, rev 93
4 +// 8/24/2013 TODO: Clean up this file
5 +
6 +#include "srv_p.h"
7 +#include "hookman.h"
8 +#include "ith/common/defs.h"
9 +#include "ith/common/const.h"
10 +//#include "ith/common/growl.h"
11 +#include "ith/sys/sys.h"
12 +//#include "CommandQueue.h"
13 +
14 +//DWORD WINAPI UpdateWindows(LPVOID lpThreadParameter);
15 +
16 +namespace { // unnamed
17 +enum NamedPipeCommand {
18 + NAMED_PIPE_DISCONNECT = 1
19 + , NAMED_PIPE_CONNECT = 2
20 +};
21 +
22 +bool newline = false;
23 +bool detach = false;
24 +
25 +// jichi 10/27/2013
26 +// Check if text has leading space
27 +enum { _filter_limit = 0x20 }; // The same as the orignal ITH filter. So, I don't have to check \u3000
28 +//enum { _filter_limit = 0x19 };
29 +inline bool has_leading_space(const BYTE *text, int len)
30 +{
31 + return len == 1 ? *text <= _filter_limit : // 1 byte
32 + *reinterpret_cast<const WORD *>(text) <= _filter_limit; // 2 bytes
33 +}
34 +
35 +// jichi 9/28/2013: Skip leading garbage
36 +// Note:
37 +// - Modifying limit will break manual translation. The orignal one is 0x20
38 +// - Eliminating 0x20 will break English-translated games
39 +const BYTE *Filter(const BYTE *str, int len)
40 +{
41 +#ifdef ITH_DISABLE_FILTER // jichi 9/28/2013: only for debugging purpose
42 + return str;
43 +#endif // ITH_DISABLE_FILTER
44 +// if (len && *str == 0x10) // jichi 9/28/2013: garbage on wine, data link escape, or ^P
45 +// return nullptr;
46 + //enum { limit = 0x19 };
47 + while (true)
48 + if (len >= 2) {
49 + if (*(const WORD *)str <= _filter_limit) { // jichi 10/27/2013: two bytes
50 + str += 2;
51 + len -= 2;
52 + } else
53 + break;
54 + } else if (*str <= _filter_limit) { // jichi 10/27/2013: 1 byte
55 + str++;
56 + len--;
57 + } else
58 + break;
59 + return str;
60 +}
61 +} // unnamed namespace
62 +
63 +//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
64 +//WCHAR command_pipe[] = L"\\??\\pipe\\ITH_COMMAND";
65 +wchar_t recv_pipe[] = ITH_TEXT_PIPE;
66 +wchar_t command_pipe[] = ITH_COMMAND_PIPE;
67 +
68 +CRITICAL_SECTION detach_cs; // jichi 9/27/2013: also used in main
69 +//HANDLE hDetachEvent;
70 +extern HANDLE hPipeExist;
71 +
72 +void CreateNewPipe()
73 +{
74 + static DWORD acl[7] = {
75 + 0x1C0002,
76 + 1,
77 + 0x140000,
78 + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
79 + 0x101,
80 + 0x1000000,
81 + 0};
82 + static SECURITY_DESCRIPTOR sd = {1, 0, 4, 0, 0, 0, (PACL)acl};
83 +
84 + HANDLE hTextPipe, hCmdPipe, hThread;
85 + IO_STATUS_BLOCK ios;
86 + UNICODE_STRING us;
87 +
88 + OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
89 + LARGE_INTEGER time = {-500000, -1};
90 +
91 + RtlInitUnicodeString(&us, recv_pipe);
92 + if (!NT_SUCCESS(NtCreateNamedPipeFile(
93 + &hTextPipe,
94 + GENERIC_READ | SYNCHRONIZE,
95 + &oa,
96 + &ios,
97 + FILE_SHARE_WRITE,
98 + FILE_OPEN_IF,
99 + FILE_SYNCHRONOUS_IO_NONALERT,
100 + 1, 1, 0, -1,
101 + 0x1000,
102 + 0x1000,
103 + &time))) {
104 + //ConsoleOutput(ErrorCreatePipe);
105 + ConsoleOutput("vnrhost:CreateNewPipe: failed to create recv pipe");
106 + return;
107 + }
108 +
109 + RtlInitUnicodeString(&us, command_pipe);
110 + if (!NT_SUCCESS(NtCreateNamedPipeFile(
111 + &hCmdPipe,
112 + GENERIC_WRITE | SYNCHRONIZE,
113 + &oa,
114 + &ios,
115 + FILE_SHARE_READ,
116 + FILE_OPEN_IF,
117 + FILE_SYNCHRONOUS_IO_NONALERT,
118 + 1, 1, 0, -1,
119 + 0x1000,
120 + 0x1000,
121 + &time))) {
122 + //ConsoleOutput(ErrorCreatePipe);
123 + ConsoleOutput("vnrhost:CreateNewPipe: failed to create cmd pipe");
124 + return;
125 + }
126 +
127 + hThread = IthCreateThread(RecvThread, (DWORD)hTextPipe);
128 + man->RegisterPipe(hTextPipe, hCmdPipe, hThread);
129 +}
130 +
131 +void DetachFromProcess(DWORD pid)
132 +{
133 + HANDLE hMutex = INVALID_HANDLE_VALUE,
134 + hEvent = INVALID_HANDLE_VALUE;
135 + //try {
136 + IO_STATUS_BLOCK ios;
137 + ProcessRecord *pr = man->GetProcessRecord(pid);
138 + if (!pr)
139 + return;
140 + //IthBreak();
141 + hEvent = IthCreateEvent(nullptr);
142 + if (STATUS_PENDING == NtFsControlFile(
143 + man->GetCmdHandleByPID(pid),
144 + hEvent,
145 + 0,0,
146 + &ios,
147 + CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
148 + 0,0,0,0))
149 + NtWaitForSingleObject(hEvent, 0, 0);
150 + NtClose(hEvent);
151 + //hEvent = INVALID_HANDLE_VALUE;
152 +
153 + WCHAR mutex[0x20];
154 + swprintf(mutex, ITH_DETACH_MUTEX_ L"%d", pid);
155 + hMutex = IthOpenMutex(mutex);
156 + if (hMutex != INVALID_HANDLE_VALUE) {
157 + NtWaitForSingleObject(hMutex, 0, 0);
158 + NtReleaseMutant(hMutex, 0);
159 + NtClose(hMutex);
160 + //hMutex = INVALID_HANDLE_VALUE;
161 + }
162 +
163 + //} catch (...) {
164 + // if (hEvent != INVALID_HANDLE_VALUE)
165 + // NtClose(hEvent);
166 + // else if (hMutex != INVALID_HANDLE_VALUE) {
167 + // NtWaitForSingleObject(hMutex, 0, 0);
168 + // NtReleaseMutant(hMutex, 0);
169 + // NtClose(hMutex);
170 + // }
171 + //}
172 +
173 + //NtSetEvent(hDetachEvent, 0);
174 + if (::running)
175 + NtSetEvent(hPipeExist, 0);
176 +}
177 +
178 +// jichi 9/27/2013: I don't need this
179 +//void OutputDWORD(DWORD d)
180 +//{
181 +// WCHAR str[0x20];
182 +// swprintf(str, L"%.8X", d);
183 +// ConsoleOutput(str);
184 +//}
185 +
186 +DWORD WINAPI RecvThread(LPVOID lpThreadParameter)
187 +{
188 + HANDLE hTextPipe = (HANDLE)lpThreadParameter;
189 +
190 + IO_STATUS_BLOCK ios;
191 + NtFsControlFile(hTextPipe,
192 + 0, 0, 0,
193 + &ios,
194 + CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_CONNECT, 0, 0),
195 + 0, 0, 0, 0);
196 + if (!::running) {
197 + NtClose(hTextPipe);
198 + return 0;
199 + }
200 +
201 + BYTE *buff;
202 +
203 + enum { PipeBufferSize = 0x1000 };
204 + buff = new BYTE[PipeBufferSize];
205 + ITH_MEMSET_HEAP(buff, 0, PipeBufferSize); // jichi 8/27/2013: zero memory, or it will crash wine on start up
206 +
207 + // 10/19/2014 jichi: there are totally three words received
208 + // See: hook/rpc/pipe.cc
209 + // struct {
210 + // DWORD pid;
211 + // TextHook *man;
212 + // DWORD module;
213 + // //DWORD engine;
214 + // } u;
215 + enum { module_struct_size = 12 };
216 + NtReadFile(hTextPipe, 0, 0, 0, &ios, buff, module_struct_size, 0, 0);
217 +
218 + DWORD pid = *(DWORD *)buff,
219 + hookman = *(DWORD *)(buff + 0x4),
220 + module = *(DWORD *)(buff + 0x8);
221 + //engine = *(DWORD *)(buff + 0xc);
222 + man->RegisterProcess(pid, hookman, module);
223 +
224 + // jichi 9/27/2013: why recursion?
225 + CreateNewPipe();
226 +
227 + //NtClose(IthCreateThread(UpdateWindows,0));
228 + while (::running) {
229 + if (!NT_SUCCESS(NtReadFile(hTextPipe,
230 + 0, 0, 0,
231 + &ios,
232 + buff,
233 + 0xf80,
234 + 0, 0)))
235 + break;
236 +
237 + enum { data_offset = 0xc }; // jichi 10/27/2013: Seem to be the data offset in the pipe
238 +
239 + DWORD RecvLen = ios.uInformation;
240 + if (RecvLen < data_offset)
241 + break;
242 + DWORD hook = *(DWORD *)buff;
243 +
244 + union { DWORD retn; DWORD cmd_type; };
245 + union { DWORD split; DWORD new_engine_type; };
246 +
247 + retn = *(DWORD *)(buff + 4);
248 + split = *(DWORD *)(buff + 8);
249 +
250 + buff[RecvLen] = 0;
251 + buff[RecvLen + 1] = 0;
252 +
253 + if (hook == IHF_NOTIFICATION) {
254 + switch (cmd_type) {
255 + case IHF_NOTIFICATION_NEWHOOK:
256 + {
257 + static long lock;
258 + while (InterlockedExchange(&lock, 1) == 1);
259 + ProcessEventCallback new_hook = man->ProcessNewHook();
260 + if (new_hook)
261 + new_hook(pid);
262 + lock = 0;
263 + } break;
264 + case IHF_NOTIFICATION_TEXT:
265 + ConsoleOutput((LPCSTR)(buff + 8));
266 + break;
267 + }
268 + } else {
269 + // jichi 9/28/2013: Debug raw data
270 + //ITH_DEBUG_DWORD9(RecvLen - 0xc,
271 + // buff[0xc], buff[0xd], buff[0xe], buff[0xf],
272 + // buff[0x10], buff[0x11], buff[0x12], buff[0x13]);
273 +
274 + const BYTE *data = buff + data_offset; // th
275 + int len = RecvLen - data_offset;
276 + bool space = ::has_leading_space(data, len);
277 + if (space) {
278 + const BYTE *it = ::Filter(data, len);
279 + len -= it - data;
280 + data = it;
281 + }
282 + if (len >> 31) // jichi 10/27/2013: len is too large, which seldom happens
283 + len = 0;
284 + //man->DispatchText(pid, len ? data : nullptr, hook, retn, split, len, space);
285 + man->DispatchText(pid, data, hook, retn, split, len, space);
286 + }
287 + }
288 +
289 + EnterCriticalSection(&detach_cs);
290 +
291 + HANDLE hDisconnect = IthCreateEvent(nullptr);
292 +
293 + if (STATUS_PENDING == NtFsControlFile(
294 + hTextPipe,
295 + hDisconnect,
296 + 0, 0,
297 + &ios,
298 + CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
299 + 0, 0, 0, 0))
300 + NtWaitForSingleObject(hDisconnect, 0, 0);
301 +
302 + NtClose(hDisconnect);
303 + DetachFromProcess(pid);
304 + man->UnRegisterProcess(pid);
305 +
306 + //NtClearEvent(hDetachEvent);
307 +
308 + LeaveCriticalSection(&detach_cs);
309 + delete[] buff;
310 +
311 + if (::running)
312 + ConsoleOutput("vnrhost:DetachFromProcess: detached");
313 +
314 + //if (::running) {
315 + // swprintf((LPWSTR)buff, FormatDetach, pid);
316 + // ConsoleOutput((LPWSTR)buff);
317 + // NtClose(IthCreateThread(UpdateWindows, 0));
318 + //}
319 + return 0;
320 +}
321 +
322 +// EOF
1 +#pragma once
2 +
3 +// settings.h
4 +// 8/24/2013 jichi
5 +
6 +struct Settings {
7 + //bool debug; // whether output debug messages using pipes
8 + int splittingInterval;// time to split text into sentences
9 +
10 + Settings() : splittingInterval(200) {}
11 +
12 +};
13 +
14 +// EOF
1 +#pragma once
2 +
3 +// srv.h
4 +// 8/23/2013 jichi
5 +// Branch: ITH/IHF.h, rev 105
6 +
7 +#include "config.h"
8 +//#include "ith/host/settings.h"
9 +#include "ith/host/hookman.h"
10 +#include "ith/host/SettingManager.h"
11 +
12 +struct Settings;
13 +struct HookParam;
14 +
15 +// jichi 8/24/2013: Why extern "C"? Any specific reason to use C instead of C++ naming?
16 +extern "C" {
17 +IHFSERVICE DWORD IHFAPI IHF_Init();
18 +IHFSERVICE DWORD IHFAPI IHF_Start();
19 +IHFSERVICE DWORD IHFAPI IHF_Cleanup();
20 +IHFSERVICE DWORD IHFAPI IHF_GetPIDByName(LPCWSTR pwcTarget);
21 +IHFSERVICE DWORD IHFAPI IHF_InjectByPID(DWORD pid);
22 +IHFSERVICE DWORD IHFAPI IHF_ActiveDetachProcess(DWORD pid);
23 +IHFSERVICE DWORD IHFAPI IHF_GetHookManager(HookManager **hookman);
24 +IHFSERVICE DWORD IHFAPI IHF_GetSettingManager(SettingManager** set_man);
25 +IHFSERVICE DWORD IHFAPI IHF_GetSettings(Settings **settings);
26 +IHFSERVICE DWORD IHFAPI IHF_InsertHook(DWORD pid, HookParam *hp, LPCWSTR name = 0);
27 +IHFSERVICE DWORD IHFAPI IHF_ModifyHook(DWORD pid, HookParam *hp);
28 +IHFSERVICE DWORD IHFAPI IHF_RemoveHook(DWORD pid, DWORD addr);
29 +IHFSERVICE DWORD IHFAPI IHF_IsAdmin();
30 +//IHFSERVICE DWORD IHFAPI IHF_GetFilters(PVOID *mb_filter, PVOID *uni_filter);
31 +IHFSERVICE DWORD IHFAPI IHF_AddLink(DWORD from, DWORD to);
32 +IHFSERVICE DWORD IHFAPI IHF_UnLink(DWORD from);
33 +IHFSERVICE DWORD IHFAPI IHF_UnLinkAll(DWORD from);
34 +} // extern "C"
35 +
36 +// EOF
1 +#pragma once
2 +// srv_p.h
3 +// 8/24/2013 jichi
4 +// Branch IHF/main.h, rev 111
5 +#include "config.h"
6 +
7 +#define GLOBAL extern
8 +#define SHIFT_JIS 0x3A4
9 +class HookManager;
10 +//class CommandQueue;
11 +class SettingManager;
12 +class TextHook;
13 +//class BitMap;
14 +//class CustomFilterMultiByte;
15 +//class CustomFilterUnicode;
16 +//#define TextHook Hook
17 +GLOBAL BOOL running;
18 +//GLOBAL BitMap *pid_map;
19 +//GLOBAL CustomFilterMultiByte *mb_filter;
20 +//GLOBAL CustomFilterUnicode *uni_filter;
21 +GLOBAL HookManager *man;
22 +//GLOBAL CommandQueue *cmdq;
23 +GLOBAL SettingManager *setman;
24 +GLOBAL WCHAR recv_pipe[];
25 +GLOBAL WCHAR command[];
26 +GLOBAL HANDLE hPipeExist;
27 +GLOBAL DWORD split_time,
28 + cyclic_remove,
29 + clipboard_flag,
30 + global_filter;
31 +GLOBAL CRITICAL_SECTION detach_cs;
32 +
33 +DWORD WINAPI RecvThread(LPVOID lpThreadParameter);
34 +DWORD WINAPI CmdThread(LPVOID lpThreadParameter);
35 +
36 +void ConsoleOutput(LPCSTR text);
37 +void ConsoleOutputW(LPCWSTR text);
38 +DWORD GetCurrentPID();
39 +//DWORD GetProcessIDByPath(LPWSTR str);
40 +HANDLE GetCmdHandleByPID(DWORD pid);
41 +//DWORD Inject(HANDLE hProc);
42 +//DWORD InjectByPID(DWORD pid);
43 +//DWORD PIDByName(LPWSTR target);
44 +//DWORD Hash(LPCWSTR module, int length=-1);
45 +
46 +// EOF
1 +// textthread.cc
2 +// 8/24/2013 jichi
3 +// Branch IHF/TextThread.cpp, rev 133
4 +// 8/24/2013 TODO: Clean up this file
5 +
6 +#ifdef _MSC_VER
7 +# pragma warning (disable:4100) // C4100: unreference formal parameter
8 +#endif // _MSC_VER
9 +
10 +#include "config.h"
11 +#include "settings.h"
12 +#include "textthread.h"
13 +#include "ith/common/const.h"
14 +#include "ith/sys/sys.h"
15 +#include "SettingManager.h"
16 +
17 +MK_BASIC_TYPE(BYTE)
18 +MK_BASIC_TYPE(ThreadParameter)
19 +
20 +static DWORD MIN_DETECT = 0x20;
21 +static DWORD MIN_REDETECT = 0x80;
22 +//#define MIN_DETECT 0x20
23 +//#define MIN_REDETECT 0x80
24 +#ifndef CURRENT_SELECT
25 +# define CURRENT_SELECT 0x1000
26 +#endif
27 +#ifndef REPEAT_NUMBER_DECIDED
28 +# define REPEAT_NUMBER_DECIDED 0x2000
29 +#endif
30 +
31 +DWORD GetHookName(LPWSTR str, DWORD pid, DWORD hook_addr,DWORD max);
32 +
33 +extern SettingManager* setman;
34 +extern Settings *settings;
35 +extern HWND hMainWnd;
36 +void CALLBACK NewLineBuff(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
37 +{
38 + KillTimer(hwnd,idEvent);
39 + TextThread *id=(TextThread*)idEvent;
40 +
41 + if (id->Status()&CURRENT_SELECT)
42 + //texts->SetLine();
43 + id->CopyLastToClipboard();
44 + id->SetNewLineFlag();
45 +}
46 +
47 +// jichi 10/27/2013: removed
48 +//void CALLBACK NewLineConsole(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
49 +//{
50 +// KillTimer(hwnd,idEvent);
51 +// TextThread *id=(TextThread*)idEvent;
52 +// if (id->Status()&USING_UNICODE)
53 +// id->AddText((BYTE*)L"\r\n",4,true,true);
54 +// if (id->Status()&CURRENT_SELECT)
55 +// {
56 +// //texts->SetLine();
57 +// }
58 +//}
59 +
60 +// jichi 10/27/2013: removed
61 +//void ReplaceSentence(BYTE* text, int len)
62 +//{
63 +// __asm int 3
64 +//}
65 +
66 +TextThread::TextThread(DWORD id, DWORD hook, DWORD retn, DWORD spl, WORD num) :
67 + //,tp
68 + thread_number(num)
69 + // jichi 9/21/2013: zero all fields
70 + , link_number(-1)
71 + , last (0)
72 + , align_space(0)
73 + , repeat_single(0)
74 + , repeat_single_current(0)
75 + , repeat_single_count(0)
76 + , repeat_detect_count(0)
77 + , head(new RepeatCountNode())
78 + , link(nullptr)
79 + //, filter(nullptr)
80 + , output(nullptr)
81 + , app_data(nullptr)
82 + //, comment(nullptr)
83 + , thread_string(nullptr)
84 + , timer(0)
85 + , status (0)
86 + , repeat_detect_limit(0x80)
87 + , last_sentence(0)
88 + , prev_sentence(0)
89 + , sentence_length(0)
90 + , repeat_index(0)
91 + , last_time(0)
92 +// , tp({id, hook, retn, spl})
93 +{
94 + tp.pid = id;
95 + tp.hook = hook;
96 + tp.retn = retn;
97 + tp.spl = spl;
98 + //head = new RepeatCountNode;
99 + //ITH_MEMSET_HEAP(head, 0, sizeof(RepeatCountNode)); // jichi 9/21/2013: zero memory
100 + //link_number = -1;
101 + //repeat_detect_limit = 0x80;
102 + //filter = nullptr;
103 + //output = nullptr;
104 +}
105 +TextThread::~TextThread()
106 +{
107 + //KillTimer(hMainWnd,timer);
108 + RepeatCountNode *t = head,
109 + *tt;
110 + while (t) {
111 + tt = t;
112 + t = tt->next;
113 + delete tt;
114 + }
115 + head = nullptr;
116 + //if (comment) {
117 + // delete[] comment;
118 + // comment = nullptr;
119 + //}
120 + if (thread_string)
121 + delete[] thread_string;
122 +}
123 +void TextThread::Reset()
124 +{
125 + //timer=0;
126 + last_sentence = 0;
127 + //if (comment) {
128 + // delete[] comment;
129 + // comment = nullptr;
130 + //}
131 + MyVector::Reset();
132 +}
133 +void TextThread::RemoveSingleRepeatAuto(const BYTE *con, int &len)
134 +{
135 +#ifdef ITH_DISABLE_REPEAT // jichi 9/28/2013: only for debugging purpose
136 + return;
137 +#endif // ITH_DISABLE_REPEAT
138 + WORD *text = (WORD *)con;
139 + if (len <= 2) {
140 + if (repeat_single) {
141 + if (repeat_single_count<repeat_single&&
142 + last == *text) {
143 + len = 0;
144 + repeat_single_count++;
145 + } else {
146 + last = *text;
147 + repeat_single_count=0;
148 + }
149 + }
150 + if (status & REPEAT_NUMBER_DECIDED) {
151 + if (++repeat_detect_count>MIN_REDETECT) {
152 + repeat_detect_count = 0;
153 + status ^= REPEAT_NUMBER_DECIDED;
154 + last = 0;
155 + RepeatCountNode *t = head,
156 + *tt;
157 + while (t) {
158 + tt = t;
159 + t = tt->next;
160 + delete tt;
161 + }
162 + head = new RepeatCountNode;
163 + ITH_MEMSET_HEAP(head, 0, sizeof(RepeatCountNode)); // jichi 9/21/2013: zero memory
164 + }
165 + } else {
166 + repeat_detect_count++;
167 + if (last == *text)
168 + repeat_single_current++;
169 + else {
170 + if (last == 0) {
171 + last = *text;
172 + return;
173 + }
174 + if (repeat_single_current == 0) {
175 + status |= REPEAT_NUMBER_DECIDED;
176 + repeat_single = 0;
177 + return;
178 + }
179 + last = *text;
180 + RepeatCountNode *it = head;
181 + if (repeat_detect_count > MIN_DETECT) {
182 + while (it = it->next)
183 + if (it->count>head->count) {
184 + head->count=it->count;
185 + head->repeat=it->repeat;
186 + }
187 + repeat_single = head->repeat;
188 + repeat_single_current = 0;
189 + repeat_detect_count = 0;
190 + status |= REPEAT_NUMBER_DECIDED;
191 + DWORD repeat_sc = repeat_single*4;
192 + if (repeat_sc > MIN_DETECT) {
193 + MIN_DETECT <<= 1;
194 + MIN_REDETECT <<= 1;
195 + }
196 + } else {
197 + bool flag=true;
198 + while (it) {
199 + if (it->repeat == repeat_single_current) {
200 + it->count++;
201 + flag = false;
202 + break;
203 + }
204 + it=it->next;
205 + }
206 + if (flag) {
207 + RepeatCountNode *n = new RepeatCountNode;
208 + n->count = 1;
209 + n->repeat = repeat_single_current;
210 + n->next = head->next;
211 + head->next = n;
212 + }
213 + repeat_single_current = 0;
214 + } //Decide repeat_single
215 + } //Check Repeat
216 + } //repeat_single decided?
217 + } //len
218 + else {
219 + status |= REPEAT_NUMBER_DECIDED;
220 + repeat_single = 0;
221 + }
222 +}
223 +
224 +void TextThread::RemoveSingleRepeatForce(BYTE *con,int &len)
225 +{
226 + // jichi 9/1/2013: manual repetition count removed
227 + WORD *text = (WORD *)con;
228 + //if (repeat_single_count<setman->GetValue(SETTING_REPEAT_COUNT)&&last==*text) {
229 + // len=0;
230 + // repeat_single_count++;
231 + //}
232 + //else
233 + {
234 + last = *text;
235 + repeat_single_count=0;
236 + }
237 +}
238 +void TextThread::RemoveCyclicRepeat(BYTE* &con, int &len)
239 +{
240 + DWORD currnet_time = GetTickCount();
241 + if (status & REPEAT_SUPPRESS) {
242 + if (currnet_time - last_time < (unsigned)settings->splittingInterval &&
243 + ::memcmp(storage + last_sentence + repeat_index, con, len) == 0) {
244 + repeat_index += len;
245 + if (repeat_index>=sentence_length)
246 + repeat_index -= sentence_length;
247 + len = 0;
248 + } else {
249 + repeat_index = 0;
250 + status &= ~REPEAT_SUPPRESS;
251 + }
252 + } else if (status & REPEAT_DETECT) {
253 + if (::memcmp(storage + last_sentence + repeat_index, con, len) == 0) {
254 + int half_length=repeat_index+len;
255 + if (::memcmp(storage + last_sentence, storage + last_sentence + half_length, repeat_index) == 0) {
256 + len=0;
257 + sentence_length=half_length;
258 + status&=~REPEAT_DETECT;
259 + status|=REPEAT_SUPPRESS;
260 +
261 + // jichi 10/27/2013: Not used
262 + //if (status&CURRENT_SELECT)
263 + // ReplaceSentence(storage+last_sentence+half_length,repeat_index);
264 + ClearMemory(last_sentence+half_length,repeat_index);
265 + used-=repeat_index;
266 + repeat_index=0;
267 + }
268 + else
269 + repeat_index += len;
270 + }
271 + else {
272 + repeat_index=0;
273 + status &= ~REPEAT_DETECT;
274 + }
275 + } else {
276 + if (sentence_length == 0)
277 + return;
278 + else if (len <= (int)sentence_length) {
279 + if (memcmp(storage + last_sentence, con, len) == 0) {
280 + status |= REPEAT_DETECT;
281 + repeat_index = len;
282 + if (repeat_index == sentence_length) {
283 + repeat_index = 0;
284 + len = 0;
285 + }
286 + } else if (sentence_length > repeat_detect_limit) {
287 + if (len > 2) {
288 + DWORD u = used;
289 + while (memcmp(storage + u - len, con, len) == 0)
290 + u -= len;
291 + ClearMemory(u, used - u);
292 + used = u;
293 + repeat_index = 0;
294 + // jichi 10/27/2013: Not used
295 + //if (status & CURRENT_SELECT)
296 + // ReplaceSentence(storage + last_sentence, used - u);
297 + status |= REPEAT_SUPPRESS;
298 + len = 0;
299 + } else if (len <= 2)
300 + {
301 + WORD tmp = *(WORD *)(storage + last_sentence);
302 + DWORD index, last_index, tmp_len;
303 + index = used-len;
304 + if (index < last_sentence)
305 + index = last_sentence;
306 + //Locate position of current input.
307 +_again:
308 + *(WORD *)(storage+last_sentence) = *(WORD *)con;
309 + while (*(WORD *)(storage + index) != *(WORD *)con)
310 + index--;
311 + *(WORD *)(storage + last_sentence) = tmp;
312 + if (index > last_sentence) {
313 + tmp_len = used - index;
314 + if (tmp_len <= 2) {
315 + repeat_detect_limit += 0x40;
316 + last_time = currnet_time;
317 + return;
318 + }
319 + if (index - last_sentence >= tmp_len &&
320 + memcmp(storage + index - tmp_len, storage + index, tmp_len) == 0) {
321 + repeat_detect_limit = 0x80;
322 + sentence_length =tmp_len;
323 + index -= tmp_len;
324 + while (memcmp(storage + index - sentence_length, storage + index, sentence_length) == 0)
325 + index -= sentence_length;
326 + repeat_index = 2;
327 + len = 0;
328 + last_index = index;
329 + if (status&USING_UNICODE) {
330 + while (storage[index] == storage[index + sentence_length])
331 + index -= 2;
332 + index += 2;
333 + while (true) {
334 + tmp = *(WORD *)(storage + index);
335 + if (tmp >= 0x3000 && tmp < 0x3020)
336 + index += 2;
337 + else
338 + break;
339 + }
340 + } else {
341 + DWORD last_char_len;
342 + while (storage[index] == storage[index + sentence_length]) {
343 + last_char_len = LeadByteTable[storage[index]];
344 + index -= last_char_len;
345 + }
346 + index += last_char_len;
347 + while (storage[index] == 0x81) {
348 + if ((storage[index+1]>>4) == 4)
349 + index += 2;
350 + else
351 + break;
352 + }
353 + }
354 + repeat_index += last_index - index;
355 + status |= REPEAT_SUPPRESS;
356 + last_sentence = index;
357 +
358 + index += sentence_length;
359 + // jichi 10/27/2013: Not used
360 + //if (status&CURRENT_SELECT)
361 + // ReplaceSentence(storage + index, used - index);
362 +
363 + ClearMemory(index, used - index);
364 + //memset(storage + index, 0, used - index);
365 + used = index;
366 + } else {
367 + index--;
368 + goto _again;
369 + }
370 + }
371 + else
372 + repeat_detect_limit += 0x40;
373 + }
374 + }
375 + }
376 + }
377 + last_time = currnet_time;
378 +}
379 +
380 +void TextThread::ResetRepeatStatus()
381 +{
382 + last=0;
383 + repeat_single=0;
384 + repeat_single_current=0;
385 + repeat_single_count=0;
386 + repeat_detect_count=0;
387 + RepeatCountNode *t = head->next,
388 + *tt;
389 + while (t) {
390 + tt = t;
391 + t = tt->next;
392 + delete tt;
393 + }
394 + //head=new RepeatCountNode;
395 + head->count = head->repeat = 0;
396 + status &= ~REPEAT_NUMBER_DECIDED;
397 +}
398 +void TextThread::AddLineBreak()
399 +{
400 + if (sentence_length == 0) return;
401 + if (status&BUFF_NEWLINE)
402 + {
403 + prev_sentence=last_sentence;
404 + sentence_length=0;
405 + if (status & USING_UNICODE)
406 + AddToStore((BYTE *)L"\r\n\r\n", 8);
407 + else
408 + AddToStore((BYTE *)"\r\n\r\n", 4);
409 + if (output)
410 + output(this, 0, 8, TRUE, app_data, false); // jichi 10/27/2013: space is false
411 + last_sentence = used;
412 + status &= ~BUFF_NEWLINE;
413 + }
414 +}
415 +void TextThread::AddText(const BYTE *con, int len, bool new_line, bool space)
416 +{
417 + if (!con || (len <= 0 && !space))
418 + return;
419 + if (len && !new_line) {
420 + // jichi 9/1/2013: manual repetition count removed
421 + //if (setman->GetValue(SETTING_REPEAT_COUNT)) {
422 + // status|=REPEAT_NUMBER_DECIDED;
423 + // RemoveSingleRepeatForce(con,len);
424 + //}
425 + //else
426 + RemoveSingleRepeatAuto(con, len);
427 + if (len <= 0 && !space)
428 + return;
429 + }
430 +
431 + // jichi 9/1/2013: manual repetition count removed
432 + //if(setman->GetValue(SETTING_CYCLIC_REMOVE)) {
433 + // //if (status & REPEAT_NUMBER_DECIDED)
434 + // RemoveCyclicRepeat(con,len);
435 + //}
436 + //if (len <= 0)
437 + // return;
438 +
439 + // jichi 10/27/2013: User-defined filter callback is disabled
440 + //if (filter)
441 + // len = filter(this, con,len, new_line, app_data);
442 + //if (len <= 0)
443 + // return;
444 +
445 + if (len && sentence_length == 0) {
446 + if (status & USING_UNICODE) {
447 + if (*(WORD *)con == 0x3000) { // jichi 10/27/2013: why skip unicode space?!
448 + con += 2;
449 + len -= 2;
450 + }
451 + } else if (*(WORD *)con == 0x4081) {
452 + con += 2;
453 + len -= 2;
454 + }
455 +
456 + if (len <= 0 && !space)
457 + return;
458 + }
459 +
460 + if (status & BUFF_NEWLINE)
461 + AddLineBreak();
462 +
463 + if (len)
464 + if (new_line) {
465 + prev_sentence = last_sentence;
466 + last_sentence = used + 4;
467 + if (status & USING_UNICODE)
468 + last_sentence += 4;
469 + sentence_length = 0;
470 + } else {
471 + SetNewLineTimer();
472 + if (link) {
473 + const BYTE *send = con;
474 + int l = len;
475 + if (status & USING_UNICODE) { // Although unlikely, a thread and its link may have different encoding.
476 + if ((link->Status() & USING_UNICODE) == 0) {
477 + send = new BYTE[l];
478 + //ITH_MEMSET_HEAP(send, 0, l); // jichi 9/26/2013: zero memory
479 + l = WC_MB((LPWSTR)con, (char *)send);
480 + }
481 + link->AddTextDirect(send, l, space);
482 + } else {
483 + if (link->Status() & USING_UNICODE) {
484 + size_t sz = len * 2 + 2;
485 + send = new BYTE[sz];
486 + //ITH_MEMSET_HEAP(send, 0, sz); // jichi 9/26/2013: zero memory
487 + l = MB_WC((char *)con, (LPWSTR)send) << 1;
488 + }
489 + link->AddTextDirect(send, l, space);
490 + }
491 + link->SetNewLineTimer();
492 + if (send != con)
493 + delete[] send;
494 + }
495 + sentence_length += len;
496 + }
497 +
498 + BYTE *data = const_cast<BYTE *>(con); // jichi 10/27/2013: TODO: Figure out where con is modified
499 + if (output)
500 + len = output(this, data, len, new_line, app_data, space);
501 + if (AddToStore(data, len)) {
502 + //sentence_length += len;
503 + /*ResetRepeatStatus();
504 + last_sentence=0;
505 + prev_sentence=0;
506 + sentence_length=len;
507 + repeat_index=0;
508 + status&=~REPEAT_DETECT|REPEAT_SUPPRESS; */
509 + }
510 +}
511 +
512 +void TextThread::AddTextDirect(const BYTE* con, int len, bool space) // Add to store directly, penetrating repetition filters.
513 +{
514 + // jichi 10/27/2013: Accordig to the logic, both len and con must be > 0
515 + if (status & BUFF_NEWLINE)
516 + AddLineBreak();
517 + SetNewLineTimer();
518 + if (link) {
519 + const BYTE *send = con;
520 + int l = len;
521 + if (status & USING_UNICODE) {
522 + if ((link->Status()&USING_UNICODE) == 0) {
523 + send = new BYTE[l];
524 + //ITH_MEMSET_HEAP(send, 0, l); // jichi 9/26/2013: zero memory
525 + l = WC_MB((LPWSTR)con,(char*)send);
526 + }
527 + link->AddText(send, l, false, space); // new_line is false
528 + } else {
529 + if (link->Status()&USING_UNICODE) {
530 + size_t sz = len * 2 + 2;
531 + send = new BYTE[sz];
532 + //ITH_MEMSET_HEAP(send, 0, sz); // jichi 9/26/2013: zero memory
533 + l = MB_WC((char *)con, (LPWSTR)send) << 1;
534 + }
535 + link->AddText(send, l, false, space); // new_line is false
536 + }
537 + link->SetNewLineTimer();
538 + if (send != con)
539 + delete[] send;
540 + }
541 + sentence_length += len;
542 +
543 + BYTE *data = const_cast<BYTE *>(con); // jichi 10/27/2013: TODO: Figure out where con is modified
544 + if (output)
545 + len = output(this, data, len, false, app_data, space);
546 + AddToStore(data, len);
547 +}
548 +
549 +DWORD TextThread::GetEntryString(LPWSTR str, DWORD max)
550 +{
551 + DWORD len = 0;
552 + if (str && max > 0x40) {
553 + max--;
554 + if (thread_string) {
555 + len = wcslen(thread_string);
556 + len = len < max ? len : max;
557 + memcpy(str, thread_string, len << 1);
558 + str[len] = 0;
559 +
560 + } else {
561 + len = swprintf(str, L"%.4X:%.4d:0x%08X:0x%08X:0x%08X:",
562 + thread_number, tp. pid, tp.hook, tp.retn, tp.spl);
563 +
564 + len += GetHookName(str + len, tp.pid, tp.hook, max - len);
565 + thread_string = new wchar_t[len + 1];
566 + //ITH_MEMSET_HEAP(thread_string, 0, (len+1) * sizeof(wchar_t)); // jichi 9/26/2013: zero memory
567 + thread_string[len] = 0;
568 + memcpy(thread_string, str, len * sizeof(wchar_t));
569 + }
570 + //if (comment) {
571 + // str += len;
572 + // max--;
573 + // DWORD cl = wcslen(comment);
574 + // if (len + cl >= max)
575 + // cl = max - len;
576 + // *str++ = L'-';
577 + // memcpy(str, comment, cl << 1);
578 + // str[cl] = 0;
579 + // len += cl;
580 + //}
581 + }
582 + return len;
583 +}
584 +// jichi 9/28/2013: removed
585 +//void TextThread::CopyLastSentence(LPWSTR str)
586 +//{
587 +// int i,j,l;
588 +// if (status&USING_UNICODE)
589 +// {
590 +// if (used>8)
591 +// {
592 +// j=used>0xF0?(used-0xF0):0;
593 +// for (i=used-0xA;i>=j;i-=2)
594 +// {
595 +// if (*(DWORD*)(storage+i)==0xA000D) break;
596 +// }
597 +// if (i>=j)
598 +// {
599 +// l=used-i;
600 +// if (i>j) l-=4;
601 +// j=4;
602 +// }
603 +// else
604 +// {
605 +// i+=2;
606 +// l=used-i;
607 +// j=0;
608 +// }
609 +// memcpy(str,storage+i+j,l);
610 +// str[l>>1]=0;
611 +// }
612 +// else
613 +// {
614 +// memcpy(str,storage,used);
615 +// str[used>>1]=0;
616 +// }
617 +// }
618 +// else
619 +// {
620 +// if (used>4)
621 +// {
622 +// j=used>0x80?(used-0x80):0;
623 +// for (i=used-5;i>=j;i--)
624 +// {
625 +// if (*(DWORD*)(storage+i)==0xA0D0A0D) break;
626 +// }
627 +// if (i>=j)
628 +// {
629 +// l=used-i;
630 +// if (i>j) l-=4;
631 +// j=4;
632 +// }
633 +// else
634 +// {
635 +// i++;
636 +// l=used-i;
637 +// j=0;
638 +// }
639 +// size_t sz = (l|0xF) + 1;
640 +// char *buff = new char[sz];
641 +// //memset(buff, 0, sz); // jichi 9/26/2013: zero memory
642 +// memcpy(buff, storage + i + j, l);
643 +// buff[l] = 0;
644 +// str[MB_WC(buff, str)] = 0;
645 +// delete[] buff;
646 +// } else {
647 +// storage[used] = 0;
648 +// str[MB_WC((char *)storage, str)] = 0;
649 +// }
650 +// }
651 +//}
652 +
653 +static char clipboard_buffer[0x400];
654 +// jichi 8/25/2013: clipboard removed
655 +void CopyToClipboard(void* str,bool unicode, int len)
656 +{
657 + if (setman->GetValue(SETTING_CLIPFLAG) && str && len > 0)
658 + {
659 + int size=(len*2|0xF)+1;
660 + if (len>=1022) return;
661 + memcpy(clipboard_buffer,str,len);
662 + *(WORD*)(clipboard_buffer+len)=0;
663 + HGLOBAL hCopy;
664 + LPWSTR copy;
665 + if (OpenClipboard(0))
666 + {
667 + if (hCopy=GlobalAlloc(GMEM_MOVEABLE,size))
668 + {
669 + if (copy=(LPWSTR)GlobalLock(hCopy))
670 + {
671 + if (unicode)
672 + {
673 + memcpy(copy,clipboard_buffer,len+2);
674 + }
675 + else
676 + copy[MB_WC(clipboard_buffer,copy)]=0;
677 + GlobalUnlock(hCopy);
678 + EmptyClipboard();
679 + SetClipboardData(CF_UNICODETEXT,hCopy);
680 + }
681 + }
682 + CloseClipboard();
683 + }
684 + }
685 +}
686 +void TextThread::CopyLastToClipboard()
687 +{
688 + // jichi 8/25/2013: clipboard removed
689 + CopyToClipboard(storage+last_sentence,(status&USING_UNICODE)>0,used-last_sentence);
690 +}
691 +
692 +//void TextThread::ResetEditText()
693 +//{
694 +// //__asm int 3;
695 +// WCHAR str[0x20];
696 +// swprintf(str,L"%.8X",_ReturnAddress());
697 +//}
698 +
699 +// jichi 9/25/2013: Removed
700 +//void TextThread::ExportTextToFile(LPWSTR) //filename)
701 +//{
702 +// HANDLE hFile=IthCreateFile(filename,FILE_WRITE_DATA,0,FILE_OPEN_IF);
703 +// if (hFile==INVALID_HANDLE_VALUE) return;
704 +// EnterCriticalSection(&cs_store);
705 +// IO_STATUS_BLOCK ios;
706 +// LPVOID buffer=storage;
707 +// DWORD len=used;
708 +// BYTE bom[4]={0xFF,0xFE,0,0};
709 +// LARGE_INTEGER offset={2,0};
710 +// if ((status&USING_UNICODE)==0)
711 +// {
712 +// len=MB_WC_count((char*)storage,used);
713 +// buffer = new wchar_t[len+1];
714 +// MB_WC((char*)storage,(wchar_t*)buffer);
715 +// len<<=1;
716 +// }
717 +// NtWriteFile(hFile,0,0,0,&ios,bom,2,0,0);
718 +// NtWriteFile(hFile,0,0,0,&ios,buffer,len,&offset,0);
719 +// NtFlushBuffersFile(hFile,&ios);
720 +// if (buffer !=storage)
721 +// delete[] buffer;
722 +// NtClose(hFile);
723 +// LeaveCriticalSection(&cs_store);
724 +//}
725 +
726 +//void TextThread::SetComment(LPWSTR str)
727 +//{
728 +// if (comment)
729 +// delete[] comment;
730 +// size_t sz = wcslen(str);
731 +// comment = new wchar_t[sz + 1];
732 +// comment[sz] = 0;
733 +// wcscpy(comment, str);
734 +//}
735 +
736 +void TextThread::SetNewLineFlag() { status |= BUFF_NEWLINE; }
737 +
738 +bool TextThread::CheckCycle(TextThread* start)
739 +{
740 + if (link==start||this==start) return true;
741 + if (link==0) return false;
742 + return link->CheckCycle(start);
743 +}
744 +void TextThread::SetNewLineTimer()
745 +{
746 + if (thread_number == 0)
747 + // jichi 10/27/2013: Not used
748 + timer = 0; //SetTimer(hMainWnd,(UINT_PTR)this, settings->splittingInterval, NewLineConsole);
749 + else
750 + timer = SetTimer(hMainWnd,(UINT_PTR)this, settings->splittingInterval, NewLineBuff);
751 +}
752 +
753 +DWORD TextThread::GetThreadString(LPWSTR str, DWORD max)
754 +{
755 + DWORD len = 0;
756 + if (max) {
757 + wchar_t buffer[0x200];
758 + wchar_t c;
759 + if (thread_string == nullptr)
760 + GetEntryString(buffer, 0x200); //This will allocate thread_string.
761 + LPWSTR p1,
762 + end;
763 + for (end = thread_string; *end; end++);
764 + c = thread_string[0];
765 + thread_string[0] = L':';
766 + for (p1 = end; *p1 != L':'; p1--);
767 + thread_string[0] = c;
768 + if (p1 == thread_string)
769 + return 0;
770 + p1++;
771 + len = end - p1;
772 + if (len >= max)
773 + len = max;
774 + memcpy(str, p1, len << 1);
775 + str[len] = 0;
776 + }
777 +
778 + return len;
779 +}
780 +void TextThread::UnLinkAll()
781 +{
782 + if (link) link->UnLinkAll();
783 + link = 0;
784 + link_number = -1;
785 +}
786 +
787 +// EOF
1 +#pragma once
2 +
3 +// textthread.h
4 +// 8/23/2013 jichi
5 +// Branch: ITH/TextThread.h, rev 120
6 +
7 +#include "ith/host/textthread_p.h"
8 +#include <intrin.h> // require _InterlockedExchange
9 +
10 +struct RepeatCountNode {
11 + short repeat;
12 + short count;
13 + RepeatCountNode *next;
14 +
15 + //RepeatCountNode() : repeat(0), count(0), next(nullptr) {}
16 +};
17 +
18 +struct ThreadParameter {
19 + DWORD pid; // jichi: 5/11/2014: The process ID
20 + DWORD hook;
21 + DWORD retn; // jichi 5/11/2014: The return address of the hook
22 + DWORD spl; // jichi 5/11/2014: the processed split value of the hook parameter
23 +};
24 +
25 +#define CURRENT_SELECT 0x1000
26 +#define REPEAT_NUMBER_DECIDED 0x2000
27 +#define BUFF_NEWLINE 0x4000
28 +#define CYCLIC_REPEAT 0x8000
29 +#define COUNT_PER_FOWARD 0x200
30 +#define REPEAT_DETECT 0x10000
31 +#define REPEAT_SUPPRESS 0x20000
32 +#define REPEAT_NEWLINE 0x40000
33 +
34 +class TextThread;
35 +typedef void (* ConsoleCallback)(LPCSTR text);
36 +typedef void (* ConsoleWCallback)(LPCWSTR text);
37 +typedef DWORD (* ThreadOutputFilterCallback)(TextThread *, BYTE *, DWORD, DWORD, PVOID, bool space); // jichi 10/27/2013: Add space
38 +typedef DWORD (* ThreadEventCallback)(TextThread *);
39 +
40 +//extern DWORD split_time,repeat_count,global_filter,cyclic_remove;
41 +
42 +class TextThread : public MyVector<BYTE, 0x200>
43 +{
44 +public:
45 + TextThread(DWORD pid, DWORD hook, DWORD retn, DWORD spl, WORD num);
46 + ~TextThread();
47 + //virtual void CopyLastSentence(LPWSTR str);
48 + //virtual void SetComment(LPWSTR);
49 + //virtual void ExportTextToFile(LPWSTR filename);
50 +
51 + virtual bool CheckCycle(TextThread *start);
52 + virtual DWORD GetThreadString(LPWSTR str, DWORD max);
53 + virtual DWORD GetEntryString(LPWSTR str, DWORD max = 0x200);
54 +
55 + void Reset();
56 + void AddText(const BYTE *con,int len, bool new_line, bool space); // jichi 10/27/2013: add const; remove console; add space
57 + void RemoveSingleRepeatAuto(const BYTE *con, int &len); // jichi 10/27/2013: add const
58 + void RemoveSingleRepeatForce(BYTE *con, int &len);
59 + void RemoveCyclicRepeat(BYTE *&con, int &len);
60 + void ResetRepeatStatus();
61 + void AddLineBreak();
62 + //void ResetEditText();
63 + void ComboSelectCurrent();
64 + void UnLinkAll();
65 + void CopyLastToClipboard();
66 +
67 + //void AdjustPrevRepeat(DWORD len);
68 + //void PrevRepeatLength(DWORD &len);
69 +
70 + //bool AddToCombo();
71 + bool RemoveFromCombo();
72 +
73 + void SetNewLineFlag();
74 + void SetNewLineTimer();
75 +
76 + BYTE *GetStore(DWORD *len) { if (len) *len = used; return storage; }
77 + DWORD LastSentenceLen() { return used - last_sentence; }
78 + DWORD PID() const { return tp.pid; }
79 + DWORD Addr() const {return tp.hook; }
80 + DWORD &Status() { return status; }
81 + WORD Number() const { return thread_number; }
82 + WORD &Last() { return last; }
83 + WORD &LinkNumber() { return link_number; }
84 + UINT_PTR &Timer() { return timer; }
85 + ThreadParameter *GetThreadParameter() { return &tp; }
86 + TextThread *&Link() { return link; }
87 + //LPCWSTR GetComment() { return comment; }
88 +
89 + ThreadOutputFilterCallback RegisterOutputCallBack(ThreadOutputFilterCallback cb, PVOID data)
90 + {
91 + app_data = data;
92 + return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&output,(long)cb);
93 + }
94 +
95 + ThreadOutputFilterCallback RegisterFilterCallBack(ThreadOutputFilterCallback cb, PVOID data)
96 + {
97 + app_data = data;
98 + return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&filter,(long)cb);
99 + }
100 +
101 + void SetRepeatFlag() { status |= CYCLIC_REPEAT; }
102 + void ClearNewLineFlag() { status &= ~BUFF_NEWLINE; }
103 + void ClearRepeatFlag() { status &= ~CYCLIC_REPEAT; }
104 +
105 +protected:
106 + void AddTextDirect(const BYTE *con, int len, bool space); // jichi 10/27/2013: add const; add space; change to protected
107 +
108 +private:
109 + ThreadParameter tp;
110 +
111 + WORD thread_number,
112 + link_number;
113 + WORD last,
114 + align_space;
115 + WORD repeat_single;
116 + WORD repeat_single_current;
117 + WORD repeat_single_count;
118 + WORD repeat_detect_count;
119 + RepeatCountNode *head;
120 +
121 + TextThread *link;
122 + ThreadOutputFilterCallback filter; // jichi 10/27/2013: Remove filter
123 + ThreadOutputFilterCallback output;
124 + PVOID app_data;
125 + //LPWSTR comment,
126 + LPWSTR thread_string;
127 + UINT_PTR timer;
128 + DWORD status,repeat_detect_limit;
129 + DWORD last_sentence,
130 + prev_sentence,
131 + sentence_length,
132 + repeat_index,
133 + last_time;
134 +};
135 +
136 +// EOF
1 +#pragma once
2 +// textthread_p.h
3 +// 8/14/2013 jichi
4 +// Branch: ITH/main_template.h, rev 66
5 +
6 +#include "config.h"
7 +
8 +template <typename T>
9 +void Release(const T &p) { delete p; }
10 +
11 +// Prevent memory release.
12 +// Used when T is basic types and will be automatically released (on stack).
13 +#define MK_BASIC_TYPE(T) \
14 + template<> \
15 + void Release<T>(const T &p) {}
16 +
17 +template<class T>
18 +struct BinaryEqual {
19 + bool operator ()(const T &a, const T &b, DWORD) { return a == b; }
20 +};
21 +
22 +template<class T, int default_size, class fComp=BinaryEqual<T> >
23 +class MyVector
24 +{
25 +public:
26 + MyVector() : size(default_size), used(0)
27 + {
28 + InitializeCriticalSection(&cs_store);
29 + storage = new T[size];
30 + // jichi 9/21/2013: zero memory
31 + // This would cause trouble if T is not an atomic type
32 + ITH_MEMSET_HEAP(storage, 0, sizeof(T) * size);
33 + }
34 +
35 + virtual ~MyVector()
36 + {
37 + if (storage)
38 + delete[] storage;
39 + DeleteCriticalSection(&cs_store);
40 + storage = 0;
41 + }
42 +
43 + void Reset()
44 + {
45 + EnterCriticalSection(&cs_store);
46 + for (int i = 0; i < used; i++) {
47 + Release<T>(storage[i]);
48 + storage[i] = T();
49 + }
50 + used = 0;
51 + LeaveCriticalSection(&cs_store);
52 + }
53 + void Remove(int index)
54 + {
55 + if (index>=used)
56 + return;
57 + Release<T>(storage[index]);
58 + for (int i = index; i < used; i++)
59 + storage[i] = storage[i+1];
60 + used--;
61 + }
62 + void ClearMemory(int offset, int clear_size)
63 + {
64 + if (clear_size < 0)
65 + return;
66 + EnterCriticalSection(&cs_store);
67 + if (offset+clear_size <= size)
68 + memset(storage+offset, 0, clear_size * sizeof(T)); // jichi 11/30/2013: This is the original code of ITH
69 + LeaveCriticalSection(&cs_store);
70 + //else __asm int 3
71 + }
72 + int AddToStore(T *con,int amount)
73 + {
74 + if (amount <= 0 || con == 0)
75 + return 0;
76 + int status = 0;
77 + EnterCriticalSection(&cs_store);
78 + if (amount + used + 2 >= size) {
79 + while (amount + used + 2 >= size)
80 + size<<=1;
81 + T *temp;
82 + if (size * sizeof(T) < 0x1000000) {
83 + temp = new T[size];
84 + if (size > used)
85 + ITH_MEMSET_HEAP(temp, 0, (size - used) * sizeof(T)); // jichi 9/25/2013: zero memory
86 + memcpy(temp, storage, used * sizeof(T));
87 + } else {
88 + size = default_size;
89 + temp = new T[size];
90 + ITH_MEMSET_HEAP(temp, 0, sizeof(T) * size); // jichi 9/25/2013: zero memory
91 + used = 0;
92 + status = 1;
93 + }
94 + delete[] storage;
95 + storage = temp;
96 + }
97 + memcpy(storage+used, con, amount * sizeof(T));
98 + used += amount;
99 + LeaveCriticalSection(&cs_store);
100 + return status;
101 + }
102 + int Find(const T &item, int start = 0, DWORD control = 0)
103 + {
104 + int c = -1;
105 + for (int i=start; i < used; i++)
106 + if (fCmp(storage[i],item,control)) {
107 + c=i;
108 + break;
109 + }
110 + //if (storage[i]==item) {c=i;break;}
111 + return c;
112 + }
113 + int Used() const { return used; }
114 + T *Storage() const { return storage; }
115 + void LockVector() { EnterCriticalSection(&cs_store); }
116 + void UnlockVector() { LeaveCriticalSection(&cs_store); }
117 +protected:
118 + CRITICAL_SECTION cs_store;
119 + int size,
120 + used;
121 + T *storage;
122 + fComp fCmp;
123 +};
124 +
125 +// EOF
126 +
127 +/*
128 +#ifndef ITH_STACK
129 +#define ITH_STACK
130 +template<class T, int default_size>
131 +class MyStack
132 +{
133 +public:
134 + MyStack(): index(0) {}
135 + void push_back(const T& e)
136 + {
137 + if (index<default_size)
138 + s[index++]=e;
139 + }
140 + void pop_back()
141 + {
142 + index--;
143 + }
144 + T& back()
145 + {
146 + return s[index-1];
147 + }
148 + T& operator[](int i) {return s[i];}
149 + int size() {return index;}
150 +private:
151 + int index;
152 + T s[default_size];
153 +};
154 +#endif
155 +*/
1 +#pragma once
2 +
3 +// mono/funcinfo.h
4 +// 12/26/2014
5 +// https://github.com/mono/mono/blob/master/mono/metadata/object.h
6 +// http://api.xamarin.com/index.aspx?link=xhtml%3Adeploy%2Fmono-api-string.html
7 +
8 +//#include "ith/import/mono/types.h"
9 +
10 +// MonoString* mono_string_new (MonoDomain *domain,
11 +// const char *text);
12 +// MonoString* mono_string_new_len (MonoDomain *domain,
13 +// const char *text,
14 +// guint length);
15 +// MonoString* mono_string_new_size (MonoDomain *domain,
16 +// gint32 len);
17 +// MonoString* mono_string_new_utf16 (MonoDomain *domain,
18 +// const guint16 *text,
19 +// gint32 len);
20 +// MonoString* mono_string_from_utf16 (gunichar2 *data);
21 +// mono_unichar2* mono_string_to_utf16 (MonoString *s);
22 +// char* mono_string_to_utf8 (MonoString *s);
23 +// gboolean mono_string_equal (MonoString *s1,
24 +// MonoString *s2);
25 +// guint mono_string_hash (MonoString *s);
26 +// MonoString* mono_string_intern (MonoString *str);
27 +// MonoString* mono_string_is_interned (MonoString *o);
28 +// MonoString* mono_string_new_wrapper (const char *text);
29 +// gunichar2* mono_string_chars (MonoString *s);
30 +// int mono_string_length (MonoString *s);
31 +// gunichar2* mono_unicode_from_external (const gchar *in, gsize *bytes);
32 +// gchar* mono_unicode_to_external (const gunichar2 *uni);
33 +// gchar* mono_utf8_from_external (const gchar *in);
34 +
35 +struct MonoFunction {
36 + const wchar_t *hookName;
37 + const char *functionName;
38 + size_t textIndex; // argument index, starting from 0
39 + size_t lengthIndex; // argument index, start from 0
40 + unsigned long hookType; // HookParam type
41 + void *text_fun; // HookParam::text_fun_t
42 +};
43 +
44 +#define MONO_FUNCTIONS_INITIALIZER \
45 + { L"mono_string_to_utf8", "mono_string_to_utf8", 0, 0, USING_UNICODE, SpecialHookMonoString } \
46 + , { L"mono_string_to_utf16", "mono_string_to_utf16", 0, 0, USING_UNICODE, SpecialHookMonoString } \
47 + , { L"mono_utf8_from_external", "mono_utf8_from_external", 1, 0, USING_STRING|USING_UTF8, nullptr } \
48 + , { L"mono_string_from_utf16", "mono_string_from_utf16", 1, 0, USING_UNICODE, nullptr } \
49 + , { L"mono_unicode_from_external", "mono_unicode_from_external", 1, 2, USING_UNICODE, nullptr } \
50 + , { L"mono_unicode_to_external", "mono_unicode_to_external", 1, 0, USING_UNICODE, nullptr }
51 +
52 +// EOF
1 +# mono.pri
2 +# 12/26/2014 jichi
3 +
4 +DEPENDPATH += $$PWD
5 +
6 +HEADERS += \
7 + $$PWD/funcinfo.h \
8 + $$PWD/types.h
9 +
10 +# EOF
1 +#pragma once
2 +
3 +// mono/types.h
4 +// 12/26/2014
5 +// https://github.com/mono/mono/blob/master/mono/metadata/object.h
6 +// http://api.xamarin.com/index.aspx?link=xhtml%3Adeploy%2Fmono-api-string.html
7 +
8 +#include <cstdint>
9 +
10 +// mono/io-layer/uglify.h
11 +typedef int8_t gint8;
12 +typedef int32_t gint32;
13 +typedef wchar_t gunichar2; // either char or wchar_t, depending on how mono is compiled
14 +
15 +typedef gint8 mono_byte;
16 +typedef gunichar2 mono_unichar2;
17 +
18 +// mono/metadata/object.h
19 +
20 +typedef mono_byte MonoBoolean;
21 +
22 +struct MonoArray;
23 +struct MonoDelegate;
24 +struct MonoException;
25 +struct MonoString;
26 +struct MonoThreadsSync;
27 +struct MonoThread;
28 +struct MonoVTable;
29 +
30 +struct MonoObject {
31 + MonoVTable *vtable;
32 + MonoThreadsSync *synchronisation;
33 +};
34 +
35 +struct MonoString {
36 + MonoObject object;
37 + gint32 length;
38 + gunichar2 chars[0];
39 +};
40 +
41 +// EOF
1 +#pragma once
2 +//#include "ith/common/const.h"
3 +
4 +// ppsspp/funcinfo.h
5 +// 12/26/2014
6 +// See: https://github.com/hrydgard/ppsspp
7 +
8 +// Core/HLE (High Level Emulator)
9 +// - sceCcc
10 +// #void sceCccSetTable(u32 jis2ucs, u32 ucs2jis)
11 +// int sceCccUTF8toUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr)
12 +// int sceCccUTF8toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr)
13 +// int sceCccUTF16toUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr)
14 +// int sceCccUTF16toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr)
15 +// int sceCccSJIStoUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr)
16 +// int sceCccSJIStoUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr)
17 +// int sceCccStrlenUTF8(u32 strAddr)
18 +// int sceCccStrlenUTF16(u32 strAddr)
19 +// int sceCccStrlenSJIS(u32 strAddr)
20 +// u32 sceCccEncodeUTF8(u32 dstAddrAddr, u32 ucs)
21 +// void sceCccEncodeUTF16(u32 dstAddrAddr, u32 ucs)
22 +// u32 sceCccEncodeSJIS(u32 dstAddrAddr, u32 jis)
23 +// u32 sceCccDecodeUTF8(u32 dstAddrAddr)
24 +// u32 sceCccDecodeUTF16(u32 dstAddrAddr)
25 +// u32 sceCccDecodeSJIS(u32 dstAddrAddr)
26 +// int sceCccIsValidUTF8(u32 c)
27 +// int sceCccIsValidUTF16(u32 c)
28 +// int sceCccIsValidSJIS(u32 c)
29 +// int sceCccIsValidUCS2(u32 c)
30 +// int sceCccIsValidUCS4(u32 c)
31 +// int sceCccIsValidJIS(u32 c)
32 +// int sceCccIsValidUnicode(u32 c)
33 +// #u32 sceCccSetErrorCharUTF8(u32 c)
34 +// #u32 sceCccSetErrorCharUTF16(u32 c)
35 +// #u32 sceCccSetErrorCharSJIS(u32 c)
36 +// u32 sceCccUCStoJIS(u32 c, u32 alt)
37 +// u32 sceCccJIStoUCS(u32 c, u32 alt)
38 +// - sceFont: search charCode
39 +// int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr)
40 +// int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr)
41 +// int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr)
42 +// int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr)
43 +// int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr)
44 +// int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight)
45 +// #int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode)
46 +// int sceFontGetShadowGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr)
47 +// int sceFontGetShadowGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight)
48 +// - sceKernelInterrupt
49 +// u32 sysclib_strcat(u32 dst, u32 src)
50 +// int sysclib_strcmp(u32 dst, u32 src)
51 +// u32 sysclib_strcpy(u32 dst, u32 src)
52 +// u32 sysclib_strlen(u32 src)
53 +//
54 +// Sample debug string:
55 +// 006EFD8E PUSH PPSSPPWi.00832188 ASCII "sceCccEncodeSJIS(%08x, U+%04x)"
56 +// Corresponding source code in sceCcc:
57 +// ERROR_LOG(HLE, "sceCccEncodeSJIS(%08x, U+%04x): invalid pointer", dstAddrAddr, jis);
58 +
59 +struct PPSSPPFunction
60 +{
61 + const wchar_t *hookName; // hook name
62 + size_t argIndex; // argument index
63 + unsigned long hookType; // hook parameter type
64 + unsigned long hookSplit; // hook parameter split, positive: stack, negative: registers
65 + const char *pattern; // debug string used within the function
66 +};
67 +
68 +// jichi 7/14/2014: UTF-8 is treated as STRING
69 +// http://867258173.diandian.com/post/2014-06-26/40062099618
70 +// sceFontGetCharGlyphImage_Clip
71 +// Sample game: [KID] Monochrome: sceFontGetCharInfo, sceFontGetCharGlyphImage_Clip
72 +//
73 +// Example: { L"sceFontGetCharInfo", 2, USING_UNICODE, 4, "sceFontGetCharInfo(" }
74 +// Text is at arg2, using arg1 as split
75 +#define PPSSPP_FUNCTIONS_INITIALIZER \
76 + { L"sceCccStrlenSJIS", 1, USING_STRING, 0, "sceCccStrlenSJIS(" } \
77 + , { L"sceCccStrlenUTF8", 1, USING_UTF8, 0, "sceCccStrlenUTF8(" } \
78 + , { L"sceCccStrlenUTF16", 1, USING_UNICODE, 0, "sceCccStrlenUTF16(" } \
79 +\
80 + , { L"sceCccSJIStoUTF8", 3, USING_UTF8, 0, "sceCccSJIStoUTF8(" } \
81 + , { L"sceCccSJIStoUTF16", 3, USING_STRING, 0, "sceCccSJIStoUTF16(" } \
82 + , { L"sceCccUTF8toSJIS", 3, USING_UTF8, 0, "sceCccUTF8toSJIS(" } \
83 + , { L"sceCccUTF8toUTF16", 3, USING_UTF8, 0, "sceCccUTF8toUTF16(" } \
84 + , { L"sceCccUTF16toSJIS", 3, USING_UNICODE, 0, "sceCccUTF16toSJIS(" } \
85 + , { L"sceCccUTF16toUTF8", 3, USING_UNICODE, 0, "sceCccUTF16toUTF8(" } \
86 +\
87 + , { L"sceFontGetCharInfo", 2, USING_UNICODE, 4, "sceFontGetCharInfo(" } \
88 + , { L"sceFontGetShadowInfo", 2, USING_UNICODE, 4, "sceFontGetShadowInfo("} \
89 + , { L"sceFontGetCharImageRect", 2, USING_UNICODE, 4, "sceFontGetCharImageRect(" } \
90 + , { L"sceFontGetShadowImageRect", 2, USING_UNICODE, 4, "sceFontGetShadowImageRect(" } \
91 + , { L"sceFontGetCharGlyphImage", 2, USING_UNICODE, 4, "sceFontGetCharGlyphImage(" } \
92 + , { L"sceFontGetCharGlyphImage_Clip", 2, USING_UNICODE, 4, "sceFontGetCharGlyphImage_Clip(" } \
93 + , { L"sceFontGetShadowGlyphImage", 2, USING_UNICODE, 4, "sceFontGetShadowGlyphImage(" } \
94 + , { L"sceFontGetShadowGlyphImage_Clip", 2, USING_UNICODE, 4, "sceFontGetShadowGlyphImage_Clip(" } \
95 +\
96 + , { L"sysclib_strcat", 2, USING_STRING, 0, "Untested sysclib_strcat(" } \
97 + , { L"sysclib_strcpy", 2, USING_STRING, 0, "Untested sysclib_strcpy(" } \
98 + , { L"sysclib_strlen", 1, USING_STRING, 0, "Untested sysclib_strlen(" }
99 +
100 + // Disabled as I am not sure how to deal with the source string
101 + //, { L"sceCccEncodeSJIS", 2, USING_STRING, 0, "sceCccEncodeSJIS(" }
102 + //, { L"sceCccEncodeUTF8", 2, USING_UTF8, 0, "sceCccEncodeUTF8(" }
103 + //, { L"sceCccEncodeUTF16", 2, USING_UNICODE, 0, "sceCccEncodeUTF16(" }
104 + //, { L"sysclib_strcmp", 2, USING_STRING, 0, "Untested sysclib_strcmp(" }
105 +
106 +// EOF