BITS 32 org 0x00010000 ; Memory load location ; ELF HEADER CONTENT PROGRAM HEADER TBL ENTRY CONTENT ; ------------------------------------------------------------------------------------------------------------------ db 0x7f, "ELF" ; magic number: 7f454c46 db 0x01 ; class: 1 (32-bit) type: 1 (Loadable segment) db 0x00 ; data: 0 (invalid)* | db 0x00 ; version: 0 (invalid)* | db 0x00 ; abi: 0 (System V) | db 0x00 ; abi version: 0 offset: 0 (File offset) db 0x00 ; padding | db 0x00 ; | | db 0x00 ; | | dd $$ ; | vaddr: $$ (File memory location) db 0x02 ; type: 2 (Executable) paddr: 0x00030002 * db 0x00 ; | | db 0x03 ; machine: 3 (Intel i386 x86) | db 0x00 ; | | dd _start ; version: _start (invalid)* filesz: _start (too large)*** dd _start ; entry: _start (Program entry point) memsz: _start *** db 0x04 ; phoff: 4 (File offset) flags: 4 (READ) *** db 0x00 ; | | db 0x00 ; | | db 0x00 ; | | db 0x00 ; shoff: 0 (File offset)** align: 0 (No alignment constraints) db 0x00 ; | | db 0x00 ; | | db 0x00 ; | | db 0x00 ; flags: 0 db 0x00 ; | db 0x00 ; | db 0x00 ; | db 0x34 ; ehsize: 52 db 0x00 ; | db 0x20 ; phentsize: 32 db 0x00 ; | db 0x01 ; phnum: 1 (.text) db 0x00 ; | ;db 0x00 ; shentsize: 0** [ Cut these out to overlap with program code ] ;db 0x00 ; | ;db 0x00 ; shnum: 0** ;db 0x00 ; | ;db 0x00 ; shstrndx: 0** ;db 0x00 ; | ; For space savings, the above constructs the ELF metadata for this program ; without invoking an external linker. The ELF header and the program ; header entry completely overlap each other. Some concessions were made to ; allow this to be possible. See the asterisks above and explainations ; below for details. ; ; * Invalid values are present to leverage overloading fields that go ; unchecked by the loader at runtime. Such values are likely being set ; to what is required by the other data structure. ; ; ** Section headers are not utilized by this program, so no relevant ; header fields are utilized. As with (*) fields, these too go ; unchecked by the loader. ; ; *** phoff must be == 4 in this arrangement, therefore program header flags ; just match it. This is fine, as apparently execute is implied in this ; case. However, since the writable bit is not set, we can not set ; memsz larger than filesz (the loader is not able to 'write' the extra ; initializing zero bytes). Therefore, both fields are set to the value ; of the program entry point, so that the entry point field from ELF ; (which coinsides) can be set properly. The fact that filesz will be ; larger than that of the actual output file is of no consequence. _start: xor edx, edx ; open(argv[1], 0, 0) xor ecx, ecx mov ebx, [esp+8] xor eax, eax mov al, 5 int 0x80 cmp eax, 0 ; if fail, exit(1) mov bl, 1 jl exit mov dl, 16 ; read(argv[1], sockaddr, sizeof(sockaddr)) mov ecx, esp mov ebx, eax mov al, 3 int 0x80 cmp eax, 16 ; if fail, exit(2) mov bl, 2 jne exit push 0 ; socket(AF_INET, SOCK_STREAM, 0) push 1 push 2 mov ecx, esp mov bl, 1 mov al, 0x66 int 0x80 push 16 ; connect(sock, sockaddr, sizeof(sockaddr)) lea ecx, [esp+16] push ecx push eax mov ecx, esp mov bl, 3 mov al, 0x66 int 0x80 cmp eax, 0 ; if fail, exit(3) mov bl, 3 jne exit xor esi, esi ; pipe(sock_fd, stdin) pop edi call pipe inc esi ; pipe(stdout, sock_fd) xchg edi, esi call pipe xor ebx, ebx ; exit(0) jmp exit pipe: mov dl, 0xff ; read(src, buff, sizeof(buff)) lea ecx, [esp+4] mov ebx, esi mov al, 3 int 0x80 cmp eax, 0 ; if finished/error, return jg pipe_cont ret pipe_cont: mov edx, eax ; write(dst, buff, nb) mov ebx, edi mov al, 4 int 0x80 jmp pipe ; loop exit: xor eax, eax mov al, 1 int 0x80