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

汇编调用Windows API复制文件丢失首词问题求助

汇编复制TXT文件丢失首个单词的Bug排查与修复

问题描述

使用Windows API编写汇编代码复制TXT文件,复制后原文件首个单词丢失。输入示例:

  • 源文件路径:C:\Users\User\Desktop\qwe\qwe.txt
  • 目标文件路径:C:\Users\User\Desktop\qwe2\qwe2.txt

原始代码

%include "io.inc"

extern _access
extern _MessageBoxA@16
extern _CloseHandle@4
extern _CreateFileA@28
extern _WriteFile@20
extern _ReadFile@20
extern _strcat
extern _strlen
extern _strtok

section .data

    buffer1 times 0xff db 0x0
    buffer1_len equ $ - buffer1
    buffer2 times 0xff db 0x0
    buffer2_len equ $ - buffer2
    
    caption db 'Do you want to Copy?', 0x0
    format db 0x0a, 0x00
    
    error db 'There is no file', 0x0d, 0x00
    error_caption db 'error', 0x0d, 0x00
    
    file db 0x00
    file2 db 0x00
    read_file_pointer times 0xffff dq 0x00
    new_file db 0x00
    read_len times 0xfffff dq 0x00
section .text
global CMAIN

    
filecheck:
    push 0x00
    push buffer1
    call _access
    add esp, 8
    cmp eax, 0
    jne error_message
    
    call copy
    ret
copy:
    push ebp
    mov ebp, esp
    
    push 0x0
    push 0x0
    push 0x3
    push 0x0
    push 0x0
    push 0x1
    push buffer1
    call _CreateFileA@28
    mov [file], eax
    
    push 0x0
    push read_len
    push 0xff
    push read_file_pointer
    push dword [file]
    call _ReadFile@20
    
    push dword [file]
    call _CloseHandle@4
    
    push 0
    push 0x80
    push 2
    push 0
    push 0
    push 0x40000000
    push buffer2
    call _CreateFileA@28
    mov [file2], eax
  

    ;Write File
    push 0
    push 0
    push dword [read_len]
    push read_file_pointer
    push dword [file2]
    call _WriteFile@20

    
    push dword [file2]
    call _CloseHandle@4
    
    mov esp, ebp
    pop ebp
    ret
    
error_message:
    push dword 0x0
    push dword error_caption
    push dword error
    push dword 0x0
    call _MessageBoxA@16
    cmp eax, 1
    je program_exit
        
message_box:
    push dword 0x4
    push dword caption
    push dword buffer1
    push dword 0x0
    call _MessageBoxA@16
    ret
    
cat:
    push ebp
    mov ebp, esp
    push buffer2
    push buffer1
    call _strcat
    mov esp, ebp
    pop ebp
    ret
    
strlens:
    push ebp
    mov ebp, esp
    push format
    push buffer1
    call _strtok
    mov esp, ebp
    pop ebp
    ret
    
CMAIN:
    mov ebp, esp; for correct debugging
    mov ax, buffer1_len
    GET_STRING buffer1, ax
    mov ax, buffer2_len
    GET_STRING buffer2, ax
    
    call cat
    call message_box
    call strlens
    
    call filecheck
    
program_exit:
    xor eax, eax
    ret

问题根源分析

  1. 冗余字符串操作破坏源路径:

    • cat函数调用_strcat(buffer1, buffer2),将目标路径拼接到源路径缓冲区末尾,直接破坏了buffer1中存储的源文件路径,导致后续CreateFileA打开的不是正确的源文件。
    • strlens函数调用_strtok(buffer1, format),进一步修改buffer1的内容,截断路径字符串,加剧了路径错误问题。这两个函数完全多余,复制文件不需要此类操作。
  2. 变量类型不匹配:

    • file和file2定义为单字节db 0x00,但Windows API的CreateFileA返回的HANDLE在32位系统中是4字节DWORD,存储时会截断句柄值,导致后续ReadFile/WriteFile/CloseHandle使用无效句柄。
  3. 缓冲区与长度变量定义冗余:

    • read_len定义为超大数组times 0xfffff dq 0x00,但ReadFile只需要一个指向DWORD的指针接收实际读取字节数,冗余定义会导致内存浪费且可能引发指针错误。
    • read_file_pointer定义为times 0xffff dq 0x00,实际每次仅读取0xff字节,无需如此大的空间。

修复后的代码

%include "io.inc"

extern _access
extern _MessageBoxA@16
extern _CloseHandle@4
extern _CreateFileA@28
extern _WriteFile@20
extern _ReadFile@20

section .data
    buffer1 times 0xff db 0x0
    buffer1_len equ $ - buffer1
    buffer2 times 0xff db 0x0
    buffer2_len equ $ - buffer2
    
    caption db 'Do you want to Copy?', 0x0
    error db 'There is no file', 0x0d, 0x00
    error_caption db 'error', 0x0d, 0x00
    
    ; 修复:HANDLE是32位DWORD,用dd定义
    file dd 0x00
    file2 dd 0x00
    ; 修复:读取缓冲区只需0xff字节,匹配ReadFile的读取长度
    read_buffer times 0xff db 0x0
    ; 修复:read_len用DWORD变量存储实际读取字节数
    read_len dd 0x00

section .text
global CMAIN

filecheck:
    push 0x00
    push buffer1
    call _access
    add esp, 8
    cmp eax, 0
    jne error_message
    
    call copy
    ret

copy:
    push ebp
    mov ebp, esp
    
    ; 打开源文件:GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING
    push 0x0
    push 0x0
    push 0x3
    push 0x0
    push 0x0
    push 0x80000000 ; GENERIC_READ
    push buffer1
    call _CreateFileA@28
    mov [file], eax
    
    ; 读取文件内容到read_buffer
    push 0x0
    push read_len
    push 0xff
    push read_buffer
    push dword [file]
    call _ReadFile@20
    
    push dword [file]
    call _CloseHandle@4
    
    ; 打开目标文件:GENERIC_WRITE, CREATE_ALWAYS
    push 0
    push 0x80
    push 2
    push 0
    push 0
    push 0x40000000 ; GENERIC_WRITE
    push buffer2
    call _CreateFileA@28
    mov [file2], eax
  
    ; 写入文件内容
    push 0
    push 0
    push dword [read_len]
    push read_buffer
    push dword [file2]
    call _WriteFile@20
    
    push dword [file2]
    call _CloseHandle@4
    
    mov esp, ebp
    pop ebp
    ret

error_message:
    push dword 0x0
    push dword error_caption
    push dword error
    push dword 0x0
    call _MessageBoxA@16
    cmp eax, 1
    je program_exit
        
message_box:
    push dword 0x4
    push dword caption
    push dword buffer1
    push dword 0x0
    call _MessageBoxA@16
    ret

CMAIN:
    mov ebp, esp; for correct debugging
    mov ax, buffer1_len
    GET_STRING buffer1, ax
    mov ax, buffer2_len
    GET_STRING buffer2, ax
    
    call message_box
    call filecheck
    
program_exit:
    xor eax, eax
    ret

修复说明

  1. 移除冗余函数:删除cat和strlens函数,避免破坏源路径缓冲区buffer1。
  2. 修正变量类型:将file和file2改为dd 0,正确存储32位文件句柄。
  3. 优化缓冲区与长度变量:
    • 将read_file_pointer改为read_buffer,大小设为0xff字节,匹配每次读取的长度。
    • 将read_len改为dd 0,作为ReadFile接收实际读取字节数的变量。
  4. 修正CreateFileA的访问权限:打开源文件时使用0x80000000(GENERIC_READ),确保正确的读取权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 02:50:38