├── README.md ├── Troopers2015-Final-Presented-Public.pptx ├── cache ├── README ├── async_cache_memory │ ├── Makefile │ ├── lib.S │ └── main.c ├── disable_threads.sh └── no_fill_mode │ ├── Makefile │ ├── lib.S │ └── main.c ├── poc gtfo code ├── aes_ni_kernel.c ├── chipsec_msr_aes.patch ├── generate_ud.asm ├── is_aes_ni_enabled.c └── ud_hook.c ├── pocorgtfo07.pdf └── util ├── Makefile ├── README ├── lib.S └── main.c /README.md: -------------------------------------------------------------------------------- 1 | # Troopers2015 2 | Troopers Conference Supporting Materials 3 | -------------------------------------------------------------------------------- /Troopers2015-Final-Presented-Public.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrbranco/Troopers2015/339bac6aa0af318a17d5ce9bbeafd3f5739c6b7d/Troopers2015-Final-Presented-Public.pptx -------------------------------------------------------------------------------- /cache/README: -------------------------------------------------------------------------------- 1 | *********** 2 | * WARNING * 3 | *********** 4 | 5 | Most of the tests will crash your machine. So, do not execute these 6 | tests on production machines because, more than the crash, you may 7 | experience other effects such as loose some files due to filesystem 8 | crash. 9 | 10 | 11 | /* 12 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 13 | * 14 | * License: Beerware 15 | */ 16 | 17 | 18 | Before running any kernel module, make sure there is only 1 thread 19 | in execution. disable_threads.sh is a script that achieves that for 20 | a system with 8 threads. If your system has a different number of 21 | threads, please, change this script. 22 | 23 | 24 | 25 | async_cache_memory: 26 | - Proves CR3 does not use cache when PAE is being used 27 | - Creates an async between cache and memory on the PDPTEs 28 | - Invalidates the cache in a way that the PDPTEs changed 29 | in the cache are not written back to memory 30 | 31 | - make clean ; make ; insmod cache.ko ; rmmod cache 32 | 33 | 34 | 35 | no_fill_mode: 36 | - Shows behavior of no-fill mode 37 | - In the code (lib.S), there are comments to test two 38 | behaviors of no-fill mode: invd that does not invalidates 39 | the cache and the write-back that happens when leaving the 40 | no-fill mode. 41 | - This code can be modified in many other ways to test other 42 | characteristics of no-fill mode. 43 | 44 | - make clean ; make ; insmod cache.ko 45 | - This code crashes - this is exactly the idea of it :) 46 | -------------------------------------------------------------------------------- /cache/async_cache_memory/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += cache.o 2 | cache-objs := main.o lib.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 9 | -------------------------------------------------------------------------------- /cache/async_cache_memory/lib.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 3 | * 4 | * License: Beerware 5 | */ 6 | 7 | .intel_syntax noprefix 8 | 9 | .text 10 | 11 | .global get_cr3 12 | .global cache_trick 13 | 14 | get_cr3: 15 | mov eax,cr3 16 | ret 17 | 18 | cache_trick: 19 | pushad 20 | cli 21 | 22 | and eax, 0xFFFFFFE0 // zero ignored CR3 bits 23 | mov esi, eax // save cr3_virt addr at esi 24 | mov edi, edx // save cr3_phys addr at edi 25 | 26 | 27 | 28 | wbinvd 29 | 30 | // Cache all PDPT entries 31 | mov eax, esi 32 | mov ebx, [eax] 33 | mov ebx, [eax + 4] 34 | mov ebx, [eax + 8] 35 | mov ebx, [eax + 12] 36 | mov ebx, [eax + 16] 37 | mov ebx, [eax + 20] 38 | mov ebx, [eax + 24] 39 | mov ebx, [eax + 28] 40 | 41 | mov eax,esi // eax has now cr3_virt 42 | 43 | // Mark PDPTE 1 as not-present 44 | mov ecx, [eax] 45 | and ecx, 0xFFFFFFFE 46 | mov [eax], ecx 47 | 48 | // Mark PDPTE 2 as not-present 49 | mov ecx, [eax + 8] 50 | and ecx, 0xFFFFFFFE 51 | mov [eax + 8], ecx 52 | 53 | // Mark PDPTE 3 as not-present 54 | mov ecx, [eax + 16] 55 | and ecx, 0xFFFFFFFE 56 | mov [eax + 16], ecx 57 | 58 | // Mark PDPTE 4 as not-present 59 | mov ecx, [eax + 24] 60 | and ecx, 0xFFFFFFFE 61 | mov [eax + 24], ecx 62 | 63 | // Some random memory accesses 64 | nop 65 | mov ecx, 0x41414141 66 | mov edx, 0xc0002000 // 0xc0002000 virt = 0x00002000 phys 67 | mov [edx], ecx 68 | mov [edx+4], ecx 69 | mov [edx+8], ecx 70 | mov [edx+12], ecx 71 | mov [edx+16], ecx 72 | mov [edx+20], ecx 73 | mov [edx+24], ecx 74 | mov [edx+28], ecx 75 | mov [edx+32], ecx 76 | mov [edx+36], ecx 77 | mov [edx+40], ecx 78 | mov [edx+44], ecx 79 | mov [edx+48], ecx 80 | mov [edx+52], ecx 81 | mov ecx, [edx+56] 82 | mov ecx, [edx+60] 83 | mov ecx, [edx+64] 84 | mov ecx, [edx+68] 85 | mov ecx, [edx+72] 86 | mov ecx, [edx+76] 87 | mov ecx, [edx+80] 88 | mov ecx, [edx+84] 89 | mov ecx, [edx+88] 90 | mov ecx, [edx+92] 91 | nop 92 | 93 | invd // Invalidates the cache 94 | 95 | sti 96 | popad 97 | 98 | mov eax,0xAABBCCDD // return value just to make sure we reached the end of the code 99 | 100 | ret 101 | -------------------------------------------------------------------------------- /cache/async_cache_memory/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 3 | * 4 | * License: Beerware 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | unsigned int get_cr3(void); 12 | unsigned int cache_trick(unsigned int addr_virt, unsigned int addr_phys); 13 | 14 | int init_module(void) { 15 | unsigned int cr3_phys, cr3_virt; 16 | unsigned int retval, i; 17 | unsigned int *ptr; 18 | 19 | cr3_phys = get_cr3(); 20 | printk(KERN_ALERT "cr3 phys = 0x%x\n", cr3_phys); 21 | 22 | cr3_virt = (unsigned int)phys_to_virt(cr3_phys); 23 | printk(KERN_ALERT "cr3 virt = 0x%x\n", cr3_virt); 24 | 25 | retval = cache_trick(cr3_virt, cr3_phys); 26 | 27 | // Just a loop to access some random addresses 28 | ptr = (unsigned int *)0xc0004000; // virtual address of 0x4000 29 | for (i = 0; i < 1000; i++) { 30 | *ptr = i; 31 | printk(KERN_ALERT "%u\n", *ptr); 32 | ptr++; 33 | } 34 | 35 | // If 0xaabbccdd is printed here, then only_nem() executed until the end 36 | printk(KERN_ALERT "retval = %x\n", retval); 37 | 38 | return 0; 39 | } 40 | 41 | void cleanup_module(void) { 42 | printk( "cleanup\n"); 43 | } 44 | -------------------------------------------------------------------------------- /cache/disable_threads.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Let only 1 CPU thread to be online 4 | echo 0 > /sys/devices/system/cpu/cpu7/online 5 | echo 0 > /sys/devices/system/cpu/cpu6/online 6 | echo 0 > /sys/devices/system/cpu/cpu5/online 7 | echo 0 > /sys/devices/system/cpu/cpu4/online 8 | echo 0 > /sys/devices/system/cpu/cpu3/online 9 | echo 0 > /sys/devices/system/cpu/cpu2/online 10 | echo 0 > /sys/devices/system/cpu/cpu1/online 11 | 12 | # Show the result 13 | cat /proc/cpuinfo 14 | -------------------------------------------------------------------------------- /cache/no_fill_mode/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += cache.o 2 | cache-objs := main.o lib.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 9 | -------------------------------------------------------------------------------- /cache/no_fill_mode/lib.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 3 | * 4 | * License: Beerware 5 | */ 6 | 7 | .intel_syntax noprefix 8 | 9 | .text 10 | 11 | .global get_cr3 12 | .global cache_trick 13 | 14 | get_cr3: 15 | mov eax,cr3 16 | ret 17 | 18 | cache_trick: 19 | pushad 20 | cli 21 | 22 | and eax, 0xFFFFFFE0 // zero ignored CR3 bits 23 | mov esi, eax // save cr3_virt addr at esi 24 | mov edi, edx // save cr3_phys addr at edi 25 | 26 | 27 | 28 | wbinvd 29 | 30 | // Cache all PDPT entries 31 | mov eax, esi 32 | mov ebx, [eax] 33 | mov ebx, [eax + 4] 34 | mov ebx, [eax + 8] 35 | mov ebx, [eax + 12] 36 | mov ebx, [eax + 16] 37 | mov ebx, [eax + 20] 38 | mov ebx, [eax + 24] 39 | mov ebx, [eax + 28] 40 | 41 | 42 | 43 | // Enter no-fill mode 44 | mov eax, cr0 45 | or eax, 0x40000000 46 | mov cr0, eax 47 | 48 | 49 | 50 | mov eax,esi // eax has now cr3_virt 51 | 52 | // Mark PDPTE 1 as not-present 53 | mov ecx, [eax] 54 | and ecx, 0xFFFFFFFE 55 | mov [eax], ecx 56 | 57 | // Mark PDPTE 2 as not-present 58 | mov ecx, [eax + 8] 59 | and ecx, 0xFFFFFFFE 60 | mov [eax + 8], ecx 61 | 62 | // Mark PDPTE 3 as not-present 63 | mov ecx, [eax + 16] 64 | and ecx, 0xFFFFFFFE 65 | mov [eax + 16], ecx 66 | 67 | // Mark PDPTE 4 as not-present 68 | mov ecx, [eax + 24] 69 | and ecx, 0xFFFFFFFE 70 | mov [eax + 24], ecx 71 | 72 | // Some random memory accesses 73 | nop 74 | mov ecx, 0x41414141 75 | mov edx, 0xc0002000 // 0xc0002000 virt = 0x00002000 phys 76 | mov [edx], ecx 77 | mov [edx+4], ecx 78 | mov [edx+8], ecx 79 | mov [edx+12], ecx 80 | mov [edx+16], ecx 81 | mov [edx+20], ecx 82 | mov [edx+24], ecx 83 | mov [edx+28], ecx 84 | mov [edx+32], ecx 85 | mov [edx+36], ecx 86 | mov [edx+40], ecx 87 | mov [edx+44], ecx 88 | mov [edx+48], ecx 89 | mov [edx+52], ecx 90 | mov ecx, [edx+56] 91 | mov ecx, [edx+60] 92 | mov ecx, [edx+64] 93 | mov ecx, [edx+68] 94 | mov ecx, [edx+72] 95 | mov ecx, [edx+76] 96 | mov ecx, [edx+80] 97 | mov ecx, [edx+84] 98 | mov ecx, [edx+88] 99 | mov ecx, [edx+92] 100 | nop 101 | 102 | 103 | 104 | /* 105 | * Commented Code 1 106 | * 107 | * "Invalidates" the cache with invd and wait some time for it to complete. 108 | * Outside of no-fill mode, cache is invalidated. Inside no-fill mode (the case here) 109 | * no invalidation will happen - thus, there will be a crash due to write-back performed 110 | * after leaving no-fill mode. 111 | * 112 | * To test this behavior, uncomment the following cpde and make sure 113 | * the "Commented Code 2" is commented. 114 | */ 115 | 116 | /* 117 | invd // "Invalidates" the cache 118 | 119 | mov ecx, 70000000 120 | mov edx, 0xc0002000 121 | teste: 122 | mov eax, [edx+100] 123 | add eax, 100 124 | loop teste 125 | */ 126 | 127 | 128 | 129 | // Back to normal cache mode 130 | mov eax, cr0 131 | and eax, 0xBFFFFFFF 132 | mov cr0, eax 133 | 134 | 135 | 136 | /* 137 | * Commented Code 2 138 | * 139 | * Mark the PDPTEs as "present". There will be a cache 140 | * write-back before this code because the no-fill mode ended. 141 | * 142 | * To test this behavior, uncomment the following code and make sure 143 | * the "Commented Code 1" is commented. 144 | */ 145 | 146 | mov eax,esi // eax has now cr3_virt 147 | 148 | // Mark PDPTE 1 as present 149 | mov ecx, [eax] 150 | or ecx, 0x00000001 151 | mov [eax], ecx 152 | 153 | // Mark PDPTE 2 as present 154 | mov ecx, [eax + 8] 155 | or ecx, 0x00000001 156 | mov [eax + 8], ecx 157 | 158 | // Mark PDPTE 3 as present 159 | mov ecx, [eax + 16] 160 | or ecx, 0x00000001 161 | mov [eax + 16], ecx 162 | 163 | // Mark PDPTE 4 as present 164 | mov ecx, [eax + 24] 165 | or ecx, 0x00000001 166 | mov [eax + 24], ecx 167 | 168 | 169 | 170 | sti 171 | popad 172 | 173 | mov eax,0xAABBCCDD // return value just to make sure we reached the end of the code 174 | 175 | ret 176 | -------------------------------------------------------------------------------- /cache/no_fill_mode/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 3 | * 4 | * License: Beerware 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | unsigned int get_cr3(void); 12 | unsigned int cache_trick(unsigned int addr_virt, unsigned int addr_phys); 13 | 14 | int init_module(void) { 15 | unsigned int cr3_phys, cr3_virt; 16 | unsigned int retval, i; 17 | unsigned int *ptr; 18 | 19 | cr3_phys = get_cr3(); 20 | printk(KERN_ALERT "cr3 phys = 0x%x\n", cr3_phys); 21 | 22 | cr3_virt = (unsigned int)phys_to_virt(cr3_phys); 23 | printk(KERN_ALERT "cr3 virt = 0x%x\n", cr3_virt); 24 | 25 | retval = cache_trick(cr3_virt, cr3_phys); 26 | 27 | // Just a loop to access some random addresses 28 | ptr = (unsigned int *)0xc0004000; // virtual address of 0x4000 29 | for (i = 0; i < 1000; i++) { 30 | *ptr = i; 31 | printk(KERN_ALERT "%u\n", *ptr); 32 | ptr++; 33 | } 34 | 35 | // If 0xaabbccdd is printed here, then only_nem() executed until the end 36 | printk(KERN_ALERT "retval = %x\n", retval); 37 | 38 | return 0; 39 | } 40 | 41 | void cleanup_module(void) { 42 | printk( "cleanup\n"); 43 | } 44 | -------------------------------------------------------------------------------- /poc gtfo code/aes_ni_kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "include/rop.h" 11 | #include 12 | 13 | #define _GNU_SOURCE 14 | 15 | #define FEATURE_CONFIG_MSR 0x13c 16 | 17 | MODULE_LICENSE("GPL"); 18 | 19 | #define MASK_LOCK_SET 0x00000001 20 | #define MASK_AES_ENABLED 0x00000002 21 | #define MASK_SET_LOCK 0x00000000 22 | 23 | void * read_msr_in_c(void * CPUInfo) 24 | { 25 | int *pointer; 26 | pointer=(int *) CPUInfo; 27 | asm volatile("rdmsr" : "=a"(pointer[0]), "=d"(pointer[3]) : "c"(FEATURE_CONFIG_MSR)); 28 | return NULL; 29 | } 30 | 31 | int __init 32 | init_module (void) 33 | { 34 | int CPUInfo[4]={-1}; 35 | 36 | printk(KERN_ALERT "AES-NI testing module\n"); 37 | 38 | read_msr_in_c(CPUInfo); 39 | 40 | printk(KERN_ALERT "read: %d %d from MSR: 0x%x \n", CPUInfo[0], CPUInfo[3], FEATURE_CONFIG_MSR); 41 | 42 | if (CPUInfo[0] & MASK_LOCK_SET) 43 | printk(KERN_ALERT "MSR: lock bit is set\n"); 44 | 45 | if (!(CPUInfo[0] & MASK_AES_ENABLED)) 46 | printk(KERN_ALERT "MSR: AES_DISABLED bit is NOT set - AES-NI is ENABLED\n"); 47 | 48 | return 0; 49 | } 50 | 51 | void __exit 52 | cleanup_module (void) 53 | { 54 | printk(KERN_ALERT "AES-NI MSR unloading \n"); 55 | } -------------------------------------------------------------------------------- /poc gtfo code/chipsec_msr_aes.patch: -------------------------------------------------------------------------------- 1 | diff -rNup chipsec-master/source/tool/chipsec/cfg/hsw.xml chipsec-master.new/source/tool/chipsec/cfg/hsw.xml 2 | --- chipsec-master/source/tool/chipsec/cfg/hsw.xml 2015-01-23 16:07:19.000000000 -0800 3 | +++ chipsec-master.new/source/tool/chipsec/cfg/hsw.xml 2015-03-09 19:13:55.949498250 -0700 4 | @@ -39,6 +39,10 @@ 5 | 6 | 7 | 8 | + 9 | + 10 | + 11 | + 12 | 13 | 14 | - 15 | \ No newline at end of file 16 | + 17 | diff -rNup chipsec-master/source/tool/chipsec/modules/hsw/aes_ni.py chipsec-master.new/source/tool/chipsec/modules/hsw/aes_ni.py 18 | --- chipsec-master/source/tool/chipsec/modules/hsw/aes_ni.py 1969-12-31 16:00:00.000000000 -0800 19 | +++ chipsec-master.new/source/tool/chipsec/modules/hsw/aes_ni.py 2015-03-09 19:22:12.693518998 -0700 20 | @@ -0,0 +1,68 @@ 21 | +#CHIPSEC: Platform Security Assessment Framework 22 | +#Copyright (c) 2010-2015, Intel Corporation 23 | +# 24 | +#This program is free software; you can redistribute it and/or 25 | +#modify it under the terms of the GNU General Public License 26 | +#as published by the Free Software Foundation; Version 2. 27 | +# 28 | +#This program is distributed in the hope that it will be useful, 29 | +#but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | +#GNU General Public License for more details. 32 | +# 33 | +#You should have received a copy of the GNU General Public License 34 | +#along with this program; if not, write to the Free Software 35 | +#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 36 | +# 37 | +#Contact information: 38 | +#chipsec@intel.com 39 | +# 40 | + 41 | + 42 | + 43 | + 44 | +## \addtogroup modules 45 | +# __chipsec/modules/hsw/aes_ni.py__ - checks for AES-NI lock 46 | +# 47 | + 48 | + 49 | +from chipsec.module_common import * 50 | +from chipsec.hal.msr import * 51 | + 52 | +TAGS = [MTAG_BIOS,MTAG_HWCONFIG] 53 | + 54 | +class aes_ni(BaseModule): 55 | + 56 | + def __init__(self): 57 | + BaseModule.__init__(self) 58 | + 59 | + def is_supported(self): 60 | + return True 61 | + 62 | + def check_aes_ni_supported(self): 63 | + return True 64 | + 65 | + def check_aes_ni(self): 66 | + self.logger.start_test( "Checking if AES-NI lock bit is set" ) 67 | + 68 | + aes_msr = chipsec.chipset.read_register( self.cs, 'IA32_AES_NI' ) 69 | + chipsec.chipset.print_register( self.cs, 'IA32_AES_NI', aes_msr ) 70 | + 71 | + aes_msr_lock = aes_msr & 0x1 72 | + 73 | + # We don't really care if it is enabled or not since the software needs to 74 | + # test - the only security issue is if it is not locked 75 | + aes_msr_disable = aes_msr & 0x2 76 | + 77 | + # Check if the lock is not set, then ERROR 78 | + if (not aes_msr_lock): 79 | + return False 80 | + 81 | + return True 82 | + 83 | + # -------------------------------------------------------------------------- 84 | + # run( module_argv ) 85 | + # Required function: run here all tests from this module 86 | + # -------------------------------------------------------------------------- 87 | + def run( self, module_argv ): 88 | + return self.check_aes_ni() 89 | -------------------------------------------------------------------------------- /poc gtfo code/generate_ud.asm: -------------------------------------------------------------------------------- 1 | Section .text 2 | 3 | global _start 4 | 5 | _start: 6 | mov ebx, 0 7 | mov eax, 1 8 | aesenc xmm7, xmm1 9 | int 0x80 -------------------------------------------------------------------------------- /poc gtfo code/is_aes_ni_enabled.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define cpuid(level, a, b, c, d) \ 4 | asm("xchg{l}\t{%%}ebx, %1\n\t" \ 5 | "cpuid\n\t" \ 6 | "xchg{l}\t{%%}ebx, %1\n\t" \ 7 | : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ 8 | : "0" (level)) 9 | 10 | int main (int argc, char **argv) { 11 | unsigned int eax, ebx, ecx, edx; 12 | cpuid(1, eax, ebx, ecx, edx); 13 | if (ecx & (1<<25)) 14 | printf("AES-NI Enabled\n"); 15 | else 16 | printf("AES-NI Disabled\n"); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /poc gtfo code/ud_hook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int index = 0; 5 | module_param(index, int, 0); 6 | 7 | #define GET_FULL_ISR(low, high) ( ((uint32_t)(low)) | (((uint32_t)(high)) << 16) ) 8 | #define GET_LOW_ISR(addr) ( (uint16_t)(((uint32_t)(addr)) & 0x0000FFFF) ) 9 | #define GET_HIGH_ISR(addr) ( (uint16_t)(((uint32_t)(addr)) >> 16) ) 10 | 11 | uint32_t original_handlers[256]; 12 | 13 | uint16_t old_gs, old_fs, old_es, old_ds; 14 | 15 | typedef struct _idt_gate_desc { 16 | uint16_t offset_low; 17 | uint16_t segment_selector; 18 | uint8_t zero; // zero + reserved 19 | uint8_t flags; 20 | uint16_t offset_high; 21 | } idt_gate_desc_t; 22 | idt_gate_desc_t *gates[256]; 23 | 24 | void handler_implemented(void) { 25 | printk(KERN_EMERG "IDT Hooked Handler\n"); 26 | } 27 | 28 | void foo(void) { 29 | __asm__("push %eax"); // placeholder for original handler 30 | 31 | __asm__("pushw %gs"); 32 | __asm__("pushw %fs"); 33 | __asm__("pushw %es"); 34 | __asm__("pushw %ds"); 35 | __asm__("push %eax"); 36 | __asm__("push %ebp"); 37 | __asm__("push %edi"); 38 | __asm__("push %esi"); 39 | __asm__("push %edx"); 40 | __asm__("push %ecx"); 41 | __asm__("push %ebx"); 42 | 43 | __asm__("movw %0, %%ds" : : "m"(old_ds)); 44 | __asm__("movw %0, %%es" : : "m"(old_es)); 45 | __asm__("movw %0, %%fs" : : "m"(old_fs)); 46 | __asm__("movw %0, %%gs" : : "m"(old_gs)); 47 | 48 | handler_implemented(); 49 | 50 | // place original handler in its placeholder 51 | __asm__("mov %0, %%eax": : "m"(original_handlers[index])); 52 | __asm__("mov %eax, 0x24(%esp)"); 53 | 54 | __asm__("pop %ebx"); 55 | __asm__("pop %ecx"); 56 | __asm__("pop %edx"); 57 | __asm__("pop %esi"); 58 | __asm__("pop %edi"); 59 | __asm__("pop %ebp"); 60 | __asm__("pop %eax"); 61 | __asm__("popw %ds"); 62 | __asm__("popw %es"); 63 | __asm__("popw %fs"); 64 | __asm__("popw %gs"); 65 | 66 | // ensures that "ret" will be the next instruction for the case 67 | // compiler adds more instructions in the epilogue 68 | __asm__("ret"); 69 | } 70 | 71 | int init_module(void) { 72 | // IDTR 73 | unsigned char idtr[6]; 74 | uint16_t idt_limit; 75 | uint32_t idt_base_addr; 76 | 77 | int i; 78 | 79 | __asm__("mov %%gs, %0": "=m"(old_gs)); 80 | __asm__("mov %%fs, %0": "=m"(old_fs)); 81 | __asm__("mov %%es, %0": "=m"(old_es)); 82 | __asm__("mov %%ds, %0": "=m"(old_ds)); 83 | 84 | __asm__("sidt %0": "=m" (idtr)); 85 | idt_limit = *((uint16_t *)idtr); 86 | idt_base_addr = *((uint32_t *)&idtr[2]); 87 | printk("IDT Base Address: 0x%x, IDT Limit: 0x%x\n", idt_base_addr, idt_limit); 88 | 89 | gates[0] = (idt_gate_desc_t *)(idt_base_addr); 90 | for (i = 1; i < 256; i++) 91 | gates[i] = gates[i - 1] + 1; 92 | 93 | printk("int %d entry addr %x, seg sel %x, flags %x, offset %x\n", index, gates[index], (uint32_t)gates[index]->segment_selector, (uint32_t)gates[index]->flags, GET_FULL_ISR(gates[index]->of 94 | fset_low, gates[index]->offset_high)); 95 | 96 | for (i = 0; i < 256; i++) 97 | original_handlers[i] = GET_FULL_ISR(gates[i]->offset_low, gates[i]->offset_high); 98 | 99 | gates[index]->offset_low = GET_LOW_ISR(&foo); 100 | gates[index]->offset_high = GET_HIGH_ISR(&foo); 101 | 102 | return 0; 103 | } 104 | 105 | void cleanup_module(void) { 106 | printk("cleanup entry %d\n", index); 107 | 108 | gates[index]->offset_low = GET_LOW_ISR(original_handlers[index]); 109 | gates[index]->offset_high = GET_HIGH_ISR(original_handlers[index]); 110 | } -------------------------------------------------------------------------------- /pocorgtfo07.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrbranco/Troopers2015/339bac6aa0af318a17d5ce9bbeafd3f5739c6b7d/pocorgtfo07.pdf -------------------------------------------------------------------------------- /util/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += util.o 2 | util-objs := main.o lib.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 9 | -------------------------------------------------------------------------------- /util/README: -------------------------------------------------------------------------------- 1 | *********** 2 | * WARNING * 3 | *********** 4 | 5 | This is a proof-of-concept code. Do not run it in production machines! 6 | 7 | 8 | /* 9 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 10 | * 11 | * License: Beerware 12 | */ 13 | 14 | 15 | This module dumps both, PAE structure of a given virtual address and MTRR information of the system. 16 | 17 | make clean ; make ; insmod util.ko ; rmmod util 18 | -------------------------------------------------------------------------------- /util/lib.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 3 | * 4 | * License: Beerware 5 | */ 6 | 7 | .intel_syntax noprefix 8 | 9 | .text 10 | 11 | .global get_cr3 12 | .global cpuid_mtrr 13 | .global ia32_mtrrcap_msr 14 | .global ia32_mtrr_def_type 15 | .global generic_rdmsr_high 16 | .global generic_rdmsr_low 17 | .global cpuid_phys_addr_size 18 | 19 | get_cr3: 20 | mov eax,cr3 21 | ret 22 | 23 | cpuid_mtrr: 24 | push ebx 25 | push ecx 26 | push edx 27 | 28 | mov eax, 0x1 29 | mov edx, 0x0 30 | cpuid 31 | 32 | mov eax, edx 33 | 34 | pop edx 35 | pop ecx 36 | pop ebx 37 | 38 | ret 39 | 40 | ia32_mtrrcap_msr: 41 | push ecx 42 | push edx 43 | 44 | mov eax,0 45 | mov ecx,0xFE 46 | rdmsr 47 | 48 | pop edx 49 | pop ecx 50 | 51 | ret 52 | 53 | ia32_mtrr_def_type: 54 | push ecx 55 | push edx 56 | 57 | mov eax,0 58 | mov ecx,0x2FF 59 | rdmsr 60 | 61 | pop edx 62 | pop ecx 63 | 64 | ret 65 | 66 | generic_rdmsr_high: 67 | push ecx 68 | push edx 69 | 70 | mov ecx, eax 71 | mov eax, 0x0 72 | mov edx, 0x0 73 | rdmsr 74 | 75 | mov eax, edx 76 | 77 | pop edx 78 | pop ecx 79 | 80 | ret 81 | 82 | generic_rdmsr_low: 83 | push ecx 84 | push edx 85 | 86 | mov ecx, eax 87 | mov eax, 0x0 88 | mov edx, 0x0 89 | rdmsr 90 | 91 | pop edx 92 | pop ecx 93 | 94 | ret 95 | 96 | cpuid_phys_addr_size: 97 | push ebx 98 | push ecx 99 | push edx 100 | 101 | mov eax, 0x80000008 102 | cpuid 103 | 104 | pop edx 105 | pop ecx 106 | pop ebx 107 | 108 | ret 109 | -------------------------------------------------------------------------------- /util/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Developed by Gabriel Negreira Barbosa (pirata) and Rodrigo Rubira Branco (BSDaemon) 3 | * 4 | * License: Beerware 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | unsigned int get_cr3(void); 12 | unsigned int cpuid_mtrr(void); 13 | unsigned int ia32_mtrrcap_msr(void); 14 | unsigned int ia32_mtrr_def_type(void); 15 | unsigned int generic_rdmsr_high(unsigned int msr); 16 | unsigned int generic_rdmsr_low(unsigned int msr); 17 | unsigned int cpuid_phys_addr_size(void); 18 | 19 | void print_pae_structure(unsigned int virt_addr) { 20 | unsigned int cr3_phys, cr3_virt; 21 | unsigned int *pdpte, *pde, *pte; 22 | unsigned int i; 23 | 24 | printk(KERN_ALERT "Getting PAE structure for the address 0x%x\n", virt_addr); 25 | 26 | cr3_phys = get_cr3(); 27 | printk(KERN_ALERT "CR3 (physical address): 0x%x\n", cr3_phys); 28 | 29 | cr3_virt = (unsigned int)phys_to_virt(cr3_phys); 30 | printk(KERN_ALERT "CR3 (virtual address): 0x%x\n", cr3_virt); 31 | 32 | // Get PDPTE 33 | pdpte = (unsigned int *) cr3_virt; 34 | i = virt_addr >> 30; 35 | pdpte += i * 2; 36 | printk(KERN_ALERT "PDPTE - PDPT Index: %d: 0x%x%x\n", i, *(pdpte+1), *pdpte); 37 | 38 | // Get PDE 39 | pde = (unsigned int *) (phys_to_virt( (*pdpte & 0xFFFFF000) ) ); 40 | i = virt_addr & 0x3FFFFFFF; 41 | i = i >> 21; 42 | pde += i * 2; 43 | printk(KERN_ALERT "PDE - PD Index: %d: 0x%x%x\n", i, *(pde+1), *pde); 44 | 45 | // Geet PTE 46 | pte = (unsigned int *) (phys_to_virt( (*pde & 0x7FFFF000) ) ); 47 | i = virt_addr & 0x001FFFFF; 48 | i = i >> 12; 49 | pte += i * 2; 50 | printk(KERN_ALERT "PTE - PT Index: %d: 0x%x%x\n", i, *(pte+1), *pte); 51 | } 52 | 53 | void print_mtrr_info(void) { 54 | unsigned int retval, i, n_var_mtrr; 55 | 56 | retval = cpuid_mtrr(); 57 | printk(KERN_ALERT "CPUID.0x1.EDX: 0x%x\n", retval); 58 | if ((retval & 0x00001000) != 0) 59 | printk(KERN_ALERT " Bit 12 (MTRR) is set\n"); 60 | 61 | retval = ia32_mtrrcap_msr(); 62 | printk(KERN_ALERT "IA32_MTRRCAP MSR (low 32-bit): 0x%x\n", retval); 63 | printk(KERN_ALERT " Number of variable range registers: %u\n", (n_var_mtrr = retval & 0x000000FF)); 64 | printk(KERN_ALERT " Fixed range registers supported (boolean): %u\n", ((retval & 0x00000100) >> 8)); 65 | printk(KERN_ALERT " Write-combining memory type supported (boolean): %u\n", ((retval & 0x00000400) >> 10)); 66 | printk(KERN_ALERT " SMRR interface supported (boolean): %u\n", ((retval & 0x00000800) >> 11)); 67 | 68 | printk(KERN_ALERT "IA32_MTRR_DEF_TYPE MSR: 0x%x\n", ia32_mtrr_def_type()); 69 | 70 | printk(KERN_ALERT "IA32_MTRR_FIX64K_00000 MSR: 0x%x%x\n", generic_rdmsr_high(0x250), generic_rdmsr_low(0x250)); 71 | printk(KERN_ALERT "IA32_MTRR_FIX16K_80000 MSR: 0x%x%x\n", generic_rdmsr_high(0x258), generic_rdmsr_low(0x258)); 72 | printk(KERN_ALERT "IA32_MTRR_FIX16K_A0000 MSR: 0x%x%x\n", generic_rdmsr_high(0x259), generic_rdmsr_low(0x259)); 73 | printk(KERN_ALERT "IA32_MTRR_FIX4K_C0000 MSR: 0x%x%x\n", generic_rdmsr_high(0x268), generic_rdmsr_low(0x268)); 74 | printk(KERN_ALERT "IA32_MTRR_FIX4K_C8000 MSR: 0x%x%x\n", generic_rdmsr_high(0x269), generic_rdmsr_low(0x269)); 75 | printk(KERN_ALERT "IA32_MTRR_FIX4K_D0000 MSR: 0x%x%x\n", generic_rdmsr_high(0x26A), generic_rdmsr_low(0x26A)); 76 | printk(KERN_ALERT "IA32_MTRR_FIX4K_D8000 MSR: 0x%x%x\n", generic_rdmsr_high(0x26B), generic_rdmsr_low(0x26B)); 77 | printk(KERN_ALERT "IA32_MTRR_FIX4K_E0000 MSR: 0x%x%x\n", generic_rdmsr_high(0x26C), generic_rdmsr_low(0x26C)); 78 | printk(KERN_ALERT "IA32_MTRR_FIX4K_E8000 MSR: 0x%x%x\n", generic_rdmsr_high(0x26D), generic_rdmsr_low(0x26D)); 79 | printk(KERN_ALERT "IA32_MTRR_FIX4K_F0000 MSR: 0x%x%x\n", generic_rdmsr_high(0x26E), generic_rdmsr_low(0x26E)); 80 | printk(KERN_ALERT "IA32_MTRR_FIX4K_F8000 MSR: 0x%x%x\n", generic_rdmsr_high(0x26F), generic_rdmsr_low(0x26F)); 81 | 82 | // CPUID showing the maximum physical address size 83 | printk(KERN_ALERT "MAXPHYADDR: 0x%x", cpuid_phys_addr_size()); 84 | 85 | // Print at most 10 variable MTRR 86 | if (n_var_mtrr > 10) 87 | n_var_mtrr = 10; 88 | 89 | for (i = 0; i < n_var_mtrr; i++) { 90 | printk(KERN_ALERT "IA32_MTRR_PHYSBASE%u MSR: 0x%x%x\n", i, generic_rdmsr_high(0x200 + (i * 2)), generic_rdmsr_low(0x200 + (i * 2))); 91 | printk(KERN_ALERT "IA32_MTRR_PHYSMASK%u MSR: 0x%x%x\n", i, generic_rdmsr_high(0x201 + (i * 2)), generic_rdmsr_low(0x201 + (i * 2))); 92 | } 93 | } 94 | 95 | int init_module(void) { 96 | print_pae_structure(0xc000a000); 97 | printk(KERN_ALERT "\n"); 98 | print_mtrr_info(); 99 | 100 | return 0; 101 | } 102 | 103 | void cleanup_module(void) { 104 | printk( "cleanup\n"); 105 | } 106 | --------------------------------------------------------------------------------