Confessions of a Design Pattern Junkie

§ April 25, 2008 16:28 by beefarino |

Me: "Hello, my name is Jim, and I'm a pattern junkie."

Group: "Hello. Jim."

Yes, I humbly admit it.  I read this book, that book, and this other one too, and now I'm pattern-tastically pattern-smitten with a pattern-obsession.  I'm that guy on the team - the one who starts the design with strategies and factories and commands and decorators before a lick of code is compiled.  The one who creates decorator and composite base classes for every interface because "I'll prolly need 'em."  The one who, at the end of the project, has produced Faulknerean code for lolcat functionality.  

But I confess: I am not the least bit ashamed.  I acknowledge my approach has been overbearing and self-indulgent. I know I need to change to be a better engineer.  Spending time as Scrum Master has shown me what pattern hysteria looks like from the outside.  It's WTFBBQ smothered in bloat sauce.

But the experience of being a pattern junkie has been irreplaceable, for a number of reasons.  Patterns are valuable to know, for reasons I'll expound on in a bit.  Taking the time to (over-)apply them to real projects has been the best way for me to learn how they work and interact.  My biggest problem is that I want to apply them as much as possible at the design stage of a project. I've come to terms with the fact that it's a bad idea, which has given me the chance to learn something and improve myself.

So, in the words of the good witch: "What have you learned Dorothy?"

First, let's talk about how misusing patterns has inhibited me.

Bad: Using a pattern leads me to using another. 

Using a strategy pattern precipitates the use of decorators and adapters on the strategy.  Using commands leads to the use of composites, iterators, and chain of responsibility.  The complexity of managing the patterns and dependency injection leads to the use of facades, factories, builders, and singletons.  Things become extraordinarily convoluted very quickly.  When I design against patterns a priori, when they don't service an existing need, the code I have to write explodes, and once it's written, maintaining it becomes a real chore.

Bad: Thinking in patterns makes me lose focus of the problem.

Using patterns makes me itch to break down problems into very atomic units, which is generally good, but I take it to the point of comedy.  Consider this example, which is an actual approach I used because I thought it was a good idea at the time.  I was working on an object that operates on an XML document. To supply the XML document to my object, I chose to define the IXMLDocumentProvider interface as an abstraction for loading the XML.  Why?  Because I was thinking about patterns and not the problem I was trying to solve.  My logic was roughly  this: if I use another strategy to manage the load behavior the XML source could be a file at runtime and an in-memory document in my unit tests, and I could use a decorator on the strategy to validate an XMLDSIG on the document in production if I need to.  In the end, all the program needed was the XML, which could have easily been supplied in a constructor or parameter.  There is but one instance of IXMLDocumentProvider in the project, and all it does is hand out an instance of an XML document supplied to its constructor.  I filled a non-existent need because I was focusing on the pattern and not the problem.

It isn't all bad; let's look at how using patterns has helped me.

Good: Using patterns yields testable code.

Using patterns extensively has helped me write highly testable code.  Patterns and dependency injection go together like peanut butter and chocolate.  Having patterns peppered throughout the design, my code is highly decoupled.  Unit testing is a breeze in such a scenario, and unit tests are good.

Good: Using patterns makes complex code understandable.

Patterns isolate concerns.  This makes large codebases more digestible, and it tends to break complex relationships into lots of smaller objects.  I know many people would disagree with me here, but I find it easier to work with 50 small class definitions that a) follow well-understood patterns and b) adhere to the single responsibility principle than 5 classes that have been incrementally expanded to 20,000+ lines of code containing a succotash of concerns.  A coherent class diagram will tell me more about a system than a list of 200+ method names.

Good: Using patterns makes complex systems extensible.

Again, patterns isolate concerns, which makes extending a system very simple once you are familiar with the system design.  For example, adding a decorator is easier, in my opinion, to altering the behavior of an existing class.  Folding new features into a well-designed strategy, command, or visitor pattern is cake.  Patterns help you grow a system by extending it, not altering it, which is a good idea.

My two-step program to better pattern application

I've learned from my mistakes.  I've come to the conclusion that patterns are a tool best applied to existing working and testable code.  My personal commitment is to stop using patterns at the design phase, but continue employing patterns when they make sense.  How will I do this?

My two steps are simple - when I work on a software feature, I promise to do the following:

  1. Design and code the feature to a working state as quickly and simply as possible.  At this phase I promise not employ patterns a priori, although I may employ Dependency Injection to make testing easier.
  2. Refactor my code to separate concerns, remove duplication, and improve readability.  At this phase, I will employ patterns NOT wherever possible, but only as necessary to meet my goal.  That means I'll pull them in when I need to separate concerns, when I need to untangle spaghetti code, when I need to make the code understandable.  

I'll let you know how the rehab goes.  Until then, there's no place like code ... there's no place like code .... there's no place like code .....



Coping with the Fear of Changing Code

§ April 20, 2008 14:43 by beefarino |

Another fear I'm seeing on the team is a fear of changing existing code.  The fear may stem from several sources: the code implements complex behavior that is undocumented; the code is inherited from a resident expert who is retasked or otherwise unavailable; the code hasn't been maintained properly and reads like a plate of spaghetti.  Whatever the source, a team member's response to the fear follows the pattern:

When team members are afraid, they will act in either their own interest of self-preservation, or in the interest of team survival.

When confronted with such code, a team member can choose one of two paths: they will choose to do as little with the code as possible, leave it alone as much as they can and still satisfy everyone's expectations; or they own up to the situation and remove the source of the fear, making the code easier for anyone to cope with and understand.

Those who pursue self-preservation take the former track.  They exert a lot of effort to develop an understanding of the code, but don't do anything to persist or share that knowledge.  Chances are they are trying to act in the team's interest by developing specialized knowledge of the code, but in the long-term they benefit only themselves.  The code remains an untenable briar patch for the next poor sod who receives it.

Those who pursue the best interests of the team take the latter approach.  They write unit tests around the existing code; they refactor the code and leverage the common design patterns to make the code comprehensible; they seek clarification from the business heads and write documentation targeted to other developers.  Their actions are targeted, whether implicitly or explicitly, at communicating with the other members of their team.



 
000/09/xmldsig#">     <SignedInfo>       <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />       <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />       <Reference URI="">...</Reference>     </SignedInfo>     <SignatureValue>...</SignatureValue>     <KeyInfo>...</KeyInfo>   </Signature> </configuration>

 

We can't just plop this new element in the app.config and expect the .NET configuration manager to process it without knowing what it is; this will cause failure during application startup.  No special tricks here, we simply need to instruct the configuration system to ignore this element by adding the following to the top of the config file:

 

<configSections>     <section name="Signature" type="System.Configuration.IgnoreSectionHandler" />     </configSections> ...

The app.config is almost ready to accept the XML digital signature...

Finalizing the App.Config Contents

Once we apply the signature to the app.config, we won't be able to alter the app.config contents without invalidating the signature.  For our example, we need to make sure our application settings are set properly:

 

<configuration>     <configSections>         <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">             <section name="XMLDSIGValidate.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />         </sectionGroup>         <section name="Signature" type="System.Configuration.IgnoreSectionHandler" />     </configSections>     <applicationSettings>         <XMLDSIGValidate.Settings1>             <setting name="ReallyImportantSetting" serializeAs="String">                 <value>if this value is altered, the application should not run</value>             </setting>         </XMLDSIGValidate.Settings1>     </applicationSettings> </configuration>

The only setting in this mess is on lines 12-13.  I set the value to something obnoxious, then move on to signing the file.

Generating the XML Digital Signature

There is no tool in the .NET SDK for applying XMLDSIG to a file, so we need to create one.  Here's the code, explanation of important stuff follows:

using System; using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography;
using System.IO;
namespace AppConfigSigner
{
    class Program
    {
        static void Main( string[] args )
        {
            // load the app config as an XmlDocument
            XmlDocument config = new XmlDocument();
            config.Load( args[ 0 ] );

            /* build up the XMLDSIG processor
             *
             * we'll use the following elements in our signature:
             *
             * - an enveloped signature transform; this will remove the
             *      actual Signature element from the document tree during
             *      XMLDSIG validation
             * - an empty Reference URI; this will indicate that the signature is applied
             *      to the entire containing document
             * - a default RSA signature key pair
             */
            XmlDsigEnvelopedSignatureTransform transform = new XmlDsigEnvelopedSignatureTransform();
            Reference reference = new Reference();
            reference.Uri = "";
            reference.AddTransform( transform );
            
            // create the XMLDSIG processor
            SignedXml xmldsig = new SignedXml( config );
            xmldsig.AddReference( reference );
            
            // set the signature key
            xmldsig.SigningKey = new RSACryptoServiceProvider();
            
            /* configure the key info elements of the signature;
             * this will instruct the XMLSIG validator on how to
             * obtain the public key to validate the signature.
             *
             * in our case, we're simply dumping the public key
             * right into the Signature element.  in production
             * this is a REALLY BAD idea, but it keeps the example
             * simple
             */
            xmldsig.KeyInfo = new KeyInfo();
            xmldsig.KeyInfo.AddClause(
                new RSAKeyValue( ( RSA )xmldsig.SigningKey )
            );
            
            xmldsig.ComputeSignature();
            
            XmlElement signature = xmldsig.GetXml();
            XmlNode signatureNode = config.ImportNode( signature, true );
            config.DocumentElement.AppendChild( signatureNode );
            
            /* save the config file
             *
             * note that we need to retain control over the file encoding
             * and the XML formatting to keep the signature valid.
             *
             * if you try this:
             *
             * config.Save( args[ 0 ] );
             *
             * you may never get a valid signature because the XmlDocument class
             * will pretty-up the XML with whitespace that wasn't there during
             * signature generation
             */
            using( FileStream fs = File.OpenWrite( args[ 0 ] ) )
            {
                using( XmlTextWriter writer = new XmlTextWriter( fs, Encoding.UTF8 ) )
                {
                    config.WriteTo( writer );
                }
            }
        }
    }
} 

The program does three things:

  1. Load an XML file specified on the command line;
  2. Sign the XML;
  3. Save the XML file back to its original location.

To calculate the XML digital signature, we need to specify few items; minimally:

In addition, we may also want to include information that the signature validator can use to find the appropriate public key during signature validation.  This is referred to as the XML digital signature KeyInfo, or sometimes the KeyInfo clause.

Creating the Signature 

The signature generation begins on line 30 with the creation of our Reference.  The XMLDSIG spec allows an XML digital signature to apply to all or part of an XML node set; the reference object is the way we identify what XML is being signed.  By supplying an empty URI value on line 32, we are indicating that the signature applies to the containing XML document.

On line 36, the SignedXml instance is created.  This is the class that will do the XMLDSIG heavy lifting.  Line 37 adds our Reference to the XMLDSIG processor.

Line 40 supplies the XMLDSIG processor with the signature key pair.  In this example, I'm using a randomly generated key set each time the config is signed; in production, you will likely want to use a specific key set every time.  

Lines 52-55 add key information to the XML digital signature.  Whoever will be verifying the app.config integrity will need to know what public key will validate the XML digital signature.  There are a plethora of options as to how to communicate public key information between two parties, enough best practices to fill a book.  To keep things simple (vs. secure), line 53 merely dumps the entire public key BLOB right into the XML digial signature.  No prizes for realizing this is a VERY BAD IDEA; there should be a very formal mechanism of public key exchange between the app.config signer and the app.config validator.  That's another post, let's get this working for now.

Line 57 calculates the signature of the app.config, and 59-62 add the XML digital signature to the app.config. 

Save the XML Delicately

The rest of the program saves the signed app.config.  This can be tricky business, as ANY significant alteration of the XML will result in the signature becoming invalid.  What's a significant alteration you ask?  Well, the addition of any whitespace for one, element ordering, text node changes of course, or the encoding of the XML.  I find that you cannot simply call the Save method of the XmlDocument class; the resulting XML is somehow invalidated during the write due to the addition of whitespace.  Your mileage may vary; if you find a better way, let the world know.

Validating the App.Config Digital Signature

The application in question will need to validate the digital signature of its app.config before it attempts to load any configuration values.  If the app.config is validated against its signature, then the application can merrily load up any values it needs, fully trusting that the configuration file is in a proper state.  If the file fails validation, the application knows that the configuration file has been tampered with and cannot be trusted.

Let's look at a sample program: 

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography.Xml;
using System.Xml;
using System.Configuration;
using System.Security.Cryptography;

namespace My
{
    static class Program
    {
        static void Main(string[] args)
        {
            // discover the path to the app config
            string configFilePath = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None ).FilePath;

            /*
            * load the app config as an XmlDocument
            *
            * it is vitally important to preserve any whitespace in
            * the original document, as the XMLDSIG spec defines ALL
            * whitespace as SIGNIFICANT
            */
            XmlDocument config = new XmlDocument();
            config.PreserveWhitespace = true;
            config.Load( configFilePath );

            // Create and initialize the XMLDSIG processor from our app config XmlDocument
            SignedXml xmldsig = new SignedXml( config );

            // find the XMLDSIG element
            XmlElement signature = ( XmlElement )config.GetElementsByTagName( "Signature" )[ 0 ];

            // load the XMLDSIG element into the XMLDSIG processor
            xmldsig.LoadXml( signature );

            // check the result of the signature
            bool result = xmldsig.CheckSignature();

            Console.WriteLine( result );
        }
    }
}

All this program does is validate the signature on its app.config and write the result of that validation to the console.

On line 26, the configuration XML document is told to preserve whitespace during load.  This is vital to proper XMLDSIG processing.  Normally the XmlDocument class will ignore "pretty-print" whitespace that exists between element nodes, but XMLDSIG considers this whitespace significant, so we need to make sure it gets into the XML node tree.

Line 30 initializes the XMLDSIG processor with the configuration XML document.  This is the document we need to validate.

Line 33 locates the XML digital signature element embedded in our app.config.  This element was added by our signer application.  The signature is fed to the XMLSDIG processor in line 36.

Line 39 is the money: the XMLDSIG processor is instructed to validate the app.config XML document against the digital signature by invoking the CheckSignature method.

The remainder of the program outputs the state of the app.config: True if the file is valid, False if it isn't. 

Do I Really Need to do This?

I tend to use DI/IoC a lot, and I tend to use one or more frameworks for configuring IoC containers, and they tend to like to read their configuration from my application configuration file, and I tend to wrinkle at the possibility of someone being able to modify my well-planned object graph with a little text file tinkering.  I've seen projects with configuration settings named "DisableSecurity" and "EnablePremiumFeatures" and yes the settings do exactly what you think they do.  In these cases I think this technique is valuable.

The question you need to ask yourself is: what could happen to my application if I can't trust my configuration file?  Consider the possibilities, and you'll have your answer.

Tune In 

I think this is a pretty kewl technique, if you think so too then grab the code and play around with the possibilities.  If there's interest and I get some time, I'd like to expand on some of the ideas started in this post.

XMLDSIGValidate.zip (8.43 kb)


Comments
Filed Under: software development
Keywords: ,

Exposing your privates the IL way!

§ February 10, 2008 15:55 by beefarino |

Here's a quick hack you can use to pry open those pesky closed types in a .NET assembly, even if you don't have the source code.  It also demonstrates the openness of managed platforms like .NET and Java.

NOTE: The procedure involves some simple decompilation techniques, so be sure you have legal hudspa to reverse whatever you're reversing.

The hack is quite simple:

  1. disassemble the .NET assembly using the ILDASM disassembler available in the .NET SDK;
  2. modify the disassembled IL code, changing private types / methods / properties / fields to public as necessary;
  3. reassembly the .NET assembly using the ILASM assembler, also available in the .NET SDK.

I'll walk through the technique using a simple example.  Take a quick look at the source code for a simple console application named myprogram.exe:

 namespace My
{
    static class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine( Message );
        }

        static string Message
        {
            get
            {
                return "this message is top secret";
            }
        }
    }
}  

The code defines one class, with one method and one property, and everything is private.  Our goal for today will be to make all of these things publically accessible without accessing this original source code.

Step 0: Create the Assembly ...

Build the sample code into an assembly named myprogram.exe using your favorite C# compiler.  If you want, try to referece the Program class in another assembly or project, and you'll notice that there are no publically visible types exposed by the myprogram.exe assembly.

If you have a flair for the dramatic, then you can delete the source code at this point since we don't need it anymore.

Step 1: Disassemble ...

The first step is to disassemble the .NET assembly using ILDASM:

ILDASM <assmebly-file> /nobar /out=<output-file> 

where <assembly-file> is the file name you want to disassemble, the /nobar switch supresses a UI progress bar, and the /out argument specifies the <output-file> that will contain the disassembly code.

The result of the above command is usually two new files, an IL file containing the disassembly, and a RES file containing the compiled resources from the assembly. 

For our purposes, we'll dump the IL into a temporary code file:

ILDASM myprogram.exe /nobar /out=temp.il

Step 2: Modify the IL ...

Step two is the nut of the hack.  If you've ever worked in assembler, but have never seen IL, you're in for a real treat (if you've never seen assembler and prefer not to dwell into such lands, you may want to skip the next section).

Sidebar to IL-town

Many of the CLI constructs that occur in the C# language appear almost verbatim in IL, making our current task excessively simple.  Crack open the temp.il file in your favorite code editor and gaze upon the IL rendition of myprogram.exe:

// note: assembly metadata removed for brevity

.class private abstract auto ansi sealed beforefieldinit My.Program extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // Code size       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  call       string My.Program::get_Message()
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } // end of method Program::Main

 .method private hidebysig specialname static string  get_Message() cil managed
  {
    // Code size       11 (0xb)
    .maxstack  1
    .locals init ([0] string CS$1$0000)
    IL_0000:  nop
    IL_0001:  ldstr      "this message is top secret"
    IL_0006:  stloc.0
    IL_0007:  br.s       IL_0009

    IL_0009:  ldloc.0
    IL_000a:  ret
  } // end of method Program::get_Message

  .property string Message()
  {
    .get string My.Program::get_Message()
  } // end of property Program::Message
} // end of class My.Program

 

Ignore all of the stuff that looks like gibberish for now - what I want you to note is that the class, method, and property-get accessor definitions are recognizable and follow predictable patterns.  Note also that they are each explicitly marked as being "private."  Sorry, but no prizes for guessing what comes next...

Modify the IL using simple text processing

The IL is just text, so we can do a simple search-and-replace with our favorite editor to make the modifications we need.  If we need to get fancy or specific, the signatures adhere to patterns well-suited for simple regular expression matching.  Whatever our scope, we simply need to change the declarations of interest from "private" to "public" (changes hilited):

.class public abstract auto ansi sealed beforefieldinit My.Program extends [mscorlib]System.Object
{
  .method public hidebysig static void  Main(string[] args) cil managed
  // ...
  .method public hidebysig specialname static string  get_Message() cil managed
  // ...
} // end of class My.Program

 

Step 3: Reassemble ... 

The IL doesn't do us any good in text form - we need the binary the IL describes.  Thanks to ILASM, the binary just a command line away...

ILASM /exe /output=<assembly-file> /res=<res-file> <source-file>

where /exe means we want to build an executable assembly, /output identifies the <assembly-file> we want to create, /res identifies a <res-file> referenced within the assembly.  Let's reassemble the open version of myprogram.exe:

ILASM /exe /output=open.myprogram.exe /res:temp.res temp.il 

This will produce a new executable named open.myprogram.exe that behaves identically to the original.  Granted, the final result of this effort may not appear terribly impressive, until you try to reference this new assembly in another project.  You'll find that the My.Program class and its members are all publically visible usable in your new project.

So ... What?

How often will you really need to expose hidden members and types without access to the original source?  Granted it will be infrequent, if ever.  I've done it enough times in the arcane projects I end up on to script the process in powershell.

And I'm not trying to prove that access modifiers fail to constitute a security platform.

The thing I find really interesting about this technique is the breadth of things you can accomplish with little to no background in reversing (the author being a case-in-point).  With a little effort and some googling on IL you can use the same basic technique to accomplish all of the following:

Accomplishing these kinds of things used to require specialized and esoteric knowledge, like "e9 is the machine code for an absolute jump on an x86 processor".  But in .NET and other managed platforms like Java, these things become so accessible you can practially leverage the original code during the reversing process.

... I'm not sure whether to stop grinning or shivering ...


Comments
Filed Under: software development
Keywords: , ,