public class HiddenGenius
{
public static Int32 GenerateMagicNumber(Int32 age, Int32 height)
{
obfuscating Your Code .
947
return (age * height) + DateTime.Now.DayOfYear;
}
[System.Reflection.ObfuscationAttribute(Exclude=true)]
public static Boolean EvaluatePerson(Int32 age, Int32 height)
{
return GenerateMagicNumber(age, height) > 6000;
}
}
}
Code Snippet MathematicalGenius.cs
Vb
Namespace ObfuscationSample
<System.Reflection.ObfuscationAttribute(ApplyToMembers:=True,Exclude:=True)> _
Public Class MathematicalGenius
Public Shared Function GenerateMagicNumber(ByVal age As Integer, _
ByVal height As Integer) As Integer
Return HiddenGenius.GenerateMagicNumber(age, height)
End Function
Public Shared Function EvaluatePerson(ByVal age As Integer, _
ByVal height As Integer) As Boolean
Return HiddenGenius.EvaluatePerson(age, height)
End Function
End Class
<System.Reflection.ObfuscationAttribute(ApplyToMembers:=False,Exclude:=True)> _
Public Class HiddenGenius
Public Shared Function GenerateMagicNumber(ByVal age As Integer, _
ByVal height As Integer) As Integer
Return (age * height) + Today.DayOfWeek
End Function
<System.Reflection.ObfuscationAttribute(Exclude:=True)> _
Public Shared Function EvaluatePerson(ByVal age As Integer, _
ByVal height As Integer) As Boolean
Return GenerateMagicNumber(age, height) > 6000
End Function
End Class
End Namespace
Code Snippet MathematicalGenius.vb
In this example, the MathematicalGenius class is the class that you want to expose outside of this
library. As such, you want to exclude this class and all its methods from being obfuscated. You do
this by applying the ObfuscationAttribute attribute with both the Exclude and ApplyToMembers
parameters set to True.
The second class, HiddenGenius, has mixed obfuscation. As a result of some squabbling among the
developers who wrote this class, the EvaluatePerson method needs to be exposed, but all other
948 .
chaPter 47 obFuScATion, ApplicATion moniToring, And mAnAgemenT
methods in this class should be obfuscated. Again, the ObfuscationAttribute attribute is applied
to the class so that the class does not get obfuscated. However, this time you want the default
behavior to be such that symbols contained in the class are obfuscated, so the ApplyToMembers
parameter is set to False. In addition, the Obfuscation attribute is applied to the EvaluatePerson
method so that it will still be accessible.
words of caution
In a couple of places it is worth considering what will happen when obfuscation — or more
precisely, renaming — occurs, and how it will affect the workings of the application.
reflection
The .NET Framework provides a rich reflection model through which types can be queried and
instantiated dynamically. Unfortunately, some of the reflection methods use string lookups for
type and member names. Clearly, the use of renaming obfuscation will prevent these lookups
from working, and the only solution is not to mangle any symbols that may be invoked using
reflection. Note that control flow obfuscation does not have this particular undesirable side-effect.
Dotfuscator’s smart obfuscation feature attempts to automatically determine a limited set of
symbols to exclude based on how the application uses reflection. For example, say that you are using
the field names of an enum type. Smart obfuscation will detect the reflection call used to retrieve the
enum’s field name, and then automatically exclude the enum fields from renaming.
strongly named assemblies
One of the purposes behind giving an assembly a strong name is that it prevents the assembly from
being tampered with. Unfortunately, obfuscating relies on being able to take an existing assembly
and modify the names and code flow, before generating a new assembly. This would mean that the
assembly no longer has a valid strong name. To allow obfuscation to occur you need to delay signing
of your assembly by checking the Delay Sign Only checkbox on the Signing tab of the Project
Properties window, as shown in Figure 47-8.
fiGure 47-8
application Monitoring and Management .
949
After building the assembly, you can then obfuscate it in the normal way. The only difference is that
after obfuscating you need to sign the obfuscated assembly, which you can do manually using the
Strong Name utility, as shown in this example:
sn -R ObfuscationSample.exe ObfuscationKey.snk
The Strong Name utility is not included in the default path, so you will either
need to run this from a Visual Studio Command Prompt (Start . All Programs
. Microsoft Visual Studio 2010 . Visual Studio Tools), or enter the full path to
sn.exe.
Debugging with Delayed signing
As displayed on the Project Properties window, checking the Delay Sign Only box prevents the
application from being able to be run or debugged. This is because the assembly will fail the strong - name
verification process. To enable debugging for an application with delayed signing, you can register the
appropriate assemblies for verification skipping. This is also done using the Strong Name utility. For
example, the following code will skip verification for the ObfuscationSample.exe application:
sn -Vr ObfuscationSample.exe
Similarly, the following will reactivate verification for this application:
sn -Vu ObfuscationSample.exe
This is a pain for you to have to do every time you build an application, so you can add the
following lines to the post-build events for the application:
"$(DevEnvDir)..\..\..\Microsoft SDKs\Windows\v7.0A\bin\sn.exe" -Vr "$(TargetPath)"
"$(DevEnvDir)..\..\..\Microsoft SDKs\Windows\v7.0A\bin\sn.exe" -Vr
"$(TargetDir)$(TargetName).vshost$(TargetExt)"
Depending on your environment, you may need to modify the post-build event
to ensure that the correct path to sn.exe is specified.
The first line skips verification for the compiled application. However, Visual Studio uses an
additional vshost file to bootstrap the application when it executes. This also needs to be registered
to skip verification when launching a debugging session.
aPPlication MonitorinG and ManaGeMent
The version of Dotfuscator that ships with Visual Studio 2010 has a whole lot of new functionality
for adding run time monitoring and management functionality to your applications. As with
obfuscation, these new capabilities are injected into your application as a post-build step, which
means you typically don’t need to modify your source code in any way to take advantage of them.
950 .
chaPter 47 obFuScATion, ApplicATion moniToring, And mAnAgemenT
The new application monitoring and management capabilities include:
.
Tamper Defense: Exits your application, and optionally notifies, if it has been modified in
an unauthorized manner.
.
Application Expiry: Configure an expiration date for your application, after which it will
no longer run.
.
Application Usage Tracking: Instrument your code to track usage, including specific
features within your application.
To enable the new monitoring and management functionality you must enable instrumentation for
your Dotfuscator project. Select the Instrumentation item from the navigation tree and select the
Options tab. Select the Enable Instrumentation option as shown in Figure 47-9.
fiGure 47-9
Once instrumentation has been enabled, you can specify the new functionality to be injected into
your application by adding Dotfuscator attributes — either as a custom attribute within your source
code, or through the Dotfuscator UI.
tamper defense
Tamper defense provides a way for you to detect when your applications have been modified in an
unauthorized manner. Whereas obfuscation is a preventative control designed to reduce the risks
that stem from unauthorized reverse engineering, tamper defense is a detective control designed to
reduce the risks that stem from unauthorized modification of your managed assemblies. The pairing
of preventative and detective controls is a widely accepted risk management pattern, for example,
fire prevention and detection.
Tamper defense is applied on a per-method basis, and tamper detection is performed at run time
when a protected method is invoked.
To add tamper defense to your application, select the Instrumentation item from the navigation
menu and then select the Attributes tab. You will see a tree that contains the assemblies you have
application Monitoring and Management .
951
added to the Dotfuscator project with a hierarchy of the
classes and methods that each assembly contains. Navigate to
the HiddenGenius.GenerateMagicNumber function,
right-click it, and select Add Attribute. This displays the list
of available Dotfuscator attributes as shown in Figure 47-10.
Select the InsertTamperCheckAttribute attribute and
click OK. The attribute is added to the selected method and
the attribute properties are listed as shown in Figure 47-11.
Finally, select the ApplicationNotificationSinkElement
property and change the value to DefaultAction.
fiGure 47-10
fiGure 47-11
You can now build the Dotfuscator project to inject the tamper defense functionality into your
application.
To help you test the tamper defense functionality, Dotfuscator ships with a simple utility that
simulates tampering of an assembly. Called TamperTester, you can find this utility in the same
directory in which Dotfuscator is installed (by default C:\Program Files\Microsoft Visual
Studio 10.0\PreEmptive Solutions\Dotfuscator Community Edition). This should be run
from the command line with the name of the assembly and the output folder as arguments:
tampertester ObfuscationSample.exe c:\tamperedapps
Make sure you run the TamperTester utility against the assemblies that were
generated by Dotfuscator and not the original assemblies built by Visual Studio.
952 .
chaPter 47 obFuScATion, ApplicATion moniToring, And mAnAgemenT
By default, your application will immediately exit if the method has been tampered with. You can
optionally configure Dotfuscator to generate a notification message to an endpoint of your choosing.
The commercial edition of Dotfuscator includes two primary extensions to the CE version; it
allows you to add a custom handler to be executed when tampering is detected supporting a custom
real-time tamper defense in lieu of the default exit behavior; and PreEmptive Solutions offers a
notification service that accepts tamper alerts and automatically notifies your organization as an
incident response.
runtime intelligence instrumentation and analytics
The term Runtime Intelligence (RI) refers to technologies and managed services for the collection,
integration, analysis, and presentation of application usage patterns and practices. In Visual
Studio 2010, Dotfuscator CE can inject RI instrumentation into your assemblies to stream session
and feature usage data to an arbitrary endpoint. The following sections describe how to use
Dotfuscator’s Runtime Intelligence instrumentation and some of the free and for-fee Runtime
Intelligence analytics options that are available.
To use Dotfuscator CE instrumentation, you must first enable it within your Dotfuscator project.
Click the Instrumentation item in the navigation tree and select the Options tab. Ensure that all the
options under Runtime Intelligence Configuration are enabled, as shown in Figure 47-12.
fiGure 47-12
Next you must add some attributes to your assemblies to ensure that they can be uniquely identified
and any instrumentation data can be accessed. Under the Attributes tab of the Instrumentation node
is the class hierarchy of any assemblies you have added to Dotfuscator. Right-click each of the
top-level nodes (the node that contains the full path to your assembly), select Add Attribute, and
add a new BusinessAttribute
attribute.
Select CompanyKey from the attribute properties listing. This attribute provides a unique identifier
for your company and should be the same across all of your assemblies. You can click the button
labeled with the ellipsis to generate a new CompanyKey. Also enter a value for the CompanyName
property that will be displayed in the portal and any reports.
application Monitoring and Management .
953
Repeat this to add a new ApplicationAttribute attribute to your assemblies. The GUID property
of this attribute should contain a unique identifier that is the same across all assemblies within this
application. As with the CompanyKey property, you can generate a new value for the GUID property
by clicking the button labeled with the ellipsis. You should also enter values for the Name and
Version properties, but the ApplicationType property can be left blank.
Once you have added these attributes, your project should look similar to Figure 47-13.
fiGure 47-13
The final step is to add SetupAttribute and TeardownAttribute attributes to your application.
These attributes can be added to any method and are usually defined once each per application,
though that is not strictly necessary if your application has multiple entry and exit points.
SetupAttribute should be placed on a method that is called soon after application startup.
Likewise, the TeardownAttribute attribute must be added to a method that is called just before the
application exits. It is sometimes a good idea to create methods specifically for these attributes.
For a C# Windows Forms application, you can place the attributes on the Main method;
alternatively, you can modify the Program.cs class by adding the AppStart and AppEnd methods as
shown in the following listing:
c#
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppStart();
954 .
chaPter 47 obFuScATion, ApplicATion moniToring, And mAnAgemenT
Application.Run(new Form1());