Tampering Detection
Tampering detection is a critical aspect of ensuring the integrity and security of software applications. In the context of the .NET, Babel Obfuscator is one powerful tool for detecting tampering. By leveraging Babelâs tampering detection feature, developers can add an extra layer of protection to their applications and execute custom logic in response to tampering attempts.
When an assembly is signed, the .NET Framework can already detect if an application has been tampered with. However, Babel Obfuscator takes this a step further by providing an additional safeguard. By activating the tampering detection feature in Babel, the obfuscated assembly becomes capable of verifying whether it has been tampered with or not. In the event of tampering, the application can be terminated, or custom methods within the assembly can be invoked to handle the tampering in a more controlled manner.
On mobile .NET MAUI targets, tampering detection is provided starting with version 12 by a packageâintegrity check instead of the desktop image hash: an APKâsignature check on Android (see Android (MAUI) Package Integrity) and a bundleâidentifier / provisioningâprofile check on iOS (see iOS (MAUI) Package Integrity). On desktop targets the check hashes the loaded image in memory, so it is inert for singleâfile, trimmed, or AOTâpublished apps; Babel emits a warning when tampering detection is requested for such a publish.
Configuring Tampering Detection
Enabling tampering detection in Babel is straightforward. It can be achieved either through the command line by adding the appropriate switch or through the Babel task by including the TamperingDetection attribute in the project file.
Command Line
babel myapp.exe --tamperingdetectionMSBuild Babel Task
<PropertyGroup>
<TamperingDetection>true</TamperingDetection>
</PropertyGroup>
<Babel TamperingDetection="$(TamperingDetection)" />Once tampering detection is activated, the obfuscated assembly will automatically check for tampering during runtime. If the assembly has been tampered with, the application will be terminated.
On desktop targets (.NET Framework and .NET running on the CoreCLR) the check works by computing a hash of the loaded image in memory and comparing it with a hash stamped into the assembly at obfuscation time. This technique requires the assembly to be present as a memoryâmapped image, so it does not apply to singleâfile, trimmed, or AOTâpublished applications; when you request tampering detection for such a publish, Babel warns that the check would be inert.
Android (MAUI) Package Integrity Ultimate
The inâmemory image hash described above cannot be used on Android: the application runs on MonoVM and the managed assemblies are packaged inside the APK rather than loaded as a Windows PE image. Starting with version 12, Babel provides an equivalent protection for .NET for Android (MAUI) targets, based on the integrity of the APK signature.
When you enable tampering detection for a net*-android assembly, Babel injects a runtime check that reads the certificate the running APK was signed with and compares it against one or more trusted signer fingerprints that you pin at obfuscation time. If the application is reâsigned or repackaged with a different key â the classic way to redistribute a modified app â the fingerprints no longer match and the tampering reaction is triggered: the application is terminated, or your custom handler is invoked (see Custom Action on Tampering Detection). Because the check inspects the operatingâsystem package signature rather than the managed image, it keeps working with trimming and aheadâofâtime (AOT) compilation.
Pinning the signing certificate
The signing certificate is not known to Babel from the assembly alone â it is applied later, when the APK is signed. You therefore pin the expected certificateâs SHAâ256 fingerprint with the --trustedsigner option. The option is repeatable, so you can pin more than one certificate (for example an upload key and a Google Play appâsigning key):
babel MyApp.dll --tamperingdetection --trustedsigner 2924C53EE9C511E9F26E0720FD8151064F7621681667D7AB1899E551CDB25104Through the MSBuild task:
<PropertyGroup>
<TamperingDetection>true</TamperingDetection>
<TrustedSigner>2924C53EE9C511E9F26E0720FD8151064F7621681667D7AB1899E551CDB25104</TrustedSigner>
</PropertyGroup>
<Babel TamperingDetection="$(TamperingDetection)" TrustedSigner="$(TrustedSigner)" />You can obtain the SHAâ256 fingerprint of your signing certificate with keytool (from the keystore) or apksigner (from a built, signed APK):
keytool -list -v -keystore my-release.keystore -alias my-alias | grep -i SHA256
# or, from a signed APK:
apksigner verify --print-certs MyApp.apk | grep -i 'SHA-256'Strip the colon separators; the value passed to --trustedsigner is a 64âcharacter hexadecimal string.
If you enable tampering detection on an Android target without pinning a trusted signer, Babel emits a warning and falls back to a weaker check that only verifies that the package is signed. Always pass --trustedsigner (TrustedSigner) with your release certificate fingerprint for real protection.
iOS (MAUI) Package Integrity Ultimate
On .NET for iOS (MAUI) the managed code is fully aheadâofâtime compiled and there is no memoryâmapped PE image to hash, so the desktop technique cannot be used. Starting with version 12, Babel provides a packageâidentity check for net*-ios targets: at runtime the obfuscated app verifies its own bundle identifier and, when running from a provisioned build, the Apple Team identifier, against values you pin at obfuscation time. If either no longer matches â for example after the app has been repackaged or reâsigned with a different developer identity â the tampering reaction is triggered (the application is terminated, or your custom handler is invoked). The check runs from a module initializer at process start and works under full AOT.
Pinning the bundle and team identifiers
Pin the expected values with the --trustedbundle and --trustedteam options:
babel MyApp.dll --tamperingdetection --trustedbundle com.mycompany.myapp --trustedteam ABCDE12345Through the MSBuild task:
<PropertyGroup>
<TamperingDetection>true</TamperingDetection>
<TrustedBundle>com.mycompany.myapp</TrustedBundle>
<TrustedTeam>ABCDE12345</TrustedTeam>
</PropertyGroup>
<Babel TamperingDetection="$(TamperingDetection)"
TrustedBundle="$(TrustedBundle)"
TrustedTeam="$(TrustedTeam)" />--trustedbundleis your appâsCFBundleIdentifier(fromInfo.plist).--trustedteamis your 10âcharacter Apple Team ID (visible in the Apple Developer portal under Membership, and in the identity name of your signing certificate, e.g.Apple Development: You (ABCDE12345)).
Each pin is optional and checked independently: pin the bundle id, the team id, or both.
The teamâidentifier check reads the appâs embedded provisioning profile (embedded.mobileprovision), which is present in development, adâhoc and enterprise builds. It is not available in the iOS Simulator (where the check is skipped) and is stripped from App Store builds (which Apple reâsigns), so for App Store distribution rely on the bundleâidentifier pin. If you enable tampering detection on an iOS target without pinning either value, Babel emits a warning and performs no integrity check.
Custom Action on Tampering Detection
To customize the response to tampering attempts, developers can define a specific method within their assembly. By applying the âon tampering detected methodâ feature using the [Obfuscation] attribute, a custom method can be designated to handle the tampering event. This allows developers to implement their own logic and take appropriate actions when tampering is detected. For example, they can set a hidden flag, generate incorrect results, or trigger specific countermeasures to mitigate the impact of the tampering. The same handler is used for the desktop image check and for the Android and iOS packageâintegrity checks, so a single method covers every target.
class CustomTampering
{
public static bool HasBeenTampered { get; internal set; }
[Obfuscation(Feature = "on tampering detected method")]
static void OnTamperingDetected()
{
HasBeenTampered = true;
}
}The code provides a basic implementation for handling tampering detection.
If HasBeenTampered is set to true, it implies that tampering has been detected. The suggested usage is to perform certain actions or execute specific code when tampering is detected:
if (CustomTampering.HasBeenTampered)
{
// Tampering detected: Implement appropriate security measures or handle the
// situation accordingly.
// Examples include logging the incident, notifying system administrators,
// disabling critical functionality or terminating the application.
}In summary, by leveraging the tampering detection feature of Babel Obfuscator, developers can significantly enhance the security of their .NET applications. With the ability to detect and respond to tampering attempts, developers can safeguard their software from unauthorized modifications, maintain data integrity, and protect sensitive information.