NS2EB is a small EFI application for fuzzing Model-Specific Registers (MSRs) in x86_64 processors. Leveraging the fan-favorite Time Stamp Counter (RDTSC
), custom General Protection Fault interrupt handler, and optionally a disassembly backing via Zydis-Amalgamated.
Also comes in EDK2 version.
- Features
- Why "NS2EB"?
- Getting Started
- Log file
- Graph
- Anomaly Extraction
- Customizations
- Important Info
- Credits
- Disclaimer
- Brute-Force MSR Analysis: Reads all MSRs from a given range of values (valid and invalid).
- Custom GP Fault Handling: Able to execute invalid MSRs reads by handling GP Faults.
- EFI-Based: Runs natively in UEFI environments, fully isolated from OS-level services overhead.
- Performance Modes: Change testing ranges, verbosity and speed via
NEED_MORE_SPEED
andMAX_MSR
. - Disassembler-Backed Analysis: Optionally disassembles faulting instructions for insights.
- Graph result overview: Includes a separate script to visualize execution time flukes.
This project is fully inspired by Christopher Domas' (@xoreaxeaxeax) Project Nightshyft, although the original Project Nightshyft was never made public, and was only demonstrated during a conference talk.
Therefore the super-creative name "Nightshyft 2: Electric Boogaloo" was used, however, it should be noted that this program CANNOT replicate the quality and functionality of the original project.
Please refer to the following picture for technical explanation:
-
Clone the repo:
$ git clone https://github.com/x0reaxeax/NS2EB.git $ cd NS2EB
-
Build the binary:
$ make
-
Copy the binary to a disk or an image on the target system: For testing under QEMU,
Mtools
'mcopy
can be used to easily write to an image file:$ mcopy -i disk.img /path/to/target/efi.efi ::
Or deploy to a UEFI-supported system.
NOTE: QEMU does NOT read any actual MSRs from the host system, and all of the MSR support is emulated (unless running in a KVM-accelerated VM, see Important Info). Observed anomalies are therefore just flukes, and no meaningful data should be expected from emulated runs.
-
Run the EFI application from an EFI Shell:
$ efi.efi
A logfile with a default name ns2be.log
is generated on the same drive and directory where the application is located.
The logfile can be used for creating a graph interpretation of the test. See Graph section for more information.
I=0x00;T=0x1020
V=0x01;T=0x0F80
I=0x02;T=0x2280
I=0x03;T=0x11E0
I=0x04;T=0x1080
I=0x05;T=0x0FC0
I=0x06;T=0x0FE0
I=0x07;T=0x1200
I=0x08;T=0x1280
I=0x09;T=0x1120
I=0x0A;T=0x12C0
I=0x0B;T=0x1220
I=0x0C;T=0x1180
I=0x0D;T=0x1140
I=0x0E;T=0x10C0
I=0x0F;T=0x10C0
V=0x10;T=0x0CC0
V=0x11;T=0x0CC0
V=0x12;T=0x0C40
I=0x13;T=0x14E0
I=0x14;T=0x11E0
I/V
indicates invalid/valid MSR, and T
represents the execution timing in cycles.
A standalone Python3 script is included with the project, which can be used to generate a graph of the testing results:
(QEMU demo)
To build a graph from the results, use the graph-gen.py script, with the generated logfile present in the same directory as the script:
$ python3 graph-gen.py
Another included script extract-anomalies.py can help extract anomalies of high-spike clock cycles from the generated logfile. Simply run
$ python3 extract-anomalies.py
with the logfile present in the same folder as the script.
By default, a NEED_MORE_SPEED
mode is active, which limits the number of console outputs when testing the MSRs.
You can disable this by commenting the line #define NEED_MORE_SPEED
in efi.c, which will allow for displaying the values of all tested MSRs in real-time.
However, since most firmwares are sadly incapable of implementing a well-optimized SIMPLE_TEXT_OUTPUT
protocol, the testing time will likely increase astronomically:
QEMU virtualized environment with OVMF firmware:
- 65536 (0x10000) MSRs with
NEED_MORE_SPEED
: 3.54 seconds - 65536 (0x10000) MSRs without
NEED_MORE_SPEED
: 1 minute 32 seconds
So yes, just by writing console output in real-time, the testing time increased over 30 times.
These constants control the starting MSR and maximum MSR values to run in the testing loop. This will directly impact the size of the produced logfile. See Important Info section before changing these.
This hidden configuration within CPU.asm will enable Zydis-backed verification of fault-generating instructions from within the Interrupt Handler.
The tool was written on top of this support in the beginning, however, to cut down execution times, it was switched to this naïve error-prone check:
if (0x320F == *(UINT16 *) RIP) {
/* for sure RDMSR, source: trust me bro */
}
You can re-enable this by adding the following line next to any existing %define
directive in CPU.asm:
%define ZYDIS_DISASM_BACKING
-
- In order to prevent the logfile growing to massive sizes on the disk, the default
MSR_MAX
value is set to0x100000
(1'048'576) MSRs, which will consume roughly 19.2MB of disk space. If the value is increased to maximum amount -0xFFFFFFFF
, it should be expected the logfile growing to around 78.645GB. It is obviously recommended to test with smaller chunks.
- In order to prevent the logfile growing to massive sizes on the disk, the default
-
- The Interrupt Handler takes over execution on each attempt to read an invalid MSR, however, it should be noted that the Interrupt Handler executes all of its shenanigans first, before executing the second (closing)
RDTSC
instruction, to calculate a clock diff. This should hopefully have no significant impact on the results, besides the invalid MSR times having a higher execution time ground. - This can be also avoided almost completely by placing the
RDTSC
instruction at the top of the Interrupt Handler.
- The Interrupt Handler takes over execution on each attempt to read an invalid MSR, however, it should be noted that the Interrupt Handler executes all of its shenanigans first, before executing the second (closing)
-
- If NS2EB is running inside a KVM-accelerated VM, be aware that some MSRs might be actually passed through to the host system instead of being fully emulated. This means that certain MSRs (e.g., TSC, APERF, MPERF,..) might (probably) return real host values, while other MSRs might be virtualized (e.g., VMX, MTRRs,..) and return fake values.
-
- I hope it's fairly obvious that this tool should be used on your own risk, and that I am NOT responsible for any damages caused by this educational-purposes-based project. This hacky superglued code can go haywire at any moment.
-
- The displayed
ExecFlag
variable is anint32
flag that controls the execution of the fuzz loop. - Since there's no
CTRL-C
-like event handler, the flag can be used to gracefully terminate the loop early via a debugger or DMA. - The displayed value is the address of this flag.
- The displayed
- Christopher Domas (@xoreaxeaxeax) for the idea and the incredible presentation.
- Zydis for amalgamated version of Zydis disassembler
- OSDev Wiki for technical descriptions
- GNU-EFI for a lightweight alternative to EDK2
- ChatGPT for Python scripts, help with EDK2 adaptation, and for mental support 🧡
This project is licensed under the MIT License. The content of this repository exists purely for educational purposes, and the author is not responsible for any damages caused by this software.
MIT License
Copyright (c) 2025 x0reaxeax
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.