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