From c00940caf0d4ded76de9ec47b17130f9ee1c2970 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 7 Oct 2016 20:25:03 -0400 Subject: [PATCH] This is me trying to figure out how to change the %fs register on Linux. :) --- research/ldt.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 research/ldt.c diff --git a/research/ldt.c b/research/ldt.c new file mode 100644 index 0000000..2edc784 --- /dev/null +++ b/research/ldt.c @@ -0,0 +1,104 @@ +// "man modify_ldt" + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + struct user_desc ldt[8 * 1024]; + long rc; + + //rc = syscall(123, (int) 0, (void *) ldt, (unsigned long) sizeof (ldt)); + //printf("read syscall == %ld\n", rc); + + char *str = malloc(64); + strcpy(str, "hello world!"); + printf("&str == %p\n", str); + + unsigned int fs = 0xFFFFFFFF; + __asm__ __volatile__ ( + "xorl %%eax, %%eax \n\t" + "movw %%fs, %%ax \n\t" + : "=a" (fs) + ); + + printf("Current %%fs: 0x%X\n", fs); + + struct user_desc *entry = ldt; + entry->entry_number = -1; + entry->base_addr = (unsigned long) str; + entry->limit = 64; + entry->seg_32bit = 1; + entry->contents = MODIFY_LDT_CONTENTS_DATA; + entry->read_exec_only = 0; + entry->limit_in_pages = 0; + entry->seg_not_present = 0; + entry->useable = 1; + + printf("entry=%u, base=%p, limit=%u\n", entry->entry_number, (void *) entry->base_addr, entry->limit); + +// modify_ldt +// rc = syscall(SYS_modify_ldt, (int) 1, (void *) entry, (unsigned long) sizeof (*entry)); +// printf("write syscall == %ld\n", rc); + +// set_thread_area + rc = syscall(SYS_set_thread_area, entry); + printf("write syscall == %ld\n", rc); + + printf("entry==%d\n", (int) (entry->entry_number)); + +// this doesn't give you a user_desc struct back, I think it gives you the real LDT entry...? +// rc = syscall(SYS_modify_ldt, (int) 0, (void *) entry, (unsigned long) sizeof (*entry) * 128); +// printf("read syscall == %ld\n", rc); + +// long i; +// for (i = 0; i < 128; i++, entry++) +// printf("entry=%u, base=%p, limit=%u\n", entry->entry_number, (void *) entry->base_addr, entry->limit); + + // I have no idea why this needs the "<< 3 | 3", but it's probably + // specified in the Intel manuals. I got this from looking at how + // Wine does it. + __asm__ __volatile__ ( + //"pushw %%ax\n\t" + //"popw %%fs \n\t" + "movw %%ax,%%fs \n\t" + : + : "a" ((entry->entry_number << 3) | 3) + ); + + fs = 0xFFFFFFFF; + __asm__ __volatile__ ( + "xorl %%eax, %%eax \n\t" + "movw %%fs, %%ax \n\t" + : "=a" (fs) + ); + + printf("New %%fs: 0x%X\n", fs); + + char newstr[16]; + memset(newstr, '\0', sizeof (newstr)); + __asm__ __volatile__ ( + "movl %%fs:0,%%eax\n\t" + "movl %%eax,(%%edi)\n\t" + "movl %%fs:4,%%eax\n\t" + "movl %%eax,4(%%edi)\n\t" + "movl %%fs:8,%%eax\n\t" + "movl %%eax,8(%%edi)\n\t" + : + : "D" (newstr) + : "eax" + ); + + printf("copied string == '%s'\n", newstr); + + return 0; +} + +// end of ldt.c ... +