Skip to content

Commit

Permalink
add got overwrite logic
Browse files Browse the repository at this point in the history
  • Loading branch information
lapla-cogito committed Aug 20, 2024
1 parent c3cac3b commit a9c411c
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 21 deletions.
Binary file added bin/got
Binary file not shown.
14 changes: 14 additions & 0 deletions bin/got.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// gcc got.c -no-pie -o got
#include<stdio.h>
#include<stdlib.h>

int secret(char* s) {
if (s[0] == 's' && s[1] == 'e' && s[2] == 'c' && s[3] == 'r' && s[4] == 'e' && s[5] == 't') {
puts("secret function called");
}
return 0;
}

int main() {
int x=system("secret");
}
7 changes: 5 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ pub enum Error {
#[error("failed in I/O operation: {0}")]
Io(std::io::Error),

#[error("")]
ExitWithCode(std::process::ExitCode),
#[error("failed to process obfuscation: {0}")]
Obfuscation(&'static str),

#[error("not found: {0}")]
NotFound(String),
}

pub type Result<T> = std::result::Result<T, Error>;
37 changes: 27 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ struct Args {
section: String,
#[arg(short, long, help = "recursive", default_value = "")]
recursive: String,
#[arg(short, long, help = "perform GOT overwrite", default_value = "false")]
got: bool,
#[arg(
long,
help = "GOT overwrite target library function name",
default_value = ""
)]
got_l: String,
#[arg(long, help = "GOT overwrite target function name", default_value = "")]
got_f: String,
}

fn main() -> crate::error::Result<()> {
Expand All @@ -65,7 +75,7 @@ fn main() -> crate::error::Result<()> {
"obfuscated"
};

exec_obfus(&args.input, output_path, &args).unwrap_or(())
exec_obfus(&args.input, output_path, &args).unwrap();
} else {
if !args.input.is_empty() {
return Err(crate::error::Error::InvalidOption(
Expand All @@ -88,7 +98,7 @@ fn main() -> crate::error::Result<()> {
std::fs::create_dir_all(dir).unwrap();
std::fs::File::create(&output_path).unwrap();

exec_obfus(entry.to_str().unwrap(), &output_path, &args).unwrap_or(());
exec_obfus(entry.to_str().unwrap(), &output_path, &args).unwrap();
}
}

Expand All @@ -113,21 +123,28 @@ fn exec_obfus(input_path: &str, output_path: &str, args: &Args) -> crate::error:
obfuscator.nullify_sec_hdr();
}
if args.symbol {
obfuscator.nullify_section(".strtab");
obfuscator.nullify_section(".strtab")?;
}
if args.comment {
obfuscator.nullify_section(".comment");
obfuscator.nullify_section(".comment")?;
}
if !args.section.is_empty() {
obfuscator.nullify_section(&args.section);
obfuscator.nullify_section(&args.section)?;
}
if args.got {
if args.got_l.is_empty() || args.got_f.is_empty() {
return Err(crate::error::Error::InvalidOption(
"both library and function names are required",
));
}

obfuscator.got_overwrite(&args.got_l, &args.got_f)?;
}

println!("obfuscation done!");
Ok(())
}
false => {
return Err(crate::error::Error::InvalidMagic);
}
false => Err(crate::error::Error::InvalidMagic),
}
}

Expand Down Expand Up @@ -177,7 +194,7 @@ mod tests {
fn null_symbol_name() {
let loader = crate::obfus::Obfuscator::open("bin/test_64bit", "bin/res_symbol");
let mut obfuscator = loader.unwrap();
obfuscator.nullify_section(".strtab");
obfuscator.nullify_section(".strtab").unwrap();
let output = std::process::Command::new("readelf")
.args(["-x29", "bin/res_symbol"])
.output()
Expand All @@ -197,7 +214,7 @@ mod tests {
fn null_comment() {
let loader = crate::obfus::Obfuscator::open("bin/test_64bit", "bin/res_comment");
let mut obfuscator = loader.unwrap();
obfuscator.nullify_section(".comment");
obfuscator.nullify_section(".comment").unwrap();
let output = std::process::Command::new("readelf")
.args(["-x27", "bin/res_comment"])
.output()
Expand Down
112 changes: 103 additions & 9 deletions src/obfus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub struct Obfuscator {
sec_hdr_size: u64,
sec_hdr_offset: u64,
sec_table: u64,
dyn_strings: String,
string_table: String,
}

impl Obfuscator {
Expand Down Expand Up @@ -111,15 +113,29 @@ impl Obfuscator {

let sec_hdr = String::from_utf8_lossy(&data_copy).to_string();

Ok(Obfuscator {
let mut obfus = Obfuscator {
input,
output,
sec_hdr,
sec_hdr_num,
sec_hdr_size,
sec_hdr_offset,
sec_table,
})
dyn_strings: String::new(),
string_table: String::new(),
};

let (section_addr, section_size, _, _) = obfus.get_section(".dynstr").unwrap();
obfus.dyn_strings =
String::from_utf8_lossy(&obfus.input[section_addr..section_addr + section_size])
.to_string();

let (section_addr, section_size, _, _) = obfus.get_section(".strtab").unwrap();
obfus.string_table =
String::from_utf8_lossy(&obfus.input[section_addr..section_addr + section_size])
.to_string();

Ok(obfus)
}

pub fn is_elf(&self) -> bool {
Expand All @@ -131,13 +147,19 @@ impl Obfuscator {
}

fn is_enable_pie(&self) -> bool {
self.input[16] == 2
self.input[16] != 2
}

fn is_stripped(&self) -> bool {
self.get_section(".symtab").unwrap().0 == 0
}

fn v2p(&self, virtual_addr: usize, section: &str) -> usize {
let (section_addr, _, _, vaddr) = self.get_section(section).unwrap();

section_addr + virtual_addr - vaddr
}

// (section_addr, section_size, entry_size, vaddr)
fn get_section(&self, section: &str) -> crate::error::Result<(usize, usize, usize, usize)> {
let searched_idx = self.sec_hdr.find(section).unwrap_or(usize::MAX);
Expand Down Expand Up @@ -203,23 +225,95 @@ impl Obfuscator {
Ok(())
}

pub fn got_overwrite(&self, function: &str, new_func_addr: &str) {
fn get_dyn_func_id(&self, function: &str) -> u64 {
let idx = self.dyn_strings.find(function).unwrap();
let (section_addr, section_size, entry_size, _) = self.get_section(".dynsym").unwrap();

let dynsym_section = &self.input[section_addr..section_addr + section_size];

for i in 0..section_size / entry_size {
let entry = &dynsym_section[i * entry_size..(i + 1) * entry_size];
let name_offset = u32::from_le_bytes(entry[0..4].try_into().unwrap());
if name_offset == idx as u32 {
return i as u64;
}
}

0
}

fn get_func_addr_by_name(&self, function: &str) -> crate::error::Result<u64> {
let idx = self.string_table.find(function).unwrap();
let (section_addr, section_size, entry_size, _) = self.get_section(".symtab").unwrap();

let dynsym_section = &self.input[section_addr..section_addr + section_size];

for i in 0..section_size / entry_size {
let entry = &dynsym_section[i * entry_size..(i + 1) * entry_size];
if self.is_64bit() {
if u32::from_le_bytes(entry[0..4].try_into().unwrap()) == idx as u32 {
return Ok(u64::from_le_bytes(entry[8..16].try_into().unwrap()));
}
} else if u32::from_le_bytes(entry[0..4].try_into().unwrap()) == idx as u32 {
return Ok(u32::from_le_bytes(entry[4..8].try_into().unwrap()) as u64);
}
}

Err(crate::error::Error::NotFound(
"function not found".to_owned() + function,
))
}

pub fn got_overwrite(
&mut self,
function: &str,
new_func_addr: &str,
) -> crate::error::Result<()> {
if self.is_enable_pie() {
println!("replacing GOT get will no effect with PIE enabled")
return Err(crate::error::Error::InvalidOption(
"replacing GOT get will no effect with PIE enabled",
));
} else if self.is_stripped() {
println!("cannot overwrite GOT with stripped binary")
return Err(crate::error::Error::InvalidOption(
"cannot overwrite GOT with stripped binary",
));
}

let id = self.get_dyn_func_id(function);

if self.is_64bit() {
let (section_addr, section_size, entry_size, vaddr) =
let (section_addr, section_size, entry_size, _) =
self.get_section(".rela.plt").unwrap();
for i in 0..section_size / entry_size {
let entry = &self.input[section_addr..section_addr + section_size]
[i * entry_size..(i + 1) * entry_size];
let info = u64::from_le_bytes(entry[8..16].try_into().unwrap()) >> 32;
if info == id {
let offset = u64::from_le_bytes(entry[0..8].try_into().unwrap());
let addr = self.v2p(offset as usize, ".got.plt");
let new_func_addr = self.get_func_addr_by_name(new_func_addr);
self.output[addr..addr + 8]
.copy_from_slice(&new_func_addr.unwrap().to_le_bytes());
return Ok(());
}
}
} else {
let (section_addr, section_size, entry_size, vaddr) =
self.get_section(".rel.plt").unwrap();
let (section_addr, section_size, entry_size, _) = self.get_section(".rel.plt").unwrap();
for i in 0..section_size / entry_size {
let entry = &self.input[section_addr..section_addr + section_size]
[i * entry_size..(i + 1) * entry_size];
let info = (u32::from_le_bytes(entry[8..16].try_into().unwrap()) >> 8) as u64;
if info == id {
let offset = u32::from_le_bytes(entry[0..4].try_into().unwrap());
let addr = self.v2p(offset as usize, ".got.plt");
let new_func_addr = self.get_func_addr_by_name(new_func_addr);
self.output[addr..addr + 4]
.copy_from_slice(&new_func_addr.unwrap().to_le_bytes());
return Ok(());
}
}
}

Err(crate::error::Error::Obfuscation("failed to overwrite GOT"))
}
}

0 comments on commit a9c411c

Please sign in to comment.