TEST指令和ZF标志

逆向工程 部件 登记
2021-06-21 07:57:27

在 lena151 RE 教程的第 07 部分中,我们得到了以下说明:

AL = 0
TEST AL,AL
JNZ ...

在此处输入图片说明

并注意:

由于JNZ,到达这里时AL必须不为零才能注册。

我的问题是:为什么 AL 必须不同于零?如果 2 个值 (0=0) 相等,则 Z 标志设置为 1,因为比较结果为真!这是正确的吗?

3个回答

为什么零标志必须与零不同?

这是一个有点混乱,但零标志为一组(即其值为1),如果最后的结果IS为零:

  • 结果 0⇒ ZF不是 0
  • 结果不是 0⇒ ZF 0

通常,设置一个标志来表明适当的条件为真,或者适当的事件发生了。(我们也说标志是( 1) 或( 0))。

。顺便说一句,这可能是也有点反直觉:JNZĴ UMP如果Ñ OT Ž ERO)跳转如果ZF 零(因为这意味着“不为零,在过去结果”,而不是“不为零的零标志”)。

最好只考虑结果,而忽略零标志- 标志主要是机器的技术工具,而不是我们人类的。

如果 2 值 (0=0) 相等,则 Z 标志设置为 1,因为比较的结果为真!这是正确的吗?

不完全的:

  • CMP比较的情况下零的意思是“他们的差为零”,所以他们是一样的,但是

  • 在 的情况下TEST AL,AL表示AND AL,AL为零”,AL本身为零

    TEST AL,AL当且仅当 AL 本身的值也为零时,该指令的结果为零。

    解释,为什么:

    • 如果值AL 零(其所有位都为0):

           0 0 0 0 0 0 0 0   ← AL
      AND  0 0 0 0 0 0 0 0   ← AL
      --------------------
           0 0 0 0 0 0 0 0   ← zero     (ZF is set to 1)
      
    • 的值AL为零(即其比特中的至少一个是1):

           0 0 1 0 0 0 0 0   ← AL
      AND  0 0 1 0 0 0 0 0   ← AL
      --------------------
         0 0 1 0 0 0 0 0     ← nonzero  (ZF is reset to 0)
      

      为什么(按位)AND,而不是TEST

      因为TEST指令做同样AND那样-的唯一的区别是逐位的结果AND操作对于TEST指令丢弃,所以只有零标志(ZF)被设定或复位。

您似乎认为 ZF 通常意味着操作数相等。这是错误的。显示操作数是否相等不是 ZF 的属性。相反,CMP如果操作数相等,则它设置零标志的属性此代码片段不执行CMP

相反,此代码片段执行TEST,其工作方式不同。在第一个和第二个操作数中都没有设置位的情况下,它完全表示 ZF。因此,如果 AL 非零,TEST AL,AL则会发现在第一个和第二个操作数中都设置了某些位(所有在 AL 中设置的位),并清除 ZF。另一方面,如果 AL 为零,则 AL 中没有位被设置,因此在第一个或第二个操作数中都没有设置位,ZF 将被设置。

可以使用TEST,AND以相同的效果执行零测试OR,其中两个操作数是相同的寄存器。您将在实际代码中找到所有三个变体来测试寄存器是否为零。

让我们以相反的顺序进入重要说明

  1. JNZ ...

    如果不是零则跳转。你想跳过(跳过“坏男孩”),即你想在这个(上一个)指令中获得“非零”:

  2. TEST AL,AL

    要获得“非零”,AL 中的值也必须是“非零”。
    AL 的值在此(上一条)指令中设置:

  3. CALL ...

    该指令调用一个函数,该函数用其返回值填充 EAX 寄存器(与调用约定一致)。AL 寄存器是 EAX 的一部分:

    在此处输入图片说明

    所以你想从这个函数返回一些“非零”,但它顽固地返回 0(意思是“未注册”)。


你有一些自然的可能性来达到你想要的行为(跳过“坏男孩”),但首先我提醒原始指令的顺序:

CALL ...
TEST AL,AL
JNZ ...
  1. JNZ ...JMP ...替换指令 JZ ...
  2. TEST AL,AL指令替换为这样指令,指令可为您提供“非零”结果。
  3. CALL ...指令替换为用“非零”填充 AL 寄存器指令。
  4. 深入了解CALL ...指令中的函数并将其更改为返回“非零”值。