mirror-ac/driver/hw.c

356 lines
10 KiB
C
Raw Permalink Normal View History

2024-02-13 19:08:38 +01:00
#include "hw.h"
2024-05-15 11:48:09 +02:00
#include "crypt.h"
#include "imports.h"
2024-07-22 12:43:09 +02:00
#include "lib/stdlib.h"
2024-08-04 08:30:31 +02:00
#include "modules.h"
2024-07-22 12:43:09 +02:00
2024-02-13 19:08:38 +01:00
#define PCI_VENDOR_ID_OFFSET 0x00
2024-02-14 17:16:27 +01:00
#define PCI_DEVICE_ID_OFFSET 0x02
#define FLAGGED_DEVICE_ID_COUNT 2
USHORT FLAGGED_DEVICE_IDS[FLAGGED_DEVICE_ID_COUNT] = {
0x0666, // default PCIe Squirrel DeviceID (used by PCI Leech)
0xffff};
2024-08-01 06:21:53 +02:00
typedef NTSTATUS (*PCI_DEVICE_CALLBACK)(
_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context);
2024-02-13 19:08:38 +01:00
/*
* Every PCI device has a set of registers commonly referred to as the PCI
* configuration space. In modern PCI-e devices an extended configuration space
* was implemented. These configuration spaces are mapped into main memory and
* this allows us to read/write to the registers.
2024-02-13 19:08:38 +01:00
*
* The configuration space consists of a standard header, containing information
* such as the DeviceID, VendorID, Status and so on. Below is the header schema
* including offsets.
2024-02-13 19:08:38 +01:00
*
* | Offset 0x00: Header Type
* | Offset 0x01: Multi-Function Device Indicator
* | Offset 0x02: Device ID (Low Byte)
* | Offset 0x03: Device ID (High Byte)
* | Offset 0x04: Status Register (16 bits)
* | Offset 0x06: Command Register (16 bits)
* | Offset 0x08: Class Code
* | Offset 0x09: Subclass Code
* | Offset 0x0A: Prog IF (Programming Interface)
* | Offset 0x0B: Revision ID
* | Offset 0x0C: BIST (Built-in Self-Test)
* | Offset 0x0D: Header Type (Secondary)
* | Offset 0x0E: Latency Timer
* | Offset 0x0F: Cache Line Size
* | Offset 0x10: Base Address Register 0 (BAR0) - 32 bits
* | Offset 0x14: Base Address Register 1 (BAR1) - 32 bits
* | Offset 0x18: Base Address Register 2 (BAR2) - 32 bits
* | Offset 0x1C: Base Address Register 3 (BAR3) - 32 bits
* | Offset 0x20: Base Address Register 4 (BAR4) - 32 bits
* | Offset 0x24: Base Address Register 5 (BAR5) - 32 bits
* | Offset 0x28: Cardbus CIS Pointer (for Cardbus bridges)
* | Offset 0x2C: Subsystem Vendor ID
* | Offset 0x2E: Subsystem ID
* | Offset 0x30: Expansion ROM Base Address
* | Offset 0x34: Reserved
* | Offset 0x38: Reserved
* | Offset 0x3C: Max_Lat (Maximum Latency)
* | Offset 0x3D: Min_Gnt (Minimum Grant)
* | Offset 0x3E: Interrupt Pin
* | Offset 0x3F: Interrupt Line
*
* We can use this to then query important information from PCI devices within
* the device tree. To keep up with modern windows kernel programming, we can
* make use of the IRP_MN_READ_CONFIG code, which as the name suggests, reads
* from a PCI devices configuration space.
2024-02-13 19:08:38 +01:00
*/
STATIC
NTSTATUS
2024-08-01 06:21:53 +02:00
QueryPciDeviceConfigurationSpace(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ UINT32 Offset,
_Out_opt_ PVOID Buffer,
_In_ UINT32 BufferLength)
2024-02-13 19:08:38 +01:00
{
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
KEVENT event = {0};
IO_STATUS_BLOCK io = {0};
PIRP irp = NULL;
2024-05-15 11:48:09 +02:00
PIO_STACK_LOCATION packet = NULL;
2024-04-13 10:23:14 +02:00
if (BufferLength == 0)
return STATUS_BUFFER_TOO_SMALL;
KeInitializeEvent(&event, NotificationEvent, FALSE);
/*
* we dont need to free this IRP as the IO manager will free it when the
* request is completed
*/
irp = IoBuildSynchronousFsdRequest(
2024-08-01 06:21:53 +02:00
IRP_MJ_PNP,
DeviceObject,
NULL,
0,
NULL,
&event,
&io);
2024-04-13 10:23:14 +02:00
if (!irp) {
DEBUG_ERROR("IoBuildSynchronousFsdRequest failed with no status.");
return STATUS_INSUFFICIENT_RESOURCES;
}
2024-08-01 06:21:53 +02:00
packet = IoGetNextIrpStackLocation(irp);
2024-05-15 11:48:09 +02:00
packet->MinorFunction = IRP_MN_READ_CONFIG;
packet->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
2024-08-01 06:21:53 +02:00
packet->Parameters.ReadWriteConfig.Offset = Offset;
packet->Parameters.ReadWriteConfig.Buffer = Buffer;
packet->Parameters.ReadWriteConfig.Length = BufferLength;
2024-04-13 10:23:14 +02:00
status = IoCallDriver(DeviceObject, irp);
2024-05-11 14:54:58 +02:00
if (status == STATUS_PENDING) {
2024-04-13 10:23:14 +02:00
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = io.Status;
}
if (!NT_SUCCESS(status))
2024-08-01 06:21:53 +02:00
DEBUG_ERROR(
"Failed to read configuration space with status %x",
status);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
return status;
2024-02-13 19:08:38 +01:00
}
/*
* NOTE: Caller is responsible for freeing the array.
*/
STATIC
NTSTATUS
2024-08-01 06:21:53 +02:00
EnumerateDriverObjectDeviceObjects(
_In_ PDRIVER_OBJECT DriverObject,
_Out_ PDEVICE_OBJECT** DeviceObjectArray,
_Out_ PUINT32 ArrayEntries)
2024-02-13 19:08:38 +01:00
{
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
UINT32 object_count = 0;
PDEVICE_OBJECT* buffer = NULL;
UINT32 buffer_size = 0;
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
*DeviceObjectArray = NULL;
2024-08-01 06:21:53 +02:00
*ArrayEntries = 0;
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
status = IoEnumerateDeviceObjectList(DriverObject, NULL, 0, &object_count);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
if (status != STATUS_BUFFER_TOO_SMALL) {
2024-08-01 06:21:53 +02:00
DEBUG_ERROR(
"IoEnumerateDeviceObjectList failed with status %x",
status);
2024-04-13 10:23:14 +02:00
return status;
}
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
buffer_size = object_count * sizeof(UINT64);
buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, buffer_size, POOL_TAG_HW);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
if (!buffer)
return STATUS_INSUFFICIENT_RESOURCES;
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
status = IoEnumerateDeviceObjectList(
2024-08-01 06:21:53 +02:00
DriverObject,
buffer,
buffer_size,
&object_count);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status)) {
2024-08-01 06:21:53 +02:00
DEBUG_ERROR(
"IoEnumerateDeviceObjectList failed with status %x",
status);
2024-04-13 10:23:14 +02:00
ExFreePoolWithTag(buffer, POOL_TAG_HW);
return status;
}
2024-02-13 19:08:38 +01:00
2024-08-01 06:21:53 +02:00
DEBUG_VERBOSE(
"EnumerateDriverObjectDeviceObjects: Object Count: %lx",
object_count);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
*DeviceObjectArray = buffer;
2024-08-01 06:21:53 +02:00
*ArrayEntries = object_count;
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
return status;
2024-02-13 19:08:38 +01:00
}
/*
* While this isnt a perfect check to determine whether a DEVICE_OBJECT is
* indeed a PDO or FDO, this is Peters preferred method... hence it is now my
* preferred method... :smiling_imp:
2024-02-13 19:08:38 +01:00
*/
STATIC
BOOLEAN
IsDeviceObjectValidPdo(_In_ PDEVICE_OBJECT DeviceObject)
{
2024-04-13 10:23:14 +02:00
return DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE ? TRUE : FALSE;
2024-02-13 19:08:38 +01:00
}
/*
* Windows splits DEVICE_OBJECTS up into 2 categories:
*
* Physical Device Object (PDO)
2024-02-13 19:29:19 +01:00
* Functional Device Object (FDO)
2024-02-13 19:08:38 +01:00
*
* A PDO represents each device that is connected to a physical bus. Each PDO
* has an associated DEVICE_NODE. An FDO represents the functionality of the
* device. Its how the system interacts with the device objects.
2024-02-13 19:08:38 +01:00
*
* More information can be found here:
* https://learn.microsoft.com/en-gb/windows-hardware/drivers/gettingstarted/device-nodes-and-device-stacks
2024-02-13 19:13:56 +01:00
*
* A device stack can have multiple PDO's, but can only have one FDO. This means
* to access each PCI device on the system, we can enumerate all device objects
* given the PCI FDO which is called pci.sys.
2024-02-13 19:08:38 +01:00
*/
NTSTATUS
2024-08-01 06:21:53 +02:00
EnumeratePciDeviceObjects(
_In_ PCI_DEVICE_CALLBACK CallbackRoutine, _In_opt_ PVOID Context)
2024-02-13 19:08:38 +01:00
{
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
UNICODE_STRING pci = RTL_CONSTANT_STRING(L"\\Driver\\pci");
PDRIVER_OBJECT pci_driver_object = NULL;
2024-04-13 10:23:14 +02:00
PDEVICE_OBJECT* pci_device_objects = NULL;
2024-08-01 06:21:53 +02:00
PDEVICE_OBJECT current_device = NULL;
UINT32 pci_device_objects_count = 0;
2024-04-13 10:23:14 +02:00
status = GetDriverObjectByDriverName(&pci, &pci_driver_object);
if (!NT_SUCCESS(status)) {
2024-08-01 06:21:53 +02:00
DEBUG_ERROR(
"GetDriverObjectByDriverName failed with status %x",
status);
2024-04-13 10:23:14 +02:00
return status;
}
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
status = EnumerateDriverObjectDeviceObjects(
2024-08-01 06:21:53 +02:00
pci_driver_object,
&pci_device_objects,
&pci_device_objects_count);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status)) {
2024-08-01 06:21:53 +02:00
DEBUG_ERROR(
"EnumerateDriverObjectDeviceObjects failed with status %x",
status);
2024-04-13 10:23:14 +02:00
return status;
}
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
for (UINT32 index = 0; index < pci_device_objects_count; index++) {
current_device = pci_device_objects[index];
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
/* make sure we have a valid PDO */
if (!IsDeviceObjectValidPdo(current_device)) {
ObDereferenceObject(current_device);
continue;
}
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
status = CallbackRoutine(current_device, Context);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status))
DEBUG_ERROR(
"EnumeratePciDeviceObjects CallbackRoutine failed with status %x",
status);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
ObDereferenceObject(current_device);
}
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
if (pci_device_objects)
ExFreePoolWithTag(pci_device_objects, POOL_TAG_HW);
2024-02-13 19:08:38 +01:00
2024-04-13 10:23:14 +02:00
return status;
2024-02-14 17:16:27 +01:00
}
BOOLEAN
IsPciConfigurationSpaceFlagged(_In_ PPCI_COMMON_HEADER Configuration)
{
2024-04-13 10:23:14 +02:00
for (UINT32 index = 0; index < FLAGGED_DEVICE_ID_COUNT; index++) {
if (Configuration->DeviceID == FLAGGED_DEVICE_IDS[index])
return TRUE;
}
2024-02-14 17:16:27 +01:00
2024-04-13 10:23:14 +02:00
return FALSE;
2024-02-14 17:16:27 +01:00
}
2024-05-15 11:48:09 +02:00
STATIC
VOID
2024-08-01 06:21:53 +02:00
ReportBlacklistedPcieDevice(
_In_ PDEVICE_OBJECT DeviceObject, _In_ PPCI_COMMON_HEADER Header)
2024-05-15 11:48:09 +02:00
{
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
2024-08-04 08:30:31 +02:00
UINT32 len = 0;
PBLACKLISTED_PCIE_DEVICE_REPORT report = NULL;
2024-05-15 11:48:09 +02:00
2024-08-04 08:30:31 +02:00
len = CryptRequestRequiredBufferLength(
sizeof(BLACKLISTED_PCIE_DEVICE_REPORT));
report = ImpExAllocatePool2(POOL_FLAG_NON_PAGED, len, REPORT_POOL_TAG);
2024-05-15 11:48:09 +02:00
if (!report)
return;
INIT_REPORT_PACKET(report, REPORT_BLACKLISTED_PCIE_DEVICE, 0);
report->device_object = (UINT64)DeviceObject;
2024-08-01 06:21:53 +02:00
report->device_id = Header->DeviceID;
report->vendor_id = Header->VendorID;
2024-05-15 11:48:09 +02:00
2024-08-04 08:30:31 +02:00
status = CryptEncryptBuffer(report, len);
2024-05-15 11:48:09 +02:00
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("CryptEncryptBuffer: %lx", status);
2024-08-04 08:30:31 +02:00
ImpExFreePoolWithTag(report, len);
2024-05-15 11:48:09 +02:00
return;
}
2024-08-04 08:30:31 +02:00
IrpQueueSchedulePacket(report, len);
2024-05-15 11:48:09 +02:00
}
2024-02-14 17:16:27 +01:00
STATIC
NTSTATUS
PciDeviceQueryCallback(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
{
2024-05-11 14:54:58 +02:00
UNREFERENCED_PARAMETER(Context);
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
2024-04-13 10:23:14 +02:00
PCI_COMMON_HEADER header = {0};
2024-02-14 17:16:27 +01:00
2024-04-13 10:23:14 +02:00
status = QueryPciDeviceConfigurationSpace(
2024-08-01 06:21:53 +02:00
DeviceObject,
PCI_VENDOR_ID_OFFSET,
&header,
sizeof(PCI_COMMON_HEADER));
2024-02-14 17:16:27 +01:00
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status)) {
2024-08-01 06:21:53 +02:00
DEBUG_ERROR(
"QueryPciDeviceConfigurationSpace failed with status %x",
status);
2024-02-14 17:16:27 +01:00
return status;
2024-04-13 10:23:14 +02:00
}
if (IsPciConfigurationSpaceFlagged(&header)) {
2024-08-01 06:21:53 +02:00
DEBUG_VERBOSE(
"Flagged DeviceID found. Device: %llx, DeviceId: %lx",
(UINT64)DeviceObject,
header.DeviceID);
ReportBlacklistedPcieDevice(DeviceObject, &header);
2024-04-13 10:23:14 +02:00
}
return status;
2024-02-14 17:16:27 +01:00
}
NTSTATUS
ValidatePciDevices()
{
2024-04-13 10:23:14 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
2024-02-14 17:16:27 +01:00
2024-04-13 10:23:14 +02:00
status = EnumeratePciDeviceObjects(PciDeviceQueryCallback, NULL);
2024-02-14 17:16:27 +01:00
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status))
DEBUG_ERROR("EnumeratePciDeviceObjects failed with status %x", status);
2024-02-14 17:16:27 +01:00
2024-04-13 10:23:14 +02:00
return status;
2024-02-13 19:08:38 +01:00
}