Technolog

Blogging over technologie.
Welcome to Technolog Sign in | Join | Help
in Search

Todotnet Blog

Assemblies opnieuw signen

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.

Published Thursday, October 12, 2006 3:18 PM by sander
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

eprogrammer said:

Hi Sander!

:lol:

Kan sn.exe niet een assembly van een nieuwe key voorzien?

Groetjes

October 12, 2006 8:56 PM
 

Sander said:

Je zou denken van wel. Bijvoorbeeld met sn -R

 -RAngel <assembly> <infile>

   Re-sign signed or partially signed assembly with the key pair in <infile>.

   If -Ra is used, hashes are recomputed for all files in the assembly.

Maar... dan verschijnt de foutmelding:

Key pair does not match public key from assembly

Dus dat werkt niet. Het kan wel als de assembly compileerd is met het DelaySign attribuut. Maar dat is voor assemblies van derden niet het geval.

October 12, 2006 9:53 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server, by Telligent Systems