{"componentChunkName":"component---src-templates-post-template-js","path":"/a-part-of-anti-virus-3-03","result":{"data":{"markdownRemark":{"id":"fa82b4c1-b7e1-52c3-9bf4-cf1da73bf3ca","html":"<p>前の章では、WFP フィルターを登録して通信のブロックや許可を行うシンプルなユーザーモードプログラムを解説しました。</p>\n<p>続いて、Antivirus や EDR などのソフトウェアでも広く利用されている WFP Callout ドライバーについて解説を行います。</p>\n<p>WFP の Callout ドライバーについては、公式の Windows-driver-samples リポジトリの <code class=\"language-text\">./network/trans/</code> 配下にいくつかのサンプルプログラムが公開されています。</p>\n<p>特に、このリポジトリ内で公開されている inspect サンプルは WFP Callout ドライバーによるトラフィックインスペクションの基礎的な機能を実装しており、\nAntivirus や EDR による WFP の利用方法に近しいサンプルの 1 つと言えます。</p>\n<p>しかし、このサンプルプログラムはおよそ 3,000 行程度のコードで実装されており、\nWFP の Callout ドライバーの概要から順を追って解説するには少々複雑です。</p>\n<p>そこで、本章では上記の公式のサンプルコードを参考に作成した、\nCallout ドライバーによる基本的なトラフィックの処理を理解するための最小限の機能を持つシンプルなカーネルドライバーのサンプルを使用します。</p>\n<p>本章で解説するサンプルプログラムについても以下のリポジトリからダウンロードすることができます。</p>\n<p>URL: <a href=\"https://github.com/kash1064/book06-wfp-samples\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://github.com/kash1064/book06-wfp-samples</a></p>\n<!-- omit in toc -->\n<h2 id=\"もくじ\" style=\"position:relative;\"><a href=\"#%E3%82%82%E3%81%8F%E3%81%98\" aria-label=\"もくじ permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>もくじ</h2>\n<ul>\n<li>\n<p><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E6%A6%82%E8%A6%81\">サンプルプログラムの概要</a></p>\n<ul>\n<li><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B\">サンプルプログラムを実行する</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E5%AE%9F%E8%A3%85%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\">サンプルプログラムの実装について</a></p>\n<ul>\n<li><a href=\"#%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%82%92%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B\">ドライバーを登録する</a></li>\n<li><a href=\"#callout-%E9%96%A2%E6%95%B0%E3%81%AE%E7%99%BB%E9%8C%B2\">Callout 関数の登録</a></li>\n<li><a href=\"#classifyfn-%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E5%88%86%E9%A1%9E%E5%87%A6%E7%90%86%E7%94%A8%E3%81%AE-callout-%E9%96%A2%E6%95%B0\">classifyFn に登録する分類処理用の Callout 関数</a></li>\n<li><a href=\"#notifyfn-%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E9%80%9A%E7%9F%A5%E5%87%A6%E7%90%86%E7%94%A8%E3%81%AE-callout-%E9%96%A2%E6%95%B0\">notifyFn に登録するイベント通知処理用の Callout 関数</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"#callout-%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8A%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%A2%E3%83%BC%E3%83%89%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%A8%E9%80%A3%E6%90%BA%E3%81%97%E3%81%A6%E3%83%88%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%82%92%E5%88%B6%E5%BE%A1%E3%81%99%E3%82%8B\">Callout ドライバーによりユーザーモードプログラムと連携してトラフィックを制御する</a></p>\n<ul>\n<li><a href=\"#callout-%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%81%A8%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%A2%E3%83%BC%E3%83%89%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E9%80%A3%E6%90%BA\">Callout ドライバーとユーザーモードプログラムの連携</a></li>\n<li><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E5%88%86%E9%A1%9E%E5%87%A6%E7%90%86%E3%81%AE%E4%B8%AD%E6%96%AD%E5%87%A6%E7%90%86\">サンプルプログラムにおける分類処理の中断処理</a></li>\n<li><a href=\"#ioctl-%E3%81%AE%E5%87%A6%E7%90%86\">IOCTL の処理</a></li>\n<li><a href=\"#%E3%83%88%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%81%AE%E5%88%86%E9%A1%9E%E5%87%A6%E7%90%86%E3%82%92%E8%A1%8C%E3%81%86\">トラフィックの分類処理を行う</a></li>\n</ul>\n</li>\n<li><a href=\"#%E3%81%BE%E3%81%A8%E3%82%81\">まとめ</a></li>\n<li><a href=\"#%E3%81%82%E3%81%A8%E3%81%8C%E3%81%8D\">あとがき</a></li>\n<li><a href=\"#%E6%9C%AC%E6%9B%B8%E3%81%AE%E3%82%82%E3%81%8F%E3%81%98\">本書のもくじ</a></li>\n</ul>\n<h2 id=\"サンプルプログラムの概要\" style=\"position:relative;\"><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E6%A6%82%E8%A6%81\" aria-label=\"サンプルプログラムの概要 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>サンプルプログラムの概要</h2>\n<p>本章で解説するサンプルプログラムは、WFP の Callout を理解するために作成した比較的シンプルな Callout ドライバーです。</p>\n<p>このカーネルドライバーは以下の機能を実装しており、特に Antivirus や EDR において重要な WFP Callout の機能をシンプルに実装しています。</p>\n<ol>\n<li>カーネルモードの WFP エンジンへの Callout 関数の登録と、ALE レイヤーに Callout を呼び出すためのフィルターの追加</li>\n<li>システムに常駐するユーザーモードプログラム側での判定結果によるトラフィックのブロック</li>\n<li>特定のアプリケーションに関連するトラフィックのブロック対象からの除外</li>\n</ol>\n<p>なお、1. の操作のうち Callout 関数の登録についてはカーネルドライバー側で行う必要がありますが、\nCallout を呼び出すためのフィルターの追加についてはカーネルモードとユーザーモードのどちらからでも行うことができます。<sup id=\"fnref-1\"><a href=\"#fn-1\" class=\"footnote-ref\">1</a></sup></p>\n<p>そのため、一般的にはフィルターの登録はユーザーモードプログラム側で行われることが多いですが、\n今回のサンプルプログラムではカーネルモードで稼働するドライバー側でフィルターの追加も実装しています。</p>\n<h3 id=\"サンプルプログラムを実行する\" style=\"position:relative;\"><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B\" aria-label=\"サンプルプログラムを実行する permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>サンプルプログラムを実行する</h3>\n<p>このサンプルプログラムをビルドすると以下のファイルが生成されるため、まずはこれらのファイルをすべてテスト署名モードを有効化した仮想マシンにコピーします。</p>\n<ul>\n<li>KernelWFPCalloutDriver.sys</li>\n<li>KernelWFPCalloutDriver.cer</li>\n<li>UserModeCalloutSample.exe</li>\n</ul>\n<p>続いて、コピーした KernelWFPCalloutDriver.sys を KernelWFPCalloutDriver としてシステムに登録します。</p>\n<p>カーネルドライバーのインストールは sc コマンドなどを使用して行うことも可能ですが、\n今回は OSR Driver Loader を使用して以下のようにサービスの登録と実行を行います。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 669px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/cb15dea4396f21dc784a8cb590e07dfe/99272/03-wfp-001.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 129.58333333333334%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAaCAYAAAC3g3x9AAAACXBIWXMAABYlAAAWJQFJUiTwAAADZklEQVRIx4WVW08aURDH9xs0fe2XbvukSR/b9J0+1ESbxtBWRVQUdrnfbyogoCAIGqfnNzDblTbpJpM5u+fMf/5zObPe1y8xub7uObmW4c2NXF1dyXw+F57n52exh/Wm8Dw9Pen68fFRFouFeP1+X7qdjgycHjhA3ofDoYzHY7m9vVWN3N3dvRD2BoOBEuh2u9Lr9eTG2XtnZ2fy5vUr+fzpo5RKZTk9PZWTkxPVSDqdlo5zCOhoNFJhjXGj0ZBsNiuJREKq1aq0Wi3xkkdH4nmefNjekmwuJ3t7e7K/v686CAJlbGBRTRSAAHh8fCyFQmEF+OvgQAG33r2TQrEkOzs7sru7K7FYTPL5fBi2sYsCplIpOTw8lCNHKh6PuwhL4jUbddl+/1bDwwMfm82m5BxbvNdqtRAgCorACnbJZFJ1u90Wj8MttyiXyxrCdDrVZHMYhojv+1IsFhV0MpkoawoDqDmyKDyMAYIZrcNB8gazqODQNOBGgIKRa4qHnQLCgvAANa+0A0L4hEJrsKaygLC2PTTOtG1AJV94YYNwrIKwoL/u7+81VDRCWqL9iGafsJUhhrA0L3zLZDIqsIYdBTMnnLNIohLmkJxgiIax5ZV3UgF71vV6PQwTRlGBaQhobAidDUAvLi6EW8Q31gBfXl4qE2xIBeeMAHtoL5ovEk4+2DhwDU/TVioVZWZniMQEZ7SX1UAByRnsYIExiWWDRscIJwbKGo1YU3MOfX5+ruzDtoEBnnAAKD3ZarUdSDO8rzimICVlWtbv8fgPZ5dXp9goQ6MOIzVSNiTfTRmX08Vi6XK7ahNaZjKZyszNzNlspu+z2Vx7UxubygBqAm0GLgcoEBXE6H8P5ymUZ/cwOkh7vf6a4SpkHDCNHx4eQuF99W0hy+VSz4RFIYfcRRoYVngKgqwWCk0FGVXWk5wdRKIy0T6EEYBMaes5cmGNGp3QMHg5xoZr+TN1PAwpCAwYUzDYnH0A0oO+H+jA2LxySMiQw4Rq1wr522Ck7WI/MyvePwGNxea9tCliArNefyCjsUvFuoC0kv0iQkArArmzO02Tk1e6P+PSkM+6QpQ78i2Zk+/JQH6m3TWsNcRfn4d9OBwMnTza1CFs+6NxK6oVN97qXUn47jcblCVVdKlxTV/Exp1ntBngbxBxbaaPR/NKAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n          <source\n              srcset=\"/static/cb15dea4396f21dc784a8cb590e07dfe/8ac56/03-wfp-001.webp 240w,\n/static/cb15dea4396f21dc784a8cb590e07dfe/d3be9/03-wfp-001.webp 480w,\n/static/cb15dea4396f21dc784a8cb590e07dfe/a6306/03-wfp-001.webp 669w\"\n              sizes=\"(max-width: 669px) 100vw, 669px\"\n              type=\"image/webp\"\n            />\n          <source\n            srcset=\"/static/cb15dea4396f21dc784a8cb590e07dfe/8ff5a/03-wfp-001.png 240w,\n/static/cb15dea4396f21dc784a8cb590e07dfe/e85cb/03-wfp-001.png 480w,\n/static/cb15dea4396f21dc784a8cb590e07dfe/99272/03-wfp-001.png 669w\"\n            sizes=\"(max-width: 669px) 100vw, 669px\"\n            type=\"image/png\"\n          />\n          <img\n            class=\"gatsby-resp-image-image\"\n            src=\"/static/cb15dea4396f21dc784a8cb590e07dfe/99272/03-wfp-001.png\"\n            alt=\"OSR Driver Loader でカーネルドライバーを登録する\"\n            title=\"OSR Driver Loader でカーネルドライバーを登録する\"\n            loading=\"lazy\"\n            style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n          />\n        </picture>\n  </a>\n    </span></p>\n<p>KernelWFPCalloutDriver の登録と実行が完了したら、続いてユーザーモードプログラムである UserModeCalloutSample.exe を実行します。</p>\n<p>この時、実行時コマンドライン引数として permit もしくは block を使用することで、Callout を使用してフィルタリングしたトラフィックを許可するかブロックするかを指定できます。</p>\n<div class=\"gatsby-highlight\" data-language=\"powershell\"><pre class=\"language-powershell\"><code class=\"language-powershell\">UserModeCalloutSample<span class=\"token punctuation\">.</span>exe <span class=\"token namespace\">[permit|block]</span></code></pre></div>\n<p>実際にこのサンプルプログラムを実行してみると、UserModeCalloutSample.exe が Callout ドライバーに指示したトラフィックの処理内容を確認することができます。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 960px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/515d8ca5bdf0d3be3a790f44ff1e4b94/b5cea/03-wfp-002.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 46.666666666666664%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABAUlEQVQoz52SyYqFQAxF304URcW1OIHzPCH+/3+lOYF69JNHL3pxqUpMTt1K+dq2TdCyLKp931XXdWn+OA4ZhkGqqpKmaaTve2nbVtI01bosy8S2bXFdV/UywHVd/wXM81yBnud9AoFN06QAA2Q1wLIsP4BJkug3HFqWJY7jqL46ZL3vW+Z51n3XdVLXtQKBEeOMHmLf9yWKItVXICCAZq7jOKozQDhlj2sO4FZA6aHuA4gAUgSQmEbcmSZgiByA8zwlCAIJw1D1BlJsZvjbITnjzsDZI/LUMM+iKHQMCsSVudYT+IQ+r0ytcU/d2yEB0L8cmsfhF2KPEQ6I41hfG/0AAREPTnRKyQUAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n          <source\n              srcset=\"/static/515d8ca5bdf0d3be3a790f44ff1e4b94/8ac56/03-wfp-002.webp 240w,\n/static/515d8ca5bdf0d3be3a790f44ff1e4b94/d3be9/03-wfp-002.webp 480w,\n/static/515d8ca5bdf0d3be3a790f44ff1e4b94/e46b2/03-wfp-002.webp 960w,\n/static/515d8ca5bdf0d3be3a790f44ff1e4b94/c89f9/03-wfp-002.webp 1140w\"\n              sizes=\"(max-width: 960px) 100vw, 960px\"\n              type=\"image/webp\"\n            />\n          <source\n            srcset=\"/static/515d8ca5bdf0d3be3a790f44ff1e4b94/8ff5a/03-wfp-002.png 240w,\n/static/515d8ca5bdf0d3be3a790f44ff1e4b94/e85cb/03-wfp-002.png 480w,\n/static/515d8ca5bdf0d3be3a790f44ff1e4b94/d9199/03-wfp-002.png 960w,\n/static/515d8ca5bdf0d3be3a790f44ff1e4b94/b5cea/03-wfp-002.png 1140w\"\n            sizes=\"(max-width: 960px) 100vw, 960px\"\n            type=\"image/png\"\n          />\n          <img\n            class=\"gatsby-resp-image-image\"\n            src=\"/static/515d8ca5bdf0d3be3a790f44ff1e4b94/d9199/03-wfp-002.png\"\n            alt=\"UserModeCalloutSample.exe でトラフィックの処理結果を確認する\"\n            title=\"UserModeCalloutSample.exe でトラフィックの処理結果を確認する\"\n            loading=\"lazy\"\n            style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n          />\n        </picture>\n  </a>\n    </span></p>\n<p>また、このサンプルプログラム内では名前解決などに必要な一部のプロセスや、Brave ブラウザーによる通信を許可するように定義されているため、\nblock を指定して UserModeCalloutSample.exe を実行した場合には、Microsoft Edge などのブロック対象のアプリケーションの通信はブロックされるものの、\nBrave ブラウザーなどの許可されたアプリケーションの通信は成功することを確認できます。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 960px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/2cf6c4347553a1f26837645f18e9f577/22c86/03-wfp-003.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 88.33333333333333%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAABYlAAAWJQFJUiTwAAADAElEQVQ4y32US2/TQBDHF/ggfFEOiKegCIkTcOLAUy1FKiAEVQsXLvRJQ9MmtuM0rRvba+/6/Upo/8zaSagqtVF+mvHszOzu7Owye6ghjmOkaUakiKIYRVHA9wMcHTmEjcPDIWHDshwcTmwNDiyS1hGNDyzyscDyKkOWp8gLSpgl4B6HdXyM/sEAB4MBPD9EGKU0gY+hbWNodmG1WkiEhyAOadyDr/RQkl8ANs4BjPD/9xc4rYCTsrEL6wjC8SDdEUZZMw41djrhhP5VE1MkANtLXmE/fgstm4eWKhZgFES5gF71AWvOU/wRz9ASL7EXvYNeLEIv30PL58mvYS+k+OINftuvwZ7HV3B7m+Fei+HWBsONnwyPDIbHJsOcznBn5xoealfxoMNwk8bvtoldgvznNIb77cb+hDO8cK+DaeIHFN1gBbr8DoP0nlxFn+iJVRj+CgxvmeQ3+v6Knv8FBv8M0/sEk3+E6S6h7y2hxxdhiWWwyANinwgaEiITQD6hIEpJTPTCP0Hpj4kKlV+g8jJUPEHlxhj5CZhjx+BOAs9Na1yXTprwOJ0sz+C7GQTZJdkkBUkekpSQjiDodB2XsBHaFiLugHU7GkyzTz11jOHQQRBEEELW7Oy0sLa2jq2tbWxubmNrc6uBvhXbEzbXN/CL/NbX18BUf0kpKZGERz0YBAGqqsJ4PK4bPgwDanbqxTCcyKD245zDcV2YugaXVri/t49eRwfLsuaGKJobk9Q3Jc/zWpZlSbKh0ZsxhYpNkqTWkzgi4ibh1EE5S9qyL4NZwGWcTZxPJmJnHcqygNY/xs6+OVvNVE5R34qLJmRnZ1PbVvVU9VJbUfVs6hvUNoUQokaV52zSqT5LqGZXge12m07dpJfjEJqmYXd3F51OB7quwzAMsnXR7XapvXgdc2nCiFbg0IuiTtF1HVqJj0AKemm8+rVRqO2ORqNZslkNzyecGhxPYDB0YVHTekFMJIjTbFbD84dy4QqnBiFDcHpcRUg9GFNNI0qYpBee8nn9H649LXrTUCZiAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n          <source\n              srcset=\"/static/2cf6c4347553a1f26837645f18e9f577/8ac56/03-wfp-003.webp 240w,\n/static/2cf6c4347553a1f26837645f18e9f577/d3be9/03-wfp-003.webp 480w,\n/static/2cf6c4347553a1f26837645f18e9f577/e46b2/03-wfp-003.webp 960w,\n/static/2cf6c4347553a1f26837645f18e9f577/7e370/03-wfp-003.webp 1143w\"\n              sizes=\"(max-width: 960px) 100vw, 960px\"\n              type=\"image/webp\"\n            />\n          <source\n            srcset=\"/static/2cf6c4347553a1f26837645f18e9f577/8ff5a/03-wfp-003.png 240w,\n/static/2cf6c4347553a1f26837645f18e9f577/e85cb/03-wfp-003.png 480w,\n/static/2cf6c4347553a1f26837645f18e9f577/d9199/03-wfp-003.png 960w,\n/static/2cf6c4347553a1f26837645f18e9f577/22c86/03-wfp-003.png 1143w\"\n            sizes=\"(max-width: 960px) 100vw, 960px\"\n            type=\"image/png\"\n          />\n          <img\n            class=\"gatsby-resp-image-image\"\n            src=\"/static/2cf6c4347553a1f26837645f18e9f577/d9199/03-wfp-003.png\"\n            alt=\"許可されていないアプリケーションによる通信がブロックされる\"\n            title=\"許可されていないアプリケーションによる通信がブロックされる\"\n            loading=\"lazy\"\n            style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n          />\n        </picture>\n  </a>\n    </span></p>\n<h2 id=\"サンプルプログラムの実装について\" style=\"position:relative;\"><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E5%AE%9F%E8%A3%85%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\" aria-label=\"サンプルプログラムの実装について permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>サンプルプログラムの実装について</h2>\n<h3 id=\"ドライバーを登録する\" style=\"position:relative;\"><a href=\"#%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%82%92%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B\" aria-label=\"ドライバーを登録する permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>ドライバーを登録する</h3>\n<p>まず、このカーネルドライバーは WDM ドライバーとして実装しており、初期化を行う DriverEntry 関数内では主に以下の操作を行います。</p>\n<ul>\n<li>デバイス名 (<code class=\"language-text\">SampleWfpCallout</code>) やスピンロック、セマフォ、リストなどのドライバー内で使用するオブジェクトの初期化</li>\n<li>いくつかの必要な IRP ハンドラの初期化</li>\n<li>デバイスオブジェクトの初期化とシンボリックリンクの登録</li>\n<li>WFP Callout フィルターの登録</li>\n</ul>\n<p>今回のサンプルプログラムでは Callout によるトラフィックのブロック判定をシステムに常駐するユーザーモードプログラムに委譲します。</p>\n<p>このため、DriverEntry 関数内では <code class=\"language-text\">IRP_MJ_DEVICE_CONTROL</code> と対応する IRP ハンドラ関数として、\nユーザーモードプログラムとカーネルドライバー間の情報連携を行うための DispatchDeviceControl 関数を登録しています。</p>\n<p>また、この中で呼び出される RegisterCalloutAndFilter 関数内では、Callout 関数や WFP フィルターの登録を行います。</p>\n<p>RegisterCalloutAndFilter 関数内で行う処理の大部分は、2 章で使用したサンプルプログラムによるフィルターの登録操作とほぼ同じであり、\nエンジンへのセッションを開いてトランザクションを開始し、WFP のサブレイヤーやフィルターの登録を行った後にトランザクションをコミットしています。</p>\n<p>しかし、このドライバーは Callout フィルターの登録を行うため、2 章で使用したサンプルプログラムとは異なり、\nFwpsCalloutRegister3 関数や FwpmCalloutAdd 関数による Callout の登録を行います。</p>\n<p>これらの操作の詳細については次の項で解説します。</p>\n<h3 id=\"callout-関数の登録\" style=\"position:relative;\"><a href=\"#callout-%E9%96%A2%E6%95%B0%E3%81%AE%E7%99%BB%E9%8C%B2\" aria-label=\"callout 関数の登録 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Callout 関数の登録</h3>\n<p>サンプルドライバー側で実装されている RegisterCalloutAndFilter 関数では、まず初めに FwpsCalloutRegister3 関数を使用して Callout 関数の登録を行います。<sup id=\"fnref-2\"><a href=\"#fn-2\" class=\"footnote-ref\">2</a></sup></p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">FWPS_CALLOUT3 callout <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\ncallout<span class=\"token punctuation\">.</span>calloutKey <span class=\"token operator\">=</span> CALLOUT_KEY<span class=\"token punctuation\">;</span>\ncallout<span class=\"token punctuation\">.</span>classifyFn <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>FWPS_CALLOUT_CLASSIFY_FN3<span class=\"token punctuation\">)</span>SampleClassify<span class=\"token punctuation\">;</span>\ncallout<span class=\"token punctuation\">.</span>notifyFn <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>FWPS_CALLOUT_NOTIFY_FN3<span class=\"token punctuation\">)</span>SampleNotify<span class=\"token punctuation\">;</span>\ncallout<span class=\"token punctuation\">.</span>flowDeleteFn <span class=\"token operator\">=</span> SampleFlowDelete<span class=\"token punctuation\">;</span>\n\nstatus <span class=\"token operator\">=</span> <span class=\"token function\">FwpsCalloutRegister3</span><span class=\"token punctuation\">(</span>\n            deviceObject<span class=\"token punctuation\">,</span> \n            <span class=\"token operator\">&amp;</span>callout<span class=\"token punctuation\">,</span> \n            <span class=\"token operator\">&amp;</span>gCalloutId\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>FwpsCalloutRegister3 関数は、<code class=\"language-text\">FWPS_CALLOUT3</code> 構造体<sup id=\"fnref-3\"><a href=\"#fn-3\" class=\"footnote-ref\">3</a></sup>の関数ポインターを Callout 関数として登録します。</p>\n<p><code class=\"language-text\">FWPS_CALLOUT3</code> 構造体には、Callout ドライバーが関数ポインターを登録するために必要な情報が定義されています。</p>\n<p>この構造体は以下のように定義されています。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">typedef</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">FWPS_CALLOUT3_</span> <span class=\"token punctuation\">{</span>\n  GUID                                calloutKey<span class=\"token punctuation\">;</span>\n  UINT32                              flags<span class=\"token punctuation\">;</span>\n  FWPS_CALLOUT_CLASSIFY_FN3           classifyFn<span class=\"token punctuation\">;</span>\n  FWPS_CALLOUT_NOTIFY_FN3             notifyFn<span class=\"token punctuation\">;</span>\n  FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN0 flowDeleteFn<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span> FWPS_CALLOUT3<span class=\"token punctuation\">;</span></code></pre></div>\n<p>このパラメーターのうち classifyFn と notifyFn は、それぞれ登録する関数へのポインターと対応しており、<code class=\"language-text\">FWPS_CALLOUT_CLASSIFY_FN3</code> コールバック関数型<sup id=\"fnref-4\"><a href=\"#fn-4\" class=\"footnote-ref\">4</a></sup>および <code class=\"language-text\">FWPS_CALLOUT_NOTIFY_FN3</code> コールバック関数型<sup id=\"fnref-5\"><a href=\"#fn-5\" class=\"footnote-ref\">5</a></sup>へのポインターという形で渡されます。</p>\n<p>今回のコードの場合は、SampleClassify 関数という、このドライバーのコード内で定義している関数を classifyFn に、また SampleNotify 関数を notifyFn にセットしています。</p>\n<p>FwpsCalloutRegister3 関数が登録する関数ポインターに関する情報が定義された <code class=\"language-text\">FWPS_CALLOUT3</code> 構造体には、\nCallout で処理されるネットワークデータが存在する場合に呼び出される Callout 関数である classifyFn (<code class=\"language-text\">FWPS_CALLOUT_CLASSIFY_FN3</code>) と、\nCallout に関するイベントを通知するために呼び出される notifyFn (<code class=\"language-text\">FWPS_CALLOUT_NOTIFY_FN3</code>) の 2 種類の関数ポインターが含まれます。</p>\n<h3 id=\"classifyfn-に登録する分類処理用の-callout-関数\" style=\"position:relative;\"><a href=\"#classifyfn-%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E5%88%86%E9%A1%9E%E5%87%A6%E7%90%86%E7%94%A8%E3%81%AE-callout-%E9%96%A2%E6%95%B0\" aria-label=\"classifyfn に登録する分類処理用の callout 関数 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>classifyFn に登録する分類処理用の Callout 関数</h3>\n<p>このサンプルプログラムでは、分類処理用の Callout 関数として SampleClassify 関数を実装しています。</p>\n<p>分類処理用の Callout 関数は、Callout によってネットワークデータの処理を行う関数で、\nフィルターエンジンからいくつかのデータとともに呼び出しが行われます。<sup id=\"fnref-6\"><a href=\"#fn-6\" class=\"footnote-ref\">6</a></sup></p>\n<p>この分類処理用の Callout 関数の呼び出し時には、<code class=\"language-text\">FWPS_INCOMING_VALUES0</code> 構造体や <code class=\"language-text\">FWPS_INCOMING_METADATA_VALUES0</code> 構造体などの情報がパラメーターとして与えられます。</p>\n<p>まず、分類処理用の Callout 関数に渡される <code class=\"language-text\">FWPS_INCOMING_VALUES0</code> 構造体<sup id=\"fnref-7\"><a href=\"#fn-7\" class=\"footnote-ref\">7</a></sup>は、\n実データである <code class=\"language-text\">FWPS_INCOMING_VALUE0</code> 構造体<sup id=\"fnref-8\"><a href=\"#fn-8\" class=\"footnote-ref\">8</a></sup>を含む形で以下のように定義されています。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">typedef</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">FWPS_INCOMING_VALUE0_</span> <span class=\"token punctuation\">{</span>\n  FWP_VALUE0 value<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span> FWPS_INCOMING_VALUE0<span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">typedef</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">FWPS_INCOMING_VALUES0_</span> <span class=\"token punctuation\">{</span>\n  UINT16               layerId<span class=\"token punctuation\">;</span>\n  UINT32               valueCount<span class=\"token punctuation\">;</span>\n  FWPS_INCOMING_VALUE0 <span class=\"token operator\">*</span>incomingValue<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span> FWPS_INCOMING_VALUES0<span class=\"token punctuation\">;</span></code></pre></div>\n<p><code class=\"language-text\">FWPS_INCOMING_VALUES0</code> 構造体の incomingValue は、実際のデータ (<code class=\"language-text\">FWP_VALUE0</code>) を含む <code class=\"language-text\">FWPS_INCOMING_VALUE0</code> 構造体の配列へのポインターであり、\nvalueCount は incomingValue として与えられた配列内の要素の数です。</p>\n<p>また、同じく分類処理用の Callout 関数にパラメーターとして渡される <code class=\"language-text\">FWPS_INCOMING_METADATA_VALUES0</code> 構造体には、\nフィルターエンジンから Callout 関数に与えられた各種メタデータが含まれます。</p>\n<p>このサンプルプログラムでは <code class=\"language-text\">FWPM_LAYER_ALE_AUTH_CONNECT_V4</code> レイヤーにフィルターを登録しており、\nCallout 関数が使用するランタイムフィルターレイヤー<sup id=\"fnref-9\"><a href=\"#fn-9\" class=\"footnote-ref\">9</a></sup>は <code class=\"language-text\">FWPS_LAYER_ALE_AUTH_CONNECT_V4</code> になります。<sup id=\"fnref-10\"><a href=\"#fn-10\" class=\"footnote-ref\">10</a></sup></p>\n<p>そのため、分類処理用の Callout 関数にパラメーターとして渡される <code class=\"language-text\">FWPS_INCOMING_VALUES0</code> 構造体 (incomingValue) の各データには、\n以下のように <code class=\"language-text\">FWPS_FIELDS_ALE_AUTH_CONNECT_V4</code> 列挙型<sup id=\"fnref-11\"><a href=\"#fn-11\" class=\"footnote-ref\">11</a></sup>の値をデータフィールド識別子として使用してアクセスすることができます。<sup id=\"fnref-12\"><a href=\"#fn-12\" class=\"footnote-ref\">12</a></sup></p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">remoteAddressV4 <span class=\"token operator\">=</span> inFixedValues<span class=\"token operator\">-></span>incomingValue<span class=\"token punctuation\">[</span>FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">.</span>uint32<span class=\"token punctuation\">;</span>\n\nremotePort <span class=\"token operator\">=</span> inFixedValues<span class=\"token operator\">-></span>incomingValue<span class=\"token punctuation\">[</span>FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">.</span>uint16<span class=\"token punctuation\">;</span>\n\nlocalPort <span class=\"token operator\">=</span> inFixedValues<span class=\"token operator\">-></span>incomingValue<span class=\"token punctuation\">[</span>FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">.</span>uint16<span class=\"token punctuation\">;</span>\n\nipProtocol <span class=\"token operator\">=</span> inFixedValues<span class=\"token operator\">-></span>incomingValue<span class=\"token punctuation\">[</span>FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">.</span>uint8<span class=\"token punctuation\">;</span>\n\naleFlags <span class=\"token operator\">=</span> inFixedValues<span class=\"token operator\">-></span>incomingValue<span class=\"token punctuation\">[</span>FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">.</span>uint32<span class=\"token punctuation\">;</span></code></pre></div>\n<p>分類処理のために呼び出された SampleClassify 関数では、さらにパラメーターとして受け取った <code class=\"language-text\">FWPS_INCOMING_METADATA_VALUES0</code> 構造体 (inMetaValues) に含まれるいくつかのメタデータの評価を行います。</p>\n<p>例えば以下では、構造体に設定されているメタデータ値を示すメタデータフィールド識別子 (currentMetadataValues) を参照し、\n<code class=\"language-text\">FWPS_METADATA_FIELD_PROCESS_ID</code> のビットの有無からプロセス ID の情報を取得可能であるか確認し、\n取得可能な場合はそのプロセス ID の情報を processId として保存しています。<sup id=\"fnref-13\"><a href=\"#fn-13\" class=\"footnote-ref\">13</a></sup></p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>inMetaValues<span class=\"token operator\">-></span>currentMetadataValues <span class=\"token operator\">&amp;</span> FWPS_METADATA_FIELD_PROCESS_ID<span class=\"token punctuation\">)</span> <span class=\"token operator\">!=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    processId <span class=\"token operator\">=</span> inMetaValues<span class=\"token operator\">-></span>processId<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>その後、分類処理用の Callout 関数である SampleClassify 関数では、\nCallout 関数に通知されたネットワークトラフィックが「ALE フローの再認証」が要求されたトラフィックであるかを評価し、\n再認証要求ではない場合には FwpsPendOperation0 関数によるトラフィック処理の保留を行います。</p>\n<p>一方で、通知されたネットワークトラフィックが再認証要求されたものである場合には、\nユーザーモードプログラム側の判定結果を元にトラフィックをブロックもしくは許可します。</p>\n<p>このような Callout 関数によるユーザーモードプログラムとの連携については、後の項で解説します。</p>\n<h3 id=\"notifyfn-に登録するイベント通知処理用の-callout-関数\" style=\"position:relative;\"><a href=\"#notifyfn-%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E9%80%9A%E7%9F%A5%E5%87%A6%E7%90%86%E7%94%A8%E3%81%AE-callout-%E9%96%A2%E6%95%B0\" aria-label=\"notifyfn に登録するイベント通知処理用の callout 関数 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>notifyFn に登録するイベント通知処理用の Callout 関数</h3>\n<p>このサンプルプログラムでは、イベント通知用の Callout 関数として SampleNotify 関数を実装しています。</p>\n<p>イベント通知用の Callout 関数は、前項で解説した分類処理用の Callout 関数とは異なり、フィルターの追加や削除などのイベントが発生した場合に呼び出されます。<sup id=\"fnref-14\"><a href=\"#fn-14\" class=\"footnote-ref\">14</a></sup></p>\n<p>このサンプルプログラムではイベント通知用の Callout である SampleNotify 関数は以下の通り非常にシンプルに実装しており、\n発生したイベントの種類に関する情報を含む <code class=\"language-text\">FWPS_CALLOUT_NOTIFY_TYPE</code> 列挙型の値 (notifyType) をパラメーターとして受け取り、\nその結果を元にイベントの発生をデバッグメッセージとして出力します。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>notifyType<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> FWPS_CALLOUT_NOTIFY_ADD_FILTER<span class=\"token operator\">:</span>\n        <span class=\"token function\">DbgPrintEx</span><span class=\"token punctuation\">(</span>\n            DPFLTR_IHVDRIVER_ID<span class=\"token punctuation\">,</span> \n            DPFLTR_INFO_LEVEL<span class=\"token punctuation\">,</span> \n            <span class=\"token string\">\"Sample callout: filter added\\n\"</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">case</span> FWPS_CALLOUT_NOTIFY_DELETE_FILTER<span class=\"token operator\">:</span>\n        <span class=\"token function\">DbgPrintEx</span><span class=\"token punctuation\">(</span>\n            DPFLTR_IHVDRIVER_ID<span class=\"token punctuation\">,</span> \n            DPFLTR_INFO_LEVEL<span class=\"token punctuation\">,</span> \n            <span class=\"token string\">\"Sample callout: filter deleted\\n\"</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n        <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token keyword\">return</span> STATUS_SUCCESS<span class=\"token punctuation\">;</span></code></pre></div>\n<h2 id=\"callout-ドライバーによりユーザーモードプログラムと連携してトラフィックを制御する\" style=\"position:relative;\"><a href=\"#callout-%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8A%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%A2%E3%83%BC%E3%83%89%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%A8%E9%80%A3%E6%90%BA%E3%81%97%E3%81%A6%E3%83%88%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%82%92%E5%88%B6%E5%BE%A1%E3%81%99%E3%82%8B\" aria-label=\"callout ドライバーによりユーザーモードプログラムと連携してトラフィックを制御する permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Callout ドライバーによりユーザーモードプログラムと連携してトラフィックを制御する</h2>\n<p>本章で解説するサンプルプログラムではユーザーモードプログラム側の判定結果を利用して\nCallout ドライバーによるトラフィックのブロックを行います。</p>\n<p>この項では、このサンプルプログラムのコア機能である Callout ドライバーとユーザーモードプログラムの連携について詳しく解説します。</p>\n<h3 id=\"callout-ドライバーとユーザーモードプログラムの連携\" style=\"position:relative;\"><a href=\"#callout-%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%81%A8%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%A2%E3%83%BC%E3%83%89%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E9%80%A3%E6%90%BA\" aria-label=\"callout ドライバーとユーザーモードプログラムの連携 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Callout ドライバーとユーザーモードプログラムの連携</h3>\n<p>WFP の Callout ドライバーは、classifyFn に登録された分類処理用の Callout 関数を使用し、\nCallout 関数が受け取った各パラメーター内の情報をユーザーモードプログラムに転送し、\nユーザーモードプログラム側の判定結果を元にネットワークトラフィックのブロックや許可を行うことができます。</p>\n<p>このような操作は多くの場合非同期的な処理により行われますが、使用するレイヤーにより実現の方法が異なります。</p>\n<p>今回のサンプルプログラムでは ALE Connect レイヤーで処理を行うため、まず FwpsPendOperation0 関数を classifyFn として登録されている関数から呼び出して操作を中断し、\nその後ユーザーモードプログラム側の処理が可能になったタイミングで FwpsCompleteOperation0 関数を呼び出して分類処理を完了します。<sup id=\"fnref-15\"><a href=\"#fn-15\" class=\"footnote-ref\">15</a></sup></p>\n<p>FwpsPendOperation0 関数<sup id=\"fnref-16\"><a href=\"#fn-16\" class=\"footnote-ref\">16</a></sup>は、ユーザーモードプログラムなどによる別の操作の完了を待つ必要のある分類処理を一時中断するために Callout 関数により呼び出されます。</p>\n<p>この関数は以下の通り定義されており、分類処理用の Callout 関数の呼び出し時にパラメーターとして渡される\n<code class=\"language-text\">FWPS_INCOMING_METADATA_VALUES0</code> 構造体に含まれる completionHandle を引数として呼び出され、\nこの中断した操作と対応するハンドルを completionContext として保存します。</p>\n<p>この completionContext に保持されたハンドルは、FwpsCompleteOperation0 関数の呼び出し時に使用します。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">NTSTATUS <span class=\"token function\">FwpsPendOperation0</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">[</span>in<span class=\"token punctuation\">]</span>  HANDLE completionHandle<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">[</span>out<span class=\"token punctuation\">]</span> HANDLE <span class=\"token operator\">*</span>completionContext\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>FwpsCompleteOperation0 関数<sup id=\"fnref-17\"><a href=\"#fn-17\" class=\"footnote-ref\">17</a></sup>は、中断されていた操作を再開するために呼び出される関数で、\n分類処理の中断時に保存した completionContext をパラメーターとして受け取ります。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">void</span> <span class=\"token function\">FwpsCompleteOperation0</span><span class=\"token punctuation\">(</span>\n<span class=\"token punctuation\">[</span>in<span class=\"token punctuation\">]</span>           HANDLE           completionContext<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">[</span>in<span class=\"token punctuation\">,</span> optional<span class=\"token punctuation\">]</span> PNET_BUFFER_LIST netBufferList\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3 id=\"サンプルプログラムにおける分類処理の中断処理\" style=\"position:relative;\"><a href=\"#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E5%88%86%E9%A1%9E%E5%87%A6%E7%90%86%E3%81%AE%E4%B8%AD%E6%96%AD%E5%87%A6%E7%90%86\" aria-label=\"サンプルプログラムにおける分類処理の中断処理 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>サンプルプログラムにおける分類処理の中断処理</h3>\n<p>このサンプルプログラムのカーネルドライバー側では、分類処理用の Callout 関数として登録されている SampleClassify 関数内で以下のように分類処理の中断が行われます。</p>\n<ol>\n<li><code class=\"language-text\">FWPS_INCOMING_VALUES0</code> 構造体 (inFixedValues) に含まれるフィルタリング条件フラグ<sup id=\"fnref-18\"><a href=\"#fn-18\" class=\"footnote-ref\">18</a></sup>を参照し、<code class=\"language-text\">FWP_CONDITION_FLAG_IS_REAUTHORIZE</code> フラグの有無を確認する (新しい接続かどうかを確認する)</li>\n<li>対象が新しい接続の場合、FwpsPendOperation0 関数を呼び出して処理を中断する</li>\n<li>接続要求に関する情報をユーザーモードプログラムとの連携のために、非ページプールに割り当てたメモリ領域 pending に一時保存する</li>\n</ol>\n<p>具体的には、FwpsPendOperation0 の呼び出しから pending への情報の保存については以下のコードで実装しています。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">status <span class=\"token operator\">=</span> <span class=\"token function\">FwpsPendOperation0</span><span class=\"token punctuation\">(</span>\n            <span class=\"token punctuation\">(</span>HANDLE<span class=\"token punctuation\">)</span>inMetaValues<span class=\"token operator\">-></span>completionHandle<span class=\"token punctuation\">,</span>\n            <span class=\"token operator\">&amp;</span>completionContext\n         <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">/* 省略 */</span>\n\nPENDING_CLASSIFY<span class=\"token operator\">*</span> pending <span class=\"token operator\">=</span> \\\n    <span class=\"token punctuation\">(</span>PENDING_CLASSIFY<span class=\"token operator\">*</span><span class=\"token punctuation\">)</span><span class=\"token function\">ExAllocatePool2</span><span class=\"token punctuation\">(</span>\n        POOL_FLAG_NON_PAGED<span class=\"token punctuation\">,</span> \n        <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span>PENDING_CLASSIFY<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> \n        <span class=\"token char\">'pfCW'</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">/* 省略 */</span>\n\n<span class=\"token function\">RtlZeroMemory</span><span class=\"token punctuation\">(</span>pending<span class=\"token punctuation\">,</span> <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>pending<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>RequestId <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>UINT64<span class=\"token punctuation\">)</span><span class=\"token function\">InterlockedIncrement64</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gNextRequestId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>CompletionContext <span class=\"token operator\">=</span> completionContext<span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>ProcessId <span class=\"token operator\">=</span> processId<span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>RemoteAddressV4 <span class=\"token operator\">=</span> remoteAddressV4<span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>RemotePort <span class=\"token operator\">=</span> remotePort<span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>LocalPort <span class=\"token operator\">=</span> localPort<span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>IpProtocol <span class=\"token operator\">=</span> ipProtocol<span class=\"token punctuation\">;</span>\npending<span class=\"token operator\">-></span>Queued <span class=\"token operator\">=</span> TRUE<span class=\"token punctuation\">;</span></code></pre></div>\n<p>上記のコードで保存された情報は、安全な操作のためにスピンロックを確保した後、\nInsertTailList 関数により各リストにエントリを追加します。</p>\n<p>また、KeReleaseSemaphore 関数によりセマフォのカウントのインクリメントも行います。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">KIRQL oldIrql<span class=\"token punctuation\">;</span>\n<span class=\"token function\">KeAcquireSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span>oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token function\">InsertTailList</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gOutstandingList<span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span>pending<span class=\"token operator\">-></span>OutstandingEntry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token function\">InsertTailList</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingQueue<span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span>pending<span class=\"token operator\">-></span>QueueEntry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token function\">KeReleaseSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token function\">KeReleaseSemaphore</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingSemaphore<span class=\"token punctuation\">,</span> IO_NO_INCREMENT<span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span> FALSE<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>これらの情報は、ユーザーモードプログラムとの連携時に使用します。</p>\n<p>SampleClassify 関数が初めての接続に対して以上の中断処理を実施したあと、\n最後にブロックされたデータをイベントログへの記録や監査を行わずにサイレントに削除する <code class=\"language-text\">FWPS_CLASSIFY_OUT_FLAG_ABSORB</code> フラグを使用して <code class=\"language-text\">FWP_ACTION_BLOCK</code> を返します。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">classifyOut<span class=\"token operator\">-></span>actionType <span class=\"token operator\">=</span> FWP_ACTION_BLOCK<span class=\"token punctuation\">;</span>\nclassifyOut<span class=\"token operator\">-></span>flags <span class=\"token operator\">|=</span> FWPS_CLASSIFY_OUT_FLAG_ABSORB<span class=\"token punctuation\">;</span>\nclassifyOut<span class=\"token operator\">-></span>rights <span class=\"token operator\">&amp;=</span> <span class=\"token operator\">~</span>FWPS_RIGHT_ACTION_WRITE<span class=\"token punctuation\">;</span></code></pre></div>\n<p>これで、Callout 関数による接続の中断処理が完了します。</p>\n<h3 id=\"ioctl-の処理\" style=\"position:relative;\"><a href=\"#ioctl-%E3%81%AE%E5%87%A6%E7%90%86\" aria-label=\"ioctl の処理 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>IOCTL の処理</h3>\n<p>このサンプルプログラムでは、<code class=\"language-text\">IRP_MJ_DEVICE_CONTROL</code> と対応する IRP ハンドラ関数として割り当てられた DispatchDeviceControl 関数を使用して、ユーザーモードプログラムとの連携を行います。</p>\n<p>ここでは、ユーザーモードプログラムから DeviceIoControl 関数により送信された以下のいずれかの独自に定義された IOCTL を処理します。</p>\n<ul>\n<li><code class=\"language-text\">IOCTL_WFP_GET_NEXT_REQUEST</code></li>\n<li><code class=\"language-text\">IOCTL_WFP_SUBMIT_DECISION</code></li>\n</ul>\n<p><code class=\"language-text\">IOCTL_WFP_GET_NEXT_REQUEST</code> は、ユーザーモードプログラムが Callout 関数により中断された接続要求に関する情報をカーネルドライバー側から取得するために使用します。</p>\n<p>一方で、<code class=\"language-text\">IOCTL_WFP_SUBMIT_DECISION</code> は、ユーザーモードプログラムがカーネルドライバー側から取得したリクエストに対する判定結果を通知するために使用します。</p>\n<p><code class=\"language-text\">IOCTL_WFP_GET_NEXT_REQUEST</code> の要求は、ユーザーモードプログラム側から以下のコードで呼び出されます。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">BOOL ok <span class=\"token operator\">=</span> <span class=\"token function\">DeviceIoControl</span><span class=\"token punctuation\">(</span>\n    device<span class=\"token punctuation\">,</span>\n    IOCTL_WFP_GET_NEXT_REQUEST<span class=\"token punctuation\">,</span>\n    nullptr<span class=\"token punctuation\">,</span>\n    <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token operator\">&amp;</span>request<span class=\"token punctuation\">,</span>\n    <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token operator\">&amp;</span>bytesReturned<span class=\"token punctuation\">,</span>\n    nullptr<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>パラメーターとして渡される request は <code class=\"language-text\">USER_CLASSIFY_REQUEST</code> 構造体のオブジェクトであり、カーネルドライバー側から分類対象のトラフィックに関する情報を受け取るために使用します。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">typedef</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">_USER_CLASSIFY_REQUEST</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">long</span> <span class=\"token keyword\">long</span> RequestId<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">long</span> <span class=\"token keyword\">long</span> ProcessId<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">long</span> RemoteAddressV4<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">short</span> RemotePort<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">short</span> Reserved<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span> USER_CLASSIFY_REQUEST<span class=\"token punctuation\">;</span></code></pre></div>\n<p>カーネルドライバー側では、<code class=\"language-text\">IOCTL_WFP_GET_NEXT_REQUEST</code> の IOCTL 要求を受け、主に以下の操作を行います。</p>\n<ul>\n<li>ドライバーが停止中でないことを確認し、KeWaitForSingleObject 関数<sup id=\"fnref-20\"><a href=\"#fn-20\" class=\"footnote-ref\">20</a></sup>で gPendingSemaphore がシグナル状態となり保留中のイベントが 1 件以上存在する状態であることを確認する</li>\n<li>保留中のイベントが存在する場合、キューとして設定している gPendingQueue からイベントを 1 つ取り出し、その情報を <code class=\"language-text\">PENDING_CLASSIFY</code> 構造体として保存する</li>\n<li>最後に、ユーザーモードプログラムが DeviceIoControl 関数の呼び出し時に指定した出力バッファーに <code class=\"language-text\">USER_CLASSIFY_REQUEST</code> 構造体と対応する情報を保存する</li>\n</ul>\n<p>上記の操作の内、特にキューから取得した情報をユーザーモードプログラムに渡す処理は主に以下のコードで行われます。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">KIRQL oldIrql<span class=\"token punctuation\">;</span>\nPENDING_CLASSIFY<span class=\"token operator\">*</span> pending <span class=\"token operator\">=</span> nullptr<span class=\"token punctuation\">;</span>\nUSER_CLASSIFY_REQUEST<span class=\"token operator\">*</span> request <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>USER_CLASSIFY_REQUEST<span class=\"token operator\">*</span><span class=\"token punctuation\">)</span>irp<span class=\"token operator\">-></span>AssociatedIrp<span class=\"token punctuation\">.</span>SystemBuffer<span class=\"token punctuation\">;</span>\n\n<span class=\"token function\">KeAcquireSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span>oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token function\">IsListEmpty</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingQueue<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    PLIST_ENTRY queueEntry <span class=\"token operator\">=</span> <span class=\"token function\">RemoveHeadList</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingQueue<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    pending <span class=\"token operator\">=</span> <span class=\"token function\">CONTAINING_RECORD</span><span class=\"token punctuation\">(</span>queueEntry<span class=\"token punctuation\">,</span> PENDING_CLASSIFY<span class=\"token punctuation\">,</span> QueueEntry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    pending<span class=\"token operator\">-></span>Queued <span class=\"token operator\">=</span> FALSE<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">KeReleaseSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>pending <span class=\"token operator\">==</span> nullptr<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    status <span class=\"token operator\">=</span> STATUS_RETRY<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token keyword\">else</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token function\">DbgPrintEx</span><span class=\"token punctuation\">(</span>DPFLTR_IHVDRIVER_ID<span class=\"token punctuation\">,</span> DPFLTR_INFO_LEVEL<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"Sample callout: dispatch request id=%llu pid=%llu\\n\"</span><span class=\"token punctuation\">,</span>\n        pending<span class=\"token operator\">-></span>RequestId<span class=\"token punctuation\">,</span>\n        pending<span class=\"token operator\">-></span>ProcessId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    request<span class=\"token operator\">-></span>RequestId <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>RequestId<span class=\"token punctuation\">;</span>\n    request<span class=\"token operator\">-></span>ProcessId <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>ProcessId<span class=\"token punctuation\">;</span>\n    request<span class=\"token operator\">-></span>RemoteAddressV4 <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>RemoteAddressV4<span class=\"token punctuation\">;</span>\n    request<span class=\"token operator\">-></span>RemotePort <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>RemotePort<span class=\"token punctuation\">;</span>\n    request<span class=\"token operator\">-></span>Reserved <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n    information <span class=\"token operator\">=</span> <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span>USER_CLASSIFY_REQUEST<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    status <span class=\"token operator\">=</span> STATUS_SUCCESS<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>一方、<code class=\"language-text\">IOCTL_WFP_SUBMIT_DECISION</code> と対応する IOCTL 要求を受けた場合、カーネルドライバー側では主に以下の操作を行います。</p>\n<ul>\n<li>ユーザーモードプログラム側から連携されたトラフィックに対する判定結果を保存する</li>\n<li>ユーザーモードプログラムから受け取った情報に含まれる RequestId と一致するトラフィックの情報をリストから取得する</li>\n<li>非ページプール領域にトラフィックの情報やその判定結果を含むエントリを割り当て、<code class=\"language-text\">FWP_CONDITION_FLAG_IS_REAUTHORIZE</code> フラグが ALE フローの再認証要求が発生した場合に参照されるリストに追加する</li>\n<li>保留されている対象のトラフィックに関連するパラメーターを受け取り FwpsCompleteOperation0 関数を実行する</li>\n</ul>\n<p>これらの操作は、主に以下のように実装されています。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\">DECISION_ENTRY<span class=\"token operator\">*</span> decisionEntry <span class=\"token operator\">=</span> \\\n    <span class=\"token punctuation\">(</span>DECISION_ENTRY<span class=\"token operator\">*</span><span class=\"token punctuation\">)</span><span class=\"token function\">ExAllocatePool2</span><span class=\"token punctuation\">(</span>\n        POOL_FLAG_NON_PAGED<span class=\"token punctuation\">,</span> \n        <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span>DECISION_ENTRY<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token char\">'dfCW'</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">/* 省略 */</span>\n\n<span class=\"token function\">RtlZeroMemory</span><span class=\"token punctuation\">(</span>decisionEntry<span class=\"token punctuation\">,</span> <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>decisionEntry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\ndecisionEntry<span class=\"token operator\">-></span>ProcessId <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>ProcessId<span class=\"token punctuation\">;</span>\ndecisionEntry<span class=\"token operator\">-></span>RemoteAddressV4 <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>RemoteAddressV4<span class=\"token punctuation\">;</span>\ndecisionEntry<span class=\"token operator\">-></span>RemotePort <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>RemotePort<span class=\"token punctuation\">;</span>\ndecisionEntry<span class=\"token operator\">-></span>LocalPort <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>LocalPort<span class=\"token punctuation\">;</span>\ndecisionEntry<span class=\"token operator\">-></span>IpProtocol <span class=\"token operator\">=</span> pending<span class=\"token operator\">-></span>IpProtocol<span class=\"token punctuation\">;</span>\ndecisionEntry<span class=\"token operator\">-></span>Block <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>decision<span class=\"token operator\">-></span>Block <span class=\"token operator\">!=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">?</span> TRUE <span class=\"token operator\">:</span> FALSE<span class=\"token punctuation\">;</span>\n\n\n<span class=\"token function\">KeAcquireSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span>oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token function\">InsertTailList</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gDecisionList<span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span>decisionEntry<span class=\"token operator\">-></span>ListEntry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token function\">KeReleaseSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token function\">DbgPrintEx</span><span class=\"token punctuation\">(</span>DPFLTR_IHVDRIVER_ID<span class=\"token punctuation\">,</span> DPFLTR_INFO_LEVEL<span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"Sample callout: submit decision id=%llu block=%lu\\n\"</span><span class=\"token punctuation\">,</span>\n    decision<span class=\"token operator\">-></span>RequestId<span class=\"token punctuation\">,</span>\n    decision<span class=\"token operator\">-></span>Block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token function\">CompleteAndFreePending</span><span class=\"token punctuation\">(</span>pending<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nstatus <span class=\"token operator\">=</span> STATUS_SUCCESS<span class=\"token punctuation\">;</span>\ninformation <span class=\"token operator\">=</span> <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span>USER_CLASSIFY_DECISION<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>これで、ユーザーモードプログラムとの情報連携が行われ、最終的な判定結果を含む情報が、<code class=\"language-text\">FWP_CONDITION_FLAG_IS_REAUTHORIZE</code> フラグが ALE フローの再認証要求が発生した場合に参照されるリストである gDecisionList に追加されます。</p>\n<p>最後に、この判定結果を利用し、Callout 関数にてトラフィックのブロックもしくは許可を行います。</p>\n<h3 id=\"トラフィックの分類処理を行う\" style=\"position:relative;\"><a href=\"#%E3%83%88%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%81%AE%E5%88%86%E9%A1%9E%E5%87%A6%E7%90%86%E3%82%92%E8%A1%8C%E3%81%86\" aria-label=\"トラフィックの分類処理を行う permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>トラフィックの分類処理を行う</h3>\n<p>前述した通り、分類処理用の Callout 関数として登録されている SampleClassify 関数内では、\n初めての接続要求を FwpsPendOperation0 関数により中断し、ユーザーモードプログラム側からの判定結果の受け取りを待機していました。</p>\n<p>その後、ユーザーモードプログラム側から <code class=\"language-text\">IOCTL_WFP_SUBMIT_DECISION</code> と対応する IOCTL 要求を受け取ることで、\nカーネルドライバーでは中断したトラフィックに対して FwpsCompleteOperation0 関数を呼び出します。</p>\n<p>保留中のトラフィックに対して FwpsCompleteOperation0 関数が呼び出されると、ALE フローの再認証要求がトリガーされます。<sup id=\"fnref-21\"><a href=\"#fn-21\" class=\"footnote-ref\">21</a></sup></p>\n<p>その後、この ALE フローの再認証要求に対して再度分類処理用の Callout 関数が呼び出され、今度は以下のコード部分が実行されます。</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>aleFlags <span class=\"token operator\">&amp;</span> FWP_CONDITION_FLAG_IS_REAUTHORIZE<span class=\"token punctuation\">)</span> <span class=\"token operator\">!=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    KIRQL oldIrql<span class=\"token punctuation\">;</span>\n    DECISION_ENTRY<span class=\"token operator\">*</span> decision <span class=\"token operator\">=</span> nullptr<span class=\"token punctuation\">;</span>\n    BOOLEAN block <span class=\"token operator\">=</span> TRUE<span class=\"token punctuation\">;</span>\n\n    <span class=\"token function\">KeAcquireSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span>oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    decision <span class=\"token operator\">=</span> <span class=\"token function\">TakeDecisionLocked</span><span class=\"token punctuation\">(</span>processId<span class=\"token punctuation\">,</span> remoteAddressV4<span class=\"token punctuation\">,</span> remotePort<span class=\"token punctuation\">,</span> localPort<span class=\"token punctuation\">,</span> ipProtocol<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">KeReleaseSpinLock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>gPendingLock<span class=\"token punctuation\">,</span> oldIrql<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>decision <span class=\"token operator\">!=</span> nullptr<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        block <span class=\"token operator\">=</span> decision<span class=\"token operator\">-></span>Block<span class=\"token punctuation\">;</span>\n        <span class=\"token function\">ExFreePoolWithTag</span><span class=\"token punctuation\">(</span>decision<span class=\"token punctuation\">,</span> <span class=\"token char\">'dfCW'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    classifyOut<span class=\"token operator\">-></span>actionType <span class=\"token operator\">=</span> block <span class=\"token operator\">?</span> FWP_ACTION_BLOCK <span class=\"token operator\">:</span> FWP_ACTION_PERMIT<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        classifyOut<span class=\"token operator\">-></span>rights <span class=\"token operator\">&amp;=</span> <span class=\"token operator\">~</span>FWPS_RIGHT_ACTION_WRITE<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token function\">DbgPrintEx</span><span class=\"token punctuation\">(</span>DPFLTR_IHVDRIVER_ID<span class=\"token punctuation\">,</span> DPFLTR_INFO_LEVEL<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"Sample callout: reauth decision pid=%llu action=%s\\n\"</span><span class=\"token punctuation\">,</span>\n        processId<span class=\"token punctuation\">,</span>\n        block <span class=\"token operator\">?</span> <span class=\"token string\">\"BLOCK\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"PERMIT\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>このコードの中では、ユーザーモードプログラム側から受け取った最終的な判定結果を含む情報がリストから取得され、\nその結果に基づいて actionType に <code class=\"language-text\">FWP_ACTION_BLOCK</code> もしくは <code class=\"language-text\">FWP_ACTION_PERMIT</code> を設定することで、\nCallout によるトラフィックのブロックもしくは許可を行っています。</p>\n<h2 id=\"まとめ\" style=\"position:relative;\"><a href=\"#%E3%81%BE%E3%81%A8%E3%82%81\" aria-label=\"まとめ permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>まとめ</h2>\n<p>本章では、WFP Callout ドライバーを用いて、ALE レイヤーでトラフィックを制御する基本的な実装を解説しました。</p>\n<p>本章で解説したユーザーモードプログラムとの連携によるトラフィックの分析などは、\nAntivirus や EDR による WFP 活用の基礎となっています。</p>\n<p>WFP の Callout は本章で扱った内容以外にも、ストリーム検査や再注入など多くの操作を実装できますが、\n本章で解説したサンプルプログラムの実装はこれらを理解するための最小限の土台になると思います。</p>\n<h2 id=\"あとがき\" style=\"position:relative;\"><a href=\"#%E3%81%82%E3%81%A8%E3%81%8C%E3%81%8D\" aria-label=\"あとがき permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>あとがき</h2>\n<p>最後までお読みいただき、ありがとうございました。</p>\n<p>本書では、Windows Filtering Platform (WFP) の基本的なアーキテクチャから、\nユーザーモードでのフィルター登録、そして Callout ドライバーによるトラフィック制御までを、\n段階的に解説してきました。</p>\n<p>特に、Antivirus や EDR における実装の観点で重要になる「どのレイヤーで、どの情報を使って、どのように判定するか」という点について、\nできるだけ実践的な形で理解できるように構成したつもりです。</p>\n<p>一方で、WFP には本書で扱いきれなかったトピックも多く存在します。</p>\n<p>例えば、より複雑なストリームインスペクションや再注入 (re-injection) の動作については、\nAntivirus および EDR のコンテキストで WFP を語る上で、さらに深掘りする価値があると思います。</p>\n<p>本書が、WFP を使ったセキュリティ機能の理解や実装を始める際の足がかりになれば幸いです。</p>\n<h2 id=\"本書のもくじ\" style=\"position:relative;\"><a href=\"#%E6%9C%AC%E6%9B%B8%E3%81%AE%E3%82%82%E3%81%8F%E3%81%98\" aria-label=\"本書のもくじ permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>本書のもくじ</h2>\n<ul>\n<li><a href=\"/a-part-of-anti-virus-3-00\">まえがき</a></li>\n<li><a href=\"/a-part-of-anti-virus-3-01\">1 章 WFP の概要とアーキテクチャ</a></li>\n<li><a href=\"/a-part-of-anti-virus-3-02\">2 章 WFP によるアクセス制御を行うサンプル</a></li>\n<li><a href=\"/a-part-of-anti-virus-3-03\">3 章 Callout ドライバーによるアクセス制御を行うサンプル</a></li>\n</ul>\n<div class=\"footnotes\">\n<hr>\n<ol>\n<li id=\"fn-1\">\n<p>Windows Kernel Programming, Second Edition P.493 (Pavel Yosifovich 著 / Independently published / 2023 年)</p>\n<a href=\"#fnref-1\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-2\">\n<p>FwpsCalloutRegister3 function (fwpsk.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nf-fwpsk-fwpscalloutregister3\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nf-fwpsk-fwpscalloutregister3</a></p>\n<a href=\"#fnref-2\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-3\">\n<p><code class=\"language-text\">FWPS_CALLOUT3</code> structure (fwpsk.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/ns-fwpsk-fwps_callout3\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/ns-fwpsk-fwps_callout3</a></p>\n<a href=\"#fnref-3\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-4\">\n<p><code class=\"language-text\">FWPS_CALLOUT_CLASSIFY_FN3</code> callback function (fwpsk.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nc-fwpsk-fwps_callout_classify_fn3\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nc-fwpsk-fwps<em>callout</em>classify_fn3</a></p>\n<a href=\"#fnref-4\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-5\">\n<p><code class=\"language-text\">FWPS_CALLOUT_NOTIFY_FN3</code> callback function (fwpsk.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nc-fwpsk-fwps_callout_notify_fn3\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nc-fwpsk-fwps<em>callout</em>notify_fn3</a></p>\n<a href=\"#fnref-5\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-6\">\n<p>Processing Classify Callouts <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/processing-classify-callouts\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/processing-classify-callouts</a></p>\n<a href=\"#fnref-6\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-7\">\n<p><code class=\"language-text\">FWPS_INCOMING_VALUES0</code> structure (fwpstypes.h) <a href=\"https://learn.microsoft.com/ja-jp/windows/win32/api/fwpstypes/ns-fwpstypes-fwps_incoming_values0\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows/win32/api/fwpstypes/ns-fwpstypes-fwps<em>incoming</em>values0</a></p>\n<a href=\"#fnref-7\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-8\">\n<p><code class=\"language-text\">FWPS_INCOMING_VALUE0</code> structure (fwpstypes.h) <a href=\"https://learn.microsoft.com/ja-jp/windows/win32/api/fwpstypes/ns-fwpstypes-fwps_incoming_value0\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows/win32/api/fwpstypes/ns-fwpstypes-fwps<em>incoming</em>value0</a></p>\n<a href=\"#fnref-8\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-9\">\n<p>Run-time filtering layer identifiers <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/run-time-filtering-layer-identifiers\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/run-time-filtering-layer-identifiers</a></p>\n<a href=\"#fnref-9\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-10\">\n<p>Filtering layer identifiers <a href=\"https://learn.microsoft.com/ja-jp/windows/win32/fwp/management-filtering-layer-identifiers-#remarks\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows/win32/fwp/management-filtering-layer-identifiers-#remarks</a></p>\n<a href=\"#fnref-10\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-11\">\n<p><code class=\"language-text\">FWPS_FIELDS_ALE_AUTH_CONNECT_V4</code> enumeration (fwpsk.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/ne-fwpsk-fwps_fields_ale_auth_connect_v4_\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/ne-fwpsk-fwps<em>fields</em>ale<em>auth</em>connect<em>v4</em></a></p>\n<a href=\"#fnref-11\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-12\">\n<p>Data field identifiers <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/data-field-identifiers\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/data-field-identifiers</a></p>\n<a href=\"#fnref-12\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-13\">\n<p>Metadata field identifiers <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/metadata-field-identifiers\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/metadata-field-identifiers</a></p>\n<a href=\"#fnref-13\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-14\">\n<p>Processing Notify Callouts <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/processing-notify-callouts\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/processing-notify-callouts</a></p>\n<a href=\"#fnref-14\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-15\">\n<p>Processing Classify Callouts Asynchronously <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/processing-classify-callouts-asynchronously\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/processing-classify-callouts-asynchronously</a></p>\n<a href=\"#fnref-15\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-16\">\n<p>FwpsPendOperation0 function (fwpsk.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nf-fwpsk-fwpspendoperation0\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nf-fwpsk-fwpspendoperation0</a></p>\n<a href=\"#fnref-16\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-17\">\n<p>FwpsCompleteOperation0 function (fwpsk.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nf-fwpsk-fwpscompleteoperation0\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/fwpsk/nf-fwpsk-fwpscompleteoperation0</a></p>\n<a href=\"#fnref-17\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-18\">\n<p>Filtering condition flags <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/filtering-condition-flags\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/filtering-condition-flags</a></p>\n<a href=\"#fnref-18\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-19\">\n<p>Types of Callouts <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/types-of-callouts\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/network/types-of-callouts</a></p>\n<a href=\"#fnref-19\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-20\">\n<p>KeWaitForSingleObject function (wdm.h) <a href=\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject</a></p>\n<a href=\"#fnref-20\" class=\"footnote-backref\">↩</a>\n</li>\n<li id=\"fn-21\">\n<p>Pending Connection Reauthorization <a href=\"https://learn.microsoft.com/ja-jp/windows/win32/fwp/ale-re-authorization#pending-connection-reauthorization\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://learn.microsoft.com/ja-jp/windows/win32/fwp/ale-re-authorization#pending-connection-reauthorization</a></p>\n<a href=\"#fnref-21\" class=\"footnote-backref\">↩</a>\n</li>\n</ol>\n</div>","fields":{"slug":"/a-part-of-anti-virus-3-03","tagSlugs":["/tag/a-part-of-anti-virus-3/","/tag/windows/","/tag/win-dbg/","/tag/anti-virus/"]},"frontmatter":{"date":"2026-04-11","description":"技術書典 20 で頒布した A PART OF ANTI-VIRUS 3 の WEB 版です。","tags":["A PART OF ANTI-VIRUS 3","Windows","WinDbg","AntiVirus"],"title":"A PART OF ANTI-VIRUS 3 - 公開サンプルコードで学ぶ Windows Filtering Platform (WFP) - (WEB 版)【3 章 Callout ドライバーによるアクセス制御を行うサンプル】","socialImage":{"publicURL":"/static/272acc1e889df0e25d89217e89d5fd13/a-part-of-anti-virus-3.png"}}}},"pageContext":{"slug":"/a-part-of-anti-virus-3-03"}},"staticQueryHashes":["251939775","401334301","825871152"]}