Skip to content

Instantly share code, notes, and snippets.

@ericlaw1979
Last active October 14, 2020 11:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericlaw1979/ff937f81a663d6930be720afca92aa3a to your computer and use it in GitHub Desktop.
Save ericlaw1979/ff937f81a663d6930be720afca92aa3a to your computer and use it in GitHub Desktop.
/*
This sample shows how to implement the IOfficeAntiVirus interface in C#
The resulting object, once registered, will calculate the file hash (SHA256/Sha1/MD5) for each file downloaded by Chrome, Edge, and Internet Explorer.
In order to successfully register this object, we'll use REGASM to register the assembly, then run a registry script to add the IOfficeAntiVirus
component category, and we'll delete the "Discardable\PostSetup" cache of known IOfficeAntiVirus implementations so that the next call to the IOfficeAntiVirus
providers will find our new object.
Eric Lawrence
14 November 2007; Updated 5 June 2019
e_lawrence@hotmail.com
//--------------------------------
AddIOAVCat.reg
//--------------------------------
Windows Registry Editor Version 5.00
[-HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\Component Categories\{56FFCC30-D398-11D0-B2AE-00A0C908FA49}]
[HKEY_CLASSES_ROOT\CLSID\{00000000-0002-4746-931C-36014B146679}\Implemented Categories\{56FFCC30-D398-11D0-B2AE-00A0C908FA49}]
//--------------------------------
//--------------------------------
go.bat
//--------------------------------
sn -k IOAV.snk
csc /target:library /keyfile:IOAV.snk showhash.cs
REM C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe ShowHash.dll
regasm ShowHash.dll
gacutil -i ShowHash.dll
AddIOAVCat.reg
//--------------------------------
*/
// IOfficeAntiVirus Reference: http://msdn2.microsoft.com/en-us/library/ms537369.aspx
// Test case for Code Download: http://www.alternatiff.com/install/00/atifxf2a.html
// Info on MarshalAs: http://msdn2.microsoft.com/en-us/library/aa288468(VS.71).aspx
// ComInterop Tutorials: http://msdn2.microsoft.com/en-us/library/aa645712(VS.71).aspx
// Info on building COM servers in .NET: http://www.codeproject.com/useritems/BuildCOMServersInDotNet.asp
// Marshalling unmanaged types: http://msdn2.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype(VS.71).aspx
// Shell Extension for showing file hash: http://www.beeblebrox.org/hashtab/
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
[assembly: AssemblyVersion("1.0.2.5")]
namespace IOAVShowHash
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MSOAVINFO
{
public int cbsize;
[MarshalAs(UnmanagedType.U4)]
public uint uFlags;
public IntPtr hwnd;
// Technically, not quite right, since this could point at a structured storage pointer
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzFullPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzHostname;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzOrigURL;
}
[Guid("56FFCC30-D398-11d0-B2AE-00A0C908FA49"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOfficeAntiVirus
{
// Specify PreserveSig to ensure that non-OK HRESULT is handed back to the caller (instead of throwing an exception)
[PreserveSig]
uint Scan(IntPtr ptr);
}
[Guid("00000000-0002-4746-931C-36014B146679")]
public class ShowHash : IOfficeAntiVirus
{
private string GetFileInfo(string sFilename){
byte[] arrHash;
FileStream fs = new FileStream(sFilename, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite);
StringBuilder sbHash = new StringBuilder();
sbHash.Append("SHA256:\t");
SHA256 shaM = new SHA256Managed();
arrHash = shaM.ComputeHash(fs);
for (int i = 0; i < arrHash.Length; i++)
{
sbHash.Append(arrHash[i].ToString("X2"));
}
fs.Seek(0, SeekOrigin.Begin);
SHA1 sha = new SHA1CryptoServiceProvider();
arrHash = sha.ComputeHash(fs);
sbHash.Append("\nSHA1:\t");
for (int i = 0; i < arrHash.Length; i++)
{
sbHash.Append(arrHash[i].ToString("X2"));
}
fs.Seek(0, SeekOrigin.Begin);
MD5 md5Hasher = MD5.Create();
arrHash = md5Hasher.ComputeHash(fs);
sbHash.Append("\nMD5:\t");
for (int i = 0; i < arrHash.Length; i++)
{
sbHash.Append(arrHash[i].ToString("X2"));
}
sbHash.AppendFormat("\nSize:\t{0:N0}", fs.Length);
fs.Close();
return sbHash.ToString();
}
public uint Scan(IntPtr ptr)
{
bool bReportVirus = false;
try
{
MSOAVINFO oInfo = (MSOAVINFO)Marshal.PtrToStructure(ptr, typeof(MSOAVINFO));
if ((null == oInfo.pwzFullPath) || !File.Exists(oInfo.pwzFullPath))
{
return 0;
}
StringBuilder sbInfo = new StringBuilder();
sbInfo.Append(GetFileInfo(oInfo.pwzFullPath) + "\n\n");
/*
sbInfo.Append(((oInfo.uFlags & 1) > 0) ? "Path:\tyes\n" : "Path:\tno\n");
sbInfo.Append(((oInfo.uFlags & 2) > 0) ? "Readonly:\tyes\n" : "Readonly:\tno\n");
sbInfo.Append(((oInfo.uFlags & 4) > 0) ? "Installed:\tyes\n" : "Installed:\tno\n");
sbInfo.Append(((oInfo.uFlags & 8) > 0) ? "Download:\tyes\n" : "Download:\tno\n");
sbInfo.Append("HWND: " + oInfo.hwnd.ToString() + "\n");
sbInfo.Append("pwzHostname: " + oInfo.pwzHostname + "\n"); // "Urlmon" for ActiveX installs, "SHDOCVW" otherwise
*/
sbInfo.Append("Path:\t" + oInfo.pwzFullPath + "\n");
sbInfo.Append("URL:\t" + oInfo.pwzOrigURL+ "\n");
var p = Process.GetCurrentProcess();
sbInfo.AppendFormat("\nRunning in '{0}' PID: {1}", p.ProcessName, p.Id);
sbInfo.Append("\n(Hit CTRL+C to copy...)");
sbInfo.Append("\nIndicate that this file contains a virus?");
bReportVirus = (DialogResult.Yes == MessageBox.Show(sbInfo.ToString(), "File Hashes",
MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2));
// Alternative implementation where we show hashes without prompting for the user to decide.
// MessageBox.Show(sbInfo.ToString(), "File Hashes", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception eX)
{
MessageBox.Show(eX.ToString(), "Error");
}
/*
0 = S_OK The file was scanned, and no viruses were found.
1 = S_FALSE The file was infected, and the virus was cleaned from the file.
0x80004005 = E_FAIL The file was infected, but the virus could not be cleaned from the file.
ERROR_FILE_NOT_FOUND The file was not found. You must embed ERROR_FILE_NOT_FOUND in an HRESULT before you return it.
*/
return (bReportVirus) ? 0x80004005 : 0;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment