Author Topic: Writing networking code in assembly  (Read 37425 times)

Offline turtle13

  • Jr. Member
  • *
  • Posts: 73
Re: Writing networking code in assembly
« Reply #30 on: September 22, 2017, 07:55:09 PM »
Trying to hard code a URL to test socket call and it's returning "255" (-1) so at least I know that my error_exit is working (or not)

Code: [Select]
; nasm -f elf32 -g sockettest.asm -o sockettest.o
; ld -m elf_i386 sockettest.o dns.o -o sockettest

bits 32

global _start
extern resolv


AF_INET         equ 2           ; sin_family
SOCK_STREAM     equ 1           ; socket type (TCP)
PROTOCOL        equ 0           ; just because

SYS_SOCKET      equ 1
SYS_CONNECT     equ 3
SYS_SEND        equ 9
SYS_RECV        equ 10

buflen          equ 1000

%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)          ; for converting port number to network byte order


; structure for sockaddr_in

struc sockaddr_in
        .sin_family:    resw 1          ; address family AF_INET 16- bits
        .sin_port:      resw 1          ; port # 16- bits
        .sin_addr:      resd 1          ; 32- bit IP address of web server
        .sin_pad:       resb 8          ; 8 bytes of padding
endstruc



section .data

socket_args dd AF_INET, SOCK_STREAM, 0  ; each arg is given 4 bytes

addr_len dd 1           ; 32- bit IP address



; instance of sockaddr_in structure

sock_addr_inst:
        dw AF_INET              ; family
        dw htons (80)           ; network byte order converted HTTP port number
        .addr   dd 0            ; fill in later- IP address
                dd 0, 0         ; 8 bytes of padding
        sock_addr_inst_size     equ $ - sock_addr_inst


connect_args dd 0, sock_addr_inst, sock_addr_inst_size





section .text

_start:


push "www.google.com"
call resolv             ; resolve to www.google.com IP address
add esp, 4              ; clean up stack
mov [ip_hostname], eax



; set up and create a socket file descriptor

push PROTOCOL
push SOCK_STREAM
push AF_INET

mov ecx, esp            ; places socketcall args into ecx for syscall
mov ebx, SYS_SOCKET     ; socket function to invoke (1= socket command)
mov eax, 102            ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; test for error (eax= socket file descriptor)
jl error_exit                 ; jump if negative (error)

mov [sock_fd], eax      ; place the newly created socket file descriptor into sock_fd
mov [connect_args], eax ; this will need the socket fd as an argument also



; now make a connection with the created socket

push dword [addr_len]           ; 32- bit IP address
push dword [ip_hostname]        ; resolved hostname- to- IP address
push dword [sock_fd]            ; identifies the socket

mov ecx, esp                    ; places connect args into ecx for syscall
mov ebx, SYS_CONNECT            ; socket function to invoke (3= socket connect)
mov eax, 102                    ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; check for errors
jl error_exit






xor eax, eax            ; clear eax if no errors occurred

exit:
        mov ebx, eax            ; put exit code into ebx
        mov eax, 1              ; exit sys call
        int 0x80

error_exit:
        xor ebx, ebx
        mov ebx, -1             ; produce -1 exit error code
        mov eax, 1              ; exit sys call
        int 0x80





section .bss

sock_fd         resd 1          ; socket fd = 32- bits
connect_fd      resd 1
buffer          resb buflen     ; address of 1000 byte 'buflen' (1,000 characters at a time)
get_request     resb 0x1000     ; 1000 bytes (characters) reserved for the HTTP GET request
cl_name         resb 300        ; 300 bytes (characters) reserved for URL typed at command line
cl_path_len     resd 1          ; 4 bytes (1 double word) reserved for storing length of typed URL's path
cl_filename_len resd 1          ; 4 bytes to store length of the URL's filename
cl_filename     resb 50         ; 50 bytes (characters) reserved for filename to download
cl_hostname     resb 50         ; 50 bytes (characters) reserved for the hostname of URL
cl_hostname_len resd 1          ; 4 bytes to store length of the hostname
cl_tail         resb 100        ; 100 bytes (characters) reserved for the end of URL (past hostname)
pathname        resb 100        ; 100 bytes (characters) for the parsed pathname
ip_hostname     resd 1          ; for storing the resolved hostname- to- IP address

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Writing networking code in assembly
« Reply #31 on: September 22, 2017, 09:02:58 PM »
Returns 0 now.
Code: [Select]
; nasm -f elf32 -g sockettest.asm -o sockettest.o
; ld -m elf_i386 sockettest.o dns.o -o sockettest

bits 32

global _start
extern resolv


AF_INET         equ 2           ; sin_family
SOCK_STREAM     equ 1           ; socket type (TCP)
PROTOCOL        equ 0           ; just because

SYS_SOCKET      equ 1
SYS_CONNECT     equ 3
SYS_SEND        equ 9
SYS_RECV        equ 10

buflen          equ 1000

%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)          ; for converting port number to network byte order


; structure for sockaddr_in

struc sockaddr_in
        .sin_family:    resw 1          ; address family AF_INET 16- bits
        .sin_port:      resw 1          ; port # 16- bits
        .sin_addr:      resd 1          ; 32- bit IP address of web server
        .sin_pad:       resb 8          ; 8 bytes of padding
endstruc



section .data

socket_args dd AF_INET, SOCK_STREAM, 0  ; each arg is given 4 bytes

addr_len dd 1           ; 32- bit IP address



; instance of sockaddr_in structure

sock_addr_inst:
        dw AF_INET              ; family
        dw htons (80)           ; network byte order converted HTTP port number
        .addr   dd 0            ; fill in later- IP address
                dd 0, 0         ; 8 bytes of padding
        sock_addr_inst_size     equ $ - sock_addr_inst


connect_args dd 0, sock_addr_inst, sock_addr_inst_size

name db "www.google.com", 0



section .text

_start:


push name ; "www.google.com"
call resolv             ; resolve to www.google.com IP address
add esp, 4              ; clean up stack
cmp eax, -1
je exit
mov [ip_hostname], eax
mov [sock_addr_inst.addr], eax


; set up and create a socket file descriptor

push PROTOCOL
push SOCK_STREAM
push AF_INET

mov ecx, esp            ; places socketcall args into ecx for syscall
mov ebx, SYS_SOCKET     ; socket function to invoke (1= socket command)
mov eax, 102            ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; test for error (eax= socket file descriptor)
jl exit                 ; jump if negative (error)

mov [sock_fd], eax      ; place the newly created socket file descriptor into sock_fd
mov [connect_args], eax ; this will need the socket fd as an argument also



; now make a connection with the created socket

push dword sock_addr_inst_size ;[addr_len]           ; 32- bit IP address
push dword sock_addr_inst ; tname]        ; resolved hostname- to- IP address
push dword [sock_fd]            ; identifies the socket

mov ecx, esp                    ; places connect args into ecx for syscall
mov ebx, SYS_CONNECT            ; socket function to invoke (3= socket connect)
mov eax, 102                    ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; check for errors
jl exit






xor eax, eax            ; clear eax if no errors occurred

exit:
        mov ebx, eax            ; put exit code into ebx
    neg ebx
        mov eax, 1              ; exit sys call
        int 0x80

error_exit:
        xor ebx, ebx
        mov ebx, -1             ; produce -1 exit error code
        mov eax, 1              ; exit sys call
        int 0x80





section .bss

sock_fd         resd 1          ; socket fd = 32- bits
connect_fd      resd 1
buffer          resb buflen     ; address of 1000 byte 'buflen' (1,000 characters at a time)
get_request     resb 0x1000     ; 1000 bytes (characters) reserved for the HTTP GET request
cl_name         resb 300        ; 300 bytes (characters) reserved for URL typed at command line
cl_path_len     resd 1          ; 4 bytes (1 double word) reserved for storing length of typed URL's path
cl_filename_len resd 1          ; 4 bytes to store length of the URL's filename
cl_filename     resb 50         ; 50 bytes (characters) reserved for filename to download
cl_hostname     resb 50         ; 50 bytes (characters) reserved for the hostname of URL
cl_hostname_len resd 1          ; 4 bytes to store length of the hostname
cl_tail         resb 100        ; 100 bytes (characters) reserved for the end of URL (past hostname)
pathname        resb 100        ; 100 bytes (characters) for the parsed pathname
ip_hostname     resd 1          ; for storing the resolved hostname- to- IP address

As you can see, I've changed quite a lot. Haven't really determined much. I'll paste a request into it and see if I can get it to actually work.

Later,
Frank

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Writing networking code in assembly
« Reply #32 on: September 22, 2017, 09:08:21 PM »
Well, I pasted a request into it, and it did work. Unfortunately, I screwed up and overwrote it, so I can't post it. It did work...

Best,
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Writing networking code in assembly
« Reply #33 on: September 22, 2017, 10:03:55 PM »
Okay, I reconstructed it...
Code: [Select]
; nasm -f elf32 -g sockettest.asm -o sockettest.o
; ld -m elf_i386 sockettest.o dns.o -o sockettest

bits 32

global _start
extern resolv


AF_INET         equ 2           ; sin_family
SOCK_STREAM     equ 1           ; socket type (TCP)
PROTOCOL        equ 0           ; just because

SYS_SOCKET      equ 1
SYS_CONNECT     equ 3
SYS_SEND        equ 9
SYS_RECV        equ 10

buflen          equ 1000

%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)          ; for converting port number to network byte order


; structure for sockaddr_in

struc sockaddr_in
        .sin_family:    resw 1          ; address family AF_INET 16- bits
        .sin_port:      resw 1          ; port # 16- bits
        .sin_addr:      resd 1          ; 32- bit IP address of web server
        .sin_pad:       resb 8          ; 8 bytes of padding
endstruc



section .data

socket_args dd AF_INET, SOCK_STREAM, 0  ; each arg is given 4 bytes

addr_len dd 1           ; 32- bit IP address



; instance of sockaddr_in structure

sock_addr_inst:
        dw AF_INET              ; family
        dw htons (80)           ; network byte order converted HTTP port number
        .addr   dd 0            ; fill in later- IP address
                dd 0, 0         ; 8 bytes of padding
        sock_addr_inst_size     equ $ - sock_addr_inst


connect_args dd 0, sock_addr_inst, sock_addr_inst_size

name db "www.google.com", 0

    msg db"GET / HTTP/1.1", 13, 10
        db "Host: www.google.com", 13, 10
db "Connection: close", 13, 10
db "User-Agent: assembly language", 13, 10, 13, 10
    msg_len equ $ - msg


section .text

_start:


push name ; "www.google.com"
call resolv             ; resolve to www.google.com IP address
add esp, 4              ; clean up stack
cmp eax, -1
je exit
mov [ip_hostname], eax
mov [sock_addr_inst.addr], eax


; set up and create a socket file descriptor

push PROTOCOL
push SOCK_STREAM
push AF_INET

mov ecx, esp            ; places socketcall args into ecx for syscall
mov ebx, SYS_SOCKET     ; socket function to invoke (1= socket command)
mov eax, 102            ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; test for error (eax= socket file descriptor)
jl exit                 ; jump if negative (error)

mov [sock_fd], eax      ; place the newly created socket file descriptor into sock_fd
mov [connect_args], eax ; this will need the socket fd as an argument also



; now make a connection with the created socket

push dword sock_addr_inst_size   ; size of the structure
push dword sock_addr_inst        ; address of the structure
push dword [sock_fd]            ; identifies the socket

mov ecx, esp                    ; places connect args into ecx for syscall
mov ebx, SYS_CONNECT            ; socket function to invoke (3= socket connect)
mov eax, 102                    ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; check for errors
jl exit

; write the request to socket
mov eax, 4
mov ebx, [sock_fd]
mov ecx, msg
mov edx, msg_len
int 80h

; read the page (if they send it to us)
mov eax, 3
mov ebx, [sock_fd]
mov ecx, buffer
mov edx, buflen
int 80h

; write it to stdout
mov edx, eax ; length is whatever we read
mov eax, 4
mov ebx, 1
mov ecx, buffer
int 80h


xor eax, eax            ; clear eax if no errors occurred

exit:
        mov ebx, eax            ; put exit code into ebx
    neg ebx
        mov eax, 1              ; exit sys call
        int 0x80

; this throws away information about what the problem was
; I don't use it
error_exit:
        xor ebx, ebx
        mov ebx, -1             ; produce -1 exit error code
        mov eax, 1              ; exit sys call
        int 0x80





section .bss

sock_fd         resd 1          ; socket fd = 32- bits
connect_fd      resd 1
buffer          resb buflen     ; address of 1000 byte 'buflen' (1,000 characters at a time)
get_request     resb 0x1000     ; 1000 bytes (characters) reserved for the HTTP GET request
cl_name         resb 300        ; 300 bytes (characters) reserved for URL typed at command line
cl_path_len     resd 1          ; 4 bytes (1 double word) reserved for storing length of typed URL's path
cl_filename_len resd 1          ; 4 bytes to store length of the URL's filename
cl_filename     resb 50         ; 50 bytes (characters) reserved for filename to download
cl_hostname     resb 50         ; 50 bytes (characters) reserved for the hostname of URL
cl_hostname_len resd 1          ; 4 bytes to store length of the hostname
cl_tail         resb 100        ; 100 bytes (characters) reserved for the end of URL (past hostname)
pathname        resb 100        ; 100 bytes (characters) for the parsed pathname
ip_hostname     resd 1          ; for storing the resolved hostname- to- IP address
So if you can parse the accursed command line properly (good luck!), your socket code should work.

Best,
Frank



Offline turtle13

  • Jr. Member
  • *
  • Posts: 73
Re: Writing networking code in assembly
« Reply #34 on: September 23, 2017, 05:41:41 AM »
My last final push. Toward the bottom I am trying to write to a file descriptor so it can be written locally. I'm not sure how to declare a local directory to be written to using the open sys call. I've given up on parsing the command line stuff.

It's been a good run. Tried my hardest and best. At least I learned something. Gonna have lots to drink tonight.

Code: [Select]
; nasm -f elf32 -g sockettest.asm -o sockettest.o
; ld -m elf_i386 sockettest.o dns.o -o sockettest

bits 32

global _start
extern resolv


AF_INET         equ 2           ; sin_family
SOCK_STREAM     equ 1           ; socket type (TCP)
PROTOCOL        equ 0           ; just because

SYS_SOCKET      equ 1
SYS_CONNECT     equ 3
SYS_WRITE       equ 4
SYS_OPEN        equ 5
SYS_SEND        equ 9
SYS_RECV        equ 10

buflen          equ 1000

%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)          ; for converting port number to network byte order


; structure for sockaddr_in

struc sockaddr_in
        .sin_family:    resw 1          ; address family AF_INET 16- bits
        .sin_port:      resw 1          ; port # 16- bits
        .sin_addr:      resd 1          ; 32- bit IP address of web server
        .sin_pad:       resb 8          ; 8 bytes of padding
endstruc



section .data

socket_args dd AF_INET, SOCK_STREAM, 0  ; each arg is given 4 bytes

addr_len dd 1           ; 32- bit IP address



; instance of sockaddr_in structure

sock_addr_inst:
        dw AF_INET              ; family
        dw htons (80)           ; network byte order converted HTTP port number
        .addr   dd 0            ; fill in later- IP address
                dd 0, 0         ; 8 bytes of padding
        sock_addr_inst_size     equ $ - sock_addr_inst


connect_args dd 0, sock_addr_inst, sock_addr_inst_size

name db "www.google.com", 0


msg db"GET / HTTP/1.0", 13, 10
        db "Host: www.google.com", 13, 10
db "Connection: close", 13, 10, 13, 10
msg_len equ $ - msg



section .text

_start:

push name               ; pointer to URL
call resolv             ; resolve to www.google.com IP address
add esp, 4             ; clean up stack
cmp eax, -1
je exit
mov [ip_hostname], eax
mov [sock_addr_inst.addr], eax          ; puts ip address into sock addr instance



; set up and create a socket file descriptor

push PROTOCOL
push SOCK_STREAM
push AF_INET

mov ecx, esp            ; places socketcall args into ecx for syscall
mov ebx, SYS_SOCKET     ; socket function to invoke (1= socket command)
mov eax, 102            ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; test for error (eax= socket file descriptor)
jl exit                 ; jump if negative (error)

mov [sock_fd], eax      ; place the newly created socket file descriptor into sock_fd
mov [connect_args], eax ; this will need the socket fd as an argument also



; now make a connection with the created socket

push dword sock_addr_inst_size  ; 32- bit IP address
push dword sock_addr_inst       ; resolved hostname- to- IP address
push dword [sock_fd]            ; identifies the socket

mov ecx, esp                    ; places connect args into ecx for syscall
mov ebx, SYS_CONNECT            ; socket function to invoke (3= socket connect)
mov eax, 102                    ; socketcall syscall
int 0x80

add esp, 12             ; clean up stack

cmp eax, 0              ; check for errors
jl exit


; write the request to socket
mov eax, 4
mov ebx, [sock_fd]
mov ecx, msg
mov edx, msg_len
int 0x80


; read the page
mov eax, 3
mov ebx, [sock_fd]
mov ecx, buffer
mov edx, buflen
int 0x80


; open/ create file
mov eax, SYS_OPEN
mov ebx, PATHNAME?
mov ecx, 3              ; read and write access
mov edx, 00700          ; read, write, execute permission
int 0x80
mov [file_fd], ebx      ; stores newly created file descriptor to write to


; write it to file_fd
mov edx, eax ; length is whatever we read
mov eax, SYS_WRITE
mov ebx, [file_fd]
mov ecx, buffer
int 0x80



xor eax, eax            ; clear eax if no errors occurred

exit:
        mov ebx, eax            ; put exit code into ebx
        neg ebx       
        mov eax, 1              ; exit sys call
        int 0x80







section .bss

sock_fd         resd 1          ; socket fd = 32- bits
connect_fd      resd 1
buffer          resb buflen     ; address of 1000 byte 'buflen' (1,000 characters at a time)
get_request     resb 0x1000     ; 1000 bytes (characters) reserved for the HTTP GET request
cl_name         resb 300        ; 300 bytes (characters) reserved for URL typed at command line
cl_path_len     resd 1          ; 4 bytes (1 double word) reserved for storing length of typed URL's path
cl_filename_len resd 1          ; 4 bytes to store length of the URL's filename
cl_filename     resb 50         ; 50 bytes (characters) reserved for filename to download
cl_hostname     resb 50         ; 50 bytes (characters) reserved for the hostname of URL
cl_hostname_len resd 1          ; 4 bytes to store length of the hostname
cl_tail         resb 100        ; 100 bytes (characters) reserved for the end of URL (past hostname)
pathname        resb 100        ; 100 bytes (characters) for the parsed pathname
ip_hostname     resd 1          ; for storing the resolved hostname- to- IP address
file_fd         resd 1

« Last Edit: September 23, 2017, 05:48:43 AM by turtle13 »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Writing networking code in assembly
« Reply #35 on: September 23, 2017, 06:44:53 AM »
I imagine "myfile.text", 0 would work. If that's a problem. "./myfile.txt", 0 Obviously you haven't tried this. Besides sys_open you might look into sys_creat (8) (note not "create"!).

The "permissions" are usually to be represented as octal. C takes a leading zero as octal, Nasm does not. 700q will probably work better than 700 decimal.

The file descriptor will be in eax, not ebx, You will certaimly want to check for error.

Don't hurt yourself.

Best,
Frank