Compiler-Based Mobile App Security vs. App Wrappers

GUARDSQUARE
GUARDSQUARE
Published in
5 min readApr 24, 2024

Written by Sander Bogaert

Mobile application protection puts the necessary lock on the application package you release. It prevents brand damage and revenue loss from threats such as back-end abuse, app cloning, piracy, IP theft, reverse engineering, and more. While there are multiple well-known tools available to protect your mobile app, they are, of course, not all created equally.

Selecting an application protection tool should not be a checklist exercise with obscure feature names. Rather, it should start with choosing a proper foundation! In this article, we explain the two groups of mobile app protection solutions available in the market. We’ll describe how they fundamentally work and why the group of compiler-based solutions is uniquely qualified to provide that foundation.

One group, mobile app security wrappers, will add a protected library with security primitives to your application. Typically, these solutions will instrument your original code with the required calls into the new library. The other group is compiler-based solutions which, on the other hand, will rebuild your original code completely and weave in multiple layers of protection in addition to hardening your application code.

So which of these groups fits your use case? In the sections below, we’ll first paint a more complete picture of both groups, afterward, we discuss the benefits, challenges, and appropriate use cases of each type.

Mobile app security with wrappers

Conceptually, wrappers are typically combinations of a regular Android/iOS SDK and some application package-level post-processing. The SDK serves two main purposes:

  1. Providing the application developer with some security controls, e.g. root detection
  2. Undoing transformations at runtime, which post-processing logic puts in place, e.g. code or asset encryption.

An important point to highlight here is that, just like any other regular SDK, there is a clear 1-to-many distribution approach. A single version or build of the SDK will be used to protect all customers.

A second SDK property that’s inherently shared by these types of solutions is the ‘separation of concerns.’ All library-provided logic is cleanly separated from your main application code. The communication between the two happens through a limited, by design, very visible set of channels. This separation exists on two abstraction levels: on the package file content level as a clearly separate library, and on the code level as a set of clearly separate functions. Though mitigation for the first one could be static linking, this is typically not possible due to technical constraints.

Some wrappers go a small step beyond combining a library with package-level post-processing and include some rudimentary code patching. Sometimes called ‘hybrid solutions’, these efforts are taken in an attempt to unlock some of the typical advantages of compiler solutions (described below). Some available examples include:

  • ‘unbreaking’ application code from the included library for tighter coupling,
  • automatically calling into the additional library from the application code to try and remove some of the security bottlenecks.

These patches are basic pattern matching-based replacements and should not be confused with proper recompilation-based solutions. The need to maintain the wrapper approach advantages prevents the required depth needed to make the code patching effective.

Compiler-based mobile app security solutions

Solutions in the compiler-based group will replace/repeat and enhance a step in the app compilation pipeline. Different solutions use different abstraction levels to apply their transformations (e.g. source-to-source, AST, IR, machine code). Though we won’t address the technical nuances of each abstraction level in this post, it is worth noting that there is more depth here to consider as it relates to leveraging a compiler-based solution.

Moving on, regardless of the chosen abstraction, the compiler-based approach enables analysis and code manipulation techniques fundamentally out of reach with any library-centric approach as seen in wrappers. These building blocks, in turn, unlock many of the advanced protection features that make up a modern software protection scheme. This is crucial because, in this way, compiler solutions level the playing field between attacker tools and the security solution, ensuring compiler solutions are not at a conceptual disadvantage vs. the attacker.

The major steps taken by compiler solutions are the following:

  • Parse and model the code and data, application package, and metadata
  • Reconstruct and derive high-level abstractions, e.g. control flow
  • Add to and transform the instructions
  • Rebuild and repackage the application

Several of these steps dictate some of the inherent properties not found in wrappers. First of all, having to parse, model, reason, and rebuild will always take more time than adding an additional library to your application. This results in comparatively longer build times than library-based approaches. Second, having to parse and model your application and its metadata means that this approach is more sensitive to changes in your tech stack, like switching languages or upgrading versions.

Wrappers vs. compilers: The key differences

Now that we understand both types of solutions, let’s explore some of the pros and cons of the earlier discussed characteristics.

One-to-many approach

As stated above, wrappers in general need no or very little information about the application they are protecting. They work 1-to-many, essentially just ‘packing’ all apps with the same protection library over and over again. This enables some quick wins, though they come at a great cost. The table below summarizes the trade-offs of this approach, the benefits of being a “pro” for app security wrapping solutions, and the disadvantages of being a “pro” for compiler-based solutions.

Skipping application & code modeling

Compiler solutions, depending on the exact approach, have to reconstruct and model a lot of information about the application they protect. This differentiator again leads to several (dis)advantages across our two groups. In the table below, the benefits of the modeling are a “pro” for compiler solutions.

When to use a wrappers vs. compiler-based solution

Overall, we’ve learned that app wrappers can potentially be a bit easier to set up and would probably have a smaller impact on your development flow. In addition, the reduced complexity and vendor R&D requirements should make them the cheaper solution. However, after a deeper look, it’s clear that these wins are only possible because of the many shortcuts taken with the library approach. While this would often be a net positive, this reasoning doesn’t apply to mobile application security at all!

So when can you use this approach to protect your mobile application? It’s a solid first step if your app is built with technology that no compiler-based solution supports yet. In addition, if your app is temporary (used for events, or various one-off instances) and the threat model allows for it, you could consider wrapping your application.

To summarize: Though it may seem counterintuitive, some complexity is actually a good thing for mobile application security. Avoiding it by design puts you at a fundamental disadvantage because it leaves your defense inherently lacking the depth it needs in a fast-evolving cat-and-mouse game.

Originally published at https://www.guardsquare.com on April 24, 2024.

--

--

GUARDSQUARE
GUARDSQUARE

Guardsquare offers the most comprehensive mobile application security solutions, from testing, protection & monitoring. Visit www.guardsquare.com for more info.