читать на ядре 0 в Kernel Force

daniel S

New member
07.01.2024
3
0
BIT
31
это правильный подход?

C++:
volatile LONG PerformanceCounter = 0;
#define PERFORMANCE_AUTO_COUNT InterlockedIncrement(&PerformanceCounter);

static FORCEINLINE uint32_t CountBitsV(uint64_t Bits)
{
    return _mm_popcnt_u64(Bits);
}

class TSingleProcessorMode2
{
    volatile LONG Hub;
    KDPC DpcArray[MAXIMUM_PROCESSORS];
    static void DpcRoutine(KDPC* pDpc, void* pContext, void* pArg1, void* pArg2);
public:
    void Initialize();
    void Execute(void(__fastcall* Routine)(void*), void* pContext);
};



void TSingleProcessorMode2::Initialize()
{
    RtlZeroMemory(this, sizeof(TSingleProcessorMode2));
    if (KeQueryActiveProcessorCount(nullptr) > 1)
        for (int i = 0; i < MAXIMUM_PROCESSORS; i++)
        {
            KeInitializeDpc(&DpcArray[i], DpcRoutine, this);
            KeSetTargetProcessorDpc(&DpcArray[i], (CCHAR)i);
            KeSetImportanceDpc(&DpcArray[i], HighImportance);
        }
}

void TSingleProcessorMode2::DpcRoutine(KDPC* pDpc, void* pContext, void* pArg1, void* pArg2)
{
    TSingleProcessorMode2* pThis = (TSingleProcessorMode2*)pContext;


#if _WIN32_WINNT < 0x0502
    KeRaiseIrqlToSynchLevel();
#else
    //KIRQL DummyIrql;
    //KeRaiseIrql(12, &DummyIrql);
    KeRaiseIrqlToSynchLevel();
#endif


    while (true)
    {

        KIRQL DummyIrql;
        KeRaiseIrql(HIGH_LEVEL, &DummyIrql);
        _disable();
        LONG probe, level = InterlockedDecrement(&pThis->Hub) << 8;
        if (level == 0)
        {
            ((void(__fastcall*)(void*))pArg1)(pArg2);
            //DbgPrint("DPC executing on processor: %d\n", KeGetCurrentProcessorNumber());
            InterlockedExchange(&pThis->Hub, -1);
        exit:
            _enable();
            KeLowerIrql(DISPATCH_LEVEL);
            return;
        }

        do
        {
            PERFORMANCE_AUTO_COUNT;
            _mm_pause();
            probe = pThis->Hub;
            if (probe < 0)
                KeMemoryBarrier();
            goto exit;
        } while (probe == 0 || --level >= 0
            || InterlockedCompareExchange(&pThis->Hub, probe + 1, probe) != probe);
        KeLowerIrql(12);
        PERFORMANCE_AUTO_COUNT;
        _mm_pause();
    }
}


void TSingleProcessorMode2::Execute(void(__fastcall* pRoutine)(void*), void* pContext)
{
    KeEnterCriticalRegion();
    KeFlushQueuedDpcs();
    if (KeQueryActiveProcessorCount(nullptr) > 1)
    {
        KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
        KIRQL Irql;
        KeRaiseIrql(DISPATCH_LEVEL, &Irql);
        {
            Hub = CountBitsV(ActiveProcessors);
            unsigned long i;
            while (_BitScanReverse64(&i, ActiveProcessors))
            {
                do
                {
                    KAFFINITY Mask = 1ull << i;
                    if ((ActiveProcessors & Mask) != 0
                        && (i != KeGetCurrentProcessorNumber() || ActiveProcessors == Mask))
                    {
                        ActiveProcessors &= ~Mask;
                        KeInsertQueueDpc(&DpcArray[i], pRoutine, pContext);
                    }
                } while ((int)--i >= 0);
            }
        }
        KeLowerIrql(Irql);
    }
    else
    {
        KIRQL DummyIrqlx;
        KeRaiseIrql(HIGH_LEVEL, &DummyIrqlx);
        _disable();
        pRoutine(pContext);
        _enable();
        KeLowerIrql(DummyIrqlx);
    }
    KeFlushQueuedDpcs();
    KeLeaveCriticalRegion();
}



void __fastcall MyCallbackFunction(void* context)
{
 // код
}

void core0(){
    TSingleProcessorMode2 OK;
    OK.Initialize();
    OK.Execute(MyCallbackFunction, nullptr);
}
 

file_

Member
10.08.2024
5
0
BIT
63
Процессоры AMD подвержены проблеме SinkClose, атаки на которую почти невозможно обнаружить

Продукты компании AMD подвержены серьезной уязвимости SinkClose, которая затрагивает несколько поколений процессоров EPYC, Ryzen и Threadripper. Уязвимость позволяет злоумышленникам с привилегиями уровня ядра (Ring 0) получить привилегии Ring -2, что может использоваться для установки малвари, которую практически невозможно обнаружить.

. ru/2024/08/12/sinkclose/
 

Koloboking

Green Team
12.01.2017
166
52
BIT
849
это правильный подход?

C++:
volatile LONG PerformanceCounter = 0;
#define PERFORMANCE_AUTO_COUNT InterlockedIncrement(&PerformanceCounter);

static FORCEINLINE uint32_t CountBitsV(uint64_t Bits)
{
    return _mm_popcnt_u64(Bits);
}

class TSingleProcessorMode2
{
    volatile LONG Hub;
    KDPC DpcArray[MAXIMUM_PROCESSORS];
    static void DpcRoutine(KDPC* pDpc, void* pContext, void* pArg1, void* pArg2);
public:
    void Initialize();
    void Execute(void(__fastcall* Routine)(void*), void* pContext);
};



void TSingleProcessorMode2::Initialize()
{
    RtlZeroMemory(this, sizeof(TSingleProcessorMode2));
    if (KeQueryActiveProcessorCount(nullptr) > 1)
        for (int i = 0; i < MAXIMUM_PROCESSORS; i++)
        {
            KeInitializeDpc(&DpcArray[i], DpcRoutine, this);
            KeSetTargetProcessorDpc(&DpcArray[i], (CCHAR)i);
            KeSetImportanceDpc(&DpcArray[i], HighImportance);
        }
}

void TSingleProcessorMode2::DpcRoutine(KDPC* pDpc, void* pContext, void* pArg1, void* pArg2)
{
    TSingleProcessorMode2* pThis = (TSingleProcessorMode2*)pContext;


#if _WIN32_WINNT < 0x0502
    KeRaiseIrqlToSynchLevel();
#else
    //KIRQL DummyIrql;
    //KeRaiseIrql(12, &DummyIrql);
    KeRaiseIrqlToSynchLevel();
#endif


    while (true)
    {

        KIRQL DummyIrql;
        KeRaiseIrql(HIGH_LEVEL, &DummyIrql);
        _disable();
        LONG probe, level = InterlockedDecrement(&pThis->Hub) << 8;
        if (level == 0)
        {
            ((void(__fastcall*)(void*))pArg1)(pArg2);
            //DbgPrint("DPC executing on processor: %d\n", KeGetCurrentProcessorNumber());
            InterlockedExchange(&pThis->Hub, -1);
        exit:
            _enable();
            KeLowerIrql(DISPATCH_LEVEL);
            return;
        }

        do
        {
            PERFORMANCE_AUTO_COUNT;
            _mm_pause();
            probe = pThis->Hub;
            if (probe < 0)
                KeMemoryBarrier();
            goto exit;
        } while (probe == 0 || --level >= 0
            || InterlockedCompareExchange(&pThis->Hub, probe + 1, probe) != probe);
        KeLowerIrql(12);
        PERFORMANCE_AUTO_COUNT;
        _mm_pause();
    }
}


void TSingleProcessorMode2::Execute(void(__fastcall* pRoutine)(void*), void* pContext)
{
    KeEnterCriticalRegion();
    KeFlushQueuedDpcs();
    if (KeQueryActiveProcessorCount(nullptr) > 1)
    {
        KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
        KIRQL Irql;
        KeRaiseIrql(DISPATCH_LEVEL, &Irql);
        {
            Hub = CountBitsV(ActiveProcessors);
            unsigned long i;
            while (_BitScanReverse64(&i, ActiveProcessors))
            {
                do
                {
                    KAFFINITY Mask = 1ull << i;
                    if ((ActiveProcessors & Mask) != 0
                        && (i != KeGetCurrentProcessorNumber() || ActiveProcessors == Mask))
                    {
                        ActiveProcessors &= ~Mask;
                        KeInsertQueueDpc(&DpcArray[i], pRoutine, pContext);
                    }
                } while ((int)--i >= 0);
            }
        }
        KeLowerIrql(Irql);
    }
    else
    {
        KIRQL DummyIrqlx;
        KeRaiseIrql(HIGH_LEVEL, &DummyIrqlx);
        _disable();
        pRoutine(pContext);
        _enable();
        KeLowerIrql(DummyIrqlx);
    }
    KeFlushQueuedDpcs();
    KeLeaveCriticalRegion();
}



void __fastcall MyCallbackFunction(void* context)
{
 // код
}

void core0(){
    TSingleProcessorMode2 OK;
    OK.Initialize();
    OK.Execute(MyCallbackFunction, nullptr);
}
Ваш подход в целом является правильным, но я хотел бы отметить несколько моментов, которые могут быть улучшены или требуют уточнения в зависимости от вашего контекста и целей.

1. Инициализация структуры:
В вашем методе Initialize используется функция RtlZeroMemory, чтобы обнулить всю структуру. Это может быть опасным, так как вы можете случайно стереть данные, которые уже были инициализированы другими способами (например, если вы хотите сохранить значение переменной Hub). Если вам нужно обнулить только часть данных, рассмотрите инициализацию конкретных членов структуры.
2. Проверка количества процессоров:
Вы правильно проверяете количество активных процессоров с помощью KeQueryActiveProcessorCount. Если процессоров больше одного, вы инициализируете DPC для каждого процессора, что в целом правильно. Однако стоит отметить, что MAXIMUM_PROCESSORS — это максимум процессоров, поддерживаемых системой, и не всегда все из них активны. Убедитесь, что этот подход соответствует вашим целям.
3. Инициализация DPC:
Вы правильно инициализируете DPC и устанавливаете их целевые процессоры и важность. Однако, если количество активных процессоров меньше MAXIMUM_PROCESSORS, некоторые DPC будут инициализированы, но не будут никогда использоваться. Возможно, стоит инициализировать DPC только для активных процессоров.
4. Волатильность переменной Hub:
Переменная Hub объявлена как volatile LONG. Это указывает компилятору, что значение переменной может измениться в любой момент, и каждый доступ к ней должен быть реальным доступом к памяти. Если эта переменная используется для синхронизации между процессорами или ядрами, то возможно следует использовать атомарные операции, такие как InterlockedIncrement и InterlockedDecrement, чтобы избежать гонок данных.
5. Оптимизация вызова DpcRoutine:
Возможно, вы захотите использовать более эффективные механизмы синхронизации или распределения задач между процессорами, чтобы избежать накладных расходов, связанных с использованием DPC, особенно если ваше приложение высокопроизводительное.
6. Метод Execute:
Я не вижу реализации метода Execute, но предполагаю, что он используется для запуска переданной функции на каждом процессоре. Важно обеспечить правильную синхронизацию выполнения функции и предотвращение гонок
 

Koloboking

Green Team
12.01.2017
166
52
BIT
849
это правильный подход?

C++:
volatile LONG PerformanceCounter = 0;
#define PERFORMANCE_AUTO_COUNT InterlockedIncrement(&PerformanceCounter);

static FORCEINLINE uint32_t CountBitsV(uint64_t Bits)
{
    return _mm_popcnt_u64(Bits);
}

class TSingleProcessorMode2
{
    volatile LONG Hub;
    KDPC DpcArray[MAXIMUM_PROCESSORS];
    static void DpcRoutine(KDPC* pDpc, void* pContext, void* pArg1, void* pArg2);
public:
    void Initialize();
    void Execute(void(__fastcall* Routine)(void*), void* pContext);
};



void TSingleProcessorMode2::Initialize()
{
    RtlZeroMemory(this, sizeof(TSingleProcessorMode2));
    if (KeQueryActiveProcessorCount(nullptr) > 1)
        for (int i = 0; i < MAXIMUM_PROCESSORS; i++)
        {
            KeInitializeDpc(&DpcArray[i], DpcRoutine, this);
            KeSetTargetProcessorDpc(&DpcArray[i], (CCHAR)i);
            KeSetImportanceDpc(&DpcArray[i], HighImportance);
        }
}

void TSingleProcessorMode2::DpcRoutine(KDPC* pDpc, void* pContext, void* pArg1, void* pArg2)
{
    TSingleProcessorMode2* pThis = (TSingleProcessorMode2*)pContext;


#if _WIN32_WINNT < 0x0502
    KeRaiseIrqlToSynchLevel();
#else
    //KIRQL DummyIrql;
    //KeRaiseIrql(12, &DummyIrql);
    KeRaiseIrqlToSynchLevel();
#endif


    while (true)
    {

        KIRQL DummyIrql;
        KeRaiseIrql(HIGH_LEVEL, &DummyIrql);
        _disable();
        LONG probe, level = InterlockedDecrement(&pThis->Hub) << 8;
        if (level == 0)
        {
            ((void(__fastcall*)(void*))pArg1)(pArg2);
            //DbgPrint("DPC executing on processor: %d\n", KeGetCurrentProcessorNumber());
            InterlockedExchange(&pThis->Hub, -1);
        exit:
            _enable();
            KeLowerIrql(DISPATCH_LEVEL);
            return;
        }

        do
        {
            PERFORMANCE_AUTO_COUNT;
            _mm_pause();
            probe = pThis->Hub;
            if (probe < 0)
                KeMemoryBarrier();
            goto exit;
        } while (probe == 0 || --level >= 0
            || InterlockedCompareExchange(&pThis->Hub, probe + 1, probe) != probe);
        KeLowerIrql(12);
        PERFORMANCE_AUTO_COUNT;
        _mm_pause();
    }
}


void TSingleProcessorMode2::Execute(void(__fastcall* pRoutine)(void*), void* pContext)
{
    KeEnterCriticalRegion();
    KeFlushQueuedDpcs();
    if (KeQueryActiveProcessorCount(nullptr) > 1)
    {
        KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
        KIRQL Irql;
        KeRaiseIrql(DISPATCH_LEVEL, &Irql);
        {
            Hub = CountBitsV(ActiveProcessors);
            unsigned long i;
            while (_BitScanReverse64(&i, ActiveProcessors))
            {
                do
                {
                    KAFFINITY Mask = 1ull << i;
                    if ((ActiveProcessors & Mask) != 0
                        && (i != KeGetCurrentProcessorNumber() || ActiveProcessors == Mask))
                    {
                        ActiveProcessors &= ~Mask;
                        KeInsertQueueDpc(&DpcArray[i], pRoutine, pContext);
                    }
                } while ((int)--i >= 0);
            }
        }
        KeLowerIrql(Irql);
    }
    else
    {
        KIRQL DummyIrqlx;
        KeRaiseIrql(HIGH_LEVEL, &DummyIrqlx);
        _disable();
        pRoutine(pContext);
        _enable();
        KeLowerIrql(DummyIrqlx);
    }
    KeFlushQueuedDpcs();
    KeLeaveCriticalRegion();
}



void __fastcall MyCallbackFunction(void* context)
{
 // код
}

void core0(){
    TSingleProcessorMode2 OK;
    OK.Initialize();
    OK.Execute(MyCallbackFunction, nullptr);
}
Для того чтобы читать данные на ядре 0 в контексте ядра (Kernel), вам нужно задействовать механизм связывания выполнения к конкретному ядру. В вашей ситуации, если вы хотите, чтобы конкретный код выполнялся на ядре 0, можно использовать подход, описанный ниже:

Подход с использованием KeSetSystemAffinityThread:

Этот подход заставляет текущий поток выполняться только на ядре 0, выполняя необходимую задачу, после чего восстанавливается исходная привязка.

C++:
void ExecuteOnCore0(void(__fastcall* Routine)(void*), void* pContext)
{
    // Получаем текущую маску аффинности системы.
    KAFFINITY OriginalAffinity = KeSetSystemAffinityThread((KAFFINITY)1);

    // Выполняем вашу функцию на ядре 0
    Routine(pContext);

    // Восстанавливаем исходную аффинность потока
    KeRevertToUserAffinityThread();
}
 

daniel S

New member
07.01.2024
3
0
BIT
31
Для того чтобы читать данные на ядре 0 в контексте ядра (Kernel), вам нужно задействовать механизм связывания выполнения к конкретному ядру. В вашей ситуации, если вы хотите, чтобы конкретный код выполнялся на ядре 0, можно использовать подход, описанный ниже:

Подход с использованием KeSetSystemAffinityThread:

Этот подход заставляет текущий поток выполняться только на ядре 0, выполняя необходимую задачу, после чего восстанавливается исходная привязка.

C++:
void ExecuteOnCore0(void(__fastcall* Routine)(void*), void* pContext)
{
    // Получаем текущую маску аффинности системы.
    KAFFINITY OriginalAffinity = KeSetSystemAffinityThread((KAFFINITY)1);

    // Выполняем вашу функцию на ядре 0
    Routine(pContext);

    // Восстанавливаем исходную аффинность потока
    KeRevertToUserAffinityThread();
}
KeSetSystemAffinityThreadEx/KeSetSystemAffinityThread можно использовать только для установки аффинности вызывающего потока. Но я хочу установить аффинность произвольного потока, и вот как это исправить:
C++:
Status = RtlCreateUserThread(ProcessHandle, NULL, FALSE, 0, 0, 0, NULL, NULL, &targetThreadHandle, &cid);

if (NT_SUCCESS(Status)) {
    DbgPrint("Поток успешно создан: ProcessId=%p, ThreadId=%p\n", cid.UniqueProcess, cid.UniqueThread);

    // Установка идеального процессора потока
    ULONG IdealThreadProcessor = 0;
    Status = ZwSetInformationThread(targetThreadHandle, ThreadIdealProcessor, &IdealThreadProcessor, sizeof(IdealThreadProcessor));
    if (!NT_SUCCESS(Status)) {
        DbgPrint("Не удалось установить идеальный процессор: 0x%08X\n", Status);
    }

    // Установка аффинности процесса на ядро 0
    KAFFINITY ProcessAffinity = (1ull << 0);
    Status = ZwSetInformationProcess(ProcessHandle, ProcessAffinityMask, &ProcessAffinity, sizeof(ProcessAffinity));
    if (!NT_SUCCESS(Status)) {
        DbgPrint("Не удалось установить аффинность процесса: 0x%08X\n", Status);
    }

    // Установка аффинности потока на ядро 0
    KAFFINITY ThreadAffinity = (1ull << 0);
    Status = ZwSetInformationThread(targetThreadHandle, ThreadAffinityMask, &ThreadAffinity, sizeof(ThreadAffinity));
    if (!NT_SUCCESS(Status)) {
        DbgPrint("Не удалось установить аффинность потока: 0x%08X\n", Status);
    }

    // Печать номера процессора и идентификатора процесса
    DbgPrint("Поток работает на ядре: %d, ProcessId: %p\n", KeGetCurrentProcessorNumber(), cid.UniqueProcess);
}
 

Вложения

  • Screenshot_87.png
    Screenshot_87.png
    1,9 КБ · Просмотры: 73

daniel S

New member
07.01.2024
3
0
BIT
31
"Вот другой способ чтения на ядре 0 с использованием ZwCreateThreadEx:

C++:
HANDLE hThread = nullptr;
if (NT_SUCCESS(ZwCreateThreadEx(
    &hThread,
    THREAD_ALL_ACCESS,
    NULL,
    ProcessHandle,
    0,
    NULL,
    NULL,
    NULL,
    NULL, NULL, NULL)))
{
    ULONG IdealThreadProcessor = 0;
    ZwSetInformationThread(hThread, ThreadIdealProcessor, &IdealThreadProcessor, sizeof(IdealThreadProcessor));

    // Установить привязку процесса к ядру 0
    KAFFINITY ProcessAffinity = (1ull << 0);
    ZwSetInformationProcess(ProcessHandle, ProcessAffinityMask, &ProcessAffinity, sizeof(ProcessAffinity));
    
    // Установить привязку потока к ядру 0
    KAFFINITY ThreadAffinity = (1ull << 0);
    ZwSetInformationThread(hThread, ThreadAffinityMask, &ThreadAffinity, sizeof(ThreadAffinity));

    DbgPrint("Поток выполняется на ядре: %d\n", KeGetCurrentProcessorNumber());
    
    return STATUS_SUCCESS;
}
 

Вложения

  • Screenshot_88.png
    Screenshot_88.png
    3 КБ · Просмотры: 51
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!