All Articles

AMSI の概要と動作について

今回は Windows の AMSI(Windows Antimalware Scan Interface) の概要と動作について簡単なメモ書きとして書きました。

内容はすべて公式ドキュメントやその他 Web サイトに記載の情報、もしくは一般に公開されている書籍などの情報を元に作成しています。

もくじ

AMSI について

AMSI(Windows Antimalware Scan Interface) とは、アプリケーションが処理するデータが悪意のあるものか否かを判断するためにシステムに登録されている AV プロバイダを利用できるインターフェースを提供する機能です。

公開ドキュメントの記載によると、AMSI はファイルやメモリ、ストリームのスキャンや、URL/IP のレピュテーションチェックなどを可能にする呼び出し構造をサポートしているそうです。

参考:マルウェア対策スキャン インターフェイス (AMSI) - Win32 apps | Microsoft Learn

AMSI の機能は Windows の UAC や PowerShell、Office VBA などのいくつかのコンポーネントにも統合されており、これらのアプリケーションを保護しています。

このようなアプリケーションとの統合により、AMSI はスクリプトベースの脅威に対処する目的などで主に使用されます。

アプリケーションの開発者は、AMSI を利用して任意のアプリケーションから任意のコンテンツのスキャン要求を実装することができます。

また、AMSI 自体はアンチマルウェアベンダーに依存しないため、任意のアンチマルウェアベンダーが AMSI を通したスキャン要求を受け取ることができます。

参考:The Rise and Fall of AMSI

AMSI による保護の詳細

AMSI は、特にスクリプトベースのマルウェアにおける文字列連結や難読化などの検出回避のテクニックへの対策として Windows 10 のリリースと同時に登場しました。

AMSI リリース時のブログポストのアーカイブなどを見てみると、PowerShell などを利用したスクリプトベースの脅威やファイルレス攻撃の増加と、その検出回避手法の多様さによる保護のギャップに対する解決策として AMSI が導入されたことがわかります。

参考:Advances in Scripting Security and Protection in Windows 10 and PowerShell V5 | MSRC Blog | Microsoft Security Response Center

参考:Windows 10 to offer application developers new malware defenses - Microsoft Malware Protection Center - Site Home - TechNet Blogs

PowerShell などのアプリケーションは難読化解除のプロセスを経た後のプレーンな攻撃コードを、その実行前に AMSI を通してシステムに登録されているアンチマルウェアエンジンにスキャン要求を行うことができます。

これにより、複雑な難読化が行われている攻撃スクリプトやメモリ内にのみ悪意のあるコードが存在するファイルレス脅威などの検出を効果的に行うことができます。

img

参考:AMSI がマルウェアからの防御にどのように役立つのか - Win32 apps | Microsoft Learn

PowerShell に統合された AMSI の動作

ここからは、PowerShell が AMSI を使用して悪意のあるスクリプトの実行を防止する一連の動作を確認していきます。

幸いなことに、PowerShell は OSS としてソースコードが公開されているため、AMSI との統合の詳細を詳しく確認することができます。

参考:PowerShell/PowerShell: PowerShell for every system!

AMSI の動作テストを行う

まずは、公式のドキュメントに記載の以下のサンプルコードを AMSIPoShscript.ps1 として保存して実行することで、AMSI による実行ブロックをテストしてみます。

# Save this sample AMSI powershell script as AMSI_PoSh_script.ps1
$testString = "AMSI Test Sample: " + "7e72c3ce-861b-4339-8740-0ac1484c1386"
Invoke-Expression $testString

参考:Microsoft Defender for Endpointを使用した AMSI デモンストレーション - Microsoft Defender for Endpoint | Microsoft Learn

これを実行すると、This script contains malicious content and has been blocked by your antivirus software. のエラーとともにスクリプトの実行がブロックされることを確認できます。

image-20250619150701366

続いて、clone したソースコードから独自にビルドした PowerShell でも AMSI の検出テストを実行してみます。(今回は release/v7.5 のコードを使用しています)

PowerShell のビルドは、専用のビルドツールを使用することで簡単に成功しました。(一部エラーは出力されていたものの、.\src\powershell-win-core\bin\Debug\net9.0\win7-x64\publish\pwsh.exe は正常に作成されていました )

Import-Module .\build.psm1
Start-PSBuild -Clean -PSModuleRestore -UseNuGetOrg -Configuration Debug

参考:PowerShell/docs/building/windows-core.md at master · PowerShell/PowerShell

ここで作成したプログラムを含む .\src\powershell-win-core\bin\Debug\net9.0\win7-x64 をまとめてテスト端末にコピーし、再度テストスクリプトを実行してみると、こちらも同じく AMSI による実行ブロックが動作することを確認できました。

image-20250619152750959

PowerShell 側の実装を調べる

公式のドキュメントに添付されていた以下の画像を見ると、PowerShell は AmsiScanBuffer または AmsiScanString を呼び出して AMSI を利用していることがわかります。

img

この関数の呼び出し箇所を辿っていくと、System.Management.Automation/engine/runtime /CompiledScriptBlock.cs の PerformSecurityChecks の関数からPerformSecurityChecks() -> ScanContent() -> WinScanContent() -> AmsiScanBuffer() の順に呼び出されていることがわかりました。

参考:PowerShell/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs at release/v7.5 · PowerShell/PowerShell

PerformSecurityChecks 関数は、直接的にはスクリプトの実行前にコンパイル処理を行う System.Management.Automationの ReallyCompile 関数から呼び出されています。

PerformSecurityChecks 関数の実装を確認すると、AmsiUtils.ScanContent(scriptExtent.Text, scriptFile)AMSI_RESULT_DETECTED を返した場合に ParseError による例外が返されるようです。

private void PerformSecurityChecks()
{
    /* 省略 */
    
    // Call the AMSI API to determine if the script block has malicious content
    var amsiResult = AmsiUtils.ScanContent(scriptExtent.Text, scriptFile);

    if (amsiResult == AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_DETECTED)
    {
        var parseError = new ParseError(
            scriptExtent,
            "ScriptContainedMaliciousContent",
            ParserStrings.ScriptContainedMaliciousContent);
        throw new ParseException(new[] { parseError });
    }

    /* 省略 */  
}

PerformSecurityChecks では、初期化された AmsiUtils クラスの ScanContent を使用して AMSI にスキャン要求が行われます。

ScanContent から呼び出される WinScanContent では、最終的に amsi.dll からロードした AmsiScanBuffer 関数を使用してスキャンを行います。

AmsiNativeMethods.AMSI_RESULT result = AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_CLEAN;

// Run AMSI content scan
int hr;
unsafe
{
    fixed (char* buffer = content)
    {
        var buffPtr = new IntPtr(buffer);
        hr = AmsiNativeMethods.AmsiScanBuffer(
            s_amsiContext,
            buffPtr,
            (uint)(content.Length * sizeof(char)),
            sourceMetadata,
            s_amsiSession,
            ref result);
    }
}

AmsiScanBuffer 関数は、スキャン対象のデータを読み取るためのバッファを受け取ります。

また、複数のスキャン要求を関連づける目的で使用されるセッション情報も amsiSession として受け取ります。

参考:AmsiScanBuffer function (amsi.h) - Win32 apps | Microsoft Learn

参考:Better know a data source: Antimalware Scan Interface

このセッション情報は、アンチマルウェア製品側で様々なスキャン要求を関連づける目的で使用できるように実装されています。

これにより、断片的なデータのみでは判断できない脅威も、各データを関連づけることで検出することができるようになる場合があります。

amsi.dll 側の動作について知る

幸いなことに、PowerShell がロードしている amsi.dll のシンボル情報は Microsoft のパブリックシンボルサーバにて配布されているので比較的容易にデバッグを行うことができます。

しかし、今回は一般に公開されている情報の範囲で記事を作成するため、Evading EDR の 10 章 ANTIMALWARE SCAN INTERFACE の記載を基に amsi.dll 側の動作をまとめることにします。

まず、amsi.dll は、レジストリに登録されている情報を参照して AMSI プロバイダの DLL を読み込みます。

アンチマルウェアベンダーは、レジストリキー HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AMSI\Providers に登録されている COM GUID を使用して AMSI プロバイダをレジストリキーに登録しています。

参考:プロバイダー DLL を AMSI に登録する

例えば、標準では HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AMSI\Providers\{2781761E-28E0-4109-99FE-B9D127C57AFE} が登録されていますが、この GUID と対応するレジストリキーを確認すると、Microsoft Defender のコンポーネントに関する情報が書き込まれており、InprocServer32 のキーの値から MpOav.dll のパスを参照できることが確認できます。

image-20250620145458719

参考:Better know a data source: Antimalware Scan Interface

プロバイダーの DLL をロードし、初期化処理が完了して AMSI を使用可能な状態となると、PowerShell などのアプリケーションから AMSI セッションなどの情報と共に AmsiScanBuffer 関数などによるスキャン要求を受け取れるようになります。

この時、AMSI 側では入力として受け取った各パラメータの妥当性を検証し、パスした場合に amsi!CAmsiAntimalware::Scan を呼び出します。

デフォルトで登録されている Microsoft Defender の AMSI モジュール(MpOav.dll)を使用する場合、AMSI 側で初期化などを行った後、Microsoft Defender ウイルス対策のクライアントインターフェースである MpClient.dll に処理を依頼します。

この後、Microsoft Defender ウイルス対策側でのスキャン結果がアプリケーションに返却されることになり、AMSI_RESULT_DETECTED が返却された場合には実行ブロックが行われます。

参考:Evading EDR | No Starch Press

まとめ

AMSI についての概要をまとめました。

続けて自作のアプリケーションから AMSI スキャン要求を発行する方法とカスタム AMSI プロバイダーを登録する方法について書こうと思っていたのですが、長くなってきたので別の記事に分けることにします。