Windows kernel32.dll 仅程序集绘制像素

blu*_*yke 1 windows assembly x86-64 kernel32

我一直在寻找堆栈溢出,但似乎找不到任何东西

Windows 64 位上的 kernel32.dll 中的哪些命令和函数可以在屏幕上绘制单个像素,最好没有 user32.dll 窗口?

Mar*_*oom 5

结果我的评论了。

win32k.sys 确实创建了新的系统调用。追溯起来,是有道理的。

win32k.sys处理DirectComposition 引擎,它类似于Windows 的桌面和 Windows 管理器:

直接组合架构

DirectComposition API 通过 COM 公开给 Win32 程序,这使得在没有 Visual Studio 的情况下很难使用,因为我们需要完整的 IDL 定义,并且在程序集中,手动在 vtables 中设置偏移量。
它也非常抽象,因此对所使用的系统调用进行逆向工程然后使用它们会很痛苦。

但是,GDI,传统的 Windows 图形 API,当然仍然受支持(它由 DirectComposition 模拟/集成)。
这个 API 是通过一些 DLL 的导出函数公开的,它不是在可组合表面方面工作,而是在 Windows 和设备上下文(允许绘制的对象)方面工作。
这使得对其进行逆向工程并在组装中使用它变得容易。

在屏幕上绘制像素最接近的是在桌面设备上下文中绘制像素(因为桌面是全屏窗口)。
使用 Win32 API,我们将使用两个函数来做到这一点:

  • GetDC,当使用 NULL 值调用时,会给出桌面的设备上下文。
  • SetPixel, 在设备上下文上绘制一个像素。

如果没有 Win32 API 而只有直接系统调用,它可能会出现问题,因为这些操作存在于较低级别的接口上是不被允许的。
例如,此接口可以公开一个共享内存区域,用于写入像素,但格式未公开。
类似地,设备上下文可以是 Win32 抽象。

但幸运的是,这是没有的情况下,无论是GetDCSetPixel拥有自己的系统调用。
这是非常幸运的,可能源于 win32k.sys 的历史(它更多地与 Win32 API 耦合,实际上是 Win32 API,IIRC)。

我对这两个 Win32 API 进行了逆向工程以获取系统调用号以及它们的使用方式(这两个数字都可以在此答案的第二个链接中找到)。
虽然GetDC只是 syscall 调用的包装器,SetPixel但会对颜色进行一些格式转换。
在下面给出的示例中,此转换被省略,如果需要由您决定(如果没有它,您可能无法编写您想要的颜色)。

我制作了一个示例程序,它在屏幕的左上角绘制一个黑色的 256x256 矩形。

黑色矩形

一些注意事项:

  • 它是一个 64 位程序,因此它可以使用该syscall指令。这只是为了展示(并避免解释WOW32Reserved指针和 WOW64 是什么以及如何使用它们)。
  • 如果程序无法获取桌面句柄,则会触发调试异常。
  • 在顶部,有用于系统调用号的常量,它们是为 Windows 7 设置的(如果有的话,不确定哪个确切的次要版本)。
  • 该程序由NASM组装并与golink链接。
  • 这是一个很无聊的程序。避免使用 Win32 API 不会为编程增加任何洞察力。如果我是你,我会使用 API。

没有外部 PE 依赖项:

无依赖

DEFAULT REL

GLOBAL main

%define SYS_GetDC                 100ah
%define SYS_SetPixel              10afh


SECTION .text

;.    .     .     .     .     .     .     .     .     .     .     .     .     .
; . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -
;
;Get the HDC of a window
;
;.    .     .     .     .     .     .     .     .     .     .     .     .     .
; . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -

;arg0 (rcx) = HWND
GetDC:
  mov r10, rcx
  mov eax, SYS_GetDC
  syscall
  ret

;.    .     .     .     .     .     .     .     .     .     .     .     .     .
; . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -
;
;Set a pixel in an HDC
;
;.    .     .     .     .     .     .     .     .     .     .     .     .     .
; . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -

SetPixel:
  mov r10, rcx
  mov eax, SYS_SetPixel
  syscall
  ret

;.    .     .     .     .     .     .     .     .     .     .     .     .     .
; . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -
;
;Main
;
;.    .     .     .     .     .     .     .     .     .     .     .     .     .
; . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -   . -

main:

  ;Get the desktop HDC

  xor ecx, ecx
  call GetDC
  test eax, eax
  jz .abort

  ;Write a 256x256 black square
  mov ebx, eax          ;HDC into rbx (which is preserved)
  
  xor esi, esi          ;esi = x = 0    
  
.x_loop:  
  xor edi, edi          ;edi = y = 0
  
.y_loop: 
  mov ecx, ebx      ;HDC
  mov edx, edi      ;Y
  mov r8, rsi       ;X
  xor r9, r9        ;Color (black, beware of the correct format!)
  call SetPixel

  inc edi           ;y++
  cmp edi, 100h
  jb .y_loop        ;while (y < 256)
 
  inc esi           ;x++
  cmp esi,  100h    
  jb .x_loop        ;while (x < 256)


  ;In Windows we can return from main
  ret




  ;Here something went wrong
  ;We must do some eye-catching action, like invoking the debugger

.abort:
  ;This will trigger a debug popup
  int3
Run Code Online (Sandbox Code Playgroud)