我尝试调用 Win32 API WriteConsoleOutputA 使用 NASM

I Try Call Win32 API WriteConsoleOutputA use NASM

我尝试调用 WriteConsoleOutputA 使用 NASM

但是错误信息总是显示

87 (0x57)

参数不正确

我不知道如何解决这个问题

STD_OUTPUT_HANDLE   EQU -11
NULL                EQU 0

GLOBAL GobleyGook
EXTERN ExitProcess, GetLastError, GetStdHandle, WriteConsoleA, WriteConsoleOutputA, FormatMessageA

SECTION .data

STRUC lpBuffer
    .Char      : RESW 1
    .Attributes: RESD 1
ENDSTRUC

_lpBuffer ISTRUC lpBuffer
    at lpBuffer.Char, DW 'A'
    at lpBuffer.Attributes, DD 1H
IEND

STRUC dwBufferSize
    .X: RESW  1 
    .Y: RESW  1
ENDSTRUC

_dwBufferSize ISTRUC dwBufferSize
    at dwBufferSize.X, DW 10
    at dwBufferSize.Y, DW 10
IEND

STRUC dwBufferCoord
    .X: RESW 1
    .Y: RESW 1
ENDSTRUC

_dwBufferCoord ISTRUC dwBufferCoord
    at dwBufferCoord.X, DW 0
    at dwBufferCoord.Y, DW 0
IEND

STRUC smallRect
    .Left  : RESW 1
    .Top   : RESW 1
    .Right : RESW 1
    .Bottom: RESW 1
ENDSTRUC

_smallRect ISTRUC smallRect
IEND

SECTION .bss
dummy   RESD 1
err     RESD 1
err2    RESD 1

SECTION .text
GobleyGook: 
    PUSH    STD_OUTPUT_HANDLE
    CALL    GetStdHandle

    PUSH    _smallRect
    PUSH    _dwBufferCoord
    PUSH    _dwBufferSize
    PUSH    _lpBuffer
    PUSH    EAX
    CALL    WriteConsoleOutputA

    CALL    GetLastError

    PUSH    NULL
    PUSH    99
    PUSH    err
    PUSH    NULL
    PUSH    EAX
    PUSH    NULL
    PUSH    1000H
    CALL    FormatMessageA

    PUSH    STD_OUTPUT_HANDLE
    CALL    GetStdHandle

    push    NULL
    push    dummy
    push    32
    push    err
    push    EAX
    call    WriteConsoleA

    PUSH    NULL
    CALL    ExitProcess

Link & 编译器

nasm -f win32 print.asm
golink.exe /console /entry GobleyGook print.obj kernel32.dll

在 windows 8.1 64 位

API 文档

https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms687404(v=vs.85).aspx

请帮帮我....

只需按如下方式修改您的代码即可!

PUSH    STD_OUTPUT_HANDLE
CALL    GetStdHandle

PUSH    _smallRect
mov ecx, [_dwBufferCoord]
PUSH    ecx
mov edx, [_dwBufferSize]
PUSH   edx 
PUSH    _lpBuffer
PUSH    EAX
CALL    WriteConsoleOutputA

你的代码有几个错误:

  • 正如评论中指出的,您需要按值传递 COORD 参数
  • 您需要传递一个等于缓冲区大小的 dwBufferSize
  • 您需要传递一个 lpWriteRegion 结构(通过引用),该结构使用您希望缓冲区在屏幕上显示的位置的坐标进行初始化。
  • 您需要检查WriteConsoleOutputA的return值来判断是否失败。您不能可靠地使用 GetLastError 来确定它是否失败。
  • 您对 lpBuffer 结构的定义不正确。相应 CHAR_INFO 结构的第二个成员 Attributes 是 16 位 WORD 而不是 32 位 DWORD.

您的缓冲区只有一个字符,使其成为 1x1 缓冲区,但您正试图传递 10x10 大小的缓冲区。因为你没有初始化 _smallRect 它的值是 0,0,0,0 将输出放在控制台缓冲区的左上角。这意味着您的单字符输出可能会在您的程序完成并打印命令提示符时立即滚出屏幕,您将永远看不到它。

这是修复了所有这些问题的程序版本:

STD_OUTPUT_HANDLE   EQU -11
NULL                EQU 0

GLOBAL GobleyGook
EXTERN _ExitProcess@4, _GetLastError@0, _GetStdHandle@4, _WriteConsoleA@20, _WriteConsoleOutputA@20, _FormatMessageA@28

SECTION .data

STRUC lpBuffer
    .Char      : RESW 1
    .Attributes: RESW 1
ENDSTRUC

_lpBuffer ISTRUC lpBuffer
    at lpBuffer.Char, DW 'A'
    at lpBuffer.Attributes, DW 2H | 8H
IEND

STRUC smallRect
    .Left  : RESW 1
    .Top   : RESW 1
    .Right : RESW 1
    .Bottom: RESW 1
ENDSTRUC

_smallRect ISTRUC smallRect
    at smallRect.Left, DW 40
    at smallRect.Top, DW 12
    at smallRect.Right, DW 41
    at smallRect.Bottom, DW 13
IEND

SECTION .bss
dummy   RESD 1
err     RESD 1
err2    RESD 1

SECTION .text
GobleyGook: 
    PUSH    STD_OUTPUT_HANDLE
    CALL    _GetStdHandle@4

    PUSH    _smallRect
    PUSH    (0 << 16) | 0  ; dwBufferCoord = 0,0
    PUSH    (1 << 16) | 1  ; dwBufferSize  = 1,1
    PUSH    _lpBuffer
    PUSH    EAX
    CALL    _WriteConsoleOutputA@20

    cmp     eax, 0
    jnz     .exit

    CALL    _GetLastError@0

    PUSH    NULL
    PUSH    99
    PUSH    err
    PUSH    NULL
    PUSH    EAX
    PUSH    NULL
    PUSH    1000H
    CALL    _FormatMessageA@28

    PUSH    STD_OUTPUT_HANDLE
    CALL    _GetStdHandle@4

    push    NULL
    push    dummy
    push    32
    push    err
    push    EAX
    call    _WriteConsoleA@20

.exit:
    PUSH    0
    CALL _ExitProcess@4

我已经更改了您的程序,使其在 40,12 处显示单字符缓冲区,并将其设为亮绿色而不是深蓝色,这样它在黑色背景上显示效果更好。我还将 API 函数的名称更改为它们的实际程序集名称,因此它会 link 与 Microsoft linker。