Skip to content

Instantly share code, notes, and snippets.

@meklarian
Created May 26, 2010 09:59
Show Gist options
  • Save meklarian/414299 to your computer and use it in GitHub Desktop.
Save meklarian/414299 to your computer and use it in GitHub Desktop.
Source code for a Win32 DLL and a sample C# project demonstrating a single function that can be used to scrub out Persistent-Zone-Identifiers (PZIs) from files.
Source code for a Win32 DLL and a sample C# project demonstrating a single function that can be used to scrub out Persistent-Zone-Identifiers (PZIs) from files.
PZIs are semi-secret NTFS fork attachments that allow PZI-aware applications to detect the origin of content. I believe support for PZIs originated with the release of windows XP.
Anyhow, this function is useful for stripping away the identifiers from downloaded files, thus allowing windows explorer to accept them as bona-fide local content without download warnings.
Caution should be exercised when performing mass-scrubbings of content. Use some judgement if you use these powers to do things on behalf of users that aren't savvy enough to be trusted with all downloaded content.
REF:
IZoneIdentifier
http://msdn.microsoft.com/en-us/library/ms537032(VS.85).aspx
REF:
Scott Hanselman's Computer Zen - Removing Security from Downloaded PowerShell Scripts with Alternative Data Streams
http://www.hanselman.com/blog/CommentView.aspx?guid=6a30d72b-4c9d-4141-b44d-9b074caa833f
REF:
Persistent Zone Identifier Object
http://msdn.microsoft.com/en-us/library/ms537029%28VS.85%29.aspx
Program.cs is provided as an example of how to use the output DLL from a C#/.NET program via P/Invoke. It should be possible to also import PZI support from URLMON.DLL, but probably more trouble than it is worth. Most of the common tasks that are needed, can be wrapped up tidily in a C/C++ unmanaged DLL.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
namespace StripPZIs
{
class Program
{
[DllImport("PZIAdapter.dll", CallingConvention=CallingConvention.StdCall)]
extern static uint StripFilePZI([MarshalAs(UnmanagedType.BStr)]string strFile);
static void StripFile(FileInfo fi, bool verbose)
{
if (verbose)
{
Console.Write("\t\"{0}\"", fi.FullName);
}
StripFilePZI(fi.FullName);
if (verbose)
{
Console.WriteLine(" Cleared");
}
}
static void StripDirectory(DirectoryInfo di, bool verbose, bool recurse)
{
if (verbose)
{
Console.WriteLine("Directory: \"{0}\"", di.FullName);
}
foreach (FileInfo fi in di.GetFiles())
{
StripFile(fi, verbose);
}
if (recurse)
{
foreach (DirectoryInfo subdir in di.GetDirectories())
{
StripDirectory(subdir, verbose, recurse);
}
}
}
static void ShowUsage()
{
Console.WriteLine("StripPZIs.exe - Removes Persistent-Zone-Identifiers from files.");
Console.WriteLine("\tUsage (Directory)");
Console.WriteLine("\t\tStripPZIs.exe «directory-name»");
Console.WriteLine("\tUsage (File)");
Console.WriteLine("\t\tStripPZIs.exe «filename»");
}
static void Main(string[] args)
{
if (args.Length <= 0) { ShowUsage(); return; }
bool verbose = false;
if (args.Length > 1)
{
if (!string.IsNullOrEmpty(args[1]) && args[1].ToLower().Equals("-v"))
{
verbose = true;
}
}
DirectoryInfo di = new DirectoryInfo(args[0]);
if (di.Exists)
{
StripDirectory(di, verbose, true);
return;
}
FileInfo fi = new FileInfo(args[0]);
if (fi.Exists)
{
StripFile(fi, verbose);
}
}
}
}
// PZIAdapter.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "PZIAdapter.h"
// This is an example of an exported function.
PZIADAPTER_API DWORD _stdcall StripFilePZI(BSTR bstrFilename)
{
if(!bstrFilename){return E_INVALIDARG;}
if(::SysStringLen(bstrFilename) <= 0){return E_INVALIDARG;}
if(!(*bstrFilename)){return E_INVALIDARG;}
CComPtr<IPersistFile> pFile;
CComQIPtr<IZoneIdentifier> pZI;
HRESULT hr = ::CoCreateInstance(CLSID_PersistentZoneIdentifier, 0, CLSCTX_ALL, IID_IPersistFile, (LPVOID *)&pFile.p);
if(FAILED(hr)){return hr;}
HRESULT hrOpen = pFile->Load(bstrFilename, STGM_READWRITE);
if(FAILED(hrOpen)){return hrOpen;}
pZI = pFile;
if(!pZI.p){return E_NOINTERFACE;}
HRESULT hrClean = pZI->Remove();
if(FAILED(hrClean)){return hrClean;}
HRESULT hrCommit = pFile->Save(bstrFilename, TRUE);
if(FAILED(hrCommit)){return hrCommit;}
return S_OK;
}
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the PZIADAPTER_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// PZIADAPTER_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef PZIADAPTER_EXPORTS
#define PZIADAPTER_API extern "C" __declspec(dllexport)
#else
#define PZIADAPTER_API extern "C" __declspec(dllimport)
#endif
PZIADAPTER_API DWORD _stdcall StripFilePZI(BSTR bstrFilename);
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
#include <atlbase.h>
#include <atlstr.h>
// NOTE: This line is ABSOLUTELY REQUIRED. Other headers will vary with your flavor of C/C++ build.
#include <urlmon.h>
// REF: http://msdn.microsoft.com/en-us/library/ms537029(VS.85).aspx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment