Author Topic: Using Strong Name Signatures to protect our assemblies  (Read 4353 times)

0 Members and 1 Guest are viewing this topic.

exmachina

  • Guest
Using Strong Name Signatures to protect our assemblies
« on: March 10, 2014, 03:26:47 PM »
Some basic rules about ofuscation and protection:
  • The best obfuscator is that you can create, if you don't have time you can buy one.
  • The best protection is the infrastructure and logic that developer designed-> the complexity of the application

Strong Name Signatures
  • An strong name signature itself is not a protection, but we can use those bytes to make it difficult for some crackers.
  • These techniques are not applicable to autocad .NET addin's
  • If you don't know what is a strong name signature, search on the internet. There is much information

There is an urban legend that says that the tampered assemblies cannot be registered in the GAC... but this is another topic


We can use the signature to protect our assemblies in several ways, one of them is that assembly verify their own integrity:

(The message exceeds the maximum allowed length, Form1.cs contains the full source code)

Code - C#: [Select]
  1. using System;
  2. using System.Reflection;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Windows.Forms;
  7.  
  8. namespace selfverification
  9. {
  10.     public partial class Form1 : Form
  11.     {
  12.         public Form1()
  13.         {
  14.             InitializeComponent();
  15.             if (!StrongNameHelper.VerifyStrongName())
  16.             {
  17.                 // The assembly is tampered so:
  18.                 // Application.Exit();, or:
  19.                 while (true)
  20.                 {}
  21.             }
  22.         }
  23.     }
  24.  
  25.     internal static class StrongNameHelper
  26.     {
  27.  
  28.         private static Guid CLSID_CLRMetaHost =
  29.             new Guid(0x9280188D, 0xE8E, 0x4867, 0xB3, 0xC, 0x7F, 0xA8, 0x38, 0x84, 0xE8, 0xDE);
  30.  
  31.         private static Guid CLSID_CLRStrongName =
  32.             new Guid(0xb79b0acd, 0xf5cd, 0x409b, 0xb5, 0xa5, 0xa1, 0x62, 0x44, 0x61, 11, 0x92);
  33.  
  34.         private static Guid IID_CLRStrongName =
  35.             new Guid(0x9fd93ccf, 0x3280, 0x4391, 0xb3, 0xa9, 150, 0xe1, 0xcd, 0xe7, 0x7c, 0x8d);
  36.  
  37.         private static Guid IID_ICLRMetaHost =
  38.             new Guid(0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16);
  39.  
  40.         private static Guid IID_ICLRRuntimeInfo =
  41.             new Guid(0xbd39d1d2, 0xba2f, 0x486a, 0x89, 0xb0, 180, 0xb0, 0xcb, 70, 0x68, 0x91);
  42.  
  43.         [DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
  44.         internal static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);
  45.  
  46.         [DllImport("mscoree.dll", EntryPoint = "CLRCreateInstance")]
  47.         private static extern int CLRCreateInstance(ref Guid clsid, ref Guid riid, ref IntPtr ppInterface);
  48.  
  49.         internal static bool VerifyStrongName()
  50.         {
  51.             // NOTE:
  52.            //encodedKey == Convert.ToBase64String(YOUR_ASSEMBLY.GetName().GetPublicKeyToken());
  53.             string encodedKey = "lCvfqUGP9m8="; //encodedKey
  54.             if ((Environment.Version.Major >= 4))
  55.                 return VerifyStrongNameCLR4(encodedKey);
  56.                 return VerifyStrongNameCLR2(encodedKey);
  57.         }
  58.  
  59.         internal static bool VerifyStrongNameCLR2(string encodedKey)
  60.         {
  61.             bool result = false;
  62.             try
  63.             {
  64.                 if (!string.IsNullOrEmpty(encodedKey))
  65.                 {
  66.                     byte[] buffer = Convert.FromBase64String(encodedKey);
  67.  
  68.                     byte[] publicKeyToken = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();
  69.                     for (int i = 0; i < buffer.Length; i++)
  70.                     {
  71.                         if (buffer[i] != publicKeyToken[i])
  72.                             return false;
  73.                     }
  74.                 }
  75.                 bool wasVerified = false;
  76.                 string location = Assembly.GetExecutingAssembly().Location;
  77.                 if (string.IsNullOrEmpty(location))
  78.                 {
  79.                     result = true;
  80.                 }
  81.                 else
  82.                 {
  83.                     bool ret = StrongNameSignatureVerificationEx(location, true, ref wasVerified);
  84.                     result = wasVerified && ret;
  85.                 }
  86.             }
  87.             catch (Exception)
  88.             {
  89.             }
  90.             return result;
  91.         }
  92.  
  93.         internal static bool VerifyStrongNameCLR4(string encodedKey)
  94.         {
  95.             bool result = false;
  96.             try
  97.             {
  98.                 if (!string.IsNullOrEmpty(encodedKey))
  99.                 {
  100.                     byte[] buffer = Convert.FromBase64String(encodedKey);
  101.  
  102.                     byte[] publicKeyToken = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();
  103.                     for (int i = 0; i < buffer.Length; i++)
  104.                     {
  105.                         if (buffer[i] != publicKeyToken[i])
  106.                             return false;
  107.                     }
  108.                 }
  109.                 string location = Assembly.GetExecutingAssembly().Location;
  110.                 result = string.IsNullOrEmpty(location) || VerifyStrongNameCLR4_internal(location);
  111.             }
  112.             catch (Exception)
  113.             {
  114.             }
  115.             return result;
  116.         }
  117.  
  118.         private static bool VerifyStrongNameCLR4_internal(string path)
  119.         {
  120.             ICLRMetaHost metaHost = null;
  121.             ICLRRuntimeInfo runtimeInfo = null;
  122.             ICLRStrongName strongName = null;
  123.             try
  124.             {
  125.                 IntPtr pointer = IntPtr.Zero;
  126.                 if ((CLRCreateInstance(ref CLSID_CLRMetaHost, ref IID_ICLRMetaHost, ref pointer) == 0) && (pointer != IntPtr.Zero))
  127.                 {
  128.                     metaHost = Marshal.GetObjectForIUnknown(pointer) as ICLRMetaHost;
  129.                     Marshal.Release(pointer);
  130.                     string str = Environment.Version.ToString();
  131.                     string version = "v" + str.Substring(0, str.LastIndexOf('.'));
  132.                     pointer = metaHost.GetRuntime(version, ref IID_ICLRRuntimeInfo);
  133.                     if (pointer != IntPtr.Zero)
  134.                     {
  135.                         runtimeInfo = Marshal.GetObjectForIUnknown(pointer) as ICLRRuntimeInfo;
  136.                         Marshal.Release(pointer);
  137.                         pointer = IntPtr.Zero;
  138.                         pointer = runtimeInfo.GetInterface(ref CLSID_CLRStrongName, ref IID_CLRStrongName);
  139.                         if (pointer != IntPtr.Zero)
  140.                         {
  141.                             strongName = Marshal.GetObjectForIUnknown(pointer) as ICLRStrongName;
  142.                             Marshal.Release(pointer);
  143.                             sbyte wasVerified = 0;
  144.                             sbyte ret = strongName.StrongNameSignatureVerificationEx(path, 1, ref wasVerified);
  145.                             return ((ret == 0) && (wasVerified != 0));
  146.                         }
  147.                     }
  148.                 }
  149.             }
  150.             finally
  151.             {
  152.                 if (strongName != null)
  153.                 {
  154.                     Marshal.ReleaseComObject(strongName);
  155.                 }
  156.                 if (runtimeInfo != null)
  157.                 {
  158.                     Marshal.ReleaseComObject(runtimeInfo);
  159.                 }
  160.                 if (metaHost != null)
  161.                 {
  162.                     Marshal.ReleaseComObject(metaHost);
  163.                 }
  164.             }
  165.             return false;
  166.         }
  167.     }
  168.     [ComImport, Guid("D332DB9E-B9B3-4125-8207-A14884F53216"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  169.     internal interface ICLRMetaHost
  170.     {
  171.       ...
  172.     }
  173.  
  174.  
  175.     [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("BD39D1D2-BA2F-486A-89B0-B4B0CB466891")]
  176.     internal interface ICLRRuntimeInfo
  177.     {
  178.        ...
  179.     }
  180.  
  181.     [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss, Guid("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D")]
  182.     internal interface ICLRStrongName
  183.     {
  184.         ...
  185.     }
  186.  
  187.     [ComImport, Guid("00000100-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  188.     internal interface IEnumUnknown
  189.     {
  190.        ...
  191.     }
  192. }


As you can see is simple.

Some tips:
  • Never show a message pointing the "problem" - remember that you're not a friend of the cracker.
  • If you raise and a error maybe you'll be giving clues...
  • "Divide et vinces". Separates the logic of your application at various assemblies and add license verification and signature verification to all of them
  • Uses "timed" threads from where you verify the signature
  • Do not use this directly in the constructor of the main form or in the entry point (usually main())


Next week more

« Last Edit: March 10, 2014, 03:37:43 PM by jar »

CADbloke

  • Bull Frog
  • Posts: 345
  • Crash Test Dummy
Re: Using Strong Name Signatures to protect our assemblies
« Reply #1 on: March 10, 2014, 04:49:56 PM »

Strong Name Signatures
  • ...
  • These techniques are not applicable to autocad .NET addin's
  • ...

If so then why is this here?

btw - see also Code Signing Certificates for verifying if assemblies have been tampered with.

exmachina

  • Guest
Re: Using Strong Name Signatures to protect our assemblies
« Reply #2 on: March 10, 2014, 05:24:24 PM »
If so then why is this here?
I do not see where the problem, in this forum (.NET thread) there are other topics like this (programming techniques), even on ASP.NET

btw - see also Code Signing Certificates for verifying if assemblies have been tampered with.
Don't worry, I also know how to do that. But it is not required since Autocad 2014 does this for us
The self integrity verification can also be done by injecting code, but this requires a good knowledge of the PE++ file format, What's your level of knowledge?
In any case, this is very well documented, just search over the internet.

Before I started programming with C # I used VB6 and I learned much about the windows API and about dll's, exe's... . I think this is one of the problems of some current C# programmers
« Last Edit: March 10, 2014, 05:28:02 PM by jar »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Using Strong Name Signatures to protect our assemblies
« Reply #3 on: March 10, 2014, 05:58:44 PM »
If so then why is this here?
I do not see where the problem, in this forum (.NET thread) there are other topics like this (programming techniques), even on ASP.NET


I can't see a problem either as it is code related.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

CADbloke

  • Bull Frog
  • Posts: 345
  • Crash Test Dummy
Re: Using Strong Name Signatures to protect our assemblies
« Reply #4 on: March 10, 2014, 06:02:33 PM »
If so then why is this here?
I do not see where the problem, in this forum (.NET thread) there are other topics like this (programming techniques), even on ASP.NET

Sorry, I was unclear.  I was asking why did you post it in .NET when "These techniques are not applicable to autocad .NET addin's"? Yes, I do appreciate programming tips like these. Whether they belong here or not is open for debate since this is an AutoCAD-specific forum and you have said this technique can't be used in AutoCAD. Regardless, it is not clever of me to discourage any contribution to the programming good of all, so please feel free to ignore my protestations.

I was also unclear about code-signing - if you sign your installer then the end-user will know if it has been hacked. You can then disclaim all responsibility for any support if they have willingly installed a hacked version of your app.

For the record, my level of PE++ is zero but all that means this post is probably not aimed at me.

I've had another coffee now so I promise not to be so grumpy. Please continue with your valuable contributions.

exmachina

  • Guest
Re: Using Strong Name Signatures to protect our assemblies
« Reply #5 on: March 10, 2014, 06:30:28 PM »
I am a little tired. I admit that sometimes i have behaved like a troll...and maybe that's why I'm not very popular. But I have never attacked anyone, and I am not trying to offend anyone.
Some time ago I lost the interest in autocad, but I try to collaborate with what I know

Thanks.

exmachina

  • Guest
Re: Using Strong Name Signatures to protect our assemblies
« Reply #6 on: March 10, 2014, 06:38:47 PM »

...."These techniques are not applicable to autocad .NET addin's"

I am quite sure that some people do not know the reason. They can not be signed because its dependencies ( AcMgd.dll... ) are not signed

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Using Strong Name Signatures to protect our assemblies
« Reply #7 on: March 10, 2014, 06:44:05 PM »
CADbloke,

Just to clear up a misconception.

The .NET forum is not restricted to CAD related code topics.


In fact, the description on the index page says it well ...
Quote
.NET
Exploiting the Common Language Runtime? C'mon in
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

CADbloke

  • Bull Frog
  • Posts: 345
  • Crash Test Dummy
Re: Using Strong Name Signatures to protect our assemblies
« Reply #8 on: March 10, 2014, 06:45:36 PM »
Understood. Thanks. Sorry for my misunderstanding and "trolling" <== harsh but fair.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Using Strong Name Signatures to protect our assemblies
« Reply #9 on: March 10, 2014, 06:55:47 PM »
I am quite sure that some people do not know the reason. They can not be signed because its dependencies ( AcMgd.dll... ) are not signed

Finally something I did know!!  They mention it on the AutoCAD DevBlog http://adndevblog.typepad.com/autocad/2012/07/can-i-sign-my-autocad-net-plug-in-with-a-strong-name.html
 
Thanks for the info Jar!
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

CADbloke

  • Bull Frog
  • Posts: 345
  • Crash Test Dummy
Re: Using Strong Name Signatures to protect our assemblies
« Reply #10 on: March 10, 2014, 07:03:53 PM »
I am quite sure that some people do not know the reason. They can not be signed because its dependencies ( AcMgd.dll... ) are not signed

Finally something I did know!!  They mention it on the AutoCAD DevBlog http://adndevblog.typepad.com/autocad/2012/07/can-i-sign-my-autocad-net-plug-in-with-a-strong-name.html

Yes, me too (I'm excited too). From that post ...

"However there are workarounds available:
...
- Sign your assembly with Authenticode signature and configure to trust the 'publisher'."

btw - see also Code Signing Certificates for verifying if assemblies have been tampered with.
which you CAN use with AutoCAD .NET add-ons.
< / Troll> :-D <== in case the nuance is lost, this is a joke, ok?

Jeff H

  • Needs a day job
  • Posts: 6151
Re: Using Strong Name Signatures to protect our assemblies
« Reply #11 on: March 10, 2014, 07:20:48 PM »
I think it is very important to understand why certain components do not apply to AutoCAD it helps to understand the over all picture.

There was another thread I think at Acad forums and like normal they never read my replies and just skipped over them, but was trying to point out that for the CLR to look at AssemblyVersion attribute it has to be strongly signed.


Jar appreciate the post and keep posting anything that is .NET related