March 18, 2025

    A Layered Approach to Mobile App Protection: Creating Defense-in-Depth

    How an attacker views your app

    The rise of fake, modified mobile apps should serve as a wake-up call for companies and brands to reinforce their app security. Organizations must take proactive steps to prevent attackers from reverse-engineering their applications, tampering with app logic, or studying proprietary intellectual property (IP). Protecting your IP means ensuring that no one can create unauthorized "enhanced" versions of your app, replicate proprietary algorithms, or extract key functions from your app or SDK. It also means preventing unauthorized modifications, access to, and use of, APIs, content, or sensitive IP.

    Security breaches highlight the serious consequences of neglecting mobile application protection. Attackers often begin by decompiling an app using readily available tools, allowing them to access its folder structure and source code. This makes identifying risks, and security gaps, and making unauthorized modifications easier. Strengthening app security is no longer optional, and it is essential to safeguarding your brand, users, and proprietary technology.

    The typical attack process:

    • Decompiling the app – Using decompiler tools to retrieve the app’s source code.
    • Reverse engineering – Understanding the app’s logic and security implementations.
    • Modifying the code – Disabling security checks or injecting malicious code.
    • Recompiling and distributing the modified app – Creating a compromised version for exploitation.

    With a weak security approach, such as applying a single layer of protection, the attacker can easily bypass security mechanisms and either change the application code logic or add his own malicious code to the application​​. This is why a multilayered security approach is critical.

    Why a single-layer of security is inadequate

    Now, let's consider the flaws in single-layer security approaches. A single-layer approach, such as simply wrapping the app in a security layer or relying on one method (e.g., root detection), may seem like a quick solution. However, attackers can often bypass individual protection mechanisms or find different techniques for achieving their goal. Remember do not rely on a single protection mechanism, for example:

    Overreliance on any single protection feature

    • Encrypting the entire code into one blob and then decrypting it at runtime may sound like a good idea. However, once the attacker figures out the decryption mechanism, they can retrieve the original code and access the underlying logic, rendering the entire approach ineffective.

    It's important to emphasize that techniques like code encryption can be part of an effective protection strategy for your mobile app. The challenge is when they are used in isolation as the sole security measure. This nuance is crucial: the problem isn't the technique itself but the overreliance on a single layer of protection. A competent security strategy requires multiple layers of protection, as no single technique can fully safeguard an application against attacks.

    When used in isolation, these techniques fall short because they create a single point of failure. Once an attacker breaks through one layer, they gain access to the app's logic and data. This is why multilayered security is essential. By incorporating multiple defenses, even if one layer is breached, others will still protect the app.

    What is a multilayered approach to app security?

    From banking to social media to e-commerce, mobile apps handle a vast amount of personal data and provide access to essential services. This makes them prime targets for malicious intent. Securing the app at multiple levels is paramount to protecting your app and its users. A multilayered approach to mobile app security is a dynamic and strategic defense method that goes beyond simple encryption or obfuscation. In this blog, we'll delve into the importance of such an approach and explain how it works to thwart reverse engineering and tampering attempts by attackers.

    A multilayered approach combines various techniques and protection layers to defend an application against malicious attacks. By using several different methods to secure your app, you can effectively reduce the chances of any single attack method succeeding. While no single security layer is foolproof, the combination of multiple techniques creates a strong security architecture that an attacker must bypass.

    To understand the effectiveness of a multilayered security approach, consider the analogy of a medieval castle. ​​Just as a castle relies on multiple layers of defense - a drawbridge, a moat, fortified walls, and watchtowers - mobile app security should integrate multiple protective techniques that work together to strengthen overall resilience. These layers may include code obfuscation, string encryption, control flow obfuscation, and runtime protections, among others. While this is not an exhaustive list, Guardsquare’s dedicated Security Research team continuously refines and enhances security strategies to stay ahead of emerging threats.

    When an attacker attempts to reverse engineer an app, layered defenses create significant hurdles, requiring substantial time, effort, and resources to bypass. By disrupting the attacker’s workflow and increasing the complexity of reverse engineering, developers can significantly reduce the risk of successful exploitation, ensuring stronger protection for their applications.

    Multilayered protection against static analysis

    Static analysis debugs compiled code without running the application. Let’s explore the types of protection that can be incorporated into a mobile app and see how they work together.

    Please note the examples provided here are intentionally simplified to illustrate key security concepts clearly. In real-world applications, security measures are far more sophisticated, relying on advanced, multi-layered strategies to effectively protect against threats. Guardsquare’s solutions go well beyond these fundamental techniques, incorporating a diverse range of cutting-edge protections designed to provide robust and comprehensive protections.

    1. Name obfuscation: The first line of defense

      One of the first layers of defense is obfuscating function and class names. Name obfuscation is the process of making the source code difficult to understand by transforming the code into a version that looks like a meaningless mess yet still functions correctly. This makes it much harder for an attacker to extract sensitive information from the app by reading through the code.

      Original Code:

      public class UserAuthenticator {
          public boolean authenticate(String username, String password) {
              // Authentication logic
          }
      }
      

      Obfuscated Code:

      public class a {
          public boolean b(String c, String d) {
              // Authentication logic
          }
      }
      

      While helpful, AI-powered tools can infer function names and, in some cases, allow the attacker to defeat this basic protection. Thus, additional layers are necessary.

    2. String encryption: Protecting sensitive data

      Another common weakness in many mobile apps is the hardcoding of sensitive information, such as API keys, credentials, and tokens, directly in the code. Even if an app's code is obfuscated, these plain-text strings can still be exposed when an attacker decompiles the app. Encrypting strings ensures that critical information remains protected.

      This is where string encryption plays a vital role. By encrypting strings and decrypting them only at runtime, developers ensure that sensitive data is never exposed in plain text within the app’s code.

      Without Encryption:

      String apiKey = "12345-ABCDE";

      With Encryption:

      String encryptedKey = decrypt("fgdsf43y6sf3f4fs");
    3. Control flow obfuscation: Misleading the attacker

      While obfuscating code and encrypting strings are essential, they don’t necessarily prevent attackers from understanding the logic of the app. Once attackers can analyze the flow of execution, they might be able to reverse engineer critical functionality. To prevent this, control flow obfuscation is used.

      Control flow obfuscation alters the code’s logical flow, introducing artificial loops, branches, and jumps that make it harder for an attacker to follow the original execution path. In simple terms, it takes a straightforward process and makes it look like a convoluted mess of code. This adds another layer of difficulty for reverse engineers trying to determine the app's core functionality.

      Before:

      if (user.isAuthenticated()) {
          grantAccess();
      } else {
          denyAccess();
      }
      

      After:

      switch (someComplexCondition()) {
          case 1:
              grantAccess();
              break;
          case 2:
              denyAccess();
              break;
          default:
              logError();
              break;
      }
      
    4. Eliminating direct method calls: Another step towards confusion

      Replacing direct function calls with indirect references hides method calls, making it harder to understand the app’s logic.

      Attackers typically look for specific methods and function calls when trying to reverse engineer an app. Method call hiding adds another layer of disarray by obfuscating method calls, making it difficult for attackers to track which functions are being executed.

      By hiding method calls or renaming methods to random characters, attackers will have a harder time understanding which functions are interacting with each other and how the app operates. This technique, when used in conjunction with control flow obfuscation and string encryption, ensures that reverse engineers can't easily deduce the app’s underlying logic.

      Before:

      UserAuthenticator auth = new UserAuthenticator();
      auth.authenticate(username, password);
      Object result = callMethod("wfowo434#$3", username, password);
      

      In this example, direct method calls are replaced with a generic proxy function (callMethod), which takes an obfuscated string identifier and parameters instead of referencing actual class or method names. Unlike standard reflection, the obfuscated identifier ("wfowo434#$3") does not directly correspond to the real method name. Instead, it is mapped internally within the code, making it significantly harder for attackers to reverse-engineer or identify the original function being invoked.

    Multilayered protection against dynamic analysis

    Even when static analysis tools fail to break down an app, attackers can still use dynamic analysis to attack a running application. Dynamic analysis allows attackers to observe how an app behaves when it’s executed, giving them an opportunity to manipulate or tamper with the app's runtime environment. How do they begin? Enter - Debuggers.

    A debugger is a tool that enables developers to analyze software code during execution, helping them identify and resolve issues in real time. However, attackers can also misuse debuggers to identify security gaps, bypass security measures, and manipulate app functionality for malicious purposes.

    To counter this, Runtime Application Self-Protection (RASP) techniques are embedded directly into the app. RASP monitors the app's runtime behavior and detects any suspicious activity, such as attempts to tamper with the app's memory or bypass security mechanisms. RASP should ideally operate from within the app, making it harder for attackers to disable or circumvent it.

    Moreover, RASP can be implemented in a way that makes it difficult for attackers to identify the specific checks. Instead of relying on a single RASP thread or function, developers can distribute RASP checks throughout the entire app code. This increases the complexity of the app’s security and makes it more challenging for attackers to bypass it.

    Creating a controlled environment for dynamic analysis:

    1. Modifying the system – Attackers alter the OS to observe and control the application’s execution. Most of the time, an attacker's first step is to use a rooted or jailbroken device, allowing them to read or tamper with any data stored at rest by the application. This is often a prerequisite for utilizing more advanced dynamic analysis tools.
    2. Modifying application data – Changing the application’s data at rest or in process memory can alter the behavior of the application. Sometimes, applications store the status of premium features in local data storage without encryption. In such cases, an attacker can achieve their goal simply by modifying this file. If that's not possible, they will need to take the next step: modifying the application itself.
    3. Modifying the application – Directly changing the app to observe and control the application’s execution. For instance, the attacker may use hooking or a debugger to trace the code execution and potentially alter the application's behavior.

    Strengthening runtime security with RASP

    • Single RASP check A single check can be easily disabled by an attacker, rendering it ineffective.
    • Multiple reinforcing RASP checks

    By embedding RASP checks directly into the user code rather than isolating them in separate functions, attackers face an exponentially greater challenge in bypassing security. This exponential difficulty arises because the checks are not just standalone barriers; they reinforce and interlock with each other. If an attacker identifies and attempts to disable a root check, an application resigning check might stop them. If they try bypassing that by tampering with system libraries, system library integrity will detect the manipulation. Any attempt to patch out a system integrity check could be thwarted by code checksumming, while attempts to hook into that check could trigger additional layers of detection. Each failed attack leads to another hurdle, creating a compounding effect where the time and effort required to bypass security measures increase dramatically. This layered, interdependent approach makes it significantly harder for attackers to disable even a single check, let alone compromise the entire app.

    The role of a compiler based approach in this layered strategy

    Compiler based approach plays a vital role in implementing effective code obfuscation. Guardsquare’s approach is analogous to how a compiler works, we operate on the code directly, rather than encapsulating the code with a simple layer of protection. Since compilers naturally regenerate an application's code, they provide an ideal framework for embedding security controls seamlessly. This capability supports advanced code analysis and transformation techniques, serving as a cornerstone of modern software protection.

    One of the biggest advantages of compiler-based obfuscation is its ability to introduce randomized variations in code semantics, structure, and placement with minimal effort from developers. This results in two major benefits:

    The "reset the clock" effect – Each new application version forces attackers to start their reverse-engineering efforts from scratch, which, after a point in time, becomes expensive in every aspect and, hence, futile.

    At Guardsquare, we refer to this phenomenon as polymorphism, meaning that the security measures change with each new app version. This dynamic strategy ensures that attackers can't rely on the same knowledge to tamper with the app over time. With every new build, the protection mechanism adapts, making reverse engineering significantly harder.

    A vast, uniformly obfuscated "haystack"—The idea behind "haystacking" comes from the proverb "finding a needle in a haystack." In the context of mobile app security, this means making it difficult for attackers to locate what they’re trying to protect in the first place. This involves two key aspects: hiding secrets and embedding protections. With the help of Guardsquare products, developers can obfuscate far more than just critical secrets; they can disguise other parts of the codebase as well, making it harder to distinguish sensitive elements from the rest. Similarly, RASP (Runtime Application Self-Protection) should not only be applied to high-value functions but distributed throughout the code to create additional layers of security. RASP checks are incorporated into the code during compilation.

    This comprehensive approach ensures that both the app’s defenses and its sensitive data remain deeply concealed, significantly increasing the effort required for an attacker to reverse-engineer the application. By utilizing a compiler based approach, developers can ensure that security mechanisms are not only deeply embedded but also evolve dynamically with each build.

    The much needed complexity of multilayered security

    A multilayered approach to mobile app security is essential for protecting both the app and its users from reverse engineering and malicious attacks. By combining techniques like name obfuscation, string encryption, control flow obfuscation, and other obfuscation techniques complemented by runtime protection, all of which adapt with every software build, developers can create an app that is far harder to breach.

    The key takeaway is that it’s not enough to rely on a single layer of protection. As attackers grow more sophisticated, so must our security strategies. By implementing multiple layers of defense, we make it exponentially harder for attackers to succeed, protecting our apps, data, and user trust. Weaving these layers seamlessly into the app’s structure, developers can significantly increase the complexity of reverse engineering attempts, deterring attackers and securing sensitive application logic. Mobile app security is not just about adding protections. It’s about strategically layering them for maximum resilience.

    Just as a medieval castle architecture used to defend its owner, so does this modern security strategy for your mobile apps, and the stakes are equally high.

    Contact us to discuss your mobile app security strategy.

    Discover how Guardsquare provides industry-leading protection for mobile apps.

    Request Pricing

    Other posts you might be interested in