Loaded Security Product Drivers
#include <Windows.h> | |
#include <ImageHlp.h> | |
#include <strsafe.h> | |
#include "loaded_psp_drivers.h" | |
#include <set> | |
#include <string> | |
#include <algorithm> | |
#pragma comment(lib, "crypt32.lib") | |
#pragma comment(lib, "imagehlp.lib") | |
using namespace std; | |
int validate_driver(wstring file_path) | |
{ | |
set<wstring> psp_signature_signers; | |
psp_signature_signers.insert(L"Carbon Black, Inc."); | |
psp_signature_signers.insert(L"CrowdStrike, Inc."); | |
psp_signature_signers.insert(L"Cylance, Inc."); | |
psp_signature_signers.insert(L"FireEye, Inc."); | |
psp_signature_signers.insert(L"McAfee, Inc."); | |
psp_signature_signers.insert(L"Sentinel Labs, Inc."); | |
psp_signature_signers.insert(L"Symantec Corporation"); | |
psp_signature_signers.insert(L"Tanium Inc."); | |
// Normalize file path to NT path. | |
transform(file_path.begin(), file_path.end(), file_path.begin(), tolower); | |
if (file_path.find(LR"(\)") != 0) | |
file_path.insert(0, LR"(\systemroot\)"); | |
// Create handle to driver file. | |
HANDLE file_handle = 0; | |
UNICODE_STRING file_path_us = { 0 }; | |
RtlCreateUnicodeString(&file_path_us, file_path.c_str()); | |
OBJECT_ATTRIBUTES object_attributes = { 0 }; | |
object_attributes.Length = sizeof(OBJECT_ATTRIBUTES); | |
object_attributes.RootDirectory = NULL; | |
object_attributes.ObjectName = &file_path_us; | |
object_attributes.Attributes = OBJ_CASE_INSENSITIVE; | |
object_attributes.SecurityDescriptor = nullptr; | |
object_attributes.SecurityQualityOfService = nullptr; | |
IO_STATUS_BLOCK io_status_block = { 0 }; | |
NtCreateFile(&file_handle, GENERIC_READ, &object_attributes, &io_status_block, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, nullptr, NULL); | |
if (!file_handle) | |
{ | |
printf("%ls -> cannot obtain handle (insufficient privs?)\n", file_path.c_str()); | |
return 1; | |
} | |
// Count certificates in file. | |
unsigned long certificate_count = 0; | |
ImageEnumerateCertificates(file_handle, CERT_SECTION_TYPE_ANY, &certificate_count, nullptr, NULL); | |
for (unsigned long i = 0; i < certificate_count; i++) | |
{ | |
// Determine the length for the ImageGetCertificateData call. | |
LPWIN_CERTIFICATE certificate_header = (LPWIN_CERTIFICATE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WIN_CERTIFICATE)); | |
ImageGetCertificateHeader(file_handle, i, certificate_header); | |
// Get the buffer for the certificate. | |
unsigned long certificate_length = certificate_header->dwLength; | |
LPWIN_CERTIFICATE certificate = (LPWIN_CERTIFICATE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, certificate_length); | |
ImageGetCertificateData(file_handle, i, certificate, &certificate_length); | |
// Call CryptVerifyMessageSignature to get a context used for CertGetNameStringW. | |
CRYPT_VERIFY_MESSAGE_PARA verify_params = { 0 }; | |
verify_params.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA); | |
verify_params.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; | |
PCCERT_CONTEXT certificate_context = (PCCERT_CONTEXT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CERT_CONTEXT)); | |
CryptVerifyMessageSignature(&verify_params, i, certificate->bCertificate, certificate->dwLength, NULL, NULL, &certificate_context); | |
// Get the name string for the certificate. | |
wchar_t certificate_name[MAX_PATH] = { 0 }; | |
CertGetNameStringW(certificate_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, NULL, nullptr, (LPWSTR)&certificate_name, MAX_PATH); | |
CertFreeCertificateContext(certificate_context); | |
// Check if it's in the white-list of certs to call out. | |
if (psp_signature_signers.count(certificate_name)) | |
printf("%ls -> %ls\n", file_path.c_str(), certificate_name); | |
HeapFree(GetProcessHeap(), NULL, certificate_header); | |
HeapFree(GetProcessHeap(), NULL, certificate); | |
} | |
CloseHandle(file_handle); | |
return 0; | |
} | |
int enumerate_loaded_drivers() | |
{ | |
// Create a handle to the service manager for calls to EnumServicesStatusExW. | |
SC_HANDLE scm_handle = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE); | |
if (!scm_handle) | |
{ | |
printf("[ERROR] Cannot open handle to service manager.\n"); | |
return 1; | |
} | |
// Determine the bytes needed for allocation. | |
unsigned long bytes_needed = 0; | |
unsigned long services_returned = 0; | |
EnumServicesStatusExW(scm_handle, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER, SERVICE_ACTIVE, nullptr, 0, &bytes_needed, &services_returned, nullptr, nullptr); | |
// Retrieve a buffer of active driver services. | |
PBYTE services = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bytes_needed); | |
if (!EnumServicesStatusExW(scm_handle, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER , SERVICE_ACTIVE, services, bytes_needed, &bytes_needed, &services_returned, nullptr, nullptr)) | |
{ | |
printf("[ERROR] Cannot enumerate services -> 0x%08X.\n", GetLastError()); | |
return 1; | |
} | |
// Get the ImagePath for each service from registry, and pass that to the validate_driver() function. | |
for (unsigned long i = 0; i < services_returned; i++) | |
{ | |
LPENUM_SERVICE_STATUS_PROCESSW service = (LPENUM_SERVICE_STATUS_PROCESSW)((ULONG64)services + i * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); | |
PWCHAR registry_path = (PWCHAR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * 2); | |
if (registry_path) | |
{ | |
StringCchCat(registry_path, MAX_PATH * 2, LR"(SYSTEM\CurrentControlSet\Services\)"); | |
StringCchCat(registry_path, MAX_PATH * 2, service->lpServiceName); | |
} | |
else | |
{ | |
continue; | |
} | |
HKEY key_handle; | |
RegOpenKeyExW(HKEY_LOCAL_MACHINE, registry_path, 0, KEY_QUERY_VALUE, &key_handle); | |
unsigned long length = 0; | |
RegQueryValueExW(key_handle, L"ImagePath", NULL, NULL, nullptr, &length); | |
HeapFree(GetProcessHeap(), NULL, registry_path); | |
if (length) | |
{ | |
PWCHAR driver_path = (PWCHAR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, length); | |
RegQueryValueExW(key_handle, L"ImagePath", NULL, NULL, (LPBYTE)driver_path, &length); | |
validate_driver(wstring(driver_path)); | |
HeapFree(GetProcessHeap(), NULL, driver_path); | |
} | |
CloseHandle(key_handle); | |
} | |
HeapFree(GetProcessHeap(), NULL, services); | |
CloseHandle(scm_handle); | |
return 0; | |
} | |
int main() | |
{ | |
return enumerate_loaded_drivers(); | |
} |
#pragma once | |
#include <Windows.h> | |
#define OBJ_CASE_INSENSITIVE 0x00000040 | |
#define FILE_OPEN 0x00000001 | |
#define FILE_NON_DIRECTORY_FILE 0x00000040 | |
typedef struct _UNICODE_STRING | |
{ | |
USHORT Length; | |
USHORT MaximumLength; | |
PWSTR Buffer; | |
} UNICODE_STRING, *PUNICODE_STRING; | |
typedef struct _OBJECT_ATTRIBUTES | |
{ | |
ULONG Length; | |
HANDLE RootDirectory; | |
PUNICODE_STRING ObjectName; | |
ULONG Attributes; | |
PVOID SecurityDescriptor; | |
PVOID SecurityQualityOfService; | |
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; | |
typedef struct _IO_STATUS_BLOCK { | |
union { | |
NTSTATUS Status; | |
PVOID Pointer; | |
} DUMMYUNIONNAME; | |
ULONG_PTR Information; | |
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; | |
typedef NTSTATUS(NTAPI* FnNtCreateFile)( | |
OUT PHANDLE FileHandle, | |
IN ACCESS_MASK DesiredAccess, | |
IN POBJECT_ATTRIBUTES ObjectAttributes, | |
OUT PIO_STATUS_BLOCK IoStatusBlock, | |
IN PLARGE_INTEGER AllocationSize, | |
IN ULONG FileAttributes, | |
IN ULONG ShareAccess, | |
IN ULONG CreateDisposition, | |
IN ULONG CreateOptions, | |
IN PVOID EaBuffer, | |
IN ULONG EaLength); | |
static FnNtCreateFile NtCreateFile = (FnNtCreateFile)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateFile"); | |
typedef NTSTATUS(NTAPI* FnRtlCreateUnicodeString)( | |
PUNICODE_STRING DestinationString, | |
PCWSTR SourceString); | |
static FnRtlCreateUnicodeString RtlCreateUnicodeString = (FnRtlCreateUnicodeString)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlCreateUnicodeString"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment