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= 命令行参数个数argcrdx= 命令行参数数组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
相关产品推荐
相关产品推荐

