Skip to content

Commit

Permalink
Merge pull request #5 from Aetopia/main
Browse files Browse the repository at this point in the history
Remove thread detection loop + use file enumeration to find Discord's executable.
  • Loading branch information
HerXayah committed Dec 15, 2023
2 parents 2e3ab74 + 76473ee commit 710c23a
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 53 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ Disables threads responsible for calling GetRawInputData for Discord, Discord PT
## Usage

1. Download the latest [Release](https://github.com/PrincessAkira/Discord-Fixer/releases).
2. Locate the directory in which `Discord.exe`, `DiscordPTB.exe` and `DiscordCanary.exe` is located and place the downloaded executable in it.
2. Locate where Discord Stable/PTB/Canary is installed and place this executable.
3. Launch the downloaded executable, this will also launch the relevant executable for Discord.

### How does it work?
1. The program attempts to locate a valid `Discord.exe`, `DiscordPTB.exe` and `DiscordCanary.exe` file.
2. Once the correct file was located, the located file will be launched.
3. The program will be iterate through the process list until it finds any threads that use the following module: `discord_utils.node`.
4. Once found, the relevant threads will be suspended.
3. Using [WinEvent](https://learn.microsoft.com/en-us/windows/win32/winauto/what-are-winevents) [Hooks](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwineventhook), the process waits until a window with the class name of `raw_input` is created.
4. The process that is hosting the `raw_input` window will have its threads iterated and if any thread is using `discord_utils.node`, it will be suspended.

# Building
1. Install the latest version of [`GCC`](https://winlibs.com/) and [`UPX`](https://upx.github.io/) for optional compression.
Expand Down
164 changes: 114 additions & 50 deletions WinMain.c
Original file line number Diff line number Diff line change
@@ -1,68 +1,132 @@
#include <windows.h>
#include <pathcch.h>
#include <Windows.h>
#include <shlwapi.h>
#include <tlhelp32.h>
#include <winternl.h>
#include <wtsapi32.h>
#include <shlwapi.h>
#define printf __builtin_printf

INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
static LPWSTR szFileName = NULL;

void WinEventProc(HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idEventThread,
DWORD dwmsEventTime)
{
INT iNumArgs = 0;
WCHAR **pszArgvW = CommandLineToArgvW(GetCommandLineW(), &iNumArgs),
*szFileName = 0;
WCHAR lpExeName[MAX_PATH] = {};
DWORD dwProcessId = 0;
DWORD dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId);
WCHAR ptszClassName[256] = {};
HANDLE hThreadSnapshot = NULL;
THREADENTRY32 te = {.dwSize = sizeof(THREADENTRY32)};
MODULEENTRY32W me = {.dwSize = sizeof(MODULEENTRY32W)};
HANDLE hThreadSnapshot = 0, hModuleSnapshot = 0, hThread = 0;
DWORD64 dw64StartAddress = 0;
PWTS_PROCESS_INFOW pProcessInfo = 0;
DWORD dwCount = 0;
BOOL bSuspended = FALSE;

PathCchRemoveFileSpec(pszArgvW[0], wcslen(pszArgvW[0]) + 1);
SetCurrentDirectoryW(pszArgvW[0]);
LocalFree(pszArgvW);
RealGetWindowClassW(hwnd, ptszClassName, 256);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId);
QueryFullProcessImageNameW(hProcess, 0, lpExeName, &((DWORD){MAX_PATH}));
PathStripPathW(_wcslwr(lpExeName));
CloseHandle(hProcess);

if ((szFileName = PathFileExistsW(L"discord.exe")
? L"discord.exe"
: PathFileExistsW(L"discordcanary.exe")
? L"discordcanary.exe"
: PathFileExistsW(L"discordptb.exe")
? L"discordptb.exe"
: 0))
if (!wcscmp(lpExeName, szFileName) && !wcscmp(ptszClassName, L"raw_input"))
{
ShellExecuteW(NULL, NULL, szFileName, NULL, NULL, SW_SHOWNORMAL);
while (!bSuspended && !SleepEx(1, TRUE))
if (Thread32First((hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)), &te))
{
WTSEnumerateProcessesW(WTS_CURRENT_SERVER, 0, 1, &pProcessInfo, &dwCount);
for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
do
{
if (wcscmp(szFileName, _wcslwr(pProcessInfo[dwIndex].pProcessName)))
if (te.th32OwnerProcessID != dwProcessId)
continue;
if (Thread32First((hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)), &te))
{
DWORD64 ThreadInformation = 0;
MODULEENTRY32W me = {.dwSize = sizeof(MODULEENTRY32W)};
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID),
hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, dwProcessId);
NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &ThreadInformation, sizeof(DWORD64), NULL);
if (Module32FirstW((hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, dwProcessId)), &me))
do
{
if (te.th32OwnerProcessID != pProcessInfo[dwIndex].ProcessId)
continue;
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &dw64StartAddress, sizeof(DWORD64), NULL);
if (Module32FirstW((hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, pProcessInfo[dwIndex].ProcessId)), &me))
do
{
if (dw64StartAddress >= (DWORD64)me.modBaseAddr &&
dw64StartAddress <= ((DWORD64)me.modBaseAddr + me.modBaseSize) &&
!wcscmp(me.szModule, L"discord_utils.node"))
bSuspended = SuspendThread(hThread);
} while (Module32NextW(hModuleSnapshot, &me));
CloseHandle(hModuleSnapshot);
CloseHandle(hThread);
} while (Thread32Next(hThreadSnapshot, &te));
}
CloseHandle(hThreadSnapshot);
}
WTSFreeMemory(pProcessInfo);
if (ThreadInformation >= (DWORD64)me.modBaseAddr &&
ThreadInformation <= ((DWORD64)me.modBaseAddr + me.modBaseSize) &&
!wcscmp(me.szModule, L"discord_utils.node"))
SuspendThread(hThread);
} while (Module32NextW(hModuleSnapshot, &me));
CloseHandle(hModuleSnapshot);
CloseHandle(hThread);
} while (Thread32Next(hThreadSnapshot, &te));
}
CloseHandle(hThreadSnapshot);
PostQuitMessage(0);
}
}

BOOL EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
DWORD dwProcessId = 0;
WCHAR lpExeName[MAX_PATH] = {};
GetWindowThreadProcessId(hWnd, &dwProcessId);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId);
QueryFullProcessImageNameW(hProcess, 0, lpExeName, &((DWORD){MAX_PATH}));
PathStripPathW(_wcslwr(lpExeName));
CloseHandle(hProcess);
if (!wcscmp(lpExeName, szFileName))
EndTask(hWnd, FALSE, TRUE);
return TRUE;
}

INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
{
CONST LPWSTR lpProcesses[] = {L"discord.exe", L"discordptb.exe", L"discordptb.exe"};
WCHAR lpPathName[MAX_PATH] = {};
HANDLE hProcess = GetCurrentProcess();
WIN32_FIND_DATAW FindFileData = {};
PWTS_PROCESS_INFOW pProcessInfo = NULL;
DWORD Count = 0;

QueryFullProcessImageNameW(hProcess, 0, lpPathName, &((DWORD){MAX_PATH}));
for (DWORD dwIndex = MAX_PATH; dwIndex < -1; dwIndex -= 1)
{
if (lpPathName[dwIndex] == '\\')
{
lpPathName[dwIndex] = '\0';
SetCurrentDirectoryW(lpPathName);
lpPathName[dwIndex] = '\\';
lpPathName[dwIndex + 1] = '*';
lpPathName[dwIndex + 2] = '\0';
break;
}
}

HANDLE hFindFile = FindFirstFileExW(lpPathName,
FindExInfoBasic,
&FindFileData,
FindExSearchLimitToDirectories,
NULL,
FIND_FIRST_EX_LARGE_FETCH);
if (hFindFile)
{
do
if (PathIsDirectoryW(FindFileData.cFileName) &&
wcscmp(FindFileData.cFileName, L".") &&
wcscmp(FindFileData.cFileName, L".."))
if (SetCurrentDirectoryW(FindFileData.cFileName))
for (INT iIndex = 0; iIndex < 3; iIndex++)
if (PathFileExistsW(lpProcesses[iIndex]))
{
szFileName = lpProcesses[iIndex];
EnumWindows(EnumWindowsProc, 0);
ShellExecuteW(NULL, NULL, szFileName, NULL, NULL, SW_SHOWNORMAL);
SetWinEventHook(EVENT_OBJECT_CREATE,
EVENT_OBJECT_CREATE,
NULL,
WinEventProc,
0,
0,
WINEVENT_OUTOFCONTEXT);
while (GetMessageW(&((MSG){}), NULL, 0, 0))
;
break;
}
while (FindNextFileW(hFindFile, &FindFileData));
FindClose(hFindFile);
}

return 0;
}

0 comments on commit 710c23a

Please sign in to comment.