parent
ed0fce1124
commit
1e616021e8
|
@ -32,9 +32,7 @@ static bool bDisableGUIUpdate;
|
|||
|
||||
#define LOADLIBRARY(name) \
|
||||
szLib=name; \
|
||||
hInst=LoadLibraryW(name); \
|
||||
if(!hInst) \
|
||||
return L"Error loading library \"" name L"\"!"
|
||||
hInst=BridgeLoadLibraryCheckedW(name, false);
|
||||
|
||||
#define LOADEXPORT(name) \
|
||||
*((FARPROC*)&name)=GetProcAddress(hInst, #name); \
|
||||
|
@ -65,13 +63,12 @@ static bool DirExists(const wchar_t* dir)
|
|||
return (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP const wchar_t* BridgeInit()
|
||||
{
|
||||
//Initialize critial section
|
||||
InitializeCriticalSection(&csIni);
|
||||
InitializeCriticalSection(&csTranslate);
|
||||
static decltype(&BridgeLoadLibraryCheckedW) pLoadLibraryCheckedW;
|
||||
static decltype(&BridgeLoadLibraryCheckedA) pLoadLibraryCheckedA;
|
||||
|
||||
//Settings load
|
||||
static const wchar_t* InitializeUserDirectory()
|
||||
{
|
||||
// Handle user directory
|
||||
if(!GetModuleFileNameW(0, szUserDirectory, _countof(szUserDirectory)))
|
||||
return L"Error getting module path!";
|
||||
|
||||
|
@ -133,24 +130,69 @@ BRIDGE_IMPEXP const wchar_t* BridgeInit()
|
|||
if(!DirExists(userDirUtf16.c_str()))
|
||||
return L"Specified user directory doesn't exist";
|
||||
|
||||
// Read the settings from the INI
|
||||
wcscpy_s(szIniFile, userDirUtf16.c_str());
|
||||
wcscat_s(szIniFile, L"\\");
|
||||
wcscat_s(szIniFile, fileNameWithoutExtension);
|
||||
wcscat_s(szIniFile, L".ini");
|
||||
BridgeSettingRead(nullptr);
|
||||
|
||||
wcscpy_s(szUserDirectory, userDirUtf16.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP const wchar_t* BridgeInit()
|
||||
{
|
||||
//Initialize critial section
|
||||
InitializeCriticalSection(&csIni);
|
||||
InitializeCriticalSection(&csTranslate);
|
||||
|
||||
// Signature checking functions
|
||||
auto hMainModule = GetModuleHandleW(nullptr);
|
||||
pLoadLibraryCheckedW = (decltype(pLoadLibraryCheckedW))GetProcAddress(hMainModule, "LoadLibraryCheckedW");
|
||||
pLoadLibraryCheckedA = (decltype(pLoadLibraryCheckedA))GetProcAddress(hMainModule, "LoadLibraryCheckedA");
|
||||
if(pLoadLibraryCheckedW == nullptr || pLoadLibraryCheckedA == nullptr)
|
||||
return L"Error finding safe library loading functions!";
|
||||
|
||||
auto userDirectoryError = InitializeUserDirectory();
|
||||
if(userDirectoryError != nullptr)
|
||||
return userDirectoryError;
|
||||
|
||||
// Variables used by the macros below
|
||||
HINSTANCE hInst;
|
||||
const wchar_t* szLib;
|
||||
static wchar_t szError[256] = L"";
|
||||
|
||||
//GUI Load
|
||||
LOADLIBRARY(gui_lib);
|
||||
LOADEXPORT(_gui_guiinit);
|
||||
LOADEXPORT(_gui_sendmessage);
|
||||
LOADEXPORT(_gui_translate_text);
|
||||
auto titanEngineDll = []()
|
||||
{
|
||||
switch(DbgGetDebugEngine())
|
||||
{
|
||||
case DebugEngineGleeBug:
|
||||
return L"GleeBug\\TitanEngine.dll";
|
||||
case DebugEngineStaticEngine:
|
||||
return L"StaticEngine\\TitanEngine.dll";
|
||||
default:
|
||||
return L"TitanEngine.dll";
|
||||
}
|
||||
}();
|
||||
|
||||
//DBG Load
|
||||
auto loadIfExists = [&](const wchar_t* szDll)
|
||||
{
|
||||
BridgeLoadLibraryCheckedW(szDll, true);
|
||||
};
|
||||
|
||||
// Imported DLLs (DBG)
|
||||
LOADLIBRARY(titanEngineDll);
|
||||
LOADLIBRARY(L"LLVMDemangle.dll");
|
||||
LOADLIBRARY(L"lz4.dll");
|
||||
LOADLIBRARY(L"jansson.dll");
|
||||
LOADLIBRARY(L"DeviceNameResolver.dll");
|
||||
LOADLIBRARY(L"XEDParse.dll");
|
||||
//loadIfExists(L"asmjit.dll"); // only loaded with user interaction
|
||||
//loadIfExists(L"Scylla.dll"); // only loaded with user interaction
|
||||
loadIfExists(L"msdia140.dll"); // only loaded with user interaction
|
||||
|
||||
// DBG
|
||||
LOADLIBRARY(dbg_lib);
|
||||
LOADEXPORT(_dbg_dbginit);
|
||||
LOADEXPORT(_dbg_memfindbaseaddr);
|
||||
|
@ -173,15 +215,58 @@ BRIDGE_IMPEXP const wchar_t* BridgeInit()
|
|||
LOADEXPORT(_dbg_dbgcmddirectexec);
|
||||
LOADEXPORT(_dbg_getbranchdestination);
|
||||
LOADEXPORT(_dbg_sendmessage);
|
||||
|
||||
// Imported DLLs (GUI)
|
||||
LOADLIBRARY(L"ldconvert.dll");
|
||||
loadIfExists(L"Qt5Core.dll");
|
||||
loadIfExists(L"Qt5Gui.dll");
|
||||
loadIfExists(L"Qt5WinExtras.dll");
|
||||
loadIfExists(L"Qt5Widgets.dll");
|
||||
loadIfExists(L"Qt5Network.dll");
|
||||
loadIfExists(L"platforms\\qwindows.dll");
|
||||
loadIfExists(L"imageformats\\qgif.dll");
|
||||
loadIfExists(L"imageformats\\qicns.dll");
|
||||
loadIfExists(L"imageformats\\qico.dll");
|
||||
loadIfExists(L"imageformats\\qjpeg.dll");
|
||||
loadIfExists(L"Qt5Svg.dll");
|
||||
loadIfExists(L"imageformats\\qsvg.dll");
|
||||
loadIfExists(L"imageformats\\qtga.dll");
|
||||
loadIfExists(L"imageformats\\qtiff.dll");
|
||||
loadIfExists(L"imageformats\\qwbmp.dll");
|
||||
loadIfExists(L"imageformats\\qwebp.dll");
|
||||
loadIfExists(L"bearer\\qgenericbearer.dll");
|
||||
loadIfExists(L"bearer\\qnativewifibearer.dll");
|
||||
loadIfExists(L"iconengines\\qsvgicon.dll");
|
||||
//loadIfExists(L"libeay32.dll"); // only loaded with user interaction
|
||||
//loadIfExists(L"ssleay32.dll"); // only loaded with user interaction
|
||||
|
||||
// GUI
|
||||
LOADLIBRARY(gui_lib);
|
||||
LOADEXPORT(_gui_guiinit);
|
||||
LOADEXPORT(_gui_sendmessage);
|
||||
LOADEXPORT(_gui_translate_text);
|
||||
|
||||
// Backwards compatibility
|
||||
BridgeLoadLibraryCheckedW(L"x64_bridge.dll", true);
|
||||
BridgeLoadLibraryCheckedW(L"x64_dbg.dll", true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP HMODULE WINAPI BridgeLoadLibraryCheckedW(const wchar_t* szDll, bool allowFailure)
|
||||
{
|
||||
return pLoadLibraryCheckedW(szDll, allowFailure);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP HMODULE WINAPI BridgeLoadLibraryCheckedA(const char* szDll, bool allowFailure)
|
||||
{
|
||||
return pLoadLibraryCheckedA(szDll, allowFailure);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP const wchar_t* BridgeStart()
|
||||
{
|
||||
if(!_dbg_dbginit || !_gui_guiinit)
|
||||
return L"\"_dbg_dbginit\" || \"_gui_guiinit\" was not loaded yet, call BridgeInit!";
|
||||
int errorLine = 0;
|
||||
BridgeSettingRead(&errorLine);
|
||||
_dbg_sendmessage(DBG_INITIALIZE_LOCKS, nullptr, nullptr); //initialize locks before any other thread than the main thread are started
|
||||
_gui_guiinit(0, 0); //remove arguments
|
||||
if(!BridgeSettingFlush())
|
||||
|
@ -1208,7 +1293,12 @@ BRIDGE_IMPEXP void DbgGetSymbolInfo(const SYMBOLPTR* symbolptr, SYMBOLINFO* info
|
|||
|
||||
BRIDGE_IMPEXP DEBUG_ENGINE DbgGetDebugEngine()
|
||||
{
|
||||
return (DEBUG_ENGINE)_dbg_sendmessage(DBG_GET_DEBUG_ENGINE, nullptr, nullptr);
|
||||
duint setting = DebugEngineTitanEngine;
|
||||
if(!BridgeSettingGetUint("Engine", "DebugEngine", &setting))
|
||||
{
|
||||
BridgeSettingSetUint("Engine", "DebugEngine", setting);
|
||||
}
|
||||
return (DEBUG_ENGINE)setting;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP const char* GuiTranslateText(const char* Source)
|
||||
|
|
|
@ -50,6 +50,10 @@ extern "C"
|
|||
/// <returns>On error it returns a non-null error message.</returns>
|
||||
BRIDGE_IMPEXP const wchar_t* BridgeInit();
|
||||
|
||||
BRIDGE_IMPEXP HMODULE WINAPI BridgeLoadLibraryCheckedW(const wchar_t* szDll, bool allowFailure);
|
||||
|
||||
BRIDGE_IMPEXP HMODULE WINAPI BridgeLoadLibraryCheckedA(const char* szDll, bool allowFailure);
|
||||
|
||||
/// <summary>
|
||||
/// Start the bridge.
|
||||
/// </summary>
|
||||
|
|
|
@ -642,51 +642,6 @@ static WString escape(WString cmdline)
|
|||
return cmdline;
|
||||
}
|
||||
|
||||
#include <delayimp.h>
|
||||
|
||||
// https://devblogs.microsoft.com/oldnewthing/20170126-00/?p=95265
|
||||
static FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
||||
{
|
||||
if(dliNotify == dliNotePreLoadLibrary && _stricmp(pdli->szDll, "TitanEngine.dll") == 0)
|
||||
{
|
||||
String fullPath = szProgramDir;
|
||||
fullPath += '\\';
|
||||
|
||||
switch(DbgGetDebugEngine())
|
||||
{
|
||||
case DebugEngineGleeBug:
|
||||
fullPath += "GleeBug\\TitanEngine.dll";
|
||||
break;
|
||||
case DebugEngineStaticEngine:
|
||||
fullPath += "StaticEngine\\TitanEngine.dll";
|
||||
break;
|
||||
case DebugEngineTitanEngine:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto hModule = LoadLibraryW(StringUtils::Utf8ToUtf16(fullPath).c_str());
|
||||
if(hModule)
|
||||
{
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Successfully loaded %s!\n"), fullPath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to load %s, falling back to regular TitanEngine.dll"), fullPath.c_str());
|
||||
}
|
||||
return (FARPROC)hModule;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Visual Studio 2015 Update 3 made this const per default
|
||||
// https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd
|
||||
#if _MSC_FULL_VER >= 190024210
|
||||
const
|
||||
#endif // _MSC_FULL_VER
|
||||
PfnDliHook __pfnDliNotifyHook2 = delayHook;
|
||||
|
||||
extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
||||
{
|
||||
if(!EngineCheckStructAlignment(UE_STRUCT_TITAN_ENGINE_CONTEXT, sizeof(TITAN_ENGINE_CONTEXT_t)))
|
||||
|
|
|
@ -388,7 +388,6 @@
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>LLVMDemangle\LLVMDemangle_x86.lib;ntdll\ntdll_x86.lib;lz4\lz4_x86.lib;jansson\jansson_x86.lib;DeviceNameResolver\DeviceNameResolver_x86.lib;XEDParse\XEDParse_x86.lib;dbghelp\dbghelp_x86.lib;TitanEngine\TitanEngine_x86.lib;ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>TitanEngine.dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
|
@ -438,7 +437,6 @@
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>LLVMDemangle\LLVMDemangle_x64.lib;ntdll\ntdll_x64.lib;lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>TitanEngine.dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <exception>
|
||||
#include <signal.h>
|
||||
#include "crashdump.h"
|
||||
#include "signaturecheck.h"
|
||||
|
||||
#define PROCESS_CALLBACK_FILTER_ENABLED 0x1
|
||||
|
||||
|
@ -37,17 +38,14 @@ BOOL
|
|||
void CrashDumpInitialize()
|
||||
{
|
||||
// Get handles to kernel32 and dbghelp
|
||||
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
|
||||
HMODULE hDbghelp = LoadLibraryA("dbghelp.dll");
|
||||
HMODULE hDbghelp = LoadLibraryCheckedW(L"dbghelp.dll", false);
|
||||
|
||||
if(hDbghelp)
|
||||
*(FARPROC*)&MiniDumpWriteDumpPtr = GetProcAddress(hDbghelp, "MiniDumpWriteDump");
|
||||
|
||||
if(hKernel32)
|
||||
{
|
||||
*(FARPROC*)&SetProcessUserModeExceptionPolicyPtr = GetProcAddress(hKernel32, "SetProcessUserModeExceptionPolicy");
|
||||
*(FARPROC*)&GetProcessUserModeExceptionPolicyPtr = GetProcAddress(hKernel32, "GetProcessUserModeExceptionPolicy");
|
||||
}
|
||||
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
|
||||
*(FARPROC*)&SetProcessUserModeExceptionPolicyPtr = GetProcAddress(hKernel32, "SetProcessUserModeExceptionPolicy");
|
||||
*(FARPROC*)&GetProcessUserModeExceptionPolicyPtr = GetProcAddress(hKernel32, "GetProcessUserModeExceptionPolicy");
|
||||
|
||||
if(MiniDumpWriteDumpPtr)
|
||||
SetUnhandledExceptionFilter(CrashDumpExceptionHandler);
|
||||
|
|
|
@ -1,21 +1,57 @@
|
|||
#include <Windows.h>
|
||||
#include "signaturecheck.h"
|
||||
|
||||
#include <delayimp.h>
|
||||
#include <Softpub.h>
|
||||
#include <wincrypt.h>
|
||||
#include <wintrust.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static wchar_t szModulePath[MAX_PATH];
|
||||
static wchar_t szApplicationDir[MAX_PATH];
|
||||
static bool bPerformSignatureChecks = false;
|
||||
|
||||
//#define DEBUG_SIGNATURE_CHECKS
|
||||
|
||||
#ifdef DEBUG_SIGNATURE_CHECKS
|
||||
static const wchar_t* gCheckedList[4096];
|
||||
static size_t gCheckedListSize = 0;
|
||||
|
||||
static void debugMessage(const wchar_t* szMessage)
|
||||
{
|
||||
wchar_t finalMessage[512] = L"[signaturecheck] ";
|
||||
wcsncat_s(finalMessage, szMessage, _TRUNCATE);
|
||||
OutputDebugStringW(finalMessage);
|
||||
}
|
||||
#endif // DEBUG_SIGNATURE_CHECKS
|
||||
|
||||
// TODO: look at hijacking of wintrust (also old vulnerabilities)
|
||||
// - https://www.bleepingcomputer.com/news/security/microsoft-code-sign-check-bypassed-to-drop-zloader-malware/
|
||||
// - https://www.trustedsec.com/blog/object-overloading/
|
||||
#pragma comment (lib, "wintrust")
|
||||
// MSASN1.dll
|
||||
// CRYPTSP.dll
|
||||
// CRYPTBASE.dll
|
||||
// other:
|
||||
// cryptnet.dll
|
||||
// iphlpapi.dll
|
||||
// profapi.dll
|
||||
// wininet.dll
|
||||
// winmm.dll
|
||||
// opengl32.dll
|
||||
// glu32.dll
|
||||
// dnsapi.dll
|
||||
// mpr.dll
|
||||
// wldp.dll
|
||||
// wtsapi32.dll
|
||||
// XP: rsaenh.dll
|
||||
// XP: psapi.dll
|
||||
// XP: WS2_32.dll
|
||||
// XP: WS2HELP.dll
|
||||
// XP: DNSAPI.dll
|
||||
#pragma comment(lib, "wintrust")
|
||||
|
||||
// Source: https://learn.microsoft.com/en-us/windows/win32/seccrypto/example-c-program--verifying-the-signature-of-a-pe-file
|
||||
bool VerifyEmbeddedSignature(LPCWSTR pwszSourceFile, bool checkRevocation = true)
|
||||
static bool VerifyEmbeddedSignature(LPCWSTR pwszSourceFile, bool checkRevocation)
|
||||
{
|
||||
LONG lStatus;
|
||||
DWORD dwLastError;
|
||||
|
@ -184,11 +220,12 @@ bool VerifyEmbeddedSignature(LPCWSTR pwszSourceFile, bool checkRevocation = true
|
|||
// Any hWVTStateData must be released by a call with close.
|
||||
WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
|
||||
|
||||
lStatus = WinVerifyTrust(
|
||||
NULL,
|
||||
&WVTPolicyGUID,
|
||||
&WinTrustData);
|
||||
auto lStatusClean = WinVerifyTrust(
|
||||
NULL,
|
||||
&WVTPolicyGUID,
|
||||
&WinTrustData);
|
||||
|
||||
SetLastError(lStatus);
|
||||
return validSignature;
|
||||
}
|
||||
|
||||
|
@ -207,32 +244,77 @@ static std::wstring Utf8ToUtf16(const char* str)
|
|||
return convertedString;
|
||||
}
|
||||
|
||||
static bool FileExists(const wchar_t* szFullPath)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesW(szFullPath);
|
||||
return (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
||||
SIGNATURE_EXPORT HMODULE LoadLibraryCheckedW(const wchar_t* szDll, bool allowFailure)
|
||||
{
|
||||
std::wstring fullDllPath = szApplicationDir;
|
||||
fullDllPath += szDll;
|
||||
|
||||
#ifdef DEBUG_SIGNATURE_CHECKS
|
||||
debugMessage(L"LoadLibraryCheckedW");
|
||||
debugMessage(fullDllPath.c_str());
|
||||
auto checkedPath = (wchar_t*)malloc(sizeof(wchar_t) * (fullDllPath.size() + 1));
|
||||
wcscpy_s(checkedPath, fullDllPath.size() + 1, fullDllPath.c_str());
|
||||
gCheckedList[gCheckedListSize++] = checkedPath;
|
||||
#endif // DEBUG_SIGNATURE_CHECKS
|
||||
|
||||
if(allowFailure && !FileExists(fullDllPath.c_str()))
|
||||
{
|
||||
#ifdef DEBUG_SIGNATURE_CHECKS
|
||||
debugMessage(L"^^^ DLL NOT FOUND ^^^");
|
||||
#endif // DEBUG_SIGNATURE_CHECKS
|
||||
SetLastError(ERROR_MOD_NOT_FOUND);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bPerformSignatureChecks)
|
||||
{
|
||||
auto validSignature = VerifyEmbeddedSignature(fullDllPath.c_str(), false);
|
||||
if(!validSignature)
|
||||
{
|
||||
#ifdef DEBUG_SIGNATURE_CHECKS
|
||||
wchar_t msg[128] = L"";
|
||||
wsprintfW(msg, L"^^^ INVALID SIGNATURE ^^^ -> %08X", GetLastError());
|
||||
debugMessage(msg);
|
||||
#else
|
||||
MessageBoxW(nullptr, fullDllPath.c_str(), L"DLL does not have a valid signature", MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
ExitProcess(TRUST_E_NOSIGNATURE);
|
||||
#endif // DEBUG_SIGNATURE_CHECKS
|
||||
}
|
||||
}
|
||||
|
||||
auto hModule = LoadLibraryW(fullDllPath.c_str());
|
||||
auto lastError = GetLastError();
|
||||
if(!allowFailure && !hModule)
|
||||
{
|
||||
MessageBoxW(nullptr, fullDllPath.c_str(), L"DLL not found!", MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
ExitProcess(lastError);
|
||||
}
|
||||
return hModule;
|
||||
}
|
||||
|
||||
SIGNATURE_EXPORT HMODULE LoadLibraryCheckedA(const char* szDll, bool allowFailure)
|
||||
{
|
||||
return LoadLibraryCheckedW(Utf8ToUtf16(szDll).c_str(), allowFailure);
|
||||
}
|
||||
|
||||
// https://devblogs.microsoft.com/oldnewthing/20170126-00/?p=95265
|
||||
static FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
||||
{
|
||||
// TODO: pre-parse the imports required and make sure there isn't a fake DLL being loaded
|
||||
// TODO: pre-parse the imports required and make sure there isn't a fake signed DLL being loaded
|
||||
if(dliNotify == dliNotePreLoadLibrary)
|
||||
{
|
||||
std::wstring fullDllPath = szModulePath;
|
||||
fullDllPath += L'\\';
|
||||
fullDllPath += Utf8ToUtf16(pdli->szDll);
|
||||
MessageBoxW(nullptr, fullDllPath.c_str(), L"dliNotePreLoadLibrary", MB_ICONERROR);
|
||||
if(bPerformSignatureChecks)
|
||||
if(_stricmp(pdli->szDll, "wintrust.dll") == 0 || _stricmp(pdli->szDll, "user32.dll") == 0)
|
||||
{
|
||||
auto validSignature = VerifyEmbeddedSignature(fullDllPath.c_str());
|
||||
if(!validSignature)
|
||||
{
|
||||
MessageBoxW(nullptr, fullDllPath.c_str(), L"DLL does not have a valid signature", MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
ExitProcess(TRUST_E_NOSIGNATURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
auto hModule = ::LoadLibraryW(fullDllPath.c_str());
|
||||
if(!hModule)
|
||||
{
|
||||
MessageBoxW(nullptr, fullDllPath.c_str(), L"DLL not found!", MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
ExitProcess(ERROR_MOD_NOT_FOUND);
|
||||
}
|
||||
return (FARPROC)hModule;
|
||||
|
||||
return (FARPROC)LoadLibraryCheckedA(pdli->szDll, false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -244,17 +326,206 @@ const
|
|||
#endif // _MSC_FULL_VER
|
||||
PfnDliHook __pfnDliNotifyHook2 = delayHook;
|
||||
|
||||
#ifdef DEBUG_SIGNATURE_CHECKS
|
||||
typedef struct _UNICODE_STRING
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING, * PUNICODE_STRING;
|
||||
|
||||
typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA
|
||||
{
|
||||
ULONG Flags; //Reserved.
|
||||
PUNICODE_STRING FullDllName; //The full path name of the DLL module.
|
||||
PUNICODE_STRING BaseDllName; //The base file name of the DLL module.
|
||||
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
||||
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, * PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
|
||||
|
||||
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA
|
||||
{
|
||||
ULONG Flags; //Reserved.
|
||||
PUNICODE_STRING FullDllName; //The full path name of the DLL module.
|
||||
PUNICODE_STRING BaseDllName; //The base file name of the DLL module.
|
||||
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
||||
} LDR_DLL_LOADED_NOTIFICATION_DATA, * PLDR_DLL_LOADED_NOTIFICATION_DATA;
|
||||
|
||||
typedef union _LDR_DLL_NOTIFICATION_DATA
|
||||
{
|
||||
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
|
||||
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
|
||||
} LDR_DLL_NOTIFICATION_DATA, * PLDR_DLL_NOTIFICATION_DATA, * const PCLDR_DLL_NOTIFICATION_DATA;
|
||||
|
||||
#define LDR_DLL_NOTIFICATION_REASON_LOADED 1
|
||||
#define LDR_DLL_NOTIFICATION_REASON_UNLOADED 2
|
||||
|
||||
VOID CALLBACK LdrDllNotification(
|
||||
_In_ ULONG NotificationReason,
|
||||
_In_ PCLDR_DLL_NOTIFICATION_DATA NotificationData,
|
||||
_In_opt_ PVOID Context
|
||||
);
|
||||
|
||||
using PLDR_DLL_NOTIFICATION_FUNCTION = decltype(&LdrDllNotification);
|
||||
|
||||
NTSTATUS NTAPI LdrRegisterDllNotification(
|
||||
_In_ ULONG Flags,
|
||||
_In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,
|
||||
_In_opt_ PVOID Context,
|
||||
_Out_ PVOID* Cookie
|
||||
);
|
||||
|
||||
using PLDR_REGISTER_DLL_NOTIFICATION_FUNCTION = decltype(&LdrRegisterDllNotification);
|
||||
|
||||
PLDR_REGISTER_DLL_NOTIFICATION_FUNCTION pLdrRegisterDllNotification;
|
||||
|
||||
static VOID CALLBACK MyLdrDllNotification(
|
||||
_In_ ULONG NotificationReason,
|
||||
_In_ PCLDR_DLL_NOTIFICATION_DATA NotificationData,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
if(NotificationReason == LDR_DLL_NOTIFICATION_REASON_LOADED)
|
||||
{
|
||||
auto buffer = NotificationData->Loaded.FullDllName->Buffer;
|
||||
auto length = NotificationData->Loaded.FullDllName->Length;
|
||||
if(memcmp(buffer, szApplicationDir, wcslen(szApplicationDir)) == 0)
|
||||
{
|
||||
auto alreadyChecked = false;
|
||||
for(size_t i = 0; i < gCheckedListSize; i++)
|
||||
{
|
||||
auto checkedPath = gCheckedList[i];
|
||||
auto checkedLen = wcslen(checkedPath);
|
||||
if(length / 2 == checkedLen && memcmp(checkedPath, buffer, length) == 0)
|
||||
{
|
||||
alreadyChecked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(alreadyChecked)
|
||||
{
|
||||
debugMessage(L"DllLoadNotification (checked)");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(wcsstr(buffer, L"\\plugins\\"))
|
||||
debugMessage(L"DllLoadNotification(plugin)");
|
||||
else
|
||||
debugMessage(L"=== UNCHECKED === DllLoadNotification");
|
||||
}
|
||||
debugMessage(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_SIGNATURE_CHECKS
|
||||
|
||||
#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
|
||||
#define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x00000200
|
||||
#define LOAD_LIBRARY_SEARCH_USER_DIRS 0x00000400
|
||||
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
|
||||
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
|
||||
|
||||
typedef BOOL(WINAPI* pfnSetDefaultDllDirectories)(DWORD DirectoryFlags);
|
||||
typedef BOOL(WINAPI* pfnSetDllDirectoryW)(LPCWSTR lpPathName);
|
||||
typedef BOOL(WINAPI* pfnAddDllDirectory)(LPCWSTR lpPathName);
|
||||
|
||||
static pfnSetDefaultDllDirectories pSetDefaultDllDirectories;
|
||||
static pfnSetDllDirectoryW pSetDllDirectoryW;
|
||||
static pfnAddDllDirectory pAddDllDirectory;
|
||||
|
||||
bool InitializeSignatureCheck()
|
||||
{
|
||||
if(!GetModuleFileNameW(GetModuleHandleW(nullptr), szModulePath, _countof(szModulePath)))
|
||||
if(!GetModuleFileNameW(GetModuleHandleW(nullptr), szApplicationDir, _countof(szApplicationDir)))
|
||||
return false;
|
||||
bPerformSignatureChecks = VerifyEmbeddedSignature(szModulePath);
|
||||
bPerformSignatureChecks = true; // TODO: remove this
|
||||
auto ptr = wcsrchr(szModulePath, L'\\');
|
||||
|
||||
std::wstring executablePath = szApplicationDir;
|
||||
auto ptr = wcsrchr(szApplicationDir, L'\\');
|
||||
if(ptr == nullptr)
|
||||
return false;
|
||||
*ptr = L'\0';
|
||||
// TODO: check signature
|
||||
// https://learn.microsoft.com/en-us/windows/win32/seccrypto/example-c-program--verifying-the-signature-of-a-pe-file
|
||||
ptr[1] = L'\0';
|
||||
|
||||
// Get system directory
|
||||
wchar_t szSystemDir[MAX_PATH] = L"";
|
||||
GetSystemDirectoryW(szSystemDir, _countof(szSystemDir));
|
||||
|
||||
// This is generically fixing DLL hijacking by using the following search order
|
||||
// - System directory
|
||||
// - Application directory
|
||||
// References:
|
||||
// - https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-setdefaultdlldirectories
|
||||
// - https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory
|
||||
// - https://medium.com/@1ndahous3/safe-code-pitfalls-dll-side-loading-winapi-and-c-73baaf48bdf5
|
||||
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
pSetDefaultDllDirectories = (pfnSetDefaultDllDirectories)GetProcAddress(hKernel32, "SetDefaultDllDirectories");
|
||||
pSetDllDirectoryW = (pfnSetDllDirectoryW)GetProcAddress(hKernel32, "SetDllDirectoryW");
|
||||
pAddDllDirectory = (pfnAddDllDirectory)GetProcAddress(hKernel32, "AddDllDirectory");
|
||||
if(pSetDefaultDllDirectories && pSetDllDirectoryW && pAddDllDirectory)
|
||||
{
|
||||
if(!pSetDllDirectoryW(L""))
|
||||
return false;
|
||||
|
||||
// Thanks to daax for finding this order
|
||||
// > If more than one directory has been added, the order in which those directories are searched is unspecified.
|
||||
// Reversing ntdll shows that it is using a singly-linked list, so the order is the opposite in which you add it
|
||||
// Wine: https://github.com/wine-mirror/wine/blob/e796002ee61bf5dfb2718e8f4fb8fa928ccdc236/dlls/ntdll/loader.c#L4423-L4462
|
||||
if(!pAddDllDirectory(szApplicationDir))
|
||||
return false;
|
||||
if(!pAddDllDirectory(szSystemDir))
|
||||
return false;
|
||||
|
||||
if(!pSetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto loadSystemDll = [&szSystemDir](const wchar_t* szName)
|
||||
{
|
||||
std::wstring fullDllPath;
|
||||
fullDllPath = szSystemDir;
|
||||
fullDllPath += L'\\';
|
||||
fullDllPath += szName;
|
||||
LoadLibraryW(fullDllPath.c_str());
|
||||
};
|
||||
|
||||
// At least prevent DLL hijacking for wintrust.dll on XP/Old 7
|
||||
loadSystemDll(L"msasn1.dll");
|
||||
loadSystemDll(L"cryptsp.dll");
|
||||
loadSystemDll(L"cryptbase.dll");
|
||||
loadSystemDll(L"wintrust.dll");
|
||||
loadSystemDll(L"rsaenh.dll");
|
||||
loadSystemDll(L"psapi.dll");
|
||||
}
|
||||
|
||||
bPerformSignatureChecks = VerifyEmbeddedSignature(executablePath.c_str(), false);
|
||||
|
||||
#ifdef DEBUG_SIGNATURE_CHECKS
|
||||
bPerformSignatureChecks = true;
|
||||
pLdrRegisterDllNotification = (PLDR_REGISTER_DLL_NOTIFICATION_FUNCTION)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "LdrRegisterDllNotification");
|
||||
if(pLdrRegisterDllNotification == nullptr)
|
||||
return true;
|
||||
PVOID Cookie;
|
||||
auto status = pLdrRegisterDllNotification(0, MyLdrDllNotification, nullptr, &Cookie);
|
||||
if(status != 0)
|
||||
return false;
|
||||
#endif // DEBUG_SIGNATURE_CHECKS
|
||||
|
||||
if(bPerformSignatureChecks)
|
||||
{
|
||||
// Safely load the MSVC runtime DLLs (since they cannot be delay loaded)
|
||||
auto loadRuntimeDll = [](const wchar_t* szDll)
|
||||
{
|
||||
std::wstring fullDllPath = szApplicationDir;
|
||||
fullDllPath += L'\\';
|
||||
fullDllPath += szDll;
|
||||
if(FileExists(fullDllPath.c_str()))
|
||||
LoadLibraryCheckedW(szDll, true);
|
||||
else
|
||||
LoadLibraryW(szDll);
|
||||
};
|
||||
loadRuntimeDll(L"msvcr120.dll");
|
||||
loadRuntimeDll(L"msvcp120.dll");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
bool InitializeSignatureCheck();
|
||||
#include <Windows.h>
|
||||
|
||||
#define SIGNATURE_EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
bool InitializeSignatureCheck();
|
||||
SIGNATURE_EXPORT HMODULE LoadLibraryCheckedW(const wchar_t* szDll, bool allowFailure);
|
||||
SIGNATURE_EXPORT HMODULE LoadLibraryCheckedA(const char* szDll, bool allowFailure);
|
|
@ -140,7 +140,7 @@
|
|||
<AdditionalManifestDependencies>
|
||||
</AdditionalManifestDependencies>
|
||||
<LargeAddressAware>true</LargeAddressAware>
|
||||
<DelayLoadDLLs>x32bridge.dll</DelayLoadDLLs>
|
||||
<DelayLoadDLLs>user32.dll;wintrust.dll;x32bridge.dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
|
@ -176,7 +176,7 @@
|
|||
<ProgramDatabaseFile>$(TargetDir)$(TargetName)_exe.pdb</ProgramDatabaseFile>
|
||||
<AdditionalManifestDependencies>
|
||||
</AdditionalManifestDependencies>
|
||||
<DelayLoadDLLs>x64bridge.dll</DelayLoadDLLs>
|
||||
<DelayLoadDLLs>user32.dll;wintrust.dll;x64bridge.dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
|
|
@ -292,7 +292,7 @@ static void AddDBFileTypeIcon(TCHAR* sz32Path, TCHAR* sz64Path)
|
|||
return;
|
||||
}
|
||||
|
||||
static TCHAR szModulePath[MAX_PATH] = TEXT("");
|
||||
static TCHAR szApplicationDir[MAX_PATH] = TEXT("");
|
||||
static TCHAR szCurrentDir[MAX_PATH] = TEXT("");
|
||||
static TCHAR sz32Path[MAX_PATH] = TEXT("");
|
||||
static TCHAR sz32Dir[MAX_PATH] = TEXT("");
|
||||
|
@ -306,7 +306,7 @@ static void restartInstall()
|
|||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
GetVersionEx(&osvi);
|
||||
auto operation = osvi.dwMajorVersion >= 6 ? TEXT("runas") : TEXT("open");
|
||||
ShellExecute(nullptr, operation, szModulePath, TEXT("::install"), szCurrentDir, SW_SHOWNORMAL);
|
||||
ShellExecute(nullptr, operation, szApplicationDir, TEXT("::install"), szCurrentDir, SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
static BOOL CALLBACK DlgLauncher(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
|
@ -429,14 +429,14 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||
CoInitialize(nullptr);
|
||||
|
||||
//Get INI file path
|
||||
if(!GetModuleFileName(nullptr, szModulePath, MAX_PATH))
|
||||
if(!GetModuleFileName(nullptr, szApplicationDir, MAX_PATH))
|
||||
{
|
||||
MessageBox(nullptr, LoadResString(IDS_ERRORGETTINGMODULEPATH), LoadResString(IDS_ERROR), MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
return 0;
|
||||
}
|
||||
TCHAR szIniPath[MAX_PATH] = TEXT("");
|
||||
_tcscpy_s(szIniPath, szModulePath);
|
||||
_tcscpy_s(szCurrentDir, szModulePath);
|
||||
_tcscpy_s(szIniPath, szApplicationDir);
|
||||
_tcscpy_s(szCurrentDir, szApplicationDir);
|
||||
auto len = int(_tcslen(szCurrentDir));
|
||||
while(szCurrentDir[len] != TEXT('\\') && len)
|
||||
len--;
|
||||
|
@ -585,9 +585,9 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||
if(MessageBox(nullptr, LoadResString(IDS_ASKSHELLEXT), LoadResString(IDS_QUESTION), MB_YESNO | MB_ICONQUESTION) == IDYES)
|
||||
{
|
||||
TCHAR szLauncherCommand[MAX_PATH] = TEXT("");
|
||||
_stprintf_s(szLauncherCommand, _countof(szLauncherCommand), TEXT("\"%s\" \"%%1\""), szModulePath);
|
||||
_stprintf_s(szLauncherCommand, _countof(szLauncherCommand), TEXT("\"%s\" \"%%1\""), szApplicationDir);
|
||||
TCHAR szIconCommand[MAX_PATH] = TEXT("");
|
||||
_stprintf_s(szIconCommand, _countof(szIconCommand), TEXT("\"%s\",0"), szModulePath);
|
||||
_stprintf_s(szIconCommand, _countof(szIconCommand), TEXT("\"%s\",0"), szApplicationDir);
|
||||
if(RegisterShellExtension(SHELLEXT_EXE_KEY, szLauncherCommand))
|
||||
AddShellIcon(SHELLEXT_ICON_EXE_KEY, szIconCommand, LoadResString(IDS_SHELLEXTDBG));
|
||||
if(RegisterShellExtension(SHELLEXT_DLL_KEY, szLauncherCommand))
|
||||
|
|
Loading…
Reference in New Issue