1. 程式人生 > >PC逆向之代碼還原技術,第六講匯編中除法代碼還原以及原理第二講,被除數是正數 除數非2的冪

PC逆向之代碼還原技術,第六講匯編中除法代碼還原以及原理第二講,被除數是正數 除數非2的冪

順序 argc 有效 text 直接 目錄 數學 分享 bubuko

目錄

  • 一丶簡介
    • 二丶代碼還原講解
    • 1.被除數無符號 除數非2的冪
    • 2.被除數無符號 除數為特例7
  • 三丶代碼還原總結

一丶簡介

上一篇博客說的除2的冪. 如果被除數是有符號的,那麽會進行調整,並使用位操作進行優化
本片博客專門講解除數不是2的冪

二丶代碼還原講解

1.被除數無符號 除數非2的冪

高級代碼:

Release匯編

.text:0040101A                 mov     eax, 38E38E39h
.text:00401023                 mul     [esp+10h+var_8]
.text:00401027                 shr     edx, 1

除數怎麽還原
代碼定式:

.text:0040101A                 mov     eax, M
.text:00401023                 mul     x          此指令等價於 mul x,M  
.text:00401027                 shr     edx, N

還原公式 : (2^(32 +n)) / M = 2^n / M 最後結果向上取整.
代入公式:
2^33 / 38E38E39
= 8589934592 / 954437177
= 8.9999999989522621036795594143123
= 向上取整(8.999...)
= 9
得出被除數是9

原理:
如果不感興趣可不看,或者你有<<C++ 與反匯編與逆向分析揭秘>>這本書,可以觀看第67頁.
原理分析:
首先那麽大數是怎麽來了.
由於除法指令周期比乘法指令周期長.所以編譯器會使用較短的乘法指令來代替除法.
數學證明公式:
設被除數為 x 除數為o
則有下面公式:
技術分享圖片
由於除數o是一個常量.且2^n次方由編譯器選擇. 所以 2^n / o 可以在編譯期間就算出來. 算出來的結果就是那個很大的數.
為什麽是很大的數,在VC++中,n的取值是大於32的. 也就是大於 2^32次方.所以參與運算就會很大了.這樣的好處就是
可以直接使用乘法的高位了.
既然我們知道那麽最大的數就是 2^n / o(除數) 的出來的.所以我們要求除數o
我們設 2^n/o 為c
則有以下公式:
技術分享圖片


可以看到最後優化成了 (x * c) >> n 等價於 (x * M) /2^n次方啊.
這裏說一下,為什麽是2^n次方.因為使用mul的時候,n的取值是大於32的.也就是2^32次方. 然後下面 使用了 sar edx,N
直接使用了edx,我們說過 eax,edx用於乘法.那麽eax就是高位.edx就是低位.這裏直接對 edx 右移了一位. 那麽是不是就是相當於
(eax,edx) >> 1位. 而eax是2^32次方.這裏直接對edx移動了.默認就是操作了eax. 所以隱含的eax不要忘記.
所以我們有了公式: (x * c) / (2^(32 + n)次方.這也跟我們上面的匯編指令相對應.
此時我們求o,進行反推: 2^n / c . 求出除數
所以還原公式為: 2^n / c.

2.被除數無符號 除數為特例7

高級代碼:

int main(int argc, char* argv[])
{
    unsigned int nValue = 16;
    scanf("%d",&nValue);// 防止優化.核心代碼不是這個
 
    int nTemp = nValue / 7;  //核心代碼 一會觀看反匯編

    scanf("%d",&nTemp); //防止優化
    return 0;
}

Debug下的匯編

.text:00401040                 mov     eax, [ebp+var_4]
.text:00401043                 xor     edx, edx
.text:00401045                 mov     ecx, 7
.text:0040104A                 div     ecx
.text:0040104C                 mov     [ebp+var_8], eax

Debug下的匯編很簡單. 獲取被除數,因為被除數是無符號.所以edx為0.所以會使用指令 xor edx,edx
進行清零. 這條語句也可以是 cdq.因為是無符號.所以使用cdq符號擴展那麽edx也是0.可能xor指令周期
比xor周期長.所以沒有使用. 雖然Debug不進行有效優化. 註意不進行有效優化是方便我們調試.但是也會
進行優化.當然不會影響你的調試. 比如 xor 也可以是cdq
如下:

.text:00401040                 mov     eax, [ebp+var_4]
.text:00401043                 cdq     
.text:00401045                 mov     ecx, 7
.text:0040104A                 div     ecx             eax = eax / ecx 等價於 eax = eax / 7;
.text:0040104C                 mov     [ebp+var_8], eax

Debug下直接進行還原即可.很簡單.

Release下的匯編

.text:0040101A                 mov     ecx, [esp+10h+var_8]
.text:0040101E                 mov     eax, 24924925h
.text:00401023                 mul     ecx
.text:00401025                 sub     ecx, edx
.text:00401027                 shr     ecx, 1
.text:00401029                 add     ecx, edx
.text:0040102B                 shr     ecx, 2
.text:0040102E                 mov     [esp+10h+var_4], ecx

Release下的匯編就比較煩了.為什麽指令是這樣. 有一個超大的數, 還有各種乘法, 減法. 移位 加法.
其實這都是有數學原理進行支撐了.而且這個還是個特例.如果不想知道數學原理.直接記住匯編順序

乘 減 移 加 移. 也算是特征. 正好對應 mul sub shr add shr

還原方法:
還原的時候我們可以設置未知數.這樣直接給一個公式進行還原
如下:

.text:0040101A                 mov     ecx, [esp+10h+var_8]
.text:0040101E                 mov     eax, M                 設最大數為M
.text:00401023                 mul     ecx
.text:00401025                 sub     ecx, edx
.text:00401027                 shr     ecx, N                 設移位為N
.text:00401029                 add     ecx, edx
.text:0040102B                 shr     ecx, N                 設置移位為N
.text:0040102E                 mov     [esp+10h+var_4], ecx

還原方法: 2^N/(2^32+M)的商向上取整
可以帶入公式:
M = 24924925h 十進制 = 613566757
n 有兩個,一個是1 一個是2 兩個n相加就是3, 因為使用edx.沒有使用eax 除法會使用 eax,edx. 所以使用edx變相的相當於以及有了2^32次方了.
代入公式:
2^35 / (2 ^32 + M)
= 34359738368 / (4294967296 + 613566757)
= 34359738368 / 4908534053
= 6.9999999993888195604619552997935
= 商向上取整 (6.9999999993888195604619552997935)
= 7
所以得出了除數為7
代碼還原的時候直接還原成 Var_8 / 7 即可.如果想看原理,且向下看.

三丶代碼還原總結

學習了新的兩種定式:
第一種,被除數為正數, 除數為正數. MUL是無符號,所以不需要進行調整.直接套用公式還原

.text:0040101A                 mov     eax, M
.text:00401023                 mul     x          此指令等價於 mul x,M  
.text:00401027                 shr     edx, N

還原公式 : (2^(32 +n)) / M = 2^n / M 最後結果向上取整.
第二種 被除數為正數 除數是特例
特征: 匯編中出現 乘 減 移 加 移

.text:0040101A                 mov     ecx, [esp+10h+var_8]
.text:0040101E                 mov     eax, M                 設最大數為M
.text:00401023                 mul     ecx                    ecx = ecx * M
.text:00401025                 sub     ecx, edx
.text:00401027                 shr     ecx, N                 設移位為N
.text:00401029                 add     ecx, edx
.text:0040102B                 shr     ecx, N                 設置移位為N
.text:0040102E                 mov     [esp+10h+var_4], ecx

還原方法: 2^(32 + N)/(2^32+M)的商向上取整
簡化公式: 2^N / (2^32 + M) 一定註意隱藏的N大於32.

PC逆向之代碼還原技術,第六講匯編中除法代碼還原以及原理第二講,被除數是正數 除數非2的冪