• XSS.stack #1 – первый литературный журнал от юзеров форума

Вызов FastIoDispatch обработчиков из пользовательского режима

varwar

El Diff
Забанен
Регистрация
12.11.2020
Сообщения
1 383
Решения
5
Реакции
1 537
Пожалуйста, обратите внимание, что пользователь заблокирован
С помощью какой API можно вызвать обработчики из FastIoDispatch на примере драйвера afd.sys?
Кусок листинга из DriverEntry.
C:
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AfdDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = AfdWskDispatchInternalDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = AfdEtwDispatch;
DriverObject->FastIoDispatch = &AfdFastIoDispatch;
DriverObject->DriverUnload = AfdUnload

Если с вызовами обработчиков из массива MajorFunction все понятно и документировано, то примеров клиентов с вызовом FastIo я не нашел ни в репозитории семплов драйверов, ни в книге Walter Oney "Programming the Microsoft Windows Driver Model".
 
why not this work? --> windows kernel APIs to hook into table --> intercept i/o rquests

else such dream fairy -->
DKOM --> find DEVICE_OBJECT + FILE_OBJECT inside memory --> modify FastIoDispatch pointers inside the table to your custom handler functions
*** for every necessary i/o operations
 
Пожалуйста, обратите внимание, что пользователь заблокирован
why not this work? --> windows kernel APIs to hook into table --> intercept i/o rquests

else such dream fairy -->
DKOM --> find DEVICE_OBJECT + FILE_OBJECT inside memory --> modify FastIoDispatch pointers inside the table to your custom handler functions
*** for every necessary i/o operations
I don't need to do things in a kernel at all. I need to find a way to call FastIoDispacth handlers from user mode application.
For example, when we use IRP_MJ_DEVICE_CONTROL dispatch routines we use DeviceIoControl API (or NtDeviceIoControlFile) with a proper IOCTL.
The question is what call chain lead to the AfdFastIoDispatch handlers. Maybe it's happen the same way (with NtDeviceIoControlFile), but breakpoints in the kernel didn't hit at all while system is runniing. So I can't see the trace.
 
interests thread, up, up
I don't need to do things in a kernel at all. I need to find a way to call FastIoDispacth handlers from user mode application.
For example, when we use IRP_MJ_DEVICE_CONTROL dispatch routines we use DeviceIoControl API (or NtDeviceIoControlFile) with a proper IOCTL.
The question is what call chain lead to the AfdFastIoDispatch handlers. Maybe it's happen the same way (with NtDeviceIoControlFile), but breakpoints in the kernel didn't hit at all while system is runniing. So I can't see the trace.
i donot know if such is possible without poking the kernel himself
can theoretically create a user mode device driver emulating kernel mode driver?
idea --> instead of direct call FastIoDispatch handlers --> we implement a virtual device object inside user mode with all io operations (including fastiodispatch handlers himself)
he then intercept io requests made by userland app --> handle replicating fastiodispatch handler behavior

or maybe there is undocumented forgotten API functions microsoft left inside the dark that we do not see)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
i donot know if such is possible without poking the kernel himself

If my assumptions are correct the traditional NtDeviceIoControlFile path can reach not restricted (in any ways, but I didn't saw any, all of them work with UM data in both thread contexts) fast handlers. Will check it programmatically later.


shit3.png
 
Пожалуйста, обратите внимание, что пользователь заблокирован
drpalpatine I found a way to trigger FastIo handlers back then. The assumptions was correct, NtDeviceIoControlFile used internally. Might be useful to someone. Sorry for the shitcode.

C:
#include <winternl.h>
#include <winsock2.h>
#include <MSWSock.h>
#include <windows.h>
#include <ntstatus.h>
#include <stdio.h>
//#include "common.h"
//#include <MSWSock.h>
//#include <mswsock.h>
#include <stdint.h>
//#include <WinSock2.h>
//#include <ws2def.h>

#define AFD_RIO_FAST_IOCTL 0x1211B
#define WSA_FLAG_REGISTERED_IO 0x100

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "ntdllp.lib")
#pragma warning(disable: "6011")

//
// Undocumented AFD structure
//

typedef struct __declspec(align(8)) AFD_RIO_REGISTER_BUFFER
{
    uint32_t RioType;
    uint32_t Field2;
    PVOID MdlBaseAddress;
    uint32_t MdlSize;
    uint32_t Field4;
}AFD_RIO_REGISTER_BUFFER;


typedef struct _FILE_IO_STATUS_INFORMATION {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} FILE_IO_STATUS_INFORMATION, *PFILE_IO_STATUS_INFORMATION;

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

const GUID WSAID_REGISTERED_IO = { 0x7d2903c2, 0x6290, 0x11cf, { 0xae, 0xd9, 0x0, 0x20, 0xaf, 0x6e, 0x72, 0x63 } };

GUID functionTableId = WSAID_MULTIPLE_RIO;
DWORD bytesReturned;
RIO_EXTENSION_FUNCTION_TABLE rioFunctions;

int main() {
    DWORD error = 0;
    HANDLE rioSocket;
    IO_STATUS_BLOCK ioStatus;
    FILE_IO_STATUS_INFORMATION fileIoStatus;
    ULONG ioctlCode = 0;

    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }

    rioSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_REGISTERED_IO);
    if (rioSocket == INVALID_SOCKET) {
        error = WSAGetLastError();
        return 1;
    }


    if (WSAIoctl(rioSocket,
                SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER,
                &functionTableId,
                sizeof(GUID),
                &rioFunctions,
                sizeof(RIO_EXTENSION_FUNCTION_TABLE),
                &bytesReturned,
                NULL,
                NULL) != NULL)
    {
        error = WSAGetLastError();
        closesocket(rioSocket);
        WSACleanup();
        free(&rioFunctions);
        return 1;
    }

    AFD_RIO_REGISTER_BUFFER *pData = malloc(0x18);

    if (pData)
    {

       /* We can change RioType to call different handlers, pseudocode of the AfdRioFastIo below
                if ( RioType == 4 )
                {
                    Cq = AfdRioRegisterBuffer(
                             (__int64)endp,
                             (AFD_RIO_REGISTER_BUFFER *)InputBuffer,
                             InBufLength,
                             (unsigned int *)OutputBuffer,
                             OutBuffLength,
                             AccessMode)
       */
        pData->RioType = 4;
        pData->MdlBaseAddress = 0;
        pData->MdlSize = 0x1000;
    }

    else
    {
        return -1;
    }
    /*
3: kd> k
 # Child-SP          RetAddr               Call Site
00 fffff60a`6ec4c358 fffff807`1a3e9bde     afd!AfdRioRegisterBuffer
01 fffff60a`6ec4c360 fffff807`1a3bdee8     afd!AfdRioFastIo+0x172
02 fffff60a`6ec4c450 fffff807`166c0f7e     afd!AfdFastIoDeviceControl+0x18508
03 fffff60a`6ec4c7f0 fffff807`166bf516     nt!IopXxxControlFile+0x46e
04 fffff60a`6ec4ca00 fffff807`1643d1e5     nt!NtDeviceIoControlFile+0x56
05 fffff60a`6ec4ca70 00007ff9`6cfceee4     nt!KiSystemServiceCopyEnd+0x25
06 000000f1`a4baf868 00007ff9`69855522     ntdll!NtDeviceIoControlFile+0x14
07 000000f1`a4baf870 00007ff6`f55311ca     mswsock!RIORegisterBuffer+0x92
08 000000f1`a4baf910 00000000`0000010c     riotest!main+0x15a
 */
    RIO_BUFFERID rioBufferId = rioFunctions.RIORegisterBuffer(&pData, sizeof(AFD_RIO_REGISTER_BUFFER));
    if (rioBufferId == RIO_INVALID_BUFFERID)
    {
        closesocket(rioSocket);
        WSACleanup();
        return 1;
    }

    rioFunctions.RIODeregisterBuffer(rioBufferId);

    closesocket(rioSocket);
    WSACleanup();

    return 0;
}
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Скрытый контент для пользователей: Whisper.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
drpalpatine I found a way to trigger FastIo handlers back then. The assumptions was correct, NtDeviceIoControlFile used internally. Might be useful to someone. Sorry for the shitcode.

C:
#include <winternl.h>
#include <winsock2.h>
#include <MSWSock.h>
#include <windows.h>
#include <ntstatus.h>
#include <stdio.h>
//#include "common.h"
//#include <MSWSock.h>
//#include <mswsock.h>
#include <stdint.h>
//#include <WinSock2.h>
//#include <ws2def.h>

#define AFD_RIO_FAST_IOCTL 0x1211B
#define WSA_FLAG_REGISTERED_IO 0x100

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "ntdllp.lib")
#pragma warning(disable: "6011")

//
// Undocumented AFD structure
//

typedef struct __declspec(align(8)) AFD_RIO_REGISTER_BUFFER
{
    uint32_t RioType;
    uint32_t Field2;
    PVOID MdlBaseAddress;
    uint32_t MdlSize;
    uint32_t Field4;
}AFD_RIO_REGISTER_BUFFER;


typedef struct _FILE_IO_STATUS_INFORMATION {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} FILE_IO_STATUS_INFORMATION, *PFILE_IO_STATUS_INFORMATION;

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

const GUID WSAID_REGISTERED_IO = { 0x7d2903c2, 0x6290, 0x11cf, { 0xae, 0xd9, 0x0, 0x20, 0xaf, 0x6e, 0x72, 0x63 } };

GUID functionTableId = WSAID_MULTIPLE_RIO;
DWORD bytesReturned;
RIO_EXTENSION_FUNCTION_TABLE rioFunctions;

int main() {
    DWORD error = 0;
    HANDLE rioSocket;
    IO_STATUS_BLOCK ioStatus;
    FILE_IO_STATUS_INFORMATION fileIoStatus;
    ULONG ioctlCode = 0;

    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }

    rioSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_REGISTERED_IO);
    if (rioSocket == INVALID_SOCKET) {
        error = WSAGetLastError();
        return 1;
    }


    if (WSAIoctl(rioSocket,
                SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER,
                &functionTableId,
                sizeof(GUID),
                &rioFunctions,
                sizeof(RIO_EXTENSION_FUNCTION_TABLE),
                &bytesReturned,
                NULL,
                NULL) != NULL)
    {
        error = WSAGetLastError();
        closesocket(rioSocket);
        WSACleanup();
        free(&rioFunctions);
        return 1;
    }

    AFD_RIO_REGISTER_BUFFER *pData = malloc(0x18);

    if (pData)
    {

       /* We can change RioType to call different handlers, pseudocode of the AfdRioFastIo below
                if ( RioType == 4 )
                {
                    Cq = AfdRioRegisterBuffer(
                             (__int64)endp,
                             (AFD_RIO_REGISTER_BUFFER *)InputBuffer,
                             InBufLength,
                             (unsigned int *)OutputBuffer,
                             OutBuffLength,
                             AccessMode)
       */
        pData->RioType = 4;
        pData->MdlBaseAddress = 0;
        pData->MdlSize = 0x1000;
    }

    else
    {
        return -1;
    }
    /*
3: kd> k
 # Child-SP          RetAddr               Call Site
00 fffff60a`6ec4c358 fffff807`1a3e9bde     afd!AfdRioRegisterBuffer
01 fffff60a`6ec4c360 fffff807`1a3bdee8     afd!AfdRioFastIo+0x172
02 fffff60a`6ec4c450 fffff807`166c0f7e     afd!AfdFastIoDeviceControl+0x18508
03 fffff60a`6ec4c7f0 fffff807`166bf516     nt!IopXxxControlFile+0x46e
04 fffff60a`6ec4ca00 fffff807`1643d1e5     nt!NtDeviceIoControlFile+0x56
05 fffff60a`6ec4ca70 00007ff9`6cfceee4     nt!KiSystemServiceCopyEnd+0x25
06 000000f1`a4baf868 00007ff9`69855522     ntdll!NtDeviceIoControlFile+0x14
07 000000f1`a4baf870 00007ff6`f55311ca     mswsock!RIORegisterBuffer+0x92
08 000000f1`a4baf910 00000000`0000010c     riotest!main+0x15a
 */
    RIO_BUFFERID rioBufferId = rioFunctions.RIORegisterBuffer(&pData, sizeof(AFD_RIO_REGISTER_BUFFER));
    if (rioBufferId == RIO_INVALID_BUFFERID)
    {
        closesocket(rioSocket);
        WSACleanup();
        return 1;
    }

    rioFunctions.RIODeregisterBuffer(rioBufferId);

    closesocket(rioSocket);
    WSACleanup();

    return 0;
}
interesting+
slightly off topic --> RIO api himself is designed for such performance + small latency i/o completion mechanism --> but there is overhead to make such frequency calls --> FastIoDispatch handlers himself?
--> maybe we will batch such i/o requests?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
drpalpatine I don't know how suitable this interfaces to the high performance applications. My goal was to determine valid input buffer structure, API and sent some data to check things, which i did.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх