Skip to content

GDA: DEX Static Patch Technology Based on Smali Just‐in‐time Compilation

charles2gan edited this page Jul 21, 2023 · 2 revisions

Some people suggested a feature that can modify and repackage APK. In fact, there are many tools that can achieve this, which I think is unnecessary, so I haven't paid attention to it for a long time. Until a while ago, a friend reported that repackaging an app failed and almost gave up. The reason was that there were many illegal instructions in DEX. When unpacking, all DEX needed to be decompiled. Due to too many illegal instructions, the recompiled APK could not work properly. With the escalation of bytecode instruction level confrontation, this issue may become increasingly common. The ultimate solution to this problem is to directly patch the instructions in the DEX file without decompiling, but it involves instruction format, local registers, and various indexing issues that need to be addressed, which is not an easy work. Therefore, in order to achieve this solution, I have this blog, which I call "static patch technology based on smali Just-in-time compilation": it is not necessary to decompile the entire APK using traditional methods to modify code, just modify one or more smali instructions and directly patch the modified instructions to the DEX file, nor do you need to recompile all the dexs.

Contribution:

  • Implement the new lightweight smali compiler LiteSmali
  • Instruction syntax prompt
  • Junk instruction cleaner
  • A Wide Spectrum Matching Junk Instruction Global Recognizer

SHOW:

1、Modifying Strings in DEX Files

2、Modify jump instructions to emit Flag

一、 Overview

In order to achieve APK instrumentation and modification, the usual approach is to use the backsmali to disassemble the target DEX/APK into smali files, then modify the smali code of interest. After this, compile it back to DEX using the smali (some software integrating these core tools to work). We know of a commercial app that may have tens of thousands of classes and tens of millions of bytecode instructions. There are various possibilities for instruction confrontation, which can easily lead to errors in tools like Apktool/backsmali/smali. Especially when dealing with APPs that have been reinforced and protected, the error rate will significantly increase. Even if a small piece of code is mishandled, or a file that needs to be decompiled (DEX file/XML file/resource file) cannot be decompiled properly, it will cause the failure of the entire instrumentation or patch process.

Therefore, implementing a technique of directly patching DEX files can greatly simplify the entire process and avoid such situations. The direct patching technology can completely break away from the dependence of a series of Toolchain and does not need to decompile and compile the entire APK file and its internal files (including XML files, resource files, DEX files, etc.), simplifying the instrumentation process, and avoiding unexpected errors.

This article aims to introduce a technology that can directly patch DEX files by smali code level and share the usage with some simple examples. Even if you are not familiar with smali, you can easily customize your own code and easily write all modifications back to the APK file through simple operations, and GDA will automatically implement APK signing and installation. You can modify the code while viewing the execution results.

Note: Since the modified APK requires signed, I have to introduce the tool apksigner.jar. Therefore, Java environment required in your system. If the default signature tool fails, you can use your own signature tool to sign the unsuccessful APK.

二、 Design and Implementation

The DEX Patch we are talking about here actually refers to modifying the method code of the class, and directly modifying the bytecode is not our expected goal. Therefore, the work requirement here is to implement smali input, smali compilation, and bytecode generation at any position, and finally write the generated bytecode back into the DEX file.

The principle is actually very simple, and the most core and difficult part of the entire process is the SMAI compiler. Conventional SMAI compilers actually do not meet my needs: one is an open-source compiler (specifically called an assembler) similar to smali, which is large and complex; I need to heavily rely on DEX files to generate bytecode, where class descriptor, method index, field index, and string index all need to be extracted from DEX files; Thirdly, it is difficult for SMAI compilers to complete the task of compiling a single smali independently of the context. Therefore, rebuilding wheels is more cost-effective in the long run, and through c++implementation, it can better interact with GDA's GUI, which is more efficient and easier to maintain. So, an itemized and context-free SMAI compiler was born, which is a very lightweight SMAI compiler without a large lexical/grammatical unit. I named it LiteSmali.

Of course, LiteSmali is far from enough. To do a good job of interaction with GDA Decompiler and Android devices, a lot of work needs to be done, such as real-time prompt of smali instructions, batch compilation, DEX write back, signature verification and APK installation. In order to continue the original code editing of GDA, single instruction editing is still implemented in the smali text box. Of course, batch smali code input is also provided, simplifying the process from code patch to code execution. The entire patch and operation process does not require any third-party tool intervention. The interactive operations supported by GDA's liteSmali are as follows:

    1. Smali instruction automatic prompt: supports real-time instruction format prompts for all Smali(including instructions, opcodes, registers)
    1. Object automatic prompt: Based on your input, the program searches for available objects from the current dex for you to use, including string, class/type, method, and field
    1. One-click patch: patch the smali code back to the DEX in real time with the Enter key 'R'
    1. String patch: modify strings in dex
    1. DEX automatic checksum: After modification, the signature and checksum of the DEX file are automatically updated.
    1. Write back DEX to APK and automatically sign: One-click implementation to write back the modified DEX file to the APK file and sign the APK file through the GDA built-in or custom certificate file.

三、 Usage

Here, I will take a crackme as an example to introduce how to use this Feature. This crackme demo is a program that input the correct password to pop up a flag. The APK is from:crackme. This is a very simple crackme, and this article is mainly used to demonstrate how to edit instructions.

1. Crackme Demo

In the above animation, click the line you want to edit, press M, and the selected smali code will be displayed in the smali edit box at the upper right corner. After editing, press Enter key to take effect. GDA will patch the DEX file in the memory, and automatically obtain the next line to wait for you to edit, if you do not need to ignore it. Finally, you can press the R key to save the modified DEX file with updating the checksum and signature into the APK file. Finally, sign the APK and install it on the Android device.

2. Edit and recover smalis

If you want to return to state before editing, you can use CTRL+Z to restore the last edited instruction. In the following figure, after continuously editing several instructions, use the shortcut keys to restore each instruction one by one.

3. Batch Compile smali

If you want to write multiple codes into a DEX file at once, you can first write the code into the file, then right-click the menu -> Multi Dex Edit, import your file. Note: smali code supports the following three formats:

  1. Pure smali code
  2. smali code with offset
  3. smali code with bytecode

For jump instructions, you need to correct the jump offset address in GDA

4. Precautions for method Calling

When calling a function, it should be noted whether the method you want to call is a private method. Although GDA can compile it, you cannot run the APP.

5. About Constructing Smali Shellcode

Although directly editing DEX files cannot introduce new strings and APIs, it is also feasible if we choose a method with sufficient space to introduce them. The specific method is also very simple. We can create an array and fill in the strings one by one. If it is an APIs, we can also fill in the APK string first, and then use reflection calls to implement it. Finally, extract the shellcode bytecode. Here is a section of shellcode I have constructed.

6. About Junk Instruction Clearing and Recovery

There are two ways to clear the instructions in GDA: one is to directly perform NOP operation on the selected line, which can be restored through CTR+Z; the other is to clear the instructions through broad-spectrum matching, which can be restored in the right-click menu.

The above animation demonstrates directly NOP the junk instructions. After the junk instructions are deleted, the decompiled code is clear.

To delete all junk instructions through broad-spectrum matching, it is necessary to edit the matching rules. Please note that after confirming the effectiveness, the current page needs to be refreshed before it can be showed.

The ?? marks in the rule represent an arbitrary byte match, and the length is specified through {}. The rule is very simple and easy to use. Like 1a05??{2}6e101b??{3} The following instructions can be matched:

Each match will be saved in Junk Manager, and you can click on each rule to restore the instructions cleared by that rule, as shown in the figure.

7.Restore all edited DEX to the original DEX

If you need to restore all modifications to their original state at once, you can do so by clicking on the following menu in the menu bar.

四、 Summary

Of course, smali editing based on DEX files is not so perfect, and there are still many limitations, such as the difficulty of introducing new strings and APIs, and many resources are limited by DEX itself. However, this is also a good technology worth trying, such as constructing shell codes, which benefits from GDA Decompiler's ability to retain the instruction level features, enabling the technology to be implemented and applied.