Windows平台x64 MASM汇编调用CreateFileA/WriteFile写文件失败求助
x64 MASM 中 CreateFileA + WriteFile 写入失败问题排查与修复
问题描述
在Windows x64平台使用MASM编写汇编代码,调用CreateFileA打开文件后,WriteFile返回RAX=0(执行失败),无法正确写入内容。
原代码片段
INCLUDELIB kernel32.lib ExitProcess PROTO CreateFileA PROTO WriteFile PROTO clearRegisters MACRO XOR RAX, RAX XOR RDX, RDX XOR RCX, RCX XOR R8, R8 XOR R9, R9 ENDM GENERIC_WRITE EQU 04000000h ;Solution 040000000h FILE_SHARE_READ EQU 1 FILE_SHARE_WRITE EQU 2 OPEN_ALWAYS EQU 4 FILE_ATTRIBUTE_NORMAL EQU 128 .DATA filePath BYTE "D:/thanks/ASSEMBLY.txt", 0 fileHandle QWORD ? txt BYTE "Learning Assembly for shellcode development.", 0 num DWORD ? .CODE main PROC clearRegisters SUB RSP, 64 LEA RCX, filePath MOV RDX, GENERIC_WRITE MOV R8, FILE_SHARE_READ OR FILE_SHARE_WRITE MOV R9, 0 MOV QWORD PTR [RSP+32], OPEN_ALWAYS MOV QWORD PTR [RSP+40], FILE_ATTRIBUTE_NORMAL MOV QWORD PTR [RSP+48], 0 CALL CreateFileA MOV fileHandle, RAX clearRegisters MOV RCX, fileHandle LEA RDX, txt MOV R8, LENGTHOF txt LEA R9, num MOV QWORD PTR [ RSP+32 ], 0 CALL WriteFile TEST RAX, RAX CALL ExitProcess main ENDP END
问题分析与修复点
1. 修正GENERIC_WRITE常量值
Windows API中GENERIC_WRITE的正确十六进制值为040000000h(即0x40000000),原代码少写一位,导致无法获取正确的文件写入权限,CreateFileA返回无效句柄。
2. 添加CreateFileA返回值检查
CreateFileA失败时会返回INVALID_HANDLE_VALUE(值为-1),必须先检查句柄有效性,再执行后续写入操作,否则无效句柄会直接导致WriteFile失败。
3. 优化写入长度计算
LENGTHOF txt会包含字符串末尾的空字节,写入文件时通常不需要该字符,改用SIZEOF txt - 1计算有效内容长度。
4. 栈参数传递确认
x64 Windows调用约定要求剩余参数按从右到左顺序压入栈,原代码的栈参数位置符合要求,但需确保调用API前栈保持16字节对齐(原代码SUB RSP,64已满足,64是16的倍数)。
修复后的代码
INCLUDELIB kernel32.lib ExitProcess PROTO CreateFileA PROTO WriteFile PROTO clearRegisters MACRO XOR RAX, RAX XOR RDX, RDX XOR RCX, RCX XOR R8, R8 XOR R9, R9 ENDM GENERIC_WRITE EQU 040000000h ; 修正为正确的写入权限常量 FILE_SHARE_READ EQU 1 FILE_SHARE_WRITE EQU 2 OPEN_ALWAYS EQU 4 FILE_ATTRIBUTE_NORMAL EQU 128 INVALID_HANDLE_VALUE EQU -1 .DATA filePath BYTE "D:/thanks/ASSEMBLY.txt", 0 fileHandle QWORD ? txt BYTE "Learning Assembly for shellcode development.", 0 num DWORD ? .CODE main PROC clearRegisters SUB RSP, 64 ; 分配栈空间,保证16字节对齐 ; 调用CreateFileA打开文件 LEA RCX, filePath ; 参数1: 文件名指针 MOV RDX, GENERIC_WRITE ; 参数2: 写入权限 MOV R8, FILE_SHARE_READ OR FILE_SHARE_WRITE ; 参数3: 共享模式 MOV R9, 0 ; 参数4: 安全属性(NULL) MOV QWORD PTR [RSP+32], OPEN_ALWAYS ; 参数5: 创建/打开方式 MOV QWORD PTR [RSP+40], FILE_ATTRIBUTE_NORMAL ; 参数6: 文件属性 MOV QWORD PTR [RSP+48], 0 ; 参数7: 模板文件句柄(NULL) CALL CreateFileA MOV fileHandle, RAX ; 检查文件句柄是否有效 CMP RAX, INVALID_HANDLE_VALUE JE exit_program ; 若无效则直接退出 ; 调用WriteFile写入内容 clearRegisters MOV RCX, fileHandle ; 参数1: 文件句柄 LEA RDX, txt ; 参数2: 写入内容指针 MOV R8, SIZEOF txt - 1 ; 参数3: 有效内容长度(去掉末尾空字节) LEA R9, num ; 参数4: 实际写入字节数指针 MOV QWORD PTR [RSP+32], 0 ; 参数5: 重叠结构(NULL) CALL WriteFile ; 可根据RAX值判断写入结果,添加后续处理逻辑 exit_program: CALL ExitProcess main ENDP END
验证注意事项
确保D:/thanks/目录已存在,否则CreateFileA会因路径不存在失败;编译运行后,检查D:/thanks/ASSEMBLY.txt是否包含指定内容。
内容的提问来源于stack exchange,提问作者0x1d
相关产品推荐
相关产品推荐

