Kỹ thuật Direct syscall và Indirect syscall

Published By: BLUE TEAM

Published On: 07/07/2025

Published in:

Giới thiệu

Direct syscallindirect syscall là hai kỹ thuật gọi hệ thống thường được sử dụng trong lĩnh vực bảo mật tấn công (offensive security), đặc biệt bởi các malware, shellcode, hoặc các công cụ khai thác nhằm né tránh sự giám sát của EDR/AV.

Trước khi nói về direct và indirect syscall, lý do và cách sử dụng các kỹ thuật này, điều quan trọng là phải làm rõ syscall là gì. Về mặt kỹ thuật, syscall là một phần của syscall stub trong Native api hoặc native function. Syscall của Native api là một tập hợp các lệnh assembly và cho phép chuyển đổi tạm thời (chuyển đổi CPU) từ user mode sang kernel mode để thực hiện các thao tác yêu cầu thực hiện trên kernel mode. Ví dụ: Khi một chương trình muốn đọc file, nó gọi CreateFile, từ đó hệ điều hành sẽ dùng syscall tại hàm native api NtCreateFile để thực hiện thao tác thật trong kernel

Sơ đồ hoạt động của syscall

Một khái niệm cần quan tâm nữa của syscall là System Service Number (SSN). SSN là một số nguyên dùng để xác định duy nhất một syscall (lời gọi hệ thống) trong Windows. Mỗi hàm hệ thống như NtAllocateVirtualMemory, NtReadVirtualMemory, NtCreateThreadEx, v.v. đều được gán một SSN tương ứng. Khi một chương trình trong user mode gọi một, SSN sẽ được nạp vào thanh ghi EAX hoặc RAX (tùy phiên bản máy) sau đó sẽ gọi lệnh syscall sẽ chuyển quyền điều khiển xuống kernel mode. Lấy ví dụ NtReadFile có SSN là 6 còn NtWriteFile là 8

 

NtReadFile
NtWriteFile

Tác dộng của EDR trong syscall

Ngày nay, có một số hàm native như NtAllocateVirtualMemory, NtProtectVirtualMemory, VirtualAlloc… thường xuyên bị các loại mã độc hay shellcode lợi dụng để thực hiện các hành vi độc hại.Do đó, trong những năm gần đây, ngày càng nhiều nhà cung cấp EDR triển khai kỹ thuật hooking usermode, nói một cách đơn giản, cho phép EDR chuyển hướng mã được thực thi trong bối cảnh API đến hooking.dll của riêng EDR để phân tích khi chạy. Nếu mã được thực thi không có vẻ độc hại đối với EDR, syscall tương quan sẽ được thực thi, nếu không, EDR sẽ ngăn chặn việc thực thi. Hooking usermode khiến việc thực thi phần mềm độc hại trở nên khó khăn hơn, do đó, kẻ tấn công sử dụng nhiều kỹ thuật khác nhau như unhooking API, direct system calls or indirect system calls để bỏ qua EDR.Lấy ví dụ một đoạn stub code của NtReadVirtualMemory trên hệ thống trong trường hợp không có EDR, nghĩa là syscall NtReadVirtualMemory không được hooked:

Chúng ta có thể thấy đoạn mã lệnh syscall NtReadVirtualMemory bắt đầu bằng các instructions:

...tương đương với 4 mã lệnh sau:

Và bên dưới là ảnh của hàm NtReadVirtualMemory khi mà được hook bởi EDR:

Các giải pháp EDR sử dụng các kỹ thuật hook để xác định xem một chức năng có được sử dụng cho mục đích xấu hay không. Cùng một phương pháp như sau:

  • Inject EDRVendor.dll vào tiến trình mới tạo
  • Cài đặt các inline hook trên các hàm API thường bị lạm dụng.
  • Xác định xem hàm có bị lạm dụng vì mục đích xấu hay không và nếu không thì tiếp tục thực hiện native function

Lệnh jmp ở trên ảnh là để nhảy đến module của EDR

Direct and Indirect syscall

Attacker, để có thể thực hiện các hành vi của mình, cần một kỹ thuật mới để mã độc của mình không bị phát hiện, cần sử dụng một kỹ thuật mới mà có thể vượt qua sự giám sát của EDR, đó chính là direct và indirect syscall. Cách hoạt động của hai kỹ thuật này về cơ bản sẽ là mã độc hoặc shellcode sẽ tự định nghĩa số hiệu syscall (SSN) của hàm cần gọi.Sau đó đặt tham số vào các thanh ghi tương ứng theo chuẩn syscall calling convention Khác biệt ở chỗ là direct syscall sẽ tự gọi luôn syscall tại phần code nó tự định nghĩa SSN còn indirect sẽ nhảy đến phần bộ nhớ chứa code mà native api gọi syscall để tận dụng chính lệnh syscall tại đó.

Sơ đồ thực thi của Direct syscall
Sơ đồ thực thi của Indirect syscall

Ta sẽ đi vào chi tiết code của từng kỹ thuật

Direct syscall

Với kỹ thuật Direct syscall, ta chỉ cần thực hiện hai bước đó là:

  • Xác định SSN của hàm mà ta muốn bypass
  • Tạo code assembly để thực hiện việc gọi syscall
  • Xác định SSN của hàm mà ta muốn bypass
  • Tạo code assembly để thực hiện việc gọi syscall

Cụ thể hơn, lấy ví dụ đoạn code thực hiện chèn shellcode vào bộ nhớ của tiến trình khác như sau:

 

Đoạn code này sử dụng 3 hàm là VirtualAllocEx, WriteProcessMemory và CreateRemoteThread, 3 hàm thường sẽ bị hook bởi EDR để kiểm tra.

Ở bước đầu tiên – xác định SSN của 3 hàm trên, ta sẽ xác định vi trí code của từng hàm trên trên bộ nhớ và đọc SSN từ đó (SSN thường nằm tại byte thứ 4) :

Tiếp theo ta sẽ khai báo các hàm assembly được sử dụng để gọi syscall, các tham số của hàm này sẽ y nguyên như hàm gốc, khác hôm chỗ ta sẽ thêm vào cuối 1 tham số là SSN với mục đích truyền vào eax để gọi syscall:

Sau đó ta sẽ viết các hàm assembly:

*Lưu ý là : Khi lấy SSN tại biến cuối cùng của hàm thì nên chú ý mỗii hàm có một số lượng tham số khác nhau nên vị trí lưu biến trên stack sẽ khác nhau, ví dụ NtAllocateVirtualMemory có 6 tham số , SSN ở tham số thứ 7 , ta sẽ lấy 8 (độ dài 1 entry trên stack) và nhân với 7 bằng 56, từ đó có thể lấy được SSN trên stack tại rsp + 56.

Cuối cùng là gọi các hàm đã chuẩn bị:

Indirect syscall

Indirect syscall sẽ phức tạp hơn 1 chút direct syscall, ngoài 2 bước, ta sẽ cần thêm 2 bước nữa là:

  • Xác định vị trí của từng lệnh syscall ứng với mỗi native API
  • Nhảy đến vị trí của lệnh syscall đó

Với bước xác định vị trí của từng lệnh syscall ứng với mỗi native API thì lệnh syscall sẽ luôn nằm sau 12 byte so với vị trí bắt đầu của mỗi hàm, do đó ta chỉ cần cộng thêm 0x12 vào địa chỉ là có ví trí của lệnh syscall:

Bên cạnh đó thêm 1 biến nữa (biến chứa địa chỉ lệnh syscall) vào cuối hàm bên cạnh biến chứa SSN:

Và cuối cùng, sửa lại code assembly để thay vì gọi syscall , code sẽ nhảy đến địa chỉ thực hiện việc syscall:

Ta có thể sử dụng Process hacker hoặc Process monitor để thấy hơn sự khác biệt, Tại indirect syscall, việc gọi syscall diễn ra tại vùng bộ nhớ của NtAllocateVirtualMemory trong ntdll.dll, còn trong direct thì syscall được gọi tại vùng nhớ của chính code direct syscall đó:

Call stack của Indirect syscall
Call stack của Direct syscall

Reference

https://blog.sektor7.net/#!res/2021/halosgate.md

https://d01a.github.io/syscalls/

https://www.scriptchildie.com/evasion/edr-bypass/2.-userland-hooks/1.-what-are-userland-hooks

https://redops.at/en/blog/direct-syscalls-vs-indirect-syscalls

https://medium.com/@0xcc00/bypassing-bitdefender-antivirus-using-api-unhooking-4fa61d8e0145

https://www.ired.team/offensive-security/defense-evasion/bypassing-cylance-and-other-avs-edrs-by-unhooking-windows-apis

https://www.ired.team/offensive-security/defense-evasion/detecting-hooked-syscall-functions

By,

Blue_Team.

100 lượt xem