Last active
August 10, 2020 03:09
-
-
Save anirudhb/13889286632d37b31d2fdbb1326ac2c4 to your computer and use it in GitHub Desktop.
AbsoluteTouchEx patch to inject into existing process
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git "a/atdll/atdll.cpp" "b/atdll/atdll.cpp" | |
index 280349b..22e818c 100644 | |
--- "a/atdll/atdll.cpp" | |
+++ "b/atdll/atdll.cpp" | |
@@ -9,6 +9,8 @@ | |
#include <hidsdi.h> | |
#include <hidpi.h> | |
#include <hidusage.h> | |
+#include <TlHelp32.h> | |
+#include <iostream> | |
#include "detours.h" | |
// Version number | |
@@ -173,6 +175,9 @@ static thread_local RAWINPUT t_injectedInput; | |
// Holds the current primary touch point ID | |
static thread_local ULONG t_primaryContactID; | |
+// Holds the hWnd to add hotkey for | |
+static HWND g_hWndToHook; | |
+ | |
// Allocates a malloc_ptr with the given size. The size must be | |
// greater than or equal to sizeof(T). | |
template<typename T> | |
@@ -883,19 +900,30 @@ AT_WndProcHook( | |
WPARAM wParam, | |
LPARAM lParam) | |
{ | |
+ if (g_hWndToHook == hWnd) { | |
+ std::cout << "Running deferred hotkey hooking" << std::endl; | |
+ RegisterHotKey(hWnd, HOTKEY_ENABLE_ID, HOTKEY_ENABLE_MOD, HOTKEY_ENABLE_VK); | |
+ RegisterHotKey(hWnd, HOTKEY_CALIBRATION_ID, HOTKEY_CALIBRATION_MOD, HOTKEY_CALIBRATION_VK); | |
+ RegisterHotKey(hWnd, HOTKEY_LOAD_ID, HOTKEY_LOAD_MOD, HOTKEY_LOAD_VK); | |
+ RegisterHotKey(hWnd, HOTKEY_SAVE_ID, HOTKEY_SAVE_MOD, HOTKEY_SAVE_VK); | |
+ g_hWndToHook = NULL; | |
+ } | |
if (message == WM_HOTKEY && wParam == HOTKEY_ENABLE_ID) { | |
g_enabled = !g_enabled; | |
debugf("Absolute touch mode -> %s", g_enabled ? "ON" : "OFF"); | |
return 0; | |
@@ -935,7 +966,7 @@ static BOOL WINAPI | |
AT_RegisterRawInputDevicesHook( | |
PCRAWINPUTDEVICE pRawInputDevices, | |
UINT uiNumDevices, | |
- UINT cbSize) | |
+ UINT cbSize, bool isHookingExistingDevices = false) | |
{ | |
if (uiNumDevices == 0) { | |
debugf("RegisterRawInputDevices called with no devices"); | |
@@ -953,16 +984,22 @@ AT_RegisterRawInputDevicesHook( | |
// chances are that only one window will be receiving raw input. Ignore errors. | |
// This is a bit ugly, but it works well enough for our purposes. | |
debugf("Registering global hotkeys with hWnd=%p", hWnd); | |
+ if (isHookingExistingDevices && g_hWndToHook == NULL) { | |
+ std::cout << "Deferring hotkey hooking to hooked WndProc" << std::endl; | |
+ g_hWndToHook = hWnd; | |
+ } | |
+ else if (!isHookingExistingDevices) { | |
RegisterHotKey(hWnd, HOTKEY_ENABLE_ID, HOTKEY_ENABLE_MOD, HOTKEY_ENABLE_VK); | |
RegisterHotKey(hWnd, HOTKEY_CALIBRATION_ID, HOTKEY_CALIBRATION_MOD, HOTKEY_CALIBRATION_VK); | |
RegisterHotKey(hWnd, HOTKEY_LOAD_ID, HOTKEY_LOAD_MOD, HOTKEY_LOAD_VK); | |
RegisterHotKey(hWnd, HOTKEY_SAVE_ID, HOTKEY_SAVE_MOD, HOTKEY_SAVE_VK); | |
- | |
+ } | |
debugf("Registering touchpad input with hWnd=%p", hWnd); | |
try { | |
@@ -1133,10 +1171,53 @@ AT_PrintSystemInfo() | |
} | |
} | |
+// Callback for EnumThreadWindows. | |
+BOOL CALLBACK EnumWindowProc(HWND hwnd, LPARAM /*lParam*/) { | |
+#ifdef _WIN64 | |
+ WNDPROC windowProc = (WNDPROC)g_originalGetWindowLongPtrW(hwnd, GWL_WNDPROC); | |
+#else | |
+ WNDPROC windowProc = (WNDPROC)g_originalGetWindowLongW(hwnd, GWL_WNDPROC); | |
+#endif | |
+ if (windowProc == NULL) { | |
+ std::cout << "Window proc is null, skipping this window" << std::endl; | |
+ return TRUE; | |
+ } | |
+ if (windowProc == AT_WndProcHook) { | |
+ std::cout << "Window seems to be already hooked, skipping" << std::endl; | |
+ return TRUE; | |
+} | |
+#ifdef _WIN64 | |
+ WNDPROC prevWindowProc = (WNDPROC)g_originalSetWindowLongPtrW(hwnd, GWL_WNDPROC, (LONG_PTR)&AT_WndProcHook); | |
+#else | |
+ WNDPROC prevWindowProc = (WNDPROC)g_originalSetWindowLongW(hwnd, GWL_WNDPROC, (LONG)&AT_WndProcHook); | |
+#endif | |
+ g_originalWndProcs[hwnd] = prevWindowProc; | |
+ std::cout << "Patched existing window proc, hwnd = " << hwnd << std::endl; | |
+ return TRUE; | |
+} | |
+ | |
// Called at startup to patch all the WinAPI functions. | |
static void | |
AT_Initialize() | |
{ | |
+ AllocConsole(); | |
DetourTransactionBegin(); | |
DetourUpdateThread(GetCurrentThread()); | |
DetourAttach((void**)&g_originalRegisterRawInputDevices, AT_RegisterRawInputDevicesHook); | |
@@ -1152,6 +1233,30 @@ AT_Initialize() | |
if (DetourTransactionCommit() != NO_ERROR) { | |
throw std::runtime_error("Failed to commit Detours transaction"); | |
} | |
+ | |
+ // Enumerate all current windows and replace their procs | |
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); | |
+ if (snapshot == INVALID_HANDLE_VALUE) { | |
+ std::cerr << "Invalid CreateToolhelp32Snapshot" << std::endl; | |
+ return; | |
+ } | |
+ THREADENTRY32 te; | |
+ te.dwSize = sizeof(THREADENTRY32); | |
+ if (Thread32First(snapshot, &te)) { | |
+ do { | |
+ EnumThreadWindows(te.th32ThreadID, EnumWindowProc, NULL); | |
+ } while (Thread32Next(snapshot, &te)); | |
+ } | |
+ else { | |
+ std::cerr << "Cannot get first thread from snapshot" << std::endl; | |
+ } | |
+ // Enumerate raw input devices and re-register if needed | |
+ PRAWINPUTDEVICE devices; | |
+ UINT numDevices; | |
+ GetRegisteredRawInputDevices(NULL, &numDevices, sizeof(RAWINPUTDEVICE)); | |
+ devices = (PRAWINPUTDEVICE)malloc(numDevices * sizeof(RAWINPUTDEVICE)); | |
+ GetRegisteredRawInputDevices(devices, &numDevices, sizeof(RAWINPUTDEVICE)); | |
+ AT_RegisterRawInputDevicesHook(devices, numDevices, sizeof(RAWINPUTDEVICE), true); | |
} | |
// Called at shutdown to unpatch all the WinAPI functions | |
@@ -1184,6 +1289,7 @@ AT_Uninitialize() | |
if (DetourTransactionCommit() != NO_ERROR) { | |
throw std::runtime_error("Failed to commit Detours transaction"); | |
} | |
+ FreeConsole(); | |
} | |
BOOL APIENTRY | |
diff --git "a/atloader/atloader.cpp" "b/atloader/atloader.cpp" | |
index 0fc3c84..448539c 100644 | |
--- "a/atloader/atloader.cpp" | |
+++ "b/atloader/atloader.cpp" | |
@@ -2,6 +2,8 @@ | |
#include <iostream> | |
#include <string> | |
#include <Windows.h> | |
+#include <TlHelp32.h> | |
+#include <conio.h> | |
#include "Detours.h" | |
// C++ exception wrapping the Win32 GetLastError() status | |
@@ -40,28 +42,49 @@ main(int argc, char *argv[]) | |
std::string exePath(path); | |
std::string exeDir = exePath.substr(0, exePath.find_last_of('\\')); | |
std::string atDllPath = exeDir + "\\atdll.dll"; | |
- std::string targetPath = exeDir + "\\attest.exe"; | |
- if (argc >= 2) { | |
- targetPath = argv[1]; | |
+ std::wstring targetProcess = L"osu!.exe"; | |
+ | |
+ PROCESSENTRY32 pe32; | |
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); | |
+ if (snapshot == INVALID_HANDLE_VALUE) { | |
+ std::cerr << "Invalid handle for CreateToolhelp32Snapshot" << std::endl; | |
+ return 1; | |
} | |
- STARTUPINFOA startupInfo = { 0 }; | |
- startupInfo.cb = sizeof(startupInfo); | |
- PROCESS_INFORMATION procInfo; | |
- if (!DetourCreateProcessWithDllExA( | |
- targetPath.c_str(), | |
- nullptr, | |
- nullptr, | |
- nullptr, | |
- TRUE, | |
- 0, | |
- nullptr, | |
- nullptr, | |
- &startupInfo, | |
- &procInfo, | |
- atDllPath.c_str(), | |
- nullptr)) | |
- { | |
- std::cerr << "Failed to create process: 0x" << std::hex << GetLastError() << std::endl; | |
+ pe32.dwSize = sizeof(PROCESSENTRY32); | |
+ | |
+ if (!Process32First(snapshot, &pe32)) { | |
+ CloseHandle(snapshot); | |
+ std::cerr << "Process32First failed" << std::endl; | |
+ return 1; | |
+ } | |
+ | |
+ while (Process32Next(snapshot, &pe32)) { | |
+ std::wcout << "Name = " << pe32.szExeFile << ", pid = " << pe32.th32ProcessID << std::endl;; | |
+ if (targetProcess.compare(pe32.szExeFile) == 0) { | |
+ std::cout << "May be the one we want" << std::endl; | |
+ std::cout << "Injecting..." << std::endl; | |
+ /* try to open the process, this is very finicky */ | |
+ HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID); | |
+ if (process) { | |
+ // try to inject ourself using CreateRemoteThread | |
+ LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA"); | |
+ LPVOID LLParam = (LPVOID)VirtualAllocEx(process, NULL, atDllPath.length(), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | |
+ WriteProcessMemory(process, LLParam, atDllPath.c_str(), atDllPath.length(), NULL); | |
+ HANDLE thread = CreateRemoteThread(process, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAddr, LLParam, NULL, NULL); | |
+ if (thread != NULL) { | |
+ std::cout << "Success!" << std::endl; | |
+ } | |
+ else { | |
+ std::cout << "Failure, code = " << GetLastError() << std::endl; | |
+ } | |
+ } | |
+ else { | |
+ std::cout << "Failed to open process, code = " << GetLastError() << std::endl; | |
+ } | |
+ break; | |
+ } | |
} | |
+ _getch(); | |
+ return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment