IOCTL Cng Random

Proof-of-concept initially developed by Grzegorz Tworek

#include <Windows.h>

#define OBJ_CASE_INSENSITIVE 0x00000040L
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020

#define NT_SUCCESS(Status)(((NTSTATUS)(Status)) >= 0)
#define IOCTL_KSEC_RNG CTL_CODE(FILE_DEVICE_KSEC, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)

typedef struct _IO_STATUS_BLOCK {
	union {
		NTSTATUS Status;
		PVOID    Pointer;
	};
	ULONG_PTR Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;

typedef struct _LSA_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;

SIZE_T StringLengthW(_In_ LPCWSTR String)
{
	LPCWSTR String2;

	for (String2 = String; *String2; ++String2);

	return (String2 - String);
}

#define InitializeObjectAttributes(p, n, a, r, s) { \
    (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
    (p)->RootDirectory = r; \
    (p)->Attributes = a; \
    (p)->ObjectName = n; \
    (p)->SecurityDescriptor = s; \
    (p)->SecurityQualityOfService = NULL; \
    }

VOID ImplZeroMemory1(_Inout_ PVOID Destination, _In_ SIZE_T Size)
{
	PBYTE Dest = (PBYTE)Destination;
	while (Size--)
	{
		*Dest++ = 0;
	}
}

VOID RtlInitUnicodeString(_Inout_ PUNICODE_STRING DestinationString, _In_ PCWSTR SourceString)
{
	SIZE_T DestSize;

	if (SourceString)
	{
		DestSize = StringLengthW(SourceString) * sizeof(WCHAR);
		DestinationString->Length = (USHORT)DestSize;
		DestinationString->MaximumLength = (USHORT)DestSize + sizeof(WCHAR);
	}
	else
	{
		DestinationString->Length = 0;
		DestinationString->MaximumLength = 0;
	}

	DestinationString->Buffer = (PWCHAR)SourceString;
}

BOOL GetRandomIntegerCryptoNextGenDeviceObject(PUINT32 RandomInteger)
{
	typedef NTSTATUS(NTAPI* NTOPENFILE)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG);
	typedef NTSTATUS(NTAPI* NTDEVICEIOCONTROLFILE)(HANDLE, HANDLE, PVOID, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG);
	typedef NTSTATUS(NTAPI* NTCLOSE)(HANDLE);

	NTOPENFILE NtOpenFile = NULL;
	NTDEVICEIOCONTROLFILE NtDeviceIoControlFile = NULL;
	NTCLOSE NtClose = NULL;
	NTSTATUS Status = 0;
	HMODULE Module = NULL;

	UNICODE_STRING DriverName = { 0 };
	OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
	IO_STATUS_BLOCK Io = { 0 };
	HANDLE Handle = NULL;
	BYTE Buffer[16] = { 0 };

	BOOL Flag = FALSE;

	Module = GetModuleHandleA("ntdll.dll");
	if (Module == NULL)
		goto EXIT_ROUTINE;

	NtOpenFile = (NTOPENFILE)GetProcAddress(Module, "NtOpenFile");
	NtDeviceIoControlFile = (NTDEVICEIOCONTROLFILE)GetProcAddress(Module, "NtDeviceIoControlFile");
	NtClose = (NTCLOSE)GetProcAddress(Module, "NtClose");

	if (!NtOpenFile || !NtDeviceIoControlFile || !NtClose)
		goto EXIT_ROUTINE;

	RtlInitUnicodeString(&DriverName, L"\\Device\\CNG");
	InitializeObjectAttributes(&ObjectAttributes, &DriverName, OBJ_CASE_INSENSITIVE, 0, 0);

	Status = NtOpenFile(&Handle, SYNCHRONIZE | FILE_READ_DATA, &ObjectAttributes, &Io, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
	if (!NT_SUCCESS(Status))
		goto EXIT_ROUTINE;

	ImplZeroMemory1(&Io, sizeof(IO_STATUS_BLOCK));

	Status = NtDeviceIoControlFile(Handle, NULL, NULL, NULL, &Io, IOCTL_KSEC_RNG, NULL, 0, Buffer, sizeof(Buffer));
	if (!NT_SUCCESS(Status))
		goto EXIT_ROUTINE;

	*RandomInteger = ((UINT32)Buffer[0]) | ((UINT32)Buffer[1] << 8) | ((UINT32)Buffer[2] << 16) | ((UINT32)Buffer[3] << 24);

	Flag = TRUE;


EXIT_ROUTINE:

	if (NtClose && Handle)
		NtClose(Handle);

	return Flag;
}

INT main(VOID)
{
	UINT32 Value = 0;

	GetRandomIntegerCryptoNextGenDeviceObject(&Value);

  return ERROR_SUCCESS;
}

Last updated