Compare commits

..

No commits in common. "c507d6c028672c7b62bea762b8b401fd9fdb65a6" and "80d346ae03652e030c4b65efb76813a315ff25b5" have entirely different histories.

19 changed files with 179 additions and 1075 deletions

14
.gitignore vendored
View File

@ -8,17 +8,3 @@ Cargo.lock
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
# Added by cargo
/target
# Remove Ghidra related testing files
/testing/ghidra
# Remove .vscode directory
.vscode
*.log

View File

@ -7,5 +7,3 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
iced-x86 = "1.18.0"
clap = "4.2.1"

View File

@ -1,35 +1,7 @@
# chisel # chisel
`chisel` is a tool for decompiling *nix ELF programs for binary analysis and reverse engineering. This project is being developed for assignments pertaining to Auburn University's **COMP5970 Binary Program Analysis** course. `chisel` is a tool for decompiling *nix ELF programs for binary analysis and reverse engineering. This project is being developed for assignments pertaining to Auburn University's **COMP5970 Binary Program Analysis** course.
## Binary Analysis Technique
`chisel` uses a linear dissassembly approach for converting the ELF text section into x86 assembly instructions. Future implementations will have more advances analysis techniques such as recursive descent, as well as potential binary patching. ## Supported Binary formats
## Supported formats
`chisel` supports binaries compiled to the [ELF format](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) from most x86/x64 *nix systems, and __does not__ currently support macOS Mach-O or Windows PE binaries. `chisel` supports binaries compiled to the [ELF format](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) from most x86/x64 *nix systems, and __does not__ currently support macOS Mach-O or Windows PE binaries.
> Due to an indexing bug, current iterations of chisel do not support 32-bit x86 applications. Only x86-64 is supported.
## Building and Installing
To build and install `chisel`, use the following steps:
```shell
$ git clone git@github.com:Gman0064/chisel.git
$ cd chisel && cargo install
```
## Usage
The following format can be used to pass a binary to `chisel` to analyze. The repository also includes a few binaries in `./testing/` as included examples. `chisel` also supports binary rewriting/patching by specifying the `-p` flag along with a `.bin` file of assembly code you would like to inject.
```shell
$ chisel [EXECUTABLE] [-p] [PATCH_FILE]
```
> Binary patching is currently very buggy and may cause segmentation faults with the patched binary

View File

@ -1,6 +0,0 @@
# 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

View File

@ -1,37 +0,0 @@
Project File Name: hello
Last Modified: Mon Apr 10 03:28:12 CDT 2023
Readonly: false
Program Name: hello
Language ID: x86:LE:64:default (2.13)
Compiler ID: gcc
Processor: x86
Endian: Little
Address Size: 64
Minimum Address: 00100000
Maximum Address: _elfSectionHeaders::000007bf
# of Bytes: 6481
# of Memory Blocks: 33
# of Instructions: 8
# of Defined Data: 105
# of Functions: 14
# of Symbols: 47
# of Data Types: 32
# of Data Type Categories: 2
Created With Ghidra Version: 10.2.3
Date Created: Mon Apr 10 03:28:12 CDT 2023
ELF File Type: shared object
ELF Original Image Base: 0x0
ELF Prelinked: false
ELF Required Library [ 0]: libc.so.6
ELF Source File [ 0]: Scrt1.o
ELF Source File [ 1]: crtstuff.c
ELF Source File [ 2]: hello.c
ELF Source File [ 3]: crtstuff.c
ELF Source File [ 4]:
Executable Format: Executable and Linking Format (ELF)
Executable Location: /media/garrett/Storage/Projects/chisel/testing/hello
Executable MD5: 45ddd8df3ccde5aa5d143ae0d00e542d
Executable SHA256: d448eaf9e134d840c4c3c87a9320060a763d3fac0e172818b87b7eda8e661b9a
FSRL: file:///media/garrett/Storage/Projects/chisel/testing/hello?MD5=45ddd8df3ccde5aa5d143ae0d00e542d
Preferred Root Namespace Category:
Relocatable: true

View File

@ -1,9 +0,0 @@
# 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
Injected code: 0x680
Call: 0x1160

View File

@ -12,7 +12,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
pub const MAGIC_NUMBER: &[u8] = &[0x7F,0x45,0x4C,0x46]; pub const MAGIC_NUMBER: &[u8] = &[0x7F,0x45,0x4C,0x46];
pub const ARCH_OFFSET: u8 = 0x04; // x86 or x64 indicator; 1 byte pub const ARCH_OFFSET: u8 = 0x04; // x86 or x64 indiicator; 1 byte
pub const ENDIAN_OFFSET: u8 = 0x05; // Endian offset (1 - little, 2 - big); 1 byte pub const ENDIAN_OFFSET: u8 = 0x05; // Endian offset (1 - little, 2 - big); 1 byte
pub const ABI_OFFSET: u8 = 0x07; // ABI identifier; 1 byte pub const ABI_OFFSET: u8 = 0x07; // ABI identifier; 1 byte
pub const TYPE_OFFSET: u8 = 0x10; // Object type identifier; 2 bytes pub const TYPE_OFFSET: u8 = 0x10; // Object type identifier; 2 bytes
@ -32,7 +32,7 @@ pub const ENTRYPOINT_OFFSET: u8 = 0x18;
pub const PHOFF_OFFSET: [u8; 2] = [0x1C, 0x20]; // Program header table pointer; 2 bytes pub const PHOFF_OFFSET: [u8; 2] = [0x1C, 0x20]; // Program header table pointer; 2 bytes
pub const SHOFF_OFFSET: [u8; 2] = [0x20, 0x28]; // Section table pointer; 2 bytes pub const SHOFF_OFFSET: [u8; 2] = [0x20, 0x28]; // Section table pointer; 2 bytes
pub const EHSIZE_OFFSET: [u8; 2] = [0x28, 0x34]; // Program header table entry size pointer; 2 bytes pub const EHSIZE_OFFSET: [u8; 2] = [0x28, 0x34]; // Program header table entry size pointer; 2 bytes
pub const PHENTSIZE_OFFSET: [u8; 2] = [0x2A, 0x36]; // Section table pointer; 2 bytes pub const PHENTSIZE_OFFSET: [u8; 2] = [0x28, 0x34]; // Section table pointer; 2 bytes
pub const PHNUM_OFFSET: [u8; 2] = [0x2C, 0x38]; // Program header table number of entries pointer; 2 bytes pub const PHNUM_OFFSET: [u8; 2] = [0x2C, 0x38]; // Program header table number of entries pointer; 2 bytes
pub const SHENTSIZE_OFFSET: [u8; 2] = [0x2E, 0x3A]; // Size of section header table; 2 bytes pub const SHENTSIZE_OFFSET: [u8; 2] = [0x2E, 0x3A]; // Size of section header table; 2 bytes
pub const SHNUM_OFFSET: [u8; 2] = [0x30, 0x3C]; // Number of entries in section table pointer; 2 bytes pub const SHNUM_OFFSET: [u8; 2] = [0x30, 0x3C]; // Number of entries in section table pointer; 2 bytes
@ -105,47 +105,43 @@ pub struct FileHeader {
pub is_x86_64: bool, pub is_x86_64: bool,
pub endian: EndianType, pub endian: EndianType,
pub abi: u8, pub abi: u8,
pub abi_str: String, pub elf_type: u8,
pub elf_type: u16, pub isa: u8,
pub isa: u16, pub entryoff: u8,
pub isa_str: String, pub phoff: u8,
pub entryoff: u64, pub shoff: u8,
pub phoff: u64, pub ehsize: u8,
pub shoff: u64, pub phentsize: u8,
pub ehsize: u16, pub phnum: u8,
pub phentsize: u16, pub shentsize: u8,
pub phnum: u16, pub shnum: u8,
pub shentsize: u16, pub shstrndx: u8
pub shnum: u16,
pub shstrndx: u16
} }
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct ProgramHeader { pub struct ProgramHeader {
pub id: u16, pub program_type: u8,
pub program_type: u32, pub flags: u8,
pub flags: u32, pub offset: u8,
pub offset: u64, pub vaddr: u8,
pub vaddr: u64, pub paddr: u8,
pub paddr: u64, pub filesz: u8,
pub filesz: u64, pub memsz: u8,
pub memsz: u64, pub align: u8,
pub align: u64,
} }
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct SectionHeader { pub struct SectionHeader {
pub id: u16, pub name: u8,
pub name_idx: u32, pub section_type: u8,
pub section_type: u32, pub flags: u8,
pub flags: u64, pub addr: u8,
pub addr: u64, pub offset: u8,
pub offset: u64, pub size: u8,
pub size: u64, pub link: u8,
pub link: u32, pub info: u8,
pub info: u32, pub addralign: u8,
pub addralign: u64, pub entsize: u8
pub entsize: u64
} }

View File

@ -4,8 +4,6 @@
// Description: Main entrypoint script for chisel. Contains basic procedures // Description: Main entrypoint script for chisel. Contains basic procedures
// for gathering ELF file and program data. // for gathering ELF file and program data.
use iced_x86::{Decoder, DecoderOptions, Formatter, NasmFormatter, Instruction};
use std::collections::HashMap;
use std::path; use std::path;
use std::env; use std::env;
use std::fs; use std::fs;
@ -14,39 +12,19 @@ use std::process::exit;
// Import modules // Import modules
mod elf; mod elf;
mod util; mod util;
mod patcher;
fn main() { fn main() {
// Collect our execution args // Collect our execution args
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let mut inject_mode: bool = false;
let mut patch_file_path: &String = &"".to_string();
// Grab our filepath from our options // Grab our filepath from our options
if &args.len() < &2 { if &args.len() < &2 {
// No file given, terminate // No file given, terminate
util::print_help(); println!("[Error] Please provide a filepath to open");
exit(0); exit(0);
} }
// Check if the arguments we have include the patching flag and file
if &args.len() > &2 {
if &args[2] == "-p" {
if &args.len() >= &4 {
inject_mode = true;
patch_file_path = &args[3];
} else {
util::print_help();
exit(0);
}
} else {
// More than 1 arg but no patching flag given, terminate
util::print_help();
exit(0);
}
}
let file_path: &String = &args[1]; let file_path: &String = &args[1];
if path::Path::new(file_path).exists() { if path::Path::new(file_path).exists() {
@ -55,212 +33,127 @@ fn main() {
let contents: Result<Vec<u8>, std::io::Error> = fs::read(file_path); let contents: Result<Vec<u8>, std::io::Error> = fs::read(file_path);
if contents.is_ok() { if contents.is_ok() {
let bytes: &Vec<u8> = &contents.expect(""); let bytes: &Vec<u8> = &contents.expect("");
let magic_num: &[u8] = &bytes[0..4]; let magic_num: &[u8] = &bytes[0..4];
// Check to see if our file contains the ELF magic number
if magic_num == elf::MAGIC_NUMBER { if magic_num == elf::MAGIC_NUMBER {
println!("Found ELF Magic Number..."); println!("Found ELF Magic Number...");
println!("Parsing File Header..."); println!("Parsing File Header...");
// Build the File Header data structure // Build the File Header data structure
let file_header: elf::FileHeader = util::build_file_header(bytes); let file_header: elf::FileHeader = build_file_header(bytes);
println!("\t- Found {} program header entries {} bytes in length", file_header.phnum, file_header.phentsize);
println!("\t- Found {} section header entries {} bytes in length", file_header.shnum, file_header.shentsize);
println!("\t- Found .shstrtab section at index {}", file_header.shstrndx);
println!("\n==== File Header ====");
util::pp_file_header(&file_header);
println!("\nParsing Section Headers..."); // TODO: This is fundamentally wrong. Using the phentsize and phnum
// values from the file header, iterate over the program header
// table to find all of the individual program headers. There is
// not just one over-arching program header
// Determine the shstrtab offset.
// This is found by taking the string table index and multiplying it by the section header entry size, then
// adding this to the initial section header offset.
let shstrtab_offset: u64 = file_header.shoff + (file_header.shentsize as u64 * file_header.shstrndx as u64);
// Build a read-only version of the .shstrtab section
let shstrtab_section: elf::SectionHeader = util::build_section_header(
bytes,
shstrtab_offset as usize,
file_header.shstrndx,
file_header.is_x86_64
);
// Define all of our offsets for the shstrtab, and build a u8 buffer of the data
let shstrtab_start: u64 = shstrtab_section.offset;
let shstrtab_end: u64 = shstrtab_section.offset + shstrtab_section.size;
let shstrtab_data: Vec<u8> = bytes[shstrtab_start as usize..shstrtab_end as usize].to_vec();
println!("\t- Found .shstrtab section");
println!("\n==== Sections ====");
let mut section_table_map: HashMap<String, elf::SectionHeader> = HashMap::new();
let mut section_table_offset: u64 = file_header.shoff;
let mut section_table_count: i32 = 0;
// Iterate through number of section headers
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_idx as usize);
util::pp_section_header(&section_header, section_table_count, &section_name);
section_table_map.insert(section_name, section_header);
// Update the section table offset counter based on the section header size
section_table_offset += file_header.shentsize as u64;
section_table_count += 1;
}
println!("\nParsing Program Segments...");
println!("\n==== Program Segments ====");
let mut program_table_offset = file_header.phoff;
let mut program_table_count: i32 = 0;
let mut pt_note_index: usize = 0;
let mut pt_note_offset: usize = 0;
// Iterate through number of Program Headers
for i in 0..file_header.phnum {
// Build Program Header data structure // Build Program Header data structure
let program_header: elf::ProgramHeader = util::build_program_header( let program_header: elf::ProgramHeader = build_program_header(
bytes, bytes,
program_table_offset as usize, file_header.phoff,
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_index == 0) {
pt_note_offset = program_table_offset as usize;
pt_note_index = i 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
program_table_offset += file_header.phentsize as u64;
program_table_count += 1;
}
let note_segment: elf::ProgramHeader = util::build_program_header(
bytes,
pt_note_offset,
pt_note_index as u16,
file_header.is_x86_64 file_header.is_x86_64
); );
// Now that we have all the sections, spit out the .text section and start a linear disassembly // TODO: Same thing applies for the Section Headers...
let text_section: &elf::SectionHeader = section_table_map.get(".text").unwrap();
let text_section_offset: usize = text_section.offset as usize;
let text_section_end: usize = text_section_offset + text_section.size as usize;
// Buffer of text section data // Build Section Header data structure
let text_section_buff: &[u8] = &bytes[text_section_offset..text_section_end]; let section_header: elf::SectionHeader = build_section_header(
bytes,
// Offsets for resizing buffer file_header.shoff,
let mut instr_start: usize = 0; file_header.is_x86_64
let mut instr_end: usize = 1;
let mut ip_offset: u64 = text_section.offset;
// Define our instruction buffer
let mut instr_bytes: &[u8] = &text_section_buff[instr_start..instr_end];
// Define our decoder and icedx86 variables
let mut decoder: Decoder = Decoder::with_ip(64, instr_bytes, text_section.offset, DecoderOptions::NONE);
let mut formatter: NasmFormatter = NasmFormatter::new();
let mut instruction: Instruction = Instruction::default();
let mut output = String::new();
// Specify options for our NASM instruction formatter
// Formatting and linear sweep pattern partially borrowed from icedx86 docs
// https://docs.rs/iced-x86/latest/iced_x86/#disassemble-decode-and-format-instructions
formatter.options_mut().set_digit_separator("`");
formatter.options_mut().set_first_operand_char_index(10);
println!("==== Text Section Analysis ====\n");
while decoder.can_decode() {
// Decode the instruction sub-buffer
decoder.decode_out(&mut instruction);
if instruction.is_invalid() {
// Instruction invalid
// Increase the buffer size by 1, then try to parse again
instr_end = instr_end + 1;
instr_bytes = &text_section_buff[instr_start..instr_end];
decoder = Decoder::with_ip(64, instr_bytes, ip_offset, DecoderOptions::NONE);
} else {
// Got a valid instruction
// Format the instruction for printing
output.clear();
formatter.format(&instruction, &mut output);
// Print the instruction to an output assembly file
println!("{:016X}\t{}", instruction.ip(), output);
// Reset the buffer start to the end of the previous buffer, then try to parse again
instr_start = instr_end;
// If the instruction end index is less than the buffer, increase it
if (instr_end + 1) < text_section_buff.len() {
instr_end = instr_end + 1;
}
// Resize the instruction buffer and parse it again
instr_bytes = &text_section_buff[instr_start..instr_end];
ip_offset = text_section.offset + instr_start as u64;
decoder = Decoder::with_ip(64, instr_bytes, ip_offset, DecoderOptions::NONE);
}
}
if inject_mode {
println!("\n==== Injecting Payload To Binary ====\n");
patcher::patch_binary(
bytes.to_vec(),
file_path.to_string(),
&patch_file_path,
&file_header,
section_table_map,
note_segment
); );
}
println!("{:?}", file_header);
println!("{:?}", program_header);
println!("{:?}", section_header);
} else { } else {
println!("[Error] Could not find magic number, is this an ELF executable?") println!("[Error] Could not find magic number, is this an ELF executable?")
} }
} }
} else { } else {
println!("[Error] File '{}' does not exist", file_path); println!("[Error] '{}' does not exist", file_path);
exit(-1); exit(-1);
} }
return; return;
} }
fn build_file_header(data: &Vec<u8>) -> elf::FileHeader {
// Determine x86 or x64 architecture
// 0 : x86
// 1 : x64
let arch: usize = (data[elf::ARCH_OFFSET as usize] - 1).into();
let file_header: elf::FileHeader = elf::FileHeader {
arch: util::parse_architecture(data[elf::ARCH_OFFSET as usize]),
is_x86_64: arch != 0,
endian: util::parse_endian(data[elf::ENDIAN_OFFSET as usize]),
abi: data[elf::ABI_OFFSET as usize],
elf_type: data[elf::TYPE_OFFSET as usize],
isa: data[elf::MACHINE_OFFSET as usize],
entryoff: data[elf::ENTRYPOINT_OFFSET as usize],
phoff: data[elf::PHOFF_OFFSET[arch] as usize],
shoff: data[elf::SHOFF_OFFSET[arch] as usize],
ehsize: data[elf::EHSIZE_OFFSET[arch] as usize],
phentsize: data[elf::PHENTSIZE_OFFSET[arch] as usize],
phnum: data[elf::PHNUM_OFFSET[arch] as usize],
shentsize: data[elf::SHENTSIZE_OFFSET[arch] as usize],
shnum: data[elf::SHNUM_OFFSET[arch] as usize],
shstrndx: data[elf::SHSTRNDX_OFFSET[arch] as usize],
};
return file_header;
}
fn build_program_header(data: &Vec<u8>, phoffset: u8, is_x86_64: bool) -> elf::ProgramHeader {
// Cast the supplied is_x86_64 bool to an array offset
// 0 : x86
// 1 : x64
let arch: usize = is_x86_64.into();
let program_header: elf::ProgramHeader = elf::ProgramHeader {
program_type: data[(elf::PH_TYPE_OFFSET + phoffset) as usize],
flags: data[(elf::PH_FLAGS_OFFSET[arch] + phoffset) as usize],
offset: data[(elf::PH_OFFSET_OFFSET[arch] + phoffset) as usize],
vaddr: data[(elf::PH_VADDR_OFFSET[arch] + phoffset) as usize],
paddr: data[(elf::PH_PADDR_OFFSET[arch] + phoffset) as usize],
filesz: data[(elf::PH_FILESZ_OFFSET[arch] + phoffset) as usize],
memsz: data[(elf::PH_MEMSZ_OFFSET[arch] + phoffset) as usize],
align: data[(elf::PH_ALIGN_OFFSET[arch] + phoffset) as usize],
};
return program_header;
}
fn build_section_header(data: &Vec<u8>, shoffset: u8, is_x86_64: bool) -> elf::SectionHeader {
// Cast the supplied is_x86_64 bool to an array offset
// 0 : x86
// 1 : x64
let arch: usize = is_x86_64.into();
let section_header: elf::SectionHeader = elf::SectionHeader {
name: data[(elf::SH_NAME_OFFSET + shoffset) as usize],
section_type: data[(elf::SH_TYPE_OFFSET + shoffset) as usize],
flags: data[(elf::SH_FLAGS_OFFSET + shoffset) as usize],
addr: data[(elf::SH_ADDR_OFFSET[arch] + shoffset) as usize],
offset: data[(elf::SH_OFFSET_OFFSET[arch] + shoffset) as usize],
size: data[(elf::SH_SIZE_OFFSET[arch] + shoffset) as usize],
link: data[(elf::SH_LINK_OFFSET[arch] + shoffset) as usize],
info: data[(elf::SH_INFO_OFFSET[arch] + shoffset) as usize],
addralign: data[(elf::SH_ADDRALIGN_OFFSET[arch] + shoffset) as usize],
entsize: data[(elf::SH_ENTSIZE_OFFSET[arch] + shoffset) as usize],
};
return section_header;
}

View File

@ -1,130 +0,0 @@
// patcher.rs
// Author: Garrett Dickinson
// Created: 04/06/2023
// 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,
file_header: &elf::FileHeader,
section_header_map: HashMap<String, elf::SectionHeader>,
note_segment: elf::ProgramHeader) {
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;
// Apply patch to end of binary
print!("Patch data read successfully, injecting at end of binary...");
let injection_offset: usize = program_data.len();
let injection_size: usize = patch_data.len();
let injection_addr: usize = injection_offset;
program_data.extend_from_slice(patch_data);
println!("Done!");
// Locate a note segment
print!("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!");
println!("Done!\n");
println!("Note section address: {:#04x}", note_section.addr);
println!("Note section offset: {:#04x}", note_section.offset);
println!("Note section size: {}\n", note_section.size);
println!("Injected address: {:#04x}", injection_addr);
println!("Injected section offset: {:#04x}", injection_offset);
println!("Injected section size: {}\n", 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;
injected_section.addralign = 16;
injected_section.flags = 6;
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 program segment
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.phoff as usize,
file_header.phentsize as usize,
injected_segment.id as usize,
&injected_segment,
file_header.is_x86_64
);
// Rewrite the program entrypoint
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(&program_data)
.expect("[Error] Could not write to patched binary data file");
}
fn read_patch_file(patch_path: &String) -> Result<Vec<u8>, std::io::Error> {
if path::Path::new(patch_path).exists() && patch_path.ends_with(".bin") {
println!("Patch file exists, reading '{}'...", patch_path);
let contents: Result<Vec<u8>, std::io::Error> = fs::read(patch_path);
return contents;
} else {
println!("[Error] Patch file '{}' is invalid or cannot be read, exiting...", patch_path);
std::process::exit(0);
}
}

View File

@ -1,111 +0,0 @@
// 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);
}
}

View File

@ -4,216 +4,9 @@
// Description: Utility script for storing common-use and helper // Description: Utility script for storing common-use and helper
// functions. // functions.
use std::mem;
// use std::io::{self, BufReader, BufRead};
// use std::fs::File;
// use std::num::ParseIntError;
use crate::elf::{self, EndianType, ArchitectureType}; use crate::elf::{self, EndianType, ArchitectureType};
pub fn build_file_header(data: &Vec<u8>) -> elf::FileHeader {
// Determine x86 or x64 architecture
// 0 : x86
// 1 : x64
let arch: usize = (data[elf::ARCH_OFFSET as usize] - 1).into();
let file_header: elf::FileHeader = elf::FileHeader {
arch: parse_architecture(data[elf::ARCH_OFFSET as usize]),
is_x86_64: arch != 0,
endian: parse_endian(data[elf::ENDIAN_OFFSET as usize]),
abi: data[elf::ABI_OFFSET as usize],
abi_str: parse_abi(data[elf::ABI_OFFSET as usize]),
elf_type: u16_from_buffer(data, elf::TYPE_OFFSET as usize),
isa: u16_from_buffer(data, elf::MACHINE_OFFSET as usize),
isa_str: parse_isa(u16_from_buffer(data, elf::MACHINE_OFFSET as usize)),
entryoff: u64_from_buffer(data, elf::ENTRYPOINT_OFFSET as usize),
phoff: u64_from_buffer(data, elf::PHOFF_OFFSET[arch] as usize),
shoff: u64_from_buffer(data, elf::SHOFF_OFFSET[arch] as usize),
ehsize: u16_from_buffer(data, elf::EHSIZE_OFFSET[arch] as usize),
phentsize: u16_from_buffer(data, elf::PHENTSIZE_OFFSET[arch] as usize),
phnum: u16_from_buffer(data, elf::PHNUM_OFFSET[arch] as usize),
shentsize: u16_from_buffer(data, elf::SHENTSIZE_OFFSET[arch] as usize),
shnum: u16_from_buffer(data, elf::SHNUM_OFFSET[arch] as usize),
shstrndx: u16_from_buffer(data, elf::SHSTRNDX_OFFSET[arch] as usize),
};
return file_header;
}
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
// 1 : x64
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),
vaddr: u64_from_buffer(data, phoffset + elf::PH_VADDR_OFFSET[arch] as usize),
paddr: u64_from_buffer(data, phoffset + elf::PH_PADDR_OFFSET[arch] as usize),
filesz: u64_from_buffer(data, phoffset + elf::PH_FILESZ_OFFSET[arch] as usize),
memsz: u64_from_buffer(data, phoffset + elf::PH_MEMSZ_OFFSET[arch] as usize),
align: u64_from_buffer(data, phoffset + elf::PH_ALIGN_OFFSET[arch] as usize)
};
return program_header;
}
pub fn overwrite_segment_header(
program_data: &mut Vec<u8>,
phoffset: usize,
phentsize: usize,
phentidx: usize,
new_segment: &elf::ProgramHeader,
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!("phoffset {}", phoffset);
println!("phentsize {}", phentsize);
println!("phentidx {}", phentidx);
let segment_type_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_TYPE_OFFSET as usize;
let segment_offset_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_OFFSET_OFFSET[arch] as usize;
let segment_vaddr_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_VADDR_OFFSET[arch] as usize;
let segment_paddr_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_PADDR_OFFSET[arch] as usize;
let segment_filesz_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_FILESZ_OFFSET[arch] as usize;
let segment_memsz_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_MEMSZ_OFFSET[arch] as usize;
let segment_flags_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_FLAGS_OFFSET[arch] as usize;
let segment_align_offset: usize = phoffset + (phentsize * phentidx) + elf::PH_ALIGN_OFFSET[arch] as usize;
program_data[segment_type_offset..segment_type_offset+4].copy_from_slice(
&new_segment.program_type.to_ne_bytes().to_vec());
println!("Overwriting segment type with {:#04x}", new_segment.program_type);
program_data[segment_offset_offset..segment_offset_offset+8].copy_from_slice(
&new_segment.offset.to_ne_bytes().to_vec());
println!("Overwriting segment offset with {:#04x}", new_segment.offset);
program_data[segment_vaddr_offset..segment_vaddr_offset+8].copy_from_slice(
&new_segment.vaddr.to_ne_bytes().to_vec());
println!("Overwriting segment vaddr with {:#04x}", new_segment.vaddr);
program_data[segment_paddr_offset..segment_paddr_offset+8].copy_from_slice(
&new_segment.paddr.to_ne_bytes().to_vec());
println!("Overwriting segment paddr with {:#04x}", new_segment.paddr);
program_data[segment_filesz_offset..segment_filesz_offset+8].copy_from_slice(
&new_segment.filesz.to_ne_bytes().to_vec());
println!("Overwriting segment filesz with {:#04x}", new_segment.filesz);
program_data[segment_memsz_offset..segment_memsz_offset+8].copy_from_slice(
&new_segment.memsz.to_ne_bytes().to_vec());
println!("Overwriting segment memsz with {:#04x}", new_segment.memsz);
program_data[segment_flags_offset..segment_flags_offset+4].copy_from_slice(
&new_segment.flags.to_ne_bytes().to_vec());
println!("Overwriting segment flag with {:#04x}", new_segment.flags);
program_data[segment_align_offset..segment_align_offset+8].copy_from_slice(
&new_segment.align.to_ne_bytes().to_vec());
println!("Overwriting segment alignment with {:#04x}\n", new_segment.align);
}
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
// 1 : x64
let arch: usize = is_x86_64.into();
let section_header: elf::SectionHeader = elf::SectionHeader {
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;
let section_flag_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_FLAGS_OFFSET as usize;
let section_align_offset: usize = stoffset + (shentsize * shentidx) + elf::SH_ADDRALIGN_OFFSET[arch] 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);
program_data[section_flag_offset..section_flag_offset+8].copy_from_slice(
&new_section.flags.to_ne_bytes().to_vec());
println!("Overwriting section flags with {:#04x}", new_section.flags as usize);
program_data[section_align_offset..section_align_offset+8].copy_from_slice(
&new_section.addralign.to_ne_bytes().to_vec());
println!("Overwriting section address alignment with {:#04x}\n", new_section.addralign 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()
);
println!("Overwriting program entrypoint with {:#04x}\n", new_entry_point as usize);
}
pub fn parse_endian(endian: u8) -> elf::EndianType { pub fn parse_endian(endian: u8) -> elf::EndianType {
match endian { match endian {
0x00 => return EndianType::Big, 0x00 => return EndianType::Big,
@ -234,7 +27,7 @@ pub fn parse_architecture(arch: u8) -> elf::ArchitectureType {
pub fn parse_abi(abi: u8) -> String { pub fn parse_abi(abi: u8) -> String {
match abi { match abi {
0x00 => "System V".to_string(), 0x00 => "SystemV".to_string(),
0x01 => "HP-UX".to_string(), 0x01 => "HP-UX".to_string(),
0x02 => "NetBSD".to_string(), 0x02 => "NetBSD".to_string(),
0x03 => "Linux".to_string(), 0x03 => "Linux".to_string(),
@ -252,7 +45,7 @@ pub fn parse_abi(abi: u8) -> String {
} }
pub fn parse_isa(isa: u16) -> String { pub fn parse_isa(isa: u8) -> String {
match isa { match isa {
0x03 => "Intel x86".to_string(), 0x03 => "Intel x86".to_string(),
0x3E => "AMD x86-64".to_string(), 0x3E => "AMD x86-64".to_string(),
@ -263,230 +56,9 @@ pub fn parse_isa(isa: u16) -> String {
0x32 => "IA_64".to_string(), 0x32 => "IA_64".to_string(),
0x28 => "Arm".to_string(), 0x28 => "Arm".to_string(),
0xB7 => "Arm 64-bit".to_string(), 0xB7 => "Arm 64-bit".to_string(),
0xF3 => "RISC-V".to_string(),
// Match unknown ISA // Match unknown ISA
_ => "Unknown".to_string() _ => "Unknown".to_string()
} }
} }
pub fn u16_from_buffer(buff: &Vec<u8>, index: usize) -> u16 {
const SIZE: usize = mem::size_of::<u16>();
let mut slice: [u8; SIZE] = [0; SIZE];
slice.copy_from_slice(&buff[index..index+SIZE]);
let value: u16 = u16::from_ne_bytes(slice);
return value;
}
pub fn u32_from_buffer(buff: &Vec<u8>, index: usize) -> u32 {
const SIZE: usize = mem::size_of::<u32>();
let mut slice: [u8; SIZE] = [0; SIZE];
slice.copy_from_slice(&buff[index..index+SIZE]);
let value: u32 = u32::from_ne_bytes(slice);
return value;
}
pub fn u64_from_buffer(buff: &Vec<u8>, index: usize) -> u64 {
const SIZE: usize = mem::size_of::<u64>();
let mut slice: [u8; SIZE] = [0; SIZE];
slice.copy_from_slice(&buff[index..index+SIZE]);
let value: u64 = u64::from_ne_bytes(slice);
return value;
}
pub fn parse_section_name(buff: &Vec<u8>, index: usize) -> String {
let mut name: Vec<u8> = Vec::new();
let mut char_ctr: usize = index;
let mut char: u8 = buff[index];
while char != 0x00 {
name.push(char);
char_ctr += 1;
char = buff[char_ctr];
}
let result = String::from_utf8(name).expect("[Error] Failed to parse section name!");
return result;
}
pub fn parse_elf_type(elf_type: u16) -> String {
match elf_type {
0x0000 => "Unknown".to_string(),
0x0001 => "Relocatable file".to_string(),
0x0002 => "Executable file".to_string(),
0x0003 => "Shared object".to_string(),
0x0004 => "Core file".to_string(),
0xFE00 => "Reserved, operating system specific".to_string(),
0xFEFF => "Reserved, operating system specific".to_string(),
0xFF00 => "Reserved, processor specific".to_string(),
0xFFFF => "Reserved, processor specific".to_string(),
// Match unknown segment type
_ => "UNKNOWN".to_string()
}
}
pub fn parse_section_type(section_type: u32) -> String {
match section_type {
0x00000000 => "SHT_NULL".to_string(),
0x00000001 => "SHT_PROGBITS".to_string(),
0x00000002 => "SHT_SYMTAB".to_string(),
0x00000003 => "SHT_STRTAB".to_string(),
0x00000004 => "SHT_RELA".to_string(),
0x00000005 => "SHT_HASH".to_string(),
0x00000006 => "SHT_DYNAMIC".to_string(),
0x00000007 => "SHT_NOTE".to_string(),
0x00000008 => "SHT_NOBITS".to_string(),
0x00000009 => "SHT_REL".to_string(),
0x0000000A => "SHT_SHLIB".to_string(),
0x0000000B => "SHT_DYNSYM".to_string(),
0x0000000E => "SHT_INIT_ARRAY".to_string(),
0x0000000F => "SHT_FINI_ARRAY".to_string(),
0x00000010 => "SHT_PREINIT_ARRAY".to_string(),
0x00000011 => "SHT_GROUP".to_string(),
0x00000012 => "SHT_SYMTAB_SHNDX".to_string(),
0x00000013 => "SHT_NUM".to_string(),
0x60000000 => "SHT_LOOS".to_string(),
// Match unknown segment type
_ => "UNKNOWN".to_string()
}
}
pub fn parse_section_flags(flags: u64) -> String {
match flags {
0x00000001 => "SHF_WRITE".to_string(),
0x00000002 => "SHF_ALLOC".to_string(),
0x00000004 => "SHF_EXECINSTR".to_string(),
0x00000010 => "SHF_MERGE".to_string(),
0x00000020 => "SHF_STRINGS".to_string(),
0x00000040 => "SHF_INFO_LINK".to_string(),
0x00000080 => "SHF_LINK_ORDER".to_string(),
0x00000100 => "SHF_OS_NONCONFORMING".to_string(),
0x00000200 => "SHF_GROUP".to_string(),
0x00000400 => "SHF_TLS".to_string(),
0x0FF00000 => "SHF_MASKOS".to_string(),
0xF0000000 => "SHF_MASKPROC".to_string(),
0x40000000 => "SHF_ORDERED".to_string(),
0x80000000 => "SHF_EXCLUDE".to_string(),
// Match unknown segment type
_ => "UNKNOWN".to_string()
}
}
pub fn parse_program_segment_type(segment_type: u32) -> String {
match segment_type {
0x00000000 => "PT_NULL".to_string(),
0x00000001 => "PT_LOAD".to_string(),
0x00000002 => "PT_DYNAMIC".to_string(),
0x00000003 => "PT_INTERP".to_string(),
0x00000004 => "PT_NOTE".to_string(),
0x00000005 => "PT_SHLIB".to_string(),
0x00000006 => "PT_PHDR".to_string(),
0x00000007 => "PT_TLS".to_string(),
0x60000000 => "PT_LOOS".to_string(),
0x6FFFFFFF => "PT_HIOS".to_string(),
0x70000000 => "PT_LOPROC".to_string(),
0x7FFFFFFF => "PT_HIPROC".to_string(),
// Match unknown segment type
_ => "UNKNOWN".to_string()
}
}
pub fn pp_file_header(header: &elf::FileHeader) {
println!("- Architecture: {:?}", header.arch);
println!("- Endian: {:?}", header.endian);
println!("- ABI: {}", header.abi_str);
println!("- Type: {}", parse_elf_type(header.elf_type));
println!("- ISA: {}", header.isa_str);
println!("- Entry Point: {:#04x}", header.entryoff);
println!("- Program Offset: {:#04x}", header.phoff);
println!("- Program Entry Size: {}", header.phentsize);
println!("- Number Program Entries: {}", header.phnum);
println!("- Section Offset: {:#04x}", header.shoff);
println!("- Section Entry Size: {}", header.shentsize);
println!("- Number Section Entries: {}", header.shnum);
}
pub fn pp_section_header(header: &elf::SectionHeader, number: i32, name: &String) {
println!("[{}] {}", number, name);
println!("\t- Type: {}", parse_section_type(header.section_type));
println!("\t- Flags: {}", parse_section_flags(header.flags));
println!("\t- Flags (Value): {}", header.flags);
println!("\t- Address: {:#04x}", header.section_type);
println!("\t- Offset: {:#04x}", header.section_type);
println!("\t- Link Index: {}", header.link);
println!("\t- Info Bytes: {}", header.info);
println!("\t- Alignment: {}", header.info);
println!();
}
pub fn pp_program_header(header: &elf::ProgramHeader, number: i32, ph_type: &String) {
println!("[{}] {}", number, ph_type);
println!("\t- Type: {}", parse_section_type(header.program_type));
println!("\t- Flags: {}", header.flags);
println!("\t- Offset: {:#04x}", header.offset);
println!("\t- Virtual Address: {:#04x}", header.vaddr);
println!("\t- Physical Address: {:#04x}", header.paddr);
println!("\t- File Size: {}", header.filesz);
println!("\t- Memory Size: {}", header.memsz);
println!("\t- Alignment: {}", header.align);
println!();
}
pub fn print_help() {
print!("Usage: chisel [EXECUTABLE] [-p] [PATCH_FILE]\n\n \
Options:\n \
\t-p\t\tToggle binary patching mode\n");
}
// 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()
// }
// 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();
// }

Binary file not shown.

View File

@ -1,32 +0,0 @@
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

Binary file not shown.

View File

@ -1,3 +1 @@
hello world hello world
this flat file should fail
because it doesn't have the ELF magic keyword

Binary file not shown.

46
testing/src/hello.s Normal file
View File

@ -0,0 +1,46 @@
.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:

View File

@ -1,32 +0,0 @@
#include <stdio.h>
int main() {
int n, i, flag = 0;
printf("Enter a positive integer: ");
scanf("%d", &n);
// 0 and 1 are not prime numbers
// change flag to 1 for non-prime number
if (n == 0 || n == 1)
flag = 1;
for (i = 2; i <= n / 2; ++i) {
// if n is divisible by i, then n is not prime
// change flag to 1 for non-prime number
if (n % i == 0) {
flag = 1;
break;
}
}
// flag is 0 for prime numbers
if (flag == 0) {
printf("%d is a prime number.", n);
}
else {
printf("%d is not a prime number.", n);
}
}