1 điểm bởi GN⁺ 2025-05-13 | 1 bình luận | Chia sẻ qua WhatsApp
  • defendnot, được tạo ra trong chuyến đi Seoul, là một công cụ cố gắng vô hiệu hóa Windows Defender bằng cách gọi trực tiếp API dịch vụ Windows Security Center (WSC), và việc này dẫn tới nhiều ngày reverse engineering
  • Công cụ trước đó no-defender dùng mã của một phần mềm diệt virus hiện có để đăng ký với WSC rằng có một phần mềm diệt virus khác; sau khi đạt khoảng 1,5k sao trên GitHub, nó bị gỡ theo yêu cầu DMCA của hãng phát triển phần mềm diệt virus
  • Ban đầu, lời gọi COM API của WSC được tái hiện trong khoảng 1 giờ, nhưng WSC xác minh tiến trình gọi nên các tiến trình thông thường bị từ chối truy cập
  • Kết quả phân tích cho thấy WSC kiểm tra WinDefend SID, quyền quản trị, chữ ký, và cờ ForceIntegrity trong DllCharacteristics của PE; triển khai cuối cùng dùng Taskmgr.exe
  • Trong môi trường rối rắm gồm MacBook arm64, PC từ xa ở Mỹ, độ trễ Parsec 210ms và VM Shadow.tech, quá trình triển khai được hoàn tất sau khi sửa lỗi đường dẫn ctx.bin và vấn đề điều kiện nguồn điện của autorun

Bối cảnh tạo ra defendnot

  • defendnot là công cụ sử dụng trực tiếp API dịch vụ Windows Security Center để vô hiệu hóa Windows Defender
  • Trọng tâm của quá trình triển khai không nằm ở bản thân lời gọi WSC, mà là lần lượt vượt qua các điều kiện xác minh chặn nó và môi trường làm việc bất tiện
  • Tài liệu kỹ thuật chi tiết hơn về WSC sẽ được người khác công bố sau

no-defender và DMCA một năm trước

  • no-defender, được công bố khoảng 1 năm trước, dùng Windows API dành cho phần mềm diệt virus để tắt Windows Defender
  • API này dùng để báo cho hệ thống rằng “đã có phần mềm diệt virus khác, nên không cần chạy kiểm tra Defender”
  • Thành phần hệ thống quản lý khu vực này là Windows Security Center (WSC)
  • no-defender hoạt động bằng cách dùng mã bên thứ ba của một phần mềm diệt virus hiện có để buộc phần mềm đó đăng ký với WSC
  • Chỉ vài tuần sau khi công bố, nó đạt khoảng 1,5k stars; khi hãng phát triển phần mềm diệt virus được sử dụng gửi yêu cầu DMCA takedown, nội dung kho lưu trữ bị xóa và sự việc kết thúc

Phân tích WSC được khởi động lại trong chuyến đi Seoul

  • Khi đang ở Airbnb tại Seoul, MrBruh xem xét no-defender và nhắn rằng anh ấy đang điều tra xem có thể triển khai một cách “sạch” mà không cần binary của phần mềm diệt virus hay không
  • Thường thì tác giả mang theo một laptop x86 riêng cho CTF hoặc công việc reverse x86, nhưng chuyến này chỉ mang M4Pro MacBook
  • Dù bất lợi vì không có thiết bị dành cho reverse x86, tác giả bắt đầu phân tích WSC trong khoảng thời gian trước khi bạn bè thức dậy

Ngày 1: Tái hiện WSC COM API và lần đầu bị từ chối truy cập

  • MrBruh cung cấp binary WSC mới nhất, và phần triển khai đăng ký WSC của phần mềm diệt virus từng dùng trước đây được lấy làm triển khai tham chiếu
  • WSC có COM API mà các phần mềm diệt virus sử dụng, và các lời gọi mà phần mềm diệt virus hiện có thực hiện được tái hiện trong khoảng 1 giờ
  • Tác giả khởi động Windows arm64 trong Parallels để thử nghiệm, nhưng kết quả là access denied
  • Từ kinh nghiệm trước đó, tác giả biết WSC xác minh tiến trình gọi API, và ban đầu nghi ngờ khả năng đó là kiểm tra chữ ký
  • Khi chèn mã vào tiến trình mà phần mềm diệt virus hiện có dùng cho tác vụ WSC, lời gọi COM để đăng ký phần mềm diệt virus mới và cập nhật trạng thái hoạt động bình thường

Nỗ lực loại bỏ binary của phần mềm diệt virus

  • Để dự án mới không lại bị hãng phần mềm diệt virus hiện có phản đối, tác giả cố dùng binary do hệ thống cung cấp thay cho binary của phần mềm diệt virus
  • Tiến trình mục tiêu đầu tiên được chọn là cmd.exe, nhưng lời gọi WSC API bị từ chối
  • Khi xem xét wscsvc.dll, tác giả thấy có đoạn mã kiểm tra liệu tiến trình gọi có phải PPL hay không
  • Tiến trình tạo bằng CreateProcessA đơn thuần không phải tiến trình được bảo vệ PPL, và rạng sáng hôm đó không thể tiến xa hơn

Ngày 2: Thiết lập môi trường debug từ xa bất tiện

  • Trên MacBook arm64, việc xử lý Windows x86 đúng cách rất khó; tác giả cũng muốn tránh phải làm việc trong môi trường arm64 hoặc không dùng được x64dbg
  • Bạn của tác giả, pindos, cho phép truy cập PC, và tác giả kết nối từ xa bằng Parsec
  • Vì kết nối từ Hàn Quốc tới PC ở Mỹ, độ trễ trung bình khoảng 210ms
  • Luồng làm việc lúc đó rất phiền phức
    • Build module bằng MSVC trong Windows arm64 trên Parallels
    • Chia sẻ artefact build với host qua thư mục dùng chung
    • Sao chép artefact vào VM trên PC của pindos bằng AnyDesk
    • Debug dịch vụ WSC trong môi trường Parsec có độ trễ 210ms
  • Môi trường bất tiện tới mức làm giảm mạnh tốc độ phát triển và phân tích

Debug dịch vụ WSC và WinDefend SID

  • Dịch vụ WSC là một DLL do svchost chạy, và yếu tố chính cản việc gắn debugger là bảo vệ PPL
  • Trên VM, tác giả bật test mode và dùng một driver với vài dòng mã ở kernel mode để gỡ PPL khỏi tiến trình mục tiêu
  • Điểm thất bại khi cmd.exe yêu cầu WSC đăng ký phần mềm diệt virus nằm ở WscServiceUtils::CreateExternalBaseFromCaller
  • Hàm này impersonate RPC client rồi kiểm tra token của tiến trình gọi có WinDefend SID hay không
  • Vì lúc đó chưa hiểu rõ cách token Windows hoạt động, tác giả cho rằng có thể vượt qua kiểm tra bằng cách impersonate WinDefend
  • Trong tình trạng thiếu ngủ, tác giả diễn giải nhầm rằng binary của phần mềm diệt virus hiện có cũng vượt qua kiểm tra IsMember này

Thử impersonate WinDefend và thất bại

  • Sau vài giờ học về Windows token, tác giả triển khai theo hướng chạy với token chứa WinDefend SID để vượt qua kiểm tra của WSC
  • Khi chạy mã trong cmd đã gắn WinDefend SID, lời gọi COM trả về STATUS_SUCCESS nhưng thực tế không có phần mềm diệt virus mới nào được đăng ký
  • Cách tiếp cận này rốt cuộc không hữu ích và phải được kiểm chứng lại vào ngày hôm sau

Ngày 3: Tái dựng thuật toán xác minh thực tế

  • Khi kiểm tra lại, binary của phần mềm diệt virus hiện có không vượt qua kiểm tra WinDefend SID
  • Nếu vượt qua kiểm tra đó thì sẽ thao tác với đối tượng WSC của Windows Defender, nhưng chỉ bằng lời gọi WSC thì không thể vô hiệu hóa Defender ngay, nên việc này vô dụng
  • Tác giả loại bỏ mã impersonate WinDefend và phân tích nhánh khác của câu điều kiện
  • Ở nhánh đó, các điểm sau được kiểm tra đối với binary gọi
    • Tiến trình có ở trạng thái elevated hay không
    • Chữ ký của binary có hợp lệ hay không
    • DllCharacteristics của PE có một cờ cụ thể hay không
  • Cờ DllCharacteristics được kiểm tra trong CSecurityVerificationManager::CreateExternalBaseFromPESettingsForceIntegrity
  • Tác giả tạo mã tái hiện bước kiểm tra binary mà WSC thực hiện trong thư mục wsc-binary-check của kho defendnot, rồi thử nghiệm trên các binary trong System32

Dùng Taskmgr.exe và lỗi ctx.bin

  • Vì người bạn cần dùng lại PC, tác giả kết nối trực tiếp tới VM bằng Parsec, nhưng môi trường còn chậm hơn do cộng thêm encoding phần mềm
  • Tác giả dùng Taskmgr.exe thay cho cmd.exe, nhưng vẫn gặp lỗi RPC
  • Do độ trễ và vấn đề nhập liệu khiến việc debug trong cùng VM trở nên khó khăn, tác giả nhận được lời khuyên và trả $30 để đăng ký shadow.tech
  • VM Shadow.tech có phiên bản Windows cũ hơn nên mã wscsvc không bị inline nhiều vào một hàm như phiên bản mới, và kết quả decompile cũng dễ đọc hơn
  • Nguyên nhân lỗi thực sự là tên AV truyền cho WSC bị sai
    • defendnot-loader dùng ctx.bin, chứa các tham số đã serialize, để truyền dữ liệu sang defendnot.dll
    • IPC để theo dõi trạng thái được triển khai riêng, nhưng phần truyền cấu hình vẫn còn giữ cách dùng ctx.bin, tàn dư từ mã no-defender cũ
    • Hàm tìm đường dẫn ctx.bin lấy thư mục cơ sở của module Taskmgr.exe làm chuẩn, thay vì nodefend.dll
    • Kết quả là byte null được truyền làm tên AV, và WSC từ chối buffer đó
  • Sau khi sửa vấn đề đường dẫn, thử nghiệm thành công

Dọn dẹp mã và vấn đề autorun

  • Để kết thúc trong cùng ngày, tác giả dọn dẹp mã và triển khai thêm tính năng cho tới 8 giờ sáng
  • Các tính năng bổ sung bao gồm chức năng thêm chính nó vào autorun
  • Tới 8 giờ sáng, chỉ còn autorun không hoạt động đúng; sau khi thử nhiều cách nhưng thất bại, tác giả đi ngủ
  • Ngày hôm sau, khi kiểm tra lại, nguyên nhân là hai checkbox liên quan tới nguồn điện khi tạo tác vụ trong Task Scheduler
  • Vì laptop không được cắm nguồn AC nên tác vụ không chạy; sau khi bỏ các cờ đó, autorun hoạt động
  • Sau đó, tác giả dọn dẹp mã thêm vài giờ và hoàn tất công việc

Kết thúc

  • Bản thân công việc khá thú vị, nhưng các vấn đề môi trường lặp đi lặp lại và luồng debug từ xa trong nhiều ngày là trải nghiệm mà tác giả không muốn gặp lại
  • Đặc biệt, MacBook arm64, VM x86 từ xa, độ trễ cao, encoding chậm và lỗi đường dẫn tệp lộ ra muộn đã làm độ khó triển khai tăng đáng kể
  • Tài liệu WSC mang tính kỹ thuật hơn sẽ được công bố riêng sau

1 bình luận

 
GN⁺ 2025-05-13
Ý kiến trên Hacker News
  • Cách xâm lấn nhất nhưng hiệu quả nhất để tắt Defender là khởi động bằng USB Linux live, đổi tên C:\ProgramData\Microsoft\Windows Defender, rồi tạo một tệp rỗng ở đúng vị trí đó

    • Group Policy vẫn hoạt động rất tốt, nên tôi đặt một domain controller cục bộ trong homelab và để nó chỉ tự động thay đổi chính sách Defender cho mọi người dùng
    • Một sản phẩm phổ biến cũng hoạt động gần như theo cách tương tự, rồi kéo sập khoảng 25% toàn bộ Internet theo nó
    • Thật lạ là Windows không phát hiện những thay đổi như vậy bằng manifest đã ký
  • Để tham khảo, WSC là viết tắt của Windows Security Center

  • Cụm the antivirus I was using làm tôi khá bối rối. Tôi không hiểu vì sao hãng antivirus đó lại có lý do gửi yêu cầu gỡ bỏ DMCA cho tác giả
    Có lẽ ý là tác giả đã reverse engineer một antivirus khác rồi đưa một phần của nó vào dự án mã nguồn mở. Nhưng cũng thấy tiêu đề kiểu Impersonating WinDefend, nên rốt cuộc tôi tò mò liệu tác giả có vi phạm luật bản quyền theo cách nào đó không

    • Theo tôi hiểu thì họ đã dùng lớp vỏ của một công cụ antivirus khác để né yêu cầu về chữ ký. Tôi hiểu đây là vùng xám, và nghĩ cũng có thể có cơ sở xem là sử dụng có tính biến đổi, nhưng tôi không phải luật sư
    • Đúng vậy. Họ đã sao chép một phần chương trình antivirus có sẵn và vi phạm luật bản quyền
      Ngay trước đoạn được trích có giải thích rằng “dự án đã dùng mã bên thứ ba của một antivirus vốn đã tồn tại, và buộc antivirus đó được đăng ký với WSC như một antivirus”
  • Đoạn mã này có cảm giác bị nguyền rủa:
    https://github.com/es3n1n/defendnot/blob/master/defendnot-lo...
    Nếu muốn biết thực sự chuyện gì đang xảy ra thì ở đây:
    https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...

    • Có ai rành phép thuật C++ giải thích được chuyện gì đang diễn ra, và vì sao lại gọi là bị nguyền rủa không?
    • Vì hạn chế thời gian nên tôi không muốn tự triển khai RAII cho các đối tượng liên quan đến COM. Dù vậy tôi dự định sẽ đổi trong bản cập nhật tiếp theo
    • Tôi không rõ phần nào bị gọi là nguyền rủa. Chữ ký ở phía gọi hơi khác tùy gu cá nhân, nhưng tôi cũng dùng pattern này ở nhiều nơi trong mã của mình
      Ví dụ trong ngôn ngữ D có sẵn trong ngôn ngữ khái niệm câu lệnh (statement) được chạy khi kết thúc scope
    • “Code là cách đối xử với đồng nghiệp” - Michael Feather, https://x.com/mfeathers/status/1031176879577780224
      Tóm lại, không phải do AI viết. Đoạn mã này trì hoãn lời gọi hàm cho đến khi đối tượng ra khỏi scope. Phần triển khai dùng macro C để tạo cú pháp ngắn hơn, lược bớt một phần định nghĩa lambda/hàm ẩn danh C cần thiết, và sinh tên biến duy nhất để quản lý lời gọi bị trì hoãn
      Tuy nhiên cú pháp kết quả tránh kiểu viết hoa vốn là quy ước thường thấy để biểu thị macro C, và thoạt nhìn trông giống như lời gọi hàm của một con trỏ đối tượng. Nếu không quen với pattern này, hoặc kỳ vọng macro sẽ được hiển thị khác đi, thì có thể gây nhầm lẫn
      Với một số người, nó đủ phổ biến và hữu ích để trong những ngữ cảnh nhất định gần như có thể xem là một idiom. Phần giải thích kỹ thuật ở https://news.ycombinator.com/item?id=43959403#43960905 diễn giải khá rõ cách macro hoạt động
  • Trong kỳ nghỉ, tôi reverse engineer desktop ảo của Windows và nhờ vậy kỳ nghỉ tuyệt hơn nhiều. Kỷ niệm đẹp nhất năm ngoái là nhận ra reverse engineering thật sự rất vui
    Tôi cũng học được nhiều điều thú vị; bên dưới RPC của Windows có một tầng messaging không được tài liệu hóa: https://csandker.io/2022/05/24/Offensive-Windows-IPC-3-ALPC....

  • Lần nào tôi cũng biết rằng nếu ảnh đại diện là nhân vật anime thì bài viết sẽ hay. Lưu lại phòng khi sau này phải quay về môi trường Windows không mấy dễ chịu

  • Dành cho ai tò mò: WSC là viết tắt của Windows Security Center. Tôi cũng đã phải tra

    • Trong bài có viết: “Phần hệ thống quản lý mớ hỗn độn này được gọi là Windows Security Center, viết tắt là WSC”
  • Vì sao lại muốn tắt WSC?

    • Có thể vì hiệu năng, cũng có thể để phát triển mã độc hoặc hack
    • Nếu là kẻ tấn công, bạn có thể nhắm vào tình huống may mắn khi không có sản phẩm phát hiện và phản ứng endpoint nào khác được cài. Nếu có các sản phẩm đó, gần như chắc chắn chúng sẽ chặn lại
      Nếu là vendor EDR, đây là một lời gọi API bị làm rối có thể dùng để kìm hãm hoặc vô hiệu hóa Windows Firewall. Ví dụ, tôi cho rằng CrowdStrike có thể dùng Windows Firewall hoặc triển khai riêng của họ đều được
    • Vì đó là phần cứng của tôi, nên tôi làm gì mình muốn thôi
    • Mọi phần mềm antivirus tối thiểu cũng là một powervirus. Tôi không muốn phải bận tâm chuyện ai đó can thiệp như bảo mẫu và nói netcat.exe là không được
    • Vì chẳng có lý do gì để cố tình tự cài rootkit lên chính mình
  • Gần đây tôi đã đọc https://nostarch.com/windows-security-internals, và nhờ bài này mà mọi thứ thấm hơn nhiều
    Tôi cũng biết sơ sơ cách các hoạt động hậu trường như vậy vận hành trên Windows, nhưng thời điểm thật vừa khéo. Chương cuối của cuốn sách đó cũng đào khá sâu vào token và SID, giống như những gì tác giả bài viết đã đề cập