An Android Package file (.apk) is a compressed archive file that contains all of the data and resources needed by an application to run on your Android device. APK file is typically created when the developer wants to share the app with others or to upload it on Google Play. Basically, an APK file is used to install an app onto your phone or tablet.
APK decompilation is the process of reverse engineering an APK file to retrieve its source code. APK decompilation is useful for understanding how an Android app works, especially if you're interested in ethical hacking or penetration testing.
Decompiling or reverse-engineering an APK file is not as complicated as it sounds. There are several free and open source APK decompiler tools available for doing this. But, the three most popular ones are:
For example, JADX is quick and convenient but sometimes resource files are partially missing in its output. So, JADX has some reliability issues. On the other hand, Apktool returns source code in detail with complete resource files.
If you want to discover all the available options (i.e. open source, online, Windows, Mac, Linux, and Android apps) then definitely check out this ultimate list of best APK decompiler tools. Here, you'll get information about the features as well as the pros/cons of each APK decompiler.
Basically, JADX is packed with a command-line utility as well as a GUI application. The Command line utility is mostly used when you want to provide an APK decompiler as a service. Whereas, the JADX GUI app is more convenient to decompile a specific APK and view its source code and resources in a better user interface.
I started with vscode-decompiler, hoping that githubs copilot will help me in the process. It turned out to be completely useless for such tasks.When I imported the decompiled stuff into AndriodStudio, due to obfuscation, 90% of the classes had problems.Because there are dozens of classes with the same name (i.e. a, b), imagine how many conflicts you get.
Next was to use jadx to decompile the application, which supported semi de-obfuscation. I could import the project into AndroidStudio. Now, all the obfuscated classes have unique names (e.g. C1189f), which makes the AndroidStudio happier.
Just to be crystal clear, you cannot recompile the application and run it, unless the application is simple enough!After a few hours of guessing the name of the classes and their fields, I finally found what I was looking for: the BLE protocol!To my surprise, it has so many commands. I quickly cleaned out a few BLE commands that I was interested in:
After I had enough info about BLE protocol, I began to write a Qt application to use it.I found the BLE support in Qt 6.5.1 quite good (at least on android & linux desktop) as I could use quite a few BLE commands painlessly.
It is clear from the above discussion that both the correctness and completeness of Android decompilation must be studied further. In this work, we have focused on the latter. As such, the first and primary research question (RQ1) that we have sought to answer is To what degree can we expect decompilers to successfully recover source code from Android apps?
Moreover, while control-flow obfuscation is presumably more rarely encountered in Dalvik bytecode than in native code, due to the aforementioned register-type conflict problem, the question remains: to what degree is decompilation-breaking obfuscation a concern when analyzing malware or commercial apps for the Android platform? We address this as our second research question (RQ2).
Here, it should be noted that Android apps can also contain native code components, whose decompilation are subject to the same challenges as with other native-code binaries, and which can also be subjected to control-flow obfuscation. However, because the limitations of native-code decompilation has already been well-studied, and because of the very different usage model for native-code decompilation, we have chosen to limit our focus to Dalvik bytecode decompilation in this study.
Our third research question concerns the performance of individual decompilers. The study by Harrand et al. (2019) showed that various idiosyncrasies of JVM decompilers can cause significant differences in relative performance between decompilers, depending on the program being analyzed. In a follow-up study (Harrand et al. 2020), they also showed that decompilation results can be combined to improve the overall correctness of recovered code. Similarly, the small-scale study by Jang et al. (2019) indicated that the same also holds true for Android decompilers. To determine if these preliminary results can be generalized, we have sought to answer the question: Do different Android decompilers tend to systematically fail on the same methods, or do their results complement each other? (RQ3)
We have addressed the three research questions above in a previous study (Mauthe et al. 2021). In addition to providing an extended presentation of the findings from that study, this paper also presents the results from a follow-up study on a large set of Android malware samples. Since our original results indicated that many decompilation failures appeared to be caused by implementation-level deficiencies, rather than fundamental limitations of the decompilation algorithms, we wanted to further study the reasons why decompilers fail. Therefore, in addition to analyzing the new dataset in the context of our original research questions, we also introduced a fourth research question: To what degree does implementation-level limitations, in contrast to fundamental algorithmic limitations, contribute to decompilation failures? (RQ4) Below, we summarize the contributions of our original study, as well as the new contributions presented in this paper.
We have performed a large-scale study of the decompilation success rate (i.e., the ratio of methods for which the decompiler reports successful decompilation) for Android apps using four different decompilers. Our original evaluation was performed on three datasets, consisting of, respectively: 3,018 open-source apps from the F-Droid repository, 13,601 apps from a recent crawl of Google Play, and a collection of 24,553 Android malware samples collected between 2010 and 2016.
Finally, as the largest new contribution of this work, we have performed data-mining on all error messages emitted by decompilers, when run on the new malware dataset, in order to gain better insights into the reasons for decompilation failures (RQ4).
The rest of the paper is structured in the following way: In Section 2, we provide some background on Android decompilation and obfuscation techniques. We outline the methodology for our study in Section 3, and present our results in Section 4. The results of our follow-up study on reasons for failures are presented in Section 5. We discuss the findings and potential threats to validity in Section 6, and survey related work in Section 7. Finally, Section 8 concludes the paper.
Android apps are developed in the Java or Kotlin languages, and compiled to Dalvik bytecode. Apps are distributed in the form of Android Application Packages (APKs), which contain one or more files of the DEX format. DEX files in turn contain a number of classes, including Dalvik bytecode for each method of a class. On Android versions prior to 5.0, Dalvik bytecode was interpreted by a virtual machine. Modern versions of Android instead use the Android Runtime (ART), which avoids the overhead of interpretation by pre-compiling the Dalvik bytecode to native code when an app is first installed.
In addition to native Dalvik decompilersFootnote 3, Java decompilers can often also be used on Android apps by first converting the Dalvik bytecode into equivalent bytecode for the JVM, using a tool such as ded (Enck et al. 2011) or dex2jarFootnote 4. Since the Kotlin language is designed to be fully interoperable with Java, apps written in Kotlin can generally also be decompiled into Java source code.
In this section, we outline the methodology of our work. We begin with a detailed description of the approach used in our original study, followed by a discussion of some of its limitations. Finally, we describe the methodology used in our follow-up study.
As depicted in Fig. 1, we begin by gathering APKs from three different sources, in order to study decompilation characteristics of different kinds of apps. We collected 3,018 open-source apps from the F-Droid repositoryFootnote 5 and 13,601 apps from the Google Play store. Finally, we used the existing Android Malware Dataset (AMD) compiled by by Wei et al. (2017), consisting of 24,553 Android malware samples collected between 2010 and 2016. While the samples in this dataset are quite old, a benefit of the AMD dataset is that each sample is labeled with its family, allowing us to compensate for bias due to some families being over-represented in the dataset.
Retrieving apps from the F-Droid repository is quite straightforward, as all apps can simply be enumerated and downloaded. The Google Play store, however, does not allow downloading apps in bulk. Therefore, similarly to previous works, we had to implement a custom crawler by partially reverse-engineering the internal Google Play API. As our aim was to collect the most popular applications in the store (i.e., the ones with the largest user-exposure), we used an approach similar to, e.g., Backes et al. (2016) and crawled Google Play by category. Our crawler first retrieves the current set of thematic categories present in Google Play and then goes on to query each of those for their respective subcategories. These subcategories are not thematic, but instead are of a commercial nature, displaying the highest grossing, highest selling and most popular applications. As we only want to include free applications in our datasetFootnote 6, we omit crawling the highest selling applications and focus on the other two subcategories. The crawler then queries the store API for all applications contained in each subcategory, and downloads all of them. This way, our set of apps will consist of the most popular apps in each category.
c80f0f1006