yara-rule-authoring について
YARA-X のマルウェア検出ルールを作成・レビューするスキルです。セキュリティ分析担当者向けに、特徴の選定、性能確認、誤検知の調査、旧 YARA からの移行を支援します。
主な機能
- 01YARA-X ルールの作成
- 02文字列とアトムの分析
- 03条件と性能の指針
- 04誤検知の調査
- 05旧 YARA ルールの移行
活用シーン
- 01マルウェアファミリー検出ルールの作成
- 02ルールの誤検知レビュー
- 03低速なルールセットの最適化
- 04ルールの YARA-X への移行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trailofbits/ skills --skill yara-rule-authoringインストール後、Claude Code で/yara-rule-authoringを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlassets/trail-of-bits-mark.svgexamples/MAL_Mac_ProtonRAT_Jan25.yarMAL_NPM_SupplyChain_Jan25.yarMAL_Win_Remcos_Jan25.yarSUSP_CRX_SuspiciousPermissions.yarSUSP_JS_Obfuscation_Jan25.yarreferences/crx-module.mddex-module.mdperformance.mdstrings.mdstyle-guide.mdtesting.mdscripts/atom_analyzer.pypyproject.tomlreview.shtest_yara_rules.pyuv.lockyara_lint.pyyara_rules.pyworkflows/rule-development.md詳細
YARA-X ルール作成
誤検知を大量に発生させずにマルウェアを検出するルールを作成します。
この SKILL.md がインストールされているディレクトリから、リンター、アトムアナライザー、
およびレビュー用ヘルパーのパスを解決してください。
以下のコマンドでは、各 <resolved-...-path> を該当スクリプトの絶対パスに置き換え、引用符はそのまま残してください。絶対パスの入力を渡さない限り、ルールファイルまたはディレクトリは作業ディレクトリからの相対パスです。
このスキルは YARA-X を対象としています。YARA-X は従来の YARA の後継である Rust 製のツールです。正規表現は 5~10 倍高速化され、エラー表示が改善され、フォーマッターが組み込まれ、検証がより厳格になり、新しいモジュール(crx、dex)が追加されています。ルールの 99% と互換性があります。VirusTotal の本番システムで採用されています。brew install yara-x または cargo install yara-x でインストールできます。CLI は yr です。既存のルールについては従来の YARA からの移行を参照してください。
基本原則
-
文字列は良質なアトムを生成する必要があります — YARA は高速に照合するため、4 バイトの部分列を抽出します。繰り返しのバイト、一般的な並び、または 4 バイト未満の文字列では、多数のファイルに対して低速なバイトコード検証が強制されます。
-
カテゴリではなく、特定のファミリーを対象にします — 「ランサムウェアを検出する」では、あらゆるものに一致する一方、何も検出できません。「LockBit 3.0 の設定抽出ルーチンを検出する」なら、必要なものを検出できます。
-
デプロイ前に正常なファイルでテストします — Windows のシステムファイルに反応するルールは役に立ちません。VirusTotal の正常ファイルコーパス、または独自のクリーンなファイルセットで検証してください。
-
低コストのチェックを先に行い、早期に判定します —
filesize(即時)、次にマジックバイト(ほぼ即時)、次に文字列(低コスト)、最後にモジュール(高コスト)の順です。 -
メタデータはドキュメントです — 将来の自分やチームが、このルールで何を検出するのか、その理由、サンプルの入手元を把握できるようにする必要があります。
使用する場面
- マルウェア検出用の新しい YARA-X ルールを作成するとき
- 品質やパフォーマンスの問題について既存のルールをレビューするとき
- 実行が遅いルールセットを最適化するとき
- IOC や脅威インテリジェンスを検出シグネチャに変換するとき
- 誤検知の問題をデバッグするとき
- 本番環境へのデプロイに向けてルールを準備するとき
- 従来の YARA ルールを YARA-X に移行するとき
- Chrome 拡張機能(crx モジュール)または Android アプリ(dex モジュール)を分析するとき
使用しない場面
- 逆アセンブルを必要とする静的解析 → Ghidra/IDA のスキルを使用してください
- 動的なマルウェア解析 → サンドボックス解析のスキルを使用してください
- ネットワークベースの検出 → Suricata/Snort のスキルを使用してください
- Volatility を使用したメモリフォレンジック → メモリフォレンジックのスキルを使用してください
- 単純なハッシュベースの検出 → ハッシュリストを使用してください
プラットフォームに関する考慮事項
YARA はあらゆるファイルタイプで動作します。対象に合わせてパターンを調整してください。
| プラットフォーム | マジックバイト | 不審な文字列 | 正常な文字列 |
|---|---|---|---|
| Windows PE | uint16(0) == 0x5A4D | API 名、Windows のパス | ミューテックス名、PDB パス |
| macOS Mach-O | uint32(0) == 0xFEEDFACE (32-bit), 0xFEEDFACF (64-bit), uint32be(0) == 0xCAFEBABE (universal) | 一般的な Obj-C メソッド | キーロガーの文字列、永続化パス |
| JavaScript/Node | (不要) | require、fetch、axios | 難読化ツールのシグネチャ、eval+decode チェーン |
| npm/pip packages | (不要) | postinstall、dependencies | 不審なパッケージ名、データ持ち出し用 URL |
| Office docs | uint32(0) == 0x04034B50 | VBA キーワード | マクロの自動実行、エンコードされたペイロード |
| VS Code extensions | (不要) | vscode.workspace | 一般的でない activationEvents、隠しファイルへのアクセス |
| Chrome extensions | crx モジュールを使用 | 一般的な Chrome API | 権限の悪用、manifest の異常 |
| Android apps | dex モジュールを使用 | 標準的な DEX 構造 | 難読化されたクラス、不審な権限 |
uintNN()はリトルエンディアンで読み取ります。 定数はバイトを逆順にして記述するか、uintNNbe()を使ってファイル上の順序で記述してください。ZIP/OOXML ファイルは50 4B 03 04で始まるため、uint32(0) == 0x04034B50となります。uint32(0) == 0x504B0304は正常にコンパイルされますが、一致することはありません。同じ落とし穴は Mach-O ユニバーサルバイナリにも当てはまります。ディスク上ではCA FE BA BEであるため、uint32(0) == 0xCAFEBABEは決して実行されない分岐になります。uint32be(0) == 0xCAFEBABEまたはuint32(0) == 0xBEBAFECAと記述してください。マジックバイトのチェックを信頼する前に、既知の正常なサンプルを 1 つ使ってyr scanで確認してください。
macOS マルウェアの検出
専用の Mach-O モジュールはまだありません。マジックバイトと文字列パターンを使用してください。有効な指標は次のとおりです。
- キーロガーの痕跡:
CGEventTapCreate、kCGEventKeyDown - SSH トンネルの文字列:
ssh -D、tunnel、socks - 永続化パス:
~/Library/LaunchAgents、/Library/LaunchDaemons - 認証情報の窃取:
security find-generic-password、keychain
// Pattern from Airbnb BinaryAlert
rule SUSP_Mac_ProtonRAT
{
strings:
$lib1 = "SRWebSocket" ascii // Library indicators
$lib2 = "SocketRocket" ascii
$behav1 = "SSH tunnel not launched" ascii // Behavioral indicators
$behav2 = "Keylogger" ascii
condition:
(uint32(0) == 0xFEEDFACF or uint32be(0) == 0xCAFEBABE) and
any of ($lib*) and any of ($behav*)
}
JavaScript の検出
| 対象 | アプローチ |
|---|---|
| npm パッケージ | package.json のパターン、postinstall/preinstall フック、データ持ち出しの組み合わせ:fetch + 環境変数へのアクセス + 認証情報のパス |
| Chrome 拡張機能 | crx モジュール |
| その他の拡張機能 | Manifest のパターン、バックグラウンドスクリプトの動作 |
| 単体の JS | 難読化の特徴(eval+atob、fromCharCode の連鎖)、固有の関数名/変数名、パックされたペイロード |
| Minified/webpack バンドル | バンドル後も残る固有の文字列(URL、マジック値)。関数名は避けてください — 改変されるためです |
有効な JS 文字列: Ethereum の関数セレクター — { a9 05 9c bb } (transfer(address,uint256))、{ 70 a0 82 31 } (balanceOf(address))、ステガノグラフィに使われるゼロ幅文字 — { E2 80 8B E2 80 8C }、難読化ツールのシグネチャ — _0x、var _0x、特定の C2 ドメインや Webhook URL。
不適切な JS 文字列: require、fetch、axios(一般的すぎます)、Buffer、crypto(正当な用途が広くあります)、process.env 単独(具体的な環境変数名が必要です)。
文字列の選定
値の優先順位: ミューテックス名は金、C2 パスは銀、エラーメッセージは銅です。スタック文字列はほぼ常に一意です。文字列が 6 個を超える場合は、過剰に適合させています。
次のいずれかに当てはまる候補文字列は除外してください。
| テスト | 問題点 | 代わりにすること |
|---|---|---|
| 4 バイト未満 | アトムにならない | より長い文字列を探す |
同じバイトの繰り返し(0000、9090) | 弱いアトム | 周囲のコンテキストを加える |
API 名(VirtualAlloc、CreateRemoteThread) | あらゆるパッカーやインストーラーが呼び出す | 呼び出し箇所の 16 進パターンと一意なマーカーを使う |
| Windows のシステムファイルに出現する | 誤検知が必ず発生する | ファミリー固有のものを探す |
よくあるパス(C:\Windows\、cmd.exe) | どこにでもある | マルウェア固有のパスを探す |
| 他のマルウェアファミリーにも出現する | このファミリーを特定できない | ファミリー固有のマーカーと組み合わせる |
残った、このファミリーに固有のものだけをルールの根拠にしてください。
文字列タイプの選択
| 必要なもの | 使用するもの |
|---|---|
| 正確な ASCII/Unicode テキスト | $s = "MutexName" ascii wide |
| 特定のバイトシーケンス | $h = { 4D 5A 90 00 } |
| 変化を含むバイトシーケンス | 16 進ワイルドカード:{ 4D 5A ?? ?? 50 45 } |
| 構造を持つパターン(URL、パス) | 範囲を限定した正規表現:/https:\/\/[a-z]{5,20}\.onion/ |
| 不明なエンコード(XOR、base64) | 修飾子:$s = "config" xor(0x00-0xFF) |
修飾子の適切な使用: 大文字・小文字やエンコードがサンプル間で異なるという確かな根拠がある場合に限り、nocase や wide を使ってください。推測で使ってはいけません。nocase はアトム生成を 2 倍にし、wide は文字列の照合を 2 倍にします。「これらの修飾子を使う明確な理由がなければ、使わないでください」— Kaspersky Applied YARA。
条件の設計
短絡評価の順序は、filesize <、マジックバイト、文字列、モジュールです。条件が 5 行を超える場合は、複数のルールに分割してください。
all of と any of
| 状況 | 使用するもの |
|---|---|
| 文字列がそれぞれマルウェアに固有 | any of them — それぞれ単独で不審 |
| 文字列は一般的だが、組み合わせると不審 | all of them — パターン全体を必須にする |
| 文字列ごとに確度が異なる | グループ化:all of ($core_*) and any of ($variant_*) |
| 誤検知が発生する | 厳しくする:any → all、必須文字列を追加 |
実運用からの教訓: 文字列に fetch、axios、http を含む any of ($network_*) を使ったルールは、ほぼすべての Web アプリケーションに一致しました。認証情報のパス、ネットワーク呼び出し、情報流出先をすべて必須にしたところ、誤検知がなくなりました。
確度によるグループ化
指標の種類によって重みは異なります。C2 ドメインは決定的な証拠になり得ますが、ライブラリのインポートには裏付けが必要です。プレフィックスでグループ化すると、段階的な要件を表現できます。
strings:
$a1 = "SRWebSocket" ascii // Category A: library indicators
$a2 = "SocketRocket" ascii
$b1 = "SSH tunnel" ascii // Category B: behavioral
$b2 = "keylogger" ascii nocase
$c1 = /https:\/\/[a-z0-9]{8,16}\.onion/ // Category C: C2
condition:
filesize < 10MB and
any of ($a*) and any of ($b*) // Evidence from BOTH categories
モジュールとバイトチェック
| 必要なもの | 使用するもの |
|---|---|
| imphash、rich header、authenticode | PE モジュール — 同等の処理を再現するには複雑すぎる |
| マジックバイトまたは単純なオフセット | uint16/uint32 — 高速で、モジュールのオーバーヘッドがない |
| セクション名/サイズ | PE モジュール。ただし、マジックバイトのフィルターを最初に置く |
| Chrome 拡張機能の権限 | crx モジュール — 文字列解析は壊れやすい |
| LNK のターゲットパス | lnk モジュール — フォーマットが複雑 |
「マジックモジュールは避け、代わりに明示的な 16 進チェックを使ってください」— Neo23x0。一般化すると、uint32() で対応できるなら、モジュールを読み込まないでください。
パフォーマンス
- 正規表現は 4 バイト以上のリテラルに固定してください。 固定しないと、ファイルのすべてのオフセットで評価され、致命的な負荷になります。
/http:\/\/.../ではなく、/mshta\.exe http:\/\/.../と記述してください。固定できない場合は、ワイルドカードを使った 16 進パターンを使用してください。 - 正規表現の量指定子にはすべて上限を設定してください。
.*ではなく、.{0,30}を使います。上限のない正規表現は、パフォーマンスを著しく損ない、メモリを大量に消費します。 - filesize を使ってループに上限を設定してください。
filesize < 100KB and for all i in (1..#a) : ...のようにします。上限のない#aは、大きなファイルで数千に達することがあります。 - バイトが固定されている場合は、正規表現より 16 進パターンを優先してください。
書き始める前に:サンプルはパックされていますか?
| シグナル | 対応 |
|---|---|
| エントロピー > 7.0 | パックされている可能性が高いです。まずアンパックされたレイヤーを見つけてください |
| 読み取り可能な文字列がほとんどない、またはまったくない | パックされている可能性が高いです。エントロピー、PE 構造、パッカーのシグネチャを使ってください |
| UPX/MPRESS/カスタムパッカーが検出された | アンパックされたペイロードを対象にするか、パッカー自体を検出してください |
| 読み取り可能な文字列がある | 文字列ベースの検出に進んでください |
パックされたレイヤーを対象にルールを書かないでください。 パッキング方法は変わりますが、ペイロードは変わりません。
文字列でうまくいかない場合は、構造に切り替える
抽出結果が API 名と汎用パスだけの場合:
| 利用できるシグナル | 使用するもの |
|---|---|
| エントロピーの高いセクション | 特定のセクションに対する math.entropy() |
| 変わったインポートパターン | インポートハッシュのクラスタリングに pe.imphash() |
| PE 構造の異常 | セクション名、サイズ、特性 |
| メタデータがある | バージョン情報、タイムスタンプ、リソース |
| 固有の特徴がない | このサンプルは YARA だけでは検出できない可能性があります |
「メタデータ、エントロピー、インポートハッシュなど、一定に保たれるファイルの他のプロパティを利用することもできます。」 — Kaspersky Applied YARA Training
誤検知のデバッグ
- どの文字列が一致しましたか? —
yr scan -s rule.yar false_positive.exe - 正規のライブラリに含まれていますか? —
not $fp_vendor_stringの除外を追加してください - よくある開発パターンですか? — その文字列を、より具体的なものに置き換えてください
- 複数の汎用文字列が同時に一致していますか? — すべてを必須にし、固有のマーカーも加えて条件を厳しくしてください
- よくある手法を使うマルウェアですか? — 手法ではなく、固有の実装の詳細を対象にしてください
アプローチを断念するタイミング
- 抽出結果が API 名とパスだけ → 構造に切り替える
- 固有の文字列を 3 つ見つけられない → パックされている可能性が高いです。アンパックされた版を対象にするか、パッカーを検出してください
- ルールが正規のファイルに一致する → 1~2 件:調査して条件を厳しくしてください。3~5 件:別の指標を探してください。6 件以上:最初からやり直してください
- 最適化後もパフォーマンスが非常に悪い → アーキテクチャの問題です。用途を絞ったルールに分割するか、厳密な事前フィルターを追加してください
- 説明を書くのが難しい → ルールが曖昧すぎます。何を捕捉するのか説明できないなら、捕捉しすぎています
退けるべき自己正当化
次のように考えていることに気づいたら、立ち止まって考え直してください。
| 自己正当化 | 専門家の回答 |
|---|---|
| 「この汎用文字列は十分に固有だ」/「この 16 進数パターンは固有だ」 | 1 つのサンプルで固有 ≠ エコシステム全体で固有です。正規のファイルでテストしてください。直感は当てになりません。 |
| 「yarGen がこの文字列を出してくれた」 | yarGen は候補を提案しますが、検証するのはあなたです。1 つずつ手動で確認してください。80% は破棄することになるでしょう。 |
| 「手元の 10 サンプルでは動く」 | 10 サンプル ≠ 本番環境です。正規のファイルのコーパスを使ってください。 |
| 「すべての亜種を捕捉する 1 つのルール」 | 誤検知の大量発生につながります。特定のファミリーを対象にしてください。 |
| 「誤検知が出たら具体性を高める」/「後で条件を追加する」 | 最初から厳密なルールを書いてください。弱いルールを展開すれば損害が発生し、誤検知は信頼を損ないます。 |
| 「これはハンティング専用だ」 | ハンティングルールは検出ルールになります。求められる品質基準は同じです。 |
| 「API 名があるから悪意のあるファイルだ」 | 正規のソフトウェアも同じ API を使用します。動作の文脈が必要です。 |
「これらのよくある文字列なら any of them で問題ない」 | よくある文字列 + any = 誤検知の大量発生です。any of は、個々に固有の文字列にだけ使ってください。 |
| 「この正規表現なら十分に具体的だ」 | /fetch.*token/ はあらゆる認証コードに一致します。データ窃取先の要件を加えてください。 |
「柔軟にするために .* を使おう」 | 範囲のない正規表現は、パフォーマンスの深刻な低下に加えてメモリを大量に消費します。.{0,30} を使ってください。 |
| 「JavaScript に問題はなさそうだ」 | 攻撃者は正規のコードにインジェクションを仕込みます。eval と decode の連鎖を確認してください。 |
| 「パフォーマンスは重要ではない」 | 遅いルールが 1 つあるだけで、ルールセット全体が遅くなります。アトムを最適化してください。 |
「どこでも --relaxed-re-syntax を使おう」 | 実際のバグが見えなくなります。問題を隠すのではなく、正規表現を修正してください。 |
| 「PEiD のルールはまだ使える」 | 時代遅れです。32 ビットのパッカーは関係ありません。 |
ツールキット
| ツール | 用途 |
|---|---|
| yr CLI | yr check(検証)、yr fmt(フォーマット)、yr scan -s(スキャンして文字列を表示)、yr dump -m pe(構造を調査) |
| yarGen | 候補となる文字列を抽出:yarGen.py -m samples/ --excludegood |
| FLOSS | 難読化された文字列やスタック文字列を抽出:floss sample.exe — yarGenで何も見つからない場合に使用 |
| signature-base | 品質の高い例を調べる |
| YARA-CI | デプロイ前に正常なファイルのコーパスでテスト |
この5つを習得してください。ツールのカタログに気を取られないようにしましょう。
開発サイクル:
yr check rule.yar # syntax, with precise line numbers
yr fmt -w rule.yar # standardize formatting
yr dump -m pe sample.exe --output-format yaml # inspect structure, no dummy rule needed
time yr scan -s rule.yar corpus/ # scan with timing
モジュールで利用できるフィールドの調査、モジュールの条件が一致しない理由のデバッグ、または新しいモジュール(crx、lnk、dotnet)について調べてからルールを記述する場合は、yr dump を使ってください。YARA-Xのエラーメッセージには正確なソース位置が示されます。yr check が15行目と示した場合、問題は15行目にあります。
バージョンによって利用可能な機能: private $helper = "pattern" は一致しても出力には表示されません(v1.3.0+)。// suppress: slow_pattern は特定の警告をインラインで抑制します(v1.4.0+)。filesize < 10_000_000 は数値のアンダースコア表記です(v1.5.0+)。$_unused でも未使用文字列の警告を抑制できます。
Chrome拡張機能の解析(crxモジュール)
YARA-X v1.5.0+ が必要です。permhash() を使用する場合はv1.11.0+が必要です。
主なAPI: crx.is_crx、crx.permissions、crx.permhash()
危険信号: nativeMessaging と downloads の併用、debugger 権限、<all_urls> を対象とするコンテンツスクリプト
import "crx"
rule SUSP_CRX_HighRiskPerms {
condition:
crx.is_crx and
for any perm in crx.permissions : (perm == "debugger")
}
API全体、権限のリスク評価、ルールの例については、crx-module.md を参照してください。
Android DEXの解析(dexモジュール)
YARA-X v1.11.0+ が必要です。従来のYARAのdexモジュールとは互換性がありません — APIはまったく異なります。
主なAPI: dex.is_dex、dex.contains_class()、dex.contains_method()、dex.contains_string()
危険信号: 1文字のクラス名(難読化)、DexClassLoader によるリフレクション、暗号化されたアセット
import "dex"
rule SUSP_DEX_DynamicLoading {
condition:
dex.is_dex and
dex.contains_class("Ldalvik/system/DexClassLoader;")
}
API全体、難読化の検出、ルールの例については、dex-module.md を参照してください。
従来のYARAからの移行
ルールの99%は互換性がありますが、検証がより厳格になります。
yr check --relaxed-re-syntax rules/ # identify issues
# fix each one, then verify without relaxed mode:
yr check rules/
| 問題 | 従来のYARA | YARA-Xでの修正 |
|---|---|---|
正規表現内のリテラル { | /{/ | /\{/ |
| 無効なエスケープ | \R は何もせずリテラル扱い | \\R または R |
| Base64文字列 | 長さの制限なし | 3文字以上が必要 |
| 負のインデックス | @a[-1] | @a[#a - 1] |
| 重複する修飾子 | 許可 | 重複を削除 |
--relaxed-re-syntax は診断用であり、最終的な解決策ではありません。正規表現を修正してください。
命名とメタデータ
{CATEGORY}_{PLATFORM}_{FAMILY}_{VARIANT}_{DATE} e.g. MAL_Win_Emotet_Loader_Jan25
カテゴリ: MAL_(マルウェア)、HKTL_(ハッキングツール)、WEBSHELL_、EXPL_、SUSP_(疑わしいもの)、GEN_(汎用)。プラットフォーム: Win_、Lnx_、Mac_、Android_、CRX_。
すべてのルールに description(「Detects」で始まるもの)、author、reference、date が必要です。
meta:
description = "Detects Example malware via unique mutex and C2 path"
author = "Your Name <[email protected]>"
reference = "https://example.com/analysis"
date = "2025-01-29"
規約の全容については、style-guide.md を参照してください。
ワークフロー
- サンプルを収集する — 複数を用意します。単一サンプルに基づくルールは脆弱です
- 候補を抽出する —
yarGen -m samples/ --excludegood - 品質を検証する — 文字列選定のテストを適用します。yarGen の出力の 80% は破棄することになります
- ルールを作成する — 適切なメタデータを設定し、コストの低いチェックを先に行います
- リントとテストを行う —
yr check、yr fmt、リンタースクリプトを実行します - 正常ファイルで検証する — VirusTotal のコーパス、またはローカルのクリーンなファイルを使います
- デプロイする — 完全なメタデータを設定してから、誤検知を監視します
作業中に確認する品質の目安:既知の亜種の 50% 未満にしか一致しないルールは狭すぎます。正常なファイルに一致するルールは広すぎます。
他の人が作成したルールをレビューする場合 — ルールを目視で読む前に両方のスクリプトを実行し、出力されたコードを引用してください。
uv run "<resolved-yara-lint-path>" suspect.yar # style, metadata, YARA-X compatibility
uv run "<resolved-atom-analyzer-path>" suspect.yar # atom quality per string
ショートカット:"<resolved-review-path>" suspect.yar(ルールファイルまたはディレクトリ)を実行すると、
yr check、yr fmt --check、リンター、アトムアナライザーを 1 回の呼び出しで実行し、
{"target": ..., "checks": {"yr_check", "yr_format", "lint", "atoms"}} という 1 つの JSON オブジェクトを出力します。各チェックには
status(ツールの終了コード)と output が含まれます。
すべてのチェックに合格した場合は 0、いずれかのチェックに失敗した場合は 1、
入力が存在しない、空、または読み取れない場合(何も検査されなかった場合)は 2 で終了します。
個別のスクリプトと同じように、checks.lint.output のコードをそのまま引用してください。
これらのスクリプトは、短い文字列、誤検知につながりやすい部分文字列、上限のない量指定子、
コストの高い項の前に置かれた安価な項といった機械的な問題を検出します。そのため、
人の判断が必要な点、つまり文字列がこのファミリーを特定できるか、
また汎用的な文字列だけで条件が発火しないかに注意を向けられます。
style-guide.md でそれぞれの項目を確認できるように、
指摘事項はコード(E002、W009)で報告してください。
検証ワークフローについては testing.md を、 手順をすべて網羅したガイドについては rule-development.md を参照してください。
よくある間違い
| 間違い | 悪い例 | 良い例 |
|---|---|---|
| API 名を指標にする | "VirtualAlloc" | 呼び出し箇所の 16 進パターン + 一意なミューテックス |
| 上限のない正規表現 | /https?:\/\/.*/ | /https?:\/\/[a-z0-9]{8,12}\.onion/ |
| ファイル形式のフィルターがない | pe.imports(...) を最初に指定 | uint16(0) == 0x5A4D and filesize < 10MB を最初に指定 |
| 短い文字列 | "abc"(3 バイト) | "abcdef"(4 バイト以上) |
| エスケープされていない波括弧(YARA-X) | /config{key}/ | /config\{key\}/ |
| エンディアンが誤ったマジックバイト | uint32(0) == 0xCAFEBABE | uint32be(0) == 0xCAFEBABE |
品質チェックリスト
ルールをデプロイする前に、以下を確認してください。
- 名前が
{CATEGORY}_{PLATFORM}_{FAMILY}_{VARIANT}_{DATE}に従っている - 説明が「Detects」で始まり、検出対象と方法を説明している
- 必須のメタデータ(作成者、参照先、日付)がすべて記載されている
- 文字列が一意であり、API 名、一般的なパス、フォーマット文字列ではない
- すべての文字列が 4 バイト以上で、アトムとして適している
- Base64 修飾子を使うのは 3 文字以上の文字列のみ
- 正規表現に上限があり、リテラルに固定され、
{がエスケープされている - 条件がコストの低いチェック(ファイルサイズ、マジックバイト)から始まっている
- マジックバイトの定数を既知の正常なサンプルと照合して確認している
- ルールが対象のサンプルすべてに一致する
- 正常ファイルのコーパスでルールの一致が 0 件である
-
yr checkとyr fmt --checkに合格する - エラーなしでリンターに合格する
- ピアレビューが完了している
スクリプト
uv run "<resolved-yara-lint-path>" rule.yar # validate style/metadata
uv run "<resolved-atom-analyzer-path>" rule.yar # check string quality
"<resolved-review-path>" rule.yar # all four checks, one JSON result
スクリプトの詳細な説明については、README.md を参照してください。
参考資料
| トピック | ドキュメント |
|---|---|
| 命名規則とメタデータの規約 | style-guide.md |
| パフォーマンスとアトムの最適化 | performance.md |
| 文字列の型と判定 | strings.md |
| テストと検証 | testing.md |
| Chrome 拡張機能モジュール(crx) | crx-module.md |
| Android DEX モジュール(dex) | dex-module.md |
| ルール開発の全プロセス | rule-development.md |
examples/ ディレクトリには、独自のルールを作成する前に読む価値のある、出典が明記された実際のルールが含まれています。
| 例 | 内容 | 出典 |
|---|---|---|
| MAL_Win_Remcos_Jan25.yar | PE マルウェア:段階的な文字列数、ファミリーごとに複数のルール | Elastic Security |
| MAL_Mac_ProtonRAT_Jan25.yar | macOS:Mach-O マジックバイト、複数カテゴリによるグループ化 | Airbnb BinaryAlert |
| MAL_NPM_SupplyChain_Jan25.yar | npm サプライチェーン:実際の攻撃パターン、ERC-20 セレクター | Stairwell Research |
| SUSP_JS_Obfuscation_Jan25.yar | JavaScript:難読化ツールの検出、密度に基づくマッチング | imp0rtp3, Nils Kuhnert |
| SUSP_CRX_SuspiciousPermissions.yar | Chrome 拡張機能:crx モジュール、権限 | 教育用 |
参考になるルールリポジトリ: Neo23x0/signature-base(本番環境向けルール 17,000 件以上)、elastic/protections-artifacts(エンドポイントでテスト済み)、imp0rtp3/js-yara-rules(JavaScript)、InQuest/awesome-yara(厳選されたインデックス)。
ガイド: YARA Style Guide と YARA Performance Guidelines(Neo23x0)、YARA-X documentation。
macOS 固有の情報: Apple 独自の本番用ルールは /System/Library/CoreServices/XProtect.bundle/ に含まれています。objective-see は macOS マルウェアの調査結果とサンプルを公開しています。