// pipe.cc // 8/24/2013 jichi // Branch: ITH_DLL/pipe.cpp, rev 66 // 8/24/2013 TODO: Clean up this file #ifdef _MSC_VER # pragma warning (disable:4100) // C4100: unreference formal parameter #endif // _MSC_VER #include "src/hijack/texthook.h" #include "src/engine/match.h" #include "src/util/util.h" #include "src/main.h" #include "include/defs.h" #include "src/util/growl.h" #include "ithsys/ithsys.h" #include "ccutil/ccmacro.h" #include // for swprintf HANDLE hookPipe; // jichi 9/28/2013: protect pipe on wine // Put the definition in this file so that it might be inlined void CliUnlockPipe() { if (IthIsWine()) IthReleaseMutex(::hmMutex); } void CliLockPipe() { if (IthIsWine()) { const LONGLONG timeout = -50000000; // in nanoseconds = 5 seconds NtWaitForSingleObject(hmMutex, 0, (PLARGE_INTEGER)&timeout); } } HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction) { UNICODE_STRING us; RtlInitUnicodeString(&us,name); SECURITY_DESCRIPTOR sd = {1}; OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0}; HANDLE hFile; IO_STATUS_BLOCK isb; if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0))) return hFile; else return INVALID_HANDLE_VALUE; } DWORD WINAPI 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), nullptr, 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_REMOVE_HOOK: { DWORD removalAddress = *(DWORD *)(buffer + 4); HANDLE hookRemovalEvent = OpenEventW(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, ITH_REMOVEHOOK_EVENT); TextHook *in = hookman; for (int i = 0; i < currentHook; in++) { if (in->Address()) i++; if (in->Address() == removalAddress) { break; } } if (in->Address()) { in->ClearHook(); } SetEvent(hookRemovalEvent); CloseHandle(hookRemovalEvent); } 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; } void ConsoleOutput(LPCSTR text) { // jichi 12/25/2013: Rewrite the implementation if (!::live) { return; } DWORD textSize = strlen(text) + 1; DWORD dataSize = textSize + 8; BYTE *buffer = new BYTE[dataSize]; *(DWORD*)buffer = HOST_NOTIFICATION; //cmd *(DWORD*)(buffer + 4) = HOST_NOTIFICATION_TEXT; //console memcpy(buffer + 8, text, textSize); WriteFile(::hookPipe, buffer, dataSize, nullptr, nullptr); } //if (str) { // int t, len, sum; // BYTE buffer[0x80]; // BYTE *buff; // len = wcslen(str) << 1; // t = swprintf((LPWSTR)(buffer + 8),L"%d: ",currentProcessId) << 1; // sum = len + t + 8; // if (sum > 0x80) { // buff = new BYTE[sum]; // memset(buff, 0, sum); // jichi 9/25/2013: zero memory // memcpy(buff + 8, buffer + 8, t); // } // else // buff = buffer; // *(DWORD *)buff = HOST_NOTIFICATION; //cmd // *(DWORD *)(buff + 4) = HOST_NOTIFICATION_TEXT; //console // memcpy(buff + t + 8, str, len); // IO_STATUS_BLOCK ios; // NtWriteFile(hookPipe,0,0,0,&ios,buff,sum,0,0); // if (buff != buffer) // delete[] buff; // return len; //} //DWORD IOutputDWORD(DWORD d) //{ // WCHAR str[0x10]; // swprintf(str,L"%.8X",d); // ConsoleOutput(str); // return 0; //} //DWORD IOutputRegister(DWORD *base) //{ // WCHAR str[0x40]; // swprintf(str,L"EAX:%.8X",base[0]); // ConsoleOutput(str); // swprintf(str,L"ECX:%.8X",base[-1]); // ConsoleOutput(str); // swprintf(str,L"EDX:%.8X",base[-2]); // ConsoleOutput(str); // swprintf(str,L"EBX:%.8X",base[-3]); // ConsoleOutput(str); // swprintf(str,L"ESP:%.8X",base[-4]); // ConsoleOutput(str); // swprintf(str,L"EBP:%.8X",base[-5]); // ConsoleOutput(str); // swprintf(str,L"ESI:%.8X",base[-6]); // ConsoleOutput(str); // swprintf(str,L"EDI:%.8X",base[-7]); // ConsoleOutput(str); // return 0; //} //DWORD IRegisterEngineModule(DWORD idEngine, DWORD dnHook) //{ // ::IdentifyEngine = (IdentifyEngineFun)idEngine; // ::InsertDynamicHook = (InsertDynamicHookFun)dnHook; // ::engine_registered = true; // return 0; //} void NotifyHookInsert(DWORD addr) { if (!::live) { return; } BYTE buffer[0xc]; *(DWORD*)buffer = HOST_NOTIFICATION; *(DWORD*)(buffer + 4) = HOST_NOTIFICATION_NEWHOOK; *(DWORD*)(buffer + 8) = addr; WriteFile(::hookPipe, buffer, 0xc, nullptr, nullptr); return; } // EOF