天天看點

抗去除花指令(二)——有創意的花指令

一、概述

“jmp/call/ret+垃圾資料”這樣的花指令已經是相當“老掉牙”了,OD的插件對付它們基本是“秒殺”,是以本文想說點“有點創意”的花指令,至少能對付OD的插件。

二、創意的核心

[2.1]花指令因何被發現

“jmp/call/ret+垃圾資料”的方法之是以容易被檢測,原因是“意圖太明顯”,具體說任何一種檢測手段,都是基于以下兩點:

①檢測跳轉結構的固定形态特征,當然這不是絕對的,如果檢測機制沒能預見到這種形态特征,此點可以忽略,本文後邊會提到一些這樣的情況。

②用可靠的方法直接證明,垃圾資料部分在任何情況下都不會被執行。應該說該點是對“不可執行花指令”的無敵檢測手段,然而卻難在“可靠”二字上,目前已知的實踐,隻是做到“可供參考”的程度。

[2.2]創意的政策

通過[2.1]的分析,我們知道要想編寫“有創意的花指令”,火力應集中在①上,是以我們通過以下政策對抗:

①      采用新的固定結構,許多插件還沒有檢測,比如下文提到的xor-cmp的結構。

②      采用“僞條件跳轉”替代“強制跳轉”

三、一步一步學創意

[3.1]一次幼稚的實踐——互補條件跳轉

首先,我們來嘗試一種用“僞條件跳轉”替代“強制跳轉”的方法,稱作“互補條件跳轉法”,即用兩個互補的條件跳轉指令替代一個強制跳轉指令。比如,用jz和jnz跳轉到同一位址,和一個jmp是等價的。

舉例:

……

  Jz Label

  Jnz Label

  Db thunkcode;垃圾資料

Label:

  ……

除了jz和jnz,還有許多互補跳轉指令,如表1。

    經過測試,隻有一少部分OD插件沒能識别這類花指令,究其原因還是這種方法形态太過固定,一旦形态特征廣為人知,檢測就相當容易。

[3.2]上面方法的改進版——用随機值獲得确定性标志位

上面的方面采用兩個互補的條件跳轉還是明顯,連普通程式都不會使用。是以,我們應該試圖隻用一個條件跳轉。具體方法是這樣的:

通過某些隐蔽的手法,使得某個标志位有确定性的值,然後利用這個确定值,進行确定性條件跳轉。比如下面的手法

Xor reg,value1

Cmp reg,value1

Jnz Label

Db thunkcode

Label:

  ……

該手法的優點是,無論value為何值,經過了xor reg,value1和cmp reg,value這兩句指令,,ZF位一定不會置位,是以jnz一定跳轉。該方法有相當多的變體,該方法的核心是使用随機值,使得某标志位有确定性值。

經過測試,OD的大部分插件都不能檢測,這類花指令變種較多,插件編寫容易遺漏或者未預見到某些形态,但是這種方法的形态特征還是相對固定的,隻是某些還未廣泛熟知,但随着時間推移,該方法的效力會越來越弱。

[3.3]利用API傳回确定值

大部分API函數的傳回值是不确定的,隻要有方法使得API傳回确定值,那麼後面接續的條件跳轉,就是等價的。比如說CreateFile傳回檔案句柄,句柄可能是任意值且有不确定性,然而我們可以使得函數CreateFile傳回值是确定的。

1)            令CreateFile傳回錯誤碼,比如故意向CreateFile傳入錯誤參數,還可以使用類似inc esp,使得堆棧不4位元組對齊,即使傳入正确參數,也會傳回錯誤碼。