首页
社区
课程
招聘
[原创]#30天写作挑战#反汇编代码还原之除数为非2的幂
发表于: 2020-9-9 17:13 18017

[原创]#30天写作挑战#反汇编代码还原之除数为非2的幂

2020-9-9 17:13
18017

反汇编技术之熟悉IDA工具
反汇编逆向技术之寻找Main入口点
反汇编代码还原之优化方式
反汇编代码还原之加减乘
反汇编代码还原之除法为2的幂

​ 除法在非2的幂优化上,采用的是除法转变为乘法 的形式. 在学习这方面知识的时候我们先了解下简单的数学知识

也有助于我们能看懂公式

分数加法

相同分母加法 分子想加 分母不变 例如下

image-20200907222151583

不同分母想加 如果是不同分母想加你就要进行寻找最小公分母

公分母指的是. 当两个或者以上的分数有相同的分母 那么他们便是公分母 注意这里是公分母.而不是最小公分母 最小公分母指的是两个分数以上,最小的公分母

最小公分母的寻找

最小公分母我们可以列出 分母的倍数 如果有两个分数那么都列出分母的倍数.找出相同的倍数.然后让其等价即可.

例如:

image-20200907222759951

列出3的倍数: 3 6 9 12 15 .....

列出6的倍数: 6 12 18 24 ....

我们发现最小公倍数都是6. 所以我们的分子分母都*2转为为相同分母然后进行想加即可

图片描述

分数乘法

如下:

image-20200907223401007

口诀: 乘分数 没难度 上乘上 下乘下 再约分

整数相乘

如果一个整数 * 一个分数.那么这个分数就可以看做是分子,而分母就是1

例子:

image-20200907223817069

至于约分.可以寻找最小公因数.跟公倍数相反.公倍数是找出相乘 公因数就是找出可以分子/分母的数. 都去除同一个数

汇编对应代码

​ 乍一看上面汇编代码.除法怎么变为了这样.为什么又有乘法又有除法.还有调整等. 那么这里就着重讲解一下.

如果想要直接还原.那么我们把代码定式提取出来 直接进行还原

代码定式

根据汇编我们只需要看三个点即可. 并且得出三个点的公式得原理

image-20200907225550924

其中M是编译器计算出来了. ecx是被除数. 这里sar n值.直接操作的是edx. 这里其实是除法转变为了乘法 而如果除法转变为乘法 那么在32位年代下.两个数相乘 32的值是不会放下的. 所以我们这里其实使用的是 edx,eax 来代表乘法的结果 然后我们直接操作了乘积的高位 这里右移1 等价于是 除以 image-20200907225444244

那么我们还原的时候直接记住死公式就可以. image-20200907225722139

直接统计n的取值. 然后用 2的32次方 + n即可. 因为乘积的低位时代表2^32次方.这里直接是对乘积高位做操作.所以我们需要加上低位的32次方的值

例子还原

我们套用公式

image-20200907230441538

2.99直接向上取整 = 3. 所以这里我们就寻得被除数为3

首先先看我们的汇编

这里我们汇编分为两部分.上边是可以直接套用公式还原. 而下方其实是获取符号位.调整一下符号位.

shr 逻辑右移. 最高位以0填充. 右移31(1F)位 取得符号位 然后这里有一个加法.其实这个加法也是套路.跟我们之前讲解的无分支优化差不多. 如果结果是正数. 那么 add edx,eax 就是加0 等于什么都不干. 如果是结果是负数 那么我们就需要除法的商做调整.做加1调整.

除法转化为乘法的原理

如果想要了解为什么非2的幂代码会变成上面的代码.那么我们就要理解下原理

设 a = 被除数 b = 除数(是一个常量值)

那么就会有以下公式

image-20200907231604161

这个就是我们上面所了解的分数相关知识.

看最后的公式

image-20200907231634994

其中 2n/b这个是可以在编译期中计算出来的. VC++6.0 或者VS2019 在编译 期间n的取值是大于32的.所以是可以算出来的.

所以我们的公式可以变为如下 在这里我们把编译器可以计算出来的值记做C. 那么可以得出以下公式

image-20200907232516529

最终简化为就是(a * c) >> n 而反过头来看我们的汇编代码

列出公式

ecx = 被除数

eax = M 等价于 2n/b的值.

ecx eax / 2^33 这条公式就正好对应着我们除法转变为乘法的原理 和我们上面的公式一样. (a c) >> n

所以我们解方程即可. 2^n / b = M值. 那么 2^n / M = b b就是我们的要求的除数. 所以得出我们的除数

除法还原公式为:

除法的还原公式

image-20200908202646241

这里的C其实就是2^n/b 在汇编中我们也设为M.所以也可以写为如下

image-20200908202210911

除法转变为乘法的公式

image-20200908214030412

转变为如下

image-20200908214044445

继续转变

image-20200908202244082

最终转变

image-20200908214109643

对于上面我们记住代码定式也可以进行还原.当然熟悉除法转变为乘法的原理更好.

高级代码看其特征我们发现其实是一样的. 都可以使用 除法转乘法的公式来进行还原

除法还原公式其实就是解方程了.解开就可以得到被除数

高级代码

汇编代码

看如上代码.根据除法转为乘法公式 (a * b) >> n .我们可以求出

2^n / b = M 2^n/M = b(除数常量)

这里只不过是换成了无符号而已.

还原公式还是同上

如:

取N 值 = 1 取M值 = 2863311531(注意这里IDA我按了下H转为10进制来查看.这样方便我们用科学计算器来进行运算)

操作的是edx.所以

高级代码如下

核心代码反汇编 代码段

代码定式

根据上面反汇编代码.我们看到三个地方 有我们的 疑似 (a * c) >> n的代码

也就是除法转变为乘法的公式

我们随便取出一处代入公式进行还原

设 M = 40000001h =10进制的 1073741825

设 n = 1E = 10进制的 30

那么代入我们的还原公式为:

image-20200908201737556

以计算器的科学计算计算出的数值是4294967292(10进制)

那么我们将这个数复制到以程序员计算的计算器中.(复制到Dec 10进制输入) 可以看到是一个负数

image-20200908202004903

注意输入的时候以QWORD输入.然后再点击一下变成DWORD则可以看到表达为-4

image-20200908202047783

此时直接对其NOT取反则可以得到原始的被除数. 但是这个被除数常量是负数

image-20200908202120166

你也可以让此值做+1调整 变为4294967293 那么就得出了数直接就是-3 可以很明确的知道我们的被除数是-3

看到上面有一段代码.我们特别不理解 为什么/-6汇编变了

这些后面有专题转么讲解特殊的怎么还原

现在可以看一下我算的

2^64 / 4,294,967,302 = 0x100000006 最高位为符号位 代表这是个负数也就是-6

如果根据定式还原得出的结果为 0xFFFFFFF9 然后对其取反得到6

但是也有代码定式

观看代码定式可以得出

乘减移加移

这种先使用定式还原

image-20200908205529875

这里取出两个n值. 1+31 = 32所以n值为32

代入公式得

2^64 / 4,294,967,303 = 0XFFFFFFF9

关于特殊汇编在下一篇应该会详细讲解.

​ 还是那句话为什么学习除法优化. 好就以我们上面的例子为例.那么使用IDA F5查看

image-20200908205952566

请问看到这种代码你怕了吗. 直接反汇编可以得出这一段代码我是干啥.用IDA反汇编就会得出 右移等等.在我们看来就是硬汇编


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-9-12 09:19 被TkBinary编辑 ,原因: 修复公式截图错误
收藏
免费 24
支持
分享
最新回复 (13)
雪    币: 1768
活跃值: (239)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
火钳刘明
2020-9-9 17:21
0
雪    币: 10
活跃值: (84)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
收藏
2020-9-9 17:28
0
雪    币: 950
活跃值: (9946)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
4
大头哥 收藏
谢谢,要观看
2020-9-9 17:30
0
雪    币: 23081
活跃值: (3447)
能力值: (RANK:648 )
在线值:
发帖
回帖
粉丝
5

别光收藏呀,要回帖、点赞,三连走起!

最后于 2020-9-9 18:06 被KevinsBobo编辑 ,原因:
2020-9-9 17:53
0
雪    币: 232
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
支持~
2020-9-9 18:17
0
雪    币: 3785
活跃值: (3947)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
感谢分享!
2020-9-11 17:57
0
雪    币: 3797
活跃值: (769)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8

老哥这里是打错字了吧, 不应该是1F吗?

乘法的结果 然后我们直接操作了乘积的高位 这里右移1 等价于是 除以 image-20200907225444244

2021-3-29 17:20
0
雪    币: 950
活跃值: (9946)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
9
gaoan 老哥这里是打错字了吧, 不应该是1F吗?乘法的结果 然后我们直接操作了乘积的高位 这里右移1 等价于是 除以 
1F是调整符号位.代表是有符号除法. sar edx 是操作的 edx,eax eax = 2^32次方. 而这里对edx操作了1 那么就是 操作了2^33次方.  欢迎继续提出问题. 
2021-3-29 17:56
0
雪    币: 229
活跃值: (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
支持~
2021-3-29 18:05
0
雪    币: 3797
活跃值: (769)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
TkBinary 1F是调整符号位.代表是有符号除法. sar edx 是操作的 edx,eax eax = 2^32次方. 而这里对edx操作了1 那么就是 操作了2^33次方. 欢迎继续提出问题.
谢谢指点
2021-3-30 09:47
0
雪    币: 3797
活跃值: (769)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12

其中 2n/b这个是可以在编译期中计算出来的. VC++6.0 或者VS2019 在编译 期间n的取值是大于32的.所以是可以算出来的.

老哥,这里说的是2的n次方还是2*n,实在没搞明白,可以指点下吗?


2021-4-2 10:17
0
雪    币: 950
活跃值: (9946)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
13
gaoan 其中 2n/b这个是可以在编译期中计算出来的. VC++6.0 或者VS2019 在编译 期间n的取值是大于32的.所以是可以算出来的.老哥,这里说的是2的n次方还是2*n,实在没搞明白,可以指点下吗 ...
都是2^n 不是2*n 除法你都认为是2^n就行.
2021-4-2 10:44
0
雪    币: 3797
活跃值: (769)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
TkBinary 都是2^n 不是2*n 除法你都认为是2^n就行.
打扰了 还有一个问题 关于 sar edx, 1 为什么除以3的时候n取值为0, 除以9的时候取值为1呢?
2021-4-2 15:20
0
游客
登录 | 注册 方可回帖
返回
//