354 lines
10 KiB
C++
Raw Normal View History

// 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 <cstdio> // for swprintf
//#include <ITH\AVL.h>
//#include <ITH\ntdll.h>
WCHAR detach_mutex[0x20];
//WCHAR write_event[0x20];
//WCHAR engine_event[0x20];
//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
//WCHAR command[] = L"\\??\\pipe\\ITH_COMMAND";
wchar_t recv_pipe[] = ITH_TEXT_PIPE;
wchar_t command[] = ITH_COMMAND_PIPE;
LARGE_INTEGER wait_time = {-100*10000, -1};
LARGE_INTEGER sleep_time = {-20*10000, -1};
DWORD engine_type;
DWORD module_base;
HANDLE hPipe,
hCommand,
hDetach; //,hLose;
//InsertHookFun InsertHook;
//IdentifyEngineFun IdentifyEngine;
//InsertDynamicHookFun InsertDynamicHook;
// jichi 9/28/2013: protect pipe on wine
// Put the definition in this file so that it might be inlined
void CliUnlockPipe()
{
if (IthIsWine())
IthReleaseMutex(::hmMutex);
}
void CliLockPipe()
{
if (IthIsWine()) {
const LONGLONG timeout = -50000000; // in nanoseconds = 5 seconds
NtWaitForSingleObject(hmMutex, 0, (PLARGE_INTEGER)&timeout);
}
}
HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction)
{
UNICODE_STRING us;
RtlInitUnicodeString(&us,name);
SECURITY_DESCRIPTOR sd = {1};
OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
HANDLE hFile;
IO_STATUS_BLOCK isb;
if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0)))
return hFile;
else
return INVALID_HANDLE_VALUE;
}
DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter) // Dynamically detect ITH main module status.
{
CC_UNUSED(lpThreadParameter);
// 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);
//hEngine=IthCreateEvent(engine_event);
//NtWaitForSingleObject(hEngine,0,0);
//NtClose(hEngine);
//while (!engine_registered)
// NtDelayExecution(0, &wait_time);
//LoadEngine(L"ITH_Engine.dll");
u.module = module_base;
u.pid = current_process_id;
u.man = hookman;
//u.engine = engine_base; // jichi 10/19/2014: disable the second dll
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;
hCommand = INVALID_HANDLE_VALUE;
while (NtWaitForSingleObject(hPipeExist, 0, &wait_time) == WAIT_TIMEOUT)
if (!::running)
goto _release;
HANDLE hMutex = IthCreateMutex(ITH_GRANTPIPE_MUTEX, 0);
NtWaitForSingleObject(hMutex, 0, 0);
while (::hPipe == INVALID_HANDLE_VALUE||
hCommand == INVALID_HANDLE_VALUE) {
NtDelayExecution(0, &sleep_time);
if (::hPipe == INVALID_HANDLE_VALUE)
::hPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE);
if (hCommand == INVALID_HANDLE_VALUE)
hCommand = IthOpenPipe(command, GENERIC_READ);
}
//NtClearEvent(hLose);
CliLockPipe();
NtWriteFile(::hPipe, 0, 0, 0, &ios, &u, sizeof(u), 0, 0);
CliUnlockPipe();
for (int i = 0, count = 0; count < ::current_hook; 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);
//OutputDWORD(tree->Count());
NtReleaseMutant(hMutex,0);
NtClose(hMutex);
::live = true;
// jichi 7/17/2014: Always hijack by default or I have to wait for it is ready
Engine::hijack();
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
::hDetach = IthCreateMutex(::detach_mutex,1);
while (::running && NtWaitForSingleObject(hPipeExist, 0, &sleep_time) == WAIT_OBJECT_0)
NtDelayExecution(0, &sleep_time);
::live = false;
for (int i = 0, count = 0; count < ::current_hook; 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);
//CliUnlockPipe();
IthReleaseMutex(::hDetach);
}
NtClose(::hDetach);
NtClose(::hPipe);
}
_release:
//NtClose(hLose);
NtClose(hPipeExist);
return 0;
}
DWORD WINAPI CommandPipe(LPVOID lpThreadParameter)
{
CC_UNUSED(lpThreadParameter);
DWORD command;
BYTE buff[0x400] = {};
HANDLE hPipeExist;
hPipeExist = IthOpenEvent(ITH_PIPEEXISTS_EVENT);
IO_STATUS_BLOCK ios={};
if (hPipeExist != INVALID_HANDLE_VALUE)
while (::running) {
while (!::live) {
if (!::running)
goto _detach;
NtDelayExecution(0, &sleep_time);
}
// jichi 9/27/2013: Why 0x200 not 0x400? wchar_t?
switch (NtReadFile(hCommand, 0, 0, 0, &ios, buff, 0x200, 0, 0)) {
case STATUS_PIPE_BROKEN:
case STATUS_PIPE_DISCONNECTED:
NtClearEvent(hPipeExist);
continue;
case STATUS_PENDING:
NtWaitForSingleObject(hCommand, 0, 0);
switch (ios.Status) {
case STATUS_PIPE_BROKEN:
case STATUS_PIPE_DISCONNECTED:
NtClearEvent(hPipeExist);
continue;
case 0: break;
default:
if (NtWaitForSingleObject(::hDetach, 0, &wait_time) == WAIT_OBJECT_0)
goto _detach;
}
}
if (ios.uInformation && ::live) {
command = *(DWORD *)buff;
switch(command) {
case HOST_COMMAND_NEW_HOOK:
//IthBreak();
buff[ios.uInformation] = 0;
//buff[ios.uInformation + 1] = 0;
NewHook(*(HookParam *)(buff + 4), (LPSTR)(buff + 4 + sizeof(HookParam)), 0);
break;
case HOST_COMMAND_REMOVE_HOOK:
{
DWORD rm_addr = *(DWORD *)(buff+4);
HANDLE hRemoved = IthOpenEvent(ITH_REMOVEHOOK_EVENT);
TextHook *in = hookman;
for (int i = 0; i < current_hook; in++) {
if (in->Address()) i++;
if (in->Address() == rm_addr) break;
}
if (in->Address())
in->ClearHook();
IthSetEvent(hRemoved);
NtClose(hRemoved);
} break;
#if 0 // Temporarily disabled as these operations are not used by VNR
case HOST_COMMAND_MODIFY_HOOK:
{
DWORD rm_addr = *(DWORD *)(buff + 4);
HANDLE hModify = IthOpenEvent(ITH_MODIFYHOOK_EVENT);
TextHook *in = hookman;
for (int i = 0; i < current_hook; in++) {
if (in->Address())
i++;
if (in->Address() == rm_addr)
break;
}
if (in->Address())
in->ModifyHook(*(HookParam *)(buff + 4));
IthSetEvent(hModify);
NtClose(hModify);
} break;
case HOST_COMMAND_HIJACK_PROCESS:
Engine::hijack();
break;
#endif // 0
case HOST_COMMAND_DETACH:
::running = false;
::live = false;
goto _detach;
}
}
}
_detach:
NtClose(hPipeExist);
NtClose(hCommand);
Util::unloadCurrentModule(); // jichi: this is not always needed
return 0;
}
//extern "C" {
void ConsoleOutput(LPCSTR text)
{ // jichi 12/25/2013: Rewrite the implementation
if (!live || !text)
return;
enum { buf_size = 0x50 };
BYTE buf[buf_size]; // buffer is needed to append the message header
size_t text_size = strlen(text) + 1;
size_t data_size = text_size + 8;
BYTE *data = (data_size <= buf_size) ? buf : new BYTE[data_size];
*(DWORD *)data = HOST_NOTIFICATION; //cmd
*(DWORD *)(data + 4) = HOST_NOTIFICATION_TEXT; //console
memcpy(data + 8, text, text_size);
IO_STATUS_BLOCK ios;
NtWriteFile(hPipe, 0, 0, 0, &ios, data, data_size, 0, 0);
if (data != buf)
delete[] data;
}
//if (str) {
// int t, len, sum;
// BYTE buffer[0x80];
// BYTE *buff;
// len = wcslen(str) << 1;
// t = swprintf((LPWSTR)(buffer + 8),L"%d: ",current_process_id) << 1;
// sum = len + t + 8;
// if (sum > 0x80) {
// buff = new BYTE[sum];
// memset(buff, 0, sum); // jichi 9/25/2013: zero memory
// memcpy(buff + 8, buffer + 8, t);
// }
// else
// buff = buffer;
// *(DWORD *)buff = HOST_NOTIFICATION; //cmd
// *(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);
// 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;
//}
DWORD NotifyHookInsert(DWORD addr)
{
if (live) {
BYTE buffer[0x10];
*(DWORD *)buffer = HOST_NOTIFICATION;
*(DWORD *)(buffer + 4) = HOST_NOTIFICATION_NEWHOOK;
*(DWORD *)(buffer + 8) = addr;
*(DWORD *)(buffer + 0xc) = 0;
IO_STATUS_BLOCK ios;
CliLockPipe();
NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0);
CliUnlockPipe();
}
return 0;
}
//} // extern "C"
// EOF