當前位置:
首頁 > 新聞 > 教你如何使用分組密碼對shellcode中的windows api字元串進行加密

教你如何使用分組密碼對shellcode中的windows api字元串進行加密

介紹

字元串/模式匹配演算法是當前最流行和最簡單的檢測shellcode方法。原理很簡單:所有代碼都有其獨特的特徵,可以根據這種特徵去在內存中驗證。即使沒有事先分析shellcode,我們也可以得到一些有用的變數,或者至少看起來它是一串可疑代碼,需要進一步分析。

我提到的有用變數是指API字元串以及hash值,它們已經在檢測惡意代碼歷史上使用了20多年。如果想要繞過這種檢測方法,編寫shelcode過程中我們要考慮使用像C或C++這樣的HLL語言,進行非常規的編程,保證shellcode中的內容是可以變換的,不固定的。

這一過程中不止可執行代碼可以變換,任何內容都可以變換:代碼,數據,常量,字元串等等。今天我要展示的是使用名為Maru的hash函數生成可排列的API散列。Maru使用分組密碼生成字元串的hash值,當然你大可不必使用分組密碼做此事,但是這樣可以防止使用SMT進行hash碰撞攻擊。

想要獲取更多有關信息,你可以閱讀:使用SAT和SMT消除簡單的散列演算法

簽名檢測

在MS-DOS病毒在30年前剛出現時,基於簽名的檢測是很容易的。為了隱藏惡意代碼,攻擊者使用八比特的變數對代碼進行異或運算,舉個例子,在1991年出現的Skism Rythem Stack Virus-808病毒,使用了感染時間時的毫秒數字進行異或運算,所以對於100個版本來說,每一個都是不同的。

這是該代碼的入口,以及其解密過程:

jmp virus_startencrypt_val db 00hvirus_start: call encrypt ; encrypt/decrypt file jmp virus ; go to start of codeencrypt: push cx mov bx, offset virus_code ; start encryption at dataxor_loop: mov ch, [bx] ; read current byte xor ch, encrypt_val ; get encryption key mov [bx], ch ; switch bytes inc bx ; move bx up a byte cmp bx, offset virus_code + virus_size ; are we done with the encryption jle xor_loop ; no? keep going pop cx ret

執行完這一串代碼之後,病毒會使用當前時間值的毫秒數對 encrypt_val 進行更新:

; mov ah, 2ch ; get time int 21h mov encrypt_val, dl ; save m_seconds to encrypt val so ; theres 100 mutations possible

攻擊者為做到隱蔽自己做了一些努力,但是解密器是可以被察覺到的,並且病毒很容易被殺掉。此外,殺毒軟體可以模擬解密程序,通過驗證簽名,在病毒執行前阻止他。

在1997年Win32病毒出現時,已經不存在MS-DOS中斷,相反,可以通過動態鏈接庫dll對API函數進行訪問,這使得檢測惡意軟體變得更加容易,當存在大量調用API函數的代碼塊時,系統就會發出警報。

攻擊者最終使用了32位校驗碼,其中最受歡迎的就是CRC32。不久之後,LSD-PL首先使用了基於ADD-Rotate—Xor方法,在他們的WASM包中,代碼如下:

i3: mov esi,[4*eax+ebx] ; ptr to symbol name add esi,edx ; rva2va push ebx ; hash: h=((h27))+c push eax xor ebx,ebxi4: xor eax,eax ; hash loop lodsb rol ebx,5 add ebx,eax cmp eax,0 jnz i4 ror ebx,5 cmp ebx,ecx ; hash compare pop eax pop ebx je i5 ; same: symbol found inc eax jmp i3 ; different: go to the next symbol

大部分合法代碼是不需要調用api的,也不會手動導入地址表或者導出地址表的。如果碰到這種行為代碼,那麼通常它會對你的計算機造成危害。

API散列是很有趣的,它不會被字元串簽名驗證給殺掉,所以如果殺毒軟體只是對是否包含調用API的代碼進行檢測,那麼這種檢測方法是無效的。儘管現在很多攻擊軟體(BeEF,meterpreter,Veil)都會使用無熵或者隨機化的散列演算法。但是他們是不會被改變的,所以檢測起來還是很容易的。

當然,這些工具都提供了像RC4、AES這樣的加密演算法,不過這樣即使通過了殺毒軟體和IDS進行的簡單掃描,但是通過模擬器去解密主要代碼,觀察它的行為,對它防禦是完全沒有問題的。

字元串問題

在理想情況下,攻擊者希望在編譯過程中對所有代碼進行混淆或者加密,並且在解密過程中不會使用冗餘的代碼和工具。

constexpr是使用c++代碼的理想選擇,不過對於C來說,則沒有這樣的功能,除非編譯器在編譯過程中對所有字元串進行修改和加密。

一些彙編程序比如MASM,NASM是支持基於宏的編譯,但是工作過程中是基於很複雜的函數的(並不是你不能)。Z0MBiE已經在2002年在」Meta病毒中的編碼「以及」在HLL中解決字元串問題「中對這一問題進行了討論,但是如果進一步查看這些解決方法,這裡只是使用很少的熵值而已。

使用熵對API字元串進行加密的目的很顯然是增加檢測有效載荷的難度。不過這不是一個長久之計,遲早會被發現,但是這種方法肯定比現有的沒有熵的hash演算法要好很多。

散列函數構造

我們可以從分組密碼中構造新的hash演算法,於是對於提供的不同key值,就會生成不同的API散列。但是,很少的分組密碼是適用於shellcode生成的。

這裡有三個可以使用的分組密碼機制(其實有很多的, 只是目前發現了三個)。

1.Davies–Meyer

將每個塊中的消息(mi)作為塊密文的key,然後將先前的hash值(Hi-1)作為要被加密的明文。然後將輸出的密文和之前的hash值(Hi-1)進行異或,生成下一個hash值(Hi)。在加密的第一輪中,之前並沒有hash值產生,會使用我們預先設定的一個常量(H0)進行加密操作。

2.Matyas–Meyer–Oseas

將每塊中的消息(mi)作為要被加密的明文。輸出的密文同樣和相同的明文塊進行異或,產生下一組hash值(Hi)。前一組hash值會作為這一組加密的密鑰。在第一輪中,並沒有之前產生的hash值,所以使用之前設定的初始化變數H0.

3. Miyaguchi–Preneel

每一塊消息都會作為要加密的明文,輸出之後的密文和同樣的明文進行異或運算,然後再和前一組產生的hash進行異或運算,產生這一組hash值(Hi)。前一組產生的hash值作為了加密的密鑰。

在第一輪中,並沒有之前產生的hash值,所以使用之前設定的初始化變數H0。這些是我認為使用的3種簡單設計。對於Maru哈希,我使用Davies-Meyer與一些非標準填充。

選擇分組密碼

我們知道在加密過程中需要一些靜態值,與加密常數相比,有什麼更好的靜態值嗎?

你可以對這些靜態值進行改變,不過可能會影響加密函數的安全性,所以最好使用一個不包含任何靜態變數的密碼。在查看可能使用的分組密碼時,我選擇的前三個是基於ADD-Rotate-Xor(ARX)設計實現的。

1. Speck

由NSA設計,於2013年進行發布(https://eprint.iacr.org/2013/404)。對於不同的架構,產生不同的密鑰以及分組大小。成為大多數架構可用的最小的基於軟體的塊密碼。

32位機器的參數為64位的分組大小以及128位的密鑰長度。64位模式下的參數為128位的分組大小,以及256為的密鑰長度。這兩種加密代碼長度分別為64位元組以及86位元組。

如下是x86代碼:

2. Chaskey-LTS

在2015年發布(https://eprint.iacr.org/2015/1182),基於Even-Mansour加密方式,使用SipHash中的置換函數進行產生。參數為128位的密鑰,和128位的分組大小。在x86機器上實現大小為90位元組:

3.XTEA

拓展微加密演算法。一種Feistel密碼,在1997年發現微加密演算法弱點之後發表(http://www.cix.co.uk/~klockstone/xtea.pdf).參數為128比特的密鑰,分組大小為64比特。他有一個已知的常量,0x9E3779B9,這使他容易被基於簽名檢測出來,大小約80個位元組:

Speck是輕量級應用程序更好的設計,不能通過簽名輕鬆識別。 (至少不是從任何常數)所以我選擇它生成hash。

Maru Hash

那麼在關於需要消除shellcode中常量的討論之後,我在這裡介紹hash函數的一部分。在轉換為整數之前,64位常數是137素數的乘法逆元。它是加密過程中的初始化參數H0。

進一步來說:

1.0.00729927007299270072992700729927是137的乘法逆元。

2. 捨棄小數部分中的前兩個0,將剩下的轉換為64位整數。

3. 結果為:0x654C37754C5E9939

H是通過用Maru常數和64位密鑰進行異或初始化的。然後將API字元串作為密鑰重複使用Speck進行加密,直到達到終止符為止。

下方代碼是C原型:

uint64_t maru(const void *str, const void *key);

str參數指向我們的API字元串,長度不應超過128位元組(即使函數接受任意長度的字元串)。key參數應該指向我們唯一的64位值,這應該是理想的隨機選擇。

uint64_t maru(const void *str, const void *key) { uint8_t *s=(uint8_t*)str; w64_t *k=(w64_t*)key; w64_t h; w128_t m; uint32_t idx, end=0, i, t, k0, k1, k2, k3, x0, x1; // set the initial hash which is 64-bit key xor 1/137 h.q = k->q ^ MARU_INIT_H; // now update the hash using string as key for (idx=0; !end; ) { // if bytes remaining if (*s != 0) { // add byte to buffer m.b[idx++] = *s++; } else { // this is last block // pad with end bits while (idx < MARU_BLK_LEN) { m.b[idx] = (uint8_t)idx; idx++; } end++; } // if m filled if (idx == MARU_BLK_LEN) { // copy 128-bit key to local registers k0 = m.w[0]; k1 = m.w[1]; k2 = m.w[2]; k3 = m.w[3]; // copy H to local space x0 = h.w[0]; x1 = h.w[1]; for (i=0; i

hash舉例

以下是對API以及潛在密鑰的測試案例,他們不必是字元串。

從示例散列可以看出,一旦密鑰被更改,生成的API哈希是完全不同的。通過選擇不同的密鑰,這使得我們的哈希值也會不同。

總結

設計自己的hash函數或者加密演算法通常會很好的繞過殺毒軟體。但是像Maru這樣的hash演算法並不適用於對防碰撞要求很高的場合。Maru hash真的是一個關於如何對shellcode中的字元串進行隨機變換,進而繞過殺毒軟體的字元串檢測的方法。

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

輕鬆審計代碼安全性,Windows 10有妙招
只因更新固件推送出錯 Lockstate智能鎖秒變磚
找漏洞、打金幣、賣賬號,依靠網路遊戲黑金活了二十年的人
威脅預警!不用再黑進系統,只要在指示牌上貼紙就可以擾亂自駕車!

TAG:嘶吼RoarTalk |

您可能感興趣

使用 Bitwarden 和 Podman 管理你的密碼
macOS:喚醒 Mac 後需要密碼Require a password after waking your Mac
Microsoft Outlook中的缺陷讓黑客輕鬆盜取您的Windows密碼
Red Valentino 密碼破譯浪漫
Google Chrome和Mozilla Firefox將支持全新無密碼登錄規範
忘記Mysql的root密碼怎麼辦(windows下的mysql)
在Exchange Server中重置用戶密碼
Telegrab惡意軟體可以獲取Telegram的密碼、Cookie及密鑰文件
iCloud更改Apple ID密碼
AgileBits否認蘋果在收購密碼管理軟體1Password
Mozilla推出兼容iOS的Face ID密碼管理器Firefox Lockbox
每日資訊Google Chrome和Mozilla Firefox將支持全新無密碼登錄規範……
「Shopify小白系列」Shopify賬戶忘記密碼怎麼辦?Shopify密碼重置&應用介紹
Inside Secure發布軟體安全工具Whitebox Designer 快速圖形化創建安全密碼構架
破解Centos7 root用戶密碼
Vitalik Buterin:密碼朋克運動的發起人之一Timothy C.May去世
巧用Win10「Microsoft Print to PDF」去除PDF密碼
Fedora 31默認禁用OpenSSH root密碼登錄
密碼管理器LastPass更新:新增對Android Oreo自動填充特性的支持
How GENE eliminates GENEral:破譯生命密碼