238 lines
5.2 KiB
V
238 lines
5.2 KiB
V
module native
|
|
|
|
enum PeCharacteristics {
|
|
// 1: relocation info stripped
|
|
// 2: file is executable
|
|
// 4: line numbers stripped
|
|
// 8: local symbols stripped
|
|
// 20: app can handle > 2GB
|
|
executable_image = 0x2f
|
|
}
|
|
|
|
const image_base = i64(0x400000)
|
|
|
|
enum PeMachine {
|
|
i386 = 0x14c
|
|
amd64 = 0x8664
|
|
arm64 = 0xaa64
|
|
}
|
|
|
|
enum PeHeader {
|
|
mz = 0x5a4d
|
|
pe = 0x4550
|
|
}
|
|
|
|
pub fn (mut g Gen) write_dos_header() {
|
|
dos_header := [
|
|
int(PeHeader.mz),
|
|
0x80, // bytes on last page of file
|
|
1, // pages in file
|
|
0, // relocations
|
|
4, // header size in paragraph
|
|
0x10, // minimum extra paragraphs
|
|
0xffff, // maximum extra paragraphs
|
|
0, // initial relative ss
|
|
0x140, // initial SP
|
|
0, // checksum
|
|
0, // IP
|
|
0, // IP relative CS
|
|
0x40, // address of relocation table
|
|
0, // overlay number
|
|
0,
|
|
0,
|
|
0,
|
|
0, // reserved
|
|
0, // oemid
|
|
0, // oeminfo
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0x80,
|
|
0, // address of PE header
|
|
]
|
|
for b in dos_header {
|
|
g.write16(b)
|
|
}
|
|
if g.buf.len != 0x40 {
|
|
g.n_error('Invalid dos header size')
|
|
}
|
|
}
|
|
|
|
// size is 0xb8
|
|
pub fn (mut g Gen) write_dos_stub() {
|
|
g.write8(0x0e) // richend
|
|
g.write8(0x1f) // richend
|
|
g.write8(0xba) // richend
|
|
g.write8(0x0e) // richend
|
|
// TODO: add a stub for DOS/16, we only run on amd64
|
|
pad_to(mut g.buf, 0x80)
|
|
}
|
|
|
|
fn (mut g Gen) write_pe_sections() {
|
|
pad_to(mut g.buf, 0x180)
|
|
g.write64(0)
|
|
g.write_string_with_padding('.idata', 8)
|
|
g.write32(0x89) // 137
|
|
g.write16(0x1000)
|
|
g.write32(0x02000000)
|
|
g.write32(0x02000000)
|
|
g.zeroes(14)
|
|
g.write16(64)
|
|
g.write8(0)
|
|
g.write8(192)
|
|
g.write_string_with_padding('.text', 8)
|
|
g.write32(75)
|
|
g.write8(0)
|
|
g.write32(0x20)
|
|
g.write32(0x00002)
|
|
g.write32(4)
|
|
g.write32(0)
|
|
g.write32(0)
|
|
g.write32(0x20000000) // 0, 0, 0, 32,
|
|
g.write([u8(0), 0, 96])
|
|
g.zeroes(52)
|
|
g.write([u8(72), 16, 0, 0])
|
|
g.write([u8(40), 16, 0, 0])
|
|
g.zeroes(20)
|
|
g.write([u8(96), 16, 0, 0])
|
|
g.write32(0)
|
|
g.write([u8(110), 16, 0, 0])
|
|
g.write32(0)
|
|
g.write([u8(125), 16, 0, 0])
|
|
g.zeroes(12)
|
|
g.write_string_with_padding('KERNEL32.DLL', 13)
|
|
g.write_string_with_padding('USER32.DLL', 13)
|
|
g.write_string_with_padding('ExitProcess', 14)
|
|
g.write_string_with_padding('GetStdHandle', 15)
|
|
g.write_string_with_padding('WriteFile', 13)
|
|
}
|
|
|
|
pub fn (mut g Gen) write_pe_header() {
|
|
pe_header := [
|
|
int(PeHeader.pe),
|
|
0,
|
|
int(PeMachine.amd64), // machine
|
|
2, // number of sections
|
|
0,
|
|
0, // timestamp
|
|
0,
|
|
0, // symbol table
|
|
0, // number of symbols
|
|
0,
|
|
0xf0, // 40 // size of optional header
|
|
int(PeCharacteristics.executable_image),
|
|
]
|
|
for b in pe_header {
|
|
g.write16(b)
|
|
}
|
|
|
|
// optional here comes here
|
|
p_opthdr := g.buf.len // should be 0x110
|
|
if p_opthdr != 0x98 {
|
|
eprintln('Invalid optdr location $p_opthdr != 0x98')
|
|
}
|
|
g.write16(0x20b) // magic (0x10b=pe32, 0x20b=pe32+)
|
|
g.write8(0x1) // major linker version
|
|
g.write8(0x49) // minor linker version
|
|
g.write32(0x200) // sizeofcode
|
|
g.write32(0x200) // initial data size
|
|
g.write32(0) // sizeof uninit data
|
|
|
|
g.write32(0x2000) // paddr of map // aligned to 4 bytes // entrypoint
|
|
g.write32(0x2000) // base of code // aligned to 4 bytes
|
|
g.write64(native.image_base) // image base vaddr // va // aligned to 4 bytes
|
|
g.write32(0x1000) // SectionAlignment
|
|
g.write32(0x200) // FileAlignment
|
|
g.write16(1) // Major OS Version
|
|
g.write16(0) // Minor OS Version
|
|
g.write16(0) // major image version
|
|
g.write16(0) // minor image version
|
|
g.write16(5) // major subsystem version
|
|
g.write16(0) // minor subsystem version
|
|
|
|
g.write32(0) // win32versionvalue
|
|
g.write32(0x3000) // hdrsize + codelen) // sizeofimage
|
|
g.write32(0x200) // hdrsize) // sizeofheaders
|
|
|
|
g.write32(0) // checksum
|
|
g.write16(3) // subsystem // subsystem
|
|
// g.write16(0x400) // dll characteristics
|
|
g.write16(0)
|
|
/*
|
|
g.write8(0x60) // dll characteristics
|
|
g.write8(0x81) // dll characteristics
|
|
*/
|
|
g.write64(0x1000) // SizeOfStackReserve
|
|
g.write64(0x1000) // SizeOfStackCommit
|
|
g.write64(0x10000) // SizeOfHeapReserve
|
|
g.write64(0) // SizeOfHeapCommit
|
|
g.write32(0) // LoaderFlags
|
|
g.write32(0x10) // NumberOfRvaAndSizes
|
|
|
|
g.write32(0)
|
|
g.write32(0)
|
|
g.write32(0x1000)
|
|
g.write32(0x100) // size of code
|
|
}
|
|
|
|
fn (mut g Gen) write_pe_section() {
|
|
// directory entries.. aka sections
|
|
// section header
|
|
g.write_string_with_padding('.text', 8)
|
|
g.write32(0x0) // pa
|
|
g.size_pos << g.buf.len
|
|
g.write32(0x1000) // va
|
|
g.write32(0x400) // sizeofrawdata
|
|
// g.patch_code << g.buf.len
|
|
g.write32(0) // ptr-torawdata
|
|
g.write32(0) // relocs
|
|
g.write32(0) // linenums
|
|
g.write16(0) // nrelocs
|
|
g.write16(0) // nlinenums
|
|
g.write32(0) // characteristics
|
|
}
|
|
|
|
pub fn (mut g Gen) generate_pe_header() {
|
|
g.write_dos_header()
|
|
g.write_dos_stub()
|
|
g.write_pe_header()
|
|
g.write_pe_sections()
|
|
|
|
pad_to(mut g.buf, 0x400)
|
|
g.code_start_pos = g.buf.len
|
|
|
|
g.call(0x18e)
|
|
g.ret()
|
|
g.main_fn_addr = g.buf.len
|
|
}
|
|
|
|
fn pad_to(mut buf []u8, len int) {
|
|
for buf.len < len {
|
|
buf << u8(0)
|
|
}
|
|
}
|
|
|
|
pub fn (mut g Gen) generate_pe_footer() {
|
|
g.sym_string_table()
|
|
pad_to(mut g.buf, 0x600)
|
|
g.file_size_pos = g.buf.len
|
|
|
|
// patch call main
|
|
if g.pref.arch == .arm64 {
|
|
bl_next := u32(0x94000001)
|
|
g.write32_at(g.code_start_pos, int(bl_next))
|
|
} else {
|
|
// +1 is for "e8"
|
|
// -5 is for "e8 00 00 00 00"
|
|
g.write32_at(g.code_start_pos + 1, int(g.main_fn_addr - g.code_start_pos) - 5)
|
|
}
|
|
g.create_executable()
|
|
}
|