はじめに
Zero2Automatedを受講しているのだが途中でPractical Analysisという課題が出た。試験でも解析レポートを作る必要があるのでせっかくなので解析レポートを作る。本番は英語になるけど日本語で書いておく。
検体情報
md5,A84E1256111E4E235250A8E3BB11F903 sha1,1B76E5A645A0DF61BB4569D54BD1183AB451C95E sha256,A0AC02A1E6C908B90173E86C3E321F2BAB082ED45236503A21EB7D984DE10611
検体動作概要
- ResourceにあるデータをRC4で復号
- 復号したデータをプロセスにインジェクション
- 画像を通信先からダウンロード、画像に含まれている暗号化されたペイロードを復号
- 復号したペイロードをsvchost.exeへプロセスインジェクション
- MessageBoxにメッセージを表示
この検体の最初に動作するmain_bin.exeをStage1として説明する。
Stage1:ResourceデータのRC4での復号
- findResourceで101という名前のリソースを探し、ロードする
- Resourceデータの0x1c以降のデータをVirtualAllocで確保した領域にコピー
- Resourceデータの0xcから0xfバイトを鍵としてRC4で復号する。
- 復号したRC4のデータを、以下のAPIを呼び出してインジェクション
- VirtualAllocEx
- WriteProcessMemory
- SetThreadContext
- ResumeThread
リソースのデータはCyberchefで復号できる。この復号してインジェクションするデータをstage2とする。
Stage1:文字列復号
Stage1では拡張したROT13での文字列暗号化が行われている。拡張したといっているのは、文字配列として"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./="が使われているからである。
以下のGhidraスクリプトで復号する。
def get_string(enc_data_addr): i = 0 while getBytes(enc_data_addr.add(i),1)[0] != 0: i+=1 return getBytes(enc_data_addr,i).tostring() def decrypt_string(enc_str_addr): enc_str = get_string(enc_str_addr) strmap = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./=" dec = "" for s in enc_str: k = strmap.index(s) dec += strmap[(k + 13) % len(strmap)] return dec
Stage2:画像を通信先からダウンロードしてインジェクション
Stage2は以下の動作を行う。
pastebin.com
のURLにアクセスし、そこに記載されているURLの画像を取得- 画像中に含まれているデータを復号する。
- svchost.exeのプロセスを作成し、復号したデータをProcessHollowingする。
ProcessHollowingし実行される処理はStage3とよぶことにする。
Stage2では、最初に以下の通信先へ接続する。
https[://]pastebin[.]com/raw/mLem9DGk
この接続先には、違うURLが記載されており、Stage2はそのURLのアクセスも行う。
この通信先へアクセスすると、以下の画像が表示される。
この画像のデータのうち、cruloader
以降のデータを0x61でxorしたデータをProcessHollowingする。
Stage2での文字列復号
Stage2では、4バイトのROL後にxorをすることで文字列の復号をしている。xorの鍵は固定ではないため注意する必要がある。
Stage3
Stage3は以下のメッセージボックスを表示するのみのプログラムである。
IoCs
https[://]pastebin[.]com/raw/mLem9DGk hxxps[://]i[.]ibb[.]co/KsfqHym/PNG-02-Copy.png