2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C# - MoTW と Zone.Identifierストリーム

Posted at

はじめに

Excel マクロがブロックされたり、EXE ファイルの実行が SmartScreen によって制限されることがあります。
本記事では、まず、これらの制約の原因となる MoTW(Mark of the Web)と、その実装メカニズムである Zone.Identifier ストリームについて記載します。
その後、C#、PowerShell、コマンドプロンプトでの Zone.Identifier 操作を記載します。

参考情報

テスト環境

ここに記載した情報は、Windows 11 24H2 で動作確認しています。
C#ソースコードは、Visual Studio Community 2022 を利用した下記プロジェクトで生成したモジュールで確認しています。

  • Windows Forms - .NET Framework 4.8
  • Windows Forms - .NET 8
  • WPF - .NET Framework 4.8
  • WPF - .NET 8

Visual Studio 2022 - .NET Framework 4.8 は、C# 7.3 が既定です。
このため、サンプルコードは、基本的に C# 7.3 機能範囲で記述しています。

MoTW と Zone.Identifier ストリーム

MoTW

MoTW(Mark of the Web)は、Windows 独自のセキュリティ機能で、インターネット経由で取得したファイルに適用される属性です。
MoTW が付与されたファイルは、特定の条件下で実行が制限されることがあります。

  • マクロ付きのOfficeファイル(Excel、Wordなど)は、マクロの実行が制限されます
  • スクリプトファイル(.ps1, .vbs, .jsなど)は、 PowerShell スクリプトや VBScript の実行が制限されます
  • 実行ファイル(.exe, .dllなど)は、Windows の SmartScreen フィルターによって実行が制限されます

Zone.Identifier ストリーム

MoTW の実装には、Zone.Identifier ストリームと呼ばれる特殊な NTFS 代替データストリーム(ADS:Alternate Data Streams)が使用されます。
Zone.Identifier ストリームには、ファイルの出所に関する情報が記録されます。

[ZoneTransfer]
ZoneId=3
ReferrerUrl=http://example.com
HostUrl=http://download.example.com/file.exe
  • ZoneId: ファイルの取得元のセキュリティゾーン
  • ReferrerUrl: ダウンロード元の Web ページ URL
  • HostUrl: ファイルを取得したサーバーの URL
  • HostIpAddress: ダウンロード元の IP アドレス(記録されない場合あり)

ブラウザでダウンロードした場合は、Zone.Identifier が作成されます。
PowerShell の Invoke-WebRequest や curl.exe など、一部のコマンドラインツールでは、Zone.Identifier が作成されません。

ZoneIdの種類:

ZoneId 意味 影響
0 ローカルコンピュータ 制限なし
1 ローカルイントラネット 制限なし
2 信頼済みサイト 制限なし
3 インターネット ブロック、もしくは、警告
4 制限付きサイト 基本的にブロック

Chrome、FireFox は独自のセキュリティモデルに基づいて、ZoneId を決定します。
Edge でダウンロードした場合、Windows「インターネットオプション」セキュリティタブの各ゾーンに設定されているサイトに基づいて、ZoneId を決定します。

MoTW-01.png

上記は、ファイル名を指定して実行で「inetcpl.cpl」を入力して起動できます。

マクロ付き Office ファイルの影響:

  • ZoneId=0,1,2 は、マクロの実行が許可されます
  • ZoneId=3 は、保護ビューで開かれ、マクロの実行が制限されます
  • ZoneId=4 は、基本的にブロックされます

スクリプトファイルの影響:

  • ZoneId=0,1,2 は、スクリプト実行が許可されます
  • ZoneId=3 は、Windows のセキュリティ機能(SmartScreen、PowerShell 実行ポリシーなど)によってブロック、もしくは、警告が表示されます
  • ZoneId=4 は、基本的にブロックされます

実行ファイルの影響:

  • ZoneId=0,1,2 は、実行が許可されます
  • ZoneId=3 は、SmartScreen による警告が表示されます
  • ZoneId=4 は、基本的にブロックされます

デジタル署名を付与すると、制限が緩和される場合があります。

アーカイブからの継承

MoTW が付与された(Zone.Identifier ストリームが付与された)アーカイブを解凍したファイルに、対象属性値が継承されるかは、解凍ソフトが Zone.Identifier ストリームをどのように扱うかに依存します。

  • Windows 標準 API を利用した解凍(Explorer、PowerShell Expand-Archive)
    • アーカイブの ZoneId が、解凍後のファイルにも継承されます
    • ZoneId 以外の属性値は継承されないことがあります(ReferrerUrl が、ダウンロード元の Web ページ URLではなく、ローカルの対象アーカイブパスに変更される等)
  • 7zip、WinRAR などのサードパーティーソフト
    • 基本的に、Zone.Identifier は継承されません

C# での操作

Zone.Identifier 存在確認

確認対象 <filename> の場合、<filename>:Zone.Identifier の存在有無で確認できます。

string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
  Console.WriteLine("Zone.Identifier が存在します。");
}
else
{
  Console.WriteLine("Zone.Identifier は存在しません。");
}

Zone.Identifier 内容取得

string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
  // Zone.Identifier 内容取得
  using (var reader = new StreamReader(filePath))
  {
    Console.WriteLine(reader.ReadToEnd());
  }
}
else
{
  Console.WriteLine("Zone.Identifier は存在しません。");
}

Zone.Identifier 削除

Windows 11:
<filename>:Zone.Identifier を System.IO.File.DeleteFile すると、Zone.Identifier のみを削除できます。(後述、Windows 10 以前の手法でも削除可能)

string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
  try
  {
    // Zone.Identifier 削除
    File.Delete(filePath);
  }
  catch
  {
    Console.WriteLine("Zone.Identifier 削除に失敗しました。");
  }
}
else
{
  Console.WriteLine("Zone.Identifier は存在しません。");
} 

Windows 10 以前:
Zone.Identifier のみを削除するには、WIN32API - DeleteFile 利用が必要です。

string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
  // Zone.Identifier 削除
  if (NativeMethods.DeleteFile(filePath))
  {
    Console.WriteLine("Zone.Identifier を削除しました。");
  }
  else
  {
    Console.WriteLine("Zone.Identifier 削除に失敗しました。");
  }
}
else
{
  Console.WriteLine("Zone.Identifier は存在しません。");
} 
private static class NativeMethods
{
  // WIN32QPI
  [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
  public static extern bool DeleteFile(string name);
}

WIN32API を直接記述していますが、Microsoft が提供している CsWin32 を利用するという手もあります。

Zone.Identifier 更新

string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
var sb = new StringBuilder();
sb.AppendLine("[ZoneTransfer]");
sb.AppendLine("ZoneId=3");
sb.Append("ReferrerUrl=https://example.com");

try
{
  // Zone.Identifier 更新
  File.WriteAllText(filePath, sb.ToString());
}
catch
{
  Console.WriteLine("Zone.Identifier 更新に失敗しました。");
}

PowerShell での操作

Zone.Identifier 存在確認

Get-Item -Path "C:\path\to\hoge.exe" -Stream Zone.Identifier

Zone.Identifier 内容表示

Get-Content -Path "C:\path\to\hoge.exe" -Stream Zone.Identifier

Zone.Identifier 削除

対象ファイルの Zone.Identifier 削除は、2パターン存在します。

Remove-Item -Path "C:\path\to\hoge.exe" -Stream Zone.Identifier
Unblock-File -Path "C:\path\to\hoge.exe"

フォルダ内のすべてのファイルを対象として、Zone.Identifier 削除は下記で可能です。

Get-ChildItem -Path "C:\path\to\folder" -Recurse | Unblock-File

Zone.Identifier 更新

# 既存のファイルの Zone.Identifier を上書き(完全に置き換える)
Set-Content -Path "C:\path\to\hoge.exe" -Stream "Zone.Identifier" -Value @(
"[ZoneTransfer]", "ZoneId=3", "ReferrerUrl=https://example.com")

# 既存のファイルの Zone.Identifier を保持し、新しいデータを追記
Add-Content -Path "C:\path\to\hoge.exe" -Value "追加の内容"

コマンドプロンプトでの操作

NTFS 代替データストリーム(ADS)を調査・管理するためのツールとして、Steram.exe - Sysinternals | Microsoft Learn が提供されていますが、標準コマンドの範囲で記載します。

Zone.Identifier 存在確認

dir を /r オプションで実行して <filename> とペアで <filename>:Zone.Identifier:$DATA が存在するか否かで確認できます。 

dir <対象フォルダパス> /r
2025/06/01 00:00    1,234,567 hoge.zip
                          257 hoge.zip:Zone.Identifier:$DATA

Zone.Identifier 内容表示

more を利用することで、Zone.Identifier を表示することができます。

more < hoge.zip:Zone.Identifier
[ZoneTransfer]
ZoneId=3
ReferrerUrl=http://example.com
HostUrl=http://download.example.com/file.exe
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?