PreEmptive logo

Symbol Renaming: App Security’s Maginot Line?

If you don’t follow application security closely, you might think of application obfuscation and symbol renaming as synonymous with good reason. Many platforms and languages, like .NET, Java, and JavaScript, have popular obfuscators that do little else—our own Dotfuscator Community Edition for .NET and ProGuard for Java are good examples. However, obfuscation is far more than symbol renaming—and in-app protection is far more than obfuscation. Much of this expansion has been driven by new security requirements, shifting attack vectors, the rise of mobile and IoT computing, and the growing recognition inside regulations and legislation of the exposure that can result from inadequately protected software. 

Is your application security built to defend against yesterday’s threats? 

One of the most widely used metaphors for expensive efforts that offer a false sense of security, the Maginot Line consists of concrete fortifications and weapons installations built by France in the 1930s to prevent a potential invasion by Germany. It was expertly constructed, reflecting the hard-won lessons from “the war to end all wars” (World War I). Unfortunately for France, Germany applied the lessons learned to their tactics and quickly adapted the latest technologies to warfare. They made short work of this supposed impenetrable defense, mostly by driving around it and flying over it. The reliance on a single (and dated) line of defense led to a quick and humiliating rout, which shocked the French public, who had been led to believe that it was “impregnable.”

Renaming in context

While certainly still relevant, renaming plays a smaller role in today’s notion of in-app protection. Figure 1 illustrates both the relative positioning of renaming inside the broader category of effective in-app security and some of the variants of renaming that may (or may not) be available inside a typical renaming transform.

Renaming Limitations

Renaming takes meaningful method names like “create_user_account” or “post_transaction” and variables like “account_num” and turns them into meaningless names like “a,” “b,” and “c.” This can make reverse engineering an application confusing for a hacker but not necessarily for other programs. Non-sensical names don’t confuse debuggers, monitoring tools, or even basic source-code generators.

RenameMaginot

As such, effective obfuscation needs to offer a layered approach, including:

  • Control Flow: changing the instruction flow executed at runtime in such a way as to break reverse engineering tools while not altering the application’s behavior.
  • String Encryption: mangling string resources so that it is difficult to search for and read them directly from the binaries. 
  • Instruction Pattern Transformation: replacing common instruction patterns generated by the compiler with other, less obvious constructs that may not map cleanly to high-level languages such as Java or C#.
  • Dummy Code Insertion: inserting code into the executable that does not affect the program’s logic but breaks decompilers or makes reverse-engineered code much more difficult to analyze.
  • Unused Code and Metadata Removal: removing debugging information, non-essential metadata, and unused code from applications. This makes them smaller and reduces the information available to an attacker. 

Renaming Variants 

Renaming is only safe when the transform can identify and update all references to a symbol with “the new name.” There are some scenarios where this is not possible. For instance, renamers can have difficulty identifying symbols referenced dynamically at runtime (e.g., used via reflection APIs). Another scenario is where the component exposes symbols for outside use by other (unprotected) applications. In both these scenarios, the renamer needs to exclude these symbols from the renaming process in order for the application to work correctly.

These scenarios give rise to more sophisticated implementations of renaming that can 

  • automatically detect publicly visible symbols and preserve their names (library mode)
  • share renaming across separate components (allowing consistent public symbol renaming across dependencies )
  • recognize popular patterns and frameworks (like XAML) and extend renaming in ways that static analysis alone could not

In short, there are meaningful distinctions even within the microcosm of renaming.

Prevention is more than obfuscation

Just as obfuscation is more than renaming, prevention is more than obfuscation. Obfuscation is a collection of transforms designed to prevent reverse engineering and tampering. The operative word in that last sentence is “prevent.” Obfuscation is a “Preventative Control” and there are now several other accepted and recognized alternatives (or compliments) to obfuscation that also help to prevent unauthorized access and control over applications. A sampling of these include anti-tamper, anti-emulator, anti-root, and anti-debug controls. Sometimes, before an attack, a bad actor will use these tools (in combination with others) to poke, prod, and otherwise compromise the software and systems they hope to ultimately hack. By denying the hacker access to these tools, even in their own sandbox, these controls are recognized as “preventative.”

In-app protection is more than prevention

Just as prevention was more than obfuscation, in-app protection is more than prevention. There are several similar models out there, and they all generally converge around three to five pillars.

  • Preventative Controls try to prevent bad things from happening. If these controls were 100% effective, we could all stop here. For example, we could save time and money on smoke detectors if we needed electrical insulation to prevent home fires. 
  • Detective Controls are the next line of defense. These controls detect when one of the events we have been trying to prevent has somehow managed to occur. 
  • Responsive Controls are the activities triggered when an event is detected. They can include defensive measures, corrective measures, and reporting or notification responses. 

Today’s in-app protection solutions must offer controls from each of these categories to ensure an effective level of security and to address what are now considered standard practices by security auditors, regulators, and enforcement agencies. 

Depth and Breadth

Just as symbol renaming comes in various forms with varying levels of sophistication, anti-debugger, anti-tamper, and all of the other categories of controls are (at least) as varied and specialized. Runtimes (Android versus .NET versus JavaScript…), platform (cloud, mobile, desktop, IoT…), and compliance obligations (PCI DSS, GDPR, …) each bring unique requirements that cannot be ignored. 

Whenever possible, learn from the mistakes of others (to avoid unnecessary mistakes of your own)

Keeping up with evolving threats and compliance obligations is—to continue with the military analogy—a two-front war that is typically well outside the scope of companies in any other line of business. 

And that’s an important pillar of PreEmptive’s mission, to track and counter the tool developments of common adversaries, understand the implications of the latest breaches, and reconcile all of this against the backdrop of evolving regulations—all to help ensure that our clients aren’t building last year’s defenses for next year’s attacks.

In This Article:

Try a Free Trial of PreEmptive Today!