一丶简介

上一篇博客说的除2的幂. 如果被除数是有符号的,那么会进行调整,并使用位操作进行优化

本片博客专门讲解除数不是2的幂

二丶代码还原讲解

1.被除数无符号 除数非2的幂

高级代码:

Release汇编

.text:0040101A                 mov     eax, 38E38E39h
.text:00401023 mul [esp+10h+var_8]
.text:00401027 shr edx, 1

除数怎么还原

代码定式:

.text:0040101A                 mov     eax, M
.text:00401023 mul x 此指令等价于 mul x,M
.text:00401027 shr edx, N

还原公式 : (2^(32 +n)) / M = 2^n / M 最后结果向上取整.

代入公式:

2^33 / 38E38E39

= 8589934592 / 954437177

= 8.9999999989522621036795594143123

= 向上取整(8.999...)

= 9

得出被除数是9

原理:

如果不感兴趣可不看,或者你有<<C++ 与反汇编与逆向分析揭秘>>这本书,可以观看第67页.

原理分析:

首先那么大数是怎么来了.

由于除法指令周期比乘法指令周期长.所以编译器会使用较短的乘法指令来代替除法.

数学证明公式:

设被除数为 x 除数为o

则有下面公式:



其实上图所说就是一个除法 转化成分子乘法的转变.

如下:

5/2 == 5 * ½  ==> 5 * (2N/2 * 2N)  ==  5 * (2n/2) * (1/2n);
其实 2n/2 (2分之2n) 是在编译器的时候进行计算的。也就是说可以的出来的。

设 (2n/2) == m

那么 5 * M * (1/2n)

继续简化既可以得出 (5*m) / 2n == 结果

那么根据反汇编也明白了。

.text:0040101A                 mov     eax, 38E38E39h              编译器计算出的(2n/2)
.text:00401023 mul [esp+10h+var_8] 这句代码的意思 = x * (2n/2)
.text:00401027 shr edx, 1 这句代码的意思是 结果 /2n 2n此时的取值是33 因为 edx,eax 直接操作的edx的一位等价于操作 2^1 + 2^32次方

根据上面的公式

eax = 2N/o (o)为常量。

mul == x * (2n/0)

shr edx,1 == x * (2n/o) / 2n

此时 2n我们可以知道是 2^33次方。

带入公式得到

x * (2^33/o) / 2^33

求o

2n / 2^33/o == 最终的常量就可以求出来了。

带入公式得到 2^33 / 38E38E39h ≈ 8.99999999 结果向上取整就是9

最终的结果就是

x / 9

公式如下

所以还原的时候。 首先确定 38E38E39h 他其实是除法演变成乘法的一个产物。

而后统计n。 n就是 右移的次数。 我们这里看到的是 2^33次方。

带入公式解方程

o = 2^n / M

M = 2N/o

2.被除数无符号 除数为特例7

高级代码:

int main(int argc, char* argv[])
{
unsigned int nValue = 16;
scanf("%d",&nValue);// 防止优化.核心代码不是这个 int nTemp = nValue / 7; //核心代码 一会观看反汇编 scanf("%d",&nTemp); //防止优化
return 0;
}

Debug下的汇编

.text:00401040                 mov     eax, [ebp+var_4]
.text:00401043 xor edx, edx
.text:00401045 mov ecx, 7
.text:0040104A div ecx
.text:0040104C mov [ebp+var_8], eax

Debug下的汇编很简单. 获取被除数,因为被除数是无符号.所以edx为0.所以会使用指令 xor edx,edx

进行清零. 这条语句也可以是 cdq.因为是无符号.所以使用cdq符号扩展那么edx也是0.可能xor指令周期

比xor周期长.所以没有使用. 虽然Debug不进行有效优化. 注意不进行有效优化是方便我们调试.但是也会

进行优化.当然不会影响你的调试. 比如 xor 也可以是cdq

如下:

.text:00401040                 mov     eax, [ebp+var_4]
.text:00401043 cdq
.text:00401045 mov ecx, 7
.text:0040104A div ecx eax = eax / ecx 等价于 eax = eax / 7;
.text:0040104C mov [ebp+var_8], eax

Debug下直接进行还原即可.很简单.

Release下的汇编

.text:0040101A                 mov     ecx, [esp+10h+var_8]
.text:0040101E mov eax, 24924925h
.text:00401023 mul ecx
.text:00401025 sub ecx, edx
.text:00401027 shr ecx, 1
.text:00401029 add ecx, edx
.text:0040102B shr ecx, 2
.text:0040102E mov [esp+10h+var_4], ecx

Release下的汇编就比较烦了.为什么指令是这样. 有一个超大的数, 还有各种乘法, 减法. 移位 加法.

其实这都是有数学原理进行支撑了.而且这个还是个特例.如果不想知道数学原理.直接记住汇编顺序

**乘 减 移 加 移. 也算是特征. 正好对应 mul sub shr add shr **

还原方法:

还原的时候我们可以设置未知数.这样直接给一个公式进行还原

如下:

.text:0040101A                 mov     ecx, [esp+10h+var_8]
.text:0040101E mov eax, M 设最大数为M
.text:00401023 mul ecx
.text:00401025 sub ecx, edx
.text:00401027 shr ecx, N 设移位为N
.text:00401029 add ecx, edx
.text:0040102B shr ecx, N 设置移位为N
.text:0040102E mov [esp+10h+var_4], ecx

还原方法: 2N/(232+M)的商向上取整

可以带入公式:

M = 24924925h 十进制 = 613566757

n 有两个,一个是1 一个是2 两个n相加就是3, 因为使用edx.没有使用eax 除法会使用 eax,edx. 所以使用edx变相的相当于以及有了2^32次方了.

代入公式:

2^35 / (2 ^32 + M)

= 34359738368 / (4294967296 + 613566757)

= 34359738368 / 4908534053

= 6.9999999993888195604619552997935

= 商向上取整 (6.9999999993888195604619552997935)

= 7

所以得出了除数为7

代码还原的时候直接还原成 Var_8 / 7 即可.如果想看原理,且向下看.

三丶代码还原总结

学习了新的两种定式:

第一种,被除数为正数, 除数为正数. MUL是无符号,所以不需要进行调整.直接套用公式还原

.text:0040101A                 mov     eax, M
.text:00401023 mul x 此指令等价于 mul x,M
.text:00401027 shr edx, N

还原公式 : (2^(32 +n)) / M = 2^n / M 最后结果向上取整.

第二种 被除数为正数 除数是特例

特征: 汇编中出现 乘 减 移 加 移

.text:0040101A                 mov     ecx, [esp+10h+var_8]
.text:0040101E mov eax, M 设最大数为M
.text:00401023 mul ecx ecx = ecx * M
.text:00401025 sub ecx, edx
.text:00401027 shr ecx, N 设移位为N
.text:00401029 add ecx, edx
.text:0040102B shr ecx, N 设置移位为N
.text:0040102E mov [esp+10h+var_4], ecx

还原方法: 2^(32 + N)/(2^32+M)的商向上取整

简化公式: 2^N / (2^32 + M) 一定注意隐藏的N大于32.

PC逆向之代码还原技术,第六讲汇编中除法代码还原以及原理第二讲,被除数是正数 除数非2的幂的更多相关文章

  1. PC逆向之代码还原技术,第四讲汇编中减法的代码还原

    目录 PC逆向之代码还原技术,第四讲汇编中减法的代码还原 一丶汇编简介 二丶高级代码对应汇编观看. 1.代码还原解析: 三丶根据高级代码IDA反汇编的完整代码 四丶知识总结 PC逆向之代码还原技术,第 ...

  2. PC逆向之代码还原技术,第三讲汇编中加法的代码还原

    目录 PC逆向之代码还原技术,第三讲汇编中加法的代码还原 一丶汇编简介 二丶高级代码对应汇编观看. 1.代码还原解析: 总结 PC逆向之代码还原技术,第三讲汇编中加法的代码还原 一丶汇编简介 在讲解加 ...

  3. 第16讲——C++中的代码重用

    C++的一个主要目标是促进代码重用.除了我们之前学的公有继承,我们在这一讲将介绍另一种代码重用的方法——类模板.

  4. XGBoost中参数调整的完整指南(包含Python中的代码)

    (搬运)XGBoost中参数调整的完整指南(包含Python中的代码) AARSHAY JAIN, 2016年3月1日     介绍 如果事情不适合预测建模,请使用XGboost.XGBoost算法已 ...

  5. 捕捉WPF应用程序中XAML代码解析异常

    原文:捕捉WPF应用程序中XAML代码解析异常 由于WPF应用程序中XAML代码在很多时候是运行时加载处理的.比如DynamicResource,但是在编译或者运行的过程中,编写的XAML代码很可能有 ...

  6. Spring官网阅读(十六)Spring中的数据绑定

    文章目录 DataBinder UML类图 使用示例 源码分析 bind方法 doBind方法 applyPropertyValues方法 获取一个属性访问器 通过属性访问器直接set属性值 1.se ...

  7. PC逆向之代码还原技术,第五讲汇编中乘法的代码还原

    目录 PC逆向之代码还原技术,第五讲汇编中乘法的代码还原 一丶简介乘法指令 1.乘法指令 2.代码还原注意问题 二丶乘法的汇编代码产生的格式 1.高级代码观看 2.乘法的汇编代码还原. 三丶乘法总结 ...

  8. PC逆向之代码还原技术,第二讲寻找程序入口点

    PC逆向之代码还原技术,第二讲寻找程序入口点 一丶简介 程序逆向的时候.我们需要知道程序入口点.动态分析的时候以便于看是什么程序编写的. 比如VC++6.0 我们可以写一个程序测试一下 我们写一段代码 ...

  9. PC逆向之代码还原技术,第一讲基本数据类型在内存中的表现形式.浮点,指针寻址公式

    目录 代码还原技术 一丶简介代码还原 二丶代码还原中的数据类型表现形式 1.整数类型 2.无符号整数 3.有符号整数 4.浮点数数据类型 5.浮点编码 4.Double类型解析. 三丶浮点汇编 1.浮 ...

随机推荐

  1. 如何删除github上的某个文件夹

    在github上只能删除仓库,却无法删除文件夹或文件, 所以只能通过命令来解决 首先进入你的master文件夹下, Git Bash Here ,打开命令窗口 $ git –help 帮助命令 $ g ...

  2. ORM框架之SQLAchemy

    SQLAchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,即:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果. 1.安装 ...

  3. mysql学习2

    1.视图 视图是一个虚拟表(非真实存在),其本质是[根据sql语句获取动态的数据集,并为其命名],用户使用时只需要使用[名称]即可获取结果集,并可以将其当作表来使用. 搜索临时表 SELECT * F ...

  4. RHEL系统初始化步骤

    1.配置网络 ##初始化网络(可在虚拟网络编辑器查看自己的网段) ##方法一:静态初始化 read -p "输入你当前Linux的IP地址:" ip ETH=` ifconfig ...

  5. 在浏览器输入URL时发生了什么

    浏览器器检查cache,如果请求对象已经缓存并且是最新的,执行第9步. 浏览器询问操作系统,请求服务器的IP地址 操作系统进行DNS查找,然后告诉浏览器服务器的IP 浏览器和服务器简历一个TCP连接( ...

  6. ubuntu下安装pandas出现 compile failed with error code 1 in /tmp/pip_build_hadoop/pandas

    都是用pip装的,是不是应该用apt-get 装的呀 ubuntu下安装pandas (出现 compile failed with error code 1 in /tmp/pip_build_ha ...

  7. go语言基础之range

    在go语言中,遍历数据或切片时可以用range,range会产生两个值,分别是数据的索引与值: package main import "fmt" func main() { x ...

  8. ucore代码分析

    lab2: 总共分为四个包一个文件,分别为: boot: 操作系统加载程序代码 kern: 操作系统内核代码 libs: 相关的库和数据结构 tools: 相关编译链接调试工具 Makefile: 构 ...

  9. C语言复习5_调试

    使用CodeBlocks调试程序 首先要注意,只有打开projects(.cbp文件)的情况下才能debug,单独打开.c文件是不能debug的 1.在行号旁边左键,出现红点,表示为断点breakpo ...

  10. Puppeteer 应用容器化

    Puppeteer 应用容器化 Intro Puppeteer是谷歌官方出品的一个通过DevTools协议控制headless Chrome的Node库.可以通过Puppeteer的提供的api直接控 ...