TL;DR

Một thread từ vxunderground khám phá chuỗi gọi hàm thật sự ẩn sau ba Windows GUI API phổ biến nhất: EnumWindows, IsWindowVisible, và DwmGetWindowAttribute. Kết quả? Tài liệu chính thức của Microsoft nói một đằng, bên trong làm một nẻo - và đây là điều mà cả malware author lẫn security researcher đều cần hiểu rõ.

Bối cảnh: Khi tài liệu nói dối (nhẹ thôi)

Windows API có nhiều lớp. Developer thường chỉ tương tác với lớp ngoài cùng - các hàm documented trong Win32 API. Nhưng bên dưới đó là một chuỗi forward đến các hàm undocumented, rồi đến syscall stub, rồi mới vào kernel.

vxunderground mô tả đây là "silly and overly complicated malware concept" - nhưng những gì họ phát hiện ra lại cực kỳ thực tế với bất kỳ ai viết code tương tác với Windows window management.

Ba chuỗi gọi hàm bị mổ xẻ

1. Enumerate windows

Mọi người dùng EnumWindows để liệt kê tất cả top-level windows. Nhưng đây là những gì thật sự xảy ra:

  • User code gọi EnumWindows (user32.dll)

  • user32 forward vào Win32u!NtUserBuildHwndList (win32u.dll)

  • NtUserBuildHwndList là một syscall - transition thẳng vào kernel mode

Điểm quan trọng: NtUserBuildHwndList nằm trong Shadow SSDT (System Service Descriptor Table dành riêng cho Win32/GUI calls). Đây là lý do các security product và rootkit thường hook tại đây để chặn/filter window enumeration ở tầng kernel.

2. Kiểm tra visibility

IsWindowVisible(hwnd) trông như một API complex, nhưng bên trong chỉ là:

hWnd->style & WS_VISIBLE

Một phép bitwise AND. WS_VISIBLE = 0x10000000 - một bit trong window style flags. Không có syscall, không có kernel transition.

Caveat quan trọng: WS_VISIBLE = TRUE không có nghĩa window thật sự hiển thị trên màn hình. Window có thể bị che hoàn toàn bởi window khác, bị đẩy ra ngoài màn hình, hoặc trên Windows 10+ bị "cloaked" (virtual desktop khác). Để check cloaked state cần dùng DwmGetWindowAttribute(DWMWA_CLOAKED).

3. Lấy screen coordinates chính xác - chỗ thú vị

Tài liệu Microsoft khuyên dùng DwmGetWindowAttribute thay vì GetWindowRect để lấy tọa độ chính xác (DWM trả về visual bounds, GetWindowRect bao gồm cả shadow/invisible resize border).

Call chain thật sự:

  1. DwmGetWindowAttribute (dwmapi.dll) - documented, Vista+, trả về HRESULT

  2. Forward sang GetWindowCompositionAttribute (user32.dll) - undocumented, Windows 7+, trả về BOOL

  3. Syscall vào Win32u!NtUserGetWindowCompositionAttribute (win32u.dll)

Và đây là điều buồn cười: DwmGetWindowAttribute được documented là hỗ trợ Vista. Nhưng hàm nó forward sang - GetWindowCompositionAttribute - chỉ tồn tại từ Windows 7.

Về lý thuyết, DwmGetWindowAttribute có thể chạy trên Vista... cho đến khi nó cố gọi một hàm Windows 7-only. Microsoft biết điều này và có lẽ quyết định: "lol ok whatever man".

Kỹ thuật đằng sau

GetWindowCompositionAttribute là hàm undocumented:

  • Không có header file, không có import library

  • Phải load thủ công qua LoadLibrary("user32.dll") + GetProcAddress

  • Signature khác với DwmGetWindowAttribute - parameters được pack vào một struct WINDOWCOMPOSITIONATTRIBDATA

  • Một số attribute values khác với DwmGetWindowAttribute (ví dụ: DWMWA_DISALLOW_PEEK = 0x11 thay vì giá trị standard)

  • Also known as NtUserGetWindowCompositionAttribute - hint rằng đây thực chất là native API layer

Tại sao win32u.dll? Microsoft đã tách các GUI/Win32 syscall stubs ra khỏi user32.dll và gdi32.dll vào một DLL riêng - win32u.dll - để phân tách rõ ràng giữa API wrapper và syscall interface. Mọi GUI operation cuối cùng đều đi qua đây.

Ai cần biết điều này?

Malware authors: Window enumeration là kỹ thuật phổ biến để detect debuggers/AV (scan window titles), implement keyloggers (track active window), và screen capture. Biết hàm nào thật sự syscall vào kernel giúp bypass user-mode hooks đặt ở lớp Win32 API.

Security researchers & AV developers: Nếu muốn monitor window enumeration, hook tại EnumWindows là không đủ - attacker có thể gọi thẳng NtUserBuildHwndList. Hook tại Shadow SSDT (kernel level) mới thật sự bắt được.

Game developers & overlay authors: Hiểu tại sao DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS) cho kết quả khác GetWindowRect - DWM bounds là visual bounds thật sự, phù hợp cho overlay và screenshot.

Timeline

Mốc

Sự kiện

2007 - Windows Vista

DwmGetWindowAttribute ra đời cùng Desktop Window Manager

2009 - Windows 7

GetWindowCompositionAttribute xuất hiện trong user32.dll

2012 - Windows 8+

Cloaked windows concept (virtual desktops)

2017

Windows Vista end-of-support (Vista/Win7 gap mất ý nghĩa thực tế)

2025

vxunderground thread khám phá lại những quirk này

Takeaway

Windows API là một mê cung của forwarding chains. Hàm documented ngoài cùng thường chỉ là một wrapper mỏng ẩn một hoặc nhiều lớp undocumented bên dưới. Đối với security research, điều quan trọng là hiểu nơi thật sự mà một operation xảy ra - không phải hàm bạn gọi, mà là syscall cuối cùng chạm vào kernel.

Như vxunderground kết luận sau khi trace toàn bộ chain: "lol ok whatever man" - đôi khi đó là cách tốt nhất để react với những quirk của Windows internals tích lũy qua 30+ năm backwards compatibility.

Via: vxunderground on X, Microsoft Docs - DwmGetWindowAttribute, Microsoft Docs - GetWindowCompositionAttribute.