Het is vrij gebruikelijk in organisaties om .NET assemblies te voorzien van een zogeheten strong name. Daar zijn verschillende redenen voor. Als de assembly bijvoorbeeld in de Global Assembly Cache wordt gezet, moet deze een strong name hebben. De standaard policy op een PC met het .NET Framework is ook zo dat assemblies die uitgevoerd worden vanaf een netwerk-lokatie geen FullTrust hebben. Dat betekent dat zo'n assembly niet alles mag (dat ie misschien zou willen). Met het uitrollen van een applicatie in een organisatie kan dan vervelend zijn.
Veel organisaties kiezen er namelijk voor om applicatie-bestanden op een netwerk-schijf te plaatsen. Dat is tenslotte makkelijker bij het uitrollen en bijwerken. Een .NET policy kan er dan voor zorgen dat alleen assemblies die getekend (signed) zijn met het strong name keypair van de organisatie vanaf de netwerklokatie wel met voldoende rechten kan worden gestart. De procedure voor het toepassen van een strong name is tamelijk eenvoudig. Dat wil zeggen, eenvoudig als je beschikt over de broncode van de onderdelen van de .NET applicatie. Componenten van externe partijen beschikken vaak over een eigen strong name. Nu kan je de systeeembeheerders vragen om ook de public key tokens van deze componenten op te nemen in de .NET policy. Maar dat is niet altijd even makkelijk. Het vragen wel, maar de uitvoering ervan. ;-)
Ondanks enig zoekwerk kon ik geen methode vinden om een assembly, gemaakt door een derde partij en voorzien van een strong name door die partij, te voorzien van een andere strong name. Dus, hieronder staat een methode die dit wel mogelijk maakt. De code is te compileren naar een console toepassing en bevat weinig error handling code. Om het wat robuuster te maken is dat wel aan te bevelen.
using System;
using System.IO;
using System.Diagnostics;
namespace AssemblyResign
{
class MainApp
{
/*
* Parameters:
* 1. assembly
* 2. strong keypair
* 3. path for result assembly
*/
[STAThread]
static void Main(string[] args)
{
string assemblyPath = args[0];
string keypairPath = args[1];
string outputPath = args[2];
// create temp path for disassembly
string tempPath = Path.GetTempPath() + "AssemblyResign\\" +
Guid.NewGuid().ToString();
Directory.CreateDirectory(tempPath);
// create output path
if(!Directory.Exists(outputPath)) {
Directory.CreateDirectory(outputPath);
}
string assemblyFileName = Path.GetFileNameWithoutExtension(assemblyPath);
string assemblyType = Path.GetExtension(assemblyPath).Remove(0,1);
// disassemble
string ildasmCommand = "ildasm.exe";
string ildasmArgs = string.Format("{0} /out={1}\\{2}.il", assemblyPath,
tempPath, assemblyFileName);
string ildasmResult = RunCommand(ildasmCommand, ildasmArgs);
if(ildasmResult.ToLower().IndexOf("error") > -1) {
// on error, quit
Console.WriteLine(ildasmResult);
return;
}
// re-assemble
string ilasmCommand = "ilasm.exe";
string ilasmArgs = string.Format("{0}\\{1}.il /output={2}\\{3}.{4} /{4}", tempPath,
assemblyFileName, outputPath, assemblyFileName, assemblyType);
string ilasmResult = RunCommand(ilasmCommand, ilasmArgs);
if(ilasmResult.IndexOf("***** FAILURE *****") > -1) {
// on error, quit
Console.WriteLine(ilasmResult);
return;
}
else {
Console.WriteLine("Operation completed successfully.");
}
}
static string RunCommand(string cmd, string arguments) {
Console.WriteLine("Executing: {0} {1}", cmd, arguments);
ProcessStartInfo ps = new ProcessStartInfo();
ps.FileName = cmd;
ps.Arguments = arguments;
ps.UseShellExecute = false;
ps.RedirectStandardOutput = true;
Process command = new Process();
command.StartInfo = ps;
command.Start();
return command.StandardOutput.ReadToEnd();
}
}
}
Eenmaal gecompileerd, kan dit programma worden aangeroepen als:
AssemblyResign [bestand.dll | bestand.exe] [key.snk] [output-folder]
Zoals je ziet wordt hier gebruik gemaakt van ildasm.exe en ilasm.exe. Ilasm.exe is terug te vinden in de Framework-folder onder de Windows-systeemmap (%windir%). Het programma ildasm.exe is onderdeel van de .NET Framework SDK.