首页 > 解决方案 > 大会 x86:LEA 和 MOVSB 更改了我的源字符串?

问题描述

我正在使用 Assembler x86(Windows 中的 Intel 32 位)做一个程序。我正在制作一个程序(用于家庭作业),我必须在其中加密一个字符串,我将通过两个字符符合的块对其进行迭代。我使用 EBX 在源字符串中移动,将其增加 2。目前,我没有进入程序的加密部分,因为我遇到了比这更小的问题。问题是,当一个块具有相同的字符时,比如“AA”,它不需要经过密码处理,所以我必须将“AA”原样复制到结果字符串中。这就是我这样做的方式:

CypheLoop:
call VerifyBlock
cmp byte[caracblock], 0
je End
cmp byte[caracblock], 1
je AddLastCharacter
cmp byte[caracblock], 2
je AddNoCiphedBlock
jmp CipheLoop

VerifyBlock 负责查看一个块的一致性,它根据其特征将“caracblock”更改为一个数字。0 表示块为空(表示字符串结束),1 表示块中只有一个字符(例如“ABC”,将有一个只有“C”的块),2 如果块的字符必须按原样复制(如前所述,另一种情况是块中有空格),或者如果块需要加密,则为 3。到目前为止,一切都很好!程序按预期添加字符并完成,但是,AddNoCiphedBlock 有一些意外行为,它看起来像这样:

AddNoCiphedBlock:
    mov esi, 0
    mov edi, 0
    mov ecx, 2
    lea esi, [sourcestring + ebx]
    lea edi, [resultstring + ebx]
    rep movsb
    add ebx, 2
    jmp CipheLoop

问题不在于它返回什么(尽管我得到的不是我所期望的),但问题的根源在于,由于某种原因,源字符串被改变了。如果我写“AA”,我得到“AA”,正确。如果我写“AABB”,我会得到“AABB”,这是正确的。如果我写“AABBCC”,我会得到“AABBAA”。源字符串,在使用 AddNoCiphedBlock 后,变为“AABBAA”,并且继续恶化。这就是通过该过程对源字符串发生的事情

AABBCC
AABBAA
AABBAA
AABBAABB
AABBAABB
AABBAABBAA

为什么会这样?我只是从源头复制一些东西!我的源字符串和结果字符串都在 .bss 部分中,分别为“sourcestring resd 1”和“resultstring resd 1”。我使用 _gets 来获取源字符串。我试图给出尽可能多的解释和细节,我什至无法理解为什么会出现这样的错误。

标签: stringassemblyx86nasm

解决方案


您只使用gets和缓冲了 4 个字节长 ( resd 1),然后溢出了它们。

当您的字符串为 4 个输入字符或更长时,终止0字节位于缓冲区之外。(gets总共存储 5 个字节:数据加上一个终止符。4'A'个字节进入,sourcestring: resd 1终止0resultstring: resd 1.

如果它们相邻,则将 src 的前 2 个字节复制到 dst 会覆盖src的0字节,因为它也是 dst 的第一个字节。

使用(大得多)更大的缓冲区,和/或使用一个函数,该函数采用读取多少字节的上限(缓冲区大小)。


如何调试这个:

一旦您知道一个字节正在更改而您希望不会更改,请在调试器中的该地址上设置一个观察点。然后它将在更改它的指令处停止。

在您的情况下,这将0"AABB". 该地址是sourcestring+4因为它位于 4 个 ASCII 字节之后。然后让它运行,你会看到它停在rep movsb.

此外,您在执行此操作时可能会注意到您的缓冲区只有 4 个字节长,因此sourcestring+4位于 4 字节缓冲区之外,和/或地址与resultstring.


代码审查:

mov esi,0没用;您已经使用lea. 此外,使用rep movsb固定大小的 2 字节副本非常复杂。

    movzx eax,  word [sourcestring + ebx]      ; 2-byte load
    mov   [resultstring + ebx], ax             ; 2-byte store

或者,如果您坚持movs,请使用movsw一次。(不是rep movsw这样你就不必设置ECX)。


推荐阅读