欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[翻译]使用OllyDbg从零开始Cracking 第五章-数学指令

[翻译]使用OllyDbg从零开始Cracking 第五章-数学指令

刚刚更新了第5章,现在奉上...
现在才发现翻译挺费时间的,膜拜哪些之前为坛子翻译文章的弟兄呀,一坐就是一下午,连陪MM聊天的时间都贡献出来了...
                                               第5章-数学指令
INC和DEC
这两个指令分别是执行增加和减少的操作,如果是INC指令的话,就加1,如果是DEC指令的话,就减1。
我们跟之前一样用OD打开cruehead的CrackMe。

EAX在我的机器上面初始值是0,如果你的机器上面不是0的话,你可以手动修改。

然后按下F7键,执行INC EAX指令,EAX就会递增1。

同样的,我们可以使用DEC指令替换掉下面的指令。

按F7键,执行指令DEC EAX,EAX将会由1变成0。

也可以增加或者减少内存单元中的值。

上面的内存单元并不会增加1,而是引发异常,因为该内存地址我们不具有写权限。

如果这里有写权限的话,结果会是怎么样的呢?我们去数据窗口查看405000地址。

反过来读取,就会是00001000,增加1的话,就变成00001001。

这是给DWORD这个4字节的值增加1的情况。
对于WORD来说增加1到最后两个字节中。

对于BYTE来说增加1到最后一个字节。

ADD
ADD指令有两个操作数,相加后的结果存放到第一个操作数中。ADD EAX,1等价于INC EAX。ADD也将两个寄存器相加,我们可以到OD里面看一看。

执行该语句之前:

在我的机器上EAX的值是00000000,ECX的值是12FFB0。你的机器上可以是其他的值,你可以自己修改它们,当你按下F7键,这两个寄存器相加,结果存放到EAX中,一起来看看。

由于EAX被修改了,所以变成了红色,相加的结果保存在其中。
也可以将寄存器与内存单元的内容相加。

在这种情况下,是否对该内存地址具有写权限都没有问题,因为相加的结果是存放到EAX寄存器中的,[405000]内存单元的值并没有改变。因为并不会引发异常。
按下F7键之前,EAX的值为0,405000内存单元中的值为00001000。

按F7键,计算它们的和。

EAX的初始值是0,现在变成了1000。如果你想把结果存放到内存单元中,我们可以这么写:

在这种情况下,结果存放到405000内存单元中,按下F7键,由于我们对该内存单元没有写权限,当尝试修改该内存单元的值时候,发引发异常。

ADC(带进位的加法)
在这种情况下,两个操作数的和加上进位标志的值,结果存放到第一个操作数中。

这里我们可以看到,EDX的值为21,加上3,已经进位标志,在这里,进位标志为0,按下F7键。

看到结果为24。现在双击你的鼠标将进位标志修改为1,然后重复上面的操作。

我们通过修改进位标志,然后重新执行这条指令。

按F7键,看,结果是25。

由于EDX的值为21,然后一个数值3,然后进位标志1,所以结果为25。
SUB
这个指令与ADD刚好相反-它将第一个操作数减去第二个操作数的值存放到第一个操作数中。

在我的机器上,执行这条指令之前,寄存器的情况如下:

按下F7键,EAX的0减去2。

16进制的结果为FFFFFFFE,在这个值上面双击鼠标,你可以看到十进制的值为-2。

我们可以看到十进制为-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正好相反,它计算两个操作数的差值,并且还要减去进位标志,结果存放到第一个操作数中。

执行该指令之前,EDX的值为21,进位标志为0。

按下F7键,EDX减去3,然后减去进位标志0。

现在,将进位标志修改为1,然后重复上面的操作。

按下F7键,EDX减去3,然后减去进位标志1。

这种情况,结果为1D。
MUL(无符号数的乘法)
有两种乘法,第一个种是MUL,这种是无符号数乘法,只有一个操作数,另一个操作数是EAX,结果存放到EDX:EAX中。
例如:
MUL ECX
这里是无符号数EAX,ECX相乘,结果存放到EDX:EAX中。
OD中来看下面的例子:

我将EAX设置为了FFFFFFF7,ECX设置为了9,使用Windows自带的计算器计算的结果如下:

结果为:

EAX的值不变,按下F7键,在OD中我们来看看会发生什么。

由于EDX和EAX的值改变了,所以以红色突出显示,而且,我们可以看到,一部分保存在EAX中,另一部分保存在EDX中,EAX容纳不下高位的8,所以存放到EDX中了,所以我们说结果存放到EDX:EAX中,也就是说,大小是单个寄存器的两倍。
下面的情况:
MUL DWORD PTR DS:[405000]
两个无符号数,405000内存单元中的值乘以EAX,结果跟之前的一样,存放到EDX:EAX中。
要在OD中查看一个数字的无符号16进制值的话,可以在任意通用寄存器上面双击鼠标左键。

第二行可以看到有符号数的值(有符号值为-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中。

当我们按下Assemble按钮的时候会提示错误,因为在OD中,数字开头不能为字符,我们可以在开头添加0来解决这个问题。

现在按下Assemble按钮就不会提示错误了。

为了确保能够读取ESI+74这个地址的值,我们将ESI的值修改为401000。

见注释:

这里表示ESI+74的值为401074,该内存单元中的值为C7000000。在数据窗口中查看一下。

这里,ESP+74是指向401074这个地址,里面存放的值为C7000000。乘以FF800002,结果存放到EBP中。
IMUL EBP, DWORD PTR [ESI+74], FF800002
按下F7键,可以看到EBP变成红色了,相乘的结果存放在其中。

在计算器中我们计算C7000000*FF800002的结果如下:

由于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

我们可以看到ECX的值为1,EAX的值为9。按F7键,它们交换数值。也就是,EAX的值变为了1,ECX的值变为了9,然后相加。

可以看出,相加的结果是存放到第一个操作数中的。ECX的值现在为9,这是执行这条指令之前EAX的值。
NEG 
该指令的目的是将操作数的符号取反,即如果我们有一个32位的16进制数,用NEG操作以后,结果就会取反。
例如:

在OD中写入NEG EAX指令,并将EAX的值改为32。

按下F7键后,将会得到一个-32。一起来看看:

在第二行中,我们看到的结果是十进制的-50(对应的十六进制的-32)。

如果你再命令栏中输入?-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

将ECX设置为0001200,EAX设置为3500。

手工计算的话,我们需要将两个数字转化为二进制:
1200二进制为01001000000000 
3500二进制为11010100000000 
我们将两数二进制按位与,例如:最后一位数字:

两个0取0。对每一位重复此过程,当两位都为1的时候才取1,这两个数中只有一次,两位都是1的情况。

按下F7键,我们将看到ECX的值为1000。相当于二进制的01000000000000。

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。

将EAX设置为1200。

按F7键。

可以看到与计算器中的结果是一直的。
这里我们第5章就结束了,下一章我们将介绍比较,跳转,函数调用,以及函数返回指令。
WORD版的如下:需要的自行下载...,配套的附件和上一章的是一样的,这里就不重复提供了...
使用OllyDbg从零开始Cracking 第五章.doc

上传的附件 图片1.png
图片2.png
图片3.png
图片4.png
图片5.png
图片6.png
图片7.png
图片8.png
图片9.png
图片10.png
图片11.png
图片12.png
图片13.png
图片14.png
图片15.png
图片16.png
图片17.png
图片18.png
图片19.png
图片20.png
图片21.png
图片22.png
图片23.png
图片24.png
图片25.png
图片26.png
图片27.png
图片28.png
图片29.png
图片30.png
图片31.png
图片32.png
图片33.png
图片34.png
图片35.png
图片36.png
图片37.png
图片38.png
图片39.png
图片40.png
图片41.png
图片42.png
图片43.png
图片44.png
图片45.png
图片46.png
图片47.png
图片48.png
图片49.png
图片50.png
图片51.png
图片52.png
图片53.png
图片54.png
图片55.png
图片56.png
图片57.png
图片58.png
图片59.png
图片60.png
使用OllyDbg从零开始Cracking 第五章.doc

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功