Chapter 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 specific 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 significant advantages, such as allowing you to dynamically query an assembly for type and method information, using reflection. However, this is a double-edged sword, because this same flexibility means that once-hidden algorithms and business logic can easily be reverse-engineered and modified, 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.

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

THE MSIL DISASSEMBLER
Figure 47-1

Figure 47-1. 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
            Return (age * height) + Today.DayOfWeek
End Function
    End Class
End Namespace

Double-clicking the GenerateMagicNumber method in IL Dasm opens up an additional window that shows the IL for that method. Figure 47-2 shows the IL for the GenerateMagicNumber method, which represents your super-secret, patent-pending algorithm. In actual fact, anyone who is prepared to spend a couple of hours learning how to interpret MSIL could quickly work out that the method simply multiplies the two int32 parameters, age and height, and then adds the current day of the year to the result.

Figure 47-2

Figure 47-2. Figure 47-2

For those who haven't spent any time understanding how to read MSIL, a decompiler can convert this IL back into one or more .NET languages.

DECOMPILERS

One of the most widely used decompilers is .NET Reflector from Red Gate Software (available for download at www.red-gate.com/products/reflector/). Reflector can be used to decompile any .NET assembly into C#, Visual Basic, Managed C11, and even Delphi. In Figure 47-3, the same assembly you just accessed is opened using IL Dasm, in Reflector.

Figure 47-3

Figure 47-3. Figure 47-3

In the pane on the left of Figure 47-3, you can see the namespaces, type, and method information in a layout similar to IL Dasm. Double-clicking a method should open the Disassembler pane on the right, which displays the contents of that method in the language specified in the toolbar. In this case, you can see the C# code that generates the magic number, which is almost identical to the original code.

Note

You may have noticed in Figure 47-3 that some of the .NET Framework base class library assemblies are listed, including System, System.Data, and System.Web. Because obfuscation has not been applied to these assemblies, they can be decompiled just as easily using Reflector. However, Microsoft has made large portions of the actual .NET Framework source code publicly available, which means you can browse the original source code of these assemblies including the inline comments. This is shown in Chapter 43.

If the generation of the magic number were a real secret on which your organization made money, the ability to decompile this application would pose a significant risk. This is made worse when you add the Reflector.FileDisassembler add-in, written by Denis Bauer (available at www.denisbauer.com/NETTools/FileDisassembler.aspx). With this add-in, an entire assembly can be decompiled into source files, complete with a project file.

OBFUSCATING YOUR CODE

So far, this chapter has highlighted the need for better protection for the logic that is embedded in your applications. Obfuscation is the art of renaming symbols and modifying code paths in an assembly so that the logic is unintelligible and can't be easily understood if decompiled. Numerous products can obfuscate your code, each using its own tricks to make the output less likely to be understood. Visual Studio 2010 ships with the Community Edition of Dotfuscator Software Services from PreEmptive Solutions, which this chapter uses as an example of how you can apply obfuscation to your code.

Note

Obfuscation does not prevent your code from being decompiled; it simply makes it more difficult for a programmer to understand the source code if it is decompiled. Using obfuscation also has some consequences that need to be considered if you need to use reflection or strong-name your application.

Dotfuscator Software Services

Although Dotfuscator can be launched from the Tools menu within Visual Studio 2010, it is a separate product with its own licensing. The Community Edition (CE) contains only a subset of the functionality of the commercial edition of the product, the Dotfuscator Suite. If you are serious about trying to hide the functionality embedded in your application, you should consider upgrading. You can find more information on the commercial version of Dotfuscator at www.preemptive.com/products/dotfuscator/compare-editions.

Dotfuscator CE uses its own project format to keep track of which assemblies you are obfuscating and any options that you specify. After starting Dotfuscator from the Tools menu, it opens with a new unsaved project. Select the Input Assemblies node in the navigation tree, and then click the button with an ellipsis (...) under the Assembly Name listing to add the .NET assemblies that you want to obfuscate. Figure 47-4 shows a new Dotfuscator project into which has been added the assembly for the application from earlier in this chapter.

Note

Unlike other build activities that are typically executed based on source files, obfuscation is a post-build activity that works with an already compiled set of assemblies. Dotfuscator takes an existing set of assemblies, applies the obfuscation algorithms to the IL, and generates a set of new assemblies.

Figure 47-4

Figure 47-4. Figure 47-4

Without needing to adjust any other settings, you can select Build Project from the Build menu, or click the "play" button (fourth from the left) on the toolbar, to obfuscate this application. If you have saved the Dotfuscator project, the obfuscated assemblies will be added to a Dotfuscated folder under the folder where the project was saved. If the project has not been saved, the output is written to c:Dotfuscated.

If you open the generated assembly using Reflector, as shown in Figure 47-5, you will notice that the GenerateMagicNumber method has been renamed, along with the input parameters. In addition, the namespace hierarchy has been removed and classes have been renamed. Although this is a rather simple example, you can see how numerous methods with similar, non-intuitive names could cause confusion and make the source code very difficult to understand when decompiled.

Figure 47-5

Figure 47-5. Figure 47-5

Note

The free version of Dotfuscator only obfuscates assemblies by renaming classes, variables, and functions. The commercial version employs several additional methods to obfuscate assemblies, such as modifying the control flow of the assembly and performing string encryption. In many cases, control flow will actually trigger an unrecoverable exception inside decompilers, effectively preventing automated decompilation.

The previous example obfuscated the public method of a class, which is fine if the method will only be called from assemblies obfuscated along with the one containing the class definition. However, if this was a class library or API that will be referenced by other, unobfuscated applications, you would see a list of classes that have no apparent structure, relationship, or even naming convention. This would make working with this assembly very difficult. Luckily, Dotfuscator enables you to control what is renamed during obfuscation. Before going ahead, you will need to refactor the code slightly to pull the functionality out of the public method. If you didn't do this and you excluded this method from being renamed, your secret algorithm would not be obfuscated. By separating the logic into another method, you can obfuscate that while keeping the public interface unchanged. The refactored code would look like the following:

C#
namespace ObfuscationSample
{
    public class MathematicalGenius
    {
        public static Int32 GenerateMagicNumber(Int32 age, Int32 height)
        {
            return SecretGenerateMagicNumber(age, height);
        }

        private static Int32 SecretGenerateMagicNumber(Int32 age, Int32 height)
        {
            return (age * height) + DateTime.Now.DayOfYear;
        }
    }
}
Figure 47-5
VB
Namespace ObfuscationSample
    Public Class MathematicalGenius
        Public Shared Function GenerateMagicNumber(ByVal age As Integer, _
                                                ByVal height As Integer) As Integer
            Return SecretGenerateMagicNumber(age, height)
        End Function

        Private Shared Function SecretGenerateMagicNumber(ByVal age As Integer, _
ByVal height As Integer) As Integer
            Return (age * height) + Today.DayOfWeek
        End Function
    End Class
End Namespace
Figure 47-5

After rebuilding the application, you will need to reopen the Dotfuscator project by selecting it from the Recent Projects list. You have several different ways of selectively applying obfuscation to an assembly. First, you can enable Library mode on specific assemblies by selecting the appropriate checkbox on the Input Assemblies screen (see Figure 47-4). This has the effect of keeping the namespace, class name, and all public properties and methods intact, while renaming all private methods and variables. Second, you can manually select which elements should not be renamed from within Dotfuscator. To do this, open the Renaming item from the navigation tree, shown in Figure 47-6.

Figure 47-6

Figure 47-6. Figure 47-6

The Renaming dialog opens on the Exclusions tab where you can see the familiar tree view of your assembly, with the attributes, namespaces, types, and methods listed. As the name of the tab suggests, this tree enables you to exclude certain elements from being renamed. In Figure 47-6, the GenerateMagicNumber method, as well as the class that it is contained in, is excluded (otherwise, you would have ended up with something like b.GenerateMagicNumber, where b is the renamed class). In addition to explicitly choosing which elements will be excluded, you can also define custom rules that can include regular expressions.

After you build the Dotfuscator project, click the Results item in the navigation tree. This screen shows the actions that Dotfuscator performed during obfuscation. The new name of each class, property, and method is displayed as a sub-node under each renamed element in the tree. You will see that the MathematicalGenius class and the GenerateMagicNumber method have not been renamed, as shown in Figure 47-7.

Figure 47-7

Figure 47-7. Figure 47-7

The SecretGenerateMagicNumber method has been renamed to a, as indicated by the sub-node with the Dotfuscator icon.

Obfuscation Attributes

In the previous example you saw how to choose which types and methods to obfuscate within Dotfuscator. Of course, if you were to start using a different obfuscating product you would have to configure it to exclude the public members. It would be more convenient to be able to annotate your code with attributes indicating whether a symbol should be obfuscated. You can do this by using the Obfuscation and ObfuscationAssemblyAttribute attributes from the System.Reflection namespace.

The default behavior in Dotfuscator is to override exclusions specified in the project with the settings specified by any obfuscation attributes. In Figure 47-4 is a series of checkboxes for each assembly added to the project, of which one is Honor Obfuscation Attributes. You can change the default behavior so that any exclusions set within the project take precedence by unchecking the Honor Obfuscation Attributes option on a per-assembly basis.

ObfuscationAssemblyAttribute

The ObfuscationAssemblyAttribute attribute can be applied to an assembly to control whether it should be treated as a class library or as a private assembly. The distinction is that with a class library it is expected that other assemblies will be referencing the public types and methods it exposes. As such, the obfuscation tool needs to ensure that these symbols are not renamed.

Alternatively, as a private assembly, every symbol can be potentially renamed. The following is the syntax for ObfuscationAssemblyAttribute:

C#
[assembly: ObfuscateAssemblyAttribute(false, StripAfterObfuscation=true)]
VB
<Assembly: ObfuscateAssemblyAttribute(False, StripAfterObfuscation:=True)>

The two arguments that this attribute takes indicate whether it is a private assembly and whether to strip the attribute off after obfuscation. The preceding snippet indicates that this is not a private assembly, and that public symbols should not be renamed. In addition, the snippet indicates that the obfuscation attribute should be stripped off after obfuscation — after all, the less information available to anyone wishing to decompile the assembly, the better.

Adding this attribute to the AssemblyInfo.cs or AssemblyInfo.vb file will automatically preserve the names of all public symbols in the ObfuscationSample application. This means that you can remove the exclusion you created earlier for the GenerateMagicNumber method.

ObfuscationAttribute

The downside of the ObfuscationAssemblyAttribute attribute is that it exposes all the public types and methods regardless of whether they existed for internal use only. On the other hand, the ObfuscationAttribute attribute can be applied to individual types and methods, so it provides a much finer level of control over what is obfuscated. To illustrate the use of this attribute, refactor the example to include an additional public method, EvaluatePerson, and place the logic into another class, HiddenGenius:

C#
namespace ObfuscationSample
{

    [System.Reflection.ObfuscationAttribute(ApplyToMembers=true, Exclude=true)]
    public class MathematicalGenius
    {
        public static Int32 GenerateMagicNumber(Int32 age, Int32 height)
        {
            return HiddenGenius.GenerateMagicNumber(age, height);
        }

        public static Boolean EvaluatePerson(Int32 age, Int32 height)
        {
            return HiddenGenius.EvaluatePerson(age, height);
        }
    }

    [System.Reflection.ObfuscationAttribute(ApplyToMembers=false, Exclude=true)]
    public class HiddenGenius
    {
        public static Int32 GenerateMagicNumber(Int32 age, Int32 height)
        {
return (age * height) + DateTime.Now.DayOfYear;
        }

        [System.Reflection.ObfuscationAttribute(Exclude=true)]
        public static Boolean EvaluatePerson(Int32 age, Int32 height)
        {
            return GenerateMagicNumber(age, height) > 6000;
        }
    }
}
ObfuscationAttribute
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
ObfuscationAttribute

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 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

Figure 47-8. Figure 47-8

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

Note

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

Figure 47-8

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 SDKsWindowsv7.0Ainsn.exe" -Vr "$(TargetPath)"
"$(DevEnvDir)......Microsoft SDKsWindowsv7.0Ainsn.exe" -Vr
"$(TargetDir)$(TargetName).vshost$(TargetExt)"

Warning

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.

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

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 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.

Figure 47-10

Figure 47-10. 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-11

Figure 47-11. 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 FilesMicrosoft Visual Studio 10.0PreEmptive SolutionsDotfuscator 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:	amperedapps

Warning

Make sure you run the TamperTester utility against the assemblies that were generated by Dotfuscator and not the original assemblies built by Visual Studio.

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

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.

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

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();
Application.Run(new Form1());
        AppEnd();
    }

    static void AppStart()
    {
    }

     static void AppEnd()
    {
    }
    }
Figure 47-13

For a VB Windows Forms application, you can use the Application Events functionality provided the Windows application framework to specify Startup and Shutdown methods as shown in the following listing:

VB
Imports Microsoft.VisualBasic.ApplicationServices
Namespace My
    Partial Friend Class MyApplication
        Private Sub MyApp_Startup(ByVal sender As Object, _
                                  ByVal e As StartupEventArgs) _
                                  Handles Me.Startup
        End Sub

        Private Sub MyApp_Shutdown(ByVal sender As Object, _
                                  ByVal e As System.EventArgs) _
                                  Handles Me.Shutdown
        End Sub
    End Class
End Namespace
Figure 47-13

Once you have a startup and shutdown method defined in your application, you can add the SetupAttribute and TeardownAttribute attributes. Locate your startup method in the tree, then right-click it and select Add Attribute. Select SetupAttribute and click OK. In the attribute properties you will need to specify a value for the CustomEndpoint property, which instructs Dotfuscator where to send any instrumentation messages. Click the ellipsis button and select PreEmptive's Free Runtime Intelligence Services from the list.

Note

You shouldn't collect information about application usage without asking permission from your users, otherwise your application could be flagged as spyware. The SetupAttribute provides three properties to help configure this — OptInSourceElement, OptInSourceName, and OptInSourceOwner.

The Runtime Intelligence Service is a managed service provided by PreEmptive Solutions that aggregates and manages Runtime Intelligence data generated by your application, and a web portal that includes runtime analytics. PreEmptive Solutions offers a free and a commercial version of its Runtime Intelligence Service.

Note

The free version of PreEmptive's Runtime Intelligence Service is suitable only for preliminary testing purposes because it lacks sufficient security and does not include any guarantees of uptime or data retention. You should transition to the commercial version or find/build an alternative for production deployment.

Finally, add the TeardownAttribute attribute to the appropriate method and then build the Dotfuscator project. Run the application a couple of times to generate some instrumentation messages. You can also use the TamperTester utility described in the previous section to create a "tampered" version of the application that generates Tamper notifications.

Once you have run the application a number of times, open your browser and visit http:/free.runtimeintelligence.com. You can log on to the portal using the unique identifier you generated earlier for the CompanyKey property.

The Welcome screen, which is displayed after you log on, shows the number of notification messages that are queued waiting to be loaded into the database. You may need to wait until any pending messages are loaded before you can view any data.

On the Application Overview menu you can view summary graphs that show data such as the application usage over time, and the operating systems and .NET Framework versions used by your users. The Application Scorecard report, shown in Figure 47-14, displays a list of all the applications registered under this Company Key, along with key metrics about their usage.

Figure 47-14

Figure 47-14. Figure 47-14

Later in this chapter you see how the usage tracking can be extended to cover usage of specific features within your application.

Application Expiry

The application expiry feature, also known as Shelf Life, allows you to specify an expiration date for your application, after which it will no longer run. This can be useful in a number of scenarios, such as when releasing beta or trial versions of software.

Application expiry requires a Shelf Life Activation Key (SLAK). This key is issued by PreEmptive, and can be requested by visiting http://www.preemptive.com/products/shelflife.

Two attributes are available to help implement application expiry. The InsertShelfLifeAttribute attribute enforces the expiration dates, ensuring that the application will not run after the specified date. It can also send a notification to an arbitrary endpoint when an expired application is executed. The InsertSignOfLifeAttribute attribute sends a notification to the Runtime Intelligence service every time your application is executed. This allows you to find out how often an application was executed.

Before adding the application expiry attributes, you should set up your assembly with the BusinessAttribute, ApplicationAttribute, SetupAttribute, and TeardownAttribute attributes, as described in the previous section on Runtime Intelligence.

It's a good idea to add the application expiry attributes to a method that is called shortly after the application is started. You may also want to add it to a method that is called regularly, just in case your users leave your application running after the expiry date. In Figure 47-15, the InsertShelfLifeAttribute and InsertSignOfLifeAttribute attributes have been added to the Form1.InitializeComponent method. This ensures that the application expiry date will be checked every time Form1 is invoked.

Figure 47-15

Figure 47-15. Figure 47-15

Both attributes require a Shelf Life Activation Key. Once you have obtained this key from PreEmptive, save it to your local disk and set the path to this file in the ActivationKeyFile property. Setting the ExpirationDate property to a date in the past is a good way to test this feature.

When an application expires, the behavior is determined by two settings. First, if you have Send Shelf Life Notification Messages checked on the Instrumentation Options tab, it will send a notification message to the endpoint you have specified. Second, if you have set the ExpirationNotificationSinkElement property to DefaultAction, the application will immediately exit.

The commercial edition of Dotfuscator allows you to specify a warning date and add custom handlers that are executed when the warning date or expiration date are reached. You could use this to deactivate specific features or display a friendly message to the users advising them that the application has expired.

The commercial version of Dotfuscator also allows your application to obtain the shelf life information from an external location, such as a web service or configuration file. This allows you to support other expiration scenarios such as expiring 30 days from installation or renewing annual subscriptions.

Application Usage Tracking

Earlier in this chapter you saw how to add the SetupAttribute and TeardownAttribute attributes to your application. By adding these attributes your application can send notification messages, and thereby allow you to track usage data and system environment statistics for your applications. These attributes are also used to determine application stability, because a missing Teardown notification indicates that the application may have crashed or a user may have gotten frustrated and simply forced an exit.

In addition to tracking application startup and shutdown, Dotfuscator allows you to further instrument your code to track usage of specific features within your application. With Dotfuscator CE, you can add up to ten FeatureAttribute attributes to your methods, each one specifying the same or a different feature. This allows you to aggregate your application's methods into a logical, high-level "feature" grouping that is independent of the actual class hierarchy of your code.

In Figure 47-16, you can see that a FeatureAttribute attribute has been added to the EvaluatePerson and the GenerateMagicNumber methods of the MathematicalGenius class. These features have been given a descriptive name, which is displayed when viewing the usage reports. These attributes also have the FeatureEventType property set to Tick, which simply tracks that the feature has been used.

Figure 47-16

Figure 47-16. Figure 47-16

In addition to Tick feature tracking, you can also track the amount of time a feature was used. In this case you will need to add two FeatureAttribute attributes — one with the FeatureEventType property set to Start and the other set to Stop. This generates two instrumentation messages and allows the Runtime Intelligence analytics service to calculate feature usage duration.

The commercial edition of Dotfuscator includes:

  • Unlimited feature tracking

  • Injection of the Microsoft WMI SDK for hardware and software stack detection

  • Extensible data capture to include custom data values

  • An SSL runtime data transmission option

Runtime Intelligence data can be used to improve the development process, provide greater visibility into application usage for IT operations, and serve as an additional data source for business activity and performance monitoring. Microsoft's own Customer Experience Improvement Program (CEIP) relies on this kind of usage data (for a description of its program, visit http://www.microsoft.com/products/ceip/).

As managed code moves beyond the desktop and the in-house server to the web client (Silverlight), the cloud (Azure), and your mobile devices, Runtime Intelligence will likely become an increasingly important part of your application life cycle management toolkit.

SUMMARY

This chapter introduced two tools, IL Dasm and Reflector, which demonstrated how easy it is to reverse-engineer .NET assemblies and learn their inner workings. You also learned how to use Dotfuscator Software Services to:

  • Protect your intellectual property using obfuscation

  • Harden your applications against modification using tamper defense

  • Monitor and measure application usage with Runtime Intelligence instrumentation

  • Enforce your application's end-of-life with shelf life

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.110.155