逆向知識第六講,取摸優化的幾種方式
逆向知識第六講,取摸優化的幾種方式
除法講完之後,直接開始講 % 運算符在匯編中表現形式
首先C的高級代碼貼上來.
高級代碼:
// Tedy.cpp : Defines the entry point for the console application. // #include "stdafx.h" int main(int argc, char* argv[]) { unsigned Number; scanf("%d",&Number); //防止常量傳播 printf("%ud \r\n",Number % 8);//無符號/2的冪 __asm { nop; nop; ;內聯匯編,觀看的時候知道怎麽看 nop; } printf("%d",Number % 3);//無符號/非二的冪 __asm { nop; nop; nop; } printf("%d" , 8 % Number);//常量/變量 __asm { nop; nop; nop; } printf("%d",argc % 8);//有符號/2的冪 __asm { nop; nop; nop; } printf("%d",argc %-8);//有符號/2的冪,除數為負數 __asm { nop; nop; nop; } printf("%d",argc %3);//有符號/非2的冪 return 0; }
一丶無符號% 2的冪在匯編中的表現形式
匯編代碼:
高級對應語句:
printf("%ud \r\n",Number % 8);
可以看出,當無符號%2的冪的時候,直接用and計算. 其值是 2^n - 1的值
比如我們的number %8,那麽and的值則是 8-1,而8是2^3次方.
現在說下7這個數, 0111 它正好是3個指數位,所以還原的時候,直接看占的二進制位數,占了幾位就是指數是多少.
需要註意:
我們一般看%某某個數的時候,我們要知道其結果保存在edx寄存器當中,而eax寄存器保存的是商
比如:
8 % 6 = 1 ..... 2 那麽其值 1在eax中,其余數2在edx中
二丶無符號/非二的冪
高級代碼:
printf("%d",Number % 3);//無符號/非二的冪
匯編代碼:
可以看出,無符號 / 非2的冪的時候,直接使用 DIV 了,同理有符號 / 非2的冪的時候,就會使用IDIV了.
這個時候還原 除數則看 給的除數是多少了.
比如這裏 DIV ecx,而ecx給的是3,則除數是3了.
還可以看到,這個地方 push的edx,那麽說明使用的edx,而上面也說了,edx中的值存放的是余數的值.
三丶常量 % 變量
高級代碼:
printf("%d" , 8 % Number);
匯編代碼:
可以看出這段匯編代碼, eax給的是常量,直接使用DIV了,用的是EDX,由此判定, 除數是一個變量,而這個變量是無符號類型了,因為上面的 XOR EDX,EDX清空了.
看到這一段代碼的時候,還原手法:
eax % [ebp + var_4] = xxx ... edx
代入公式得:
8 % 變量 = 商...余數.
如果你知道變量是具體的值,比如現在是3
那麽8 % 3 = 商...余數 即可.
四丶重點: 有符號 % 2的冪
高級代碼:
printf("%d",argc % 8);//有符號/2的冪
匯編代碼:
有符號的處理,比無符號復雜一些.主要判斷一下符號位.
比如上面的高級代碼對應的這些匯編代碼.看不懂沒關系.依次講解.
我們知道有符號%一個數的時候,需要判斷符號位對吧
那麽此時分為三部分去看.
第一部分 : 正數的情況下
上面匯編代碼表示, 我用有符號變量 % 一個80000007h,得出的結果如果不是負數(jns)那麽余數就是正數,直接跳走了
首先我說下為什麽是 800...7h
上面也說過了,要保留符號位
那麽8則是符號位,也就是1, 而為什麽最後是7那?,這個則是保留指數位.
800...7h換算成二進制表達形式為:
10000000000000000000000000000111
高位為符號位,低3位為指數位(當然不是固定的,它的指數位是 2^n-1,比如我們的除數為8,那麽指數位則是 2^3 - 1 = 7,而7正好是占3個指數位,比如是16,那麽2^4 - 1 = 15,而15的指數位則是占了4個二進制位)
這一段匯編代碼,是計算正數的
假設我們的argc有符號變量為9
那麽9對應的二進制則為
00000000000000000000000000001001
and (那麽與剛才的二進制去 &(與)一下結果還是正數)
10000000000000000000000000000111
=
00000000000000000000000000000001 那麽其值結果為1,也就是余數為1,而不是負數,此時就可以跳走直接運算了.
第二部分: 負數的情況下
上面說了正數的情況下,你直接and 2^n-1 的值即可.那麽得出的結果還是正數.
那麽現在是負數額情況下.
我們看到一個16進制的數字 0FFFFFFF8h,那麽是什麽意思那?
當然對應的二進制表達方式也寫出來.
11111111111111111111111111111000
此時看匯編代碼 ,註意 dec inc這些是特殊情況下需要用到的,暫時不管,現在只看 中間的or指令.
我們試想一下,如果我們余數是負數的情況下,
舉例子:
-9 % 8 = 1 ... -1
也就是上面判斷為正數的先走一遍.得到的余數二進制為 -1
那麽對應二進制也就是
100000000000000000000000000000001 (現在的EDX的值).
然後現在有or了一下0FFFFFFF8h 這個值,那麽說下這個怎麽得到的.
我們上面說過了,保留了符號位,符號位置為1,還有保留指數位 (2^n - 1)
那麽這個時候, 這個值就是 把中間的值變為1,保留(2^n-1的位數)
11111111111111111111111111111000
高位一個符號位,中間的0變為1,最後三個則是指數位,此時or之後
10000000000000000000000000001
or(或 |)
11111111111111111111111111111000
=
1000000000000000000000000001
那麽則得出結果是 -1
第三部分: 特殊情況下
特殊情況下,則是 一個 dec,然後最後一個inc回來的時候.
這個則是當余數為0的情況下才會觸發.
比如 8 % 8 = 0;
走第一部分匯編代碼的時候,edx裏面的值都是0了.
然後-1,繼續or, or出來的結果加1還是0.這個主要是余數為0的情況下.
重點: 還原手法
上面只是說的原理.(其實也不算高深點的原理,這裏是站在匯編代碼的角度下說的,其實真正的都有數學定理和公式)
以後凡是看到這塊匯編代碼:
我們直接看指數位是多少位即可. 比如上面我們%8,那麽指數位是3個,那麽還原的時候就是 r = 2^n次方即可.
n = 指數位
n = 3
如果計算上面的余數則
r = 2^ 3
r = 8即可.
當然我們要看一下最後用的寄存器是不是edx,如果是edx,那麽就是 %,如果是用的eax,那麽結果就是 /
很顯然上面是用的edx,
還原回來的匯編代碼為:
[ebp + argc] % 2^n
有符號局部變量 % 8 即可.
五丶有符號 % -2的冪
高級代碼:
printf("%d",argc %-8);//有符號/2的冪,除數為負數
對應匯編代碼:
首先在講解之前,我們要明白一下.
我們舉例子:
8 % 6 = 1 ... 2
8 %-6 = -1.....2
但是我們看一下,我們的余數並沒有改變其結果, 余數都是2
比如我們列一個公式
a(被除數) b(除數) q(商) r (余數)
a % b = q ... r 這個是基本的.
那麽
a % |b| = |q| ... r 摸不摸 b的絕對值,其 r值不變的.影響的只是 q對不起.
但是
|a| % b = |q| ...|r| 那麽這個時候,如果把a變為絕對值,那麽絕對會影響r的值.
上面的匯編代碼.則是寫了一個無分支求絕對值而已.如果數學公式搞懂了,那麽看上面的匯編代碼則會懂了
第一部分,無分支求絕對值
這個則是無分支求絕對值的代碼.
首先esi的值是上面 argc局部變量的值,只不過上下文中沒有修改esi,所以在這裏直接使用.這裏就想象成一個變量
然後CDQ, edx的值,跟隨者eax的符號位填充,如果 eax(也就是現在變量的值是正數,那麽eax的高位則是0,那麽edx的值全部都是0)
如果是正數的情況下:
正數的情況下,eax是正數,edx因為符號擴展,所以結果是0, xor之後,其結果還是原值.
此時 原值 eax - edx (相當於, - 0 )那麽其結果還是原值.
然後
此時把除數變為正數了,那麽 直接使用and 7即可.(7是 2^n-1的值)
and之後,其eax的值則是余數(這裏不是EDX了,有時候我們要看,這裏是eax去弄得,所以放到裏面了)
and之後,下方繼續幾行匯編代碼,這些匯編代碼都一樣得出的結果還是原來的值.
如果是負數的情況下:
匯編代碼就是這麽一大堆.
然後負數的情況下,執行完求絕對值的代碼之後,其結果就變成了正數. 在and eax,7上面弄得.
那麽此時如果原來是負數的情況下,那麽下方繼續再來一遍,變為負數.
那麽此時得出的除數是負數. 也就是 b為負數.(除數)
還原手法:
不管怎麽做,上面先把絕對值求出來,然後和 (2^n-1)去and,此時得出了除數是 (2^n) ,那麽怎麽判斷正數還是負數.
判斷下方是否在取反了即可.
逆向知識第六講,取摸優化的幾種方式