From 290ef57490914156ff6a0a6dc7b648a0af7ce99e Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sun, 20 May 2018 13:11:55 -0400 Subject: [PATCH] cleaning things up --- vnr/ithsys/ithsys.cc | 8 +- vnr/ithsys/ithsys.h | 2 +- vnr/texthook/host/hookman.cc | 4 +- vnr/texthook/host/hookman.h | 2 +- vnr/texthook/host/host.cc | 17 +- vnr/texthook/host/host_p.h | 2 +- vnr/texthook/host/pipe.cc | 356 +++++++++++------------------ vnr/vnrhook/src/hijack/texthook.cc | 22 +- vnr/vnrhook/src/hijack/texthook.h | 7 +- vnr/vnrhook/src/main.cc | 23 +- vnr/vnrhook/src/pipe.cc | 128 ++++++++--- vnr/vnrhook/src/util/util.cc | 1 + 12 files changed, 269 insertions(+), 303 deletions(-) diff --git a/vnr/ithsys/ithsys.cc b/vnr/ithsys/ithsys.cc index 128f51f..3b49610 100644 --- a/vnr/ithsys/ithsys.cc +++ b/vnr/ithsys/ithsys.cc @@ -129,7 +129,7 @@ size_t IthGetCurrentModulePath(wchar_t *buf, size_t len) HANDLE hHeap; // used in ith/common/memory.h #endif // ITH_HAS_HEAP -DWORD current_process_id; +DWORD currentProcessId; DWORD debug; BYTE launch_time[0x10]; LPVOID page; @@ -238,7 +238,7 @@ public: AcquireLock(); DWORD pid,addr,len; if (hProc == NtCurrentProcess()) - pid = ::current_process_id; + pid = ::currentProcessId; else { PROCESS_BASIC_INFORMATION info; NtQueryInformationProcess(hProc, ProcessBasicInformation, &info, sizeof(info), &len); @@ -287,7 +287,7 @@ public: DWORD pid,addr,len; AcquireLock(); if (hProc==NtCurrentProcess()) - pid = ::current_process_id; + pid = ::currentProcessId; else { PROCESS_BASIC_INFORMATION info; NtQueryInformationProcess(hProc,ProcessBasicInformation,&info,sizeof(info),&len); @@ -733,7 +733,7 @@ BOOL IthInitSystemService() mov ecx,[eax+0x20] mov eax,[eax+0x30] mov peb,eax - mov current_process_id,ecx + mov currentProcessId,ecx } debug = peb->BeingDebugged; LowFragmentHeap = 2; diff --git a/vnr/ithsys/ithsys.h b/vnr/ithsys/ithsys.h index 87c67f3..4457f43 100644 --- a/vnr/ithsys/ithsys.h +++ b/vnr/ithsys/ithsys.h @@ -63,7 +63,7 @@ void CheckThreadStart(); extern HANDLE hHeap; // used in ith/common/memory.h #endif // ITH_HAS_HEAP -extern DWORD current_process_id; +extern DWORD currentProcessId; extern DWORD debug; extern BYTE LeadByteTable[]; extern LPVOID page; diff --git a/vnr/texthook/host/hookman.cc b/vnr/texthook/host/hookman.cc index 65c46b5..aee7541 100644 --- a/vnr/texthook/host/hookman.cc +++ b/vnr/texthook/host/hookman.cc @@ -485,7 +485,7 @@ void HookManager::RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread) else NtClearEvent(destroy_event); } -void HookManager::RegisterProcess(DWORD pid, DWORD hookman, DWORD module) +void HookManager::RegisterProcess(DWORD pid) { HM_LOCK; wchar_t str[0x40], @@ -494,8 +494,6 @@ void HookManager::RegisterProcess(DWORD pid, DWORD hookman, DWORD module) //ConsoleOutput("vnrhost:RegisterProcess: lock"); //EnterCriticalSection(&hmcs); record[register_count - 1].pid_register = pid; - record[register_count - 1].hookman_register = hookman; - record[register_count - 1].module_register = module; //record[register_count - 1].engine_register = engine; swprintf(str, ITH_SECTION_ L"%d", pid); HANDLE hSection = IthCreateSection(str, HOOK_SECTION_SIZE, PAGE_READONLY); diff --git a/vnr/texthook/host/hookman.h b/vnr/texthook/host/hookman.h index bcbbeba..b54abcf 100644 --- a/vnr/texthook/host/hookman.h +++ b/vnr/texthook/host/hookman.h @@ -71,7 +71,7 @@ public: void RemoveSingleHook(DWORD pid, DWORD addr); void RegisterThread(TextThread*, DWORD); // private void RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread); - void RegisterProcess(DWORD pid, DWORD hookman, DWORD module); + void RegisterProcess(DWORD pid); void UnRegisterProcess(DWORD pid); //void SetName(DWORD); diff --git a/vnr/texthook/host/host.cc b/vnr/texthook/host/host.cc index 2317b46..62a895a 100644 --- a/vnr/texthook/host/host.cc +++ b/vnr/texthook/host/host.cc @@ -56,9 +56,9 @@ namespace { // unnamed void GetDebugPrivileges() - { + { // Artikash 5/19/2018: Is it just me or is this function 100% superfluous? HANDLE processToken; - TOKEN_PRIVILEGES Privileges = { 1, {0x14, 0, SE_PRIVILEGE_ENABLED} }; + TOKEN_PRIVILEGES Privileges = {1, {0x14, 0, SE_PRIVILEGE_ENABLED}}; OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &processToken); AdjustTokenPrivileges(processToken, FALSE, &Privileges, 0, nullptr, nullptr); @@ -79,7 +79,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused) IthInitSystemService(); GetDebugPrivileges(); // jichi 12/20/2013: Since I already have a GUI, I don't have to InitCommonControls() - //Used by timers. + // Used by timers. InitCommonControls(); // jichi 8/24/2013: Create hidden window so that ITH can access timer and events dummyWindow = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0); @@ -133,7 +133,6 @@ IHFSERVICE bool IHFAPI OpenHost() IHFSERVICE void IHFAPI StartHost() { CreateNewPipe(); - ::pipeExistsEvent = CreateEventW(nullptr, TRUE, TRUE, ITH_PIPEEXISTS_EVENT); } IHFSERVICE void IHFAPI CloseHost() @@ -142,12 +141,10 @@ IHFSERVICE void IHFAPI CloseHost() if (::running) { ::running = FALSE; - ResetEvent(::pipeExistsEvent); delete man; delete settings; CloseHandle(::hookMutex); CloseHandle(preventDuplicationMutex); - CloseHandle(::pipeExistsEvent); DeleteCriticalSection(&detachCs); } LeaveCriticalSection(&::hostCs); @@ -169,7 +166,7 @@ IHFSERVICE bool IHFAPI InjectProcessById(DWORD processId, DWORD timeout) success = false; } - HMODULE textHooker = LoadLibraryExW(L"vnrhook", nullptr, DONT_RESOLVE_DLL_REFERENCES); + HMODULE textHooker = LoadLibraryExW(ITH_DLL, nullptr, DONT_RESOLVE_DLL_REFERENCES); if (textHooker == nullptr) { success = false; @@ -184,7 +181,7 @@ IHFSERVICE bool IHFAPI InjectProcessById(DWORD processId, DWORD timeout) success = false; } - void* loadLibraryStartRoutine = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW"); + LPTHREAD_START_ROUTINE loadLibraryStartRoutine = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW"); if (success) { @@ -192,7 +189,7 @@ IHFSERVICE bool IHFAPI InjectProcessById(DWORD processId, DWORD timeout) { if (WriteProcessMemory(processHandle, remoteData, textHookerPath, textHookerPathSize, nullptr)) { - if (HANDLE thread = CreateRemoteThread(processHandle, nullptr, 0, (LPTHREAD_START_ROUTINE)loadLibraryStartRoutine, remoteData, 0, nullptr)) + if (HANDLE thread = CreateRemoteThread(processHandle, nullptr, 0, loadLibraryStartRoutine, remoteData, 0, nullptr)) { WaitForSingleObject(thread, timeout); CloseHandle(thread); @@ -247,7 +244,7 @@ IHFSERVICE void IHFAPI GetHostSettings(Settings **p) } } -// I don't understand the following operations, so I'm making minimal changes in cleanup -Artikash 11 May 2018 +// Artikash 5/11/2018: I don't understand the following operations, so I'm making minimal changes in cleanup IHFSERVICE DWORD IHFAPI Host_InsertHook(DWORD pid, HookParam *hp, LPCSTR name) { diff --git a/vnr/texthook/host/host_p.h b/vnr/texthook/host/host_p.h index a2356a1..1c16159 100644 --- a/vnr/texthook/host/host_p.h +++ b/vnr/texthook/host/host_p.h @@ -31,7 +31,7 @@ GLOBAL DWORD split_time, global_filter; GLOBAL CRITICAL_SECTION detachCs; -DWORD WINAPI RecvThread(LPVOID lpThreadParameter); +DWORD WINAPI TextReceiver(LPVOID lpThreadParameter); DWORD WINAPI CmdThread(LPVOID lpThreadParameter); DWORD GetCurrentPID(); diff --git a/vnr/texthook/host/pipe.cc b/vnr/texthook/host/pipe.cc index beedad8..c60dc56 100644 --- a/vnr/texthook/host/pipe.cc +++ b/vnr/texthook/host/pipe.cc @@ -9,6 +9,8 @@ #include "vnrhook/include/const.h" #include "ithsys/ithsys.h" #include +#include "growl.h" +#include //#include "CommandQueue.h" //#include @@ -17,57 +19,57 @@ //DWORD WINAPI UpdateWindows(LPVOID lpThreadParameter); -namespace { // unnamed -enum NamedPipeCommand { - NAMED_PIPE_DISCONNECT = 1 - , NAMED_PIPE_CONNECT = 2 -}; +namespace +{ // unnamed -bool newline = false; -bool detach = false; + // jichi 10/27/2013 + // Check if text has leading space + enum { FILTER_LIMIT = 0x20 }; // The same as the orignal ITH filter. So, I don't have to check \u3000 + //enum { FILTER_LIMIT = 0x19 }; + inline bool HasLeadingSpace(const BYTE *text, int len) + { + return len == 1 ? *text <= FILTER_LIMIT : // 1 byte + *(WORD*)text <= FILTER_LIMIT; // 2 bytes + } -// jichi 10/27/2013 -// Check if text has leading space -enum { _filter_limit = 0x20 }; // The same as the orignal ITH filter. So, I don't have to check \u3000 -//enum { _filter_limit = 0x19 }; -inline bool has_leading_space(const BYTE *text, int len) -{ - return len == 1 ? *text <= _filter_limit : // 1 byte - *reinterpret_cast(text) <= _filter_limit; // 2 bytes -} - -// jichi 9/28/2013: Skip leading garbage -// Note: -// - Modifying limit will break manual translation. The orignal one is 0x20 -// - Eliminating 0x20 will break English-translated games -const BYTE *Filter(const BYTE *str, int len) -{ + // jichi 9/28/2013: Skip leading garbage + // Note: + // - Modifying limit will break manual translation. The orignal one is 0x20 + // - Eliminating 0x20 will break English-translated games + const BYTE* Filter(const BYTE *str, int len) + { #ifdef ITH_DISABLE_FILTER // jichi 9/28/2013: only for debugging purpose - return str; -#endif // ITH_DISABLE_FILTER -// if (len && *str == 0x10) // jichi 9/28/2013: garbage on wine, data link escape, or ^P -// return nullptr; - //enum { limit = 0x19 }; - while (true) - if (len >= 2) { - if (*(const WORD *)str <= _filter_limit) { // jichi 10/27/2013: two bytes - str += 2; - len -= 2; - } else - break; - } else if (*str <= _filter_limit) { // jichi 10/27/2013: 1 byte - str++; - len--; - } else - break; - return str; -} -} // unnamed namespace + return str; +#endif + while (true) + { + if (len >= 2) + { + if (*(WORD*)str <= FILTER_LIMIT) + { // jichi 10/27/2013: two bytes + str += 2; + len -= 2; + } + else + { + break; + } -//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE"; -//WCHAR command_pipe[] = L"\\??\\pipe\\ITH_COMMAND"; -wchar_t recv_pipe[] = ITH_TEXT_PIPE; -wchar_t command_pipe[] = ITH_COMMAND_PIPE; + } + else if (*str <= FILTER_LIMIT) + { // jichi 10/27/2013: 1 byte + str++; + len--; + } + else + { + break; + } + } + return str; + } + +} // unnamed namespace CRITICAL_SECTION detachCs; // jichi 9/27/2013: also used in main //HANDLE hDetachEvent; @@ -75,204 +77,106 @@ extern HANDLE pipeExistsEvent; void CreateNewPipe() { - HANDLE hTextPipe, hCmdPipe, hThread; + HANDLE hookPipe, hostPipe, TextReceivingThread; - hTextPipe = CreateNamedPipeW(ITH_TEXT_PIPE, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0x1000, 0x1000, MAXDWORD, NULL); - hCmdPipe = CreateNamedPipeW(ITH_COMMAND_PIPE, PIPE_ACCESS_OUTBOUND, 0, PIPE_UNLIMITED_INSTANCES, 0x1000, 0x1000, MAXDWORD, NULL); - hThread = CreateThread(nullptr, 0, RecvThread, hTextPipe, 0, nullptr); - man->RegisterPipe(hTextPipe, hCmdPipe, hThread); + hookPipe = CreateNamedPipeW(ITH_TEXT_PIPE, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0x1000, 0x1000, MAXDWORD, NULL); + hostPipe = CreateNamedPipeW(ITH_COMMAND_PIPE, PIPE_ACCESS_OUTBOUND, 0, PIPE_UNLIMITED_INSTANCES, 0x1000, 0x1000, MAXDWORD, NULL); + TextReceivingThread = CreateThread(nullptr, 0, TextReceiver, hookPipe, 0, nullptr); + man->RegisterPipe(hookPipe, hostPipe, TextReceivingThread); } -void DetachFromProcess(DWORD pid) +DWORD WINAPI TextReceiver(LPVOID lpThreadParameter) { - HANDLE hMutex = INVALID_HANDLE_VALUE, - hEvent = INVALID_HANDLE_VALUE; - //try { - IO_STATUS_BLOCK ios; - ProcessRecord *pr = man->GetProcessRecord(pid); - if (!pr) - return; - //IthBreak(); - hEvent = IthCreateEvent(nullptr); - if (STATUS_PENDING == NtFsControlFile( - man->GetCmdHandleByPID(pid), - hEvent, - 0,0, - &ios, - CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0), - 0,0,0,0)) - NtWaitForSingleObject(hEvent, 0, 0); - NtClose(hEvent); - //hEvent = INVALID_HANDLE_VALUE; + HANDLE hookPipe = (HANDLE)lpThreadParameter; + ConnectNamedPipe(hookPipe, nullptr); - WCHAR mutex[0x20]; - swprintf(mutex, ITH_DETACH_MUTEX_ L"%d", pid); - hMutex = IthOpenMutex(mutex); - if (hMutex != INVALID_HANDLE_VALUE) { - NtWaitForSingleObject(hMutex, 0, 0); - NtReleaseMutant(hMutex, 0); - NtClose(hMutex); - //hMutex = INVALID_HANDLE_VALUE; - } + enum { PIPE_BUFFER_SIZE = 0x1000 }; + BYTE* buffer = new BYTE[PIPE_BUFFER_SIZE]; + DWORD bytesRead, processId; - //} catch (...) { - // if (hEvent != INVALID_HANDLE_VALUE) - // NtClose(hEvent); - // else if (hMutex != INVALID_HANDLE_VALUE) { - // NtWaitForSingleObject(hMutex, 0, 0); - // NtReleaseMutant(hMutex, 0); - // NtClose(hMutex); - // } - //} + // Artikash 5/20/2018: Shouldn't Windows automatically close the handles when the host process stops running? + //if (!::running) { + // NtClose(hookPipe); + // return 0; + //} - //NtSetEvent(hDetachEvent, 0); - if (::running) - NtSetEvent(pipeExistsEvent, 0); -} + ReadFile(hookPipe, &processId, sizeof(processId), &bytesRead, nullptr); + man->RegisterProcess(processId); -// jichi 9/27/2013: I don't need this -//void OutputDWORD(DWORD d) -//{ -// WCHAR str[0x20]; -// swprintf(str, L"%.8X", d); -// ConsoleOutput(str); -//} + // jichi 9/27/2013: why recursion? + // Artikash 5/20/2018: To create a new pipe for another process + CreateNewPipe(); -DWORD WINAPI RecvThread(LPVOID lpThreadParameter) -{ - HANDLE hTextPipe = (HANDLE)lpThreadParameter; + while (::running) + { + if (!ReadFile(hookPipe, buffer, PIPE_BUFFER_SIZE, &bytesRead, nullptr)) + { + break; + } - IO_STATUS_BLOCK ios; - NtFsControlFile(hTextPipe, - 0, 0, 0, - &ios, - CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_CONNECT, 0, 0), - 0, 0, 0, 0); - if (!::running) { - NtClose(hTextPipe); - return 0; - } + enum { DATA_OFFSET = 0xc }; // jichi 10/27/2013: Seem to be the data offset in the pipe - BYTE *buff; + if (bytesRead < DATA_OFFSET) + { + break; + } - enum { PipeBufferSize = 0x1000 }; - buff = new BYTE[PipeBufferSize]; - ::memset(buff, 0, PipeBufferSize); // jichi 8/27/2013: zero memory, or it will crash wine on start up + union { DWORD retn; DWORD commandType; }; + DWORD hook = *(DWORD *)buffer; + retn = *(DWORD *)(buffer + 4); + DWORD split = *(DWORD *)(buffer + 8); - // 10/19/2014 jichi: there are totally three words received - // See: hook/rpc/pipe.cc - // struct { - // DWORD pid; - // TextHook *man; - // DWORD module; - // //DWORD engine; - // } u; - enum { module_struct_size = 12 }; - NtReadFile(hTextPipe, 0, 0, 0, &ios, buff, module_struct_size, 0, 0); + buffer[bytesRead] = 0; + buffer[bytesRead + 1] = 0; - // jichi 7/2/2015: This must be consistent with the struct declared in vnrhook/pipe.cc - DWORD pid = *(DWORD *)buff, - module = *(DWORD *)(buff + 0x8), - hookman = *(DWORD *)(buff + 0x4); - //engine = *(DWORD *)(buff + 0xc); - man->RegisterProcess(pid, hookman, module); + if (hook == HOST_NOTIFICATION) + { + switch (commandType) + { + case HOST_NOTIFICATION_NEWHOOK: + { + static long lock; + while (InterlockedExchange(&lock, 1) == 1); + man->ProcessNewHook()(processId); + lock = 0; + } + break; + case HOST_NOTIFICATION_TEXT: + USES_CONVERSION; + man->AddConsoleOutput(A2W((LPCSTR)(buffer + 8))); + break; + } + } + else + { + // jichi 9/28/2013: Debug raw data + //ITH_DEBUG_DWORD9(RecvLen - 0xc, + // buffer[0xc], buffer[0xd], buffer[0xe], buffer[0xf], + // buffer[0x10], buffer[0x11], buffer[0x12], buffer[0x13]); - // jichi 9/27/2013: why recursion? - CreateNewPipe(); + const BYTE *data = buffer + DATA_OFFSET; // th + int dataLength = bytesRead - DATA_OFFSET; + bool space = ::HasLeadingSpace(data, dataLength); + if (space) + { + const BYTE *it = ::Filter(data, dataLength); + dataLength -= it - data; + data = it; + } + man->DispatchText(processId, data, hook, retn, split, dataLength, space); + } + } - //NtClose(IthCreateThread(UpdateWindows,0)); - while (::running) { - if (!NT_SUCCESS(NtReadFile(hTextPipe, - 0, 0, 0, - &ios, - buff, - 0xf80, - 0, 0))) - break; + EnterCriticalSection(&detachCs); - enum { data_offset = 0xc }; // jichi 10/27/2013: Seem to be the data offset in the pipe + DisconnectNamedPipe(hookPipe); + DisconnectNamedPipe(man->GetCmdHandleByPID(processId)); + man->UnRegisterProcess(processId); - DWORD RecvLen = ios.uInformation; - if (RecvLen < data_offset) - break; - DWORD hook = *(DWORD *)buff; + LeaveCriticalSection(&detachCs); + delete[] buffer; - union { DWORD retn; DWORD cmd_type; }; - union { DWORD split; DWORD new_engine_type; }; - - retn = *(DWORD *)(buff + 4); - split = *(DWORD *)(buff + 8); - - buff[RecvLen] = 0; - buff[RecvLen + 1] = 0; - - if (hook == HOST_NOTIFICATION) { - switch (cmd_type) { - case HOST_NOTIFICATION_NEWHOOK: - { - static long lock; - while (InterlockedExchange(&lock, 1) == 1); - ProcessEventCallback new_hook = man->ProcessNewHook(); - if (new_hook) - new_hook(pid); - lock = 0; - } break; - case HOST_NOTIFICATION_TEXT: - //qDebug() << ((LPCSTR)(buff + 8)); - break; - } - } else { - // jichi 9/28/2013: Debug raw data - //ITH_DEBUG_DWORD9(RecvLen - 0xc, - // buff[0xc], buff[0xd], buff[0xe], buff[0xf], - // buff[0x10], buff[0x11], buff[0x12], buff[0x13]); - - const BYTE *data = buff + data_offset; // th - int len = RecvLen - data_offset; - bool space = ::has_leading_space(data, len); - if (space) { - const BYTE *it = ::Filter(data, len); - len -= it - data; - data = it; - } - if (len >> 31) // jichi 10/27/2013: len is too large, which seldom happens - len = 0; - //man->DispatchText(pid, len ? data : nullptr, hook, retn, split, len, space); - man->DispatchText(pid, data, hook, retn, split, len, space); - } - } - - EnterCriticalSection(&detachCs); - - HANDLE hDisconnect = IthCreateEvent(nullptr); - - if (STATUS_PENDING == NtFsControlFile( - hTextPipe, - hDisconnect, - 0, 0, - &ios, - CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0), - 0, 0, 0, 0)) - NtWaitForSingleObject(hDisconnect, 0, 0); - - NtClose(hDisconnect); - DetachFromProcess(pid); - man->UnRegisterProcess(pid); - - //NtClearEvent(hDetachEvent); - - LeaveCriticalSection(&detachCs); - delete[] buff; - - if (::running) - DOUT("detached"); - - //if (::running) { - // swprintf((LPWSTR)buff, FormatDetach, pid); - // ConsoleOutput((LPWSTR)buff); - // NtClose(IthCreateThread(UpdateWindows, 0)); - //} - return 0; + return 0; } // EOF diff --git a/vnr/vnrhook/src/hijack/texthook.cc b/vnr/vnrhook/src/hijack/texthook.cc index 544e9c9..a98820b 100644 --- a/vnr/vnrhook/src/hijack/texthook.cc +++ b/vnr/vnrhook/src/hijack/texthook.cc @@ -234,7 +234,7 @@ DWORD GetModuleBase() // *(DWORD*)buffer=-1; // *(DWORD*)(buffer+4)=1; // IO_STATUS_BLOCK ios; -// NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0); +// NtWriteFile(hookPipe,0,0,0,&ios,buffer,0x10,0,0); // } //} @@ -488,9 +488,9 @@ DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn) IthCoolDown(); // jichi 9/28/2013: cool down to prevent parallelization in wine //CliLockPipe(); - if (STATUS_PENDING == NtWriteFile(::hPipe, 0, 0, 0, &ios, pbData, dwCount + HEADER_SIZE, 0, 0)) { - NtWaitForSingleObject(::hPipe, 0, 0); - NtFlushBuffersFile(::hPipe, &ios); + if (STATUS_PENDING == NtWriteFile(::hookPipe, 0, 0, 0, &ios, pbData, dwCount + HEADER_SIZE, 0, 0)) { + NtWaitForSingleObject(::hookPipe, 0, 0); + NtFlushBuffersFile(::hookPipe, &ios); } //CliUnlockPipe(); } @@ -550,7 +550,7 @@ int TextHook::UnsafeInsertHookCode() if (base) hp.address += base; else { - current_hook--; + currentHook--; ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: function not found in the export table"); return no; } @@ -561,7 +561,7 @@ int TextHook::UnsafeInsertHookCode() hp.type &= ~(MODULE_OFFSET | FUNCTION_OFFSET); } else { - current_hook--; + currentHook--; ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: module not present"); return no; } @@ -569,7 +569,7 @@ int TextHook::UnsafeInsertHookCode() { TextHook *it = hookman; - for (int i = 0; (i < current_hook) && it; it++) { // Check if there is a collision. + for (int i = 0; (i < currentHook) && it; it++) { // Check if there is a collision. if (it->Address()) i++; //it = hookman + i; @@ -640,7 +640,7 @@ int TextHook::UnsafeInsertHookCode() //Check if the new hook range conflict with existing ones. Clear older if conflict. { TextHook *it = hookman; - for (int i = 0; i < current_hook; it++) { + for (int i = 0; i < currentHook; it++) { if (it->Address()) i++; if (it == this) @@ -686,7 +686,7 @@ int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, hp.hook_len = 0; hp.module = 0; hp.length_offset = len_off & 0xffff; - current_hook++; + currentHook++; if (current_available >= this) for (current_available = this + 1; current_available->Address(); current_available++); IthReleaseMutex(hmMutex); @@ -701,7 +701,7 @@ int TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag) if (name && name != hook_name) { SetHookName(name); } - current_hook++; + currentHook++; current_available = this+1; while (current_available->Address()) current_available++; @@ -742,7 +742,7 @@ int TextHook::ClearHook() memset(this, 0, sizeof(TextHook)); // jichi 11/30/2013: This is the original code of ITH //if (current_available>this) // current_available = this; - current_hook--; + currentHook--; IthReleaseMutex(hmMutex); return err; } diff --git a/vnr/vnrhook/src/hijack/texthook.h b/vnr/vnrhook/src/hijack/texthook.h index 8b25948..775600c 100644 --- a/vnr/vnrhook/src/hijack/texthook.h +++ b/vnr/vnrhook/src/hijack/texthook.h @@ -19,11 +19,11 @@ // - 0x8 dwSplit split value #define HEADER_SIZE 0xc -extern int current_hook; +extern int currentHook; extern WCHAR dll_mutex[]; //extern WCHAR dll_name[]; extern DWORD trigger; -//extern DWORD current_process_id; +//extern DWORD currentProcessId; // jichi 6/3/2014: Get memory range of the current module extern DWORD processStartAddress, @@ -77,11 +77,12 @@ extern FilterRange *filter; extern bool running, live; -extern HANDLE hPipe, +extern HANDLE hookPipe, hmMutex; DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter); DWORD WINAPI CommandPipe(LPVOID lpThreadParameter); +DWORD WINAPI PipeManager(LPVOID unused); //void RequestRefreshProfile(); diff --git a/vnr/vnrhook/src/main.cc b/vnr/vnrhook/src/main.cc index ffd51b1..751f277 100644 --- a/vnr/vnrhook/src/main.cc +++ b/vnr/vnrhook/src/main.cc @@ -62,14 +62,14 @@ HINSTANCE hDLL; HANDLE hSection; bool running, live = false; -int current_hook = 0, +int currentHook = 0, user_hook_count = 0; DWORD trigger = 0; HANDLE hFile, hMutex, hmMutex; -//DWORD current_process_id; +//DWORD currentProcessId; extern DWORD enter_count; //extern LPWSTR current_dir; extern DWORD engine_type; @@ -133,7 +133,7 @@ void RequestRefreshProfile() *(DWORD *)(buffer + 8) = 0; IO_STATUS_BLOCK ios; CliLockPipe(); - NtWriteFile(hPipe, 0, 0, 0, &ios, buffer, HEADER_SIZE, 0, 0); + NtWriteFile(hookPipe, 0, 0, 0, &ios, buffer, HEADER_SIZE, 0, 0); CliUnlockPipe(); } } @@ -156,7 +156,7 @@ DWORD GetFunctionAddr(const char *name, DWORD *addr, DWORD *base, DWORD *size, L BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved) { - static HANDLE hSendThread, + static HANDLE pipeThread, hCmdThread; CC_UNUSED(lpReserved); @@ -189,7 +189,7 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved) // No longer checking if SystemService fails, which could happen on non-Japanese OS IthInitSystemService(); - swprintf(hm_section, ITH_SECTION_ L"%d", current_process_id); + swprintf(hm_section, ITH_SECTION_ L"%d", currentProcessId); // jichi 9/25/2013: Interprocedural communication with vnrsrv. hSection = IthCreateSection(hm_section, HOOK_SECTION_SIZE, PAGE_EXECUTE_READWRITE); @@ -211,12 +211,12 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved) { wchar_t hm_mutex[0x100]; - swprintf(hm_mutex, ITH_HOOKMAN_MUTEX_ L"%d", current_process_id); + swprintf(hm_mutex, ITH_HOOKMAN_MUTEX_ L"%d", currentProcessId); ::hmMutex = IthCreateMutex(hm_mutex, FALSE); } { wchar_t dll_mutex[0x100]; - swprintf(dll_mutex, ITH_PROCESS_MUTEX_ L"%d", current_process_id); + swprintf(dll_mutex, ITH_PROCESS_MUTEX_ L"%d", currentProcessId); DWORD exists; ::hMutex = IthCreateMutex(dll_mutex, TRUE, &exists); // jichi 9/18/2013: own is true, make sure the injected dll is singleton if (exists) @@ -231,8 +231,7 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved) AddAllModules(); InitFilterTable(); - hSendThread = IthCreateThread(WaitForPipe, 0); - hCmdThread = IthCreateThread(CommandPipe, 0); + pipeThread = IthCreateThread(PipeManager, 0); } break; case DLL_PROCESS_DETACH: { @@ -250,9 +249,9 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved) Engine::terminate(); - if (hSendThread) { - NtWaitForSingleObject(hSendThread, 0, (PLARGE_INTEGER)&timeout); - NtClose(hSendThread); + if (pipeThread) { + NtWaitForSingleObject(pipeThread, 0, (PLARGE_INTEGER)&timeout); + NtClose(pipeThread); } if (hCmdThread) { diff --git a/vnr/vnrhook/src/pipe.cc b/vnr/vnrhook/src/pipe.cc index 59a2a59..5e5b038 100644 --- a/vnr/vnrhook/src/pipe.cc +++ b/vnr/vnrhook/src/pipe.cc @@ -12,7 +12,7 @@ #include "src/util/util.h" #include "src/main.h" #include "include/defs.h" -//#include "src/util/growl.h" +#include "src/util/growl.h" #include "ithsys/ithsys.h" #include "ccutil/ccmacro.h" #include // for swprintf @@ -34,7 +34,7 @@ LARGE_INTEGER sleep_time = {-20*10000, -1}; DWORD engine_type; DWORD module_base; -HANDLE hPipe, +HANDLE hookPipe, hCommand, hDetach; //,hLose; //InsertHookFun InsertHook; @@ -71,20 +71,88 @@ HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction) return INVALID_HANDLE_VALUE; } +DWORD WINAPI PipeManager(LPVOID unused) +{ + enum { STANDARD_WAIT = 1000 }; + while (::running) + { + DWORD count; + BYTE* buffer = new BYTE[0x1000]; + HANDLE hostPipe = ::hookPipe = INVALID_HANDLE_VALUE, + pipeAcquisitionMutex = CreateMutexW(nullptr, TRUE, ITH_GRANTPIPE_MUTEX); + + while (::hookPipe == INVALID_HANDLE_VALUE || hostPipe == INVALID_HANDLE_VALUE) + { + Sleep(STANDARD_WAIT); + if (::hookPipe == INVALID_HANDLE_VALUE) + { + ::hookPipe = CreateFileW(ITH_TEXT_PIPE, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + } + if (hostPipe == INVALID_HANDLE_VALUE) + { + hostPipe = CreateFileW(ITH_COMMAND_PIPE, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + } + } + + WriteFile(::hookPipe, &::currentProcessId, sizeof(::currentProcessId), &count, nullptr); + + for (int i = 0, count = 0; count < ::currentHook; i++) + { + if (hookman[i].RecoverHook()) // jichi 9/27/2013: This is the place where built-in hooks like TextOutA are inserted + { + count++; + } + } + + ReleaseMutex(pipeAcquisitionMutex); + CloseHandle(pipeAcquisitionMutex); + + ::live = true; + Engine::hijack(); + ConsoleOutput("vnrcli:WaitForPipe: pipe connected"); + + while (::running) + { + Sleep(STANDARD_WAIT); + if (!ReadFile(hostPipe, buffer, 0x800, &count, nullptr)) + { + break; + } + DWORD command = *(DWORD*)buffer; + switch (command) + { + case HOST_COMMAND_NEW_HOOK: + buffer[count] = 0; + NewHook(*(HookParam *)(buffer + 4), (LPSTR)(buffer + 4 + sizeof(HookParam)), 0); + break; + case HOST_COMMAND_DETACH: + ::running = false; + break; + } + } + + ::live = false; + for (int i = 0, count = 0; count < ::currentHook; i++) + { + if (hookman[i].RemoveHook()) + { + count++; + } + } + CloseHandle(::hookPipe); + CloseHandle(hostPipe); + } + Util::unloadCurrentModule(); + return 0; +} + DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter) // Dynamically detect ITH main module status. { CC_UNUSED(lpThreadParameter); - // jichi 7/2/2015:This must be consistent with the struct declared in vnrhost/pipe.cc - struct { - DWORD pid; - DWORD module; - TextHook *man; - //DWORD engine; - } u; - //swprintf(engine_event,L"ITH_ENGINE_%d",current_process_id); - swprintf(::detach_mutex, ITH_DETACH_MUTEX_ L"%d", current_process_id); - //swprintf(lose_event,L"ITH_LOSEPIPE_%d",current_process_id); + //swprintf(engine_event,L"ITH_ENGINE_%d",currentProcessId); + swprintf(::detach_mutex, ITH_DETACH_MUTEX_ L"%d", currentProcessId); + //swprintf(lose_event,L"ITH_LOSEPIPE_%d",currentProcessId); //hEngine=IthCreateEvent(engine_event); //NtWaitForSingleObject(hEngine,0,0); //NtClose(hEngine); @@ -93,35 +161,33 @@ DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter) // Dynamically detect ITH mai // NtDelayExecution(0, &wait_time); //LoadEngine(L"ITH_Engine.dll"); - u.module = module_base; - u.pid = current_process_id; - u.man = hookman; //u.engine = engine_base; // jichi 10/19/2014: disable the second dll HANDLE hPipeExist = IthOpenEvent(ITH_PIPEEXISTS_EVENT); IO_STATUS_BLOCK ios; //hLose=IthCreateEvent(lose_event,0,0); if (hPipeExist != INVALID_HANDLE_VALUE) while (::running) { - ::hPipe = INVALID_HANDLE_VALUE; + ::hookPipe = INVALID_HANDLE_VALUE; hCommand = INVALID_HANDLE_VALUE; while (NtWaitForSingleObject(hPipeExist, 0, &wait_time) == WAIT_TIMEOUT) if (!::running) goto _release; + GROWL_MSG(L"Pipe connected"); HANDLE hMutex = IthCreateMutex(ITH_GRANTPIPE_MUTEX, 0); NtWaitForSingleObject(hMutex, 0, 0); - while (::hPipe == INVALID_HANDLE_VALUE|| + while (::hookPipe == INVALID_HANDLE_VALUE|| hCommand == INVALID_HANDLE_VALUE) { NtDelayExecution(0, &sleep_time); - if (::hPipe == INVALID_HANDLE_VALUE) - ::hPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE); + if (::hookPipe == INVALID_HANDLE_VALUE) + ::hookPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE); if (hCommand == INVALID_HANDLE_VALUE) hCommand = IthOpenPipe(command, GENERIC_READ); } //NtClearEvent(hLose); CliLockPipe(); - NtWriteFile(::hPipe, 0, 0, 0, &ios, &u, sizeof(u), 0, 0); + NtWriteFile(::hookPipe, 0, 0, 0, &ios, &::currentProcessId, sizeof(::currentProcessId), 0, 0); CliUnlockPipe(); - for (int i = 0, count = 0; count < ::current_hook; i++) + for (int i = 0, count = 0; count < ::currentHook; i++) if (hookman[i].RecoverHook()) // jichi 9/27/2013: This is the place where built-in hooks like TextOutA are inserted count++; //ConsoleOutput(dll_name); @@ -141,19 +207,19 @@ DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter) // Dynamically detect ITH mai NtDelayExecution(0, &sleep_time); ::live = false; - for (int i = 0, count = 0; count < ::current_hook; i++) + for (int i = 0, count = 0; count < ::currentHook; i++) if (hookman[i].RemoveHook()) count++; if (!::running) { IthCoolDown(); // jichi 9/28/2013: Use cooldown instead of lock pipe to prevent from hanging on exit //CliLockPipe(); - //NtWriteFile(::hPipe, 0, 0, 0, &ios, man, 4, 0, 0); - NtWriteFile(::hPipe, 0, 0, 0, &ios, hookman, 4, 0, 0); + //NtWriteFile(::hookPipe, 0, 0, 0, &ios, man, 4, 0, 0); + NtWriteFile(::hookPipe, 0, 0, 0, &ios, hookman, 4, 0, 0); //CliUnlockPipe(); IthReleaseMutex(::hDetach); } NtClose(::hDetach); - NtClose(::hPipe); + NtClose(::hookPipe); } _release: //NtClose(hLose); @@ -211,7 +277,7 @@ DWORD WINAPI CommandPipe(LPVOID lpThreadParameter) HANDLE hRemoved = IthOpenEvent(ITH_REMOVEHOOK_EVENT); TextHook *in = hookman; - for (int i = 0; i < current_hook; in++) { + for (int i = 0; i < currentHook; in++) { if (in->Address()) i++; if (in->Address() == rm_addr) break; } @@ -226,7 +292,7 @@ DWORD WINAPI CommandPipe(LPVOID lpThreadParameter) DWORD rm_addr = *(DWORD *)(buff + 4); HANDLE hModify = IthOpenEvent(ITH_MODIFYHOOK_EVENT); TextHook *in = hookman; - for (int i = 0; i < current_hook; in++) { + for (int i = 0; i < currentHook; in++) { if (in->Address()) i++; if (in->Address() == rm_addr) @@ -270,7 +336,7 @@ void ConsoleOutput(LPCSTR text) memcpy(data + 8, text, text_size); IO_STATUS_BLOCK ios; - NtWriteFile(hPipe, 0, 0, 0, &ios, data, data_size, 0, 0); + NtWriteFile(hookPipe, 0, 0, 0, &ios, data, data_size, 0, 0); if (data != buf) delete[] data; } @@ -279,7 +345,7 @@ void ConsoleOutput(LPCSTR text) // BYTE buffer[0x80]; // BYTE *buff; // len = wcslen(str) << 1; - // t = swprintf((LPWSTR)(buffer + 8),L"%d: ",current_process_id) << 1; + // t = swprintf((LPWSTR)(buffer + 8),L"%d: ",currentProcessId) << 1; // sum = len + t + 8; // if (sum > 0x80) { // buff = new BYTE[sum]; @@ -292,7 +358,7 @@ void ConsoleOutput(LPCSTR text) // *(DWORD *)(buff + 4) = HOST_NOTIFICATION_TEXT; //console // memcpy(buff + t + 8, str, len); // IO_STATUS_BLOCK ios; - // NtWriteFile(hPipe,0,0,0,&ios,buff,sum,0,0); + // NtWriteFile(hookPipe,0,0,0,&ios,buff,sum,0,0); // if (buff != buffer) // delete[] buff; // return len; @@ -343,7 +409,7 @@ DWORD NotifyHookInsert(DWORD addr) *(DWORD *)(buffer + 0xc) = 0; IO_STATUS_BLOCK ios; CliLockPipe(); - NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0); + NtWriteFile(hookPipe,0,0,0,&ios,buffer,0x10,0,0); CliUnlockPipe(); } return 0; diff --git a/vnr/vnrhook/src/util/util.cc b/vnr/vnrhook/src/util/util.cc index def0a24..efbdd03 100644 --- a/vnr/vnrhook/src/util/util.cc +++ b/vnr/vnrhook/src/util/util.cc @@ -304,6 +304,7 @@ termin: EXTERN_C IMAGE_DOS_HEADER __ImageBase; // See: http://stackoverflow.com/questions/3410130/dll-unloading-itself +// TODO: This doesn't always work. Fix it. bool Util::unloadCurrentModule() { auto fun = ::FreeLibrary;