mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
Added digital signature validation for d3d12core.dll
This commit is contained in:
committed by
Baldur Karlsson
parent
dcb65e20e2
commit
92f64281d0
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <wincrypt.h>
|
||||
#include "core/settings.h"
|
||||
#include "hooks/hooks.h"
|
||||
#include "strings/string_utils.h"
|
||||
@@ -41,7 +42,7 @@ namespace
|
||||
DWORD SystemCoreVersion;
|
||||
rdcstr D3D12Core_Override_Path;
|
||||
rdcstr D3D12Core_Temp_Path;
|
||||
};
|
||||
}; // namespace
|
||||
|
||||
MIDL_INTERFACE("DFAFDD2C-355F-4CB3-A8B2-EA7F9260148B")
|
||||
ID3D12CoreModule : public IUnknown
|
||||
@@ -154,6 +155,160 @@ HRESULT WINAPI Hooked_SDKLayers_D3D12GetInterface(_In_ REFCLSID rclsid, _In_ REF
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Can check signatures of .exe and .dll files
|
||||
bool IsSignedByMicrosoft(const rdcstr &filename)
|
||||
{
|
||||
bool IsSignatureValid = false;
|
||||
|
||||
typedef BOOL(WINAPI * PFN_CRYPTQUERYOBJECT)(DWORD, const void *, DWORD, DWORD, DWORD, DWORD *,
|
||||
DWORD *, DWORD *, HCERTSTORE *, HCRYPTMSG *,
|
||||
const void **);
|
||||
typedef BOOL(WINAPI * PFN_CRYPTMSGGETPARAM)(HCRYPTMSG, DWORD, DWORD, void *, DWORD *);
|
||||
typedef PCCERT_CONTEXT(WINAPI * PFN_CERTFINDCERTIFICATEINSTORE)(HCERTSTORE, DWORD, DWORD, DWORD,
|
||||
const void *, PCCERT_CONTEXT);
|
||||
typedef DWORD(WINAPI * PFN_CERTGETNAMESTRINGW)(PCCERT_CONTEXT, DWORD, DWORD, void *, LPWSTR, DWORD);
|
||||
typedef BOOL(WINAPI * PFN_CERTFREECERTIFICATECONTEXT)(PCCERT_CONTEXT);
|
||||
typedef BOOL(WINAPI * PFN_CERTCLOSESTORE)(HCERTSTORE, DWORD);
|
||||
typedef BOOL(WINAPI * PFN_CRYPTMSGCLOSE)(HCRYPTMSG);
|
||||
|
||||
HMODULE crypt32 = NULL;
|
||||
PFN_CRYPTQUERYOBJECT CryptQueryObject = NULL;
|
||||
PFN_CRYPTMSGGETPARAM CryptMsgGetParam = NULL;
|
||||
PFN_CERTFINDCERTIFICATEINSTORE CertFindCertificateInStore = NULL;
|
||||
PFN_CERTGETNAMESTRINGW CertGetNameStringW = NULL;
|
||||
PFN_CERTFREECERTIFICATECONTEXT CertFreeCertificateContext = NULL;
|
||||
PFN_CERTCLOSESTORE CertCloseStore = NULL;
|
||||
PFN_CRYPTMSGCLOSE CryptMsgClose = NULL;
|
||||
|
||||
HCERTSTORE store = NULL;
|
||||
HCRYPTMSG msg = NULL;
|
||||
PCMSG_SIGNER_INFO signer_info = NULL;
|
||||
DWORD signer_info_size{};
|
||||
PCCERT_CONTEXT cert_context = NULL;
|
||||
CERT_INFO cert_info{};
|
||||
LPTSTR signer_name = NULL;
|
||||
DWORD signer_name_length{};
|
||||
|
||||
do
|
||||
{
|
||||
crypt32 = LoadLibraryA("crypt32.dll");
|
||||
|
||||
if(!crypt32)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CryptQueryObject = (PFN_CRYPTQUERYOBJECT)GetProcAddress(crypt32, "CryptQueryObject");
|
||||
CryptMsgGetParam = (PFN_CRYPTMSGGETPARAM)GetProcAddress(crypt32, "CryptMsgGetParam");
|
||||
CertFindCertificateInStore =
|
||||
(PFN_CERTFINDCERTIFICATEINSTORE)GetProcAddress(crypt32, "CertFindCertificateInStore");
|
||||
CertGetNameStringW = (PFN_CERTGETNAMESTRINGW)GetProcAddress(crypt32, "CertGetNameStringW");
|
||||
CertFreeCertificateContext =
|
||||
(PFN_CERTFREECERTIFICATECONTEXT)GetProcAddress(crypt32, "CertFreeCertificateContext");
|
||||
CertCloseStore = (PFN_CERTCLOSESTORE)GetProcAddress(crypt32, "CertCloseStore");
|
||||
CryptMsgClose = (PFN_CRYPTMSGCLOSE)GetProcAddress(crypt32, "CryptMsgClose");
|
||||
|
||||
if(!CryptQueryObject || !CryptMsgGetParam || !CertFindCertificateInStore ||
|
||||
!CertGetNameStringW || !CertFreeCertificateContext || !CertCloseStore || !CryptMsgClose)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rdcwstr wideFilename = StringFormat::UTF82Wide(filename);
|
||||
|
||||
// Get message handle and store handle from the signed file.
|
||||
BOOL res = CryptQueryObject(
|
||||
CERT_QUERY_OBJECT_FILE, wideFilename.c_str(), CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
|
||||
CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, &store, &msg, NULL);
|
||||
|
||||
if(!res)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get signer information size.
|
||||
res = CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &signer_info_size);
|
||||
if(!res)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Allocate memory for signer information.
|
||||
signer_info = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, signer_info_size);
|
||||
if(!signer_info)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get Signer Information.
|
||||
res = CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)signer_info, &signer_info_size);
|
||||
if(!res)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cert_info.Issuer = signer_info->Issuer;
|
||||
cert_info.SerialNumber = signer_info->SerialNumber;
|
||||
|
||||
// Get Certificate handle
|
||||
cert_context = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
|
||||
CERT_FIND_SUBJECT_CERT, (PVOID)&cert_info, NULL);
|
||||
if(!cert_context)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get Subject name size.
|
||||
signer_name_length =
|
||||
CertGetNameStringW(cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0);
|
||||
if(!signer_name_length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Allocate memory for subject name.
|
||||
signer_name = (LPTSTR)LocalAlloc(LPTR, signer_name_length * sizeof(WCHAR));
|
||||
if(!signer_name)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get subject name.
|
||||
if(!CertGetNameStringW(cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, signer_name,
|
||||
signer_name_length))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Check whether signer is Microsoft
|
||||
// Since Microsoft uses multiple different signatures,
|
||||
// We just check whether "Microsoft" is a substring of signer simple name
|
||||
// Nobody except Microsoft should ever have such signature
|
||||
if(wcsstr(signer_name, L"Microsoft") == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
IsSignatureValid = true;
|
||||
|
||||
} while(0);
|
||||
|
||||
if(signer_info != NULL)
|
||||
LocalFree(signer_info);
|
||||
if(cert_context != NULL)
|
||||
CertFreeCertificateContext(cert_context);
|
||||
if(store != NULL)
|
||||
CertCloseStore(store, 0);
|
||||
if(msg != NULL)
|
||||
CryptMsgClose(msg);
|
||||
if(signer_name != NULL)
|
||||
LocalFree(signer_name);
|
||||
if(crypt32)
|
||||
FreeLibrary(crypt32);
|
||||
|
||||
return IsSignatureValid;
|
||||
}
|
||||
|
||||
void D3D12_PrepareReplaySDKVersion(UINT SDKVersion, bytebuf d3d12core_file,
|
||||
bytebuf d3d12sdklayers_file, HMODULE d3d12lib)
|
||||
{
|
||||
@@ -288,12 +443,18 @@ void D3D12_PrepareReplaySDKVersion(UINT SDKVersion, bytebuf d3d12core_file,
|
||||
FileIO::fwrite(d3d12core_file.data(), 1, d3d12core_file.size(), f);
|
||||
FileIO::fclose(f);
|
||||
|
||||
D3D12Core_Override_Path = get_dirname(filename);
|
||||
D3D12Core_Temp_Path = get_dirname(filename);
|
||||
if(!IsSignedByMicrosoft(filename))
|
||||
{
|
||||
FileIO::Delete(filename);
|
||||
RDCERR(
|
||||
"Can't verify digital signature of D3D12Core.dll embedded in capture, it won't be "
|
||||
"used");
|
||||
break;
|
||||
}
|
||||
|
||||
filename = get_dirname(filename) + "/d3d12sdklayers.dll";
|
||||
rdcstr sdklayers_filename = get_dirname(filename) + "/d3d12sdklayers.dll";
|
||||
|
||||
f = FileIO::fopen(filename.c_str(), FileIO::WriteBinary);
|
||||
f = FileIO::fopen(sdklayers_filename.c_str(), FileIO::WriteBinary);
|
||||
|
||||
// if we can write to this file, we have exclusive use of it so let's write it and use it
|
||||
if(f)
|
||||
@@ -302,6 +463,19 @@ void D3D12_PrepareReplaySDKVersion(UINT SDKVersion, bytebuf d3d12core_file,
|
||||
FileIO::fclose(f);
|
||||
}
|
||||
|
||||
if(!IsSignedByMicrosoft(sdklayers_filename))
|
||||
{
|
||||
FileIO::Delete(filename);
|
||||
FileIO::Delete(sdklayers_filename);
|
||||
RDCERR(
|
||||
"Can't verify digital signature of d3d12sdklayers.dll embedded in capture, it won't "
|
||||
"be used");
|
||||
break;
|
||||
}
|
||||
|
||||
D3D12Core_Override_Path = get_dirname(filename);
|
||||
D3D12Core_Temp_Path = get_dirname(filename);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user