← Back to list

Android native string deobfuscation

Background

JackHunter · 2025-07-05 11:12 · 31 claps · 4.8 min read
#android-reversing #android-security #reverse-engineering #idapro
Open on Medium ↗

Android native string deobfuscation

Background

With the continuous escalation of security countermeasures, it is common to encounter encrypted strings in target .so files during native reverse engineering. Since strings are crucial for locating key code, decrypting and restoring these encrypted strings becomes essential. This article introduces several common methods for cracking string encryption and explains them with practical examples.

Tracing All Returned Strings

Concept: Some string obfuscation schemes decrypt strings at runtime and return the decrypted strings as C pointers to the caller. However, locating these decryption functions can be challenging. Using Frida, we can hook all functions in the module and attempt to output results with readCString() when the functions return.

Advantages:

  • If lucky, sensitive key strings can be directly observed, allowing quick identification of critical functions.

Disadvantages:

  • May cause the app to crash, making the tracing process unstable.
  • Produces a large amount of output data, making it difficult to filter useful information.

Steps:

  1. Run the script toolchain_collect_ret_insn.py.
  • Select “Yes” to generate a hook script for all return instructions in the IDB directory.
  • Select “No” to generate a hook script only for exported functions’ return instructions.

  1. Make minor adjustments to the generated script and use it.

Example Output:

Identifying Frequently Called Functions

Concept: Some string obfuscation schemes frequently call fixed string decryption functions at runtime. Since a single .so file typically contains hundreds or thousands of strings, these decryption functions are often called far more frequently than regular functions. By analyzing the cross-references of all functions and sorting them in descending order, these string decryption functions can be quickly identified. This method can also be used to locate string constructors, serving as key points for deobfuscation.

Advantages:

  • High stability, requiring hooks for only a few functions.
  • Minimal interference data.
  • Suitable for both heap-based and stack-based string encryption schemes.

Disadvantages:

  • Requires manual inspection to locate string decryption functions.

Steps:

  1. Run the script top_xrefs.py and input the number of functions (N) with the highest reference counts to view.

  1. Example Results:

xxard:

String decryption implementation:

xxsec:

xxny:

Tracing JNI String-Related Functions

Concept: When strings are passed between Java and native layers as parameters or return values, JNI functions such as NewString, NewStringUTF, and GetStringUTFChars are typically called. By hooking these interfaces, we can trace the strings.

Advantages:

  • Produces minimal irrelevant data.

Disadvantages:

  • Limited output data, making it difficult to locate key functions.

Implementation:

  1. Use the open-source project FridaContainer by deathmemory for JNI tracing:

FCAnd.jni.hookJNI(‘NewString’, {

onEnter: function (args) {

try {

var str = args[1].readCString();

console.log(‘NewString ‘ + ‘ str: ‘ + str);

} catch (error) {}

}

});

FCAnd.jni.hookJNI(‘NewStringUTF’, {

onEnter: function (args) {

try {

var str = args[1].readCString();

console.log(‘NewStringUTF ‘ + ‘ str: ‘ + str);

} catch (error) {}

}

});

FCAnd.jni.hookJNI(‘GetStringUTFChars’, {

onLeave: function (retval) {

try {

var str = retval.readCString();

console.log(‘GetStringUTFChars ‘ + ‘ str: ‘ + str);

} catch (error) {}

}

});

  1. Alternatively, use the open-source project JnitraceForCpp by zhenxi.

Memory Dump

Concept: Some .so files use open-source OLLVM for string encryption, where strings are decrypted back into the .data section during the init function. Using Frida dump tools, decrypted strings can be directly extracted from memory.

Advantages:

  • Highly effective for encryption schemes that refill decrypted strings into the .data section.

Disadvantages:

  • Ineffective for heap- or stack-based string encryption.

Steps:

  1. Launch the app and trigger critical logic to ensure the target module is loaded into memory.

  2. Use Frida dump tools to extract the decrypted .so file from memory.

  3. Copy the script fix_convey_str_list.py to the IDA plugin directory and restart IDA to activate it.

  4. Load the dumped .so file in IDA and use the plugin to export the parsed string list.

  1. Re-import the exported string list into the original (non-dumped) .so file for analysis.

Memory Scanning

Concept: For heap-based string encryption schemes, decrypted strings are dynamically allocated in memory, and their pointers are stored in global variables. By writing IDA scripts to scan the .data and .bss sections, string pointers can be identified, and decrypted strings can be output.

Advantages:

  • Highly effective for dynamically allocated memory-based string encryption schemes.

Disadvantages:

  • Ineffective for stack-based string encryption.

Steps:

  1. Use the script toolchain_trace_dyn_dec_str.py to generate a Frida JavaScript script and modify the module name in Module.findBaseAddress.

  2. Launch the app, trigger critical logic, and wait for string decryption to complete before dumping.

  1. Save the dumped string information to a file and use the IDA script toolchain_trace_dyn_dec_str.py to supplement the information back into the IDB file.

  1. For .bss section addresses without allocated space in the file, set breakpoints at the corresponding addresses and add comments. This allows easy string lookup through the breakpoint window (Ctrl+ALT+B).

  1. View string annotations in the assembly window:

Conclusion

This article focuses on reverse engineering techniques for cracking native-layer string encryption. It provides detailed explanations of various strategies, including tracing returned strings, identifying frequently called functions, JNI string tracing, memory dumps, and memory scanning. These methods effectively address different types of string encryption schemes, offering strong support for reverse analysis. It is hoped that this article will inspire and assist readers in their practical work.

Code repository: https://github.com/imb4dm4n/Deadly-3000


메타데이터
post_id
3d21c5a9df5d
slug
android-native-string-deobfuscation-3d21c5a9df5d
url
https://medium.com/@jackSparr0w/android-native-string-deobfuscation-3d21c5a9df5d
canonical_url
https://medium.com/@jackSparr0w/android-native-string-deobfuscation-3d21c5a9df5d
author_url
https://medium.com/@jackSparr0w
status
ok
fetched_at
2026-07-19 03:40:01