C C 條件(三目)運算子巧妙原理解析

2021-08-24 21:35:26 字數 2247 閱讀 1162

最近一直研究乙個對個人而言很有價值的乙個lib庫的逆向。在今天下班後突然靈感閃現,這個斷斷續續逆了接近一周的核心管理類。終於在今天給逆完了。在最後乙個函式裡,碰到了之前基本沒有用過的一條指令。(呵呵,高手見笑了!)當然光看單句的彙編指令,是沒有辦法看出具體的作用的,而且還很可能會認為原作者本來就是用彙編來實現的!呵呵,先不廢話,先貼出反彙編**一睹為快:

movdword ptr [b],64h // int b

xor eax,eax

cmpdword ptr [b],0

setg al

sub eax,1

and eax,64h

add eax,0c8h

mov dword ptr [a],eax // int a

今天的lib裡面的那段迷惑的**就跟這段**一致,唯獨a、b變數不一樣。當然這個不影響結果。一開始可能會對setg這條指令的用途不了解。二是看下面藍色的三條指令,什麼又是減,又是and,又是add一些莫名奇妙的立即數。還真讓人迷惑這段**翻譯成c++將怎麼寫。難道就一句一句的翻譯?這樣的話恐怕一條彙編就是一句c++。而且到了setg這條指令時還真不知道怎麼單獨的將其翻譯成c++的什麼語句。呵呵!這可能也就是逆向所帶來的樂趣之一吧(個人觀點)!

好了。不廢話,先分析下。首先b是乙個變數,首先被賦值成0x64(100)。然後將b與0進行比較,如果有心的朋友會覺得奇怪,這個cmp的下面一條語句怎麼不是跳轉語句,一般都是比較後,然後根據比較結果進行跳轉。否則cmp有什麼意義呢?到這裡的話誤導我們的就是setg這條指令了。要了解它,首先得知道cmp會影響到標誌暫存器的標誌位。cmp是執行的減法操作,將前面的運算元減去後面的運算元。與sub的區別就是它不將減後的值放到目的運算元中。所以cmp有可能減溢位等,從而影響到了標誌位。由此一來我們就算猜測都能知道setg應該與標誌位有關係。然後通過資料或者奔騰x86指令集查詢表(我使用的平台是intel x86 cpu)。就可以知道setg指令乃是大於零為真,setg al 就是如果cmp比較後大於零,al裡的值將是0x01。setg的判斷表示式就是(zf=0 and sf=of),還有個setle( zf = 1 or sf <> of ),等等還有幾個,這裡就不一一說明。有興趣的朋友可以去查閱。

之後藍色的三條指令,仔細分析會發現,如果eax為0的話,sub eax, 1後eax將是0xffffffff。之後再and eax, 64h結果eax為64h,之後再是加c8h。之後就給a變數了。然後再分析另外一種情況,假如eax為1, sub eax, 1後將是0,再and等於沒運算,之後才是加上c8h,後面就一樣了。前面的xor eax, eax就不說了,就是把eax清零。這樣一分析,可以有個大概的c++語句的錐形。那就是三目運算子:(?:)。

好了,這句c++語句很短,那就是:

int b = 100;

int a = ( b <= 0) ? 300 : 200;

哈哈,很簡單吧!其實逆向就是這樣,分析一大段很可能翻譯過來的c++**就一句而已。這篇文章說是巧妙原理解析。這裡的巧妙之處就在於編譯器很聰明(ms很厲害),這些細節的技巧可以給我們很多的啟發。這個三目運算在彙編層面上,首先編譯器會把後面冒號兩邊的數字求差,差將用於and運算。b <= 100後eax要麼為1要麼為0。因此後面的sub eax, 1後eax要麼為0xffffffff,要麼為0,為0xffffffff表示b小於等於0。b小於等於0之後的and eax, 64h也就將300 - 200的差100賦值給了eax,之後再add c8h(200),便得到了300。反之,sub eax, 1後。 eax將為0。and運算後等於就沒有算上差值,之後加上冒號後面的數。就是小的200了。呵呵!這些細節,ms的程式很細心啊!

還有就是一點,這裡記錄的差值是有符號的,而且是固定的冒號前面的數減去後面的數。如果前面的數小於後面的數,那麼這裡記錄的將是乙個負值,原理一樣。

再舉乙個例子吧:

mov dword ptr [b],1

xor eax,eax

cmp dword ptr [b],0

setg al

lea eax,[eax+eax-1]

mov dword ptr [a],eax

這個例子就不用說了,直接貼c++**:

int b = 1;

int a = ( b > 0 )? 1 : -1;

或者是bool型別的。注意看紅色指令的巧用,它直接代替了and和add指令。大家慢慢體會!

如果後面冒號兩邊任意一邊是變數的話,就不會被編譯成這樣子了,就會被編譯成普通的跳轉類似於if語句了。

好了,這裡就是一點小小的心得,當是長個記性。高手大牛略過哈! - - 準備一會兒睡覺了!

運算子巧妙原理解析

最近一直研究乙個對個人而言很有價值的乙個lib庫的逆向。在今天下班後突然靈感閃現,這個斷斷續續逆了接近一周的核心管理類。終於在今天給逆完了。在最後乙個函式裡,碰到了之前基本沒有用過的一條指令。呵呵,高手見笑了!當然光看單句的彙編指令,是沒有辦法看出具體的作用的,而且還很可能會認為原作者本來就是用彙編...

《轉》運算子巧妙原理解析

最近一直研究乙個對個人而言很有價值的乙個lib庫的逆向。在今天下班後突然靈感閃現,這個斷斷續續逆了接近一周的核心管理類。終於在今天給逆完了。在最後乙個函式裡,碰到了之前基本沒有用過的一條指令。呵呵,高手見笑了!當然光看單句的彙編指令,是沒有辦法看出具體的作用的,而且還很可能會認為原作者本來就是用彙編...

C 條件運算子(三目運算子)

在某些情況下,可以用條件運算子 來簡化if語句。是乙個三元運算子,其構成的表示式格式為 表示式1 表示式2 表示式3 條件運算子的執行流程示意圖如上圖所示,描述如下 1 計算表示式1的值 2 若表示式的值為真 或非0 則只計算表示式2,並將其結果作為整個表示式的值 反之,即表示式1的值為假 或為0 ...