Showing
26 changed files
with
5697 additions
and
0 deletions
vnr/ith/hook/hook.h
0 → 100644
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 |
vnr/ith/hook/hook.pro
0 → 100644
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 |
vnr/ith/hook/main.cc
0 → 100644
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 | +*/ |
vnr/ith/hook/rpc/pipe.cc
0 → 100644
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 |
vnr/ith/hook/tree/avl.h
0 → 100644
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 |
vnr/ith/hookxp/hookxp.pro
0 → 100644
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 |
vnr/ith/host/CMakeLists.txt
0 → 100644
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 | +) |
vnr/ith/host/SettingManager.h
0 → 100644
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 |
vnr/ith/host/avl_p.h
0 → 100644
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 |
vnr/ith/host/config.h
0 → 100644
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 |
vnr/ith/host/hookman.cc
0 → 100644
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 |
vnr/ith/host/hookman.h
0 → 100644
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 |
vnr/ith/host/host.pri
0 → 100644
vnr/ith/host/host.pro
0 → 100644
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 |
vnr/ith/host/main.cc
0 → 100644
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 |
vnr/ith/host/pipe.cc
0 → 100644
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 |
vnr/ith/host/settings.h
0 → 100644
vnr/ith/host/srv.h
0 → 100644
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 |
vnr/ith/host/srv_p.h
0 → 100644
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 |
vnr/ith/host/textthread.cc
0 → 100644
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 |
vnr/ith/host/textthread.h
0 → 100644
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 |
vnr/ith/host/textthread_p.h
0 → 100644
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 | +*/ |
vnr/ith/import/mono/funcinfo.h
0 → 100644
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 |
vnr/ith/import/mono/mono.pri
0 → 100644
vnr/ith/import/mono/types.h
0 → 100644
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 |
vnr/ith/import/ppsspp/funcinfo.h
0 → 100644
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 |
-
Please register or login to post a comment