├── Makefile ├── README └── asmscan.asm /Makefile: -------------------------------------------------------------------------------- 1 | asmscan: asmscan.o 2 | ld -s -o asmscan asmscan.o 3 | asmscan.o: asmscan.asm 4 | nasm -f elf -o asmscan.o asmscan.asm 5 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | asmscan 2 | Author: Eugene Ma 3 | 4 | ==========[ 0x0 Introduction ] 5 | 6 | asmscan is a port scanner written entirely in 32-bit x86 assembly, with 7 | both TCP and SYN scanning capabilities. It uses Linux system calls to interface 8 | with the network stack, which makes the code unportable across platforms, but 9 | keeps it completely libc free. 10 | 11 | ==========[ 0x1 Features ] 12 | 13 | - libc free 14 | - compact binary size 15 | - network optimized speed 16 | 17 | ==========[ 0x2 Installation ] 18 | 19 | You will need nasm. 20 | 21 | 22 | $ cat Makefile 23 | asmscan: asmscan.o 24 | ld -s -o asmscan asmscan.o 25 | asmscan.o: asmscan.asm 26 | nasm -f elf -o asmscan.o asmscan.asm 27 | 28 | ==========[ 0x3 Usage ] 29 | 30 | $ ./asmscan 31 | Usage: asmscan 32 | 33 | ==========[ 0x4 Operation ] 34 | 35 | asmscan implements two modes of operation. 36 | 37 | 1. If run by a normal user, asmscan will perform a TCP scan, and attempt to 38 | connect with ports 0-1023. 39 | 40 | 2. If run with root permissions, asmscan will perform a SYN scan, sending 41 | custom crafted TCP SYN packets to the target host and listening for replies. It 42 | will first send an ICMP ping to calculate the shortest time to wait for replies 43 | from the host. 44 | 45 | In both modes, asmscan scans ports in parallel instead of serially. This gives 46 | it speeds that are comparable to those of nmap. 47 | 48 | ==========[ 0x5 Todo ] 49 | 50 | - Allow user to specify a range of ports 51 | - Allow user to specify a range of IP's 52 | - Greater granularity of port state: notify the user if a port is open, closed, 53 | filtered, or possibly something else. 54 | - Make the binary even smaller 55 | -------------------------------------------------------------------------------- /asmscan.asm: -------------------------------------------------------------------------------- 1 | ; vim: ft=nasm 2 | ; Usage: asmscan 3 | ; Author: Eugene Ma 4 | 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8 | 9 | section .data 10 | ; Error messages to call if we exit prematurely 11 | open_error_msg: db 'Error: sys_open failed', 10, 0 12 | socket_error_msg: db 'Error: sys_socket failed', 10, 0 13 | select_error_msg: db 'Error: sys_select failed', 10, 0 14 | connect_error_msg: db 'Error: sys_connect failed', 10, 0 15 | sendto_error_msg: db 'Error: sys_sendto failed', 10, 0 16 | recvfrom_error_msg: db 'Error: sys_recvfrom failed', 10, 0 17 | parse_error_msg: db 'Error: malformed ip address', 10, 0 18 | usage_msg: db 'Usage: asmscan ', 10, 0 19 | 20 | ; printf("%d open", port) 21 | port_open_fmtstr: db ' open', 10, 0 22 | ; printf("%d closed", port) 23 | port_closed_fmtstr: db ' closed', 10, 0 24 | ; printf("Latency %d ms", time) 25 | latency_fmtstr1: db 'Latency: ', 0 26 | latency_fmtstr2: db ' ms', 10, 0 27 | 28 | ; Path to the random number generator device 29 | devrpath: db '/dev/urandom', 0 30 | 31 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 32 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 33 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 34 | 35 | section .bss 36 | ; This struct needs to be filled in before using sockets 37 | ; struct sockaddr_in { 38 | ; short int sin_family; // Address family, AF_INET 39 | ; unsigned short int sin_port; // Port number 40 | ; struct in_addr sin_addr; // Internet address 41 | ; unsigned char sin_zero[8]; // Same size as struct sockaddr 42 | ; }; 43 | sockaddr: resb (2+2+4+8) 44 | sockaddrlen equ $-sockaddr 45 | sockaddrlenbuf: resd 1 46 | 47 | ; The bitmap used to track living sockets and as select argument 48 | ; typedef struct { 49 | ; unsigned long fds_bits [__FDSET_LONGS]; 50 | ; } __kernel_fd_set; 51 | masterfds: resd 32 52 | wrfds: resd 32 53 | rdfds: resd 32 54 | masterfdslen equ 32 55 | 56 | ; Number of ports to scan in parallel 57 | max_parallel_ports equ 64 58 | ; For storing socket descriptors we care about 59 | socketarray: resd max_parallel_ports 60 | ; Used in conjunction with socketarray to map socket to port 61 | portarray: resw max_parallel_ports 62 | 63 | ; The source and target IPv4 addresses in network byte order 64 | victimaddr: resd 1 65 | myaddr: resd 1 66 | 67 | ; Temporary storage for strings 68 | writebuf: resb 256 69 | 70 | ; Maximum time to wait for incoming packets in usec 71 | max_timeout equ 500000 72 | ; struct timeval { 73 | ; int tv_sec; // seconds 74 | ; int tv_usec; // microseconds 75 | ; }; 76 | ; This can be mangled by us or the kernel at any time! 77 | tv_volatile: resd 2 78 | ; This is always zero 79 | tv_zero: resd 2 80 | ; This is the delay between sending packets 81 | tv_master: resd 2 82 | 83 | ; The global buffers we use to send and recieve datagrams 84 | sendbuf: resb 1024 85 | recvbuf: resb 1024 86 | sendbuflen: resd 1 87 | recvbuflen: resd 1 88 | 89 | ; To store the file descriptor mapped to /dev/urandom 90 | devrfd: resd 1 91 | 92 | ; Useful miscellaneous constants 93 | iphdrlen equ 20 94 | icmphdrlen equ 8 95 | EINPROGRESS equ -115 96 | EAGAIN equ -11 97 | SYN_FLAG equ 0x2 98 | 99 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 100 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 101 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 102 | 103 | section .text 104 | global _start 105 | 106 | _start: 107 | mov ebp, esp 108 | ; String operations increment pointers by default 109 | cld 110 | 111 | check_argc: 112 | ; Check argument count 113 | cmp [ebp], dword 2 114 | 115 | ; Make sure we were invoked with one argument 116 | je parse_argv 117 | ; Otherwise, print usage string and exit with exit code 1 118 | push dword -1 119 | push dword usage_msg 120 | call premature_exit 121 | 122 | parse_argv: 123 | ; Parse the IP string into octets and store them into a buffer 124 | push dword victimaddr 125 | push dword [ebp + 8] 126 | call parse_octets 127 | add esp, 8 128 | 129 | ; Check return value 130 | test eax, eax 131 | 132 | ; Parse returns zero on success 133 | jns load_sockaddr 134 | ; Otherwise, complain about malformed IP and exit with exit code 1 135 | push dword -1 136 | push dword parse_error_msg 137 | call premature_exit 138 | 139 | load_sockaddr: 140 | mov edi, sockaddr 141 | ; Set the protocol family to AF_INET 142 | mov ax, 2 143 | stosw 144 | ; Set the port to zero for now 145 | xor ax, ax 146 | stosw 147 | mov eax, [victimaddr] 148 | stosd 149 | ; Store the length of this struct in a buffer 150 | mov [sockaddrlenbuf], dword sockaddrlen 151 | 152 | check_root: 153 | ; Root user has uid = 0 154 | call sys_getuid 155 | cmp eax, 0 156 | je ping 157 | 158 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 159 | 160 | tcp_scan: 161 | ; Store the current port in ebx 162 | xor ebx, ebx 163 | tcp_scan_loop: 164 | ; Store the index into socketarray and portarray in esi 165 | ; Store the highest numbered socket descriptor in edi 166 | xor esi, esi 167 | xor edi, edi 168 | tcp_scan_connect_loop: 169 | ; Create a non-blocking stream socket 170 | ; (PF_INET, (SOCK_STREAM | O_NONBLOCK), IPPROTO_TCP) 171 | push dword 6 172 | push dword (1 | 4000q) 173 | call spawn_socket 174 | add esp, 8 175 | 176 | ; Check return value 177 | test eax, eax 178 | 179 | ; Return value should be a valid socket descriptor 180 | jns tcp_scan_store_socket 181 | ; Else, print socket error message and exit with errno 182 | push eax 183 | push socket_error_msg 184 | call premature_exit 185 | 186 | tcp_scan_store_socket: 187 | ; Save the socket descriptor in an array 188 | mov [socketarray + 4 * esi], eax 189 | ; Map the socket descriptor to the port 190 | mov [portarray + 2 * esi], word bx 191 | ; Update highest numbered socket descriptor 192 | cmp eax, edi 193 | cmovg edi, eax 194 | 195 | ;;; Connect socket to current port ;;; 196 | 197 | ; Load sockaddr with port in network byte order 198 | mov [sockaddr + 2], byte bh 199 | mov [sockaddr + 3], byte bl 200 | push sockaddrlen 201 | push sockaddr 202 | push eax 203 | call sys_connect 204 | add esp, 12 205 | 206 | ; The errno should indicate the connection is pending 207 | cmp eax, EINPROGRESS 208 | je tcp_scan_connect_next 209 | cmp eax, EAGAIN 210 | je tcp_scan_connect_next 211 | test eax, eax 212 | jns tcp_scan_connect_next 213 | ; Else, print connect error message and exit with errno 214 | push eax 215 | push connect_error_msg 216 | call premature_exit 217 | 218 | tcp_scan_connect_next: 219 | ; Increment and port 220 | inc word bx 221 | ; Increment array index 222 | inc esi 223 | cmp esi, max_parallel_ports 224 | jl tcp_scan_connect_loop 225 | 226 | ; Wait 500 ms for requested connects to finish or timeout 227 | mov [tv_volatile + 4], dword 500000 228 | push tv_volatile 229 | push dword 0 230 | push dword 0 231 | push dword 0 232 | push dword 0 233 | call sys_select 234 | add esp, 20 235 | 236 | ; Copy master fds to wrfds 237 | mov esi, masterfds 238 | mov edi, wrfds 239 | mov ecx, masterfdslen 240 | rep movsd 241 | 242 | ; Monitor sockets with select 243 | push tv_zero 244 | push dword 0 245 | push dword wrfds 246 | push dword 0 247 | ; Select takes highest numbered file descriptor + 1 248 | inc edi 249 | push edi 250 | call sys_select 251 | add esp, 20 252 | ; Reset index into socketarray and portarray 253 | xor esi, esi 254 | 255 | ; Check return value 256 | cmp eax, 0 257 | 258 | ; Select returns the number of bits set in wrfds 259 | je tcp_scan_next_batch 260 | jns tcp_scan_write_loop 261 | ; Otherwise, print select error message and exit with errno 262 | push eax 263 | push select_error_msg 264 | call premature_exit 265 | 266 | tcp_scan_write_loop: 267 | ; Traverse array and write to sockets set in wrfds 268 | mov eax, [socketarray + 4 * esi] 269 | ; Test the bit mapped to this socket 270 | bt [wrfds], eax 271 | ; If the bit is cleared, the socket is not ready for 272 | ; writing and the state of the TCP connection is 273 | ; unknown. This possibly exposes a filtered port which 274 | ; drops TCP "three-way handshake" packets. 275 | jnc tcp_scan_port_filtered 276 | 277 | ; If the bit is set, the socket is ready for writing; 278 | ; try a 0 byte write to the socket 279 | push dword 0 280 | push dword 0 281 | push eax 282 | call sys_write 283 | add esp, 12 284 | 285 | ; Check return value 286 | test eax, eax 287 | ; If return value is negative, then the write failed 288 | js tcp_scan_port_closed 289 | 290 | ; The write succeeded, so print the open port 291 | push port_open_fmtstr 292 | movzx eax, word [portarray + 2 * esi] 293 | push eax 294 | call print_port 295 | add esp, 4 296 | 297 | tcp_scan_port_filtered: 298 | tcp_scan_port_closed: 299 | ; Try next socket 300 | inc esi 301 | cmp esi, max_parallel_ports 302 | jl tcp_scan_write_loop 303 | 304 | tcp_scan_next_batch: 305 | ; Close all open socket descriptors 306 | call cleanup_sockets 307 | ; Scan the next batch of ports, or exit 308 | cmp bx, word 1024 309 | jl tcp_scan_loop 310 | 311 | tcp_scan_done: 312 | jmp exit 313 | 314 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 315 | 316 | ping: 317 | ; Create non-blocking raw socket with ICMP protocol 318 | ; (PF_SET, (SOCK_RAW | O_NONBLOCK), IPPROTO_ICMP) 319 | push dword 1 320 | push dword (3 | 4000q) 321 | call spawn_socket 322 | add esp, 8 323 | 324 | ; Check return value 325 | test eax, eax 326 | 327 | ; Return value should be a valid socket descriptor 328 | jns ping_store_socket 329 | ; Otherwise, print socket error message and exit with errno 330 | push eax 331 | push socket_error_msg 332 | call premature_exit 333 | 334 | ping_store_socket: 335 | ; Store the returned socket descriptor 336 | mov [socketarray], eax 337 | 338 | ; Build an ICMP packet with message type 8 (Echo request). 339 | ; The kernel will craft the IP header. 340 | mov edi, sendbuf 341 | ; Type: 8 (Echo request) 342 | mov al, 8 343 | stosb 344 | ; Code: 0 (Cleared for this type) 345 | xor al, al 346 | stosb 347 | ; Calculate the ICMP checksum later 348 | xor eax, eax 349 | stosw 350 | ; Identifier: 0, Sequence number: 0 351 | stosd 352 | ; Now we have to zero out 56 bytes of ICMP padding data 353 | xor eax, eax 354 | mov ecx, 14 355 | rep stosd 356 | ; Calculate the ICMP checksum which includes ICMP header and data 357 | push dword ((icmphdrlen+56)/2) 358 | push dword sendbuf 359 | call cksum 360 | add esp, 8 361 | ; Store result in packet ICMP header 362 | mov [sendbuf + 2], word ax 363 | ; Store the length of the packet we wish to send 364 | mov [sendbuflen], dword (icmphdrlen + 56) 365 | 366 | ; Count down the number of packets sent in ebx 367 | mov ebx, 3 368 | ping_send_packets: 369 | ; The socket is in non-blocking mode, so sending and receiving data 370 | ; occurs asynchronously. Send 3 pings and block until socket has data 371 | ; ready to be read. 372 | push dword [socketarray] 373 | call send_packet 374 | add esp, 4 375 | 376 | ; The errno should indicate connection in progress 377 | cmp eax, EINPROGRESS 378 | je ping_send_next_packet 379 | cmp eax, EAGAIN 380 | je ping_send_next_packet 381 | test eax, eax 382 | jns ping_send_next_packet 383 | ; Otherwise, print sendto error message and exit with errno 384 | push eax 385 | push sendto_error_msg 386 | call premature_exit 387 | 388 | ping_send_next_packet: 389 | ; Send another packet? 390 | dec ebx 391 | jnz ping_send_packets 392 | 393 | ; Time how long it takes to receieve the first ICMP echo response 394 | mov edi, tv_volatile 395 | xor eax, eax 396 | stosd 397 | mov eax, max_timeout 398 | ; Initialize tv_usec to maximum timeout 399 | stosd 400 | 401 | ; Copy masterfds to rdfds 402 | mov esi, masterfds 403 | mov edi, rdfds 404 | mov ecx, masterfdslen 405 | rep movsd 406 | 407 | ; Block until data is ready to be read, or timeout is exceeded 408 | push tv_volatile 409 | push dword 0 410 | push dword 0 411 | push rdfds 412 | push dword [socketarray] 413 | inc dword [esp] 414 | call sys_select 415 | add esp, 20 416 | 417 | ; Check return value 418 | cmp eax, 0 419 | 420 | ; Select returns the number of bits set in rdfds 421 | je ping_no_reply 422 | jns ping_replied 423 | ; Otherwise, print select error message and exit with errno 424 | push eax 425 | push dword select_error_msg 426 | call premature_exit 427 | 428 | ping_no_reply: 429 | ;;; Victim didn't respond to our ping ;;; 430 | 431 | ; Free the socket we used 432 | call cleanup_sockets 433 | ; Give up on SYN scanning, because we have no other way of 434 | ; getting the IP address for now. 435 | jmp tcp_scan 436 | 437 | ping_replied: 438 | ; Calculate the packet delay from max_timeout - remaining time 439 | mov eax, max_timeout 440 | mov ecx, [tv_volatile + 4] 441 | sub eax, ecx 442 | ; Set delay to RTT * 2 443 | shl eax, 1 444 | mov [tv_master + 4], eax 445 | 446 | ; Read the socket for a response 447 | mov [recvbuflen], dword 0xffff 448 | push dword [socketarray] 449 | call recv_packet 450 | add esp, 4 451 | 452 | ; Check return value 453 | test eax, eax 454 | 455 | ; recvfrom should return the number of bytes received 456 | jns ping_save_address 457 | ; Otherwise, print recvfrom error message and exit with errno 458 | push eax 459 | push dword recvfrom_error_msg 460 | call premature_exit 461 | 462 | ping_save_address: 463 | ;;; Swipe the IP address from the ICMP packet we recieved ;;; 464 | 465 | ; This should get the destination address field of the IP header 466 | lea esi, [recvbuf + 16] 467 | mov edi, myaddr 468 | movsd 469 | 470 | ;;; Print expected latency (useful for debugging) ;;; 471 | 472 | ; Convert microseconds to milliseconds 473 | mov eax, [tv_master + 4] 474 | mov ecx, 1000 475 | div ecx 476 | ; Convert this number to a string 477 | push writebuf 478 | push eax 479 | call ultostr 480 | add esp, 8 481 | ; "Latency: %d ms" 482 | push latency_fmtstr1 483 | call printstr 484 | mov [esp], dword writebuf 485 | call printstr 486 | mov [esp], dword latency_fmtstr2 487 | call printstr 488 | add esp, 4 489 | 490 | ; All done - close socket 491 | call cleanup_sockets 492 | 493 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 494 | 495 | syn_scan: 496 | ; Create a raw non-blocking socket with TCP protocol 497 | ; (PF_INET, (SOCK_RAW | NON_BLOCK), IPPROTO_TCP) 498 | push dword 6 499 | push dword (3|4000q) 500 | call spawn_socket 501 | add esp, 8 502 | 503 | ; Check return value 504 | test eax, eax 505 | 506 | ; Return value should be a valid socket descriptor 507 | jns syn_scan_store_socket 508 | ; Otherwise, print socket error message and exit with errno 509 | push eax 510 | push socket_error_msg 511 | call premature_exit 512 | 513 | syn_scan_store_socket: 514 | ; Store the raw socket file descriptor in socketarray array 515 | mov [socketarray], eax 516 | 517 | ; Open random number generator device for generating SYN sequences 518 | ; (O_RDONLY, "/dev/urandom") 519 | push dword 0 520 | push dword devrpath 521 | call sys_open 522 | add esp, 8 523 | 524 | ; Check return value 525 | test eax, eax 526 | 527 | ; Return value should be a valid file descriptor 528 | jns syn_scan_store_random 529 | ; Otherwise, print open error message and exit with errno 530 | push dword eax 531 | push dword open_error_msg 532 | call premature_exit 533 | 534 | syn_scan_store_random: 535 | ; Save the returned file descriptor 536 | mov [devrfd], eax 537 | 538 | ; Store the current port in ebx 539 | xor ebx, ebx 540 | syn_scan_loop: 541 | ; Count down the number of packets sent in esi 542 | mov esi, max_parallel_ports 543 | syn_scan_send_syn_loop: 544 | ; Send a TCP packet with the SYN flag set 545 | push dword SYN_FLAG 546 | push dword ebx 547 | push dword [socketarray] 548 | call send_tcp_raw 549 | add esp, 12 550 | 551 | ; Check return value 552 | test eax, eax 553 | 554 | ; Return value should be number of bytes sent 555 | jns syn_scan_send_next 556 | ; Else, print sendto error message and exit with errno 557 | push eax 558 | push dword sendto_error_msg 559 | call premature_exit 560 | 561 | syn_scan_send_next: 562 | ; Increment current port 563 | inc ebx 564 | ; Check if we should do another port 565 | dec esi 566 | jnz syn_scan_send_syn_loop 567 | 568 | ; Copy tv_master to tv_volatile 569 | lea esi, [tv_master + 4] 570 | lea edi, [tv_volatile + 4] 571 | movsd 572 | 573 | ; Give some time for the packets to arrive 574 | push tv_volatile 575 | push dword 0 576 | push dword 0 577 | push dword 0 578 | push dword 0 579 | call sys_select 580 | add esp, 20 581 | 582 | ; Copy masterfds to rdfds 583 | mov esi, masterfds 584 | mov edi, rdfds 585 | mov ecx, masterfdslen 586 | rep movsd 587 | 588 | ; Monitor sockets with select 589 | push tv_zero 590 | push dword 0 591 | push dword 0 592 | push dword rdfds 593 | push dword [socketarray] 594 | inc dword [esp] 595 | call sys_select 596 | add esp, 20 597 | 598 | ; Check return value 599 | cmp eax, 0 600 | 601 | ; Select returns the number of bits set in rdfds 602 | je syn_scan_next_batch 603 | jns syn_scan_recv_reply_loop 604 | ; Otherwise, print select error message and exit with errno 605 | push eax 606 | push dword select_error_msg 607 | call premature_exit 608 | 609 | syn_scan_recv_reply_loop: 610 | ;;; Store the reply packet in recvbuf and look for flags ;;; 611 | 612 | ; Read the socket for a response 613 | mov [recvbuflen], dword 0xffff 614 | push dword [socketarray] 615 | call recv_packet 616 | add esp, 4 617 | 618 | ; Check return value 619 | test eax, eax 620 | 621 | ; If signed, then we were unable to read any more data 622 | ; Otherwise, recvfrom returns the number of bytes received 623 | js syn_scan_next_batch 624 | 625 | ; IP header length located in last 4 bits of first byte 626 | movzx eax, byte [recvbuf] 627 | and eax, 0xf 628 | ; Convert from words to bytes 629 | shl eax, 2 630 | ; Store the address of start of TCP header in edi 631 | mov edi, eax 632 | ; Point to flags field 633 | add eax, 13 634 | ; Bitwise separation of flags in the target byte: 635 | ; 0 | 0 | URG | ACK | PSH | RST | SYN | FIN 636 | lea esi, [recvbuf + eax] 637 | lodsb 638 | ; Filter for the ACK and SYN flags 639 | and al, 0x12 640 | ; ACK = 1, SYN = 1 641 | cmp al, 0x12 642 | jne syn_scan_recv_reply_loop 643 | 644 | ; Print the port if flags ACK and SYN are on 645 | push dword port_open_fmtstr 646 | ; Extract the port from the TCP header 647 | movzx eax, word [recvbuf + edi] 648 | xchg al, ah 649 | ; Print the open port 650 | push eax 651 | call print_port 652 | add esp, 8 653 | 654 | ; Keep receiving packets until recvfrom fails 655 | jmp syn_scan_recv_reply_loop 656 | 657 | syn_scan_next_batch: 658 | ; Scan the next batch of ports, or clean up 659 | cmp ebx, 1024 660 | jl syn_scan_loop 661 | 662 | syn_scan_done: 663 | ; Clean up file descriptors and exit 664 | push dword [devrfd] 665 | call sys_close 666 | add esp, 4 667 | call cleanup_sockets 668 | 669 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 670 | 671 | exit: 672 | mov ebp, esp 673 | mov eax, 1 674 | xor ebx, ebx 675 | int 0x80 676 | 677 | ; ------------------------------------------------------------------------------ 678 | ; send_tcp_raw: 679 | ; Send a TCP packet with custom header to the specified port 680 | ; Expects: stack - socket descriptor, port, TCP header flag 681 | ; devrfd - contains file descriptor mapped to random 682 | ; number generator device 683 | ; Returns: number of bytes sent in eax, or -errno on error 684 | send_tcp_raw: 685 | push ebp 686 | mov ebp, esp 687 | push edi 688 | 689 | ; Prepare the raw TCP packet to send 690 | mov edi, sendbuf 691 | ; Load the source port 692 | mov ax, 31337 693 | xchg al, ah 694 | stosw 695 | ; Load the destination port 696 | mov ax, [ebp + 12] 697 | xchg al, ah 698 | stosw 699 | ; SEQ = rand() 700 | call rand 701 | stosd 702 | ; ACK = 0 703 | xor eax, eax 704 | stosd 705 | ; Data offset = 5 << 4 (length of header in dwords) 706 | mov al, 0x5 707 | shl al, 4 708 | stosb 709 | ; Flags = type; 0x2 = SYN, 0x3 = RST 710 | xor al, al 711 | or al, [ebp + 16] 712 | stosb 713 | ; Max window size = 4096 bytes 714 | mov ax, 4096 715 | xchg al, ah 716 | stosw 717 | ; Checksum = 0 718 | xor ax, ax 719 | stosw 720 | ; Urgent pointer = 0 (not used) 721 | stosw 722 | 723 | ; Prepare TCP pseudo-header 724 | ; struct pseudo_hdr { 725 | ; u_int32_t src; /* 32bit source ip address*/ 726 | ; u_int32_t dst; /* 32bit destination ip address */ 727 | ; u_char mbz; /* 8 reserved bits (all 0) */ 728 | ; u_char proto; /* protocol field of ip header */ 729 | ; u_int16_t len; /* tcp length (both header and data) */ 730 | ; } 731 | ; Load source ip address 732 | mov eax, [myaddr] 733 | stosd 734 | ; Load destination ip address 735 | mov eax, [victimaddr] 736 | stosd 737 | ; 8 reserved bits (all 0) 738 | xor al, al 739 | stosb 740 | ; Protocol field of ip header = IPPROTO_TCP 741 | mov al, 6 742 | stosb 743 | ; Length of TCP header and data (20 + 0) in bytes 744 | mov ax, 20 745 | xchg al, ah 746 | stosw 747 | 748 | ; Calculate TCP header and pseudo-header checksum 749 | push dword (20+12) 750 | push sendbuf 751 | call cksum 752 | add esp, 8 753 | 754 | ; Store checksum in TCP header 755 | mov [sendbuf + 16], ax 756 | ; Set the length in bytes to send 757 | mov [sendbuflen], dword 20 758 | 759 | ; Send the SYN packet 760 | push dword [ebp + 8] 761 | call send_packet 762 | add esp, 4 763 | 764 | pop edi 765 | mov esp, ebp 766 | pop ebp 767 | ret 768 | ; ------------------------------------------------------------------------------ 769 | 770 | ; ------------------------------------------------------------------------------ 771 | ; cksum: 772 | ; Do a 16 bit checksum for given data and length 773 | ; Expects: pointer to data, data length in words 774 | ; Returns: checksum 775 | cksum: 776 | push ebp 777 | mov ebp, esp 778 | push esi 779 | 780 | ; Address 781 | mov esi, [ebp + 8] 782 | ; Length 783 | mov ecx, [ebp + 12] 784 | ; The accumulator 785 | xor edx, edx 786 | ; For the strange condition that length given was zero 787 | cmp ecx, 0 788 | jz cksum_done 789 | cksum_loop: 790 | xor eax, eax 791 | ; Load esi to lower 16 bis of eax 792 | lodsw 793 | add edx, eax 794 | dec ecx 795 | jnz cksum_loop 796 | ; Take the upper 16 bits of edx and add it to lower 16 bits 797 | mov eax, edx 798 | and eax, 0xffff 799 | shr edx, 16 800 | add eax, edx 801 | ; Take care of the carry 802 | mov edx, eax 803 | shr edx, 16 804 | add eax, edx 805 | ; Take the one's complement 806 | not eax 807 | 808 | cksum_done: 809 | pop esi 810 | mov esp, ebp 811 | pop ebp 812 | ret 813 | ; ------------------------------------------------------------------------------ 814 | 815 | ; ------------------------------------------------------------------------------ 816 | ; printstr: 817 | ; Print a string to standard output 818 | ; Expects: string address 819 | ; Returns: bytes written, -errno on error 820 | printstr: 821 | push ebp 822 | mov ebp, esp 823 | 824 | ; Get string length 825 | push dword [ebp + 8] 826 | call strlen 827 | add esp, 4 828 | ; Write to standard output 829 | push eax 830 | push dword [ebp + 8] 831 | push dword 1 832 | call sys_write 833 | add esp, 12 834 | 835 | mov esp, ebp 836 | pop ebp 837 | ret 838 | ; ------------------------------------------------------------------------------ 839 | 840 | ; ------------------------------------------------------------------------------ 841 | ; strlen: 842 | ; Calculate the length of null-terminated string 843 | ; Expects: string address 844 | ; Returns: length in eax 845 | strlen: 846 | push ebp 847 | mov ebp, esp 848 | push edi 849 | 850 | xor eax, eax 851 | xor ecx, ecx 852 | not ecx 853 | mov edi, [ebp + 8] 854 | repne scasb 855 | not ecx 856 | lea eax, [ecx - 1] 857 | 858 | pop edi 859 | mov esp, ebp 860 | pop ebp 861 | ret 862 | ; ------------------------------------------------------------------------------ 863 | 864 | ; ------------------------------------------------------------------------------ 865 | ; parse_octets: 866 | ; Convert an IPv4 address from text to binary form 867 | ; Expects: ip string, destination buffer 868 | ; Returns: 0 in eax, ~0 on error 869 | parse_octets: 870 | push ebp 871 | mov ebp, esp 872 | sub esp, 4 873 | push ebx 874 | push esi 875 | push edi 876 | 877 | mov esi, [ebp + 8] 878 | mov ebx, [ebp + 12] 879 | lea edi, [ebp - 4] 880 | ; This value comes in handy when its on the stack 881 | push edi 882 | parse_loop: 883 | ; Load the string into the four byte buffer we allocated 884 | load_string: 885 | ; This loads the next byte from [esi] into al 886 | lodsb 887 | ; Check for termination characters 888 | cmp al, byte 0 889 | je convert_octet 890 | cmp al, byte '.' 891 | je convert_octet 892 | ; Make sure its a valid octet digit (0-9) 893 | cmp al, byte '0' 894 | jl invalid_ip 895 | cmp al, byte '9' 896 | jg invalid_ip 897 | ; Otherwise this is a valid digit, store it in buffer 898 | stosb 899 | ; Make sure we stored less than 4 bytes in the buffer 900 | cmp edi, ebp 901 | jg invalid_ip 902 | jmp load_string 903 | ; If we reached here, we're ready to convert the octet into its 904 | ; binary representation 905 | convert_octet: 906 | ; First make sure we stored at least one digit 907 | cmp edi, [esp] 908 | je invalid_ip 909 | ; Okay, now we've confirmed our octet consists of 1 to 3 910 | ; digits, terminate the string by writing the null byte. 911 | mov [edi], byte 0 912 | ; The argument we need is already on the stack, it points to 913 | ; the first byte of the octet string 914 | call strtoul 915 | ; An octet has to be an 8-bit value 916 | cmp eax, 255 917 | jg invalid_ip 918 | ; Now load the next octet into the destination octet buffer 919 | mov [ebx], byte al 920 | count_octets: 921 | push ebx 922 | sub ebx, [ebp + 12] 923 | cmp ebx, 3 924 | pop ebx 925 | je last_octet 926 | cmp [esi - 1], byte '.' 927 | jne invalid_ip 928 | ; We still have more work to do! 929 | prepare_next_octet: 930 | ; First, make sure we increment the destination address. 931 | inc ebx 932 | ; Finally, reset buffer pointer to start of buffer so we can 933 | ; write another octet 934 | lea edi, [ebp - 4] 935 | jmp parse_loop 936 | last_octet: 937 | ; All four octets are supposedly loaded in the destination 938 | ; buffer. This means esi is must be pointing to a null byte. 939 | cmp [esi - 1], byte 0 940 | jne invalid_ip 941 | jmp parse_success 942 | invalid_ip: 943 | xor eax, eax 944 | not eax 945 | jmp exit_parse_octets 946 | parse_success: 947 | xor eax, eax 948 | exit_parse_octets: 949 | add esp, 4 950 | 951 | pop edi 952 | pop esi 953 | pop ebx 954 | mov esp, ebp 955 | pop ebp 956 | ret 957 | ; ------------------------------------------------------------------------------ 958 | 959 | ; ------------------------------------------------------------------------------ 960 | ; strtoul: 961 | ; Convert a number from text to binary form 962 | ; Expects: string address 963 | ; Returns: 32-bit unsigned integer in eax 964 | strtoul: 965 | push ebp 966 | mov ebp, esp 967 | 968 | ; Load string address in edx 969 | mov edx, [ebp + 8] 970 | ; Clear "result" register 971 | xor eax, eax 972 | strtoul_loop: 973 | ; Load ecx with character 974 | movzx ecx, byte [edx] 975 | inc edx 976 | ; Terminate if NUL byte 977 | cmp cl, byte 0 978 | je strtoul_done 979 | ; Multiply current result by 10, 980 | ; then add current character - '0' 981 | lea eax, [eax + eax * 4] 982 | lea eax, [ecx + eax * 2 - '0'] 983 | jmp strtoul_loop 984 | strtoul_done: 985 | mov esp, ebp 986 | pop ebp 987 | ret 988 | ; ------------------------------------------------------------------------------ 989 | 990 | ; ------------------------------------------------------------------------------ 991 | ; ultostr: 992 | ; Convert a number from binary to text form 993 | ; Expects: 32-bit unsigned integer, buffer 994 | ; Returns: nothing 995 | ultostr: 996 | push ebp 997 | mov ebp, esp 998 | push ebx 999 | push edi 1000 | push esi 1001 | 1002 | ; Push string characters onto stack in reverse order 1003 | dec esp 1004 | mov [esp], byte 0 1005 | ; ecx counts how many characters to write 1006 | xor ecx, ecx 1007 | inc ecx 1008 | mov eax, [ebp + 8] 1009 | ; This is our divisor 1010 | mov ebx, 10 1011 | ; eax: quotient contains the rest of input number 1012 | ; edx: remainder contains the digit we want to write 1013 | ultostr_loop: 1014 | xor edx, edx 1015 | div ebx 1016 | add dl, byte '0' 1017 | dec esp 1018 | mov [esp], byte dl 1019 | inc ecx 1020 | ; Stop if eax is 0 1021 | cmp eax, 0 1022 | jne ultostr_loop 1023 | ; Copy chars on stack to destination buffer 1024 | ; They will be in order because stack grows down 1025 | mov esi, esp 1026 | mov edi, [ebp + 12] 1027 | repne movsb 1028 | ; Realign stack pointer 1029 | mov esp, esi 1030 | 1031 | pop esi 1032 | pop edi 1033 | pop ebx 1034 | mov esp, ebp 1035 | pop ebp 1036 | ret 1037 | ; ------------------------------------------------------------------------------ 1038 | 1039 | ; ------------------------------------------------------------------------------ 1040 | ; spawn_socket: 1041 | ; Create a new socket and add it to masterfds 1042 | ; Expects: socket type, protocol 1043 | ; Returns: socket descriptor in eax, or -errno on error 1044 | spawn_socket: 1045 | push ebp 1046 | mov ebp, esp 1047 | 1048 | ; Push protocol 1049 | push dword [ebp + 12] 1050 | ; Push type 1051 | push dword [ebp + 8] 1052 | ; PF_INET by default 1053 | push dword 2 1054 | call sys_socket 1055 | add esp, 12 1056 | ; Check return value 1057 | test eax, eax 1058 | js spawn_socket_done 1059 | ; Add it to "master" fd bitfield 1060 | bts [masterfds], eax 1061 | 1062 | spawn_socket_done: 1063 | mov esp, ebp 1064 | pop ebp 1065 | ret 1066 | ; ------------------------------------------------------------------------------ 1067 | 1068 | ; ------------------------------------------------------------------------------ 1069 | ; cleanup_sockets: 1070 | ; Close all living sockets 1071 | ; Expects: nothing 1072 | ; Returns: nothing 1073 | cleanup_sockets: 1074 | push ebp 1075 | mov ebp, esp 1076 | 1077 | ; Initialize bitmap index to 1023, which is the highest file descriptor 1078 | ; that can exist in a fdset. 1079 | mov eax, 1023 1080 | lea ecx, [masterfds + masterfdslen] 1081 | 1082 | ; Find dword containing highest numbered file descriptor 1083 | find_highest_loop: 1084 | cmp [ecx], dword 0 1085 | jnz cleanup_sockets_loop 1086 | sub eax, 32 1087 | sub ecx, 4 1088 | jmp find_highest_loop 1089 | 1090 | ; Loop through remaining bits in fdset 1091 | cleanup_sockets_loop: 1092 | ; Clear bit to zero and store original bit in CF 1093 | btr [masterfds], eax 1094 | ; If bit was set, close the mapped socket 1095 | jc close_socket 1096 | 1097 | ; Otherwise go to next socket 1098 | jmp free_next_socket 1099 | 1100 | close_socket: 1101 | push eax 1102 | call sys_close 1103 | pop eax 1104 | 1105 | ; Keep looking for sockets to free until counter is negative 1106 | free_next_socket: 1107 | dec eax 1108 | jns cleanup_sockets_loop 1109 | 1110 | mov esp, ebp 1111 | pop ebp 1112 | ret 1113 | ; ------------------------------------------------------------------------------ 1114 | 1115 | ; ------------------------------------------------------------------------------ 1116 | ; premature_exit: 1117 | ; Print error message, clean up file descriptors, then exit with exit code 1118 | ; Expects: error msg, -errno 1119 | ; Returns: errno to shell 1120 | premature_exit: 1121 | push ebp 1122 | mov ebp, esp 1123 | 1124 | ; Print error message 1125 | push dword [ebp + 8] 1126 | call printstr 1127 | add esp, 4 1128 | ; Close file descriptor mapped to /dev/urandom 1129 | cmp dword [devrfd], 0 1130 | je premature_exit_close_sockets 1131 | push dword [devrfd] 1132 | call sys_close 1133 | add esp, 4 1134 | ; Free all open sockets (raw, icmp, tcp, etc...) 1135 | premature_exit_close_sockets: 1136 | call cleanup_sockets 1137 | ; Convert -errno to errno 1138 | mov ebx, [ebp + 12] 1139 | not ebx 1140 | inc ebx 1141 | ; Exit and send errno to shell 1142 | mov eax, 1 1143 | int 0x80 1144 | ; ------------------------------------------------------------------------------ 1145 | 1146 | ; ------------------------------------------------------------------------------ 1147 | ; sys_getuid: 1148 | ; Return the user ID of this process 1149 | ; Expects: nothing 1150 | ; Returns: uid in eax 1151 | sys_getuid: 1152 | push ebp 1153 | mov ebp, esp 1154 | 1155 | mov eax, 199 1156 | int 0x80 1157 | 1158 | mov esp, ebp 1159 | pop ebp 1160 | ret 1161 | ; ------------------------------------------------------------------------------ 1162 | 1163 | ; ------------------------------------------------------------------------------ 1164 | ; sys_read: 1165 | ; Read from file 1166 | ; Expects: fd, buffer, buffer len 1167 | ; Returns: number of bytes read, or -errno 1168 | sys_read: 1169 | push ebp 1170 | mov ebp, esp 1171 | push ebx 1172 | 1173 | mov eax, 3 1174 | mov ebx, [ebp + 8] 1175 | mov ecx, [ebp + 12] 1176 | mov edx, [ebp + 16] 1177 | int 0x80 1178 | 1179 | pop ebx 1180 | mov esp, ebp 1181 | pop ebp 1182 | ret 1183 | ; ------------------------------------------------------------------------------ 1184 | 1185 | ; ------------------------------------------------------------------------------ 1186 | ; sys_write: 1187 | ; Write to file 1188 | ; Expects: fd, buffer, buffer len 1189 | ; Returns: number of bytes written, or -errno 1190 | sys_write: 1191 | push ebp 1192 | mov ebp, esp 1193 | push ebx 1194 | 1195 | mov eax, 4 1196 | mov ebx, [ebp + 8] 1197 | mov ecx, [ebp + 12] 1198 | mov edx, [ebp + 16] 1199 | int 0x80 1200 | 1201 | pop ebx 1202 | mov esp, ebp 1203 | pop ebp 1204 | ret 1205 | ; ------------------------------------------------------------------------------ 1206 | 1207 | ; ------------------------------------------------------------------------------ 1208 | ; sys_close: 1209 | ; Close a file descriptor 1210 | ; Expects: file descriptor 1211 | ; Returns: 0 in eax | -errno in eax if error 1212 | sys_close: 1213 | push ebp 1214 | mov ebp, esp 1215 | push ebx 1216 | 1217 | mov eax, 6 1218 | mov ebx, [ebp + 8] 1219 | int 0x80 1220 | 1221 | pop ebx 1222 | mov esp, ebp 1223 | pop ebp 1224 | ret 1225 | ; ------------------------------------------------------------------------------ 1226 | 1227 | ; ------------------------------------------------------------------------------ 1228 | ; sys_open: 1229 | ; Open a file descriptor 1230 | ; Expects: file descriptor 1231 | ; Returns: fd in eax, or -errno if error 1232 | sys_open: 1233 | push ebp 1234 | mov ebp, esp 1235 | push ebx 1236 | 1237 | ; int open(const char *pathname, int flags); 1238 | mov eax, 5 1239 | mov ebx, [ebp + 8] 1240 | mov ecx, [ebp + 12] 1241 | int 0x80 1242 | 1243 | pop ebx 1244 | mov esp, ebp 1245 | pop ebp 1246 | ret 1247 | ; ------------------------------------------------------------------------------ 1248 | 1249 | ; ------------------------------------------------------------------------------ 1250 | ; sys_connect: 1251 | ; Connect a socket 1252 | ; Expects: int socket, address, address length 1253 | ; Returns: 0 in eax or -errno on error 1254 | sys_connect: 1255 | push ebp 1256 | mov ebp, esp 1257 | push ebx 1258 | push edi 1259 | 1260 | mov eax, 102 1261 | mov ebx, 3 1262 | ; sys_socketcall is a wrapper around all the socket system calls, and 1263 | ; takes as an argument a pointer to the arguments specific to the 1264 | ; socket call we want to use, so load ecx with the address of the first 1265 | ; argument on the stack 1266 | lea ecx, [ebp + 8] 1267 | int 0x80 1268 | 1269 | pop edi 1270 | pop ebx 1271 | mov esp, ebp 1272 | pop ebp 1273 | ret 1274 | ; ------------------------------------------------------------------------------ 1275 | 1276 | ; ------------------------------------------------------------------------------ 1277 | ; sys_socket: 1278 | ; Create a socket 1279 | ; Expects: int domain, int type, int protocol 1280 | ; Returns: socket descriptor in eax or -errno on error 1281 | sys_socket: 1282 | push ebp 1283 | mov ebp, esp 1284 | push ebx 1285 | push edi 1286 | 1287 | mov eax, 102 1288 | mov ebx, 1 1289 | lea ecx, [ebp + 8] 1290 | int 0x80 1291 | 1292 | pop edi 1293 | pop ebx 1294 | mov esp, ebp 1295 | pop ebp 1296 | ret 1297 | ; ------------------------------------------------------------------------------ 1298 | 1299 | ; ------------------------------------------------------------------------------ 1300 | ; sys_select: 1301 | ; Wrapper around sys_select 1302 | ; Expects: int nfds, fd_set *rdfds, fd_set *wrfds, 1303 | ; fd_set *exceptfds, struct timeval *timeout 1304 | ; Returns: total number of fildes set in fd_set structs, -errno if error 1305 | sys_select: 1306 | push ebp 1307 | mov ebp, esp 1308 | push ebx 1309 | push esi 1310 | push edi 1311 | 1312 | mov eax, 142 1313 | mov ebx, [ebp + 8] 1314 | mov ecx, [ebp + 12] 1315 | mov edx, [ebp + 16] 1316 | mov esi, [ebp + 20] 1317 | mov edi, [ebp + 24] 1318 | int 0x80 1319 | 1320 | pop edi 1321 | pop esi 1322 | pop ebx 1323 | mov esp, ebp 1324 | pop ebp 1325 | ret 1326 | ; ------------------------------------------------------------------------------ 1327 | 1328 | ; ------------------------------------------------------------------------------ 1329 | ; sys_sendto 1330 | ; Send a packet to target host 1331 | ; Expects: socket, buffer, length, flags, sockaddr, sockaddrlen 1332 | ; Returns: number of characters sent, -errno on error 1333 | sys_sendto: 1334 | push ebp 1335 | mov ebp, esp 1336 | push ebx 1337 | 1338 | mov eax, 102 1339 | mov ebx, 11 1340 | lea ecx, [ebp + 8] 1341 | int 0x80 1342 | 1343 | pop ebx 1344 | mov esp, ebp 1345 | pop ebp 1346 | ret 1347 | ; ------------------------------------------------------------------------------ 1348 | 1349 | ; ------------------------------------------------------------------------------ 1350 | ; sys_recvfrom 1351 | ; Receieve a packet from target host 1352 | ; Expects: socket, buffer, length, flags, sockaddr, sockaddrlen 1353 | ; Returns: number of characters received, -errno on error 1354 | sys_recvfrom: 1355 | push ebp 1356 | mov ebp, esp 1357 | push ebx 1358 | 1359 | mov eax, 102 1360 | mov ebx, 12 1361 | lea ecx, [ebp + 8] 1362 | int 0x80 1363 | 1364 | pop ebx 1365 | mov esp, ebp 1366 | pop ebp 1367 | ret 1368 | ; ------------------------------------------------------------------------------ 1369 | 1370 | ; ------------------------------------------------------------------------------ 1371 | ; send_packet 1372 | ; Send a packet to target host 1373 | ; Expects: stack - socket 1374 | ; sockaddr - points to target host 1375 | ; sendbuf - filled out for us 1376 | ; sendbuflen - filled out for us 1377 | ; Returns: number of bytes sent, or -errno 1378 | send_packet: 1379 | push ebp 1380 | mov ebp, esp 1381 | 1382 | push dword sockaddrlen 1383 | push dword sockaddr 1384 | push dword 0 1385 | push dword [sendbuflen] 1386 | push dword sendbuf 1387 | push dword [ebp + 8] 1388 | call sys_sendto 1389 | add esp, 24 1390 | 1391 | mov esp, ebp 1392 | pop ebp 1393 | ret 1394 | ; ------------------------------------------------------------------------------ 1395 | 1396 | ; ------------------------------------------------------------------------------ 1397 | ; recv_packet 1398 | ; Receive a packet from target host 1399 | ; Expects: stack - socket 1400 | ; sockaddr - points to target host 1401 | ; recvbuf - filled out for us 1402 | ; recvbuflen - filled out for us 1403 | ; Returns: number of bytes received, or -errno 1404 | recv_packet: 1405 | push ebp 1406 | mov ebp, esp 1407 | 1408 | push dword sockaddrlenbuf 1409 | push dword sockaddr 1410 | push dword 0 1411 | push dword [recvbuflen] 1412 | push dword recvbuf 1413 | push dword [ebp + 8] 1414 | call sys_recvfrom 1415 | add esp, 24 1416 | 1417 | mov esp, ebp 1418 | pop ebp 1419 | ret 1420 | ; ------------------------------------------------------------------------------ 1421 | 1422 | ; ------------------------------------------------------------------------------ 1423 | ; rand 1424 | ; Get a random 32-bit integer from /dev/urandom 1425 | ; Expects: stack - nothing 1426 | ; devrfd - fd with read perms mapped to /dev/urandom 1427 | ; Returns: random int in eax 1428 | rand: 1429 | push ebp 1430 | mov ebp, esp 1431 | sub esp, 4 1432 | push esi 1433 | 1434 | lea esi, [ebp - 4] 1435 | 1436 | push dword 4 1437 | push esi 1438 | push dword [devrfd] 1439 | call sys_read 1440 | add esp, 12 1441 | 1442 | lodsd 1443 | 1444 | pop esi 1445 | mov esp, ebp 1446 | pop ebp 1447 | ret 1448 | ; ------------------------------------------------------------------------------ 1449 | 1450 | ; ------------------------------------------------------------------------------ 1451 | ; print_port 1452 | ; Write to stdout telling the user if the port was open or closed. 1453 | ; Expects: port, open/closed message buffer 1454 | ; Returns: nothing 1455 | print_port: 1456 | push ebp 1457 | mov ebp, esp 1458 | 1459 | ; Convert port number to string 1460 | push writebuf 1461 | push dword [ebp + 8] 1462 | call ultostr 1463 | add esp, 8 1464 | ; Print port number 1465 | push dword writebuf 1466 | call printstr 1467 | ; Swap buffers 1468 | mov eax, [ebp + 12] 1469 | mov [esp], eax 1470 | call printstr 1471 | add esp, 4 1472 | 1473 | mov esp, ebp 1474 | pop ebp 1475 | ret 1476 | ; ------------------------------------------------------------------------------ 1477 | ; EOF ========================================================================== 1478 | --------------------------------------------------------------------------------