---
# System prepended metadata

title: 'Task1: Tìm hiểu về assembly'

---

# Training KCSC 2024
## Task1: Tìm hiểu về assembly
- Nhiệm vụ của task 1 là `Tìm hiểu về assembly và cách dùng syscall. Viết 1 chương trình assembly x64 kết nối tới localhost port 12345 và gửi nội dung`.
- Assembly là một ngôn ngữ lập trình bậc thấp. Assembly có 3 phần cơ bản là **data**, **bss** và **text**.
+**Data** là phần chứa các biến ta khởi tạo lúc chạy chương trình. Nó không thay đổi trong khi chạy.
+**Bss** là nơi sử dụng để khai báo các biến.
+**Text** là nơi để chương trình nhận biết nơi bắt đầu. Phần này phải bắt đầu bằng `global _start`

- Các câu lệnh trong Assembly đều ở trên 1 dòng và có cú pháp:
`[label]   instruction   [operands]   [;comment]`
+`instruction` là câu lệnh được thực thi ví dụ như `mov`, `add`,...
+`operands` là tham số của các câu lệnh. Nó có thể là địa chỉ, biến, độ dài,...

- Nhìn chung, mỗi khi ta làm một hành động nào đó, ví dụ như in ra màn hình chẳng hạn, cấu trúc chung của các hành động đó là:
    ```python=
    mov rax, 1          ; gọi lệnh syscall để write
    mov rdi, 1          ; file descriptor (1 là stdout)
    mov rsi, hello      ; địa chỉ của chuỗi "Hello World!"
    mov rdx, 13         ; chiều dài của chuỗi
    syscall             ; gọi hệ thống                

- Quay trở lại với nhiệm vụ chính, để kết nối đến một server và gửi một nội dung, đại khái ta phải thực hiện công việc sau đây: tạo 1 socket, đưa socket vao `rdi`, kết nối đến sever, gửi tin nhắn, đóng socket và thoát chương trình.
- Đầu tiên ta phải **khai báo dữ liệu**:
```python=
section .data
    ip db '127.0.0.1'            ; Địa chỉ IP của server
    port dw 12347                ; Port của server
    msg db 'hi', 0               ; Dữ liệu gửi đến server

section .bss
    addr resb 16                 ; Dùng để lưu địa chỉ sockaddr_in
```
- Tiếp đến là **tạo socket**:
```python=
        ; Tạo socket
        mov rax, 41    ;gọi lệnh syscall để tạo socket
	mov rdi, 2     ;dùng AF_INET (IPv4)   
	mov rsi, 1     ;dùng TCP
	mov rdx, 0     ;đặt protocol=0
	syscall        ;gọi syscall
```
- Để kết nối đến một server, ta cần cung cấp địa chỉ IP và port mà server đang lắng nghe. Cấu trúc `sockaddr_in` là một dạng đặc biệt chứa thông tin về địa chỉ mạng mà socket sẽ kết nối.
> Trong phần thiết lập `port`, ta sẽ phải chuyển từ giá trị **little-endian (byte thấp lưu trước)** thành **big-endian (byte cao lưu trước)**. Bởi vì trong kiến trúc `x86_64`, máy tính thường sẽ lưu trữ theo kiểu **little-endian** còn trong mạng thì sẽ là **big-endian**. 
```python=
    ; Đưa socket vào rdi 
    mov rdi, rax

    ; Thiết lập sockaddr_in
    mov word [addr], 2           
	
    ; Chuyển port thành big-endian
    mov ax, [port]        ; Đọc cổng vào thanh ghi ax (16 bit)
    xchg al, ah           ; Đảo byte thấp và byte cao cho nhau
    mov [addr+2], ax      ; Lưu giá trị đã chuyển đổi vào sin_port
	
    ; Thiết lập địa chỉ ip
    mov dword [addr+4], 0x0100007F; sin_addr = 127.0.0.1 (dạng nhị phân)
    xor rax, rax                 ;
    mov qword [addr+8], rax      ;

```
- Sau khi đã thiết lập xong `sockaddr_in`, ta chỉ cần **kết nối đến server và gửi nội dung**:
```python= 
; Kết nối tới server
    mov rax, 42                  ;lệnh syscall connect
    mov rsi, addr                ;Địa chỉ của sockaddr_in
    mov rdx, 16                  ;Kích thước sockaddr_in
    syscall                      ;Gọi syscall

    ; Gửi tin nhắn
    mov rax, 44                  ;syscall send
    mov rsi, msg                 ;Địa chỉ của tin nhắn
    mov rdx, 2                   ;Số byte cần gửi 
    syscall                      ;Gọi syscall 

```
- Cuối cùng, để hoàn thiện code, ta phải **đóng socket và kết thúc chương trình**:
```python=
    ; Đóng socket
    mov rax, 3                   ;syscall close
    syscall                      ;Gọi syscall để đóng socket

    ; Thoát chương trình
    mov rax, 60                  ;syscall exit
    xor rdi, rdi                 ;Exit code 0
    syscall                      ;Gọi syscall để thoát

```

- **Final script**:
```pytho=
section .data
    ip db '127.0.0.1'            ;Địa chỉ IP của server
    port dw 12347                ;Sử dụng 'dw' vì cổng là 16-bit
    msg db 'hi', 0               ;Tin nhắn gửi đến server

section .bss
    addr resb 16                 ;Dùng để lưu địa chỉ sockaddr_in (16 byte)

section .text
    global _start

_start:
    ; Tạo socket
    mov rax, 41                  ;syscall socket
    mov rdi, 2                   ;AF_INET (IPv4)
    mov rsi, 1                   ;SOCK_STREAM (TCP)
    mov rdx, 0                   ;Protocol 0
    syscall                      ;Gọi syscall, kết quả trả về trong rax

    ; Đưa socket vào rdi 
    mov rdi, rax

    ; Thiết lập sockaddr_in
    mov word [addr], 2           ;sin_family = AF_INET (2)
	
	; Chuyển port thành big-endian
	mov ax, [port]
	xchg al, ah
    mov [addr+2], ax      ;sin_port = htons(12347)
	
	; Thiết lập địa chỉ ip
    mov dword [addr+4], 0x0100007F; sin_addr = 127.0.0.1 (dạng nhị phân)
    xor rax, rax                 ;sin_zero = 0
    mov qword [addr+8], rax      ;Đặt phần sin_zero thành 0

    ; Kết nối tới server
    mov rax, 42                  ;syscall connect
    mov rsi, addr                ;Địa chỉ của sockaddr_in
    mov rdx, 16                  ;Kích thước sockaddr_in
    syscall                      ;Gọi syscall

    ; Gửi tin nhắn
    mov rax, 44                  ;syscall send
    mov rsi, msg                 ;Địa chỉ của tin nhắn
    mov rdx, 2                   ;Số byte cần gửi (2 byte cho "hi")
    syscall                      ;Gọi syscall để gửi tin nhắn

    ; Đóng socket
    mov rax, 3                   ;syscall close
    syscall                      ;Gọi syscall để đóng socket

    ; Thoát chương trình
    mov rax, 60                  ;syscall exit
    xor rdi, rdi                 ;Exit code 0
    syscall                      ;Gọi syscall

```
- Tạo một server để chạy thử xem script có hoạt động không:
![image](https://hackmd.io/_uploads/rkfX9NWJkx.png)
- Compile script chạy thử:
![image](https://hackmd.io/_uploads/H1gB54Wykl.png)
- Sau khi chạy thử thì thấy sever đã được kết nối đến và gửi một tin nhắn **hi**:
![image](https://hackmd.io/_uploads/Hyow5NW1Jl.png)
- Success!