them in sync because it means that they can determine the assembly version via
Windows Explorer. Alternatively, other organizations use the fi le version to
represent changes to an assembly (for example, a hotfi x or service pack), whereas
the assembly version is used for new versions of the application.
932 .
chaPter 46 ASSembly VerSioning And Signing
As the comments in the VB snippet explain, assembly version numbers have four components — Major,
Minor, Build, and Revision. Again, how you increment these is completely up to you. In fact, you could
even elect for Visual Studio 2010 to increment them for you by specifying an * for the build and/or
revision numbers. One fairly common strategy is to use the Major and Minor numbers to represent the
actual version of the product being worked on. Incrementing just the Minor number would perhaps
represent minor fixes and minimal new functionality (similar to a service pack), whereas the Major
number would represent new core functionality.
This leaves the Build and Revision numbers that can be used to perhaps tie into the build process.
For example, the Build number might represent the week number into development for a particular
release, whereas the Revision number might represent the most recent revision number in the source
repository. This last value then becomes very important because it can be used, in isolation, to
access the exact source code from the repository that was used to build a particular version.
Version consistency
The default project configuration doesn’t lend itself easily to having a consistent version number
across all projects within a solution. However, using the ability to include linked files in a project,
you can coerce Visual Studio 2010 into giving you version consistency. This is particularly
important if you have an automated build system that automatically increments the version number.
Instead of having to update any number of AssemblyInfo files, it can simply modify a single file and
have all projects be updated.
You need to start by creating an additional AssemblyInfo file, say GlobalAssemblyInfo.vb, in
the solution folder. To do this, right-click the Solution node and select Add New Item. The new
item will be added to a Solution Items
folder in your solution. Into this file you
need to move the AssemblyVersion and
AssemblyFileVersion attributes from the
AssemblyInfo file in your projects (you will
also need to import the System.Reflection
namespace unless you fully qualify the
attribute names).
Once you have done this, you then need to
add this file into each of your projects. You
do this via the Add Existing Item right-click
menu item for the projects in the Solution
Explorer tool window. When you have
located the GlobalAssemblyInfo.vb or
GlobalAssemblyInfo.cs file, make sure you
select the Add As Link item from the Add
drop-down, as shown in Figure 46-3.
This one GlobalAssemblyInfo file can
be used in any number of projects, the one limitation being that it is specific to VB or C#. If
you have a solution that uses a mix of VB and C# projects, you will need to have a central
fiGure 46-3
The Global assembly Cache .
933
GlobalAssemblyInfo file for each language — this is still better than having to maintain the
version information in a separate file for each project. Note that you can include other assembly
attributes in these central files, such as the AssemblyCopyright, AssemblyCompany, and
AssemblyTrademark, if appropriate.
stronGly naMed asseMblies
A strong name consists of the parts that uniquely identify an assembly’s identity. This includes
the plain-text name and a version number. Added to these elements are a public key and a digital
signature. These are generated with a corresponding private key. Because of this private/public key
system coupled with a digital signature, strong names can be relied on to be completely unique.
Further, by signing your assembly you are preventing someone from maliciously tampering with
your code. .NET assemblies are relatively easy to reverse engineer, modify, and compile as a modified
assembly. The hash that is created as part of the signing process changes as the assembly is
modified — in effect providing a security mechanism against unauthorized modifications.
Using a strong name can also ensure that the version of your assembly is the one that has been
shipped. No modification can be made to it without affecting its signature and thus breaking its
compatibility with the generated strong name.
As mentioned previously, using strong names also gives administrators the ability to explicitly
set security policy against your solutions by referring to their unique names. This can give a
corporation confidence that once deployed, the software will run as expected because it cannot be
tampered with without affecting the signing of the strong name.
Once you start using strong-named assemblies in your solution, you will have to
use strong-named files right down the chain of references, because allowing an
unsigned assembly as part of the chain would break the very security that strong-
naming your assembly was intended to implement.
the Global asseMbly cache
Every computer that has the .NET Framework installed has a system-wide cache, called the Global
Assembly Cache (GAC), which can be used to store assemblies that are to be shared by multiple
applications. Assemblies that are added to the GAC are accessible from any .NET application
on the same system. This itself can be a huge saving for organizations where you have common
functionality that you want to share between applications.
In this cache (usually stored in a folder within the Windows directory) you’ll find the common
language run time components as well as other globally registered binary files that you, and anyone
else, can consume. If an assembly is only going to be used by a single application, it should be
deployed in that application’s folder.
934 . chaPter 46 ASSembly VerSioning And Signing
If you do decide to share the assembly between applications, you will need to know how to store
it in the GAC. Your assembly must also be strong - named. You don ’ t have a choice in the matter,
because the cache interrogates all fi les to ensure that their integrity is valid; hence, it needs the
strong - name versioning to compare against. Instructions on how to strongly name your assemblies
appear at the end of this chapter.
Once you have a strongly named assembly you can add it to the GAC by using the gacutil.exe
command - line tool like this:
gacutil.exe /i AssemblyInformationApplication.dll
If an assembly with the same strong name already exists, you can force a reinstall with the /f
option. To uninstall the assembly you use this command:
gacutil.exe /u AssemblyInformationApplication
It is important to note here that adding assemblies to the GAC is not
recommended unless you really need to share assemblies between applications,
and they are too large to redistribute alongside each application.
Gacutil.exe is a part of the Microsoft .NET Framework Software Developer
Kit (SDK) and not a part of the standard redistributable. This means that you
can only rely on it being present in development environments. For deployment
to the GAC on client machines, you should use an MSI fi le. See Chapter 48 for
more details.
siGninG an asseMbly
Previously, signing an assembly in Visual Studio required the generation of a strong - name key
( .snk ) fi le via an external utility and then editing the assembly attributes of your application ’ s
confi guration fi le. Thankfully, Visual Studio has built - in support for signing all managed code
projects using the Signing tab in the project properties editor, as you can see from Figure 46 - 4.
The Signing tab enables you to sign the assembly in the lower half of the page. You fi rst should
select the Sign the Assembly checkbox to indicate that you will be generating a strong name. You
will then need to select the strong - name key fi le to use when signing the assembly.
signing an assembly .
935
fiGure 46-4
Existing key files in either the older .snk paired key file format or the new .pfx format can be used.
From the drop-down list, select the Browse option to locate the file in your file system and click OK
in the dialog to save the key file to the Signing page settings.
Alternatively, you can create a new strong-named key
by selecting the New option from the drop-down list.
When you choose New, you will be able to create a new
.pfx formatted strong-named file. Figure 46-5 shows the
Create Strong Name Key dialog. You can simply choose a
filename to use for the key or you can additionally protect
the key file with a password. If you do decide to add a
password, you will be prompted to enter the password if
you build your application on any other computer the
first time. Thereafter, Visual Studio will remember
the password.
Either way, once you’ve created and selected the key file, it will be added to your project in the
Solution Explorer, enabling you to easily include it for deployment projects.
One of the main reasons you might want to sign your assemblies is to ensure that they cannot be
modified. For this reason, most organizations place a high level of security around the strong-name
key file that is used to sign their assemblies. As such, it is likely that you won’t have access to the
private key to successfully sign the assembly. When you’re in this situation, you still need to dictate
that the application be digitally signed. However, instead of providing the full strong-name key
file, which contains the public and private key information, you provide only a file containing the
public key information and select the Delay Sign Only checkbox. Later, perhaps as part of your
build process, you would need to sign the assemblies using the full key:
sn –R AssemblyInformationApplication MyOrganisationsStrongkey.snk
fiGure 46-5
936 .
chaPter 46 ASSembly VerSioning And Signing
If you select to delay the signing of your assemblies, you won’t be able to debug or even run the
application, because it will fail the assembly verification process that is part of the pre-execution
checks that the .NET Framework does on assemblies. Actually, this is a little inaccurate because it is
possible to register your assembly (or in fact any assembly signed with the same public key) so that
the verification step will be skipped:
sn – Vr AssemblyInformationApplication.exe
You should only ever register assemblies to skip verification on development
machines. Further, you can unregister an assembly (or all assemblies signed with
the same public key) using the sn command with the –Vu parameter.
suMMary
Strongly naming your assembly and thus safeguarding it from improper use is now straightforward
to implement, and can be done completely from within the Visual Studio 2010 IDE. The Signing
page gives you the ability to both create and set the key file without having to edit the application’s
assembly attributes directly.
47
obfuscation, application
Monitoring, and Management
what’s in this chaPter?
.
Exploring the features of Dotfuscator Software Services -
Community Edition, a free post-build hardening and application
monitoring tool that ships with Visual Studio
.
Understanding how obfuscation can be used to prevent your
assemblies from being easily decompiled
.
Using tamper defense to protect your application assemblies from
unauthorized modification
.
Configuring application expiry to encode a specifi c date after which
your application can’t be executed
.
Setting up usage tracking to determine what applications and
features are being used
If you ’ ve peeked under the covers at the details of how .NET assemblies are executed, you
will have picked up on the fact that instead of compiling to machine language (and regardless
of the programming language used), all .NET source code is compiled into the Microsoft
Intermediary Language (MSIL, or just IL, for short). The IL is then just - in - time compiled when
it is required for execution. This two - stage approach has a number of signifi cant advantages,
such as allowing you to dynamically query an assembly for type and method information, using
refl ection. However, this is a double - edged sword, because this same fl exibility means that
once - hidden algorithms and business logic can easily be reverse - engineered and modifi ed, legally
or otherwise. This chapter introduces tools and techniques that will help to protect your source
code from prying eyes and monitor the execution of your applications.
938 .
chaPter 47 obFuScATion, ApplicATion moniToring, And mAnAgemenT
the Msil disasseMbler
Before looking at how you can protect your code from other people and monitor its behavior “in
the wild,” this section describes a couple of tools that can help you build better applications. The
first tool is the Microsoft .NET Framework IL Disassembler, or IL Dasm. This is included as part of
the Microsoft Windows SDK, which is installed by default with Visual Studio 2010. You can find it
under Start . All Programs . Microsoft Visual Studio 2010 . Microsoft Windows SDK Tools .
IL Disassembler. In Figure 47-1, a small class library has been opened using this tool, and you can
immediately see the namespace and class information contained within this assembly.
fiGure 47-1
To compare the IL that is generated, the original source code for the MathematicalGenius class is as
follows:
c#
namespace ObfuscationSample
{
public class MathematicalGenius
{
public static Int32 GenerateMagicNumber(Int32 age, Int32 height)
{
return (age * height) + DateTime.Now.DayOfYear;
}
}
}
Vb
Namespace ObfuscationSample
Public Class MathematicalGenius
Public Shared Function GenerateMagicNumber(ByVal age As Integer, _
ByVal height As Integer) As Integer