1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
| .intel_syntax noprefix .globl _start
.section .text
_start: # Open socket mov rdi, 2 mov rsi, 1 mov rdx, 0 mov rax, 41 syscall # Store socket fd in rbx mov rbx, rax
# Bind socket to address mov rdi, rbx lea rsi, sa_family_t mov rdx, 16 mov rax, 49 syscall
# Listen on socket mov rdi, rbx mov rsi, 0 mov rax, 50 syscall
accept_jump: # Accept a connection mov rdi, rbx mov rsi, 0 mov rdx, 0 mov rax, 43 syscall # Save new fd for bound connection in r12 mov r12, rax
# Fork the process and let the child do the serving mov rax, 57 syscall cmp rax, 0 je serve_connection # Close the connection if parent mov rdi, r12 mov rax, 3 syscall # Then go back to listening jmp accept_jump
serve_connection: # Close listening socket mov rdi, rbx mov rax, 3 syscall
# Read from the connection mov rdi, r12 lea rsi, read_buffer mov rdx, [read_packet_length] mov rax, 0 syscall
# Figure out what file was requested lea rdi, read_buffer mov rsi, 1 lea rdx, space call get_nth_substr mov r13, rax lea rdi, read_buffer mov rsi, 2 call get_nth_substr mov r14, rax sub r14, 1 # r13 = start (exclusive), r14 = end (inclusive) mov rdi, r13 mov rsi, r14 lea rdx, file_name_buffer call write_to_buf # Filename is now stored in file_name_buffer
# Check request type mov dil, [read_buffer] # Compare to "G" cmp dil, 0x47 # Continue (GET process) if G, otherwise do POST jne POST
GET: # Open that file lea rdi, file_name_buffer mov rsi, 0 mov rdx, 0 mov rax, 2 syscall mov r13, rax
# Read file contents mov rdi, r13 lea rsi, file_read_buffer mov rdx, 1024 mov rax, 0 syscall
# Close the file mov rdi, r13 mov rax, 3 syscall
# Write status to connection mov rdi, r12 lea rsi, write_static mov rdx, 19 mov rax, 1 syscall
# Write file contents to connection lea rdi, file_read_buffer call get_len mov rdx, rax sub rdx, 1 mov rdi, r12 lea rsi, file_read_buffer mov rax, 1 syscall
jmp exit
POST: # Open that file lea rdi, file_name_buffer mov rsi, 0x41 # O_CREAT, O_WRONLY mov rdx, 0777 mov rax, 2 syscall mov r13, rax
# Get the POST content lea rdi, read_buffer mov rsi, 1 lea rdx, double_cr_lf call get_nth_substr mov rsi, rax add rsi, 1
# Get write length mov rdi, rsi call get_len mov rdx, rax # Get rid of the pesky null byte sub rdx, 1 # Write to file mov rdi, r13 mov rax, 1 syscall
# Close the file mov rdi, r13 mov rax, 3 syscall
# Write status to connection mov rdi, r12 lea rsi, write_static mov rdx, 19 mov rax, 1 syscall
exit: # Close the connection mov rdi, r12 mov rax, 3 syscall
# Sys exit mov rdi, 0 mov rax, 60 syscall
# Get the length of a null-terminated string (including the first null byte) # Args: # rdi - buffer we're checking the length of # rax - length get_len: mov rax, 0 get_len_loop: # See if rdi + rax-th byte is null mov r10, rdi add r10, rax mov r10, [r10] add rax, 1 cmp r10, 0x00 jne get_len_loop ret
# Copy the bytes spanning rdi to rsi to the buffer rdx # rdx MUST BE LONGER THAN rsi - rdi BYTES, rdi MUST BE LESS THAN rsi # Args: # rdi - start (exclusive) of the string we're copying # rsi - end (inclusive) of the string we're copying # rdx - buffer we're copying to # rax - unchanged write_to_buf: write_to_buf_loop: add rdi, 1 mov r9, [rdi] mov [rdx], r9 add rdx, 1 cmp rdi, rsi jne write_to_buf_loop mov byte ptr [rdx], 0x00 ret
# Get address of the (last byte of) the nth occurence of substring in string (occurences must be non-overlapping) # ONLY GUARANTEED TO WORK ON NULL-TERMINATED STRINGS # Args: # rdi - target string address # rsi - n # rdx - substring
# rax - address of nth character get_nth_substr: # Set rcx (ocurrence counter) mov rcx, 0 # Set r10 (to traverse substring) mov r10, rdx check_character_loop: # r9b = character at position mov r9b, [rdi] # If string's terminated, obviously the substring doesn't occur enough times cmp r9b, 0x00 je not_enough_occurrences # Step through substring iff r9b = current byte cmp r9b, byte ptr [r10] jne character_not_equal add r10, 1 # If we've reached the end of the substring, increment counter and reset r10 cmp byte ptr [r10], 0x00 jne after_comparison mov r10, rdx add rcx, 1 jmp after_comparison character_not_equal: # Reset r10 without adding to count mov r10, rdx after_comparison: # Return address if we've got the nth ocurrence cmp rcx, rsi je match # Otherwise increment and continue add rdi, 1 jmp check_character_loop match: mov rax, rdi ret not_enough_occurrences: mov rax, -1 ret
.section .data # sockaddr_in struct sa_family_t: .word 2 bind_port: .word 0x5000 bind_address: .double 0x00000000 pad: .byte 0,0,0,0,0,0,0,0 # Make empty buffers to read to read_buffer: .space 1024 file_name_buffer: .space 1024 file_read_buffer: .space 1024 # Constants # Yes it's dumb to use a quad word for this, but it simplifies copying it to the register read_packet_length: .quad 0x0000000000000400 write_static: .string "HTTP/1.0 200 OK\r\n\r\n" space: .string " " double_cr_lf: .string "\r\n\r\n"
|