aka hernos
Süper Üye
NX bit flip ve Software Write bit flip bugünlerde belki bir meme olabilir fakat geçenlerde yaptığım analizler sonucu EAAC'nın EPROCESS deki mitigation flaglerine DisableDynamicCode eklemesi yüzümde bir gülümsemeye sebep oldu. Yıl 2024 saçma sapan çözümler bulmaya çalışıyolar
Azıcık beyni olan ve Windows Internal Bookdaki memory managament kısmını okuyan bir birey bile bunu nasıl atlatıcağını az çok bilir. Aşağıdakı paylaştığım kodda önce ntoskrnl de pte base adressimizi buluyoruz pattern scan yaparak sonra bu pte base addresimize bit shift operasyonları yaparak ilgili sanal addresin PTE sanal adresini buluyoruz ve asıl işlem burada başlıyor bu PTE nin bitlerini manipulate ederek keyfimize göre bir memory sayfasına read/write/execute access izinlerini verebiliyoruz. Bizzat denedim ve başarıyla çalıştı. VAD lerdeki protection flagleri bu yol ile güncellenmediği için herhangi bir Usermodedan memory sayfası hala izinler verilmemiş olarak gözükecektir aynı şekilde Anticheatde bunu göremicektir fakat memory sayfasına istediğiniz gibi manipulate edebilceksiniz. Bu arada PTE base adressimiz her boot time sırasında yer değiştirdiği için pattern scan ile almak zorunda kalıyoruz. Aşağıda paylaştığım kod pastelemeye hazırdır. Yakında bununla ilgili daha detaylı bir yazıyı kaleme alıp blog sayfamda paylaşıcağım takipde kalınız.İyi akşamlar herkese 
Blog sayfam;
Bağlantıları görmek için lütfen
Giriş Yap
C++:
typedef union _PTE
{
// Normally, emulating PAGE_NOACCESS means turning the valid bit off in the PTE
ULONG64 value;
// Bitfield in a struct
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0. (PAGE_NOACCESS) // bit 0
ULONG64 rw : 1; // written-before // bit 1
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 page_write : 1; // Determines the memory type used to access the memory.
ULONG64 page_cache : 1; // Determines the memory type used to access the memory.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 dirty : 1; // If 0, the memory backing this page has not been written to.
ULONG64 large_page : 1; // Large page
ULONG64 global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
ULONG64 cow : 1; // copy on write
ULONG64 prt : 1; // protetype
ULONG64 wrt : 1; // write-access
ULONG64 pfn : 36; // The page frame number of the backing physical page.
ULONG64 reserved : 4;
ULONG64 ignored3 : 7;
ULONG64 protect_key : 4; // If the PKE bit of CR4 is set, determines the protection key.
ULONG64 nx : 1; // If 1, instruction fetches not allowed.
};
} PTE, * PPTE;
auto fint_pte_base() -> uintptr_t {
auto ntoskrnl = utils::get_kernel_module("ntoskrnl.exe");
uintptr_t pte_base{ 0 };
if (ntoskrnl) {
printf("ntoskrnl base => 0x%p!", ntoskrnl);
auto sig_base = utils::pattern_scan(ntoskrnl, "\x48\xC1\xE9\x09\x48\xB8\xF8\xFF\xFF\xFF\x7F\x00\x00\x00\x48\x23\xC8\x48\xB8", "xxxxxxxxxxxxxxxxxxx");
if (sig_base)
{
pte_base = *(__int64*)(sig_base + 19);
printf("pte base found at => 0x%p!", pte_base);
}
else
{
printf("sig_base not found!");
}
}
else
{
printf("ntoskrnl not found!");
}
return pte_base;
}
auto resolve_pte_for_virtual(uintptr_t virtual_address) -> uintptr_t {
auto MiGetPteAddress = [](unsigned __int64 a1) -> unsigned __int64
{
unsigned __int64 pte_base = fint_pte_base();
return pte_base ? ((a1 >> 9) & 0x7FFFFFFFF8) + pte_base : 0;
};
return MiGetPteAddress(virtual_address);
}
NTSTATUS give_execute_access(uint32_t cid, uintptr_t virtual_address) {
PEPROCESS process = { 0 }; NTSTATUS status = STATUS_UNSUCCESSFUL;
PsLookupProcessByProcessId(HANDLE(cid), &process);
if (process != nullptr && virtual_address != 0)
{
unsigned __int64 pte_virtual = resolve_pte_for_virtual(virtual_address);
if (pte_virtual != 0)
{
printf("[+] pte_virtual => 0x%p", pte_virtual);
KAPC_STATE state = { 0 };
KeStackAttachProcess(process, &state);
unsigned __int64 bits = *(unsigned __int64*)pte_virtual;
PTE pte_new = { 0 };
pte_new.value = bits;
pte_new.nx = 0;
*(unsigned __int64*)pte_virtual = pte_new.value;
KeUnstackDetachProcess(&state);
status = STATUS_SUCCESS;
}
ObDereferenceObject(process);
}
return status;
}
NTSTATUS give_write_access(uint32_t cid, uintptr_t virtual_address) {
PEPROCESS process = { 0 }; NTSTATUS status = STATUS_UNSUCCESSFUL;
PsLookupProcessByProcessId(HANDLE(cid), &process);
if (process != nullptr && virtual_address != 0)
{
unsigned __int64 pte_virtual = resolve_pte_for_virtual(virtual_address);
if (pte_virtual != 0)
{
KAPC_STATE state = { 0 };
KeStackAttachProcess(process, &state);
unsigned __int64 bits = *(unsigned __int64*)pte_virtual;
PTE pte_new = { 0 };
pte_new.value = bits;
pte_new.wrt = 1;
*(unsigned __int64*)pte_virtual = pte_new.value;
KeUnstackDetachProcess(&state);
status = STATUS_SUCCESS;
}
ObDereferenceObject(process);
}
return status;
}
Son düzenleme: