Skip to content

Instantly share code, notes, and snippets.

@jthuraisamy
Last active October 15, 2023 03:01
Show Gist options
  • Save jthuraisamy/4c4c751df09f83d3620013f5d370d3b9 to your computer and use it in GitHub Desktop.
Save jthuraisamy/4c4c751df09f83d3620013f5d370d3b9 to your computer and use it in GitHub Desktop.
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