# RISC - **RISC** (viết tắt của **R**educed **I**nstructions **S**et **C**omputer - Máy tính với tập lệnh đơn giản hóa) - là một phương pháp thiết kế các bộ vi_xử_lý ([VXL](https://vi.wikipedia.org/wiki/Vi_x%E1%BB%AD_l%C3%BD)) theo hướng đơn giản hóa tập lệnh >trong đó thời gian thực thi tất cả các lệnh đều như nhau # Seminar - link canva: https://www.canva.com/design/DAGbajqwMNY/maXdwMXxM57_cP8-ATKCIw/view?utm_content=DAGbajqwMNY&utm_campaign=designshare&utm_medium=link2&utm_source=uniquelinks&utlId=h9d63fddf40 # ARM - luyện tập trên 2 kiến trúc 'i386' và 'amd64' cũng đã nhiều - nên blog này sẽ nghiên cứu về kiến trúc ARM là chủ yếu > không lạ cũng không mới, khả năng gặp nhiều trong các bài CTF-pwnable ## overview - ARM Cortex – Mx là vi xử lý được sử dụng phổ biến nhất hiện nay trong lĩnh vực hệ thống nhúng - **ARM** (viết cách điệu là **arm**) full name là **Advanced RISC Machine** - là một họ kiến trúc dạng [RISC](https://vi.wikipedia.org/wiki/RISC) cho các [vi xử lý máy tính](https://vi.wikipedia.org/wiki/CPU), được cấu hình cho các môi trường khác nhau ## registers ### ARM 32-bits ![image](https://hackmd.io/_uploads/BJikpd0XT.png) - thanh ghi từ **R0** tới **R12** là "thanh ghi dùng chung" (**general purpose register**) > lưu trữ dữ liệu của các phép tính toán, lưu trữ địa chỉ > có độ rộng 32bit > **R11** và **R12** ít được quan tâm nên list vào chung - thanh ghi **R7** sẽ là **syscall number** > [link](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/syscalls.md#arm-32_bit_EABI) - thanh ghi **R13** được gọi là ``StackPointer (SP)`` sẽ trỏ tới thành phần nằm trên đỉnh của stack > ngoài ra còn có 2 nhánh thanh ghi nữa: > **PSP** (**P**rocessor **S**tack **P**ointer) và **MSP** (**M**ain **S**tack **P**ointer) > những thanh ghi này được gọi là "Banked version of SP" - thanh ghi **R14** được gọi là ``Link Register (LR)`` sử dụng để lưu và trả lại vị trí của hàm > lưu thông tin của subroutines, function call và exceptions - thanh ghi **R15** được gọi là ``Program Counter (PC)`` sẽ trỏ tới tập lệnh tiếp theo được lấy từ bộ nhớ, bộ xử lý sẽ thực hiện lệnh này sử dụng PC sau đó sẽ tăng PC lên > thanh ghi này chứa địa chỉ câu lệnh sẽ được thực thi :::spoiler 👉 more info - Với cấu trúc của ARM là **AAPCS** (**A**RM **A**rchitecture **P**rocedure **C**all **S**tandard), một phần của **ABI** (**A**pplication **B**inary **I**nterface) sẽ sử dụng các thanh ghi R0, R1, R2 để đưa các tham số đầu vào vào hàm C, các tham số được trả lại nằm trong thanh ghi R0 - giả định **SP** sẽ luôn là **MSP** (**M**ain **S**tack **P**ointer) chứ không phải là **PSP** (**P**rocess **S**tack **P**ointer) ::: - có 3 trạng thái của thanh ghi là: - **APSR** (**A**pplication **P**rogram **S**tatus **R**egister) - **IPSR** (**I**nterrupt **P**rogram **S**tatus **R**egister) - **EPSR** (**E**xecution **P**rogram **S**tatus **R**egister) ![image.png](https://hackmd.io/_uploads/S1B75OU7T.png) - ngoài ra còn có 1 trạng thái thường thấy nhất khi debug ARM32 là **CPRS** (**C**urrent **P**rogram **S**tatus **R**egister) ![image](https://hackmd.io/_uploads/rkTbxtRXa.png) - các bit ``N,Z,V,C,Q`` đưa thông tin về kết quả của quá trình tính toán ALU trước đó - ``N`` bit được set sau một phép tính số học hoặc logic để xác định kết quả có là âm hay không > identicial to **SF** in EFLAG register on x86 - ``Z`` bit được set nếu kết quả là 0 > identicial to **ZF** in EFLAG register on x86 - ``C`` bit được set khi tràn giá trị unsigned > identicial to **CF** in EFLAG register on x86 - ``V`` bit được set khi tràn giá trị signed > identicial to **OF** in EFLAG register on x86 - ``Q`` bit khi trạng thái “bão hòa” xảy ra - ``T`` bit luôn là 1 thực hiện các tập lệnh Thumb® của ARM®Cortex™-M :::spoiler more info 👉 ![image](https://hackmd.io/_uploads/H1NZWY0Q6.png) ::: - ``ISR_NUMBER`` cho thấy ngắt nào đang được xử lý > cái này liên quan đến "ngắt" - là thành phần rất quan trọng trong một hệ thống nhúng > là phần mềm kích hoạt phần cứng hoạt động #### relating to Intel processors ![image](https://hackmd.io/_uploads/BJE1RuRX6.png) ### ARM 64-bits - còn 1 cái tên khác là **aarch64** ![image](https://hackmd.io/_uploads/r1Dx8colA.png) - trên 64-bits thì sẽ có 31 **general purpose register** > tương ứng từ **x0** đến **x30** > **x0** thường giữ return value (giống $rax) - ngoài ra cũng có các lower access 32-bits là **w0** đến **w30** - các arguments sẽ được push vào **x0** -> **x7** > lố sẽ tính từ stack trở đi - thanh ghi **x8** sẽ là **syscall number** >[link](https://www.chromium.org/chromium-os/developer-library/reference/linux-constants/syscalls/#arm64-64-bit) - thanh ghi **x30** chứa return address ### Special Registers: - ``Frame Pointer (FP)`` : giống $rbp - ``Link Register (LR)`` : chứa return addr - ``Program Counter (PC)`` : chứa địa chỉ của lệnh hiện tại đang thực hiện - ``Stack Pointer (SP)`` : chứa địa chỉ đỉnh stack ## Intructions - xem [link](https://hocarm.org/lap-trinh-hop-ngu-voi-arm/) ### ARM32 - có một số lệnh cơ bản như: - ``MOV R0, #1`` : đưa 1 vào R0 - ``ADD R1, R2, R3`` : cộng R2 với R3 và đưa vào R1 - ``LDR R3, [R8]`` : đưa giá trị trong R8 vào R3 - ``POP {R3,PC}`` : đưa value stack hiện tại vào R3 và return ### ARM64 - tương đồng ARM32 nhưng có 1 số minor change | Opcode | Purpose | |--------|------------------------------------------------------------| | MOV | Used to copy values. | | MOVN | Used to copy negative values. | | LSL/LSR| Logical shift left, Logical shift right. | | LDR | Load data from the memory to the register. | | STR | Store data from the register to the memory. | | LDP | Load a pair of values to the registers. | | STP | Store a pair of values to memory. | | ADR | Loads an address within a certain range, without performing a data load. | | CMP | Compare two values, flags are updated automatically. | | B | ``B <label>`` performs a direct, PC-relative, branch to ``<label>``. | | BR | `BR` performs an indirect, or absolute, branch to the address specified. | | BLR | Branch to a register and stores the address of the next instruction into the link register (x30). | ### example ![image](https://hackmd.io/_uploads/SkeibKAQT.png) :::spoiler **LDR** and **STR** ![image](https://hackmd.io/_uploads/Sk-WMF0X6.png) ``` LDR R2, [R0] @ [R0] - origin address is the value found in R0. STR R2, [R1] @ [R1] - destination address is the value found in R1. ``` - **LDR** operation: loads the value at the address found in **R0** to the destination register **R2** - **STR** operation: stores the value found in **R2** to the memory address found in **R1** ```asm # Offet form: Immediate value as the offset STR Ra, [Rb, imm] LDR Ra, [Rc, imm] ``` ```asm # Offset form: Register as the offset STR Ra, [Rb, Rc] LDR Ra, [Rb, Rc] ``` ```asm # Offset form: Scaled register as the offset LDR Ra, [Rb, Rc, <shifter>] STR Ra, [Rb, Rc, <shifter>] ``` ::: ## document - [ARM-32 Intrucction Set](https://docs.google.com/viewerng/viewer?url=https://iitd-plos.github.io/col718/ref/arm-instructionset.pdf) - [ARM-64 Course · Reverse Engineering](https://0xinfection.github.io/reversing/pages/arm-64-course.html) - [ARM64 Assembly Language Notes](https://cit.dixie.edu/cs/2810/arm64-assembly.html) ## DEBUG - ta sẽ dùng 1 tool **qemu** để hỗ trợ quá trình DEBUG ### setup qemu ```bash $ sudo apt-get install qemu $ sudo apt-get install gdb-multiarch $ sudo apt install qemu-system-arm $ pip install tomli $ git clone https://git.qemu.org/git/qemu.git $ cd qemu $ #gỡ rối BEGIN $ sudo apt-get install sphinx $ pip install sphinx_rtd_theme==1.1.1 $ sudo apt-get install ninja-build $ sudo apt-get install libpixman-1-dev $ sudo add-apt-repository ppa:gnome3-team/gnome3-staging $ sudo apt-get update $ sudo apt update $ sudo dpkg --add-architecture i386 $ sudo apt install libc6:i386 $ sudo apt-get install libgvnc-1.0-dev $ sudo apt-get install device-tree-compiler $ sudo apt-get install libfdt-dev $ sudo apt-get install libcapstone-dev $ #nếu còn nhiều lỗi hiện 'NO' khi cài, cứ quăng hỏi chatgpt =)))) $ #gỡ rối END $ ./configure --target-list=arm-softmmu,aarch64-softmmu && make ``` ### setup debug static ```bash $ sudo apt-get install libc6-dev-armhf-cross $ sudo apt-get install gcc-arm-linux-gnueabihf ``` 1. terminal 1 ``$ qemu-arm -g <port> <binary>`` > với \<port> là số mình tuỳ chọn ---> mở máy chủ host 2. terminal 2 ``$ sudo gdb-multiarch <binary> `` ``gef➤ target remote :<port> `` > ta sẽ debug với nc là localhost:\<port> (localhost ở đây cho 0 vẫn được) ### setup debug dynamic ```bash $ sudo apt-get install qemu-user $ sudo apt-get install qemu-user-static $ sudo apt-get install libc6-arm64-cross $ apt-cache search 'libstdc++' | grep arm64 $ sudo mkdir /etc/qemu-binfmt $ sudo ln -s /usr/aarch64-linux-gnu /etc/qemu-binfmt/aarch64 ``` - tương tự với debug tĩnh, nhưng ở đây script ta viết sẽ bao quát hơn #### exploit - đầu tiên trong file ``solve.py`` mình sẽ exploit ```python p = process(['qemu-arm', '-g' ,'1234' ,'./vuln']) context.log_level = 'debug' raw_input('Debug') ``` >'-g' là gdb server (có thể gọi là mở port 1234) >'./vuln' sẽ là file binary mình muốn debug 1. terminal 1 ```bash $ ./solve.py DEBUG ``` #### debuger - nếu thích, ta có thể viết thêm 1 file để setup breakpoint sẵn - mẫu file ``debug.gdb``: ```gdb file vuln set architecture arm target remote :1234 b*main+38 c ``` 2. terminal 2 ```bash $ gdb-multiarch -q -x debug.dbg ``` - hoặc ta chạy chay tự set breakpoint cũng được ```bash $ gdb-multiarch vuln pwndbg> set architecture arm The target architecture is set to "arm". pwndbg> target remote :1234 pwndbg> b*main+38 ``` ## reference - https://vi.wikipedia.org/wiki/C%E1%BA%A5u_tr%C3%BAc_ARM - https://hocarm.org/ - https://ad2001.gitbook.io/a-noobs-guide-to-arm-exploitation - https://medium.com/@hocsama/svattt-2017-hello-arm-1888dab81a9d > cái nào bị chặn thì bật VPN lên (do bị chặn ở server VN) ## Heap in ARM - tương đồng với khi exploit trên 'x86' và 'amd64' > overview: https://hackmd.io/@trhoanglan04/heap_introduce - tồn tại các BUG phổ biến như DBF, UAF > overview: https://hackmd.io/@trhoanglan04/heap_exploit # RISC-V - có exploit 1 bài kiến trúc 'risc-v' trước đây ([xem wu](https://hackmd.io/@trhoanglan04/rylCPYDSh#ROPV)) ## overview - là một kiến trúc tập lệnh ([ISA](https://vi.wikipedia.org/wiki/Ki%E1%BA%BFn_tr%C3%BAc_t%E1%BA%ADp_l%E1%BB%87nh)) phần cứng mã nguồn mở dựa trên kiến trúc tập lệnh máy tính với tập lệnh đơn giản hóa ([RISC](https://vi.wikipedia.org/wiki/RISC)) ![image](https://hackmd.io/_uploads/rJvdyD14a.png) ## registers - kiến trúc **RISC-V** có 32 thanh ghi (32-bits) ![image](https://hackmd.io/_uploads/rkSC1v1V6.png) ## instruction - RISC-V instruction được chia thành các định dạng khác nhau dựa trên cấu trúc và loại toán hạng của chúng - Các loại phổ biến 1. **R-type**: Được sử dụng cho các phép toán số học và logic, bao gồm hai thanh ghi nguồn và một thanh ghi đích. 2. **I-type**: Được sử dụng cho các hoạt động tức thời, trong đó một toán hạng là thanh ghi và toán hạng còn lại là giá trị tức thời 3. **S-type**: Được sử dụng cho các hoạt động `store`, lưu trữ dữ liệu từ register vào memory. 4. **B-type**: Được sử dụng cho các hoạt động `branch`, thực hiện `jump` có điều kiện dựa trên comparison results. 5. **U-type**: Được sử dụng cho các`jump` vô điều kiện và các hằng số mức lệnh. 6. **J-type**: Được sử dụng cho các hoạt động `jump` operations với signed immediate offset. ![image](https://hackmd.io/_uploads/H1EErOOS0.png) ### Arithmetic - **ADD**: Adds two registers and stores the result in a destination register. Syntax: `ADD rd, rs1, rs2` - **SUB**: Subtracts one register from another and stores the result in a destination register. Syntax: `SUB rd, rs1, rs2` - **ADDI**: Adds an immediate value to a register and stores the result in a destination register. Syntax: `ADDI rd, rs1, imm` ### Logical - **AND**: Performs bitwise AND between two registers and stores the result in a destination register. Syntax: `AND rd, rs1, rs2` - **OR**: Performs bitwise OR between two registers and stores the result in a destination register. Syntax: `OR rd, rs1, rs2` - **XOR**: Performs bitwise XOR between two registers and stores the result in a destination register. Syntax: `XOR rd, rs1, rs2` ### Memory Access #### Load - **LW** (Load Word): Loads a 32-bit word from memory into a register. Syntax: ``LW rd, offset(rs1)`` Example: ``LW x1, 0(x2)`` - **LH** (Load Halfword): Loads a 16-bit halfword from memory into a register. Syntax: ``LH rd, offset(rs1)`` Example: ``LH x3, 4(x4)`` - **LB** (Load Byte): Loads an 8-bit byte from memory into a register. Syntax: ``LB rd, offset(rs1)`` Example: ``LB x5, -8(x6)`` >[!Note]Load instructions yêu cầu chỉ định destination register (rd) rõ ràng, memory address thu được bằng cách adding offset vào base register (offset(rs1)). #### Store - **SW** (Store Word): Stores a 32-bit word from a register into memory. Syntax: ``SW rs2, offset(rs1)`` Example: ``SW x7, 16(x8)`` - **SH** (Store Halfword): Stores a 16-bit halfword from a register into memory. Syntax: ``SH rs2, offset(rs1)`` Example: ``SH x9, -4(x10)`` - **SB** (Store Byte): Stores an 8-bit byte from a register into memory. Syntax: ``SB rs2, offset(rs1)`` Example: ``SB x11, 12(x12)`` >[!Note]Store instructions yêu cầu chỉ định source register (rs2) rõ ràng, memory address thu được bằng cách adding offset vào base register (offset(rs1)). ### Control Transfer - **JAL** (Jump and Link): Jumps to a target address and stores the return address in a register. Syntax: `JAL rd, target` - **JALR** (Jump and Link Register): Jumps to a target address with a register offset and stores the return address in a register. Syntax: `JALR rd, rs1, offset` - **BEQ** (Branch if Equal): Branches to a target address if two registers are equal. Syntax: `BEQ rs1, rs2, target` - **BNE** (Branch if Not Equal): Branches to a target address if two registers are not equal. Syntax: `BNE rs1, rs2, target` - **BLT** (Branch if Less Than): Branches to a target address if one register is less than another. Syntax: ``BLT rs1, rs2, target`` Example: `BLT x6, x7, target_label` - **BGE** (Branch if Greater Than or Equal): Branches to a target address if one register is greater than or equal to another. Syntax: `BGE rs1, rs2, target` Example: `BGE x8, x9, target_label` ### Syscall - **ECALL** (Environment Call): The ECALL instruction is used to invoke a system call and transfer control to the operating system. ```py # Load system call number into register a7 and arguments into other registers `LI a7, <system_call_number>` # Perform system call `ECALL` ``` ### Relative ![image](https://hackmd.io/_uploads/HJsc9EI9ye.png) ## DEBUG ### setup qemu ```bash $ sudo apt install qemu-system-misc qemu-user-static binfmt-support $ git clone https://git.qemu.org/git/qemu.git #skip if exist $ cd qemu $ ./configure --target-list=riscv64-softmmu $ make $ update-binfmts --display #check ``` ### setup debug 1. terminal1 ```bash $ qemu-riscv64 -g <port> <binary> ``` 2. terminal2 ```bash $ sudo gdb-multiarch <binary> pwndbg> target remote :<port> ``` ## coding RISC-V - thấy mỗi [link](https://www.cs.cornell.edu/courses/cs3410/2019sp/riscv/interpreter/#) này là mới mẻ ## reference - [link](https://embeddedinn.com/articles/tutorial/Linux-Python-on-RISCV-using-QEMU-from-scratch/) > chưa có time xem nên coi đỡ link này nhó =))) - https://vi.wikipedia.org/wiki/RISC-V