おもちゃバコ

中身スカスカ♡

「初めてのマルウェア解析 Windowsマルウェアを解析するための概念、ツール、テクニックを探る」を読んだ

こんにちは

初めてのマルウェア解析を読んだ感想,レビュー,備忘録的なものです。


書籍

今回はオライリーの公式サイトで電子書籍版を購入しました。
pdfやepub形式でダウンロード出来るので,環境を選ばない点で便利ですね。

www.oreilly.co.jp

想定読者

  • マルウェア解析に興味がある人。
  • セキュリティの基礎を学びたい人。
  • システムよりの知識を深めたい人。
  • 解析ツールの使い方を知りたい人。

プログラム知識はC言語とPython2.7を知っていれば大丈夫です。
アセンブリも出てきますが本書に興味を持っている人は大丈夫だと思います。
対象PCはWindowsですが,解析環境はLinuxです。

何とは明言しませんが,不正対策に興味がある人にもおススメです。
マルチプラットフォーム(特にWindows)を扱う人は楽しく読めると思います。
DLLの理解を深めたい人にもおススメ。

手を動かして学びたい派は満足できるはず。


メモ

マルウェアはMalicious Softwareが正式名称。

自分はLinux環境の物理マシンがないので,マルウェア実行はしない。
サンプルコードを書いて疑似的に試すだけ。

メモは雑。

1章 ようこそ,マルウェア解析の世界へ

マルウェアは「悪意ある行為を実行するコードの総称」
 -> でバイナリ,スクリプトなど形式は色々。

マルウェア解析の種類
  1. 表層解析
    プログラムを実行せずに解析する手法
    分析対象に関連するメタデータの抽出などを行う。
  2. 動的解析
    分析対象を隔離環境で実行し,動作を解析する手法
    実行が簡単で,挙動が確認できるので有益な情報が得やすい。
  3. コード解析(静的解析)
    プログラムの内部動作を理解するために行う高度な解析手法
    コード解析は,静的コード解析・動的コード解析に分類される。
    逆アセンブルなどを行うため,OSなどのシステム概念を理解する必要あり。
  4. メモリ解析
    フォレンジック調査で必要な痕跡を見つけるためにRAMを分析する手法
    マルウェアのステルス機能を検出する上でも役立つ。

マルウェア解析はVMで行おうね。
 -> マルウェアによっては仮想環境を回避してホストに感染してくるので注意
 -> 仮想ソフト最新,ネット接続ダメ,仮想環境は空にすること。
 -> ネット接続時はパケットキャプチャやwgetなどで偽装することを考える。

・本書はWindowsマルウェア分析なので,ホストはLinuxか🍎がおススメ
 -> 脱走されてもワンチャン感染できないため。
 -> 書籍はLinux上にWindowsVMとLinuxVMを立てて,LinuxVMがルーティング。
 -> 白紙のスナップショットを作成しておくといろいろ楽

・INetSim
 -> マルウェアが使用するネットワークプロトコルのサーバをシミュレーション
 -> 後でがっつり説明するよだって。

・検体は自分で探して。

関係ないけど「ようこそ,~」の構文ってよく使われてるよね。

2章 表層解析

・ファイル形式の判別で対象OSが判別
 -> Portable Executable(PE)ならWindowsとか。
 -> Windowsベースは大体exe, dll, sysのどれか。

・ファイル形式ではなくファイルシグニチャが重要
 -> ファイルヘッダに書き込まれてる識別子。MZ(4D 5A)とか。
 -> バイナリエディタで開けばわかる(自分はvim+xxd)
 -> fileコマンドやpython-magicでもいける。
 -> WindowsはCFF Explorerが良き。

・ファイル内容に基づいて生成されるフィンガープリントは重要
 -> ファイル内容に基づくハッシュ値があればファイル名の偽装は見破れる。
 -> マルウェアがコピーしたマルウェアがオリジナルなのかが判別できる。
 -> データベースで検索すれば手元の検体が新種か判別できる。

・md5sum, sha256sum, sha1sumでファイルハッシュを生成できる(Linux)
 -> WindowsはHashMyFilesなど。
 -> Pythonならhaslib。
 -> Git Bashでmd5sumやfileなどが使えたのでWindowsの方はうんぬんかんぬん。

マルウェアスキャンサービスはVirusTotalがおススメ
 -> PythonAPIが公開されてる。
 -> 標的型攻撃の場合はハッシュだけ送信するのが良さそう。
 -> 機密情報が記載されてる場合もあるので

・文字列抽出で手がかりを探す
 -> Linuxはstringsコマンドでいける(-a, -el)
 -> Windowsはpestudioが強い
 -> Stringsコマンドを公式からダウンロードでもいける。

・検出回避のために難読化されてるときはFLOSSがよい。
 -> FireEyeLabs Obfuscated String Solver

・パッカー(Packer)
 プログラムを圧縮して,実行ファイルを難読化するプログラム。
 -> もともと実行ファイルを圧縮するものだった
 -> 今ではマルウェア圧縮に使われているらしい(ESET)
 -> UPXが有名(-dオプションで解凍)
 -> 圧縮ファイルとして暗号化させることでシグネチャ参照を回避するのが目的?

・クリプター(Cryptor)
 圧縮ではなく暗号化を行う。

・パッカー検出はExeinfo PEなどがある。

・PEヘッダはプログラム機能に関する情報がめっちゃ得られる。

マルウェアはOS標準機能を利用する。
 -> Windows上にファイルを作成する場合はkernel32.dllのAPIを呼び出すなど。
 -> マルウェアが依存するDLLを調べれば目的や挙動が示唆できる。
 -> ファイル依存関係はPEファイル構造のインポートテーブルに格納される。
 -> 実行時にDLLを明示的に読み込み,関数アドレスを解決することで
  インポートテーブルに含まれないようにしている場合もある。

・インポート関数の数で難読化されているか判別できる。
 -> 少なければ難読化されている可能性が高い。

・エクスポート関数名は解析対策に偽装されている場合があるので注意

コンパイル時刻の検体特定に役立つ。
 -> 改ざんされていても改ざんされている事実が残るため。
 -> Delphiは1992/06/19になるのでわかりやすい。

・アイコン,メニュー,ダイアログなどのリソースは.rsrcに格納されている。
 -> Resource Hackerで解析可能。
 -> よくあるアイコンをExcelに偽装しているマルウェアもここを見ればわかる。

・ファジーハッシュ(Fuzzy Hashing)
 類似度を検証するためのハッシュ(雑)
 MD5とかは同一判別しかできないが,
 類似度解析を行えばマルウェアファミリーを識別できる。
 -> ssdeepなど。

・インポートハッシュ(import Hash)
 同じ攻撃者によって作成された別のマルウェアを識別する手法(参考)
 -> ライブラリ・インポート関数の命名や順序からハッシュ値を計算する。

・YARA
 マルウェアに含まれる固有の文字列・データを識別するソフト。
 -> 詳細は本書見て。

3章 動的解析

・Process Hacker
 システムリソース監視に役立つオープンソースツール。

・Process Monitor
 ファイルシステムレジストリ,プロセスなどをリアルタイム監視できるツール。
 -> Noribenと連携するとマルウェア解析に役立つ。

Wireshark
 みんな大好きパケットスニファ。

・INetSim
 DNS, HTTP/HTTPSなどの標準インターネットサービスを模倣するソフト

・動的解析のステップ
 1. クリーンスナップショットへ戻す
 2. 監視・動的解析ツールの実行
 3. マルウェアの実行
 4. 監視ツールの停止
 5. 結果の分析

Dynamic Link Library
 他プログラムで利用できるエクスポート関数を含むモジュール。
 API関数を呼び出したい場合は,
 APIをエクスポートするDLLをメモリ空間にロードする必要がある。
 -> 詳しくはここ

・DLLが悪用される理由
 ・任意のプロセスに読み込ませることで,マルウェアの挙動を隠す。
 ・実行中のプロセスにDLLインジェクションを仕掛け,
  システム持続性を確保する。
 ・DLLをメモリ空間に読み込ませ,プロセス機能を操作する。
 ・実行ファイルより解析が難しい場合がある。

・rundll32.exe
 DLLを起動,エクスポートされた関数を呼び出す。
 1. DLL Entry Point関数を呼び出す(DLLMain関数のこと)
  -> マルウェアはDLLMain関数に実装されていることが多い。
 2. DLL読み込み完了後,エクスポート関数のアドレスを取得して関数を呼び出す。

・エクスポート関数のないDLL
 DLL Entry Point関数が呼び出されることを利用して,
 DLLMainにロガーなどの機能を実装する。

・Remote DLL
 システム上で実行中のプロセスにDLLインジェクションを仕掛けるツール。
 explorer.exeなどの特定プロセス以外で実行された場合,
 挙動を変えたりするプロセス対策。

・サービスDLL
 サービスとして読み込まれる時だけ実行されるDLLのこと。

4章 アセンブリ言語と逆アセンブル入門

みんな大好きリバースエンジニアリングの基礎。
詳細に説明されているのでアセンブリ入門者にもおススメ。

・データのメモリ常駐
 メモリ内では,データの下位バイトは下位アドレスに,
 上位バイトは上位アドレスに格納されるリトルエンディアン形式。

・命令ポインタ
 EIPはメモリ内の次の命令アドレスを指す。
 (多分)プログラムカウンタのこと(参考)

・オペコードとオペランド
 混乱しないで!

・各括弧はメモリアドレス指定
 -> ものによるのを忘れずに。

・逆アセンブル結果から型情報の推測は重要。

・CMP命令
 引き算してゼロフラグを設定するか判別。
 -> cmp eax, 45
・TEST命令
 ANDしてゼロフラグを設定するか判別。
 -> test eax, eax

・スタックは上位アドレスから下位アドレスの方向へ積み上げる。
 -> popされた値は論理的に削除されるが,物理的にはメモリ上に残っている。

・関数プロローグ
 関数実行前の前処理のこと。
 関数終了後に復元する処理は関数エピローグ。
 -> 大体フレームポインタを弄ってる。

Windows 32-bit on Windows 64-bit(WOW64)
 64bit Windowsで32bitの実行ファイルを実行するためのサブシステム。
 64ビットDLLは/Windows/System32
 32ビットDLLは/Windows/SysWOW64
 -> 32ビットマルウェアがSystem32にアクセスする場合はSysWOW64
 -> OSが自動でリダイレクトしてくれる。
 -> 混乱するかもしれないので32ビットWindows環境も視野に。

5章 IDAによる逆アセンブル

IDAの機能説明がモリモリ書いてあるので,読み返すときはこの章。

・Ghidra
 NSAが2019年に無償公開したリバースエンジニアリングフレームワーク
 -> 最近(20221104頃)よく見るよね。
 -> 本書では使わないよ。

マルウェアはWindowsAPI関数をよく利用する。
 -> ファイルシステム,プロセス,メモリ,ネットワーク通信など。
 -> 基礎は大事ということ。

・代表的なDLL
 1. Kernel32.dll
  プロセス,メモリなどのシステム操作関係。
 2. Advapi32.dll
  サービスとレジストリに関連。
 3. Gdi32.dll
  グラフィック関連。
 4. User32.dll
  WindowsUIコンポーネントの作成・操作関係。
  キーロガーとかに使われやすい。
 5. MSVCRT.dll
  C言語標準ライブラリ。
 6. WS2_32.dll/WSock32.dll
  ネットワーク通信関連。
 7. WinInet.dll
  HTTP/FTPプロトコルとのやり取り関係。
 8. Urlmon.dll
  MIME-Type処理とWebコンテンツのダウンロードなど。
  WinInetのラッパー。
 9. NTDLL.dll
  WindowsネイティブAPI関数。
  ユーザモードやカーネルモードのプログラムインタフェースとして機能する。
  文章化がされていないが,マルウェア開発者はよく使うらしい。

ハンガリアン記法
 変数前にデータ型の略語を付ける記法。
 -> DWORD dwTest;

・WindowsAPIに付いてるAとかWとか
 AはANSI文字列,WはUnicode文字列。
 -> CreateFileA関数はANSI文字列を入力として受け取る。

・接尾辞のEX
 互換性のない関数を更新した時に付く。
 RegCreateKeyEx(RegCreateKeyの拡張版)

・命令の書き換えは同じバイトに調整する。
 -> 少ない場合はNOPでパディング。
 -> 多い場合は後ろの命令を上書きするしかない。

6章 マルウェアデバッグ

x64dbgの使い方も説明している。

・ステップインとステップオーバ
 ステップインは関数内部まで行く。
 ステップオーバは関数全体をスキップする。
-> 違いを答えられるようにしよう。

・ソフトウェアブレークポイント
 指定アドレスをINT3命令などのソフトウェアブレークポイント命令に置換する。
 -> 無制限に設定できる反面,ブレークポイント命令探知されやすい。
 -> デバッガの挙動を変更(妨害に近い?)できる(INT Scanning)

・ハードウェアブレークポイント
 CPUデバッグレジスタを利用する。
 -> x86ならDR0~DR7
 -> 命令置換はないが,デバッグレジスタ内の値に基づいて中断を判別。

・メモリブレークポイント
 命令がメモリへアクセスしたときに停止する。
 -> メモリ内に存在するデータへどの命令がアクセスするのか特定したり。

・条件付きブレークポイント

・dnSpy
 .NETアプリケーション用解析ツール。

7章 マルウェアの機能と持続性

ダウンローダ
 インターネットから部品をダウンロードして実行するプログラム。
 -> UrlDownloadToFile関数をShellExecute関数などと組み合わせる。

・ドロッパー

キーロガー
 -> GetAsyncKeyState関数やSetWindowHookEX関数によるHookが主流。

・リムーバルメディアによる複製
 Autorunの利用(デフォルトでは禁止されているはず)
 -> GetLogicalDriveStringsAとCopyFileAを利用するなど。

・APT1 WEBC2-DIVバックドア

・攻撃者はSNSクラウドストレージサービスなどをC2通信に利用する。
 -> 悪意があるのか判別が難しい

PowerShellは悪用されやすい(cmdletなどが...)
 Post-Exploitationフェーズなどで間接的に呼び出すなど。
 -> メモリから直でコードを動作させたりする。
 -> 標準では安全機構として.ps1は実行できないようになっている(はず)

・持続性メカニズム(Persistence)
 再起動しても再感染なしに攻撃コードを実行する的な概念(?)
 01. RUNレジストリキー
 02. スケジュールタスク
 03. スタートアップフォルダ
 04. Winlogonレジストリ
 05. Image File Execution Options
 06. アクセシビリティプログラム
   -> ログインしてなくても使える(Shift5回のアイツとか)
 07. AppInit_DLLs
   -> セキュアブート化で無効になっているはず。
 08. DLL Search Order Hijacking
 09. COM hijacking
 10. サービス

8章 コードインジェクションとフッキング

仮想メモリ
 OSのメモリマネージャが提供する仮想的なメモリ。
 -> プロセスは独自のメモリ空間を持っているように見える。
 -> プロセスメモリとカーネルメモリに分離される。

・プロセスメモリ
 1. プロセス実行ファイル
 2. DLL
 3. プロセス環境変数
 4. プロセスヒープ
 5. スレッドスタック
 6. プロセス環境ブロック(PEB)
カーネルメモリ
 1. hal.dll(The Hardware Abstraction Layer)
 2. ntoskrnl.exe
 3. win32k.sys

・CreateToolhelp32Snapshot関数
 実行中のプロセスのスナップショットを取得する。
 -> Process32First/Process32Nextと大体セット。

・リモートDLLインジェクション
 LoadLibrary関数経由でプロセスメモリ空間へDLLをロードさせる。
 1. PID取得(ハンドルを開く)
 2. 対象にメモリ割り当て
  -> VirtualAllocEx関数
 3. 割り当てたメモリにDLLパス名をコピー
  -> リモートスレッドを作成し,LoadLibraryを呼び出す。
  -> GetModuleHandleA関数などでkernel32.dllのベースアドレスを取得したり。
 4. CreateRemoteThread関数を呼び出し,対象にスレッドを作成
  -> LoadLibrary関数を実行するため。
  -> NTCreateThreadEx関数もある(No文書)
 5. VirtualFreeとCloseHandleで後片付け

・同程度の整合性レベルでプロセスにコードを挿入可能
 -> 特権権限ならそれ相当が必要。

APCインジェクション
 非同期プロシージャコール(Asynchronous Procedure Calls,APC)で
 対象プロセスにDLLを読み込ませる。
 1. OpenThreadで対象のスレッドへのハンドルを開く
 2. QueueUserAPCでスレッドのAPCキューへAPC関数を入れる

・SetWindowsHookExによるDLLインジェクション

・Shimを悪用したDLLインジェクション
 DLL挿入目的でShimを作成する。

・リモート実行ファイル/シェルコードインジェクション
 直にプロセスメモリへコードを挿入する。
 -> DLLの配置が不要。
 1. OpenProcessでプロセスへのハンドルを開く
 2. VirtualAllocExで特定アドレスへメモリ割り当て
 3. WriteProcessMemoryで割り当てメモリへ実行ファイルを書き込む
 4. CreateRemoteThreadしてエントリポイントのアドレス指定

・プロセスハロウイン
 正当なプロセスの実行セクションを別の実行ファイルへ置き換える。
 -> FWやIPS検知を回避する目的。
 -> VirtualAllocEXなどを避けてNtMapViewOfSectionなどを利用する場合もある。

・IATフッキング
 関数ポインタの交換に依存。

・インラインパッチ
 トランポリン

9章 難読化手法

・難読化理由
 C2通信の秘匿,IPS検知回避,表層解析対策など。

・単純エンコード
 BASE64エンコード,XOR暗号化など。
 -> 実装が簡単かつリソースが少なくて性能も十分なためよく使われる。

・シーザ暗号
 暗号: (i + key) % (length of CHARA)
 複合: (j - key) & (length of CHARA)

BASE64エンコーディング
 暗号対象を3バイト(24ビット)ずつ分解し,
 そのビット列を連結したものを6ビットで構成してテーブルに当てはめる。
 -> 3バイト入力を4文字に変換する。
 -> 性質上,エンコード文字列の長さは4の倍数。

・XORエンコーディング
 ・シングルバイトXOR
  各文字に対してKeyを固定してXOR。
  キー長は1バイト(実質,暗号化出来てない)
  -> ブルートフォースで突破されやすい。
  -> NULL(0x00)バイトでキーが割り出される(何も考えてないと直ぐばれる)
 ・マルチバイトXORエンコード
  32ビットのキーとかでエンコードする。

マルウェアの暗号化
 暗号インジケータ
  1. 暗号化関数へ参照する文字列やインポート
  2. 暗号化定数
  3. 暗号化モジュールに利用するユニーク命令

・Signsrch
 暗号シグネチャ検索などの便利ツール。

・FindCrypt2

10章 メモリフォレンジックを利用したマルウェアハンティング

ツールを利用した解析方法について解説されている。

・メモリフォレンジックの手順
 1. メモリイメージ取得 => メモリダンプ
 2. メモリ解析

11章 メモリフォレンジックを利用した高度なマルウェア検出

・PAGE_EXECUTE_READWRITE
 他プロセスから介入されないようにする保護属性

・仮想アドレス記述子(VSD)

・コードインジェクション検出
 PAGE_EXECUTE_READWRITE保護を持つメモリ領域を探索して,
 内容を検証すればよい。

カーネルモードコード署名
 カーネルモードドライバをメモリに読むためにはデジタル署名を必要としている。
 -> ルートキットによるカーネルドライバのインストール対策。
 -> bootkitで回避しようとしてくる。

・bootkit
 OSが読まれる前(システム起動プロセス初期段階など)で感染させる。
 -> カーネルサードパーティ製ドライバの脆弱性をつく。

カーネルモジュール


感想

エンジニアなのにマルウェアは「得体のしれない怖いモノ」としか認識していなかったのですが,本書を読んだことでマルウェアも「プログラム」って認識にレベルアップしました。

マルウェアの挙動を知ることで間接的にシステム層寄りについても理解を深めることが出来たので良かったです。

読み物としても面白いので何度か読み直したいな~