尝试使用纯 Win64 API(无 C 运行时)从 x64 汇编器读取控制台输入
Trying to read console input from x64 assembler using pure Win64 APIs (No C runtime)
我刚开始学习 x64 汇编程序,我刚遇到一个我无法解释的问题。从 Kernel32.dll 的 ReadFile 如何从 C 代码工作,我期待它在控制台停止并等待我输入完整的行,然后 returning 到调用者,令人惊讶的是没有为我工作。 ReadFile 过程似乎 return 一个零长度的字符串,无论在键盘上按下什么,或者就此而言,从命令 shell.
上的管道传递给它的是什么
;%USERPROFILE%\nasm\learning\stdio.asm
;
;Basic usage of the standard input/output/error channels.
;
;nasm -f win64 stdio.asm
;golink /console /ni /entry main stdio.obj kernel32.dll
%include "\inc\nasmx.inc"
%include "\inc\win32\windows.inc"
%include "\inc\win32\kernel32.inc"
%ifidn __BITS__, 0x40
;// assert: set call stack for procedure prolog to max
;// invoke param bytes for 64-bit assembly mode
DEFAULT REL
NASMX_PRAGMA CALLSTACK, 0x30
%endif
entry toplevel
;
section .data
errmsg db "No errors to report!",0xd,0xa
errmsglen equ $-errmsg
query db "What is your name?",0xd,0xa
querylen equ $-query
greet db "Welcome, "
greetlen equ $-greet
crlf db 0xd,0xa
crlflen equ $-crlf
bNamelim db 0xff
minusone equ 0xffffffffffffffff
zero equ 0x0
section .bss
hStdInput resq 0x1
hStdOutput resq 0x1
hStdError resq 0x1
hNum resq 0x1
hMode resq 0x1
bName resb 0x100
bNamelen resq 0x1
section .text
proc toplevel, ptrdiff_t argcount, ptrdiff_t cmdline
locals none
invoke GetStdHandle, STD_INPUT_HANDLE
mov qword [hStdInput], rax
; invoke GetConsoleMode, qword [hStdInput], hMode
; mov rdx, [hMode]
; and dl, ENABLE_PROCESSED_INPUT
; and dl, ENABLE_LINE_INPUT
; and dl, ENABLE_ECHO_INPUT
; invoke SetConsoleMode, qword [hStdInput], rdx
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov qword [hStdOutput], rax
invoke GetStdHandle, STD_ERROR_HANDLE
mov qword [hStdError], rax
invoke WriteFile, qword [hStdOutput], query, querylen, hNum, zero
invoke WaitForSingleObject, qword[hStdInput], minusone
invoke ReadFile, qword [hStdInput], bName, bNamelim, bNamelen, zero
invoke WriteFile, qword [hStdOutput], greet, greetlen, hNum, zero
invoke WriteFile, qword [hStdOutput], bName, bNamelen, hNum, zero
invoke WriteFile, qword [hStdOutput], crlf, crlflen, hNum, zero
invoke WriteFile, qword [hStdError], errmsg, errmsglen, hNum, zero
invoke ExitProcess, zero
endproc
我已经使用 C 运行时完成了相同的功能并且它有效,但现在我试图在不使用那个拐杖的情况下获得一个工作版本。我正在使用 NASM(使用 NASMX 包含提供宏的文件)和 GoLink,链接到 kernel32.dll。我究竟做错了什么?我错过了 which API 的什么行为?
从有关 Win32 控制台的 MSDN 文章 APIs,ReadFile 的行为让我感到惊讶。
此外,如果我从程序集中删除 WaitForSingleObject 调用,C 等价物中不存在的东西,整个程序完成 运行 而无需停止等待控制台输入,尽管 ReadFile 被假定为做到这一点。
编辑
好吧,Raymond Chen 询问了宏扩展以及根据调用约定它们是否正确,所以:
invoke GetStdHandle, STD_INPUT_HANDLE
mov qword [hStdInput], rax
这变成了
sub rsp,byte +0x20
mov rcx,0xfffffffffffffff6
call qword 0x2000
add rsp,byte +0x20
mov [0x402038],rax
这似乎遵循 Win64 的 0-4 整数参数调用的调用约定就好了。五参数形式怎么样?
invoke WriteFile, qword [hStdOutput], query, querylen, hNum, zero
这变成了
sub rsp,byte +0x30
mov rcx,[0x402040]
mov rdx,0x402016
mov r8d,0x14
mov r9,0x402050
mov qword [rsp+0x20],0x0
call qword 0x2006
add rsp,byte +0x30
在我看来,至少 invoke
宏是正确的。 proc
-locals
-endproc
宏更难,因为它分散了,我相信 invoke
宏以某种方式依赖它。无论如何,序言最终扩展为:
push rbp
mov rbp,rsp
mov rax,rsp
and rax,byte +0xf
jz 0x15
sub rsp,byte +0x10
and spl,0xf0
mov [rbp+0x10],rcx
mov [rbp+0x18],rdx
结语最终扩展为:
mov rsp,rbp
pop rbp
ret
根据我对 Win64 的无可否认的微薄知识,两者似乎都可以。
编辑
好的,多亏了 Harry Johnston 的回答,我的代码才开始工作:
;%USERPROFILE%\nasm\learning\stdio.asm
;
;Basic usage of the standard input/output/error channels.
;
;nasm -f win64 stdio.asm
;golink /console /ni /entry main stdio.obj kernel32.dll
%include "\inc\nasmx.inc"
%include "\inc\win32\windows.inc"
%include "\inc\win32\kernel32.inc"
%ifidn __BITS__, 0x40
;// assert: set call stack for procedure prolog to max
;// invoke param bytes for 64-bit assembly mode
DEFAULT REL
NASMX_PRAGMA CALLSTACK, 0x30
%endif
entry toplevel
section .data
errmsg db "No errors to report!",0xd,0xa
errmsglen equ $-errmsg
query db "What is your name?",0xd,0xa
querylen equ $-query
greet db "Welcome, "
greetlen equ $-greet
crlf db 0xd,0xa
crlflen equ $-crlf
bNamelim equ 0xff
minusone equ 0xffffffffffffffff
zero equ 0x0
section .bss
hStdInput resq 0x1
hStdOutput resq 0x1
hStdError resq 0x1
hNum resq 0x1
hMode resq 0x1
bName resb 0x100
bNamelen resq 0x1
section .text
proc toplevel, ptrdiff_t argcount, ptrdiff_t cmdline
locals none
invoke GetStdHandle, STD_INPUT_HANDLE
mov qword [hStdInput], rax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov qword [hStdOutput], rax
invoke GetStdHandle, STD_ERROR_HANDLE
mov qword [hStdError], rax
invoke WriteFile, qword [hStdOutput], query, querylen, hNum, zero
invoke ReadFile, qword [hStdInput], bName, bNamelim, bNamelen, zero
invoke WriteFile, qword [hStdOutput], greet, greetlen, hNum, zero
invoke WriteFile, qword [hStdOutput], bName, [bNamelen], hNum, zero
invoke WriteFile, qword [hStdOutput], crlf, crlflen, hNum, zero
invoke WriteFile, qword [hStdError], errmsg, errmsglen, hNum, zero
invoke ExitProcess, zero
endproc
然而,该代码仍然没有回答 Raymond Chen 关于宏的问题以及它们是否违反 Win64 ABI,所以我将不得不再研究一下。
编辑 我认为没有宏的版本完全遵循 x64 ABI,包括展开数据。
;%USERPROFILE%\nasm\learning\stdio.asm
;
;Basic usage of the standard input/output/error channels.
;
;nasm -f win64 stdio.asm
;golink /console /ni /entry main stdio.obj kernel32.dll
;Image setup
bits 64
default rel
global main
;Linkage
extern GetStdHandle
extern WriteFile
extern ReadFile
extern ExitProcess
;Read only data
section .rdata use64
zero: equ 0x0
query: db "What is your name?",0xd,0xa
querylen: equ $-query
greet: db "Welcome, "
greetlen: equ $-greet
errmsg: db "No errors to report!",0xd,0xa
errmsglen: equ $-errmsg
crlf: db 0xd,0xa
crlflen: equ $-crlf
bNamelim: equ 0xff
STD_INPUT_HANDLE: equ -10
STD_OUTPUT_HANDLE: equ -11
STD_ERROR_HANDLE: equ -12
UNW_VERSION: equ 0x1
UNW_FLAG_NHANDLER: equ 0x0
UNW_FLAG_EHANDLER: equ 0x1
UNW_FLAG_UHANDLER: equ 0x2
UNW_FLAG_CHAININFO: equ 0x4
UWOP_PUSH_NONVOL: equ 0x0
UWOP_ALLOC_LARGE: equ 0x1
UWOP_ALLOC_SMALL: equ 0x2
UWOP_SET_FPREG: equ 0x3
UWOP_SAVE_NONVOL: equ 0x4
UWOP_SAVE_NONVOL_FAR: equ 0x5
UWOP_SAVE_XMM128: equ 0x8
UWOP_SAVE_XMM128_FAR: equ 0x9
UWOP_PUSH_MACHFRAME: equ 0xa
;Uninitialised data
section .bss use64
argc: resq 0x1
argv: resq 0x1
envp: resq 0x1
hStdInput: resq 0x1
hStdOutput: resq 0x1
hStdError: resq 0x1
hNum: resq 0x1
hMode: resq 0x1
bName: resb 0x100
bNamelen: resq 0x1
;Program code
section .text use64
main:
.prolog:
.argc: mov qword [argc], rcx
.argv: mov qword [argv], rdx
.envp: mov qword [envp], r8
.rsp: sub rsp, 0x8*0x4+0x8
.body:
; hStdInput = GetStdHandle (STD_INPUT_HANDLE)
mov rcx, qword STD_INPUT_HANDLE
call GetStdHandle
mov qword [hStdInput], rax
; hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE)
mov rcx, qword STD_OUTPUT_HANDLE
call GetStdHandle
mov qword [hStdOutput], rax
; hStdError = GetStdHandle (STD_ERROR_HANDLE)
mov rcx, qword STD_ERROR_HANDLE
call GetStdHandle
mov qword [hStdError], rax
; WriteFile (*hStdOutput, &query, querylen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword query
mov r8d, dword querylen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; ReadFile (*hStdInput, &bName, bNamelim, &bNameLen, NULL)
mov rcx, qword [hStdInput]
mov rdx, qword bName
mov r8d, dword bNamelim
mov r9, qword bNamelen
mov qword [rsp+0x20], zero
call ReadFile
; WriteFile (*hStdOutput, &crlf, crlflen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword crlf
mov r8d, dword crlflen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdOutput, &greet, greetlen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword greet
mov r8d, dword greetlen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdOutput, &bName, *bNamelen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword bName
mov r8d, dword [bNamelen]
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdOutput, &crlf, crlflen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword crlf
mov r8d, dword crlflen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdError, &errmsg, errmsglen, &hNum, NULL)
mov rcx, qword [hStdError]
mov rdx, qword errmsg
mov r8d, dword errmsglen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; ExitProcess(0)
.exit: xor ecx, ecx
call ExitProcess
.rval: xor eax, eax ; return 0
.epilog:
add rsp, 0x8*0x4+0x8
ret
.end:
; Win64 Windows API x64 Structured Exception Handling (SEH) - procedure data
section .pdata rdata align=4 use64
pmain:
.start: dd main wrt ..imagebase
.end: dd main.end wrt ..imagebase
.info: dd xmain wrt ..imagebase
; Win64 Windows API x64 Structured Exception Handling (SEH) - unwind information
section .xdata rdata align=8 use64
xmain:
.versionandflags:
db UNW_VERSION + (UNW_FLAG_NHANDLER << 0x3) ; Version = 1
; Version is low 3 bits. Handler flags are high 5 bits.
.size: db main.body-main.prolog ; size of prolog that is
.count: db 0x1 ; Only one unwind code
.frame: db 0x0 + (0x0 << 0x4) ; Zero if no frame pointer taken
; Frame register is low 4 bits, Frame register offset is high 4 bits,
; rsp + 16 * offset at time of establishing
.codes: db main.body-main.prolog ; offset of next instruction
db UWOP_ALLOC_SMALL + (0x4 << 0x4) ; UWOP_INFO: 4*8+8 bytes
; Low 4 bytes UWOP, high 4 bytes op info.
; Some ops use one or two 16 bit slots more for addressing here
db 0x0,0x0 ; Unused record to bring the number to be even
.handl: ; 32 bit image relative address to entry of exception handler
.einfo: ; implementation defined structure exception info
问题实际上是在您更改控制台模式时:
...
and dl, ENABLE_PROCESSED_INPUT
and dl, ENABLE_LINE_INPUT
and dl, ENABLE_ECHO_INPUT
...
因为 ENABLE_*
宏是单个位,and
将它们组合在一起会得到零,这意味着您将零传递给 SetConsoleMode
。如果要设置位,请使用 or
而不是 and
。如果您要清除这些位,则需要通过在前面添加 ~
(二进制 NOT)来反转这些位。
此外,根据 MSDN for GetConsoleInput
(具体来说,dwMode
参数),控制台在启动时无论如何都会设置这些位,因此您无需再次设置它们。
我怀疑这是你的问题:
bNamelim db 0xff
[...]
invoke ReadFile, qword [hStdInput], bName, bNamelim, bNamelen, zero
您传递的是地址而不是 bNamelim
的值。
我不确定 ReadFile 应该如何响应大于 32 位的值,但这肯定不是您想要的。
我刚开始学习 x64 汇编程序,我刚遇到一个我无法解释的问题。从 Kernel32.dll 的 ReadFile 如何从 C 代码工作,我期待它在控制台停止并等待我输入完整的行,然后 returning 到调用者,令人惊讶的是没有为我工作。 ReadFile 过程似乎 return 一个零长度的字符串,无论在键盘上按下什么,或者就此而言,从命令 shell.
上的管道传递给它的是什么;%USERPROFILE%\nasm\learning\stdio.asm
;
;Basic usage of the standard input/output/error channels.
;
;nasm -f win64 stdio.asm
;golink /console /ni /entry main stdio.obj kernel32.dll
%include "\inc\nasmx.inc"
%include "\inc\win32\windows.inc"
%include "\inc\win32\kernel32.inc"
%ifidn __BITS__, 0x40
;// assert: set call stack for procedure prolog to max
;// invoke param bytes for 64-bit assembly mode
DEFAULT REL
NASMX_PRAGMA CALLSTACK, 0x30
%endif
entry toplevel
;
section .data
errmsg db "No errors to report!",0xd,0xa
errmsglen equ $-errmsg
query db "What is your name?",0xd,0xa
querylen equ $-query
greet db "Welcome, "
greetlen equ $-greet
crlf db 0xd,0xa
crlflen equ $-crlf
bNamelim db 0xff
minusone equ 0xffffffffffffffff
zero equ 0x0
section .bss
hStdInput resq 0x1
hStdOutput resq 0x1
hStdError resq 0x1
hNum resq 0x1
hMode resq 0x1
bName resb 0x100
bNamelen resq 0x1
section .text
proc toplevel, ptrdiff_t argcount, ptrdiff_t cmdline
locals none
invoke GetStdHandle, STD_INPUT_HANDLE
mov qword [hStdInput], rax
; invoke GetConsoleMode, qword [hStdInput], hMode
; mov rdx, [hMode]
; and dl, ENABLE_PROCESSED_INPUT
; and dl, ENABLE_LINE_INPUT
; and dl, ENABLE_ECHO_INPUT
; invoke SetConsoleMode, qword [hStdInput], rdx
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov qword [hStdOutput], rax
invoke GetStdHandle, STD_ERROR_HANDLE
mov qword [hStdError], rax
invoke WriteFile, qword [hStdOutput], query, querylen, hNum, zero
invoke WaitForSingleObject, qword[hStdInput], minusone
invoke ReadFile, qword [hStdInput], bName, bNamelim, bNamelen, zero
invoke WriteFile, qword [hStdOutput], greet, greetlen, hNum, zero
invoke WriteFile, qword [hStdOutput], bName, bNamelen, hNum, zero
invoke WriteFile, qword [hStdOutput], crlf, crlflen, hNum, zero
invoke WriteFile, qword [hStdError], errmsg, errmsglen, hNum, zero
invoke ExitProcess, zero
endproc
我已经使用 C 运行时完成了相同的功能并且它有效,但现在我试图在不使用那个拐杖的情况下获得一个工作版本。我正在使用 NASM(使用 NASMX 包含提供宏的文件)和 GoLink,链接到 kernel32.dll。我究竟做错了什么?我错过了 which API 的什么行为? 从有关 Win32 控制台的 MSDN 文章 APIs,ReadFile 的行为让我感到惊讶。
此外,如果我从程序集中删除 WaitForSingleObject 调用,C 等价物中不存在的东西,整个程序完成 运行 而无需停止等待控制台输入,尽管 ReadFile 被假定为做到这一点。
编辑 好吧,Raymond Chen 询问了宏扩展以及根据调用约定它们是否正确,所以:
invoke GetStdHandle, STD_INPUT_HANDLE
mov qword [hStdInput], rax
这变成了
sub rsp,byte +0x20
mov rcx,0xfffffffffffffff6
call qword 0x2000
add rsp,byte +0x20
mov [0x402038],rax
这似乎遵循 Win64 的 0-4 整数参数调用的调用约定就好了。五参数形式怎么样?
invoke WriteFile, qword [hStdOutput], query, querylen, hNum, zero
这变成了
sub rsp,byte +0x30
mov rcx,[0x402040]
mov rdx,0x402016
mov r8d,0x14
mov r9,0x402050
mov qword [rsp+0x20],0x0
call qword 0x2006
add rsp,byte +0x30
在我看来,至少 invoke
宏是正确的。 proc
-locals
-endproc
宏更难,因为它分散了,我相信 invoke
宏以某种方式依赖它。无论如何,序言最终扩展为:
push rbp
mov rbp,rsp
mov rax,rsp
and rax,byte +0xf
jz 0x15
sub rsp,byte +0x10
and spl,0xf0
mov [rbp+0x10],rcx
mov [rbp+0x18],rdx
结语最终扩展为:
mov rsp,rbp
pop rbp
ret
根据我对 Win64 的无可否认的微薄知识,两者似乎都可以。
编辑 好的,多亏了 Harry Johnston 的回答,我的代码才开始工作:
;%USERPROFILE%\nasm\learning\stdio.asm
;
;Basic usage of the standard input/output/error channels.
;
;nasm -f win64 stdio.asm
;golink /console /ni /entry main stdio.obj kernel32.dll
%include "\inc\nasmx.inc"
%include "\inc\win32\windows.inc"
%include "\inc\win32\kernel32.inc"
%ifidn __BITS__, 0x40
;// assert: set call stack for procedure prolog to max
;// invoke param bytes for 64-bit assembly mode
DEFAULT REL
NASMX_PRAGMA CALLSTACK, 0x30
%endif
entry toplevel
section .data
errmsg db "No errors to report!",0xd,0xa
errmsglen equ $-errmsg
query db "What is your name?",0xd,0xa
querylen equ $-query
greet db "Welcome, "
greetlen equ $-greet
crlf db 0xd,0xa
crlflen equ $-crlf
bNamelim equ 0xff
minusone equ 0xffffffffffffffff
zero equ 0x0
section .bss
hStdInput resq 0x1
hStdOutput resq 0x1
hStdError resq 0x1
hNum resq 0x1
hMode resq 0x1
bName resb 0x100
bNamelen resq 0x1
section .text
proc toplevel, ptrdiff_t argcount, ptrdiff_t cmdline
locals none
invoke GetStdHandle, STD_INPUT_HANDLE
mov qword [hStdInput], rax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov qword [hStdOutput], rax
invoke GetStdHandle, STD_ERROR_HANDLE
mov qword [hStdError], rax
invoke WriteFile, qword [hStdOutput], query, querylen, hNum, zero
invoke ReadFile, qword [hStdInput], bName, bNamelim, bNamelen, zero
invoke WriteFile, qword [hStdOutput], greet, greetlen, hNum, zero
invoke WriteFile, qword [hStdOutput], bName, [bNamelen], hNum, zero
invoke WriteFile, qword [hStdOutput], crlf, crlflen, hNum, zero
invoke WriteFile, qword [hStdError], errmsg, errmsglen, hNum, zero
invoke ExitProcess, zero
endproc
然而,该代码仍然没有回答 Raymond Chen 关于宏的问题以及它们是否违反 Win64 ABI,所以我将不得不再研究一下。
编辑 我认为没有宏的版本完全遵循 x64 ABI,包括展开数据。
;%USERPROFILE%\nasm\learning\stdio.asm
;
;Basic usage of the standard input/output/error channels.
;
;nasm -f win64 stdio.asm
;golink /console /ni /entry main stdio.obj kernel32.dll
;Image setup
bits 64
default rel
global main
;Linkage
extern GetStdHandle
extern WriteFile
extern ReadFile
extern ExitProcess
;Read only data
section .rdata use64
zero: equ 0x0
query: db "What is your name?",0xd,0xa
querylen: equ $-query
greet: db "Welcome, "
greetlen: equ $-greet
errmsg: db "No errors to report!",0xd,0xa
errmsglen: equ $-errmsg
crlf: db 0xd,0xa
crlflen: equ $-crlf
bNamelim: equ 0xff
STD_INPUT_HANDLE: equ -10
STD_OUTPUT_HANDLE: equ -11
STD_ERROR_HANDLE: equ -12
UNW_VERSION: equ 0x1
UNW_FLAG_NHANDLER: equ 0x0
UNW_FLAG_EHANDLER: equ 0x1
UNW_FLAG_UHANDLER: equ 0x2
UNW_FLAG_CHAININFO: equ 0x4
UWOP_PUSH_NONVOL: equ 0x0
UWOP_ALLOC_LARGE: equ 0x1
UWOP_ALLOC_SMALL: equ 0x2
UWOP_SET_FPREG: equ 0x3
UWOP_SAVE_NONVOL: equ 0x4
UWOP_SAVE_NONVOL_FAR: equ 0x5
UWOP_SAVE_XMM128: equ 0x8
UWOP_SAVE_XMM128_FAR: equ 0x9
UWOP_PUSH_MACHFRAME: equ 0xa
;Uninitialised data
section .bss use64
argc: resq 0x1
argv: resq 0x1
envp: resq 0x1
hStdInput: resq 0x1
hStdOutput: resq 0x1
hStdError: resq 0x1
hNum: resq 0x1
hMode: resq 0x1
bName: resb 0x100
bNamelen: resq 0x1
;Program code
section .text use64
main:
.prolog:
.argc: mov qword [argc], rcx
.argv: mov qword [argv], rdx
.envp: mov qword [envp], r8
.rsp: sub rsp, 0x8*0x4+0x8
.body:
; hStdInput = GetStdHandle (STD_INPUT_HANDLE)
mov rcx, qword STD_INPUT_HANDLE
call GetStdHandle
mov qword [hStdInput], rax
; hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE)
mov rcx, qword STD_OUTPUT_HANDLE
call GetStdHandle
mov qword [hStdOutput], rax
; hStdError = GetStdHandle (STD_ERROR_HANDLE)
mov rcx, qword STD_ERROR_HANDLE
call GetStdHandle
mov qword [hStdError], rax
; WriteFile (*hStdOutput, &query, querylen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword query
mov r8d, dword querylen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; ReadFile (*hStdInput, &bName, bNamelim, &bNameLen, NULL)
mov rcx, qword [hStdInput]
mov rdx, qword bName
mov r8d, dword bNamelim
mov r9, qword bNamelen
mov qword [rsp+0x20], zero
call ReadFile
; WriteFile (*hStdOutput, &crlf, crlflen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword crlf
mov r8d, dword crlflen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdOutput, &greet, greetlen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword greet
mov r8d, dword greetlen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdOutput, &bName, *bNamelen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword bName
mov r8d, dword [bNamelen]
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdOutput, &crlf, crlflen, &hNum, NULL)
mov rcx, qword [hStdOutput]
mov rdx, qword crlf
mov r8d, dword crlflen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; WriteFile (*hStdError, &errmsg, errmsglen, &hNum, NULL)
mov rcx, qword [hStdError]
mov rdx, qword errmsg
mov r8d, dword errmsglen
mov r9, qword hNum
mov qword [rsp+0x20], zero
call WriteFile
; ExitProcess(0)
.exit: xor ecx, ecx
call ExitProcess
.rval: xor eax, eax ; return 0
.epilog:
add rsp, 0x8*0x4+0x8
ret
.end:
; Win64 Windows API x64 Structured Exception Handling (SEH) - procedure data
section .pdata rdata align=4 use64
pmain:
.start: dd main wrt ..imagebase
.end: dd main.end wrt ..imagebase
.info: dd xmain wrt ..imagebase
; Win64 Windows API x64 Structured Exception Handling (SEH) - unwind information
section .xdata rdata align=8 use64
xmain:
.versionandflags:
db UNW_VERSION + (UNW_FLAG_NHANDLER << 0x3) ; Version = 1
; Version is low 3 bits. Handler flags are high 5 bits.
.size: db main.body-main.prolog ; size of prolog that is
.count: db 0x1 ; Only one unwind code
.frame: db 0x0 + (0x0 << 0x4) ; Zero if no frame pointer taken
; Frame register is low 4 bits, Frame register offset is high 4 bits,
; rsp + 16 * offset at time of establishing
.codes: db main.body-main.prolog ; offset of next instruction
db UWOP_ALLOC_SMALL + (0x4 << 0x4) ; UWOP_INFO: 4*8+8 bytes
; Low 4 bytes UWOP, high 4 bytes op info.
; Some ops use one or two 16 bit slots more for addressing here
db 0x0,0x0 ; Unused record to bring the number to be even
.handl: ; 32 bit image relative address to entry of exception handler
.einfo: ; implementation defined structure exception info
问题实际上是在您更改控制台模式时:
...
and dl, ENABLE_PROCESSED_INPUT
and dl, ENABLE_LINE_INPUT
and dl, ENABLE_ECHO_INPUT
...
因为 ENABLE_*
宏是单个位,and
将它们组合在一起会得到零,这意味着您将零传递给 SetConsoleMode
。如果要设置位,请使用 or
而不是 and
。如果您要清除这些位,则需要通过在前面添加 ~
(二进制 NOT)来反转这些位。
此外,根据 MSDN for GetConsoleInput
(具体来说,dwMode
参数),控制台在启动时无论如何都会设置这些位,因此您无需再次设置它们。
我怀疑这是你的问题:
bNamelim db 0xff
[...]
invoke ReadFile, qword [hStdInput], bName, bNamelim, bNamelen, zero
您传递的是地址而不是 bNamelim
的值。
我不确定 ReadFile 应该如何响应大于 32 位的值,但这肯定不是您想要的。