Finish linear sweep implementation, add polish, update README
This commit is contained in:
parent
f56400d124
commit
0d227f10af
22
README.md
22
README.md
|
|
@ -4,4 +4,24 @@
|
||||||
|
|
||||||
## Supported Binary formats
|
## Supported Binary 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
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ chisel [path to ELF executable]
|
||||||
|
```
|
||||||
|
|
|
||||||
188
src/main.rs
188
src/main.rs
|
|
@ -4,9 +4,8 @@
|
||||||
// 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::*;
|
use iced_x86::{Decoder, DecoderOptions, Formatter, NasmFormatter, Instruction};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::Write;
|
|
||||||
use std::path;
|
use std::path;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
@ -36,53 +35,59 @@ 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 = build_file_header(bytes);
|
let file_header: elf::FileHeader = util::build_file_header(bytes);
|
||||||
|
|
||||||
println!("\t- Found {} program header entries {} bytes in length", file_header.phnum, file_header.phentsize);
|
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 {} section header entries {} bytes in length", file_header.shnum, file_header.shentsize);
|
||||||
println!("\t- Found .shstrtab section at index {}", file_header.shstrndx);
|
println!("\t- Found .shstrtab section at index {}", file_header.shstrndx);
|
||||||
|
|
||||||
println!("{:?}", file_header);
|
println!("\n==== File Header ====");
|
||||||
|
util::pp_file_header(&file_header);
|
||||||
|
|
||||||
|
|
||||||
println!("\nParsing Section Headers...");
|
println!("\nParsing Section Headers...");
|
||||||
|
|
||||||
|
|
||||||
// Determine the shstrtab offset.
|
// Determine the shstrtab offset.
|
||||||
// This is found by taking the string table index and multiplying it by the section header entry size, then
|
// 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.
|
// 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);
|
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
|
// Build a read-only version of the .shstrtab section
|
||||||
let shstrtab_section: elf::SectionHeader = build_section_header(
|
let shstrtab_section: elf::SectionHeader = util::build_section_header(
|
||||||
bytes,
|
bytes,
|
||||||
shstrtab_offset as usize,
|
shstrtab_offset as usize,
|
||||||
file_header.is_x86_64
|
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_start: u64 = shstrtab_section.offset;
|
||||||
let shstrtab_end: u64 = shstrtab_section.offset + shstrtab_section.size;
|
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();
|
let shstrtab_data: Vec<u8> = bytes[shstrtab_start as usize..shstrtab_end as usize].to_vec();
|
||||||
|
|
||||||
println!("\t- Found .shstrtab section");
|
println!("\t- Found .shstrtab section");
|
||||||
|
|
||||||
|
println!("\n==== Sections ====");
|
||||||
println!("\n=== Sections ===");
|
|
||||||
|
|
||||||
let mut section_table_map: HashMap<String, elf::SectionHeader> = HashMap::new();
|
let mut section_table_map: HashMap<String, elf::SectionHeader> = HashMap::new();
|
||||||
let mut section_table_offset: u64 = file_header.shoff;
|
let mut section_table_offset: u64 = file_header.shoff;
|
||||||
let mut section_table_count: i32 = 0;
|
let mut section_table_count: i32 = 0;
|
||||||
|
|
||||||
// Build Section Header data structure
|
// Iterate through number of section headers
|
||||||
for _ in 0..file_header.shnum {
|
for _ in 0..file_header.shnum {
|
||||||
let section_header: elf::SectionHeader = build_section_header(
|
|
||||||
|
// Build section header data structure
|
||||||
|
let section_header: elf::SectionHeader = util::build_section_header(
|
||||||
bytes,
|
bytes,
|
||||||
section_table_offset as usize,
|
section_table_offset as usize,
|
||||||
file_header.is_x86_64
|
file_header.is_x86_64
|
||||||
|
|
@ -91,37 +96,37 @@ fn main() {
|
||||||
// Determine the section name for each section using the shstrtab data
|
// 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 as usize);
|
||||||
|
|
||||||
println!("[{}] {}", section_table_count, section_name);
|
util::pp_section_header(§ion_header, section_table_count, §ion_name);
|
||||||
println!("{:?}", section_header);
|
|
||||||
|
|
||||||
section_table_map.insert(section_name, section_header);
|
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_offset += file_header.shentsize as u64;
|
||||||
section_table_count += 1;
|
section_table_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("\nParsing Program Segments...");
|
println!("\nParsing Program Segments...");
|
||||||
|
|
||||||
println!("\n=== Program Segments ===");
|
println!("\n==== Program Segments ====");
|
||||||
|
|
||||||
let mut program_table_offset = file_header.phoff;
|
let mut program_table_offset = file_header.phoff;
|
||||||
let mut program_table_count: i32 = 0;
|
let mut program_table_count: i32 = 0;
|
||||||
|
|
||||||
// Build Section Header data structure
|
// Iterate through number of Program Headers
|
||||||
for _ in 0..file_header.phnum {
|
for _ in 0..file_header.phnum {
|
||||||
// Build Program Header data structure
|
// Build Program Header data structure
|
||||||
let program_header: elf::ProgramHeader = build_program_header(
|
let program_header: elf::ProgramHeader = util::build_program_header(
|
||||||
bytes,
|
bytes,
|
||||||
program_table_offset as usize,
|
program_table_offset as usize,
|
||||||
file_header.is_x86_64
|
file_header.is_x86_64
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set a default section name if there's no index found in the table
|
// Parse the program name using the program type
|
||||||
let program_name: String = util::parse_program_segment_type(program_header.program_type);
|
let program_name: String = util::parse_program_segment_type(program_header.program_type);
|
||||||
|
|
||||||
println!("[{}] {}", program_table_count, program_name);
|
util::pp_program_header(&program_header, program_table_count, &program_name);
|
||||||
println!("{:?}", program_header);
|
|
||||||
|
|
||||||
|
// Update the program header table offset counter based on the program header size
|
||||||
program_table_offset += file_header.phentsize as u64;
|
program_table_offset += file_header.phentsize as u64;
|
||||||
program_table_count += 1;
|
program_table_count += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -132,23 +137,69 @@ fn main() {
|
||||||
let text_section_offset: usize = text_section.offset as usize;
|
let text_section_offset: usize = text_section.offset as usize;
|
||||||
let text_section_end: usize = text_section_offset + text_section.size as usize;
|
let text_section_end: usize = text_section_offset + text_section.size as usize;
|
||||||
|
|
||||||
|
// Buffer of text section data
|
||||||
let text_section_buff: &[u8] = &bytes[text_section_offset..text_section_end];
|
let text_section_buff: &[u8] = &bytes[text_section_offset..text_section_end];
|
||||||
|
|
||||||
let mut decoder: Decoder = Decoder::new(64, text_section_buff, DecoderOptions::NONE);
|
// Offsets for resizing buffer
|
||||||
|
let mut instr_start: usize = 0;
|
||||||
|
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 instruction: Instruction = Instruction::default();
|
||||||
let instruction_start: u64 = 0;
|
let mut output = String::new();
|
||||||
let instruction_length: u64 = 1;
|
|
||||||
|
|
||||||
while (instruction_start + instruction_length) < text_section.size {
|
// Specify options for our NASM instruction formatter
|
||||||
//let instruction_bytes: &[u8] = &text_section_buff[instruction_start..instruction_length];
|
// Formatting and linear sweep pattern partially borrowed from icedx86 docs
|
||||||
//instruction.
|
// https://docs.rs/iced-x86/latest/iced_x86/#disassemble-decode-and-format-instructions
|
||||||
//decoder.decode_out(instruction)
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//let out_file = fs::File::create("out.s").unwrap();
|
|
||||||
//out_file.write()
|
|
||||||
//out_file.flush();
|
|
||||||
|
|
||||||
} 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?")
|
||||||
}
|
}
|
||||||
|
|
@ -159,81 +210,4 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
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],
|
|
||||||
abi_str: util::parse_abi(data[elf::ABI_OFFSET as usize]),
|
|
||||||
elf_type: util::u16_from_buffer(data, elf::TYPE_OFFSET as usize),
|
|
||||||
isa: util::u16_from_buffer(data, elf::MACHINE_OFFSET as usize),
|
|
||||||
isa_str: util::parse_isa(util::u16_from_buffer(data, elf::MACHINE_OFFSET as usize)),
|
|
||||||
entryoff: util::u64_from_buffer(data, elf::ENTRYPOINT_OFFSET as usize),
|
|
||||||
phoff: util::u64_from_buffer(data, elf::PHOFF_OFFSET[arch] as usize),
|
|
||||||
shoff: util::u64_from_buffer(data, elf::SHOFF_OFFSET[arch] as usize),
|
|
||||||
ehsize: util::u16_from_buffer(data, elf::EHSIZE_OFFSET[arch] as usize),
|
|
||||||
phentsize: util::u16_from_buffer(data, elf::PHENTSIZE_OFFSET[arch] as usize),
|
|
||||||
phnum: util::u16_from_buffer(data, elf::PHNUM_OFFSET[arch] as usize),
|
|
||||||
shentsize: util::u16_from_buffer(data, elf::SHENTSIZE_OFFSET[arch] as usize),
|
|
||||||
shnum: util::u16_from_buffer(data, elf::SHNUM_OFFSET[arch] as usize),
|
|
||||||
shstrndx: util::u16_from_buffer(data, elf::SHSTRNDX_OFFSET[arch] as usize),
|
|
||||||
};
|
|
||||||
|
|
||||||
return file_header;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn build_program_header(data: &Vec<u8>, phoffset: usize, 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: util::u32_from_buffer(data, phoffset + elf::PH_TYPE_OFFSET as usize),
|
|
||||||
flags: util::u32_from_buffer(data, phoffset + elf::PH_FLAGS_OFFSET[arch] as usize),
|
|
||||||
offset: util::u64_from_buffer(data, phoffset + elf::PH_OFFSET_OFFSET[arch] as usize),
|
|
||||||
vaddr: util::u64_from_buffer(data, phoffset + elf::PH_VADDR_OFFSET[arch] as usize),
|
|
||||||
paddr: util::u64_from_buffer(data, phoffset + elf::PH_PADDR_OFFSET[arch] as usize),
|
|
||||||
filesz: util::u64_from_buffer(data, phoffset + elf::PH_FILESZ_OFFSET[arch] as usize),
|
|
||||||
memsz: util::u64_from_buffer(data, phoffset + elf::PH_MEMSZ_OFFSET[arch] as usize),
|
|
||||||
align: util::u64_from_buffer(data, phoffset + elf::PH_ALIGN_OFFSET[arch] as usize)
|
|
||||||
};
|
|
||||||
|
|
||||||
return program_header;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn build_section_header(data: &Vec<u8>, shoffset: usize, 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: util::u32_from_buffer(data, shoffset + elf::SH_NAME_OFFSET as usize),
|
|
||||||
section_type: util::u32_from_buffer(data, shoffset + elf::SH_TYPE_OFFSET as usize),
|
|
||||||
flags: util::u64_from_buffer(data, shoffset + elf::SH_FLAGS_OFFSET as usize),
|
|
||||||
addr: util::u64_from_buffer(data, shoffset + elf::SH_ADDR_OFFSET[arch] as usize),
|
|
||||||
offset: util::u64_from_buffer(data, shoffset + elf::SH_OFFSET_OFFSET[arch] as usize),
|
|
||||||
size: util::u64_from_buffer(data, shoffset + elf::SH_SIZE_OFFSET[arch] as usize),
|
|
||||||
link: util::u32_from_buffer(data, shoffset + elf::SH_LINK_OFFSET[arch] as usize),
|
|
||||||
info: util::u32_from_buffer(data, shoffset + elf::SH_INFO_OFFSET[arch] as usize),
|
|
||||||
addralign: util::u64_from_buffer(data, shoffset + elf::SH_ADDRALIGN_OFFSET[arch] as usize),
|
|
||||||
entsize: util::u64_from_buffer(data, shoffset + elf::SH_ENTSIZE_OFFSET[arch] as usize)
|
|
||||||
};
|
|
||||||
|
|
||||||
return section_header;
|
|
||||||
}
|
}
|
||||||
196
src/util.rs
196
src/util.rs
|
|
@ -9,6 +9,83 @@ use std::mem;
|
||||||
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, 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: 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 build_section_header(data: &Vec<u8>, shoffset: usize, 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: 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)
|
||||||
|
};
|
||||||
|
|
||||||
|
return section_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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,
|
||||||
|
|
@ -29,7 +106,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 => "SystemV".to_string(),
|
0x00 => "System V".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(),
|
||||||
|
|
@ -113,12 +190,81 @@ pub fn parse_section_name(buff: &Vec<u8>, index: usize) -> String {
|
||||||
char = buff[char_ctr];
|
char = buff[char_ctr];
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = String::from_utf8(name).expect("Failed to parse section name!");
|
let result = String::from_utf8(name).expect("[Error] Failed to parse section name!");
|
||||||
|
|
||||||
return result;
|
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 {
|
pub fn parse_program_segment_type(segment_type: u32) -> String {
|
||||||
match segment_type {
|
match segment_type {
|
||||||
0x00000000 => "PT_NULL".to_string(),
|
0x00000000 => "PT_NULL".to_string(),
|
||||||
|
|
@ -137,4 +283,48 @@ pub fn parse_program_segment_type(segment_type: u32) -> String {
|
||||||
// Match unknown segment type
|
// Match unknown segment type
|
||||||
_ => "UNKNOWN".to_string()
|
_ => "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- 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!();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
104
test_run
104
test_run
|
|
@ -1,104 +0,0 @@
|
||||||
File exists, reading 'testing/hello'...
|
|
||||||
Found ELF Magic Number...
|
|
||||||
Parsing File Header...
|
|
||||||
- Found 13 program header entries 56 bytes in length
|
|
||||||
- Found 31 section header entries 64 bytes in length
|
|
||||||
- Found .shstrtab section at index 30
|
|
||||||
FileHeader { arch: X86_64, is_x86_64: true, endian: Little, abi: 0, abi_str: "SystemV", elf_type: 3, isa: 62, isa_str: "AMD x86-64", entryoff: 4192, phoff: 64, shoff: 13976, ehsize: 64, phentsize: 56, phnum: 13, shentsize: 64, shnum: 31, shstrndx: 30 }
|
|
||||||
|
|
||||||
Parsing Section Headers...
|
|
||||||
- Found .shstrtab section
|
|
||||||
|
|
||||||
=== Sections ===
|
|
||||||
[0]
|
|
||||||
SectionHeader { name: 0, section_type: 0, flags: 0, addr: 0, offset: 0, size: 0, link: 0, info: 0, addralign: 0, entsize: 0 }
|
|
||||||
[1] .interp
|
|
||||||
SectionHeader { name: 27, section_type: 1, flags: 2, addr: 792, offset: 792, size: 28, link: 0, info: 0, addralign: 1, entsize: 0 }
|
|
||||||
[2] .note.gnu.property
|
|
||||||
SectionHeader { name: 35, section_type: 7, flags: 2, addr: 824, offset: 824, size: 48, link: 0, info: 0, addralign: 8, entsize: 0 }
|
|
||||||
[3] .note.gnu.build-id
|
|
||||||
SectionHeader { name: 54, section_type: 7, flags: 2, addr: 872, offset: 872, size: 36, link: 0, info: 0, addralign: 4, entsize: 0 }
|
|
||||||
[4] .note.ABI-tag
|
|
||||||
SectionHeader { name: 73, section_type: 7, flags: 2, addr: 908, offset: 908, size: 32, link: 0, info: 0, addralign: 4, entsize: 0 }
|
|
||||||
[5] .gnu.hash
|
|
||||||
SectionHeader { name: 87, section_type: 1879048182, flags: 2, addr: 944, offset: 944, size: 36, link: 6, info: 0, addralign: 8, entsize: 0 }
|
|
||||||
[6] .dynsym
|
|
||||||
SectionHeader { name: 97, section_type: 11, flags: 2, addr: 984, offset: 984, size: 168, link: 7, info: 1, addralign: 8, entsize: 24 }
|
|
||||||
[7] .dynstr
|
|
||||||
SectionHeader { name: 105, section_type: 3, flags: 2, addr: 1152, offset: 1152, size: 143, link: 0, info: 0, addralign: 1, entsize: 0 }
|
|
||||||
[8] .gnu.version
|
|
||||||
SectionHeader { name: 113, section_type: 1879048191, flags: 2, addr: 1296, offset: 1296, size: 14, link: 6, info: 0, addralign: 2, entsize: 2 }
|
|
||||||
[9] .gnu.version_r
|
|
||||||
SectionHeader { name: 126, section_type: 1879048190, flags: 2, addr: 1312, offset: 1312, size: 48, link: 7, info: 1, addralign: 8, entsize: 0 }
|
|
||||||
[10] .rela.dyn
|
|
||||||
SectionHeader { name: 141, section_type: 4, flags: 2, addr: 1360, offset: 1360, size: 192, link: 6, info: 0, addralign: 8, entsize: 24 }
|
|
||||||
[11] .rela.plt
|
|
||||||
SectionHeader { name: 151, section_type: 4, flags: 66, addr: 1552, offset: 1552, size: 24, link: 6, info: 24, addralign: 8, entsize: 24 }
|
|
||||||
[12] .init
|
|
||||||
SectionHeader { name: 161, section_type: 1, flags: 6, addr: 4096, offset: 4096, size: 27, link: 0, info: 0, addralign: 4, entsize: 0 }
|
|
||||||
[13] .plt
|
|
||||||
SectionHeader { name: 156, section_type: 1, flags: 6, addr: 4128, offset: 4128, size: 32, link: 0, info: 0, addralign: 16, entsize: 16 }
|
|
||||||
[14] .plt.got
|
|
||||||
SectionHeader { name: 167, section_type: 1, flags: 6, addr: 4160, offset: 4160, size: 16, link: 0, info: 0, addralign: 16, entsize: 16 }
|
|
||||||
[15] .plt.sec
|
|
||||||
SectionHeader { name: 176, section_type: 1, flags: 6, addr: 4176, offset: 4176, size: 16, link: 0, info: 0, addralign: 16, entsize: 16 }
|
|
||||||
[16] .text
|
|
||||||
SectionHeader { name: 185, section_type: 1, flags: 6, addr: 4192, offset: 4192, size: 268, link: 0, info: 0, addralign: 16, entsize: 0 }
|
|
||||||
[17] .fini
|
|
||||||
SectionHeader { name: 191, section_type: 1, flags: 6, addr: 4460, offset: 4460, size: 13, link: 0, info: 0, addralign: 4, entsize: 0 }
|
|
||||||
[18] .rodata
|
|
||||||
SectionHeader { name: 197, section_type: 1, flags: 2, addr: 8192, offset: 8192, size: 18, link: 0, info: 0, addralign: 4, entsize: 0 }
|
|
||||||
[19] .eh_frame_hdr
|
|
||||||
SectionHeader { name: 205, section_type: 1, flags: 2, addr: 8212, offset: 8212, size: 52, link: 0, info: 0, addralign: 4, entsize: 0 }
|
|
||||||
[20] .eh_frame
|
|
||||||
SectionHeader { name: 219, section_type: 1, flags: 2, addr: 8264, offset: 8264, size: 172, link: 0, info: 0, addralign: 8, entsize: 0 }
|
|
||||||
[21] .init_array
|
|
||||||
SectionHeader { name: 229, section_type: 14, flags: 3, addr: 15800, offset: 11704, size: 8, link: 0, info: 0, addralign: 8, entsize: 8 }
|
|
||||||
[22] .fini_array
|
|
||||||
SectionHeader { name: 241, section_type: 15, flags: 3, addr: 15808, offset: 11712, size: 8, link: 0, info: 0, addralign: 8, entsize: 8 }
|
|
||||||
[23] .dynamic
|
|
||||||
SectionHeader { name: 253, section_type: 6, flags: 3, addr: 15816, offset: 11720, size: 496, link: 7, info: 0, addralign: 8, entsize: 16 }
|
|
||||||
[24] .got
|
|
||||||
SectionHeader { name: 171, section_type: 1, flags: 3, addr: 16312, offset: 12216, size: 72, link: 0, info: 0, addralign: 8, entsize: 8 }
|
|
||||||
[25] .data
|
|
||||||
SectionHeader { name: 262, section_type: 1, flags: 3, addr: 16384, offset: 12288, size: 16, link: 0, info: 0, addralign: 8, entsize: 0 }
|
|
||||||
[26] .bss
|
|
||||||
SectionHeader { name: 268, section_type: 8, flags: 3, addr: 16400, offset: 12304, size: 8, link: 0, info: 0, addralign: 1, entsize: 0 }
|
|
||||||
[27] .comment
|
|
||||||
SectionHeader { name: 273, section_type: 1, flags: 48, addr: 0, offset: 12304, size: 43, link: 0, info: 0, addralign: 1, entsize: 1 }
|
|
||||||
[28] .symtab
|
|
||||||
SectionHeader { name: 1, section_type: 2, flags: 0, addr: 0, offset: 12352, size: 864, link: 29, info: 18, addralign: 8, entsize: 24 }
|
|
||||||
[29] .strtab
|
|
||||||
SectionHeader { name: 9, section_type: 3, flags: 0, addr: 0, offset: 13216, size: 477, link: 0, info: 0, addralign: 1, entsize: 0 }
|
|
||||||
[30] .shstrtab
|
|
||||||
SectionHeader { name: 17, section_type: 3, flags: 0, addr: 0, offset: 13693, size: 282, link: 0, info: 0, addralign: 1, entsize: 0 }
|
|
||||||
|
|
||||||
Parsing Program Segments...
|
|
||||||
|
|
||||||
=== Program Segments ===
|
|
||||||
[0] PT_PHDR
|
|
||||||
ProgramHeader { program_type: 6, flags: 4, offset: 64, vaddr: 64, paddr: 64, filesz: 728, memsz: 728, align: 8 }
|
|
||||||
[1] PT_INTERP
|
|
||||||
ProgramHeader { program_type: 3, flags: 4, offset: 792, vaddr: 792, paddr: 792, filesz: 28, memsz: 28, align: 1 }
|
|
||||||
[2] PT_LOAD
|
|
||||||
ProgramHeader { program_type: 1, flags: 4, offset: 0, vaddr: 0, paddr: 0, filesz: 1576, memsz: 1576, align: 4096 }
|
|
||||||
[3] PT_LOAD
|
|
||||||
ProgramHeader { program_type: 1, flags: 5, offset: 4096, vaddr: 4096, paddr: 4096, filesz: 377, memsz: 377, align: 4096 }
|
|
||||||
[4] PT_LOAD
|
|
||||||
ProgramHeader { program_type: 1, flags: 4, offset: 8192, vaddr: 8192, paddr: 8192, filesz: 244, memsz: 244, align: 4096 }
|
|
||||||
[5] PT_LOAD
|
|
||||||
ProgramHeader { program_type: 1, flags: 6, offset: 11704, vaddr: 15800, paddr: 15800, filesz: 600, memsz: 608, align: 4096 }
|
|
||||||
[6] PT_DYNAMIC
|
|
||||||
ProgramHeader { program_type: 2, flags: 6, offset: 11720, vaddr: 15816, paddr: 15816, filesz: 496, memsz: 496, align: 8 }
|
|
||||||
[7] PT_NOTE
|
|
||||||
ProgramHeader { program_type: 4, flags: 4, offset: 824, vaddr: 824, paddr: 824, filesz: 48, memsz: 48, align: 8 }
|
|
||||||
[8] PT_NOTE
|
|
||||||
ProgramHeader { program_type: 4, flags: 4, offset: 872, vaddr: 872, paddr: 872, filesz: 68, memsz: 68, align: 4 }
|
|
||||||
[9] UNKNOWN
|
|
||||||
ProgramHeader { program_type: 1685382483, flags: 4, offset: 824, vaddr: 824, paddr: 824, filesz: 48, memsz: 48, align: 8 }
|
|
||||||
[10] UNKNOWN
|
|
||||||
ProgramHeader { program_type: 1685382480, flags: 4, offset: 8212, vaddr: 8212, paddr: 8212, filesz: 52, memsz: 52, align: 4 }
|
|
||||||
[11] UNKNOWN
|
|
||||||
ProgramHeader { program_type: 1685382481, flags: 6, offset: 0, vaddr: 0, paddr: 0, filesz: 0, memsz: 0, align: 16 }
|
|
||||||
[12] UNKNOWN
|
|
||||||
ProgramHeader { program_type: 1685382482, flags: 4, offset: 11704, vaddr: 15800, paddr: 15800, filesz: 584, memsz: 584, align: 1 }
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
File exists, reading 'testing/hello32'...
|
|
||||||
Found ELF Magic Number...
|
|
||||||
Parsing File Header...
|
|
||||||
- Found 11 program header entries 32 bytes in length
|
|
||||||
- Found 29 section header entries 40 bytes in length
|
|
||||||
- Found .shstrtab section at index 28
|
|
||||||
FileHeader { arch: X86, is_x86_64: false, endian: Little, abi: 0, abi_str: "SystemV", elf_type: 3, isa: 3, isa_str: "Intel x86", entryoff: 223338303600, phoff: 59184649338932, shoff: 13780, ehsize: 52, phentsize: 32, phnum: 11, shentsize: 40, shnum: 29, shstrndx: 28 }
|
|
||||||
|
|
||||||
Parsing Section Headers...
|
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
hello world
|
hello world
|
||||||
|
this flat file should fail
|
||||||
|
because it doesn't have the ELF magic keyword
|
||||||
BIN
testing/isPrime
Executable file
BIN
testing/isPrime
Executable file
Binary file not shown.
32
testing/src/isPrime.c
Normal file
32
testing/src/isPrime.c
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user