逆向课程第四讲逆向中的优化方式,除法原理,以及除法优化上

一丶为什么要熟悉除法的优化,以及除法原理

是这样的,在计算机中,除法运算对应的汇编指令分为 DIV(无符号除法指令) 以及 IDIV(有符号除法指令).

但是,除法指令的执行周期较长效率很低.所以编译器想进办法的用其它指令去代替除法指令.

比如:

DIV 指令是100个周期

计算 2 / 2

那么可能在汇编中的表现形式是这样的

CDQ  符号扩展

DIV EDX,2

好,现在100个周期没有了

减法和加法指令,指令周期是4个那么上面的公式可以演化为

mov eax,2

sub eax,2

就算mov 指令是10个指令,那么总共计算起来才14个指令,而正好完成了一个除法

如果我们把指令周期看做时间的话,那么100个指令周期是100秒,14个指令周期是14秒

那么是不是时间变快了,那么相应的软件运行速度以及启动速度也变快了.

二丶丶熟悉数学证明

在讲解除法之前,我们要熟悉一下数学公式,以及数学证明,因为在除法的优化中,和这些数学公式息息相关.

当然你不看证明也可以,但是公式一定要明白

这里我讲解的是  <<C++反汇编与逆向分析技术揭秘>>  作者: 钱林松 赵海旭

伟大的钱老师的著作. 第47页

首先我们要明白计算机中的除法

1.有符号树和无符号数混除,那么结果是无符号的

2.两个无符号整数相除,结果还是无符号的.

3.计算机中面临如何处理小数,比如 9 / 4 = 2.25

理解数学中的向下取整,以及向上取整

向下取整

讲道理:  比如对x向下取整,  x>=0  那么就是 取得不大于x的最大整数,  相反也就是说, 小于x的遇到的第一个整数

比如 x = 5

那么向下取整则是4

不大于5,那么就是小于5, 然后遇到的最大整数,也就是4

向上取整:

同理,向上取整则是  不小于x的最大整数.

除法的扩展知识:

  在整数的处罚中,只有能整除和不能整除的两种情况(废话)不能整除,则会产生余数.

设 a = 被除数  b = 除数   c = 商  r = 余数

那么可以得到下面的公式:

除法原型:

  a / b = c .... r

6  / 4 = 1 ...2

1.  |r|  < |b|         : 余数的绝对值,绝对会小于除数的.  比如  6 / 4 = 1 .... 2  那么 余数2 不关是正数还是父数,绝对都是绝对会小于除数的,也就是4

2. a = c * b + r     : 求被除数,被除数是商*除数+余数

3.b  =  (a - r)/c     : 求除数,除数等于 被除数-余数 / 商

4.c = (a - r)/b    : 求商: 被除数 - 余数 / 除数

5. r = a - (c * b)          : 求余数 被除数 - (商 * 除数)

3.计算机中的除法

1.当除数为变量,的时候

计算机中.的汇编指令为  DIV 或者 IDIV,因为除数是不确定的

比如:

  int n ;

  7 / n    ===> 汇编指令就用DIV 或者IDIV

没有优化的余地,看汇编代码.

除数为有符号相除

除数为无符号

当除数为变量,且分为有符号和无符号相除

有符号相除: 那么使用的汇编指令是IDIV

无符号相除: 那么使用的汇编指令是DIV

2.当除数为2的幂的时候被除数分为有符号和无符号位的时候

比如代码为:

被除数无符号的情况下,除数是2的幂次方: (也就是n是无符号)

  n / 8 那么8是2^3次方

那么直接优化为 shr

左移三位

被除数有符号的情况下且大于0,除数是2的幂次方

看到汇编代码懵逼,那么上公式,证明,然后则明白

首先公式等于

当B (除数)大于0则使用上面的公式,当b < 0则使用下面的公式

比如计算机中,被除数为正数的时候,可以使用第一个公式的第一个,也可以使用第二个,不过计算机默认向0取整

比如我们计算 17 / 8

正常计算  17 / 8 = 2 .xxxx

有小数

不过计算机计算出来的结果则是2,省略小数了,那么计算机使用的则是第一个公式.

a / b 向下取整,  然后也可以 a - b + 1 / b 向上取整

我们实验一下,

代入得到

17 - 8 + 1 / 8 =

  10 / 8 = 1.25  转化为后面的公式,向上取整则是2了.

那么上面的汇编代码应该能看明白了.

首先 Cdq 是符号扩展的意思,也就是EDX和EAX一起使用,变成了一个64位寄存器.

然后利用and和edx比较7, 这个7怎么的出来了,这个7就是上面我们用第一个公式计算出来的

也就是  a - b + 1 这个, 这个7则是b + 1的值.

然后 add eax,edx   被除数 + 上 and过后的值.

最后右边移动三位.

这里编译器巧妙的利用 cdq符号扩展,然后利用了公式,进行了无分支判断.

如果我们的被除数是正数,那么 符号扩展之后,edx的值则全部是0,然后and过后,结果还是0

那么我们的被除数 + 0 右移3位  然后向下取整.

比如我们计算的  n / 8

n取值为17

那么计算的出  b + 1 的值为   8 + 1

那么是正数,则edx为0,and 9之后还是0

那么下面直接 add eax,edx

eax = 原来的被除数 也就是17

edx  结果and后为0

那么结果还是17

最后 17 右移动三位则是  2.xxx  向下取整就是2了.

如果是负数,那么b+1的值还是9

那么此时  add eax,edx  = -17 + b - 1 = -10

而后 -10 右移动3位  (-10 / 8) = 1.25 此时向上取整,结果还是-2

公式的话,主要看计算机,一般计算机整数相除,选择向下取整

负数相除,选择向上取整.

3.无符号是被除数的情况下除数为非2的幂的时候

比如高级语言

unsigned int a;

a / 3 那么汇编指令有不一样了

我们看下最后两个, /3 的,还有/ 0x87654321的

优化成了这样,还是没有看到除法

a /c  C为常量的时候 a(被除数)

那么可以得出公式 am >> n位  (具体的推导公式就不写了,反正都是记公式)

其中m = 2n / c   (n的取值范围看系统,如果是16位,那么n的起步就是16 ,32位则是32位起步)

那么现在

mov eax ,xxxxx     xxxx是m

mul  reg32

shr  edx,1fh          1fh是n

那么根据上面的公式  am >> n

现在已经知道n和m了

而 m = 2n / c

那么现在可以求C了

按照最后一个求得出  n = 1f  ,也就是2^1f + 2^32

为什么要加上2^32,因为 EDX和eax现在是一个64位寄存器,(看作是)符号扩展了,EDX移动一位,那么相当于eax 移动33位.

m = 0f2044d73

现在求C的值

反推即可

C = 2^n / m

转为十进制计算

9223372036854775808   /  4060368243 = 2271560480.4455111112443010011986

结果向上取整得出2271560481

转为16进制得出

顺利还原代码.

转载于:

作者:IBinary
出处:http://www.cnblogs.com/iBinary/

原文地址:https://www.cnblogs.com/gd-luojialin/p/11219746.html

时间: 2024-07-31 04:13:13

逆向课程第四讲逆向中的优化方式,除法原理,以及除法优化上的相关文章

逆向课程第五讲逆向中的优化方式,除法原理,以及除法优化下

一丶除法的优化 1.有符号被除数 / 无符号除数的情况下 高级代码为: 汇编中优化的体现形式 相比于昨天,我们发现了的 无符号 / 常量多出了点东西 无符号/常量 如果无符号/常量,那么我们还原的时候 套用公式即可 am >> n a是被除数  m是设  2n/c   等价于  m == 2n/c 无符号的情况的,n的值是2^33次方  ,n = 33 根据上面得知,  m = 0AAAAAAABh 此时求出C来即可,  C = 除数 公式: 2n / m = c 套进去得到 2^33次方 /

从0 开始 WPF MVVM 企业级框架实现与说明 ---- 第四讲 WPF中 ControlTemplate

上讲我们介绍了DataTemplate,现在我们就介绍下ControlTemplate,可能后面大多在编码时候会出现一些英文,工作习惯,请见谅. ControlTemplate: 控件的外观,也就是控件是什么样子 后面在我们这个项目中会大量用到这个东西, 现在我大概介绍一下你怎样去使用一个控件模板,首先你得定义一个控件模板,基本格式如下: <ControlTemplate x:Key="按钮控件模板名称"> 在这里就可以去定义你当前这个模板的具体样式,比如你定义一个按钮的样

开发人员应该对IIS理论层的知识了解的多一些~第四讲 HttpModel中的几大事件

返回目录 本文主要介绍HttpModule,它在一个网页请求过程中是一个怎样的过程是我们要知道的,在网页加载过程中HttpModule在何时被执行也是我们要知道的,以及,HttpModule在网页请求过程中,所被触发的各个事件也是我们要知道的,下面就带着问题来看文章吧 ASP.NET对请求处理的过程 当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给 ASPNET_ISAPI.dll(否则交给对应的应用程序去解释它)

逆向知识第十讲,循环在汇编中的表现形式,以及代码还原

一丶do While在汇编中的表现形式 1.1高级代码: #include "stdafx.h" int main(int argc, char* argv[]) { int nSum = 0; int i = 0; do { nSum = nSum + i; } while (i <=100); return 0; } 高级代码很简单,只是一个简单的求1~100的累加 1.2 Debug版本下的汇编表现形式 代码定式很简单 ADDR .....do While逻辑代码块 xxx

逆向课程第三讲逆向中的优化方式,以及加减乘

逆向课程第三讲逆向中的优化方式,以及加减乘 一丶为什么要熟悉优化方式 熟悉优化方式,可以在看高级代码的时候浮现出汇编代码,以及做逆向对抗的时候,了解汇编代码混淆 优化和混淆是相反的 优化: 指的是汇编代码越少越好,让程序更快的执行 混淆: 一条汇编代码变为多条汇编代码,影响逆向人员的破解能力,但是软件的效率大大降低 二丶加减乘的常见的几种优化方式 优化方式分为: 1.常量折叠 2.常量传播 3.变量去除 这些优化方式成为窥孔优化 (有10几种后面会一一到来) 首先了解什么是常量折叠,常量传播,然

逆向知识第九讲,switch case语句在汇编中表达的方式

一丶Switch Case语句在汇编中的第一种表达方式 (引导性跳转表) 第一种表达方式生成条件: case 个数偏少,那么汇编中将会生成引导性的跳转表,会做出 if else的情况(类似,但还是能分辨出来的) 1.高级代码: #include "stdafx.h" int main(int argc, char* argv[]) { switch(argc) { case 0: printf("case 0\n"); break; case 1: printf(&

逆向知识第八讲,if语句在汇编中表达的方式

一丶if else的最简单情况还原(无分支情况) 高级代码: #include "stdafx.h" int main(int argc, char* argv[]) { unsigned int nNumber = 0; scanf("%ud",&nNumber); if(argc == 0) { nNumber = 0; //第一种情况下无分支 } else { nNumber = -1; } return nNumber; } 总共两种情况,我们看下R

逆向知识第六讲,取摸优化的几种方式

逆向知识第六讲,取摸优化的几种方式 除法讲完之后,直接开始讲 % 运算符在汇编中表现形式 首先C的高级代码贴上来. 高级代码: // Tedy.cpp : Defines the entry point for the console application. // #include "stdafx.h" int main(int argc, char* argv[]) { unsigned Number; scanf("%d",&Number); //防止

机器学习中使用的神经网络第四讲笔记

Geoffery Hinton教授的Neuron Networks for Machine Learning的第四讲主要介绍如何使用back propagation算法来学习到词汇的特征表示. Learning to predict the next word 接下来的几小节主要介绍如何使用back propagation算法来学习到词汇的特征表示.我们从一个很简单的例子开始,介绍使用back propagation算法来将词汇间的相关信息转换成特征向量. 下图给出了一个家庭的树状图,我们要做的