WCharacter / RDTSC-KVM-Handler

my patches for linux kernel to spoof rdtsc and make vm exit undetected
221 stars 30 forks source link

Some improvements. #18

Open giuseppejaripappalardo opened 11 months ago

giuseppejaripappalardo commented 11 months ago

Hello, thanks for your nice work.

I would like to propose some fine tuning, up to you if bring or not:

static int handle_rdtsc(struct kvm_vcpu *vcpu) { // Static variables to keep track of the fake and previous TSC values static u64 rdtsc_fake = 0; static u64 rdtsc_prev = 0; // Static variable for the divisor, makes it easy to adjust the TSC rate static const u64 divisore = 16;

// Retrieve the real TSC value
u64 rdtsc_real = rdtsc();

// Check if this is the first run of the function
if (print_once) {
    printk("[handle_rdtsc] fake rdtsc vmx function is working\n");
    print_once = 0; // Ensure this block runs only once
    rdtsc_fake = rdtsc_real; // Initialize the fake TSC value
}

// Calculate the fake TSC value if not the first run
if (rdtsc_prev != 0 && rdtsc_real > rdtsc_prev) {
    u64 diff = rdtsc_real - rdtsc_prev;
    u64 fake_diff = diff / divisore; // Calculate the difference to be added to the fake TSC
    rdtsc_fake += fake_diff;
} else if (rdtsc_prev == 0) {
    // Handle the initial case where rdtsc_prev is zero
    rdtsc_fake = rdtsc_real;
}

// Prevent the fake TSC from regressing or exceeding the real TSC
if (rdtsc_fake < rdtsc_prev || rdtsc_fake > rdtsc_real) {
    rdtsc_fake = rdtsc_prev + (rdtsc_real - rdtsc_prev) / divisore;
}

// Update the previous TSC value
rdtsc_prev = rdtsc_real;

// Set the fake TSC value to the VM's CPU registers
vcpu->arch.regs[VCPU_REGS_RAX] = rdtsc_fake & -1u;
vcpu->arch.regs[VCPU_REGS_RDX] = (rdtsc_fake >> 32) & -1u;  

// Skip the emulated instruction and return
return skip_emulated_instruction(vcpu);

}

Regards, Jari

felikcat commented 1 month ago

This patch makes Windows 10 crash no matter what on 'IPI_WATCHDOG_TIMEOUT' on a i7 12700K. Screenshot_20240814

The unmodified patch works as intended with no BSOD.

I've done the following to make these patches work on kernel 6.9; in vmx.c:

        /*
     * Not used by KVM, but fully supported for nesting, i.e. are allowed in
     * vmcs12 and propagated to vmcs02 when set in vmcs12.
     */
    exec_control &= ~(CPU_BASED_USE_IO_BITMAPS |
              CPU_BASED_MONITOR_TRAP_FLAG |
              CPU_BASED_PAUSE_EXITING);

    // Ensure handle_rdtsc() is used.
    exec_control |= CPU_BASED_RDTSC_EXITING;

In vmx.h:

#define __KVM_REQUIRED_VMX_CPU_BASED_VM_EXEC_CONTROL            \
    (CPU_BASED_HLT_EXITING |                    \
     CPU_BASED_CR3_LOAD_EXITING |                   \
     CPU_BASED_CR3_STORE_EXITING |                  \
     CPU_BASED_UNCOND_IO_EXITING |                  \
     CPU_BASED_MOV_DR_EXITING |                 \
     CPU_BASED_USE_TSC_OFFSETTING |                 \
     CPU_BASED_MWAIT_EXITING |                  \
     CPU_BASED_MONITOR_EXITING |                    \
     CPU_BASED_INVLPG_EXITING |                 \
     CPU_BASED_RDPMC_EXITING |                  \
     CPU_BASED_RDTSC_EXITING |                                      \
     CPU_BASED_INTR_WINDOW_EXITING)