第五章-数学指令

ollydbg

使用OllyDbg从零开始Cracking
第五章 – 数学指令
(翻译:安于此生)

 

INC和DEC

这两个指令分别是执行增加和减少的操作,如果是INC指令的话,就加1,如果是DEC指令的话,就减1。
我们跟之前一样用OD打开cruehead的CrackMe。
ollydbg-182
EAX在我的机器上面初始值是0,如果你的机器上面不是0的话,你可以手动修改。
ollydbg-183
然后按下F7键,执行INC EAX指令,EAX就会递增1。
ollydbg-184
同样的,我们可以使用DEC指令替换掉下面的指令。
ollydbg-185
按F7键,执行指令DEC EAX,EAX将会由1变成0。
ollydbg-186
也可以增加或者减少内存单元中的值。
ollydbg-187
上面的内存单元并不会增加1,而是引发异常,因为该内存地址我们不具有写权限。
ollydbg-188
如果这里有写权限的话,结果会是怎么样的呢?我们去数据窗口查看405000地址。
ollydbg-189
反过来读取,就会是00001000,增加1的话,就变成00001001。
ollydbg-190
这是给DWORD这个4字节的值增加1的情况。
对于WORD来说增加1到最后两个字节中。
ollydbg-191
对于BYTE来说增加1到最后一个字节。
ollydbg-192

 

ADD

ADD指令有两个操作数,相加后的结果存放到第一个操作数中。ADD EAX,1等价于INC EAX。 ADD也将两个寄存器相加,我们可以到OD里面看一看。
ollydbg-193
执行该语句之前:
ollydbg-194
在我的机器上EAX的值是00000000,ECX的值是12FFB0。你的机器上可以是其他的值,你可以自己修改它们,当你按下F7键,这两个寄存器相加,结果存放到EAX中,一起来看看。
ollydbg-195
由于EAX被修改了,所以变成了红色,相加的结果保存在其中。
也可以将寄存器与内存单元的内容相加。
ollydbg-196
在这种情况下,是否对该内存地址具有写权限都没有问题,因为相加的结果是存放到EAX寄存器中的,[405000]内存单元的值并没有改变。因为并不会引发异常。
按下F7键之前,EAX的值为0,405000内存单元中的值为00001000。
ollydbg-197
ollydbg-198
按F7键,计算它们的和。
ollydbg-199
EAX的初始值是0,现在变成了1000。如果你想把结果存放到内存单元中,我们可以这么写:
ollydbg-200
在这种情况下,结果存放到405000内存单元中,按下F7键,由于我们对该内存单元没有写权限,当尝试修改该内存单元的值时候,发引发异常。
ollydbg-201

 

ADC(带进位的加法)

在这种情况下,两个操作数的和加上进位标志的值,结果存放到第一个操作数中。
ollydbg-202
ollydbg-203
这里我们可以看到,EDX的值为21,加上3,已经进位标志,在这里,进位标志为0,按下F7键。
ollydbg-204
看到结果为24。现在双击你的鼠标将进位标志修改为1,然后重复上面的操作。
ollydbg-205
我们通过修改进位标志,然后重新执行这条指令。
ollydbg-206
按F7键,看,结果是25。
ollydbg-207
由于EDX的值为21,然后一个数值3,然后进位标志1,所以结果为25。

 

SUB

这个指令与ADD刚好相反-它将第一个操作数减去第二个操作数的值存放到第一个操作数中。
ollydbg-208
在我的机器上,执行这条指令之前,寄存器的情况如下:
ollydbg-209
按下F7键,EAX的0减去2。
ollydbg-210
16进制的结果为FFFFFFFE,在这个值上面双击鼠标,你可以看到十进制的值为-2。
ollydbg-211
我们可以看到十进制为-2。
另外也可以使用该指令来计算寄存器的值来寄存器的值,寄存器的值减去内存单元的值。
SUB EAX, ECX
即EAX-ECX的值保存到EAX中。

SUB EAX,DWORD PTR DS:[405000]
寄存器EAX减去405000内存单元的值,并将结果保存在EAX中。
SUB DWORD PTR DS:[405000],EAX
这种情况下,由于我们对405000这个内存单元没有写权限,将结果存放到其中的话,会引发一个异常。

 

SBB

该指令跟ADC正好相反,它计算两个操作数的差值,并且还要减去进位标志,结果存放到第一个操作数中。
ollydbg-212
执行该指令之前,EDX的值为21,进位标志为0。
ollydbg-213
按下F7键,EDX减去3,然后减去进位标志0。
ollydbg-214
现在,将进位标志修改为1,然后重复上面的操作。
ollydbg-215
按下F7键,EDX减去3,然后减去进位标志1。
ollydbg-216
这种情况,结果为1D。

 

MUL(无符号数的乘法)

有两种乘法,第一个种是MUL,这种是无符号数乘法,只有一个操作数,另一个操作数是EAX,结果存放到EDX:EAX中。
例如:
MUL ECX
这里是无符号数EAX,ECX相乘,结果存放到EDX:EAX中。
OD中来看下面的例子:
ollydbg-217
ollydbg-218
我将EAX设置为了FFFFFFF7,ECX设置为了9,使用Windows自带的计算器计算的结果如下:
ollydbg-219
ollydbg-220
结果为:
ollydbg-221
EAX的值不变,按下F7键,在OD中我们来看看会发生什么。
ollydbg-222
由于EDX和EAX的值改变了,所以以红色突出显示,而且,我们可以看到,一部分保存在EAX中,另一部分保存在EDX中,EAX容纳不下高位的8,所以存放到EDX中了,所以我们说结果存放到EDX:EAX中,也就是说,大小是单个寄存器的两倍。
下面的情况:
MUL DWORD PTR DS:[405000]
两个无符号数,405000内存单元中的值乘以EAX,结果跟之前的一样,存放到EDX:EAX中。
要在OD中查看一个数字的无符号16进制值的话,可以在任意通用寄存器上面双击鼠标左键。
ollydbg-223
第二行可以看到有符号数的值(有符号值为-81),但是MUL这样的指令,操作数都是无符号的。第三行包含了无符号的十进制值。我们可以看到是4294967215,是一个无符号数。

 

IMUL(有符号数的乘法)

IMUL指令用法类似于MUL。
IMUL ECX
该指令将有有符号数ECX乘以EAX,结果存放到EDX:EAX中。
除了上面一条指令外,IMUL还允许使用多个操作数,这是与MUL不同的地方。
补充:
尽管在默认情况下是使用EAX和EDX寄存器,但是我们还可以指定其他的数据源以及目标多达三个操作数。第一个操作数,用来乘以两个数,并且保存相乘的结果,结果必须保存在寄存器中。下面我们将看到两个和三个操作数的例子。
F7EB IMUL EBX EAX x EBX -> EDX:EAX
这是第一个例子,类似于MUL,但是是有符号的乘法。
696E74020080FF IMUL EBP, DWORD PTR [ESI+74],FF800002 [ESI+74] x FF800002 -> EBP
这是第二个例子,其中有三个操作数: ESI+74内存单元的值乘以FF800002,并且将结果存储到EBP中。我们可以在OD中执行看看。
把IMUL EBP, DWORD PTR [ESI+74], FF800002拷贝到OD中。
ollydbg-224
当我们按下Assemble按钮的时候会提示错误,因为在OD中,数字开头不能为字符,我们可以在开头添加0来解决这个问题。
ollydbg-225
现在按下Assemble按钮就不会提示错误了。
ollydbg-226
为了确保能够读取ESI+74这个地址的值,我们将ESI的值修改为401000。
ollydbg-227
见注释:
ollydbg-228
这里表示ESI+74的值为401074,该内存单元中的值为C7000000。在数据窗口中查看一下。
ollydbg-229
这里,ESP+74是指向401074这个地址,里面存放的值为C7000000。乘以FF800002,结果存放到EBP中。
IMUL EBP, DWORD PTR [ESI+74], FF800002
按下F7键,可以看到EBP变成红色了,相乘的结果存放在其中。
ollydbg-230
在计算器中我们计算C7000000*FF800002的结果如下:
ollydbg-231
由于EBP容纳不下结果,所以只能保存能够容纳的部分,其余的部分丢弃。
第三个例子,只有两个操作数,两者相乘,并将结果存放到第一个操作数中。
0FAF55E8 IMUL EDX, DWORD PTR [EBP-18] EDX x [EBP-18] -> EDX
正如你所看到的,这些方法中,最好的方式就是一个操作数的方式,结果存放到EDX:EAX中,这意味着拥有两倍的大小,通过两个操作数或者三个操作数无法完成的操作可以通过一个操作数的方式来完成。

 

DIV(无符号除法)/IDIV(有符号除法)

这两个指令反别与MUL和IMUL相反。
DIV只有一个操作数,该操作数必须是无符号数,结果存放到EDX:EAX中。
IDIV指令经常被使用。如果是一个操作数的话,那么它和DIV类似,只不过操作数是有符号的,结果依然保存在EDX:EAX中。两个操作数的情况,第一个操作数除以第二个操作数,结果存放到第一个操作数中。三个操作数的情况,第二个操作数除以第三个操作数,结果存放到第一个操作数中。
由于跟MUL和IMUL类似,这里就不提供例子了。

 

XADD(交换并相加)

正如你所猜想的一样,这个指令其实就是XCHG和ADD两个简单指令的组合。
XADD EAX,ECX
ollydbg-232
ollydbg-233
我们可以看到ECX的值为1,EAX的值为9。按F7键,它们交换数值。也就是,EAX的值变为了1,ECX的值变为了9,然后相加。
ollydbg-234
可以看出,相加的结果是存放到第一个操作数中的。ECX的值现在为9,这是执行这条指令之前EAX的值。

 

NEG

该指令的目的是将操作数的符号取反,即如果我们有一个32位的16进制数,用NEG操作以后,结果就会取反。
例如:
ollydbg-235
在OD中写入NEG EAX指令,并将EAX的值改为32。
ollydbg-236
按下F7键后,将会得到一个-32。一起来看看:
ollydbg-237
在第二行中,我们看到的结果是十进制的-50(对应的十六进制的-32)。
ollydbg-238
如果你再命令栏中输入?-32,就可以得到其十进制的值。这个值就是-50,还有16进制的值FFFFFFCE。
所以NEG指令是将操作数符号取反。

 

逻辑指令

逻辑指令有两个操作数,两操作数按位运算,并将结果存放到第一个操作数中。

 

AND

只有两个二进制位都为1的时候结果才为1,其他情况,结果都为0。
1 and 1 = 1
1 and 0 = 0
0 and 1 = 0
0 and 0 = 0
让我们来看看OD中的例子:
AND ECX,EAX
ollydbg-239
将ECX设置为0001200,EAX设置为3500。
ollydbg-240
手工计算的话,我们需要将两个数字转化为二进制:
1200二进制为01001000000000
3500二进制为11010100000000
我们将两数二进制按位与,例如:最后一位数字:
ollydbg-241
两个0取0。对每一位重复此过程,当两位都为1的时候才取1,这两个数中只有一次,两位都是1的情况。
ollydbg-242
按下F7键,我们将看到ECX的值为1000。相当于二进制的01000000000000。
ollydbg-243

 

OR

该指令AND的不同之处在于,两位中只要有一位为1,结果就取1。
1 or 1 = 1
1 or 0 = 1
0 or 1 = 1
0 or 0 = 0

 

XOR

该指令时异或运算,当两位不同时取1,相同时取0。
1 xor 1 = 0
1 xor 0 = 1
0 xor 1 = 1
0 xor 0 = 0

 

NOT

该指令是简单的按位取反。
not 1 = 0
not 0 = 1
例如:not 0110 = 1001
例如:EAX=1200,其二进制位1001000000000,我们将其填充为32位,不足的时候补0。
00000000000000000001001000000000
NOT后得到:
11111111111111111110110111111111
在windows自带的计算器中十六进制显示为FFFFEDFF。
ollydbg-244
将EAX设置为1200。
ollydbg-245
按F7键。
ollydbg-246
可以看到与计算器中的结果是一直的。
这里我们第5章就结束了,下一章我们将介绍比较,跳转,函数调用,以及函数返回指令。

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注