关于Release版除法反汇编的小结

引子:

    诸如a/b(a是变量,b是常量)这种带常量的除法,可以被(数学上的)等价变换为[a/(2^n)]*[(2^n)/b]的形式。由于b和n是常量,因此在编译期间,编译器会将(2^n)/b转换成新的常量b',上式变为(a*b')/(2^n)。将原本除法表达式转换为乘法和移位运算符(PS:除以2^n可以被编译成右移n位)。编译器为什么要做这样的转化?据说,执行转化后的表达式需要3个机器周期,而执行idiv指令需要8个机器周期。

正文:

    上述转换,对于代码的执行确实大有裨益,但这使得反汇编时除数笼罩在阴翳中了。我们的目标是在反汇编过程中识别 乘数b'和移位数n,然后反推除数b。 在反汇编过程中除法运算中,常常会遇到诸如:0x92492493H这类数值巨大的常量,作者称之为MagicNumber。我们需要对魔数分类讨论:
1.魔数值位于区间 [0x00000000,0x80000000):

    1.1).识别魔数位于这个区间的除数不需要对魔数做额外的处理,所以先予讨论。最简单的情形就是执行(i)mul后,用sar指令使edx右移n位。edx是乘法运算结果的高32bit,因此实际右移(32+n)位。

mov ecx,[esp+arg0]
mov eax,38E38E39h
imul ecx
sar edx,1
mov eax,edx
shr eax,1Fh
add edx,eax
push edx

上面这段代码组成的表达式为:38E38E39*ecx/2^33,与公式(a*b')/(2^n)对比,可得b'=MagicNumber=38E38E39,n=33,根据公式b=(2^n)/b',可得b=9.

    1.2).最简单的情形往往只是一个特例。多数情形下,执行(i)mul后,edx会与被除数参与到零星的几步四则运算。于此,需要将表达式按乘法的结合律进行合并:
mov ecx,[esp+arg0]
mov eax,24924925h
mul ecx
sub ecx,edx
shr ecx,1
add ecx,edx
shr ecx,2
push ecx
...

上面这段代码组成的表达式为:{[ecx-(ecx*MagicNumber)/(2^32)]/2+(ecx*MagicNumber)/(2^32)}/2^2,其中MagicNumber=24924925h,ecx为被除数。合并表达式后为ecx*(2^32+MagicNumber)/(2^35)。与公式(a*b')/(2^n)对比,可得b'=2^32+MagicNumber,n=35。根据公式b=(2^n)/b',可得b=(2^35)/(2^32+24924925h)=7

2 .魔数值位于区间 [0x80000000,0xFFFFFFFF]:
    2.1).如果位于这个区间的魔数参与到有符号乘法中,因为有符号数的最高位是符号位,所以对应的有符号乘法指令不会让最高位参与数值计算。对于这种实际参与乘法计算的数是负数的情况,需要做特殊处理,MagicNumber在计算前要变为MagicNumber=MagicNumber-2^32,如下例:
mov eax,92492493h
imul esi
add edx,esi
sar edx,2
mov eax,edx
shr eax,1Fh
add edx,eax
push edx
...
上面这段代码组成的表达式为:[(MagicNumber*esi)/2^23+esi]*1/4,其中MagicNumber=92492493h-2^32。合并表达式后为(0x92492493)*esi/2^34。与公式(a*b')/(2^n)对比,可得b'=0x92492493H,n=34.根据公式b=(2^n)/b',可得b=7.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值