Created
February 10, 2021 22:00
-
-
Save tuket/6f214486487ab2592adbd4ad1778bc6b to your computer and use it in GitHub Desktop.
Generate a raw ELF executable using C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <stdint.h> | |
typedef uint8_t u8; | |
typedef uint16_t u16; | |
typedef uint32_t u32; | |
typedef uint64_t u64; | |
typedef struct Elf64Header { | |
char elfMagicNumber[4]; // "\x7fELF" | |
u8 bitAmount; // 1: 32-bit, 2: 64-bit | |
u8 endian; // 1: little endian, 2: big endian | |
u8 elfVersion1; // must be 1 | |
u8 osAbi; // 0: System V, 3: Linux | |
u8 abiVersion; // in statically linked executables has no effect. In dynamically linked executables, if OS_ABI==3, defines dynamic linker features | |
u8 unused[7]; | |
u16 objFileType; // ET_EXEC=2, ET_DYN=3 (DYN is used for PIC) | |
u16 arch; // 0x3E: AMD64 | |
u32 elfVersion2; // the elf version again, must be 1 | |
u64 entryPointOffset; // entry point from where the process should start executing | |
u64 phtOffset; // start of the program header table | |
u64 shtOffset; // start of the section header table | |
u32 processorFlags; // processor-specific flags | |
u16 headerSize; // the size of this header | |
u16 phtEntrySize; // the size of one PHT entry | |
u16 numPhtEntries; // num entries in the PHT | |
u16 shtEntrySize; // the size of one SHT entry | |
u16 numShtEntries; // num entries in the SHT | |
u16 namesSht; // the index of the SHT entry that contains the section names | |
} Elf64Header; | |
typedef struct Elf64_PhtEntry { | |
u32 segmentType; // 1: loadable segment, 2: dynamic linking info | |
u32 flags; // segment-dependent flags (position for 64-bit structure) | |
u64 offset; // offset of the segment in the file image | |
u64 vaddr; // virtual address of the segment in memory | |
u64 paddr; // on systems where the physical address is relevant, reserved for the physical address of the segment | |
u64 sizeInFile; // size of the segment in the file image | |
u64 sizeInMem; // size of the segment in memory | |
u64 align; // 0 and 1 specify no alignment. Otherwise should be a positive, integral power of 2, with 'vaddr' equating 'offset' modulus 'p_align' | |
} Elf64_PhtEntry; | |
// https://godbolt.org/z/vh8aEe | |
const unsigned char asmCode[] = { | |
0xb8, 0x01, 0x00, 0x00, 0x00, // mov rax, 1 (syscall: write) | |
0xbf, 0x01, 0x00, 0x00, 0x00, // mov rdi, 1 (stdout) | |
0x48, 0x8d, 0x35, 0x10, 0x0, 0x0, 0x0, // lea rsi, [rel helloStr] | |
0xba, 0x07, 0x00, 0x00, 0x00, // mov rex, sizeof(helloStr) | |
0x0f, 0x05, // syscall | |
0xb8, 0x3c, 0x00, 0x00, 0x00, // mov eax, 3c | |
0x48, 0x31, 0xff, // xor rdi, rdi | |
0x0f, 0x05 // syscall | |
}; | |
const char helloStr[] = {'h', 'e', 'l', 'l', 'o', '\n'}; | |
int main() | |
{ | |
const int headersSize = sizeof(Elf64Header) + sizeof(Elf64_PhtEntry); | |
const int codeSize = sizeof(asmCode); | |
const int fileSize = headersSize + codeSize + sizeof(helloStr); | |
Elf64Header header = { | |
.elfMagicNumber = {0x7F, 'E', 'L', 'F'}, | |
.bitAmount = 2, // 64-bit | |
.endian = 1, // little endian | |
.elfVersion1 = 1, | |
.osAbi = 0, // system V | |
.abiVersion = 0, | |
.unused = {0,0,0,0,0,0,0}, | |
.objFileType = 3, | |
.arch = 0x3E, | |
.elfVersion2 = 1, | |
.entryPointOffset = 0x400000 + headersSize, | |
.phtOffset = sizeof(Elf64Header), | |
.shtOffset = 0, | |
.processorFlags = 0, | |
.headerSize = 64, | |
.phtEntrySize = sizeof(Elf64_PhtEntry), | |
.numPhtEntries = 1, | |
.shtEntrySize = 0, | |
.numShtEntries = 0, //1, | |
.namesSht = 0 | |
}; | |
Elf64_PhtEntry phtEntry = { | |
.segmentType = 1, // 1: PT_LOAD | |
.flags = 0x7, // 0: execute, 1: write, 2: read | |
.offset = headersSize, | |
.vaddr = 0x400000 + headersSize, // linux | |
.paddr = 0x400000 + headersSize, | |
.sizeInFile = codeSize, | |
.sizeInMem = codeSize, | |
.align = 0x1000 | |
}; | |
FILE* file = fopen("raw_exe", "w"); | |
fwrite(&header, 1, sizeof(header), file); | |
fwrite(&phtEntry, 1, sizeof(phtEntry), file); | |
fwrite(asmCode, 1, sizeof(asmCode), file); | |
fwrite(helloStr, 1, sizeof(helloStr), file); | |
fclose(file); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment