Skip to content

Commit

Permalink
Security updates (#23)
Browse files Browse the repository at this point in the history
* Added experimental thread protection

* Added Discord memory protection
Fixed an uncatched exception while launching Discord

* Moved integrity check settings into the secureKV
Added option to enable Discord process protection

* Added update checker

* Update file version
  • Loading branch information
andro2157 authored Feb 21, 2022
1 parent 9e0d389 commit e96ca03
Show file tree
Hide file tree
Showing 16 changed files with 388 additions and 92 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,4 @@ FodyWeavers.xsd
/ProtectionPayload/PROD-YUBI-NOSTARTUP
/DiscordTokenProtector/PROD-YUBI-NOSTARTUP
/DiscordTokenProtector/PROD-YUBI
/private
31 changes: 20 additions & 11 deletions DiscordTokenProtector/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ class Context {
inline void networkHandler() {
using nlohmann::json;

std::once_flag discordSecurityInfo;

while (m_protectionState == ProtectionStates::Connected) {
try {
std::string msg = m_networkManager.Recv();
Expand All @@ -209,6 +211,13 @@ class Context {
g_secureKV->reopenFile(true);
ExitProcess(0);
}

if (g_secureKV->read_int("protect_discord_process", kd, DEFAULT_KV::protect_discord_process)) {
std::call_once(discordSecurityInfo, []() {
g_discord->setDiscordSecurityInfo(DiscordType::Discord);
g_logger.info("set Discord security info!");
});
}
}
}
catch (std::exception& e) {
Expand Down Expand Up @@ -283,17 +292,17 @@ class Context {
remover_canary_LocalStorage.Remove();

//Check before launching!
if (g_config->read<bool>("integrity")) {
if (g_secureKV->read_int("integrity", kd, DEFAULT_KV::integrity)) {
m_protectionState = ProtectionStates::Checking;
if (m_protectionState == ProtectionStates::Stop) continue;

integrityCheck.setCheckHash(g_config->read<bool>("integrity_checkhash"));
integrityCheck.setCheckExecutableSig(g_config->read<bool>("integrity_checkexecutable"));
integrityCheck.setCheckModule(g_config->read<bool>("integrity_checkmodule"));
integrityCheck.setCheckResources(g_config->read<bool>("integrity_checkresource"));
integrityCheck.setCheckScripts(g_config->read<bool>("integrity_checkscripts"));
integrityCheck.setAllowBetterDiscord(g_config->read<bool>("integrity_allowbetterdiscord"));
integrityCheck.setRedownloadHashes(g_config->read<bool>("integrity_redownloadhashes"));
integrityCheck.setCheckHash(g_secureKV->read_int("integrity_checkhash", kd, DEFAULT_KV::integrity_checkhash));
integrityCheck.setCheckExecutableSig(g_secureKV->read_int("integrity_checkexecutable", kd, DEFAULT_KV::integrity_checkexecutable));
integrityCheck.setCheckModule(g_secureKV->read_int("integrity_checkmodule", kd, DEFAULT_KV::integrity_checkmodule));
integrityCheck.setCheckResources(g_secureKV->read_int("integrity_checkresource", kd, DEFAULT_KV::integrity_checkresource));
integrityCheck.setCheckScripts(g_secureKV->read_int("integrity_checkscripts", kd, DEFAULT_KV::integrity_checkscripts));
integrityCheck.setAllowBetterDiscord(g_secureKV->read_int("integrity_allowbetterdiscord", kd, DEFAULT_KV::integrity_allowbetterdiscord));
integrityCheck.setRedownloadHashes(g_secureKV->read_int("integrity_redownloadhashes", kd, DEFAULT_KV::integrity_redownloadhashes));

integrityCheck.setDiscordVersion(g_discord->getDiscordVersion(discordType));

Expand All @@ -315,11 +324,11 @@ class Context {

m_protectionState = ProtectionStates::Injecting;

PROCESS_INFORMATION discordProcess = g_discord->startSuspendedDiscord(discordType);//TODO CloseHandle?
//g_processprotection->ProtectProcess(discordProcess.hProcess);//TODO Fix

//TODO make this thing async
try {
PROCESS_INFORMATION discordProcess = g_discord->startSuspendedDiscord(discordType);//TODO CloseHandle?
//g_processprotection->ProtectProcess(discordProcess.hProcess);//TODO Fix

if (m_protectionState == ProtectionStates::Stop) continue;

std::promise<USHORT> portPromise;
Expand Down
89 changes: 71 additions & 18 deletions DiscordTokenProtector/Discord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "Discord.h"
#include "Protection/FileCert.h"
#include "Protection/ProcessProtection.h"
#include "Utils/CurlUtils.h"
#include "Utils/Utils.h"

Expand Down Expand Up @@ -185,15 +186,34 @@ PROCESS_INFORMATION Discord::startSuspendedDiscord(DiscordType type) {

std::wstring processDir = getLocal() + (type == DiscordType::Discord ? L"\\Discord" : L"\\DiscordCanary");

//Copy the security descriptor of DTP

//SECURITY_ATTRIBUTES secAttrib;
//secAttrib.nLength = sizeof(secAttrib);
//secAttrib.bInheritHandle = FALSE;

//if (DWORD error = GetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT,
// ATTRIBUTE_SECURITY_INFORMATION |
// DACL_SECURITY_INFORMATION |
// GROUP_SECURITY_INFORMATION |
// LABEL_SECURITY_INFORMATION |
// OWNER_SECURITY_INFORMATION,
// NULL, NULL, NULL, NULL, &secAttrib.lpSecurityDescriptor); error != ERROR_SUCCESS) {
// g_logger.error(sf() << __FUNCSIG__ " : Failed GetSecurityInfo : " << error);
//}

if (!CreateProcessW(
NULL,
const_cast<LPWSTR>((type == DiscordType::Discord ? m_discordModulePath : m_discordCanaryModulePath).c_str()),
NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,
/*&secAttrib*/NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,
const_cast<LPCWSTR>(processDir.c_str()),
&startupInfo, &processInfo)) {
//LocalFree(secAttrib.lpSecurityDescriptor);
throw std::runtime_error(sf() << __FUNCSIG__ " : Failed CreateProcessW : " << GetLastError());
}

//LocalFree(secAttrib.lpSecurityDescriptor);

return processInfo;
}

Expand All @@ -203,27 +223,48 @@ DWORD Discord::getDiscordPID(DiscordType type, bool fast, bool suspend) {
auto pids = getProcessIDbyName(type == DiscordType::Discord ? L"Discord.exe" : L"DiscordCanary.exe");

for (DWORD pid : pids) {
HANDLE hProcess = OpenProcess(/*PROCESS_QUERY_INFORMATION*/PROCESS_ALL_ACCESS/*to suspend*/, FALSE, pid);
DWORD pathSize = MAX_PATH;
WCHAR processPath[MAX_PATH];
if (isValidDiscordPID(pid, fast, suspend))
return pid;
}
return 0;
}

if (hProcess == NULL || !QueryFullProcessImageNameW(hProcess, NULL, processPath, &pathSize)) {
continue;//Most likely not discord
}
std::vector<DWORD> Discord::getDiscordPIDs(DiscordType type, bool fast, bool suspend) {
std::vector<DWORD> discordPids;

DWORD validPid = NULL;
if (fast) validPid = pid;
else {
if (suspend) pfnNtSuspendProcess(hProcess);
if (isValidDiscordModule(processPath)) validPid = pid;
else
pfnNtResumeProcess(hProcess);
}
CloseHandle(hProcess);
if (type == DiscordType::None) return discordPids;

if (validPid) return validPid;
auto pids = getProcessIDbyName(type == DiscordType::Discord ? L"Discord.exe" : L"DiscordCanary.exe");

for (DWORD pid : pids) {
if (isValidDiscordPID(pid, fast, suspend))
discordPids.push_back(pid);
}
return 0;

return discordPids;
}

bool Discord::isValidDiscordPID(DWORD pid, bool fast, bool suspend) {
HANDLE hProcess = OpenProcess(/*PROCESS_QUERY_INFORMATION*/PROCESS_ALL_ACCESS/*to suspend*/, FALSE, pid);
DWORD pathSize = MAX_PATH;
WCHAR processPath[MAX_PATH];

if (hProcess == NULL || !QueryFullProcessImageNameW(hProcess, NULL, processPath, &pathSize)) {
return false;//Most likely not discord
}

bool isValid = fast;

if (!isValid) {
if (suspend) pfnNtSuspendProcess(hProcess);
if (isValidDiscordModule(processPath)) isValid = true;
else
pfnNtResumeProcess(hProcess);
}

CloseHandle(hProcess);

return isValid;
}

void Discord::injectPayload(PROCESS_INFORMATION pInfo, size_t port) {
Expand Down Expand Up @@ -309,6 +350,18 @@ bool Discord::suspendDiscord(DiscordType type, bool suspend) {
return success;
}

bool Discord::setDiscordSecurityInfo(DiscordType type) {
bool success = true;

for (auto pid : g_discord->getDiscordPIDs(DiscordType::Discord)) {
HANDLE hProc = OpenProcess(WRITE_DAC, FALSE, pid);
success &= ProcessProtection::setHandleSecurityInfo(hProc);
CloseHandle(hProc);
}

return success;
}

std::wstring Discord::getLocal() {
TCHAR szPath[MAX_PATH];
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, szPath)) || wcsstr(szPath, L"AppData\\Local") == nullptr) {
Expand Down
5 changes: 5 additions & 0 deletions DiscordTokenProtector/Discord.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,15 @@ class Discord {
PROCESS_INFORMATION startSuspendedDiscord(DiscordType type);

DWORD getDiscordPID(DiscordType type, bool fast = false, bool suspend = false);
std::vector<DWORD> getDiscordPIDs(DiscordType type, bool fast = false, bool suspend = false);
bool isValidDiscordPID(DWORD pid, bool fast, bool suspend);

static void injectPayload(PROCESS_INFORMATION pInfo, size_t port = 0);

bool suspendDiscord(DiscordType type, bool suspend);

bool setDiscordSecurityInfo(DiscordType type);

static WORD getDiscordRPCPort();
static bool AcceptHandoff(const std::string& port, const std::string& key, const secure_string& token);
static DiscordUserInfo getUserInfo(const secure_string& token);
Expand Down
2 changes: 1 addition & 1 deletion DiscordTokenProtector/DiscordTokenProtector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ void mainInit() {

g_processprotection = std::make_unique<ProcessProtection>();
#ifdef _PROD
//TODO Protect threads, threads are killable without admin permission
g_processprotection->HookCreateThread();
g_processprotection->ProtectProcess();
#endif
g_discord = std::make_unique<Discord>();
Expand Down
4 changes: 2 additions & 2 deletions DiscordTokenProtector/DiscordTokenProtector.rc
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ MAINICON ICON "512x icon.ico"

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 0,0,0,7
PRODUCTVERSION 0,0,0,8
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -86,7 +86,7 @@ BEGIN
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "DiscordTokenProtector.exe"
VALUE "ProductName", "Discord Token Protector"
VALUE "ProductVersion", "0.0.0.7"
VALUE "ProductVersion", "0.0.0.8"
END
END
BLOCK "VarFileInfo"
Expand Down
13 changes: 7 additions & 6 deletions DiscordTokenProtector/DiscordTokenProtector.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,13 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(LibraryPath)</LibraryPath>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files (x86)\Yubico\Yubico PIV Tool\lib;$(LibraryPath)</LibraryPath>
<IncludePath>C:\Program Files (x86)\Yubico\Yubico PIV Tool\include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
<IncludePath>C:\Program Files (x86)\Yubico\Yubico PIV Tool\include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files (x86)\Yubico\Yubico PIV Tool\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='PROD|Win32'">
<LinkIncremental>false</LinkIncremental>
Expand Down Expand Up @@ -256,7 +256,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;YUBIKEYSUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
Expand All @@ -274,7 +274,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;YUBIKEYSUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
Expand Down Expand Up @@ -506,6 +506,7 @@
<ClInclude Include="Protection\ProcessProtection.h" />
<ClInclude Include="Storage\SecureKV.h" />
<ClInclude Include="Utils\Timer.h" />
<ClInclude Include="Utils\Updater.h" />
<ClInclude Include="Utils\Utils.h" />
</ItemGroup>
<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions DiscordTokenProtector/DiscordTokenProtector.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@
<ClInclude Include="Protection\IntegrityCheck.h">
<Filter>Fichiers d%27en-tête\Protection</Filter>
</ClInclude>
<ClInclude Include="Utils\Updater.h">
<Filter>Fichiers d%27en-tête\Utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DiscordTokenProtector.rc">
Expand Down
2 changes: 1 addition & 1 deletion DiscordTokenProtector/Includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ __forceinline void FATALERROR_STR(std::string str) {
FATALERROR(str.c_str());
}

#define VER "dev-7"
#define VER "dev-8"

#pragma comment(lib, "OpenGL32.lib")
#pragma comment(lib, "crypt32.lib")
Expand Down
Loading

0 comments on commit e96ca03

Please sign in to comment.