CAS Tamper-Proofing is Broken: Consequences for Software Licensing

Last updated 2009-09-16.


Contents


How Tamper-Proofing Works

The Microsoft .NET Framework has always featured the ability to digitally sign assemblies. One of the reasons for this is that the .NET Framework will refuse to load an assembly whose digital signature does not match the signature in the calling assembly's manifest.

In simple terms, this provides tamper-proofing: if I digitally sign my library and compile against it, you can't replace my library with your own assembly. The only way you could persuade my application to run against your library would be to sign your library with my private key, and you don't have access to that. Microsoft explicitly makes this claim here:

Add a strong name to the assembly. By adding a strong name, you make the assembly tamper proof by digitally signing it.


The Problem

The development of the Reflexil plugin for Reflector has rendered such tamper-proofing ineffectual. It is easy to use Reflexil to undo the digital signing on any assembly, and allow an arbitrary assembly with the same name to be used in its place.


Demonstration

  1. Download and unpack the CasDemo project. This project consists of a command line application called CasDemo and two libraries. One library is signed, and returns false when CasDemo asks it whether it is licensed to run. The other library is unsigned, and returns true.
  2. Download and install Reflector and the Reflexil plugin.
  3. Build CasDemo from Visual Studio (2005 or later) and run it from the command line. You will see that it produces the following output:
    
      H:\CasDemo\CasDemo\bin\Debug>CasDemo.exe
      Licence is not valid.
        
  4. Copy the unsigned assembly into the bin directory and run CasDemo again. You will see that the .NET Framework refuses to run the application, as the unsigned assembly does not match the signed assembly in CasDemo.exe's manifest:
    
      H:\CasDemo\CasDemo\bin\Debug>copy h:\CasDemo\UnsignedLicensing\bin\Debug\CasDemo
        .Licensing.dll .
      Overwrite .\CasDemo.Licensing.dll? (Yes/No/All): y
            1 file(s) copied.
    
      H:\CasDemo\CasDemo\bin\Debug>CasDemo.exe
    
      Unhandled Exception: System.IO.FileLoadException: Could not load file or assembl
      y 'CasDemo.Licensing, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0dee83243
      983b813' or one of its dependencies. The located assembly's manifest definition
      does not match the assembly reference. (Exception from HRESULT: 0x80131040)
      File name: 'CasDemo.Licensing, Version=1.0.0.0, Culture=neutral, PublicKeyToken=
      0dee83243983b813'
      at CasDemo.Program.Main(String[] args)
        
  5. Rebuild CasDemo to ensure that the signed assembly is put back in place.
  6. Open CasDemo.exe with Reflector. Expand References, right-click on CasDemo.Licensing and choose 'Go To Assembly'.
  7. Select the CasDemo.Licensing assembly which should appear under CasDemo. From the menu select Tools -> Reflexil v0.9.
  8. Click the '[Strong Name Remover...]' link at the bottom-right of the window. Click the Select button and choose CasDemo.Licensing.dll. This selects that assembly for strong name removal.
  9. Click the 'Add' button and choose CasDemo.exe. This updates CasDemo.exe to no longer require a strong name from CasDemo.Licensing.dll.
  10. Click 'Remove Strong Name and update referencing assemblies', then close Reflector.
  11. Run CasDemo again from the command line, and you'll see it works just as before:
    
      H:\CasDemo\CasDemo\bin\Debug>CasDemo.exe
      Licence is not valid.
        
  12. Copy the unsigned assembly into the bin directory and run CasDemo again. This time, instead of failure, CasDemo will happily make use of the unsigned assembly:
    
      H:\CasDemo\CasDemo\bin\Debug>copy h:\CasDemo\UnsignedLicensing\bin\Debug\CasDemo
        .Licensing.dll .
      Overwrite .\CasDemo.Licensing.dll? (Yes/No/All): y
      1 file(s) copied.
    
      H:\CasDemo\CasDemo\bin\Debug>CasDemo.exe
      Licence is valid.
        


Consequences for Software Licensing

Code Access Security can no longer be relied upon to prevent the use of tampered assemblies in shipped products. This means that if your application is dependent upon Code Access Security to perform licensing checks, it is trivial for an attacker to replace your licensing assembly with another, thereby gaining free access to your application.

We suggest investigating your existing licensing solution to determine whether it is vulnerable to such an attack. We designed OffByZero Cobalt (our own software licensing solution) so that it does not depend upon Code Access Security for tamper-proofing. If you would like to find out more about OffByZero Cobalt, please sign up for a free trial or contact us directly.