MOVSX (带符号扩展的传送指令)
第二个操作数可能一个寄存器也可能是内存单元,第一个操作数的位数比第二个操作数多,第二个操作数的符号位填充第一个操作数剩余部分。 下面是一个例子。 这里我们还是在OD中载入CrueHead'а的CrackMe。
这里我不会说太多,因为我想在座各位自己来计算这个操作数求值,嘿嘿。 在OD中,反汇编窗口和数据窗口中间有一个解释窗口。
这里我们可以看到,解释窗口向我们展示了我们操作数里面存放的值。我这里,BX存放的是F000。
同时可以看到,EAX的值为0,所以这些东西总是可以帮助我们理解OD要执行的指令(我希望你已经掌握了其中的概念和寻址方式,嘿嘿)。 按F7键。
16
看到AX,BX中存放的是F000,并且EAX剩余部分填充为了FFFF,因为F000是一个负的16位数字。如果BX存放1234,EAX将等于00001234,即左边的字节将会被0填充,因为1234是一个正的16位数字。
16位数和32位数的正数和负数的概念是一样的,只不过16位数的范围是0000到FFFF。0000到7FFF是正数,8000到FFFF是负数。
如果我们把BX修改为7FFF,把EAX修改为0,然后执行这条指令会发生什么呢。
AX被赋值为了7FFF,其余部分被填充为0了-因为7FFF是正数。我们还可以把BX修改为8000(负)。
按F7键。
17
AX被赋值为了8000,剩余的部分为FFFF,因为8000是负数。 MOVZX (带0扩展的传送指令)
MOVZX类似于前面的语句,但是这种情况下,剩余的部分不根据第二个操作数的正负来进行填充。我们这里不提供范例,因为和上面是相似的,剩余的部分总是被填充为0。 LEA (取地址指令)
类似于MOV指令, 但是第一个操作数是一个通用寄存器,并且第二个操作数是一个内存单元。当计算的时候要依赖于之前的结果的话,那么这个指令就非常有用。 我们在OD中写入以下指令:
在这种情况下,有括号,但不需要获取ECX+38指向内存的值,只需要计算ECX+38的值即可。我这里,ECX的值为 12FFB0。
在这个例子中,LEA指令就计算ECX + 38的值,然后将计算的结果赋值给EAX。 解释窗口中显示了两个操作数。
它表示,该操作数是12FFE8,也就是ECX+38的值,并且EAX的值为0。 按F7键。
18
指定的地址被存放到了EAX中,因为完成的是赋值操作,所以我们会认为操作数是内存单元中的值,但是实际上
操作数仅仅是内存单元的地址,而不是里面的内容。 XCHG (交换 寄存器/内存单元 和 寄存器) 该指令交换两个操作数的值,例如: XCHG EAX,ECX
EAX的值将被存放到ECX中。反之亦然。我们在OD中来验证这一点。
在我的机器上,EAX的值为0,ECX的值为12FFB0。
按F7键,看到他们交换了数值。
19
你也可以使用这个指令来交换寄存器和内存单元的值,本节之前有提到。
按下F7键:
这个例子我们在MOV指令使用过,这里我们对该内存地址没有写权限。
好了,这就是常用指令的第一部分,是非常有用的以及有趣的,我给出的例子能够体现这一点。在接下来的部分,我们将继续研究指令。
第5章-数学指令 INC和DEC
这两个指令分别是执行增加和减少的操作,如果是INC指令的话,就加1,如果是DEC指令的话,就减1。
我们跟之前一样用OD打开cruehead的CrackMe。
EAX在我的机器上面初始值是0,如果你的机器上面不是0的话,你可以手动修改。
然后按下F7键,执行INC EAX指令,EAX就会递增1。
同样的,我们可以使用DEC指令替换掉下面的指令。
20