colorful rat Ratfactor.com > Dave's Repos

mez

A utility for ELF header experiments written in Zig
git clone http://ratfactor.com/repos/mez/mez.git

mez/zem.zig

Download raw file: zem.zig

1 // zem - makes an ELF file - which we can look at with mez 2 3 const std = @import("std"); 4 5 const Bytes = struct { 6 mem: [0x2000]u8 = undefined, 7 pos: usize = 0, 8 9 pub fn writeNum(self: *Bytes, num: anytype) void { 10 const T = @TypeOf(num); 11 std.mem.writeIntSliceNative(T, self.mem[self.pos..], num); 12 // std.debug.print("Writing {x} ({s})\n", .{num, @typeName(@TypeOf(num))}); 13 self.pos += @sizeOf(T); 14 } 15 16 pub fn writeBytes(self: *Bytes, source_bytes: []const u8) void { 17 // std.debug.print("Writing {d} bytes\n", .{source_bytes.len}); 18 for (source_bytes) |b| { 19 // std.debug.print(" 0x{x}: {x}\n", .{self.pos, b}); 20 self.mem[self.pos] = b; 21 self.pos += 1; 22 } 23 } 24 25 pub fn padTo(self: *Bytes, addr: usize) void { 26 while (self.pos < addr) { 27 self.mem[self.pos] = 0; 28 self.pos += 1; 29 } 30 } 31 32 pub fn print(self: Bytes) void { 33 for(self.mem[0..self.pos], 0..self.pos) |b,a| { 34 std.debug.print("\x1b[90m{x}:\x1b[39m{x} ", .{a,b}); 35 } 36 std.debug.print("\n", .{}); 37 } 38 39 pub fn get(self: Bytes) []const u8 { 40 return self.mem[0..self.pos]; 41 } 42 }; 43 44 pub fn main() !void { 45 // var bytes: [100]u8 = undefined; 46 // var pos: usize = 0; 47 48 var bytes = Bytes{}; 49 50 // hard-coding for ease! 51 const segment_count = 2; 52 const program_mem_addr: u32 = 0x8040000; 53 const data_mem_addr: u32 = 0x8041000; 54 const ph_size = 32; // program header size (bytes) 55 const elf_size = 52; // main elf header size (bytes) 56 const total_header = elf_size + (ph_size * segment_count); 57 const entry_addr = program_mem_addr + total_header; 58 59 std.debug.print("total header: {d} bytes\n", .{total_header}); 60 61 bytes.writeBytes(&[_]u8{ 0x7F, 'E', 'L', 'F' }); // magic 62 bytes.writeNum(@as(u8, 1)); // 32-bit 0x04 63 bytes.writeNum(@as(u8, 1)); // little endian 0x05 64 bytes.writeNum(@as(u8, 1)); // elf version 0x06 65 bytes.writeNum(@as(u8, 0)); // systemV os abi 0x07 66 bytes.writeNum(@as(u8, 0)); // abi version 0x08 67 bytes.writeBytes(&[_]u8{ 68 0, // pad 0x09 69 0, // pad 0x0a 70 0, // pad 0x0b 71 0, // pad 0x0c (7 bytes padding) 72 0, // pad 0x0d 73 0, // pad 0x0e 74 0, // pad 0x0f 75 }); 76 bytes.writeNum(@as(u16, 2)); // executable 0x10 77 bytes.writeNum(@as(u16, 3)); // arch intel 80386 0x12 78 bytes.writeNum(@as(u32, 1)); // ELF version 0x14 79 bytes.writeNum(entry_addr); // entry address! 0x18 80 81 // next is elf_size because program headers start right after 82 // main elf header. 83 bytes.writeNum(@as(u32, elf_size)); // e_phoff 0x1C 84 85 // Stuff 86 bytes.writeNum(@as(u32, 0)); // e_shoff ignore! 0x20 87 bytes.writeNum(@as(u32, 0)); // e_flags 0x24 88 bytes.writeNum(@as(u16, elf_size)); // e_hsize 0x28 89 90 // Program header size and count 91 bytes.writeNum(@as(u16, 32)); // ph size (each) 0x2A 92 bytes.writeNum(@as(u16, 2)); // ph count 0x2C 93 94 // More section stuff to ignore: 95 bytes.writeNum(@as(u16, 0)); // sh size 0x2E 96 bytes.writeNum(@as(u16, 0)); // sh count 0x30 97 bytes.writeNum(@as(u16, 0)); // sh str idx 0x32 98 99 // Program Header 1 100 // ================================================ 101 bytes.writeNum(@as(u32, 1)); // ptype (1=LOAD) 102 bytes.writeNum(@as(u32, 0)); // file offset to load! 103 bytes.writeNum(@as(u32, program_mem_addr)); // write to mem! 104 bytes.writeNum(@as(u32, program_mem_addr)); // same (physical) 105 bytes.writeNum(@as(u32, 0x1000)); // bytes to write 106 bytes.writeNum(@as(u32, 0x1000)); // memory to alloc 107 bytes.writeNum(@as(u32, 5)); // flags (RX) 108 bytes.writeNum(@as(u32, 0x1000)); // alignment 109 110 // Program Header 2 111 // ================================================ 112 bytes.writeNum(@as(u32, 1)); // ptype (1=LOAD) 113 bytes.writeNum(@as(u32, 0x1000)); // file offset to load! 114 bytes.writeNum(@as(u32, data_mem_addr)); // write to mem! 115 bytes.writeNum(@as(u32, data_mem_addr)); // same (physical) 116 bytes.writeNum(@as(u32, 13)); // bytes to write 117 bytes.writeNum(@as(u32, 13)); // memory to alloc 118 bytes.writeNum(@as(u32, 6)); // flags (RW) 119 bytes.writeNum(@as(u32, 0x1000)); // alignment 120 121 // Write program (0x22 bytes) 122 // ================================================ 123 bytes.writeBytes(&[_]u8{ 124 // comes from hello.asm - then hand-edited address to 125 // point to my data segment: 0x8041000 126 0xba, 0x0d, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x10, 0x04, 0x08, 127 0xbb, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00, 128 0xcd, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 129 0x00, 0x00, 0xcd, 0x80, 130 }); 131 132 // Pad to next 0x1000, then write string data 133 // ================================================ 134 bytes.padTo(0x1000); 135 bytes.writeBytes("Hello world.\x0a"); 136 137 138 // Print what we're gonna write to compare with mez 139 // LOL - not now that there's 1kb padding! 140 //bytes.print(); 141 142 const file = try std.fs.cwd().createFile("foo", .{ 143 .mode = 0o777, 144 }); 145 defer file.close(); 146 _ = try file.write(bytes.get()); 147 }