You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win64汇编PE64 Console程序无法获取argc和argv问题求助

Win64汇编(FASM PE64 CONSOLE)命令行参数获取错误排查

你在开发Win64汇编项目时遇到了命令行参数获取的问题:原本预期[rsp]是参数个数argc、[rsp+8]是可执行文件名,但实际取值完全不符合预期,导致程序无论是否传参都会打印消息。你的FASM源码如下:

FORMAT PE64 CONSOLE
ENTRY MAIN
SECTION '.text' CODE READABLE EXECUTABLE
MAIN:
 mov r12, [rsp] ; 此处r12应存储命令行参数个数,但实际不是!
 sub rsp, 56
 mov ecx, -11
 call [K32.GetStdHandle]
 cmp r12, 1 ; 参数个数需大于1(默认是可执行文件名,传参时才打印)
 jle .exit
.write:
 mov ecx, eax ; STD_OUTPUT_HANDLE(EAX)
 mov rdx, .hello
 mov r8d, .hello_len
 xor r9d, r9d
 mov QWORD [rsp+32], 0
 call [K32.WriteFile]
.exit:
 add rsp, 56
 xor ecx, ecx
 call [K32.ExitProcess]
 hlt
.hello DB 'Argument Received', 0x00
.hello_len = $ - .hello
SECTION '.idata' IMPORT DATA READABLE WRITABLE
 DD 0,0,0,RVA K32DLL,RVA K32
 DD 0,0,0,0,0
K32DLL DB 'KERNEL32.DLL', 0x00
K32:
 .ExitProcess DQ RVA ___ExitProcess
 .GetStdHandle DQ RVA ___GetStdHandle
 .WriteFile DQ RVA ___WriteFile
 DQ 0
___ExitProcess DB 0,0,'ExitProcess',0
___GetStdHandle DB 0,0,'GetStdHandle',0
___WriteFile DB 0,0,'WriteFile',0

问题根源:Win64入口点的调用约定和Win32完全不同!

你之前的认知是Win32汇编的参数传递逻辑,但Win64采用FastCall调用约定——系统调用你的入口点MAIN时,参数并不是直接压在栈上,而是通过寄存器传递:

  • rcx = 命令行参数个数argc
  • rdx = 命令行参数数组argv(每个元素是指向字符串的指针)

你现在直接读取[rsp],拿到的其实是系统调用入口点后的返回地址,自然不是你想要的argc。

修复后的代码

只需要修改参数获取的部分,直接从寄存器读取argc即可:

FORMAT PE64 CONSOLE
ENTRY MAIN
SECTION '.text' CODE READABLE EXECUTABLE
MAIN:
 mov r12, rcx ; 直接从rcx获取argc!
 sub rsp, 56
 mov ecx, -11
 call [K32.GetStdHandle]
 cmp r12, 1 ; 参数个数大于1时(即存在用户传入的参数)执行打印
 jle .exit
.write:
 mov ecx, eax ; STD_OUTPUT_HANDLE
 mov rdx, .hello
 mov r8d, .hello_len
 xor r9d, r9d
 mov QWORD [rsp+32], 0
 call [K32.WriteFile]
.exit:
 add rsp, 56
 xor ecx, ecx
 call [K32.ExitProcess]
 hlt
.hello DB 'Argument Received', 0x00
.hello_len = $ - .hello
SECTION '.idata' IMPORT DATA READABLE WRITABLE
 DD 0,0,0,RVA K32DLL,RVA K32
 DD 0,0,0,0,0
K32DLL DB 'KERNEL32.DLL', 0x00
K32:
 .ExitProcess DQ RVA ___ExitProcess
 .GetStdHandle DQ RVA ___GetStdHandle
 .WriteFile DQ RVA ___WriteFile
 DQ 0
___ExitProcess DB 0,0,'ExitProcess',0
___GetStdHandle DB 0,0,'GetStdHandle',0
___WriteFile DB 0,0,'WriteFile',0

额外说明:如果需要访问具体参数

比如要获取第一个用户传入的参数(即可执行文件名后的第一个参数),可以通过rdx指向的argv数组读取:

; 假设r12已经存储了argc,rdx是argv数组
cmp r12, 2 ; 确保存在至少一个用户参数
jle .no_arg
mov rsi, [rdx + 8] ; argv[1],第一个用户参数的指针
; 接下来可以使用rsi指向的字符串做操作
.no_arg:

修改后,程序就能正确判断是否有用户传入的参数,只有当参数个数大于1时才打印消息,完全符合你的预期。

内容的提问来源于stack exchange,提问作者ELHASKSERVERS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:55:23