【问题标题】:Calling WriteConsole through an intermediate function does not work properly通过中间函数调用 WriteConsole 无法正常工作
【发布时间】:2015-12-04 14:35:56
【问题描述】:

我正在尝试学习 assembly,所以我手动CC++ 代码转换为 assembly 代码。

环境

  • x86

  • Visual Studio

目标

手动将以下C 代码转换为assembly 代码:

static HANDLE OUTPUT_HANDLE;

BOOL __stdcall InputConsole(const VOID *lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten)
{
    WriteConsoleA(OUTPUT_HANDLE, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, 0);
}

int main()
{
    DWORD charsWritten;
    OUTPUT_HANDLE = GetStdHandle(STD_OUTPUT_HANDLE);


    InputConsole("Hello World!\n", 13, &charsWritten);
}

尝试

.586
.model flat, stdcall
.stack 4096

EXTRN   ExitProcess@4       :   PROC
EXTRN   GetStdHandle@4      :   PROC
EXTRN   WriteConsoleA@20    :   PROC

.data
    STD_OUTPUT_HANDLE       DD  ?
    WRITE_CONSOLE_STRING    DB  "Hello World!", 10, 0
    CHARS_WRITTEN           DD  ?

.code

WriteConsole PROC   
    PUSH    0                   ; lpReserved

    MOV     EAX, [ESP + 16]     ; lpNumberOfCharsWritten
    PUSH    EAX

    MOV     EAX, [ESP + 16]     ; nNumberOfCharsToWrite
    PUSH    EAX

    MOV     EAX, [ESP + 16]     ; lpBuffer
    PUSH    EAX

    PUSH    STD_OUTPUT_HANDLE   ; hConsoleOutput

    CALL    WriteConsoleA@20

    ADD     ESP, 12             ; Restore stack

    RET
WriteConsole ENDP

main: NOP
    PUSH    -11
    CALL    GetStdHandle@4;
    MOV     STD_OUTPUT_HANDLE, EAX

    LEA     EAX, CHARS_WRITTEN
    PUSH    EAX

    PUSH    13

    LEA     EAX, WRITE_CONSOLE_STRING
    PUSH    EAX

    CALL    WriteConsole

    PUSH    0
    CALL    ExitProcess@4
END main

问题

到目前为止,它确实打印了实际行,但是Access Violation Exception 被抛出ADD ESP, 12。在使用调试器仔细检查后,似乎我应该将 16 而不是 12 添加到 ESP 以恢复堆栈。仍然在创建16 之后,它会在从procedure 返回后冻结应用程序。

问题

  • 我只在堆栈中压入三个 4 字节参数,为什么我需要添加 16 而不是 12
  • 使用ESP + xx 访问“输入参数”是否正确?
  • 为什么我的程序会冻结,即使我正在恢复堆栈并且控制台上实际写入了一些内容?
  • 是否有另一种方法可以在 assembly 中“通过引用传递参数”而不是使用全局 .data 地址?

旁注

我知道您可以在 Visual Studio(这是我正在使用的 IDE)中为过程设置参数,但是我应该可以这样做,对吧?

【问题讨论】:

  • WriteConsoleA 将自行从堆栈中删除参数,因此请尝试删除 ADD ESP, 12
  • @MikeCAT 我知道这一点,但我也需要从堆栈中删除为我的自定义过程提供的参数。因为我正在关注 __stdcall
  • add esp 不能这样做,ret 12 不能这样做。
  • InputConsole 接受 3 个参数,因此数量为 4 * 3 = 12。RET imm16 指令对于“返回并将 imm16 添加到 ESP”很有用。
  • 一共是16个,是的,返回地址4个字节,参数12个。但顺序很重要。

标签: c++ c visual-studio assembly masm32


【解决方案1】:

add esp 不会这样做,ret 12 会这样做。 ——小丑

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 2016-06-17
    • 2015-05-18
    • 1970-01-01
    相关资源
    最近更新 更多