Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion best-practices/MASTG-BEST-0029.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Implementing Resilience and RASP Signals
alias: implementing-resilience-and-rasp-signals
id: MASTG-BEST-0029
platform: generic
knowledge: [MASTG-KNOW-0027, MASTG-KNOW-0028, MASTG-KNOW-0029, MASTG-KNOW-0030, MASTG-KNOW-0031, MASTG-KNOW-0032, MASTG-KNOW-0033, MASTG-KNOW-0034, MASTG-KNOW-0035]
knowledge: [MASTG-KNOW-0027, MASTG-KNOW-0028, MASTG-KNOW-0029, MASTG-KNOW-0030, MASTG-KNOW-0031, MASTG-KNOW-0032, MASTG-KNOW-0033, MASTG-KNOW-0034, MASTG-KNOW-0035, MASTG-KNOW-0089]
status: placeholder
note: Resilience controls and RASP (Runtime Application Self-Protection) style checks are defense in depth measures that raise attacker cost by detecting risky environments and runtime tampering. They do not replace secure design and they are inherently bypassable, so they should be selected and tuned based on the app's threat model and risk tolerance.
---
49 changes: 35 additions & 14 deletions knowledge/android/MASVS-RESILIENCE/MASTG-KNOW-0033.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ Android classes, methods, fields, packages, and local variables can be renamed t

This is a type of layout obfuscation, which doesn't impact the program's performance.

R8 and ProGuard can rename classes, methods, and fields during the release build process. The behavior is controlled through the release build configuration and keep rules that preserve selected identifiers. See the [Android app optimization documentation](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization), the [Android keep rules guide](https://developer.android.com/topic/performance/app-optimization/add-keep-rules), and the [ProGuard manual](https://www.guardsquare.com/manual/configuration/usage).
R8 and @MASTG-TOOL-0022 can rename classes, methods, and fields during the release build process. The behavior is controlled through the release build configuration and keep rules that preserve selected identifiers. See the [Android app optimization documentation](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization), the [Android keep rules guide](https://developer.android.com/topic/performance/app-optimization/add-keep-rules), and the @MASTG-TOOL-0022 [manual](https://www.guardsquare.com/manual/configuration/usage).

The following example shows how identifier renaming can be enabled in a release build with R8 or ProGuard.
The following example shows how identifier renaming can be enabled in a release build with R8 or @MASTG-TOOL-0022.

```groovy
android {
Expand All @@ -36,7 +36,7 @@ android {
// your project's release build type.
minifyEnabled true

// Includes the default ProGuard rules files that are packaged with
// Includes the default optimization rules files packaged with
// the Android Gradle plugin. To learn more, go to the section about
// R8 configuration files.
proguardFiles(
Expand All @@ -48,7 +48,7 @@ android {
}
```

The file `proguard-rules.pro` is where you define custom ProGuard rules. With the flag `-keep` you can keep certain code that is not being removed by R8, which might otherwise produce errors. For example:
The file `proguard-rules.pro` is where you define custom @MASTG-TOOL-0022 rules. With the flag `-keep` you can keep certain code that is not being removed by R8, which might otherwise produce errors. For example:

```pro
-keep class com.example.api.PublicApi { *; }
Expand All @@ -65,9 +65,9 @@ String encryption replaces plaintext literals with encoded or encrypted represen

When this technique is applied, the original string values may no longer appear directly in the decompiled code or extracted DEX data; the clear strings are only present at runtime.

`dProtect` extends the ProGuard rule format with string obfuscation passes. See the [dProtect strings encryption documentation](https://obfuscator.re/dprotect/passes/strings/) for more information about how to encrypt strings.
@MASTG-TOOL-0153 extends the @MASTG-TOOL-0022 rule format with string obfuscation passes. See its [strings encryption documentation](https://obfuscator.re/dprotect/passes/strings/) for more information about how to encrypt strings.

The following example shows how string obfuscation can be configured with `dProtect`.
The following example shows how string obfuscation can be configured with @MASTG-TOOL-0153.

```pro
-obfuscate-strings class com.example.sensitive.ApiClient {
Expand All @@ -82,6 +82,17 @@ Android apps can keep part of their logic outside the main static DEX view and m

This changes where executable logic is stored and when it becomes available to the runtime. As a result, part of the application logic may be separated from the main static codebase and may only become visible after the corresponding loading or unpacking logic executes.

For example, an app can store `payload.dex.enc` in `assets/`, decrypt it after startup, and load the resulting DEX bytes with `InMemoryDexClassLoader`.

```kotlin
val encrypted = assets.open("payload.dex.enc").readBytes()
val dexBuffer = ByteBuffer.wrap(decrypt(encrypted, runtimeKey))
val loader = InMemoryDexClassLoader(dexBuffer, classLoader)
val entry = loader.loadClass("com.example.protected.Entry")
```

Use @MASTG-TOOL-0009 with @MASTG-TECH-0165 to identify known compilers, obfuscators, and packers in APKs. The absence of a known signature does not prove that dynamic loading or custom packing is not present.

### Reflection and Indirect Invocation

Reflection is a property of some programming languages, including Java, that allows an app or process to inspect types and invoke constructors, methods, and fields dynamically at runtime.
Expand All @@ -96,9 +107,9 @@ The control-flow graph of a function is a representation of the elementary compu

Control flow obfuscation modifies the bytecode to produce a more complex control-flow graph in the decompiled output. Common examples include inserted conditions, opaque predicates, or transformations around branch instructions such as `GOTO #offset`.

`dProtect` provides a dedicated pass for this transformation. See the [dProtect control-flow obfuscation documentation](https://obfuscator.re/dprotect/passes/control-flow/).
@MASTG-TOOL-0153 provides a dedicated pass for this transformation. See its [control-flow obfuscation documentation](https://obfuscator.re/dprotect/passes/control-flow/).

The following example shows how control-flow obfuscation can be configured with `dProtect`.
The following example shows how control-flow obfuscation can be configured with @MASTG-TOOL-0153.

```pro
-obfuscate-control-flow class com.example.sensitive.** { *; }
Expand All @@ -116,6 +127,16 @@ Obfuscation in Android apps is not limited to executable code. Apps can also enc

These resources may contain configuration data, scripts, model files, web assets, or auxiliary data consumed by the Java or Kotlin layer at runtime. The app then includes logic to decode or decrypt the resource before using it.

For example, an app can store `rules.json.enc` or `model.bin.enc` in `assets/` and decrypt the file with `javax.crypto.Cipher` before parsing or passing it to the relevant runtime component.

```kotlin
val encrypted = assets.open("rules.json.enc").readBytes()
val cleartext = cipher.doFinal(encrypted)
val rules = JSONObject(cleartext.decodeToString())
```

This protects against direct resource extraction from the APK, but it does not prevent recovery of the decrypted data or decryption material during runtime analysis.

## Native Layer

Native code can be obfuscated with many different transformations. On Android, these techniques are commonly applied to C or C++ code compiled with the NDK and operate on lower-level representations such as LLVM IR or machine code, rather than on DEX bytecode.
Expand All @@ -136,7 +157,7 @@ This makes the execution flow harder to follow because the natural branching str

[O-MVLL](https://obfuscator.re/omvll/passes/control-flow-flattening/) provides a control-flow flattening pass for native code.

The following example shows how control-flow flattening can be enabled with `O-MVLL`.
The following example shows how control-flow flattening can be enabled with O-MVLL.

```python
def flatten_cfg(self, mod: omvll.Module, func: omvll.Function):
Expand All @@ -153,7 +174,7 @@ In native code, one way to achieve this is to add duplicate basic blocks, redund

For example, adding duplicate basic blocks is made by [O-MVLL Basic Block Duplicate](https://obfuscator.re/omvll/passes/basic-block-duplicate/), which, as said previously, duplicates the selected basic blocks and inserts a runtime branch that chooses between equivalent versions of the same logic.

The following example shows how junk code can be introduced with `O-MVLL`'s Basic Block Duplicate pass.
The following example shows how junk code can be introduced with O-MVLL's Basic Block Duplicate pass.

```python
def basic_block_duplicate(self, mod: omvll.Module, func: omvll.Function):
Expand All @@ -166,7 +187,7 @@ Arithmetic obfuscation replaces simple arithmetic or bitwise operations with mor

[O-MVLL](https://obfuscator.re/omvll/passes/arithmetic/) provides an arithmetic obfuscation pass that rewrites operations into more complex expressions.

The following example shows how arithmetic obfuscation can be enabled with `O-MVLL`.
The following example shows how arithmetic obfuscation can be enabled with O-MVLL.

```python
def obfuscate_arithmetic(self, mod: omvll.Module,
Expand All @@ -182,7 +203,7 @@ Plaintext strings in native code can reveal implementation details such as file

[O-MVLL](https://obfuscator.re/omvll/passes/strings-encoding/) provides several string encoding options for native code.

The following example shows how string encoding can be configured with `O-MVLL`.
The following example shows how string encoding can be configured with O-MVLL.

```python
def obfuscate_string(self, _, __, string: bytes):
Expand All @@ -197,7 +218,7 @@ Opaque constants protect integer constants by replacing them with more complex c

[O-MVLL](https://obfuscator.re/omvll/passes/opaque-constants/) provides a pass for obfuscating constants in native code.

The following example shows how opaque constants can be enabled with `O-MVLL`.
The following example shows how opaque constants can be enabled with O-MVLL.

```python
class Config(omvll.ObfuscationConfig):
Expand All @@ -213,7 +234,7 @@ Obfuscated function calls hide the original callee by replacing direct calls wit

[O-MVLL](https://obfuscator.re/omvll/passes/indirect-call/) provides an indirect call pass that converts direct calls into indirect calls.

The following example shows how indirect calls can be enabled with `O-MVLL`.
The following example shows how indirect calls can be enabled with O-MVLL.

```python
def indirect_call(self, mod: omvll.Module, func: omvll.Function):
Expand Down
Loading
Loading