Add support for ELF code injection
This commit is contained in:
parent
8aa55bdb23
commit
ab0f273cd9
6
notes/code_injection.md
Normal file
6
notes/code_injection.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ELF Code injection notes
|
||||
|
||||
- Locate PT_NOTE segments in binary
|
||||
- Locate a suitable `.note.*` section for replacing code
|
||||
- Modify the injection code section type from `SHT_NOTE` to `SHT_PROGBITS`
|
||||
- Update relevant start, offset, and end addresses for new section
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
To Do
|
||||
# To Do
|
||||
|
||||
Code injection
|
||||
- Have a script with 3 functions, (main, funcA, funcB), and replace refs to funcA with funcB
|
||||
- Trampoline definitions of a function to a new modified function that gets places in memory
|
||||
-
|
||||
## Code injection
|
||||
- Have a script with 3 functions, (main, funcA, funcB), and replace refs to funcA with funcB
|
||||
- Trampoline definitions of a function to a new modified function that gets places in memory
|
||||
|
||||
Injected code: 0x680
|
||||
|
||||
Call: 0x1160
|
||||
|
|
@ -121,8 +121,9 @@ pub struct FileHeader {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProgramHeader {
|
||||
pub id: u16,
|
||||
pub program_type: u32,
|
||||
pub flags: u32,
|
||||
pub offset: u64,
|
||||
|
|
@ -134,9 +135,10 @@ pub struct ProgramHeader {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SectionHeader {
|
||||
pub name: u32,
|
||||
pub id: u16,
|
||||
pub name_idx: u32,
|
||||
pub section_type: u32,
|
||||
pub flags: u64,
|
||||
pub addr: u64,
|
||||
|
|
|
|||
36
src/main.rs
36
src/main.rs
|
|
@ -20,7 +20,7 @@ mod patcher;
|
|||
fn main() {
|
||||
// Collect our execution args
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let mut patch_mode: bool = false;
|
||||
let mut inject_mode: bool = false;
|
||||
let mut patch_file_path: &String = &"".to_string();
|
||||
|
||||
// Grab our filepath from our options
|
||||
|
|
@ -34,7 +34,7 @@ fn main() {
|
|||
if &args.len() > &2 {
|
||||
if &args[2] == "-p" {
|
||||
if &args.len() >= &4 {
|
||||
patch_mode = true;
|
||||
inject_mode = true;
|
||||
patch_file_path = &args[3];
|
||||
} else {
|
||||
util::print_help();
|
||||
|
|
@ -87,6 +87,7 @@ fn main() {
|
|||
let shstrtab_section: elf::SectionHeader = util::build_section_header(
|
||||
bytes,
|
||||
shstrtab_offset as usize,
|
||||
file_header.shstrndx,
|
||||
file_header.is_x86_64
|
||||
);
|
||||
|
||||
|
|
@ -104,17 +105,18 @@ fn main() {
|
|||
let mut section_table_count: i32 = 0;
|
||||
|
||||
// Iterate through number of section headers
|
||||
for _ in 0..file_header.shnum {
|
||||
for i in 0..file_header.shnum {
|
||||
|
||||
// Build section header data structure
|
||||
let section_header: elf::SectionHeader = util::build_section_header(
|
||||
bytes,
|
||||
section_table_offset as usize,
|
||||
i,
|
||||
file_header.is_x86_64
|
||||
);
|
||||
|
||||
// Determine the section name for each section using the shstrtab data
|
||||
let section_name: String = util::parse_section_name(&shstrtab_data, section_header.name as usize);
|
||||
let section_name: String = util::parse_section_name(&shstrtab_data, section_header.name_idx as usize);
|
||||
|
||||
util::pp_section_header(§ion_header, section_table_count, §ion_name);
|
||||
|
||||
|
|
@ -131,19 +133,25 @@ fn main() {
|
|||
|
||||
let mut program_table_offset = file_header.phoff;
|
||||
let mut program_table_count: i32 = 0;
|
||||
let mut pt_note_offset: usize = 0;
|
||||
|
||||
// Iterate through number of Program Headers
|
||||
for _ in 0..file_header.phnum {
|
||||
for i in 0..file_header.phnum {
|
||||
// Build Program Header data structure
|
||||
let program_header: elf::ProgramHeader = util::build_program_header(
|
||||
bytes,
|
||||
program_table_offset as usize,
|
||||
i,
|
||||
file_header.is_x86_64
|
||||
);
|
||||
|
||||
// Parse the program name using the program type
|
||||
let program_name: String = util::parse_program_segment_type(program_header.program_type);
|
||||
|
||||
if (program_name == "PT_NOTE") && (pt_note_offset == 0) {
|
||||
pt_note_offset = program_table_offset as usize;
|
||||
}
|
||||
|
||||
util::pp_program_header(&program_header, program_table_count, &program_name);
|
||||
|
||||
// Update the program header table offset counter based on the program header size
|
||||
|
|
@ -151,6 +159,13 @@ fn main() {
|
|||
program_table_count += 1;
|
||||
}
|
||||
|
||||
let note_segment: elf::ProgramHeader = util::build_program_header(
|
||||
bytes,
|
||||
pt_note_offset,
|
||||
0,
|
||||
file_header.is_x86_64
|
||||
);
|
||||
|
||||
|
||||
// Now that we have all the sections, spit out the .text section and start a linear disassembly
|
||||
let text_section: &elf::SectionHeader = section_table_map.get(".text").unwrap();
|
||||
|
|
@ -221,14 +236,17 @@ fn main() {
|
|||
}
|
||||
|
||||
|
||||
if patch_mode {
|
||||
if inject_mode {
|
||||
|
||||
println!("\n==== Applying Patch To Binary ====\n");
|
||||
println!("\n==== Injecting Payload To Binary ====\n");
|
||||
|
||||
patcher::patch_binary(
|
||||
bytes.to_vec(),
|
||||
file_path.to_string(),
|
||||
&patch_file_path
|
||||
&patch_file_path,
|
||||
&file_header,
|
||||
section_table_map,
|
||||
note_segment
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -238,7 +256,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
println!("[Error] '{}' does not exist", file_path);
|
||||
println!("[Error] File '{}' does not exist", file_path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
|
|||
173
src/patcher.rs
173
src/patcher.rs
|
|
@ -4,105 +4,124 @@
|
|||
// Description: Houses binary rewriting and patching functionality for chisel.
|
||||
|
||||
use std::path;
|
||||
use std::fs;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::io::Error;
|
||||
|
||||
use crate::util;
|
||||
use crate::elf;
|
||||
|
||||
|
||||
pub fn patch_binary(binary_contents: Vec<u8>, binary_name: String, patch_file_path: &String) {
|
||||
pub fn patch_binary(
|
||||
binary_contents: Vec<u8>,
|
||||
binary_name: String,
|
||||
patch_file_path: &String,
|
||||
file_header: &elf::FileHeader,
|
||||
section_header_map: HashMap<String, elf::SectionHeader>,
|
||||
note_segment: elf::ProgramHeader) {
|
||||
|
||||
let patch_data: HashMap<usize, Vec<u8>> = parse_patch_file(patch_file_path);
|
||||
let mut bytes: Vec<u8> = binary_contents;
|
||||
|
||||
println!("Patch data read successfully, applying...");
|
||||
let patch_result: Result<Vec<u8>,Error> = read_patch_file(patch_file_path);
|
||||
let patch_data: &Vec<u8> = &patch_result.as_ref().unwrap();
|
||||
|
||||
let mut program_data: Vec<u8> = binary_contents;
|
||||
|
||||
for patch in patch_data {
|
||||
let start_offset = patch.0;
|
||||
let mut i: usize = 0;
|
||||
while i < (patch.1.len()) {
|
||||
bytes[(start_offset + i) as usize] = patch.1[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
println!("Done!");
|
||||
// Apply patch to end of binary
|
||||
println!("Patch data read successfully, injecting at end of binary...");
|
||||
|
||||
let patched_file_name: String = binary_name + "_patched";
|
||||
let injection_offset: usize = program_data.len();
|
||||
let injection_size: usize = patch_data.len();
|
||||
let injection_addr: usize = injection_offset;
|
||||
|
||||
println!("Writing '{}' to disk...", patched_file_name);
|
||||
program_data.extend_from_slice(patch_data);
|
||||
|
||||
let mut file = std::fs::File::create(patched_file_name)
|
||||
print!("Done!");
|
||||
|
||||
|
||||
// Locate a note segment
|
||||
println!("Pulling .note.ABI-tag segment data...");
|
||||
let note_section: &elf::SectionHeader = section_header_map.get(".note.ABI-tag")
|
||||
.expect("[Error] Failed to pull ABI-tag section from binary!");
|
||||
print!("Done!\n");
|
||||
|
||||
println!("Note section address: {:#04x}", note_section.addr);
|
||||
println!("Note section offset: {:#04x}", note_section.offset);
|
||||
println!("Note section size: {}", note_section.size);
|
||||
println!("");
|
||||
println!("Injected address: {:#04x}", injection_addr);
|
||||
println!("Injected section offset: {:#04x}", injection_offset);
|
||||
println!("Injected section size: {}", injection_size);
|
||||
|
||||
|
||||
// Rewrite the section header
|
||||
let mut injected_section: elf::SectionHeader = elf::SectionHeader::from(note_section.clone());
|
||||
|
||||
injected_section.section_type = 1;
|
||||
injected_section.addr = injection_addr as u64;
|
||||
injected_section.offset = injection_offset as u64;
|
||||
injected_section.size = injection_size as u64;
|
||||
|
||||
util::overwrite_section_header(
|
||||
&mut program_data,
|
||||
file_header.shoff as usize,
|
||||
file_header.shentsize as usize,
|
||||
injected_section.id as usize,
|
||||
&injected_section,
|
||||
file_header.is_x86_64
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Rewrite the section header
|
||||
let mut injected_segment: elf::ProgramHeader = elf::ProgramHeader::from(note_segment.clone());
|
||||
|
||||
injected_segment.program_type = 1;
|
||||
injected_segment.offset = injection_offset as u64;
|
||||
injected_segment.vaddr = injection_offset as u64;
|
||||
injected_segment.paddr = injection_offset as u64;
|
||||
injected_segment.filesz = injection_size as u64;
|
||||
injected_segment.memsz = injection_size as u64;
|
||||
injected_segment.flags = 5;
|
||||
injected_segment.align = 0x1000;
|
||||
|
||||
util::overwrite_segment_header(
|
||||
&mut program_data,
|
||||
file_header.shoff as usize,
|
||||
file_header.shentsize as usize,
|
||||
injected_section.id as usize,
|
||||
&injected_section,
|
||||
file_header.is_x86_64
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
util::overwrite_entrypoint(&mut program_data, injection_offset);
|
||||
|
||||
|
||||
// Spit everything back out
|
||||
let out_file_name: String = binary_name + ".patched";
|
||||
|
||||
println!("Writing '{}' to disk...", out_file_name);
|
||||
|
||||
let mut file = std::fs::File::create(out_file_name)
|
||||
.expect("[Error] Could not write patched binary to disk");
|
||||
|
||||
file.write_all(&bytes)
|
||||
.expect("[Error] Could not write to patched binary file");
|
||||
|
||||
file.write_all(&program_data)
|
||||
.expect("[Error] Could not write to patched binary data file");
|
||||
}
|
||||
|
||||
|
||||
fn parse_patch_file(patch_path: &String) -> HashMap<usize, Vec<u8>>{
|
||||
// Load the file from patch_binary() arg
|
||||
// Iterate through file, if line starts with # ignore
|
||||
// Otherwise, parse as such
|
||||
// [ADDRESS] [SPACE] [HEX],[HEX],[HEX],....
|
||||
// [ADDRESS] [SPACE] [STRING]
|
||||
fn read_patch_file(patch_path: &String) -> Result<Vec<u8>, std::io::Error> {
|
||||
|
||||
if path::Path::new(patch_path).exists() && patch_path.ends_with(".patch") {
|
||||
if path::Path::new(patch_path).exists() && patch_path.ends_with(".bin") {
|
||||
println!("Patch file exists, reading '{}'...", patch_path);
|
||||
|
||||
let contents = util::read_lines(patch_path.to_string());
|
||||
let mut patch_data: HashMap<usize, Vec<u8>> = HashMap::new();
|
||||
let contents: Result<Vec<u8>, std::io::Error> = fs::read(patch_path);
|
||||
|
||||
for line in contents {
|
||||
let unwrapped = line.unwrap();
|
||||
if unwrapped.trim().starts_with("#") || unwrapped.is_empty() {
|
||||
//Skip
|
||||
} else {
|
||||
let mut statement = unwrapped.split(":");
|
||||
let address: usize = util::hex_to_int(statement.next().unwrap().trim()).unwrap();
|
||||
let data: &str = statement.next().unwrap().trim();
|
||||
|
||||
if !data.is_empty() {
|
||||
if data.contains("\"") {
|
||||
// Value is a string literal
|
||||
let cleaned = data.replace("\"", "");
|
||||
let bytes: Vec<u8> = cleaned.as_bytes().to_vec();
|
||||
|
||||
print!("{}: ", address);
|
||||
|
||||
let mut i = 0;
|
||||
while i < bytes.len() {
|
||||
print!("{} ", bytes[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
patch_data.insert(address, bytes);
|
||||
|
||||
} else {
|
||||
// Data is comma seperated list or a single value
|
||||
let byte_str: String = data.replace(",", "");
|
||||
let bytes: Vec<u8> = util::hex_to_buff(&byte_str).unwrap();
|
||||
|
||||
print!("{}: ", address);
|
||||
|
||||
let mut i = 0;
|
||||
while i < bytes.len() {
|
||||
print!("{} ", bytes[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
patch_data.insert(address, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return patch_data;
|
||||
return contents;
|
||||
|
||||
} else {
|
||||
println!("[Error] Patch file '{}' is invalid or cannot be read, exiting...", patch_path);
|
||||
|
|
|
|||
111
src/patcher.rs.bak
Normal file
111
src/patcher.rs.bak
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// patcher.rs
|
||||
// Author: Garrett Dickinson
|
||||
// Created: 04/06/2023
|
||||
// Description: Houses binary rewriting and patching functionality for chisel.
|
||||
|
||||
use std::path;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
|
||||
use crate::util;
|
||||
|
||||
|
||||
pub fn patch_binary(binary_contents: Vec<u8>, binary_name: String, patch_file_path: &String) {
|
||||
|
||||
let patch_data: HashMap<usize, Vec<u8>> = parse_patch_file(patch_file_path);
|
||||
let mut bytes: Vec<u8> = binary_contents;
|
||||
|
||||
println!("Patch data read successfully, applying...");
|
||||
|
||||
for patch in patch_data {
|
||||
let start_offset = patch.0;
|
||||
let mut i: usize = 0;
|
||||
while i < (patch.1.len()) {
|
||||
bytes[(start_offset + i) as usize] = patch.1[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
println!("Done!");
|
||||
|
||||
let patched_file_name: String = binary_name + "_patched";
|
||||
|
||||
println!("Writing '{}' to disk...", patched_file_name);
|
||||
|
||||
let mut file = std::fs::File::create(patched_file_name)
|
||||
.expect("[Error] Could not write patched binary to disk");
|
||||
|
||||
file.write_all(&bytes)
|
||||
.expect("[Error] Could not write to patched binary file");
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn parse_patch_file(patch_path: &String) -> HashMap<usize, Vec<u8>>{
|
||||
// Load the file from patch_binary() arg
|
||||
// Iterate through file, if line starts with # ignore
|
||||
// Otherwise, parse as such
|
||||
// [ADDRESS] [SPACE] [HEX],[HEX],[HEX],....
|
||||
// [ADDRESS] [SPACE] [STRING]
|
||||
|
||||
if path::Path::new(patch_path).exists() && patch_path.ends_with(".patch") {
|
||||
println!("Patch file exists, reading '{}'...", patch_path);
|
||||
|
||||
let contents = util::read_lines(patch_path.to_string());
|
||||
let mut patch_data: HashMap<usize, Vec<u8>> = HashMap::new();
|
||||
|
||||
for line in contents {
|
||||
let unwrapped = line.unwrap();
|
||||
if unwrapped.trim().starts_with("#") || unwrapped.is_empty() {
|
||||
//Skip
|
||||
} else {
|
||||
let mut statement = unwrapped.split(":");
|
||||
let address: usize = util::hex_to_int(statement.next().unwrap().trim()).unwrap();
|
||||
let data: &str = statement.next().unwrap().trim();
|
||||
|
||||
if !data.is_empty() {
|
||||
if data.contains("\"") {
|
||||
// Value is a string literal
|
||||
let cleaned = data.replace("\"", "");
|
||||
let bytes: Vec<u8> = cleaned.as_bytes().to_vec();
|
||||
|
||||
print!("{}: ", address);
|
||||
|
||||
let mut i = 0;
|
||||
while i < bytes.len() {
|
||||
print!("{} ", bytes[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
patch_data.insert(address, bytes);
|
||||
|
||||
} else {
|
||||
// Data is comma seperated list or a single value
|
||||
let byte_str: String = data.replace(",", "");
|
||||
let bytes: Vec<u8> = util::hex_to_buff(&byte_str).unwrap();
|
||||
|
||||
print!("{}: ", address);
|
||||
|
||||
let mut i = 0;
|
||||
while i < bytes.len() {
|
||||
print!("{} ", bytes[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
patch_data.insert(address, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return patch_data;
|
||||
|
||||
} else {
|
||||
println!("[Error] Patch file '{}' is invalid or cannot be read, exiting...", patch_path);
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
163
src/util.rs
163
src/util.rs
|
|
@ -5,9 +5,9 @@
|
|||
// functions.
|
||||
|
||||
use std::mem;
|
||||
use std::io::{self, BufReader, BufRead};
|
||||
use std::fs::File;
|
||||
use std::num::ParseIntError;
|
||||
// use std::io::{self, BufReader, BufRead};
|
||||
// use std::fs::File;
|
||||
// use std::num::ParseIntError;
|
||||
|
||||
use crate::elf::{self, EndianType, ArchitectureType};
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ pub fn build_file_header(data: &Vec<u8>) -> elf::FileHeader {
|
|||
}
|
||||
|
||||
|
||||
pub fn build_program_header(data: &Vec<u8>, phoffset: usize, is_x86_64: bool) -> elf::ProgramHeader {
|
||||
pub fn build_program_header(data: &Vec<u8>, phoffset: usize, id: u16, is_x86_64: bool) -> elf::ProgramHeader {
|
||||
|
||||
// Cast the supplied is_x86_64 bool to an array offset
|
||||
// 0 : x86
|
||||
|
|
@ -51,6 +51,7 @@ pub fn build_program_header(data: &Vec<u8>, phoffset: usize, is_x86_64: bool) ->
|
|||
let arch: usize = is_x86_64.into();
|
||||
|
||||
let program_header: elf::ProgramHeader = elf::ProgramHeader {
|
||||
id: id,
|
||||
program_type: u32_from_buffer(data, phoffset + elf::PH_TYPE_OFFSET as usize),
|
||||
flags: u32_from_buffer(data, phoffset + elf::PH_FLAGS_OFFSET[arch] as usize),
|
||||
offset: u64_from_buffer(data, phoffset + elf::PH_OFFSET_OFFSET[arch] as usize),
|
||||
|
|
@ -65,7 +66,48 @@ pub fn build_program_header(data: &Vec<u8>, phoffset: usize, is_x86_64: bool) ->
|
|||
}
|
||||
|
||||
|
||||
pub fn build_section_header(data: &Vec<u8>, shoffset: usize, is_x86_64: bool) -> elf::SectionHeader {
|
||||
pub fn overwrite_segment_header(program_data: &mut Vec<u8>,
|
||||
stoffset: usize,
|
||||
shentsize: usize,
|
||||
shentidx: usize,
|
||||
new_section: &elf::SectionHeader,
|
||||
is_x86_64: bool) {
|
||||
|
||||
// Cast the supplied is_x86_64 bool to an array offset
|
||||
// 0 : x86
|
||||
// 1 : x64
|
||||
let arch: usize = is_x86_64.into();
|
||||
|
||||
println!("stoffset {}", stoffset);
|
||||
println!("shentsize {}", shentsize);
|
||||
println!("shentidx {}", shentidx);
|
||||
|
||||
let section_addr_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_ADDR_OFFSET[arch] as usize;
|
||||
let section_offset_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_OFFSET_OFFSET[arch] as usize;
|
||||
let section_size_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_SIZE_OFFSET[arch] as usize;
|
||||
let section_type_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_TYPE_OFFSET as usize;
|
||||
|
||||
program_data[section_addr_offset..section_addr_offset+8].copy_from_slice(
|
||||
&new_section.addr.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section addr with {:#04x}", new_section.addr);
|
||||
|
||||
program_data[section_offset_offset..section_offset_offset+8].copy_from_slice(
|
||||
&new_section.offset.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section offset with {:#04x}", new_section.offset as usize);
|
||||
|
||||
program_data[section_size_offset..section_size_offset+8].copy_from_slice(
|
||||
&new_section.size.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section size with {:#04x}", new_section.size as usize);
|
||||
|
||||
program_data[section_type_offset..section_type_offset+4].copy_from_slice(
|
||||
&new_section.section_type.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section type with {:#04x}", new_section.section_type as usize);
|
||||
|
||||
// return section_header;
|
||||
}
|
||||
|
||||
|
||||
pub fn build_section_header(data: &Vec<u8>, stoffset: usize, id: u16, is_x86_64: bool) -> elf::SectionHeader {
|
||||
|
||||
// Cast the supplied is_x86_64 bool to an array offset
|
||||
// 0 : x86
|
||||
|
|
@ -73,22 +115,74 @@ pub fn build_section_header(data: &Vec<u8>, shoffset: usize, is_x86_64: bool) ->
|
|||
let arch: usize = is_x86_64.into();
|
||||
|
||||
let section_header: elf::SectionHeader = elf::SectionHeader {
|
||||
name: u32_from_buffer(data, shoffset + elf::SH_NAME_OFFSET as usize),
|
||||
section_type: u32_from_buffer(data, shoffset + elf::SH_TYPE_OFFSET as usize),
|
||||
flags: u64_from_buffer(data, shoffset + elf::SH_FLAGS_OFFSET as usize),
|
||||
addr: u64_from_buffer(data, shoffset + elf::SH_ADDR_OFFSET[arch] as usize),
|
||||
offset: u64_from_buffer(data, shoffset + elf::SH_OFFSET_OFFSET[arch] as usize),
|
||||
size: u64_from_buffer(data, shoffset + elf::SH_SIZE_OFFSET[arch] as usize),
|
||||
link: u32_from_buffer(data, shoffset + elf::SH_LINK_OFFSET[arch] as usize),
|
||||
info: u32_from_buffer(data, shoffset + elf::SH_INFO_OFFSET[arch] as usize),
|
||||
addralign: u64_from_buffer(data, shoffset + elf::SH_ADDRALIGN_OFFSET[arch] as usize),
|
||||
entsize: u64_from_buffer(data, shoffset + elf::SH_ENTSIZE_OFFSET[arch] as usize)
|
||||
id: id,
|
||||
name_idx: u32_from_buffer(data, stoffset + elf::SH_NAME_OFFSET as usize),
|
||||
section_type: u32_from_buffer(data, stoffset + elf::SH_TYPE_OFFSET as usize),
|
||||
flags: u64_from_buffer(data, stoffset + elf::SH_FLAGS_OFFSET as usize),
|
||||
addr: u64_from_buffer(data, stoffset + elf::SH_ADDR_OFFSET[arch] as usize),
|
||||
offset: u64_from_buffer(data, stoffset + elf::SH_OFFSET_OFFSET[arch] as usize),
|
||||
size: u64_from_buffer(data, stoffset + elf::SH_SIZE_OFFSET[arch] as usize),
|
||||
link: u32_from_buffer(data, stoffset + elf::SH_LINK_OFFSET[arch] as usize),
|
||||
info: u32_from_buffer(data, stoffset + elf::SH_INFO_OFFSET[arch] as usize),
|
||||
addralign: u64_from_buffer(data, stoffset + elf::SH_ADDRALIGN_OFFSET[arch] as usize),
|
||||
entsize: u64_from_buffer(data, stoffset + elf::SH_ENTSIZE_OFFSET[arch] as usize)
|
||||
};
|
||||
|
||||
return section_header;
|
||||
}
|
||||
|
||||
|
||||
pub fn overwrite_section_header(program_data: &mut Vec<u8>,
|
||||
stoffset: usize,
|
||||
shentsize: usize,
|
||||
shentidx: usize,
|
||||
new_section: &elf::SectionHeader,
|
||||
is_x86_64: bool) {
|
||||
|
||||
// Cast the supplied is_x86_64 bool to an array offset
|
||||
// 0 : x86
|
||||
// 1 : x64
|
||||
let arch: usize = is_x86_64.into();
|
||||
|
||||
println!("stoffset {}", stoffset);
|
||||
println!("shentsize {}", shentsize);
|
||||
println!("shentidx {}", shentidx);
|
||||
|
||||
let section_addr_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_ADDR_OFFSET[arch] as usize;
|
||||
let section_offset_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_OFFSET_OFFSET[arch] as usize;
|
||||
let section_size_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_SIZE_OFFSET[arch] as usize;
|
||||
let section_type_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_TYPE_OFFSET as usize;
|
||||
|
||||
program_data[section_addr_offset..section_addr_offset+8].copy_from_slice(
|
||||
&new_section.addr.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section addr with {:#04x}", new_section.addr);
|
||||
|
||||
program_data[section_offset_offset..section_offset_offset+8].copy_from_slice(
|
||||
&new_section.offset.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section offset with {:#04x}", new_section.offset as usize);
|
||||
|
||||
program_data[section_size_offset..section_size_offset+8].copy_from_slice(
|
||||
&new_section.size.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section size with {:#04x}", new_section.size as usize);
|
||||
|
||||
program_data[section_type_offset..section_type_offset+4].copy_from_slice(
|
||||
&new_section.section_type.to_ne_bytes().to_vec());
|
||||
println!("Overwriting section type with {:#04x}", new_section.section_type as usize);
|
||||
|
||||
// return section_header;
|
||||
}
|
||||
|
||||
|
||||
pub fn overwrite_entrypoint(program_data: &mut Vec<u8>,
|
||||
new_entry_point: usize) {
|
||||
|
||||
let offset: usize = elf::ENTRYPOINT_OFFSET as usize;
|
||||
program_data[offset..offset+8].copy_from_slice(
|
||||
&new_entry_point.to_ne_bytes().to_vec()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
pub fn parse_endian(endian: u8) -> elf::EndianType {
|
||||
match endian {
|
||||
0x00 => return EndianType::Big,
|
||||
|
|
@ -339,23 +433,28 @@ pub fn print_help() {
|
|||
}
|
||||
|
||||
|
||||
pub fn read_lines(filename: String) -> io::Lines<BufReader<File>> {
|
||||
// Open the file in read-only mode.
|
||||
let file = File::open(filename).unwrap();
|
||||
// Read the file line by line, and return an iterator of the lines of the file.
|
||||
return io::BufReader::new(file).lines();
|
||||
}
|
||||
// pub fn read_lines(filename: String) -> io::Lines<BufReader<File>> {
|
||||
// // Open the file in read-only mode.
|
||||
// let file = File::open(filename).unwrap();
|
||||
// // Read the file line by line, and return an iterator of the lines of the file.
|
||||
// return io::BufReader::new(file).lines();
|
||||
// }
|
||||
|
||||
// Borrowed from the following Stack Overflow post
|
||||
// https://stackoverflow.com/questions/52987181/how-can-i-convert-a-hex-string-to-a-u8-slice
|
||||
pub fn hex_to_buff(s: &str) -> Result<Vec<u8>, ParseIntError> {
|
||||
(0..s.len())
|
||||
.step_by(2)
|
||||
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
|
||||
.collect()
|
||||
}
|
||||
// // Borrowed from the following Stack Overflow post
|
||||
// // https://stackoverflow.com/questions/52987181/how-can-i-convert-a-hex-string-to-a-u8-slice
|
||||
// pub fn hex_to_buff(s: &str) -> Result<Vec<u8>, ParseIntError> {
|
||||
// (0..s.len())
|
||||
// .step_by(2)
|
||||
// .map(|i| u8::from_str_radix(&s[i..i + 2], 16))
|
||||
// .collect()
|
||||
// }
|
||||
|
||||
|
||||
pub fn hex_to_int(s: &str) -> Result<usize, ParseIntError> {
|
||||
return usize::from_str_radix(s, 16)
|
||||
}
|
||||
// pub fn hex_to_usize(s: &str) -> Result<usize, ParseIntError> {
|
||||
// return usize::from_str_radix(s, 16)
|
||||
// }
|
||||
|
||||
|
||||
// pub fn usize_to_hex(i: usize) -> String {
|
||||
// return format!("{:X}", i).to_string();
|
||||
// }
|
||||
BIN
testing/elfpatching/hello_patch.bin
Normal file
BIN
testing/elfpatching/hello_patch.bin
Normal file
Binary file not shown.
32
testing/elfpatching/hello_patch.s
Normal file
32
testing/elfpatching/hello_patch.s
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
BITS 64
|
||||
|
||||
SECTION .text
|
||||
global main
|
||||
|
||||
main:
|
||||
push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
push r11
|
||||
|
||||
mov rax,1
|
||||
mov rdi,1
|
||||
lea rsi,[rel $+hello-$]
|
||||
mov rdx,[rel $+len-$]
|
||||
syscall
|
||||
|
||||
pop r11
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
|
||||
;push 0x1060 ; jump to original entry point
|
||||
; ; could be replaced dynamically?
|
||||
;ret
|
||||
|
||||
hello: db "Calling injected code >:)",10
|
||||
len: dd 26
|
||||
BIN
testing/elfpatching/login
Executable file
BIN
testing/elfpatching/login
Executable file
Binary file not shown.
Binary file not shown.
BIN
testing/hello32
BIN
testing/hello32
Binary file not shown.
|
|
@ -1,14 +0,0 @@
|
|||
# Trampoline segment
|
||||
# Pushes and returns to 0x116b
|
||||
#3f80 : 48C7C00100000048C7C70100000048C7C68007000048C7C20D0000000F05686B110000C3
|
||||
# No syscall
|
||||
1190 : 48C7C00100000048C7C70100000048C7C6C011000048C7C20D000000686B110000C3
|
||||
|
||||
# String data to print from trampoline instruction
|
||||
11C0 : "Hello, World!"
|
||||
|
||||
# Initial jump to trampoline
|
||||
#1160 : 6880060000C3
|
||||
#1160 : 6890110000C3
|
||||
|
||||
2004 : "Hello, Patch!"
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
int main() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int my_function() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int another_function() {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
.file "main.c"
|
||||
.text
|
||||
.section .rodata
|
||||
.LC0:
|
||||
.string "Hello, World!"
|
||||
.text
|
||||
.globl main
|
||||
.type main, @function
|
||||
main:
|
||||
.LFB0:
|
||||
.cfi_startproc
|
||||
endbr64
|
||||
pushq %rbp
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_offset 6, -16
|
||||
movq %rsp, %rbp
|
||||
.cfi_def_cfa_register 6
|
||||
leaq .LC0(%rip), %rax
|
||||
movq %rax, %rdi
|
||||
movl $0, %eax
|
||||
call printf@PLT
|
||||
movl $0, %eax
|
||||
popq %rbp
|
||||
.cfi_def_cfa 7, 8
|
||||
ret
|
||||
.cfi_endproc
|
||||
.LFE0:
|
||||
.size main, .-main
|
||||
.ident "GCC: (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.gnu.property,"a"
|
||||
.align 8
|
||||
.long 1f - 0f
|
||||
.long 4f - 1f
|
||||
.long 5
|
||||
0:
|
||||
.string "GNU"
|
||||
1:
|
||||
.align 8
|
||||
.long 0xc0000002
|
||||
.long 3f - 2f
|
||||
2:
|
||||
.long 0x3
|
||||
3:
|
||||
.align 8
|
||||
4:
|
||||
Loading…
Reference in New Issue
Block a user