Last active
October 15, 2023 03:01
-
-
Save jthuraisamy/4c4c751df09f83d3620013f5d370d3b9 to your computer and use it in GitHub Desktop.
Loaded Security Product Drivers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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