using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.IO;
using System.Text;
using NDesk.Options;
/* Description:
Light-weight utility to help maintain an archive of Windows system files.
* Possibly useful for binary diff analysis of MS updates.
*
* Distributed:
* L1pht Offensive Labs http://www.l1pht.com
* Bugs, comments, suggestions saintpatrick@l1pht.com
*
* Feature Requests:
* - Store MD5 information for each file in a searchable database. Neat, but not certain the need is there.
*
* History:
* - 3/20/2010 Built
* - 3/21/2010 Fixed a bug so that it's possible to do crazy stuff like have spaces in folder names ;P (QA win)
*/
namespace binaryeti
{
class Program
{
// This should work across versions
static string systemFolder = Environment.GetFolderPath(Environment.SpecialFolder.System);
static void Main(string[] args)
{
string homepath=string.Empty;
bool help = false;
OptionSet yetiOptions = new OptionSet()
{
{"p|path=","The parent path of the archive",v=>homepath=v},
{"h|help","Show this screen",v => help=v != null},
};
// Let the Yeti have some args. nom nom.
yetiOptions.Parse(args);
if (help)
{
ShowHelp(yetiOptions);
return;
};
// If we have a parent we can do the rest.
if (homepath == string.Empty)
{
ShowHelp(yetiOptions);
}
else
{
DirectoryInfo systemDir = new DirectoryInfo(systemFolder);
string sanitizedFileVersion;
Console.WriteLine("[*] Starting archive process");
foreach (FileInfo file in systemDir.GetFiles())
{
if (file.Extension == ".dll" | file.Extension == ".ocx")
{
string newParentPath = homepath + "\\" + file.Name;
newParentPath = System.Text.RegularExpressions.Regex.Replace(newParentPath, @"""", "");
FileVersionInfo currentFilesVersionInfo = FileVersionInfo.GetVersionInfo(file.FullName);
if (currentFilesVersionInfo.FileVersion != null)
{
sanitizedFileVersion = FilenameStripperPole(currentFilesVersionInfo.FileVersion);
}
else
{
// If I don't have some sort of reliable version I'm using the MD5 of the file.
sanitizedFileVersion = GetMD5HashFromFile(file.FullName);
Console.WriteLine("[*] Had to use MD5 for version folder for file: " + file.Name);
}
if (Directory.Exists(newParentPath)!=true)
{
Directory.CreateDirectory(newParentPath);
}
try
{
if (Directory.Exists(newParentPath + "\\" + sanitizedFileVersion) != true)
{
Directory.CreateDirectory(newParentPath + "\\" + sanitizedFileVersion);
Console.WriteLine("[*] Archiving " + newParentPath + "\\" + sanitizedFileVersion);
File.Copy(file.FullName, newParentPath + "\\" + sanitizedFileVersion + "\\" + file.Name);
}
}
catch (Exception ex)
{
Console.WriteLine("[X] Error archiving due to: " + ex.Message);
}
}
}
Console.WriteLine("[*] Archive process finished");
}
}
///
/// Shows the command line options for the utility
///
/// The NDesk OptionSet created for the utility
static void ShowHelp (OptionSet myoptionset)
{
Console.WriteLine ("Usage: binaryeti [OPTIONS]");
Console.WriteLine();
Console.WriteLine ("Fill out the args and I'll archive your "+ systemFolder +" dlls and ocxs.");
Console.WriteLine ();
Console.WriteLine ("Options:");
myoptionset.WriteOptionDescriptions (Console.Out);
}
///
/// Function to retrieve MD5 hash for a file
///
/// The path of the file to hash
/// A string containing
static string GetMD5HashFromFile(string fullFileName)
{
StringBuilder sb = new StringBuilder();
try
{
FileStream file = new FileStream(fullFileName, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("X2"));
}
}
catch (Exception ex)
{
Console.WriteLine("[X] Error during MD5 hashing of: " + fullFileName);
Console.WriteLine("[X] " + ex.Message);
}
return sb.ToString();
}
///
/// Lame function to strip out invalid directory chars.
///
///
///
static string FilenameStripperPole(string originalString)
{
originalString = originalString.Replace(":", "");
originalString = originalString.Replace("?", "");
originalString = originalString.Replace("<", "");
originalString = originalString.Replace(">", "");
originalString = originalString.Replace("|", "");
return originalString;
}
}
}