I want to call a C++ DLL from a C KMDF, I made this code
C++ Code
dll.h
extern "C" {
__declspec(dllexport) void MyFunction();
}
dll.cpp
void MyFunction()
{
std::cout << "Hello from MyFunction in C++ MyLibrary.dll" << std::endl;
}
c Code
Source.c
#include <ntddk.h>
#include <wdf.h>
#define CALL_DLL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA)
NTSTATUS GetModuleBaseAddress(PUNICODE_STRING ModuleName, PVOID* ModuleBase)
{
NTSTATUS status = STATUS_SUCCESS;
PVOID systemModuleInfo = NULL;
// Query system information to obtain module information
ULONG systemModuleInfoSize = 0;
status = ZwQuerySystemInformation(SystemModuleInformation, &systemModuleInfo, systemModuleInfoSize, &systemModuleInfoSize);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
// Allocate memory for the module information
systemModuleInfo = ExAllocatePool(NonPagedPool, systemModuleInfoSize);
if (systemModuleInfo)
{
// Retrieve the module information
status = ZwQuerySystemInformation(SystemModuleInformation, systemModuleInfo, systemModuleInfoSize, &systemModuleInfoSize);
if (NT_SUCCESS(status))
{
// Iterate through the module list
PSYSTEM_MODULE_INFORMATION moduleInfo = (PSYSTEM_MODULE_INFORMATION)systemModuleInfo;
ULONG moduleCount = systemModuleInfoSize / sizeof(SYSTEM_MODULE_INFORMATION);
for (ULONG i = 0; i < moduleCount; i++)
{
UNICODE_STRING moduleName;
RtlInitUnicodeString(&moduleName, moduleInfo[i].ImageName);
if (RtlEqualUnicodeString(&moduleName, ModuleName, TRUE))
{
*ModuleBase = moduleInfo[i].Base;
status = STATUS_SUCCESS;
break;
}
}
if (NT_SUCCESS(status))
{
// Module found
status = STATUS_SUCCESS;
}
else
{
// Module not found
status = STATUS_NOT_FOUND;
}
}
// Free the allocated memory
ExFreePool(systemModuleInfo);
}
else
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
status = STATUS_UNSUCCESSFUL;
}
return status;
}
NTSTATUS LoadDllAndCallFunction(PUNICODE_STRING DllPath, PUNICODE_STRING ModuleName, PUNICODE_STRING FunctionName)
{
NTSTATUS status = STATUS_SUCCESS;
PVOID dllBase = NULL;
HANDLE fileHandle = NULL;
// Open the DLL file
OBJECT_ATTRIBUTES objectAttributes;
InitializeObjectAttributes(&objectAttributes, DllPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
IO_STATUS_BLOCK ioStatus;
status = ZwCreateFile(&fileHandle, GENERIC_READ, &objectAttributes, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
{
// Handle the error when opening the file
return status;
}
// Load the DLL
status = PsLoadImage(DllPath, NULL, NULL, 0, &dllBase);
if (!NT_SUCCESS(status))
{
// Handle the error when loading the DLL
ZwClose(fileHandle);
return status;
}
// Get the base address of the module
PVOID moduleBase = NULL;
status = GetModuleBaseAddress(ModuleName, &moduleBase);
if (!NT_SUCCESS(status))
{
// Handle the error when getting the module base address
PsUnloadImage(dllBase);
ZwClose(fileHandle);
return status;
}
// Get the function address
PVOID functionAddress = NULL;
status = LdrGetProcedureAddress(moduleBase, FunctionName, 0, &functionAddress);
if (!NT_SUCCESS(status))
{
// Handle the error when getting the function address
PsUnloadImage(dllBase);
ZwClose(fileHandle);
return status;
}
// Call the function
typedef VOID(*FunctionPtr)();
FunctionPtr function = (FunctionPtr)functionAddress;
function();
// Unload the DLL
status = PsUnloadImage(dllBase);
if (!NT_SUCCESS(status))
{
// Handle the error when unloading the DLL
}
ZwClose(fileHandle);
return status;
}
//VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
//{
// UNREFERENCED_PARAMETER(DriverObject);
// // Unload any resources
//}
void initDevice()
{
KdPrint(("KMD - The DEVICE must be INIT \r\n"));
//UNREFERENCED_PARAMETER(RegistryPath);
//DriverObject->DriverUnload = DriverUnload;
UNICODE_STRING dllPath;
RtlInitUnicodeString(&dllPath, L"C:\\path\\MyLibrary.dll"); // Path to the user DLL
UNICODE_STRING moduleName;
RtlInitUnicodeString(&moduleName, L"MyLibrary.dll"); // Name of the module to load
UNICODE_STRING functionName;
RtlInitUnicodeString(&functionName, L"MyFunction"); // Name of the function to call
NTSTATUS status = LoadDllAndCallFunction(&dllPath, &moduleName, &functionName);
if (!NT_SUCCESS(status))
{
// Handle the error
return;
}
return STATUS_SUCCESS;
}
NTSTATUS DispatchDevCTL(PDEVICE_OBJECT DeviceObject_local, PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject_local);
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
ULONG returnLength = 0;
PVOID buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG inLength = irpsp->Parameters.DeviceIoControl.InputBufferLength;
ULONG outLength = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
WCHAR* demo = L"Sample returned from driver";
HANDLE threadHandle;
UNREFERENCED_PARAMETER(outLength);
UNREFERENCED_PARAMETER(inLength);
switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
{
case CALL_DLL:
status = PsCreateSystemThread(&threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, initDevice, NULL);
if (!NT_SUCCESS(status))
{
// Handle the error
return status;
}
// Close the thread handle
ZwClose(threadHandle);
// Complete the IRP
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = returnLength;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
int i;
//The UNREFERENCED_PARAMETER is used to indicate to the compiler that the parameter is not being used intentionality in the code and skip the warning (C4100)
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegistryPath);
//KdPrint(("Hello World \r\n"));
DriverObject->DriverUnload = Unload;
status = IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject);
if (!NT_SUCCESS(status))
{
KdPrint(("KMD - Creating device failed \r\n"));
return status;
}
status = IoCreateSymbolicLink(&SymLinkName, &DeviceName);
if (!NT_SUCCESS(status))
{
KdPrint(("KMD - Creating symbolic link failed \r\n"));
IoDeleteDevice(DeviceObject);
return status;
}
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = DispatchPassThru;
}
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDevCTL;
//DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchCustom1;
KdPrint(("KMD - Driver Loaded \r\n"));
return status;
}
I'm using VS2019, with this Project configuration
When I build the project, those errors are shown:
- 'ZwQuerySystemInformation' undefined; assuming extern returning int
- 'PsLoadImage' undefined; assuming extern returning int
- 'PsUnloadImage' undefined; assuming extern returning int
- 'LdrGetProcedureAddress' undefined; assuming extern returning int
What am I making wrong? or exist another way to call a DLL from a Driver?