汇编实现凯撒密码时写入超512字节文件失败的问题排查
凯撒密码文件加解密程序问题修复:仅处理前512字节
问题描述
我用汇编实现了凯撒密码程序,支持文件加解密、密码分析,要求按512字节块读写文件,但处理超过512字节的文件时,仅能输出前512字节内容。曾怀疑问题出在WriteFile调用,但排查后发现根源并非该函数本身。
错误根源:寄存器冲突
核心问题是寄存器被意外覆盖:
在descriptografar和criptografar函数中,你将输入文件的句柄存入了edi寄存器,但在后续处理缓冲区的循环里,执行了lea edi, [buffer],直接覆盖了edi中保存的文件句柄。当第一次循环结束后,第二次调用ReadFile时,edi已经指向缓冲区而非文件句柄,导致无法读取后续文件块,最终只处理了第一块512字节数据。
修复方案
更换用于保存文件句柄的寄存器,避免和缓冲区操作使用的寄存器冲突。比如将输入文件句柄存入ebp(或其他未被缓冲区操作占用的寄存器),保留edi用于缓冲区指针操作。
修正后的核心代码片段(以descriptografar为例)
descriptografar: ; ... 省略原有输入读取、密钥转换代码 ... invoke CreateFile, addr inputFileBuffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL mov ebp, eax ; 用ebp保存输入文件句柄,替换原来的edi invoke CreateFile, addr outputFileBuffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL mov ebx, eax @@readLoop1: invoke ReadFile, ebp, addr buffer, sizeof buffer, addr bytesRead, NULL ; 这里用ebp作为文件句柄 xor ecx, ecx mov ecx, dword ptr [bytesRead] cmp ecx, 0 je @@endReadLoop1 lea edi, [buffer] mov esi, edi mov edx, ecx @@loop1: mov al, byte ptr [esi] sub al, byte ptr [keyBuffer] mov byte ptr [edi], al inc esi inc edi dec edx jnz @@loop1 mov ecx, dword ptr [bytesRead] invoke WriteFile, ebx, addr buffer, ecx, addr bytesWritten, NULL jmp @@readLoop1 @@endReadLoop1: invoke CloseHandle, ebp ; 关闭文件句柄时用ebp invoke CloseHandle, ebx jmp menuLoop
同样需要修正criptografar函数
将其中保存输入文件句柄的edi替换为ebp,对应ReadFile和CloseHandle的调用也改为使用ebp:
criptografar: ; ... 省略原有输入读取、密钥转换代码 ... invoke CreateFile, addr inputFileBuffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL mov ebp, eax ; 替换edi为ebp invoke CreateFile, addr outputFileBuffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL mov ebx, eax @@readLoop2: invoke ReadFile, ebp, addr buffer, sizeof buffer, addr bytesRead, NULL ; 使用ebp xor ecx, ecx mov ecx, dword ptr [bytesRead] cmp ecx, 0 je @@endReadLoop2 lea edi, [buffer] mov esi, edi mov edx, ecx @@loop2: mov al, byte ptr [esi] add al, byte ptr [keyBuffer] mov byte ptr [edi], al inc esi inc edi dec edx jnz @@loop2 mov ecx, dword ptr [bytesRead] invoke WriteFile, ebx, addr buffer, ecx, addr bytesWritten, NULL jmp @@readLoop2 @@endReadLoop2: invoke CloseHandle, ebp ; 使用ebp关闭句柄 invoke CloseHandle, ebx jmp menuLoop
额外注意事项
- 凯撒密码仅对字母有效,当前代码会修改所有字节(包括非字母字符),如果需要仅处理字母,需添加判断逻辑(比如检查ASCII范围是否在A-Z或a-z之间)。
- 密钥处理部分,
atodw返回的是双字,但你只取了al(字节),如果密钥超过255会被截断,但需求里密钥是1-20,所以当前逻辑没问题。
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

