整数除法(除以2的幂, 除以非2的幂)

转载 2016年08月30日 02:23:00

前言

除法推导过程还不理解, 先用公式吧.
这里写图片描述
这里写图片描述

试验总结

找个Demo来逆向.
只有除法(变量/常量)会有魔法数, +-*都不会.
看到魔法数(很怪的很大的16进制数)时, 先套除法公式, 看是不是整数除法. 一共就7种, 判断完, 都不是, 再按照正常的做法翻译成C代码.
如果不能用C语言直接描述, 还是得看看是否看错了. e.g. cdq出现在魔法数的上下文中.
如果做个除法片段判断程序, 将反汇编定式都收录进来, 就不用人工判断是否为除法了, 能提高效率.
在没作出除法定式判断程序前, 可以封装一个函数, 根据m,n算出b, 看像不像除数.

逆向完后, 先比对RE工程生成的反汇编代码和原始工程的反汇编代码的区别, 在release模式下, 因为使用了寄存器变量, 无法保证完全相同.

如果测试数据够全或输入数据够少或输出结果可预测, 可以输入数据跑一下, 看RE工程和原始工程输出是否一样.

试验代码

// RE.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <math.h>

//     int CalcDiv_B(double fM, int n) {
//         int iC = 0;
// 
//         /*
//         变量除以非2的幂 公式:
// 
//         被除数 a
//         除数 b
//         商q
//         余数 r
// 
//         a = qb + r
//         a/b = q + r/b
// 
//         a/b = a* (1/b) = a* (2^n) /b * (1/2^n) = a* 2^n /b >> n
//         设m = (2^n)/b
//         b = (2^n)/m
//         a/b = a * m >> n
// 
//         m已知, 出现的除法反汇编实现中
//         被除数a已知, 和m做乘积的那个数就是a
//         n要根据除法反汇编中移位次数算出来, 也是已知的
//         */
// 
//         double fB = pow(2, n);
//         fB = fB / fM;
// 
//         // 一直要向上取整
//         iC = (int)fB + 1;
//         return iC;
//     }

int main(int argc, char* argv[])
{
    // int iC = CalcDiv_B(0x6BCA1AF3, 35); ///< 19
    // int iC = CalcDiv_B(0x55555556, 32);

//     ; =============== S U B R O U T I N E =======================================
// 
//     ; .text:00401000
// 
//     ; int __cdecl main(int argc, const char **argv, const char **envp)
//     _main           proc near               ; CODE XREF: start+AF.p
// 
//     argc            = dword ptr  4
//     argv            = dword ptr  8
//     envp            = dword ptr  0Ch
// 
//                     push    esi
//                     push    edi

    int eax = 0;
//                     xor     eax, eax

    int ecx = 0;
//                     xor     ecx, ecx

    int esi = 8;
//                     mov     esi, 8

    int edi = 0;
//                     xor     edi, edi
// 
    do {
        if (0 == eax) {

//     L_BEGIN:                                ; CODE XREF: _main+1D.j _main+3C.j ...
//                     test    eax, eax        ; .text:0040100D
//                     jnz     short L_NEXT1   ; .text:0040101F
            edi = 1;
//                     mov     edi, 1

            eax = 4;
//                     mov     eax, 4

            ecx = edi;
//                     mov     ecx, edi
            continue;
//                     jmp     short L_BEGIN   ; .text:0040100D
//     ; ---------------------------------------------------------------------------
        }

// 
//     L_NEXT1:                                ; CODE XREF: _main+F.j
        if (1 == eax) {
//                     cmp     eax, 1          ; .text:0040101F
//                     jnz     short L_NEXT2   ; .text:0040103E

                        // 变量/常量的除法么?
                        // m = (2^n)/c
                        // c = (2^n)/m

                        // 如果是除法
                        // n = 32 + 3 = 35
                        // m = 6BCA1AF3h
                        // c(除数) = (2^35)/6BCA1AF3h = 

//                     mov     eax, 6BCA1AF3h
//                     imul    ecx
//                     sar     edx, 3

//                     mov     eax, edx
//                     shr     eax, 1Fh
//                     add     edx, eax
            ecx = ecx / 19;

//                     mov     eax, 3
            eax = 3;
//                     mov     ecx, edx
//                     jmp     short L_BEGIN   ; .text:0040100D
            continue;
        }
//     ; ---------------------------------------------------------------------------
// 
//     L_NEXT2:                                ; CODE XREF: _main+22.j
//                     cmp     eax, 2          ; .text:0040103E
//                     jnz     short L_NEXT3   ; .text:0040105A
        if (2 == eax) {
//                     mov     eax, edi
//                     imul    eax, ecx
            eax = edi * ecx;

            // cdq不是C语言能直接描述的
//                     cdq
//                     and     edx, 3
//                     add     eax, edx
//                     sar     eax, 2
//                     mov     ecx, eax
            /*
            变量除以2的幂 公式:
            对零取整[X / 2^n] = 下取整[(x + 2^n - 1)/2^n]
            */
            // 依赖[变量除以2的幂]公式, 看出 n = 2, 被乘数是eax
            ecx = eax / 4;

//                     mov     eax, 1
            eax = 1;
//                     jmp     short L_BEGIN   ; .text:0040100D
            continue;
        }
//     ; ---------------------------------------------------------------------------
// 
//     L_NEXT3:                                ; CODE XREF: _main+41.j
//                     cmp     eax, 3          ; .text:0040105A
//                     jz      short L_NEXT4   ; .text:00401083
        if (eax == 3) {
            break;
        }
//                     cmp     eax, 4
//                     jnz     short L_BEGIN   ; .text:0040100D
        if (eax != 4) {
            continue;
        }

//                     mov     edx, esi
//                     mov     eax, 55555556h

//                     imul    edx, esi
//                     imul    esi, edx
        esi = esi * esi *esi;

        // imul esi 开始操作魔法数eax, 开始算除法(变量/非2的幂), m = 0x55555556
        // esi * eax => edx:eax
        // a/b = am >> n
        // a*m后, 没有继续向右移位, 直接使用edx调整商, 说明 n = 32
        // CalcDiv_B(0x55555556, 32) 算出除数 = 3
//                     imul    esi

        // 用符号位调整商
//                     mov     eax, edx
//                     shr     eax, 1Fh
//                     add     edx, eax
        edi = esi / 3;
//                     mov     eax, 2
        eax = 2;
//                     mov     edi, edx

//                     jmp     short L_BEGIN   ; .text:0040100D
            continue;

//     ; ---------------------------------------------------------------------------
    } while (1);
// 
//     L_NEXT4:                                ; CODE XREF: _main+5D.j
//                     lea     edx, [ecx+ecx*8] ; .text:00401083
                        // 9 * ecx
//                     lea     eax, [ecx+edx*2]
                        // 变量扩散
                        // lea eax, [ecx + 9 * ecx * 2]
                        // lea eax, 19*ecx
//                     shl     eax, 2
                        // 19*ecx *4 = 76*ecx
                        eax = 76*ecx;
//                     push    eax
//                     push    offset Format   ; "%d\r\n"
//                     call    _printf
                        printf("%d\r\n", eax);

//                     add     esp, 8
//                     xor     eax, eax
//                     pop     edi
//                     pop     esi
//                     retn                    ; .text:0040109E
//     _main           endp
// 
//     ; ---------------------------------------------------------------------------

    return 0;
}

相关文章推荐

【Codeforces Round 354 (Div 2)E】【数学 多项式除法 讨论】The Last Fight Between Human and AI 多项式除以x-k是否值整除

E. The Last Fight Between Human and AI time limit per test 1 second memory limit per test 256 me...

团体程序设计天梯赛-练习集 -- L2-018. 多项式A除以B(多项式除法--模拟)

题意: 给你两个多项式A和B,求A/B 的商和余数。 思路: 这个题目 学到了多项式除法 = =,好水。 具体看一下百度百科: 多项式除法的介绍 多项式A/B,循环终止条件就是当A的最...

大整数除法2(取模和取余) 有改进,但依旧过不了 UVa 10494

对上一版本的改进地方在于,用减法代替除法时,直接将减数补0对齐被减数(参考北大那本书上提到的算法,但依旧没过了。。) Code: //两个大整数相除和取余。有改进,但依旧过不了 #include...

计算机中如何实现除数是2的幂次的除法

前言: 本来是在看汇编里面的数据条件传送指令,做习题的时候看着me

java语言实现:数论经典问题 除法表达 ,无平方因子数 ,直线上的点,同余与模算术 大整数取模 幂取模,模线性方程

package com.supermars.practice; import java.util.Scanner; public class 除法表达式 { static Scanner cin...

判断输入的一个非负的正整数,其是否是2的幂

/** 判断输入的一个非负的正整数,其是否是2的幂 */ #include #include #include using namespace std; #define max -1 /*...
  • leo115
  • leo115
  • 2012-09-24 14:08
  • 1074

整数的2的幂分解

#include #include #include #include #include using namespace std; int dp[1000008]; /*题目描述 一个整数总可以拆...

【LeetCode231算法/编程练习C++】--判断是否是2的整数次幂 //按位与&的用处

LeetCode第231条,按位与的作用 Given an integer, write a function to determine if it is a power of two. ...

华为机试题【9】-整数分割为2的幂次

题目描述:一个整数可以拆分为2的幂的和,例如:7 = 1+ 2 + 47 = 1 + 2 + 2 + 27 = 1 + 1 + 1 + 47 = 1 + 1 + 1 + 2 + 27 ...

找到大于一个正整数N的最小2的次幂数

在看JDK1.7中ArrayDeque源码时,有一个函数是这样写的: private void allocateElements(int numElements) { int init...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)