Выделите страницу с привилегиями выполнения по произвольному в настоящее время неиспользуемому виртуальному адресу в драйвере ядра windows - PullRequest
1 голос
/ 22 марта 2020

Я пишу драйвер режима ядра (Windows 10 64-бит), где мне требуется выполнение кода по виртуальному адресу в виртуальном адресном пространстве другого драйвера, который в настоящее время не используется (MmIsAddressValid возвращает false).

Что я пробовал:

  1. вызов недокументированной функции ntoskrnl MiFillPteHierarchy. Эта функция возвращает 4 указателя, один из которых должен быть указателем на структуру PTE, которую мне нужно изменить, чтобы дать привилегии выполнения кода странице. Я обнаружил, что когда я обращаю внимание на эти указатели, я получаю ошибку сегментации страницы BSOD. Функция работает нормально, когда я даю ей адрес, для которого MmIsAddressValid возвращает true (что и следовало ожидать).

Функция MIFILLPTEHIERARCHY в ntoskrnl возвращает 4 виртуальных адреса, соответствующих PTE, PDE, PDPTE и PML4E (насколько мне известно). Вот функция sig, которую я имею:

typedef uint64_t(__fastcall* MIFILLPTEHIERARCHY)(void* virtualaddy, PTE_HIERARCHY* hierarchy);

Структура PTE_HIERARCHY выглядит следующим образом

struct PTE_HIERARCHY {
    PTE* pte;
    uint64_t* PDE;
    uint64_t* PDPTE;
    uint64_t* PML4E;
};

(единственная созданная мной структура PTE)

согласно инструкции INTEL, которую я читал https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.pdf Структура PTE выглядит следующим образом:

union PTE{

    uint64_t raw;

    struct {
        uint64_t present : 1; //Present; must be 1 to map a 4-KByte pag
        uint64_t read_write : 1; //Read/write; if 0, writes may not be allowed to the 4-KByte page referenced by this entry (see Section 4
        uint64_t user_supervisor : 1; //User/supervisor; if 0, user-mode accesses are not allowed to the 4-KByte page referenced by this entry (see Section 4.6)
        uint64_t PWT : 1; //Page-level write-through; indirectly determines the memory type used to access the 4-KByte page referenced by this entry (see Section 4.9.
        uint64_t PCD : 1; //Page-level cache disable; indirectly determines the memory type used to access the 4-KByte page referenced by this entry (see Section 4.9.2
        uint64_t accessed : 1; //Accessed; indicates whether software has accessed the 4-KByte page referenced by this entry (see Section 4.8
        uint64_t dirty : 1; //Dirty; indicates whether software has written to the 4-KByte page referenced by this entry (see Section 4.8)
        uint64_t PAT : 1; //Indirectly determines the memory type used to access the 4-KByte page referenced by this entry (see Section 4.9.2)
        uint64_t global : 1; //Global; if CR4.PGE = 1, determines whether the translation is global (see Section 4.10); ignored otherwis
        uint64_t ignored : 3;
        uint64_t physical_page_address : 36; //Physical address of the 4-KByte page referenced by this entry
        uint64_t reserved : 4;
        uint64_t ignored2 : 7;
        uint64_t protection_key : 4; //Protection key; if CR4.PKE = 1, determines the protection key of the page (see Section 4.6.2); ignored otherwise
        uint64_t xd : 1; //if IA32_EFER.NXE = 1, execute-disable (if 1, instruction fetches are not allowed from the 4-KByte page controlled by this entry; see Section 4.6); otherwise, reserved (must be 0
    }values;

};

Моя реализация:



//enumerate system modules
uint32_t buffersize=0;
PRTL_PROCESS_MODULES mods=nullptr;
            ZwQuerySystemInformation(SystemModuleInformation,0,buffersize,&buffersize);
mods = (PRTL_PROCESS_MODULES)ExAllocatePool(NonPagedPool, buffersize);
ZwQuerySystemInformation(SystemModuleInformation, mods, buffersize, &buffersize);

//using ACPI as an example
const char* drivername = "ACPI.sys";
for (uint32_t i = 0; i < mods->NumberOfModules; i++) {
    RTL_PROCESS_MODULE_INFORMATION mod = mods->Modules[i];
    char currentdriver[0x100] = { 0 };
    memcpy(&currentdriver[0], &mod.FullPathName[mod.OffsetToFileName], 8);
    if (!strcmp(currentdriver, drivername)) {
            imagebase = mod.ImageBase[i]
            imagesize=mod.size[i]

            break;
}
}

//I then find some unused virtual address in the drivers address space
//something like 
for imagebase < address < infinity (just find some address that is not valid
if(!MmIsAddressValid(address))
targetaddress= address
else
address++

//query MiFillPteHierarchy for PTE hierarchy
PTE_HIERARCHY hierarchy = {0};
MiFillPteHierarchy(targetaddress, &hierarchy);

hierarchy.PTE->values.present //BSOD here


//However if I have a virtual address where MmIsAddressValid returns true;
hierarchy.PTE->values.present //NO BSOD 

Моя идея состояла в том, чтобы получить структуру PTE и изменить ее так, чтобы у меня было выполнение кода привилегии и ОС / ЦП не перезаписывают эту область виртуальной памяти другой страницей.

MmMapLockedPagesSpecifyCache. Когда я использую этот метод, указатель возврата находится совсем рядом с целевым виртуальным адресом.

Это мой код, использующий этот метод

//where MmIsAddressValid(targetvirtualaddress)=false
void* pool = ExAllocatePool(NonPagedPool/PagePool(tried both),50);
memset(pool, 0, 50);
PMDL MDL = IoAllocateMdl(pool, 50, false, false, nullptr);
MmBuildMdlForNonPagedPool(MDL);
void* resultantaddress = MmMapLockedPagesSpecifyCache(MDL, KernelMode, MmNonCached, targetvirtualaddress, false, HighPagePriority);
//resultantaddress is nowhere near targetvirtualaddress

В идеале то, что я хотел бы:

MmIsAddressValid(targetaddress) returns false //windows can overwrite
//do something to page here
MmIsAddressValid(targetaddress) returns true //windows wont overwrite
//modify PTE to gain code execution privileges 

(Насколько мне известно, если MmIsAddressValid возвращает true, это означает, что windows знает, что виртуальный адрес используется, и не будет пытаться его перезаписать)

Я предполагаю, что мой вопрос Почему разыменование PTE / PDE для этого виртуального адреса, который не используется, приводит к BSOD (ошибка сегментации страницы)? И почему MmMapLockedPagesSpecifyCache не размещает страницу где-либо рядом с целевым адресом? И если оба эти метода не будут работать для моих целей, что я могу сделать?

...