In theory, an organization is able to see exactly what code will do if it develops its own proprietary code libraries. However, this is a fallacy, since often simply being able to read the source code for a program does not imply you understand what it is capable of doing.

The perfect example of this is the buffer overflow/overrun exploit that has plagued many applications for many years. To this day, code is still being written that is vulnerable to this well-known and understood exploit.

However, most organizations do not have the luxury of being able to avoid common security exploits. They’re left with one of two options. They can search through the code for the problem and hope that the problem doesn’t exist elsewhere. Otherwise, they can recognize that if the problem exists in one place then it likely exists in other places. As those in the pest control industry say, “Where there is one, there are bound to be more.”

But how can an organization effectively track down every occurrence of a certain type of bug/exploit? Enter application transformation. Application transformation, specifically source transformation, allows developers to identify patterns in code and fix all occurrences of those patterns instead of simply one occurrence.

The full power of simple find/replace

Using the programming language C++, we can contrive a simple example of using find/replace. Suppose the problem is a result of using a particular class within a particular library. Further, suppose that the company has decided not to use that class and instead has found a class from a different organization that addresses the problem. So the issue becomes one of removing references to the original class and inserting references to the new class they will use.

The expectation might be that this can be achieved using a simple find/replace mechanism. For example, in the following C++ code:

class MySecurityClass{

StringPtr m_stringPtr;

public:

MySecurityClass (){}

MySecurityClass (char * charPtr_){

m_stringPtr = StringPtr (new String (charPtr_));

}

void foo (int someInt, StringPtr stringPtr){

}

};

It is conceivable that the organization decides that it no longer wants to make use of the StringPtr class because it happens that it is vulnerable to the buffer overflow/overrun exploit. So it will switch to using a different String class implementation (TCStringPtr) by making use of a simple find/replace:

class MySecurityClass{

TCStringPtr m_stringPtr;

public:

MySecurityClass (){}

MySecurityClass (char * charPtr_){

m_stringPtr = TCStringPtr (new String (charPtr_));

}

};

The Real Problem

The above can easily be achieved using a simple find/replace; however most “real” code will be doing something more complicated than invoking a single constructor and in many cases the interfaces between classes will not be identical. The code that uses those classes may have to be changed as well — for example:

class MySecurityClass{

SomeClass m_someObj;

public:

void foo (int someInt_){

m_someObj.foo(someInt_);

m_someObj.anotherFoo();

}

void aDifferentFoo (int someInt_){

m_someObjWithDifferentName.foo(someInt_);

m_someObjWithDifferentName.anotherFoo();

}

};

Now let’s assume that the organization using the above code wants to make use of a different class that has a different interface than the class it was using before. Now it needs to ensure that instead of instantiating an object of type SomeClass, it instantiates an object of type SomeOtherClass. However, as it turns out the interface of SomeOtherClass isn’t the same as the interface of SomeClass. In fact, SomeOtherClass can use one method/function named “betterFunction” everywhere that SomeClass was previously using both “foo” and “anotherFoo.” So the above code should become:

class MySecurityClass{

SomeOtherClass m_someObj;

SomeOtherClass m_someObjWithDifferentName;

public:

void foo (int someInt_){

m_someObj.betterFunction(someInt_);

}

void aDifferentFoo (int someInt_){

m_someObjWithDifferentName.betterFunction(someInt_);

}

};

However, this simply cannot be achieved properly using a simple find/replace. The main problem is that simple find/replace mechanisms lack code comprehension. Therefore, there is no way to tell the find/replace mechanism to find each instance of a SomeClass object and its use of the “foo” method/function that takes an int as an argument, followed by an invocation of “anotherFoo” method/argument, and then replace it with the single invocation of SomeOtherClass’s “betterFunction” method/function.

The Solution

The only way to teach a computer a language is to give that computer a grammar. A grammar, as it applies to a language like English, is something that can be used to understand how words can be combined to form sentences. The concept is the same for grammars of languages like C++ and Java. It describes how the various parts of a computer language can be combined to form valid computer programs.

By making use of a grammar, the computer is able to “understand” the semantics of almost any language. Most source transformation tools make use of a grammar so that they can go beyond the power of simple find/replace mechanisms.

TXL: The Program

A popular source transformation tool that can be obtained free of charge is a program called TXL. Without getting into the technical details of how TXL works, TXL allows developers to specify their grammar and then a set of rules for how they would like to transform an existing program.

By leveraging TXL, a developer is able to “write code that will itself write code.” However, the power of TXL goes far beyond the ability to simply determine the type of an object and change its method invocations according to a change in the requirements for an application. TXL has been used for a wide variety of applications, such as Programming Language Processing, Program Analysis and Instrumentation, Software Engineering, Database and Document Processing.

In addition, TXL has already been successfully used to reduce the occurrence of buffer overflows/overruns in C programs. Application security is often approached in a point solution manner instead of in a holistic manner. This results in an iterative process of finding and solving each instance of a particular problem/exploit rather than identifying the common pattern.

By making use of transformational software like TXL, an organization can effectively reduce the amount of time required to find and fix security problems.

Cassidy is a senior consultant with Deloitte Security Services.