diff options
| -rw-r--r-- | include/soyuz/library.hh | 4 | ||||
| -rw-r--r-- | include/soyuz/resource.hh | 17 | ||||
| -rw-r--r-- | include/soyuz/soyuz.hh | 1 | ||||
| -rw-r--r-- | include/soyuz/tray.hh | 26 | ||||
| -rw-r--r-- | include/soyuz/windows.hh | 3 | ||||
| -rw-r--r-- | resource/resource.rc | 44 | ||||
| -rw-r--r-- | resource/soyuz.ico | bin | 0 -> 14982 bytes | |||
| -rw-r--r-- | soyuz/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | soyuz/library.cc | 23 | ||||
| -rw-r--r-- | soyuz/soyuz.cc | 84 | ||||
| -rw-r--r-- | soyuz/tray.cc | 135 | ||||
| -rw-r--r-- | soyuz/windows.cc | 3 |
12 files changed, 324 insertions, 20 deletions
diff --git a/include/soyuz/library.hh b/include/soyuz/library.hh index 41668a7..ae7ce13 100644 --- a/include/soyuz/library.hh +++ b/include/soyuz/library.hh @@ -11,8 +11,12 @@ #define NT_SUCCESS(status) (status >= 0) #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +namespace soyuz { + static auto enum_windows_proc(HWND hwnd, LPARAM lparam) -> BOOL; auto find_lunar() -> DWORD; auto delete_handle(DWORD pid) -> int; +} + #endif //SOYUZ_LIBRARY_HH diff --git a/include/soyuz/resource.hh b/include/soyuz/resource.hh new file mode 100644 index 0000000..89c1242 --- /dev/null +++ b/include/soyuz/resource.hh @@ -0,0 +1,17 @@ +// Copyright (C) 2021-2021 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef SOYUZ_RESOURCE_HH +#define SOYUZ_RESOURCE_HH + +#pragma once + +#include <shellapi.h> +#include <Windows.h> + +#define ICO1 101 +#define ID_TRAY_APP_ICON 1001 +#define ID_TRAY_EXIT 1002 +#define WM_SYSICON (WM_USER + 1) + +#endif //SOYUZ_RESOURCE_HH diff --git a/include/soyuz/soyuz.hh b/include/soyuz/soyuz.hh index 20cf432..99ffaa4 100644 --- a/include/soyuz/soyuz.hh +++ b/include/soyuz/soyuz.hh @@ -8,5 +8,6 @@ #define LUNAR_WINDOW_NAME_BASE "Lunar Client (" #define DISCORD_IPC_NAMED_PIPE_NAME L"\\Device\\NamedPipe\\discord-ipc-0" +#define WINDOW_TRAY_NAME "Soyuz - 1.1.0 | Copyright (C) 2021-2021 Fuwn" #endif //SOYUZ_SOYUZ_HH diff --git a/include/soyuz/tray.hh b/include/soyuz/tray.hh new file mode 100644 index 0000000..27c3214 --- /dev/null +++ b/include/soyuz/tray.hh @@ -0,0 +1,26 @@ +// Copyright (C) 2021-2021 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef SOYUZ_TRAY_HH +#define SOYUZ_TRAY_HH + +#pragma once + +#include <string> +#include <vector> +#include <Windows.h> + +#define LOG(message) logs.push_back(message); + +auto WindowProcedure(HWND, UINT, WPARAM, LPARAM) -> LRESULT; // CALLBACK +auto minimize() -> void; +auto restore() -> void; +auto InitNotifyIconData() -> void; + +namespace soyuz { + +auto log(const std::string &message) -> void; + +} + +#endif //SOYUZ_TRAY_HH diff --git a/include/soyuz/windows.hh b/include/soyuz/windows.hh index dd145ac..f709444 100644 --- a/include/soyuz/windows.hh +++ b/include/soyuz/windows.hh @@ -1,3 +1,6 @@ +// Copyright (C) 2021-2021 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + #ifndef SOYUZ_WINDOWS_HH #define SOYUZ_WINDOWS_HH diff --git a/resource/resource.rc b/resource/resource.rc new file mode 100644 index 0000000..32cf3e6 --- /dev/null +++ b/resource/resource.rc @@ -0,0 +1,44 @@ +// Copyright (C) 2021-2021 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + +#include "soyuz/resource.hh" + +ICO1 ICON DISCARDABLE "soyuz.ico" + + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1.1.0 // 1,0,0,0 +FILEFLAGSMASK 0x3fL +#ifdef _DEBUG +FILEFLAGS 0x9L +#else +FILEFLAGS 0x8L +#endif +FILEOS 0x40004L +FILETYPE 0x2L +FILESUBTYPE 0x0L +BEGIN +BLOCK "StringFileInfo" +BEGIN +BLOCK "040904b0" +BEGIN +VALUE "Comments", "\0" +VALUE "CompanyName", "Fuwn Technologies\0" +VALUE "FileDescription", "Discord RPC Blocker for Lunar Client\0" +VALUE "FileVersion", "1,0,0,0\0" +VALUE "InternalName", "Soyuz\0" +VALUE "LegalCopyright", "Copyright (C) 2021-2021 Fuwn\0" +VALUE "LegalTrademarks", "\0" +VALUE "OriginalFilename", "soyuz.exe\0" +VALUE "PrivateBuild", "1\0" +VALUE "ProductName", "Soyuz\0" +VALUE "ProductVersion", "1.1.0\0" // 10, 0, 0, 0 +VALUE "SpecialBuild", "\0" +END +END +BLOCK "VarFileInfo" +BEGIN +VALUE "Translation", 0x409, 1200 +END +END diff --git a/resource/soyuz.ico b/resource/soyuz.ico Binary files differnew file mode 100644 index 0000000..3b2f9cc --- /dev/null +++ b/resource/soyuz.ico diff --git a/soyuz/CMakeLists.txt b/soyuz/CMakeLists.txt index 01eddb7..fdf5897 100644 --- a/soyuz/CMakeLists.txt +++ b/soyuz/CMakeLists.txt @@ -1,5 +1,7 @@ -add_executable(${PROJECT_NAME} +add_executable(${PROJECT_NAME} WIN32 + tray.cc library.cc + ../resource/resource.rc soyuz.cc windows.cc ) diff --git a/soyuz/library.cc b/soyuz/library.cc index 5356bcd..bf2b451 100644 --- a/soyuz/library.cc +++ b/soyuz/library.cc @@ -3,20 +3,24 @@ #include <cstdio> #include <memory> +#include <sstream> #include <string> #include <Windows.h> #include "soyuz/library.hh" #include "soyuz/soyuz.hh" +#include "soyuz/tray.hh" #include "soyuz/windows.hh" +namespace soyuz { + static auto enum_windows_proc(HWND hwnd, LPARAM lparam) -> BOOL { int length = GetWindowTextLength(hwnd); auto title = new CHAR[length + 1]; GetWindowText(hwnd, title, length); if (strstr(title, LUNAR_WINDOW_NAME_BASE)) { - *((HWND*)lparam) = hwnd; + *((HWND *)lparam) = hwnd; delete[] title; @@ -48,7 +52,9 @@ auto delete_handle(DWORD pid) -> int { pid ); if (!lunar) { - printf("could not open handle to lunar client: %lu\n", GetLastError()); + std::stringstream ss; + ss << "could not open handle to lunar client: " << GetLastError(); + soyuz::log(ss.str()); return 1; } @@ -69,12 +75,12 @@ auto delete_handle(DWORD pid) -> int { if (NT_SUCCESS(status)) { break; } if (status == STATUS_INFO_LENGTH_MISMATCH) { size += 1 << 10; continue; } - printf("could not enumerate handle\n"); + soyuz::log("could not enumerate handle, skipping"); return 1; } - auto *info = reinterpret_cast<PROCESS_HANDLE_SNAPSHOT_INFORMATION*>(buffer.get()); + auto *info = reinterpret_cast<PROCESS_HANDLE_SNAPSHOT_INFORMATION *>(buffer.get()); for (ULONG i = 0; i < info->NumberOfHandles; ++i) { HANDLE h = info->Handles[i].HandleValue; HANDLE target; @@ -105,23 +111,22 @@ auto delete_handle(DWORD pid) -> int { swprintf_s(target_name, DISCORD_IPC_NAMED_PIPE_NAME); size_t length = wcslen(target_name); - auto *name = reinterpret_cast<UNICODE_STRING*>(name_buffer); + auto *name = reinterpret_cast<UNICODE_STRING *>(name_buffer); if (name->Buffer && _wcsnicmp(name->Buffer, target_name, length) == 0) { - printf("found lunar client's discord ipc named pipe\n"); + soyuz::log("found lunar client's discord ipc named pipe"); DuplicateHandle( lunar, h, GetCurrentProcess(), &target, - 0, FALSE, DUPLICATE_CLOSE_SOURCE ); CloseHandle(target); - printf("closed lunar client's discord ipc named pipe\n"); + soyuz::log("closed lunar client's discord ipc named pipe"); return 0; } @@ -129,3 +134,5 @@ auto delete_handle(DWORD pid) -> int { return 0; } + +} diff --git a/soyuz/soyuz.cc b/soyuz/soyuz.cc index f6be4e2..b030bd5 100644 --- a/soyuz/soyuz.cc +++ b/soyuz/soyuz.cc @@ -3,25 +3,87 @@ #pragma comment(lib, "ntdll.lib") -#include <cstdio> +#include <thread> #include <Windows.h> #include "soyuz/library.hh" +#include "soyuz/resource.hh" +#include "soyuz/tray.hh" -auto main() -> int { - DWORD pid = find_lunar(); - if (pid == 0 || pid == 3435973836) { - printf("could not locate lunar client\n"); +extern UINT WM_TASKBAR; +extern HWND window; +extern HMENU menu; +extern NOTIFYICONDATA data; +extern TCHAR tip[64]; +extern char class_name[]; +extern std::vector<std::string> logs; - return 1; +auto WinMain(HINSTANCE instance, HINSTANCE previous, LPSTR argument, int show) -> int { // WINAPI + MSG messages; + WNDCLASSEX wincl; + WM_TASKBAR = RegisterWindowMessageA("TaskbarCreated"); + + wincl.hInstance = instance; + wincl.lpszClassName = class_name; + wincl.lpfnWndProc = WindowProcedure; + wincl.style = CS_DBLCLKS; + wincl.cbSize = sizeof(WNDCLASSEX); + + wincl.hIcon = LoadIcon (GetModuleHandle(nullptr), MAKEINTRESOURCE(ICO1)); + wincl.hIconSm = LoadIcon (GetModuleHandle(nullptr), MAKEINTRESOURCE(ICO1)); + wincl.hCursor = LoadCursor (nullptr, IDC_ARROW); + wincl.lpszMenuName = nullptr; + wincl.cbClsExtra = 0; + wincl.cbWndExtra = 0; + wincl.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(255, 255, 255))); + if (!RegisterClassEx (&wincl)) { + return 0; } - printf("located lunar client: %lu\n\n", pid); - for (;;) { - if (delete_handle(pid) == 1) { - printf("unable to close lunar client's discord ipc named pipe\n"); + window = CreateWindowEx( + 0, + class_name, + class_name, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 544, + 375, + HWND_DESKTOP, + nullptr, + instance, + nullptr + ); + InitNotifyIconData(); + ShowWindow(window, show); + + // https://medium.com/@vgasparyan1995/a-new-thread-in-c-20-jthread-ebd121ae8906 + std::jthread soyuz {[](const std::stop_token& stop) -> void { + DWORD pid = soyuz::find_lunar(); + if (pid == 0 || pid == 3435973836) { + soyuz::log("could not locate lunar client"); + + exit(1); } + std::stringstream ss; + ss << "located lunar client: pid " << pid; + soyuz::log(ss.str()); + + while (!stop.stop_requested()) { + if (soyuz::delete_handle(pid) == 1) { + soyuz::log("unable to close lunar client's discord ipc named pipe"); + } + } + }}; + + while (GetMessage(&messages, nullptr, 0, 0)) { + TranslateMessage(&messages); + DispatchMessage(&messages); } - return 0; + soyuz::log("requesting exit"); + soyuz.request_stop(); soyuz.join(); + + soyuz::log("exiting"); + return (int)messages.wParam; } diff --git a/soyuz/tray.cc b/soyuz/tray.cc new file mode 100644 index 0000000..1796bf0 --- /dev/null +++ b/soyuz/tray.cc @@ -0,0 +1,135 @@ +// Copyright (C) 2021-2021 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + +#include "soyuz/tray.hh" +#include "soyuz/resource.hh" +#include "soyuz/soyuz.hh" + +UINT WM_TASKBAR = 0; +HWND window; +HMENU menu; +NOTIFYICONDATA data; +TCHAR tip[64] = TEXT(WINDOW_TRAY_NAME); +char class_name[] = WINDOW_TRAY_NAME; +std::vector<std::string> logs = { + "lunar client has been hooked, you may now close this window", +}; + +auto WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT { // CALLBACK + if (message == WM_TASKBAR && !IsWindowVisible(window)) { + minimize(); return 0; + } + + switch (message) { + case WM_ACTIVATE: + Shell_NotifyIcon(NIM_ADD, &data); + break; + + case WM_PAINT: { + PAINTSTRUCT ps; + RECT rect; + HDC hdc = BeginPaint(window, &ps); + + GetClientRect(hwnd, &rect); + + int height = 5; + for (const auto &i : logs) { + TextOut(hdc, 5, height, i.c_str(), (int)strlen(i.c_str())); + height += 20; + } + + EndPaint(window, &ps); + } break; + + case WM_CREATE: + ShowWindow(window, SW_HIDE); + menu = CreatePopupMenu(); + AppendMenu(menu, MF_STRING, ID_TRAY_EXIT, TEXT("Exit Soyuz")); + + break; + + case WM_SYSCOMMAND: + switch(wParam & 0xFFF0) { + case SC_MINIMIZE: + case SC_CLOSE: + minimize(); return 0; // break; + } break; + + case WM_SYSICON: { + switch (wParam) { + case ID_TRAY_APP_ICON: + SetForegroundWindow(window); + break; + + default: ; + } + + if (lParam == WM_LBUTTONUP) { + restore(); + } else if (lParam == WM_RBUTTONDOWN) { + POINT curPoint; + GetCursorPos(&curPoint); + SetForegroundWindow(window); + + UINT clicked = TrackPopupMenu( + menu, + TPM_RETURNCMD | TPM_NONOTIFY, + curPoint.x, + curPoint.y, + 0, + hwnd, + nullptr + ); + + SendMessage(hwnd, WM_NULL, 0, 0); + if (clicked == ID_TRAY_EXIT) { + Shell_NotifyIcon(NIM_DELETE, &data); + PostQuitMessage(0); + } + } + } break; + + case WM_NCHITTEST: { + LRESULT uHitTest = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam); + if (uHitTest == HTCLIENT) { + return HTCAPTION; + } else { + return uHitTest; + } + } + + case WM_CLOSE: + minimize(); return 0; // break; + + case WM_DESTROY: + PostQuitMessage (0); break; + + default: ; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + +void minimize() { ShowWindow(window, SW_HIDE); } +void restore() { ShowWindow(window, SW_SHOW); } + +void InitNotifyIconData() { + memset(&data, 0, sizeof(NOTIFYICONDATA)); + + data.cbSize = sizeof(NOTIFYICONDATA); + data.hWnd = window; + data.uID = ID_TRAY_APP_ICON; + data.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + data.uCallbackMessage = WM_SYSICON; + data.hIcon = (HICON)LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(ICO1)); + strncpy_s(data.szTip, tip, sizeof(tip)); +} + +namespace soyuz { + +auto log(const std::string &message) -> void { + LOG(message) + RedrawWindow(window, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); +} + +} diff --git a/soyuz/windows.cc b/soyuz/windows.cc index df1d08f..4cc84fc 100644 --- a/soyuz/windows.cc +++ b/soyuz/windows.cc @@ -1 +1,4 @@ +// Copyright (C) 2021-2021 Fuwn +// SPDX-License-Identifier: GPL-3.0-only + #include "soyuz/windows.hh" |