From ffbb081bcc4a48b724f2906d60eeb1adc8fdbe46 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Tue, 17 Jul 2018 19:18:36 -0400 Subject: [PATCH] refactor and start using pipe instead of section to get hook info --- gui/window.cpp | 21 ++----------- vnr/profile/misc.cpp | 2 +- vnr/texthook/host/hookman.cc | 34 ++++++++++++++------- vnr/texthook/host/hookman.h | 17 +++++++---- vnr/texthook/host/host.cc | 14 ++++----- vnr/texthook/host/pipe.cc | 31 +++++++++++-------- vnr/texthook/host/textthread.cc | 2 +- vnr/vnrhook/include/const.h | 2 +- vnr/vnrhook/include/types.h | 2 +- vnr/vnrhook/src/hijack/texthook.cc | 22 -------------- vnr/vnrhook/src/hijack/texthook.h | 3 +- vnr/vnrhook/src/main.cc | 4 +-- vnr/vnrhook/src/pipe.cc | 48 +++++++++++------------------- 13 files changed, 86 insertions(+), 116 deletions(-) diff --git a/gui/window.cpp b/gui/window.cpp index c03ec99..c01c36b 100644 --- a/gui/window.cpp +++ b/gui/window.cpp @@ -363,23 +363,8 @@ bool GetHookParam(DWORD pid, DWORD hook_addr, HookParam& hp) { if (!pid) return false; - ProcessRecord *pr = ::man->GetProcessRecord(pid); - if (!pr) - return false; - bool result = false; - WaitForSingleObject(pr->hookman_mutex, 0); - const Hook *hks = (Hook *)pr->hookman_map; - for (int i = 0; i < MAX_HOOK; i++) - { - if (hks[i].Address() == hook_addr) - { - hp = hks[i].hp; - result = true; - break; - } - } - ReleaseMutex(pr->hookman_mutex); - return result; + hp = man->GetHook(pid, hook_addr).hp; + return true; } std::wstring GetEntryString(TextThread& thread) @@ -506,7 +491,7 @@ bool IsUnicodeHook(const ProcessRecord& pr, DWORD hook) { bool res = false; WaitForSingleObject(pr.hookman_mutex, 0); - auto hooks = (const Hook*)pr.hookman_map; + auto hooks = (const OldHook*)pr.hookman_map; for (DWORD i = 0; i < MAX_HOOK; i++) { if (hooks[i].Address() == hook) diff --git a/vnr/profile/misc.cpp b/vnr/profile/misc.cpp index effb5cf..789fd8e 100644 --- a/vnr/profile/misc.cpp +++ b/vnr/profile/misc.cpp @@ -257,7 +257,7 @@ std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address) { std::wstring hook_name; WaitForSingleObject(pr.hookman_mutex, 0); - auto hooks = (const Hook*)pr.hookman_map; + auto hooks = (const OldHook*)pr.hookman_map; for (int i = 0; i < MAX_HOOK; ++i) { auto& hook = hooks[i]; diff --git a/vnr/texthook/host/hookman.cc b/vnr/texthook/host/hookman.cc index 1685c6a..8387310 100644 --- a/vnr/texthook/host/hookman.cc +++ b/vnr/texthook/host/hookman.cc @@ -29,10 +29,10 @@ HookManager::HookManager() : detach(nullptr), hook(nullptr), new_thread_number(0), - threadTable(), + textThreadsByParams(), processRecordsByIds() { - TextThread* consoleTextThread = threadTable[{0, -1UL, -1UL, -1UL}] = new TextThread({ 0, -1UL, -1UL, -1UL }, new_thread_number++, splitDelay); + TextThread* consoleTextThread = textThreadsByParams[{0, -1UL, -1UL, -1UL}] = new TextThread({ 0, -1UL, -1UL, -1UL }, new_thread_number++, splitDelay); consoleTextThread->Status() |= USING_UNICODE; SetCurrent(consoleTextThread); @@ -46,7 +46,7 @@ HookManager::~HookManager() TextThread *HookManager::FindSingle(DWORD number) { - for (auto i : threadTable) + for (auto i : textThreadsByParams) { if (i.second->Number() == number) { @@ -77,7 +77,7 @@ void HookManager::RemoveSingleHook(DWORD pid, DWORD addr) { HM_LOCK; std::vector removedThreads; - for (auto i : threadTable) + for (auto i : textThreadsByParams) { if (i.second->PID() == pid && i.second->Addr() == addr) { @@ -91,7 +91,7 @@ void HookManager::RemoveSingleHook(DWORD pid, DWORD addr) } for (auto i : removedThreads) { - threadTable.erase(i); + textThreadsByParams.erase(i); } SelectCurrent(0); } @@ -100,7 +100,7 @@ void HookManager::RemoveProcessContext(DWORD pid) { HM_LOCK; std::vector removedThreads; - for (auto i : threadTable) + for (auto i : textThreadsByParams) { if (i.second->PID() == pid) { @@ -114,7 +114,7 @@ void HookManager::RemoveProcessContext(DWORD pid) } for (auto i : removedThreads) { - threadTable.erase(i); + textThreadsByParams.erase(i); } SelectCurrent(0); } @@ -159,9 +159,9 @@ void HookManager::DispatchText(DWORD pid, const BYTE *text, DWORD hook, DWORD re HM_LOCK; ThreadParameter tp = {pid, hook, retn, spl}; TextThread *it; - if (!(it = threadTable[tp])) + if (!(it = textThreadsByParams[tp])) { - it = threadTable[tp] = new TextThread(tp, new_thread_number++, splitDelay); + it = textThreadsByParams[tp] = new TextThread(tp, new_thread_number++, splitDelay); if (create) { create(it); @@ -175,7 +175,7 @@ void HookManager::AddConsoleOutput(LPCWSTR text) if (text) { int len = wcslen(text) * 2; - TextThread *console = threadTable[{0, -1UL, -1UL, -1UL}]; + TextThread *console = textThreadsByParams[{0, -1UL, -1UL, -1UL}]; console->AddSentence(std::wstring(text)); } } @@ -202,6 +202,18 @@ HANDLE HookManager::GetHostPipe(DWORD pid) return processRecordsByIds[pid] ? processRecordsByIds[pid]->hostPipe : nullptr; } +Hook HookManager::GetHook(DWORD processId, DWORD addr) +{ + HM_LOCK; + return hooksByAddresses[{ processId, addr, 0, 0}]; +} + +void HookManager::SetHook(DWORD processId, DWORD addr, Hook hook) +{ + HM_LOCK; + hooksByAddresses[{ processId, addr, 0, 0}] = hook; +} + void AddHooksToProfile(Profile& pf, const ProcessRecord& pr); DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread* thread); void MakeHookRelative(const ProcessRecord& pr, HookParam& hp); @@ -220,7 +232,7 @@ void HookManager::GetProfile(DWORD pid, pugi::xml_node profile_node) void AddHooksToProfile(Profile& pf, const ProcessRecord& pr) { WaitForSingleObject(pr.hookman_mutex, 0); - auto hooks = (const Hook*)pr.hookman_map; + auto hooks = (const OldHook*)pr.hookman_map; for (DWORD i = 0; i < MAX_HOOK; ++i) { if (hooks[i].Address() == 0) diff --git a/vnr/texthook/host/hookman.h b/vnr/texthook/host/hookman.h index 78e63b0..16cfc38 100644 --- a/vnr/texthook/host/hookman.h +++ b/vnr/texthook/host/hookman.h @@ -8,6 +8,8 @@ #include "host/textthread.h" #include "winmutex/winmutex.h" #include +#include +#include "vnrhook/include/types.h" namespace pugi { class xml_node; @@ -23,7 +25,12 @@ struct ProcessRecord { HANDLE hookman_section; LPVOID hookman_map; HANDLE hostPipe; - //std::unordered_map hooksByAddress; +}; + +struct Hook +{ + HookParam hp; + std::wstring name; }; typedef DWORD (*ProcessEventCallback)(DWORD pid); @@ -41,11 +48,10 @@ class DLLEXPORT HookManager public: HookManager(); ~HookManager(); - // jichi 12/26/2013: remove virtual modifiers TextThread *FindSingle(DWORD number); ProcessRecord *GetProcessRecord(DWORD pid); - //void LockHookman(); - //void UnlockHookman(); + Hook GetHook(DWORD processId, DWORD addr); + void SetHook(DWORD processId, DWORD addr, Hook hook); void ClearCurrent(); void SelectCurrent(DWORD num); void SetCurrent(TextThread *it); @@ -85,7 +91,8 @@ public: void GetProfile(DWORD pid, pugi::xml_node profile_node); private: - std::unordered_map threadTable; + std::unordered_map textThreadsByParams; + std::unordered_map hooksByAddresses; // Artikash 7/17/2018: retn and spl should always be zero when accessing this! std::unordered_map processRecordsByIds; CRITICAL_SECTION hmcs; diff --git a/vnr/texthook/host/host.cc b/vnr/texthook/host/host.cc index 5ab07ab..b70a83a 100644 --- a/vnr/texthook/host/host.cc +++ b/vnr/texthook/host/host.cc @@ -68,7 +68,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused) DLLEXPORT bool StartHost() { - preventDuplicationMutex = CreateMutexW(nullptr, TRUE, ITH_SERVER_MUTEX); if (GetLastError() == ERROR_ALREADY_EXISTS || ::running) { @@ -101,7 +100,6 @@ DLLEXPORT void CloseHost() DLLEXPORT bool InjectProcessById(DWORD processId, DWORD timeout) { - if (processId == GetCurrentProcessId()) { return false; @@ -158,11 +156,11 @@ DLLEXPORT DWORD InsertHook(DWORD pid, const HookParam *hp, std::string name) BYTE buffer[PIPE_BUFFER_SIZE] = {}; *(DWORD*)buffer = HOST_COMMAND_NEW_HOOK; - memcpy(buffer + 4, hp, sizeof(HookParam)); - if (name.size()) strcpy((char*)buffer + 4 + sizeof(HookParam), name.c_str()); + *(HookParam*)(buffer + sizeof(DWORD)) = *hp; + if (name.size()) strcpy((char*)buffer + sizeof(DWORD) + sizeof(HookParam), name.c_str()); DWORD unused; - WriteFile(commandPipe, buffer, 4 + sizeof(HookParam) + name.size(), &unused, nullptr); + WriteFile(commandPipe, buffer, sizeof(DWORD) + sizeof(HookParam) + name.size(), &unused, nullptr); return 0; } @@ -173,12 +171,12 @@ DLLEXPORT DWORD RemoveHook(DWORD pid, DWORD addr) return -1; HANDLE hookRemovalEvent = CreateEventW(nullptr, TRUE, FALSE, ITH_REMOVEHOOK_EVENT); - BYTE buffer[8]; + BYTE buffer[sizeof(DWORD) * 2] = {}; *(DWORD*)buffer = HOST_COMMAND_REMOVE_HOOK; - *(DWORD*)(buffer + 4) = addr; + *(DWORD*)(buffer + sizeof(DWORD)) = addr; DWORD unused; - WriteFile(commandPipe, buffer, 8, &unused, nullptr); + WriteFile(commandPipe, buffer, sizeof(DWORD) * 2, &unused, nullptr); WaitForSingleObject(hookRemovalEvent, 1000); CloseHandle(hookRemovalEvent); man->RemoveSingleHook(pid, addr); diff --git a/vnr/texthook/host/pipe.cc b/vnr/texthook/host/pipe.cc index 57d737b..14caf92 100644 --- a/vnr/texthook/host/pipe.cc +++ b/vnr/texthook/host/pipe.cc @@ -61,32 +61,37 @@ DWORD WINAPI TextReceiver(LPVOID lpThreadParameter) if (*(DWORD*)buffer == HOST_NOTIFICATION) { + USES_CONVERSION; switch (*(DWORD*)(buffer + 4)) // Artikash 7/17/2018: Notification type { - case HOST_NOTIFICATION_NEWHOOK: - { - + case HOST_NOTIFICATION_NEWHOOK: + man->SetHook(processId, + ((HookParam*)(buffer + sizeof(DWORD) * 2))->address, + { + *(HookParam*)(buffer + sizeof(DWORD) * 2), // Hook address + std::wstring(A2W( + (const char*)buffer + sizeof(DWORD) * 2 + sizeof(HookParam) // Hook name + )) + } + ); break; - } case HOST_NOTIFICATION_TEXT: - USES_CONVERSION; - man->AddConsoleOutput(A2W((LPCSTR)(buffer + 8))); + man->AddConsoleOutput(A2W((LPCSTR)(buffer + sizeof(DWORD) * 2))); // Text break; } } else { - DWORD hook = *(DWORD*)buffer; - DWORD retn = *(DWORD*)(buffer + 4); - DWORD split = *(DWORD*)(buffer + 8); // 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]); - - const BYTE *data = buffer + HEADER_SIZE; // th - int dataLength = bytesRead - HEADER_SIZE; - man->DispatchText(processId, data, hook, retn, split, dataLength); + man->DispatchText(processId, buffer + HEADER_SIZE, + *(DWORD*)buffer, // Hook address + *(DWORD*)(buffer + sizeof(DWORD)), // Return address + *(DWORD*)(buffer + sizeof(DWORD) * 2), // Split + bytesRead - HEADER_SIZE + ); } } diff --git a/vnr/texthook/host/textthread.cc b/vnr/texthook/host/textthread.cc index 347b537..4820d2e 100644 --- a/vnr/texthook/host/textthread.cc +++ b/vnr/texthook/host/textthread.cc @@ -39,7 +39,7 @@ DWORD GetHookName(LPSTR str, DWORD pid, DWORD hook_addr, DWORD max) if (!pr) return 0; WaitForSingleObject(pr->hookman_mutex, 0); - const Hook *hks = (const Hook *)pr->hookman_map; + const OldHook *hks = (const OldHook *)pr->hookman_map; for (int i = 0; i < MAX_HOOK; i++) if (hks[i].Address() == hook_addr) { len = hks[i].NameLength(); diff --git a/vnr/vnrhook/include/const.h b/vnr/vnrhook/include/const.h index 336fa32..d5630ca 100644 --- a/vnr/vnrhook/include/const.h +++ b/vnr/vnrhook/include/const.h @@ -253,7 +253,7 @@ enum { // - 0x0 dwAddr hook address // - 0x4 dwRetn return address // - 0x8 dwSplit split value -#define HEADER_SIZE 0xc +#define HEADER_SIZE sizeof(DWORD) * 3 #define TIMEOUT 5000 // 5 seconds diff --git a/vnr/vnrhook/include/types.h b/vnr/vnrhook/include/types.h index 442b766..3ff4846 100644 --- a/vnr/vnrhook/include/types.h +++ b/vnr/vnrhook/include/types.h @@ -74,7 +74,7 @@ struct SendParam { HookParam hp; }; -struct Hook { // size: 0x80 +struct OldHook { // size: 0x80 HookParam hp; LPSTR hook_name; int name_length; diff --git a/vnr/vnrhook/src/hijack/texthook.cc b/vnr/vnrhook/src/hijack/texthook.cc index 9c21bf7..ea1302f 100644 --- a/vnr/vnrhook/src/hijack/texthook.cc +++ b/vnr/vnrhook/src/hijack/texthook.cc @@ -339,8 +339,6 @@ DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn) BYTE *pbData, pbSmallBuff[SMALL_BUFF_SIZE]; DWORD dwType = hp.type; - if (!::live) // the pipe thread is busy - return 0; //if ((dwType & NO_CONTEXT) == 0 && HookFilter(dwRetn)) // return 0; @@ -730,26 +728,6 @@ int TextHook::ClearHook() return err; } -int TextHook::ModifyHook(const HookParam &hp) -{ - //WCHAR name[0x40]; - DWORD len = 0; - if (hook_name) - len = ::strlen(hook_name); - LPSTR name = 0; - if (len) { - name = new char[len + 1]; - //ITH_MEMSET_HEAP(name, 0, sizeof(wchar_t) * (len + 1)); // jichi 9/26/2013: zero memory - strcpy(name, hook_name); - } - ClearHook(); - InitHook(hp, name); - InsertHook(); - if (name) - delete[] name; - return 0; -} - int TextHook::RecoverHook() { if (hp.address) { diff --git a/vnr/vnrhook/src/hijack/texthook.h b/vnr/vnrhook/src/hijack/texthook.h index bdfe3ac..05b536d 100644 --- a/vnr/vnrhook/src/hijack/texthook.h +++ b/vnr/vnrhook/src/hijack/texthook.h @@ -26,7 +26,7 @@ void InitFilterTable(); // jichi 9/25/2013: This class will be used by NtMapViewOfSectionfor // interprocedure communication, where constructor/destructor will NOT work. -class TextHook : public Hook +class TextHook : public OldHook { int UnsafeInsertHookCode(); DWORD UnsafeSend(DWORD dwDataBase, DWORD dwRetn); @@ -40,7 +40,6 @@ public: int RecoverHook(); int RemoveHook(); int ClearHook(); - int ModifyHook(const HookParam&); int SetHookName(LPCSTR name); int GetLength(DWORD base, DWORD in); // jichi 12/25/2013: Return 0 if failed void CoolDown(); // jichi 9/28/2013: flush instruction cache on wine diff --git a/vnr/vnrhook/src/main.cc b/vnr/vnrhook/src/main.cc index 8029060..972ef4b 100644 --- a/vnr/vnrhook/src/main.cc +++ b/vnr/vnrhook/src/main.cc @@ -41,8 +41,7 @@ FilterRange *filter = _filter; WCHAR hm_section[0x100]; HANDLE hSection; -bool running, - live = false; +bool running; int currentHook = 0, user_hook_count = 0; DWORD trigger = 0; @@ -121,7 +120,6 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID unused) // jichi 10/2/2103: Cannot use __try in functions that require object unwinding //ITH_TRY { ::running = false; - ::live = false; Engine::terminate(); diff --git a/vnr/vnrhook/src/pipe.cc b/vnr/vnrhook/src/pipe.cc index 4152a65..4f3a60a 100644 --- a/vnr/vnrhook/src/pipe.cc +++ b/vnr/vnrhook/src/pipe.cc @@ -56,13 +56,11 @@ DWORD WINAPI PipeManager(LPVOID unused) ReleaseMutex(pipeAcquisitionMutex); CloseHandle(pipeAcquisitionMutex); - ::live = true; Engine::hijack(); ConsoleOutput("vnrcli:WaitForPipe: pipe connected"); while (::running) { - Sleep(STANDARD_WAIT); if (!ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE / 2, &count, nullptr)) // Artikash 5/21/2018: why / 2? wchar_t? { break; @@ -72,18 +70,20 @@ DWORD WINAPI PipeManager(LPVOID unused) { case HOST_COMMAND_NEW_HOOK: buffer[count] = 0; - NewHook(*(HookParam *)(buffer + 4), (LPSTR)(buffer + 4 + sizeof(HookParam)), 0); + NewHook(*(HookParam *)(buffer + sizeof(DWORD)), // Hook parameter + (LPSTR)(buffer + 4 + sizeof(HookParam)), // Hook name + 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) + if (in->Address() == *(DWORD *)(buffer + sizeof(DWORD))) // Hook address { break; } @@ -102,8 +102,9 @@ DWORD WINAPI PipeManager(LPVOID unused) break; } } + CloseHandle(::hookPipe); + CloseHandle(hostPipe); - ::live = false; for (int i = 0, count = 0; count < ::currentHook; i++) { if (hookman[i].RemoveHook()) @@ -111,44 +112,31 @@ DWORD WINAPI PipeManager(LPVOID unused) count++; } } - CloseHandle(::hookPipe); - CloseHandle(hostPipe); } FreeLibraryAndExitThread(::currentModule, 0); 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); +{ + BYTE buffer[PIPE_BUFFER_SIZE]; + *(DWORD*)buffer = HOST_NOTIFICATION; + *(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_TEXT; + strcpy((char*)buffer + sizeof(DWORD) * 2, text); DWORD unused; - WriteFile(::hookPipe, buffer, dataSize, &unused, nullptr); + WriteFile(::hookPipe, buffer, strlen(text) + sizeof(DWORD) * 2, &unused, nullptr); } -// Artikash 7/3/2018: TODO: Finish using this in vnrhost instead of section to deliver hook name +// Artikash 7/3/2018: TODO: Finish using this in vnrhost instead of section to deliver hook info void NotifyHookInsert(HookParam hp, LPCSTR name) { - if (!::live) - { - return; - } BYTE buffer[PIPE_BUFFER_SIZE]; *(DWORD*)buffer = HOST_NOTIFICATION; - *(DWORD*)(buffer + 4) = HOST_NOTIFICATION_NEWHOOK; - *(HookParam*)(buffer + 8) = hp; - strcpy((char*)buffer + 8 + sizeof(HookParam), name); + *(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_NEWHOOK; + *(HookParam*)(buffer + sizeof(DWORD) * 2) = hp; + strcpy((char*)buffer + sizeof(DWORD) * 2 + sizeof(HookParam), name); DWORD unused; - WriteFile(::hookPipe, buffer, strlen(name) + 8 + sizeof(HookParam), &unused, nullptr); + WriteFile(::hookPipe, buffer, strlen(name) + sizeof(DWORD) * 2 + sizeof(HookParam), &unused, nullptr); return; }