今天遇到了取模的问题,记录一下。
参考c++反汇编与逆向这本书,如下:
在VC++6.0中,对两个变量取模或者对非2的幂取模,可直接使用div或idiv指令完成,余数在dx或者是edx中。对2的K次方取余,余数的值只需取得被除数二进制数值中的最后k位的值即可,负数则还需在k位之前补1,设k为5,可以得到以下代码:
mov reg,被除数
and reg,8000001Fh
jns LAB1
or reg,0FFFFFFE0h
LAB1:
如果余数的值非零,以上代码是没有问题的;如果余数的值为零,则根据以上代码计算出的结果(FFFFFFE0)是错误的。因此应该加以调整,调整的方法为在or运算之前减1,在or运算之后加1.对于余数不为0的情况,此调整不影响计算结果;对于余数为0的情况,末尾K位全部为0值,此时减1得到末尾K位为1,or运算得到-1,最后加1得到余数值为0.调整后代码如下:
mov reg,被除数
and reg,8000001F;这里的立即数是去掉高位保留低位的掩码,其值由2^k决定
jns LAB1
dec reg
or reg,FFFFFFE0
inc reg
LAB1:
当遇到以上指令序列时,基本可判定是取模代码,其取模原型为被除数(变量)对2^k(常量)执行取模运算,jns可表明是有符号计算,考察"and reg,8000001F"这类去掉高位保留低位的代码,统计出一共保留了多少低位,即可得到k的值,代入求得2^k的值后,可恢复取模代码原型。