Initial signature checking PoC working
This commit is contained in:
parent
a9261b7627
commit
c4df19f724
|
@ -0,0 +1,260 @@
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <delayimp.h>
|
||||||
|
#include <Softpub.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#include <wintrust.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
static wchar_t szModulePath[MAX_PATH];
|
||||||
|
static bool bPerformSignatureChecks = false;
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
LONG lStatus;
|
||||||
|
DWORD dwLastError;
|
||||||
|
|
||||||
|
// Initialize the WINTRUST_FILE_INFO structure.
|
||||||
|
|
||||||
|
WINTRUST_FILE_INFO FileData;
|
||||||
|
memset(&FileData, 0, sizeof(FileData));
|
||||||
|
FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
||||||
|
FileData.pcwszFilePath = pwszSourceFile;
|
||||||
|
FileData.hFile = NULL;
|
||||||
|
FileData.pgKnownSubject = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
WVTPolicyGUID specifies the policy to apply on the file
|
||||||
|
WINTRUST_ACTION_GENERIC_VERIFY_V2 policy checks:
|
||||||
|
|
||||||
|
1) The certificate used to sign the file chains up to a root
|
||||||
|
certificate located in the trusted root certificate store. This
|
||||||
|
implies that the identity of the publisher has been verified by
|
||||||
|
a certification authority.
|
||||||
|
|
||||||
|
2) In cases where user interface is displayed (which this example
|
||||||
|
does not do), WinVerifyTrust will check for whether the
|
||||||
|
end entity certificate is stored in the trusted publisher store,
|
||||||
|
implying that the user trusts content from this publisher.
|
||||||
|
|
||||||
|
3) The end entity certificate has sufficient permission to sign
|
||||||
|
code, as indicated by the presence of a code signing EKU or no
|
||||||
|
EKU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
||||||
|
WINTRUST_DATA WinTrustData;
|
||||||
|
|
||||||
|
// Initialize the WinVerifyTrust input data structure.
|
||||||
|
|
||||||
|
// Default all fields to 0.
|
||||||
|
memset(&WinTrustData, 0, sizeof(WinTrustData));
|
||||||
|
|
||||||
|
WinTrustData.cbStruct = sizeof(WinTrustData);
|
||||||
|
|
||||||
|
// Use default code signing EKU.
|
||||||
|
WinTrustData.pPolicyCallbackData = NULL;
|
||||||
|
|
||||||
|
// No data to pass to SIP.
|
||||||
|
WinTrustData.pSIPClientData = NULL;
|
||||||
|
|
||||||
|
// Disable WVT UI.
|
||||||
|
WinTrustData.dwUIChoice = WTD_UI_NONE;
|
||||||
|
|
||||||
|
// Check certificate revocations
|
||||||
|
WinTrustData.fdwRevocationChecks = checkRevocation ? WTD_REVOKE_WHOLECHAIN : WTD_REVOKE_NONE;
|
||||||
|
|
||||||
|
// Verify an embedded signature on a file.
|
||||||
|
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
|
||||||
|
|
||||||
|
// Verify action.
|
||||||
|
WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
|
||||||
|
|
||||||
|
// Verification sets this value.
|
||||||
|
WinTrustData.hWVTStateData = NULL;
|
||||||
|
|
||||||
|
// Not used.
|
||||||
|
WinTrustData.pwszURLReference = NULL;
|
||||||
|
|
||||||
|
// This is not applicable if there is no UI because it changes
|
||||||
|
// the UI to accommodate running applications instead of
|
||||||
|
// installing applications.
|
||||||
|
WinTrustData.dwUIContext = 0;
|
||||||
|
|
||||||
|
// Set pFile.
|
||||||
|
WinTrustData.pFile = &FileData;
|
||||||
|
|
||||||
|
// WinVerifyTrust verifies signatures as specified by the GUID
|
||||||
|
// and Wintrust_Data.
|
||||||
|
lStatus = WinVerifyTrust(
|
||||||
|
NULL,
|
||||||
|
&WVTPolicyGUID,
|
||||||
|
&WinTrustData);
|
||||||
|
|
||||||
|
bool validSignature = false;
|
||||||
|
switch(lStatus)
|
||||||
|
{
|
||||||
|
case ERROR_SUCCESS:
|
||||||
|
/*
|
||||||
|
Signed file:
|
||||||
|
- Hash that represents the subject is trusted.
|
||||||
|
|
||||||
|
- Trusted publisher without any verification errors.
|
||||||
|
|
||||||
|
- UI was disabled in dwUIChoice. No publisher or
|
||||||
|
time stamp chain errors.
|
||||||
|
|
||||||
|
- UI was enabled in dwUIChoice and the user clicked
|
||||||
|
"Yes" when asked to install and run the signed
|
||||||
|
subject.
|
||||||
|
*/
|
||||||
|
wprintf_s(L"The file \"%s\" is signed and the signature "
|
||||||
|
L"was verified.\n",
|
||||||
|
pwszSourceFile);
|
||||||
|
validSignature = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRUST_E_NOSIGNATURE:
|
||||||
|
// The file was not signed or had a signature
|
||||||
|
// that was not valid.
|
||||||
|
|
||||||
|
// Get the reason for no signature.
|
||||||
|
dwLastError = GetLastError();
|
||||||
|
if(TRUST_E_NOSIGNATURE == dwLastError ||
|
||||||
|
TRUST_E_SUBJECT_FORM_UNKNOWN == dwLastError ||
|
||||||
|
TRUST_E_PROVIDER_UNKNOWN == dwLastError)
|
||||||
|
{
|
||||||
|
// The file was not signed.
|
||||||
|
wprintf_s(L"The file \"%s\" is not signed.\n",
|
||||||
|
pwszSourceFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The signature was not valid or there was an error
|
||||||
|
// opening the file.
|
||||||
|
wprintf_s(L"An unknown error occurred trying to "
|
||||||
|
L"verify the signature of the \"%s\" file.\n",
|
||||||
|
pwszSourceFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRUST_E_EXPLICIT_DISTRUST:
|
||||||
|
// The hash that represents the subject or the publisher
|
||||||
|
// is not allowed by the admin or user.
|
||||||
|
wprintf_s(L"The signature is present, but specifically "
|
||||||
|
L"disallowed.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRUST_E_SUBJECT_NOT_TRUSTED:
|
||||||
|
// The user clicked "No" when asked to install and run.
|
||||||
|
wprintf_s(L"The signature is present, but not "
|
||||||
|
L"trusted.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CRYPT_E_SECURITY_SETTINGS:
|
||||||
|
/*
|
||||||
|
The hash that represents the subject or the publisher
|
||||||
|
was not explicitly trusted by the admin and the
|
||||||
|
admin policy has disabled user trust. No signature,
|
||||||
|
publisher or time stamp errors.
|
||||||
|
*/
|
||||||
|
wprintf_s(L"CRYPT_E_SECURITY_SETTINGS - The hash "
|
||||||
|
L"representing the subject or the publisher wasn't "
|
||||||
|
L"explicitly trusted by the admin and admin policy "
|
||||||
|
L"has disabled user trust. No signature, publisher "
|
||||||
|
L"or timestamp errors.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// The UI was disabled in dwUIChoice or the admin policy
|
||||||
|
// has disabled user trust. lStatus contains the
|
||||||
|
// publisher or time stamp chain error.
|
||||||
|
wprintf_s(L"Error is: 0x%x.\n",
|
||||||
|
lStatus);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any hWVTStateData must be released by a call with close.
|
||||||
|
WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
|
||||||
|
|
||||||
|
lStatus = WinVerifyTrust(
|
||||||
|
NULL,
|
||||||
|
&WVTPolicyGUID,
|
||||||
|
&WinTrustData);
|
||||||
|
|
||||||
|
return validSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::wstring Utf8ToUtf16(const char* str)
|
||||||
|
{
|
||||||
|
std::wstring convertedString;
|
||||||
|
if(!str || !*str)
|
||||||
|
return convertedString;
|
||||||
|
int requiredSize = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
|
||||||
|
if(requiredSize > 0)
|
||||||
|
{
|
||||||
|
convertedString.resize(requiredSize - 1);
|
||||||
|
if(!MultiByteToWideChar(CP_UTF8, 0, str, -1, (wchar_t*)convertedString.c_str(), requiredSize))
|
||||||
|
convertedString.clear();
|
||||||
|
}
|
||||||
|
return convertedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
if(dliNotify == dliNotePreLoadLibrary)
|
||||||
|
{
|
||||||
|
std::wstring fullDllPath = szModulePath;
|
||||||
|
fullDllPath += L'\\';
|
||||||
|
fullDllPath += Utf8ToUtf16(pdli->szDll);
|
||||||
|
MessageBoxW(nullptr, fullDllPath.c_str(), L"dliNotePreLoadLibrary", MB_ICONERROR);
|
||||||
|
if(bPerformSignatureChecks)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 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;
|
||||||
|
|
||||||
|
bool InitializeSignatureCheck()
|
||||||
|
{
|
||||||
|
if(!GetModuleFileNameW(GetModuleHandleW(nullptr), szModulePath, _countof(szModulePath)))
|
||||||
|
return false;
|
||||||
|
bPerformSignatureChecks = VerifyEmbeddedSignature(szModulePath);
|
||||||
|
bPerformSignatureChecks = true; // TODO: remove this
|
||||||
|
auto ptr = wcsrchr(szModulePath, 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
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
bool InitializeSignatureCheck();
|
|
@ -9,6 +9,7 @@
|
||||||
#include "crashdump.h"
|
#include "crashdump.h"
|
||||||
#include "../bridge/bridgemain.h"
|
#include "../bridge/bridgemain.h"
|
||||||
#include "LoadResourceString.h"
|
#include "LoadResourceString.h"
|
||||||
|
#include "signaturecheck.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@fn int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
@fn int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||||
|
@ -25,6 +26,10 @@
|
||||||
|
|
||||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||||
{
|
{
|
||||||
|
// Reference: https://www.trendmicro.com/pl_pl/research/23/b/investigating-the-plugx-trojan-disguised-as-a-legitimate-windows.html
|
||||||
|
if(!InitializeSignatureCheck())
|
||||||
|
MessageBoxA(nullptr, "Failed to initialize signature check.", "Error", MB_SYSTEMMODAL | MB_ICONERROR);
|
||||||
|
|
||||||
CrashDumpInitialize();
|
CrashDumpInitialize();
|
||||||
|
|
||||||
const wchar_t* errormsg = BridgeInit();
|
const wchar_t* errormsg = BridgeInit();
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="crashdump.cpp" />
|
<ClCompile Include="crashdump.cpp" />
|
||||||
|
<ClCompile Include="signaturecheck.cpp" />
|
||||||
<ClCompile Include="x64dbg_exe.cpp" />
|
<ClCompile Include="x64dbg_exe.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
<ClInclude Include="icon.h" />
|
<ClInclude Include="icon.h" />
|
||||||
<ClInclude Include="LoadResourceString.h" />
|
<ClInclude Include="LoadResourceString.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="signaturecheck.h" />
|
||||||
<ClInclude Include="strings.h" />
|
<ClInclude Include="strings.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -124,7 +126,7 @@
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -138,6 +140,7 @@
|
||||||
<AdditionalManifestDependencies>
|
<AdditionalManifestDependencies>
|
||||||
</AdditionalManifestDependencies>
|
</AdditionalManifestDependencies>
|
||||||
<LargeAddressAware>true</LargeAddressAware>
|
<LargeAddressAware>true</LargeAddressAware>
|
||||||
|
<DelayLoadDLLs>x32bridge.dll</DelayLoadDLLs>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
@ -161,7 +164,7 @@
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -173,6 +176,7 @@
|
||||||
<ProgramDatabaseFile>$(TargetDir)$(TargetName)_exe.pdb</ProgramDatabaseFile>
|
<ProgramDatabaseFile>$(TargetDir)$(TargetName)_exe.pdb</ProgramDatabaseFile>
|
||||||
<AdditionalManifestDependencies>
|
<AdditionalManifestDependencies>
|
||||||
</AdditionalManifestDependencies>
|
</AdditionalManifestDependencies>
|
||||||
|
<DelayLoadDLLs>x64bridge.dll</DelayLoadDLLs>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
<ClCompile Include="x64dbg_exe.cpp">
|
<ClCompile Include="x64dbg_exe.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="signaturecheck.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="resource.h">
|
<ClInclude Include="resource.h">
|
||||||
|
@ -38,6 +41,9 @@
|
||||||
<ClInclude Include="LoadResourceString.h">
|
<ClInclude Include="LoadResourceString.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="signaturecheck.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="resource.rc">
|
<ResourceCompile Include="resource.rc">
|
||||||
|
|
Loading…
Reference in New Issue