整数除法(除以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;
}

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

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

整数除法对照表(变量/2的幂)

前言如果要做一个代码定式库, 需要收集些素材. 也和代码定式混个脸熟试验代码// hw.cpp : Defines the entry point for the console applicati...

C语言之详解#ifdef等宏

  这几个宏是为了进行条件编译。一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某...

浅谈C语言中"#ifndef/#define/#endif"的作用

一.在c语言中,写头文件的时候,我们应当注重和遵守以下的两个原则:   1.所有的头文件中,必须要有这样的一个保护,即防止头文件#include重复。   2.所有的头文件只#include自己直...

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

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

【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...

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

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

你听说过角谷猜想吗?任意的正整数,比如 5, 我们从它开始,如下规则计算如果是偶数,则除以2,如果是奇数,则乘以3再加1.如此循环,最终必会得到“1” !

/** * 你听说过角谷猜想吗? 任意的正整数,比如 5, 我们从它开始,如下规则计算: 如果是偶数,则除以2,如果是奇数,则乘以3再加1. 如此循环,最终必会得到“1” ! 比如 5 的处理过...

角谷步数 你听说过角谷猜想吗? 任意的正整数,比如 5, 我们从它开始,如下规则计算: 如果是偶数,则除以2,如果是奇数,则乘以3再加1. 如此循环,最终必会得到“1” !

/* 角谷步数 * 你听说过角谷猜想吗? 任意的正整数,比如 5, 我们从它开始,如下规则计算: 如果是偶数,则除以2,如果是奇数,则乘以3再加1. 如此循环,最终必会得到“1” ! 比如 5 的...

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

package com.supermars.practice; import java.util.Scanner; public class 除法表达式 { static Scanner cin...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:整数除法(除以2的幂, 除以非2的幂)
举报原因:
原因补充:

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