Blog 2 min read

Detect Obfuscated Names in a C/C++ Project

Share this article
Detect Obfuscated Names in a C/C++ Project

How many times have you come across code like this?

obfuscatednames

In some cases, code like this may not be a major issue. But if developers use this coding practice frequently, it can become costly for the company. Every newcomer who needs to debug the code or add a new feature will spend a significant amount of time trying to understand the existing codebase.

How can we detect these obfuscated names so that we can refactor them?

1. Using clang-query and  AST Matchers

Clang’s LibASTMatchers is a powerful library for matching nodes in the AST and executing code that uses the matched nodes. Combined with LibTooling, LibASTMatchers helps to write code-to-code transformation tools or query tools.

The clang-query tool is based on LibASTMatchers and provides an easy way to query the AST nodes of a specific source file.

For example, if we want to detect functions whose names contain only one character, we can execute this AST matcher:

functionDecl(matchesName("^[a-zA-Z]$"))

AST Matchers provide a powerful way to query a codebase. Here's a quick definition from the AST Matchers documentation.

AST matchers are predicates on nodes in the AST. Matchers are created by calling creator functions that allow building up a tree of matchers, where inner matchers are used to make the match more specific.

For example, to create a matcher that matches all class or union declarations in the AST of a translation unit, you can call recordDecl(). To narrow the match down, for example to find all class or union declarations with the name “Foo”, insert a hasName matcher: the call recordDecl(hasName("Foo")) returns a matcher that matches classes or unions that are named “Foo”, in any namespace. By default, matchers that accept multiple inner matchers use an implicit allOf(). This allows further narrowing down the match, for example to match all classes that are derived from “Bar”: recordDecl(hasName("Foo"), isDerivedFrom("Bar")).

2. Using CppDepend and CQLinq

CppDepend comes with CQLinq, a code query language for querying your codebase.

CQLinq defines several predefined domains that you can query, including: Types; Methods; Fields; Namespaces; Projects

These domains enumerate not only all code elements of the code base queried, but also all third-party code elements used by the code base (like for example the type string and all methods and fields of the type string that are used by the code base).

The syntax is as simple as:

from m in Methods where m.NbLinesOfCode > 30 select m

And to detect functions whose names contain only one character, we can execute the following CQLinq query:

Untitled2

Conclusion:

Do not underestimate the importance of symbol names; good names make a codebase easier to understand and maintain. Automating your build process to detect poorly named symbols can help improve the overall quality of your codebase.

Share this article