[Android] Jadx dynamic debugging application

【Android】Jadx dynamic debugging application

1. Foreword

Jadx already supports dynamic debugging of APP, but I have never tried it. Try to go through the process from a reverse perspective and get familiar with it, so that you can read it in the future.

2. Related knowledge

2.1 Principle of dynamic debugging

The principle of dynamic debugging can be summarized as the following steps:

  • Start the application process: Use a debugger or other tool to start the application process and attach it to the debugger.

  • Inject debug code: Inject debug code into the application process to capture relevant information while the application is running. Typically, the debugging code sets breakpoints at certain critical points in the application and pauses the execution of the application at the breakpoints.

A common method of injecting debugger code is to use the dynamic link library (DLL) or shared object (SO) mechanism provided by the operating system. In this case, the debugger loads a specific DLL or SO library via the operating system API and injects it into the target process. This library can contain debugger code, or other forms of code (such as hooks or proxies) to allow debugging operations while the process is running.

  • Communicating with the debugger: Once the application is paused, the debug code communicates with the debugger and communicates the state and behavior of the application to the debugger. The debugger can view the application’s stack, variables, threads and other information, and perform some debugging operations, such as single step execution, variable modification, memory viewing, etc.

Resume Application Execution: When the debugger finishes debugging, the debug code notifies the application to continue executing and resumes the application execution from the breakpoint.

2.2 Debugger and target process communication

Communication between the debugger and the target process can be accomplished in several ways:

  • Socket-based communication: The debugger and the target process can communicate through local network sockets. In the application, the debugger can open a local socket and listen for connection requests from the target process. Once the target process is connected to the socket, the debugger can send debugging instructions to the process and receive the execution status and results of the process.

  • Communication based on shared memory: The debugger and the target process can communicate through shared memory. In an application, the debugger can create a shared memory region and map it into the address space of the target process. Once the shared memory is mapped into the target process, the debugger can write debugging instructions into the memory and read the execution status and results of the process from the memory.

  • Communication based on inter-process communication: The debugger and the target process can communicate through the inter-process communication (IPC) mechanism. In an application, the debugger can use IPC mechanisms (such as pipes, message queues, signals, etc.) to send debugging instructions and receive execution status and results from the target process.

2.3 debuggable

debuggable is an Android application property that specifies whether the application allows a debugger to attach to the application process. When the debuggable property is set to true, a debugger can attach to the application process and can view and modify the application’s state and behavior.

Setting the debuggable property to true is often useful when developing and testing applications, as it allows developers to use a debugger to quickly locate and fix problems. For example, a developer can use a debugger to view the values of variables, execute lines of code, set breakpoints, and more.

However, the debuggable attribute should be set to false before releasing the application to production to increase the security of the application. If the debuggable attribute of the application is set to true, then hackers can use the debugger to view sensitive data of the application, execute malicious code, etc., which will pose a great threat to the security of the application.

It should be noted that if the application is hardened or uses other protection technologies, it may not be possible to set the debuggable property to true. In addition, some Android system versions may restrict the debuggable property of the application, so before setting the debuggable property, please make sure you understand the environment and limitations of the application.

In Android 4.2 and above, Google restricts the debuggable attribute, and only when the signature of the application is the same as the system signature, the debuggable attribute is allowed to be set to true. This is to improve the security of the application and prevent hackers from using the debugger to steal sensitive information of the application.

In Android 7.0 and higher, Google has further strengthened the restrictions on the debuggable attribute. Only when android:debuggable=”true” is explicitly declared in the application’s AndroidManifest.xml file, Only allow the debuggable property to be set to true. This is to prevent the application from accidentally enabling debugging in a production environment, thereby reducing the security of the application.

2.4 ro.debuggable

ro.debuggable is an Android system property, which indicates whether the entire Android system is in debug mode. When set to 1, the whole system can be connected and debugged by a debugger. When set to 0, the whole system cannot be connected by a debugger, which can increase the security of the system.

To put the whole system into debug mode, the system property ro.debuggable needs to be set to 1. This can be achieved by running the following command on the device’s command line interface:

adb shell setprop ro.debuggable 1

By setting ro.debuggable to 1, the entire Android system can run in debug mode and allow the debugger to connect to all applications on the system for debugging.

2.5 Developer mode – debug switch

Developer Mode Turning on the debuggable option simply allows the app to run in debug mode and allows the app to be debugged with a debugger. In fact, if the system’s ro.debuggable property is set to 0, the application cannot be debugged in system debug mode even if the debuggable option is turned on in developer mode.

Dynamic debugging and reproduction

Based on the above basic knowledge, two debugging ideas are provided as follows

Idea 1: frida Hook debuggable attribute value

ro.debuggable=0
debuggable=”false” via hook -> debuggable=”true”

Use Frida hook to set the debuggable property of the application to true.

// Attach to the specified application and execute the specified function
Java. perform(function () {<!-- -->
  // application package name
  var packageName = 'com.example.myapp';

  // modified debuggable parameter value
  var debuggableValue = true;

  // Find the Application class
  var Application = Java. use('android. app. Application');

  // modify debuggable parameter value
  Object.defineProperty(Application, 'debuggable', {<!-- -->
    get: function () {<!-- -->
      return debuggableValue;
    },
    set: function (value) {<!-- -->
      debuggableValue = value;
    }
  });

  // print debug information
  console.log(`Successfully set debuggable to ${<!-- -->debuggableValue}`);
});

This script will hook the android.app.Application class and set the debuggable property to true. To execute this script in the application, enter the following command in the console to execute at startup:

frida -U -f com.example.app -l script.js


Next, you should use jadx to select the process to be debugged, but there is a problem with my device, and my application process is empty. I don’t know why.

Idea 2: Modify the system ro.debuggable value

ro.debuggable=0 modify -> ro.debuggable=1
debuggable=”false” via hook -> debuggable=”true”

First look at the native ro.debuggable value

 ~  adb shell getprop ro.debuggable

2.1 Method 1: mprop

https://github.com/wpvsyou/mprop


Result: failed

2.2 Method 2: Overwrite /system/build.prop directly


Prompt Read-only
Result: failed

2.3 Method 3: Magisk command modification

magisk resetprop

Result: Success
But it fails after reboot

2.4 Magisk module reset



Then you can use the props command to modify

I directly choose 4, and there is no ro.debuggable locally, so I choose 5 to add an option

It is found to take effect permanently after restarting

Result: Success

jadx dynamic debugging

Going back to the original question, the initial question is that the debug process of jadx does not exist. When we modify the debuggable of the system, will the process list of jadx be different?

The answer is yes, we can already select the process
in two steps
First select the number of lines to debug, then select the smali code

Press f2 to break the point, and press f9 to start monitoring. When the program logic reaches the breakpoint, it will be blocked and start debugging. The call stack and parameter information can be seen in the figure.

Following

So far, jadx dynamic debugging has also been reproduced. It can be seen that when we set the debuggable parameter of the system to 1, even if our application debuggable is not equal to true, it can be dynamically debugged.