summary refs log tree commit diff
path: root/src/main.rs
blob: c143e2204d3a07aa175be2804ba35a37bf5c1459 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// #![allow(incomplete_features)]
// #![feature(unsized_locals)]
mod structs;
use crate::structs::{
    ElfHeader, ElfProgramHeader, ElfProgramType, ElfSectionHeader, ElfSectionType, ElfSymbol,
};
use std::io::Read;

#[repr(C)]
#[derive(Debug)]
struct Elf {
    header: &'static ElfHeader,
    sections: &'static [ElfSectionHeader],
    symbols: &'static [ElfSymbol],
    programs: &'static [ElfProgramHeader],
    shstrtab: *const u8,
    start: *const u8,
}

impl Elf {
    pub fn new(bytes: &[u8]) -> Elf {
        let header = unsafe { &*(bytes.as_ptr() as *const ElfHeader) };
        assert_eq!(&header.ident.magic, b"\x7fELF");

        let sections = unsafe {
            std::slice::from_raw_parts(
                bytes.as_ptr().add(header.shoff as usize) as *const ElfSectionHeader,
                header.shnum as usize,
            )
        };

        let shstrtab = unsafe {
            bytes
                .as_ptr()
                .add((&sections[header.shstrndx as usize]).offset as usize)
        };

        let programs = unsafe {
            std::slice::from_raw_parts(
                bytes.as_ptr().add(header.phoff as usize) as *const ElfProgramHeader,
                header.phnum as usize,
            )
        };
        // dbg!(program);

        let symtab = sections
            .iter()
            .find(|&&sec| sec.r#type == ElfSectionType::SymTab)
            .expect("No symbol table!");
        // //dbg!(&sections[symtab.link as usize]);
        let symstrtab = &sections[symtab.link as usize];
        let symbols = unsafe {
            std::slice::from_raw_parts(
                bytes.as_ptr().add(symtab.offset as usize) as *const ElfSymbol,
                (symtab.size / symtab.entsize) as usize,
            )
        };

        // dbg!(symbols.len());
        // .iter()
        // .filter(|sym| sym.shndx != 0)
        // .filter_map(|sym| unsafe {
        // std::ffi::CStr::from_ptr(std::ptr::addr_of!(symstrtab).add(sym.name as usize) as *const i8).to_str().ok()
        // })
        // .filter(|name| name.len() > 1)
        // .collect();
        // dbg!(symbols);
        // for sym in symbols {
        // // //     dbg!(sym);
        //     let name = unsafe {
        //        std::ffi::CStr::from_ptr(bytes.as_ptr().add(symstrtab.offset as usize).add(sym.name as usize) as *const i8)
        //             .to_str()
        //             .unwrap_or("")
        //     };
        //     dbg!(name);
        // }

        Elf {
            header,
            sections,
            symbols,
            programs,
            shstrtab,
            start: bytes.as_ptr(),
        }
    }
}

// readelf behavior here
impl std::fmt::Display for Elf {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("ELF Header:\n")?;
        formatter.write_fmt(format_args!("{}\n", self.header))?;

        formatter.write_str("Section Headers:\n")?;
        formatter
            .write_str("  [Nr] Name              Type             Address           Offset\n")?;
        formatter
            .write_str("       Size              EntSize          Flags  Link  Info  Align\n")?;

        for (i, section) in self.sections.iter().enumerate() {
            let name = unsafe {
                std::ffi::CStr::from_ptr(self.shstrtab.add(section.name as usize) as *const i8)
                    .to_str()
                    .expect("Bad section name")
            };
            formatter.write_fmt(format_args!("  [{: >2}] {: <17.17} {}\n", i, name, section))?;
        }

        formatter.write_str("Key to Flags:\n")?;
        formatter.write_str(
            "  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),\n",
        )?;
        formatter.write_str(
            "  L (link order), O (extra OS processing required), G (group), T (TLS),\n",
        )?;
        formatter.write_str("  C (compressed), x (unknown), o (OS specific), E (exclude),\n")?;
        formatter.write_str("  D (mbind), l (large), p (processor specific)\n\n")?;

        formatter.write_str("Program Headers:\n")?;
        formatter.write_str("  Type           Offset             VirtAddr           PhysAddr\n")?;
        formatter
            .write_str("                 FileSiz            MemSiz              Flags  Align\n")?;
        for program in self.programs {
            formatter.write_fmt(format_args!("  {}\n", program));
            if program.r#type == ElfProgramType::Interp {
                let interpreter = unsafe {
                    std::ffi::CStr::from_ptr(self.start.add(program.offset as usize) as *const i8)
                        .to_str()
                        .expect("Bad interpreter name")
                };
                formatter.write_fmt(format_args!(
                    "      [Requesting program interpreter: {interpreter}]\n"
                ));
            }
        }

        // printing notes is a littlec complicated
        // for section in self.sections.iter().filter(|&&sec| sec.r#type == ElfSectionType::Note) {
        //     let name = unsafe {
        //         std::ffi::CStr::from_ptr(self.shstrtab.add(section.name as usize) as *const i8)
        //             .to_str()
        //             .expect("Bad section name")
        //     };
        //     formatter.write_fmt(format_args!("Displaying notes found in: {}\n{}\n", name, section))?;
        // }
        Ok(())
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();

    let buffer = {
        let mut f = std::fs::File::open(&args[1]).expect("no file found");
        let metadata = std::fs::metadata(&args[1]).expect("unable to read metadata");
        let mut buffer = vec![0; metadata.len() as usize];
        f.read(&mut buffer).expect("buffer overflow");
        buffer
    };
    let elf = Elf::new(&buffer[..]);
    println!("{}", elf);

    // dbg!(symtab);
}