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

来源:互联网 发布:linux proccess port 编辑:程序博客网 时间:2024/04/29 10:37

前言

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

试验总结

找个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;}
0 0