1 Introduction

The number of Android-based smartphones is growing rapidly. As a relative latecomer to the smartphone market, one of the top priorities of Android-based smartphones is openness, so that it can quickly gain market share and be adopted by more companies. Accordingly, the Android Market the key market in which apps are distributed is also run in an open way. Anyone can register as an app developer, self-sign developed apps, and register them without having to go through a complicated procedure. In addition, Google allows for app markets run by third parties in an attempt to overcome the disadvantage of being a latecomer, which has led to rapid growth. However, this kind of open policy in which anyone can publish apps on the market has a fundamental weakness: apps containing malicious code can be published just as easily. In addition, Android apps can be easily decompiled due to their structural characteristics [7], which mean that apps modified in this way can be repackaged. Amid the current situation in which this kind of vulnerability exists, more and more Android-based financial service apps, including banking apps, are finding their way into user’s hands.

We analyze whether it is possible to use repackaging attacks to forge or modify some of the most popular smartphone banking apps being distributed in South Koreas Android Market. Specifically, when a user requests a money transfer from a sender to an intended recipient in the money transfer service provided by a banking app, a forged app tries to transfer the money to an unintended attackers account instead. Whether this is actually possible is tested by publishing the forged app on the real Android Market. The experimental results showed that repackaged forged apps ran successfully for all seven of the banking apps tested. This means that attackers can successfully perform an attack with just the forged app, without needing to obtain any of the following: the sender’s public key certificate, the account password, and the security card. Further, we analyze the root cause for this and investigate technical countermeasures for the vulnerability.

This paper is organized as follows. Section 2 takes a brief look at related work. Section 3 describes the results of a vulnerability analysis performed on actual banking apps. Section 4 describes the attack results of the forged app, which was actually published on the Android Market. Section 5 attempts to find countermeasures for the repackaging vulnerability. Finally, the conclusions are presented in Sect. 6.

2 Related Work

This section introduces the building and distribution processes of Android apps, repackaging vulnerability, and reverse engineering techniques for Android apps.

2.1 Android App Building

Android apps are written in Java. They are ultimately created in the form of Android Application Package (APK) files [1]. An APK is a packaged file that includes files needed for app execution. The types of files included in the app are as follows.

  • DalVik Executable (DEX) file: The executable file resulting from compilation of the Java source code.

  • Manifest file: A file containing app properties such as privileges, the app package file, and version.

  • eXtensible Markup Language (XML) file: A file in which the user interface (UI) layout and values are defined.

  • Resource file: A file containing resources required for app execution, such as images.

Figure 1 shows the series of steps for the building and packaging of files that make up the APK. First, the Java source code is compiled using the Javac compiler (included in the Java Development Kit) and outputted in the form of a class file that runs on the Java Virtual Machine (JVM). The resulting class file is converted to a DEX file using the dx converter included in the Android SDK [2]. The DEX file runs on the Dalvik Virtual Machine.

Fig. 1
figure 1

Android app building process. The series of steps for the building and packaging of files are needed to make up the APK

The manifest file, which is in the form of XML, and other XML files needed for app execution are encoded in binary form. After that, the DEX, XML, manifest, and resource files are packaged in an APK file, which is in ZIP format. The initially created APK file does not include the developer signature, which is needed in order to distribute it. The unsigned APK file can be self-signed with the developer’s private key using Jarsigner [8]. The developer’s signature and the public key are then added to the APK file, which completes the Android app building process.

2.2 Android App Distribution

The steps taken by developers to register and distribute their apps on the Android Market are as follows.

  • Developer registration: Anyone can register as a developer for USD 25. The app developer makes a request for developer registration by sending his/her personal information and credit information to the market. The market will then check the information and approve the registration accordingly.

  • App registration: The developer sends a self-signed app to the market and makes a request for its registration. The market will check that the app is signed and that the package name does not conflict with that of previously registered apps. If there are no problems, the app is registered in the market.

  • App distribution: The registered app is immediately published to users and distributed to them at their request.

  • App installation and signature verification: A check is done to see whether there are any installed apps having the same package name; if this is the case, the developer signature is checked to see whether it is in fact the same app. Depending on the result, the app is installed, or updated, or the installation is cancelled.

Android allows app distribution by means other than using Googles Android Market. The Android Market takes the form of an open market structure, allowing for the creation of third party markets, and distribution can be done via any distribution path, such as website downloading and side loading. This means that it is possible for developers to update their apps regardless of the distribution path; all that is required is that the updated app is self-signed with the same developer’s private key. In Android, this is referred to as a “seamless update.”

2.3 Repackaging Vulnerability

Security [3, 18] is one of most important issues in various computing environments. Multiple security holes have been found in different Android components [15, 20]. Among these, this paper focuses on the self-signed app repackaging problem. Reverse engineering techniques [6] can be used to create forged apps containing arbitrary code in the APK file. This vulnerability is caused by the structural characteristics of bytecode [13] that runs on a virtual machine (VM). Bytecode in object files contains character strings of class names, method names, member variable names, and so on. In addition, the methods are classified by logic, facilitating reverse engineering. Figure 2 shows the Android app forgery process, which exploits this vulnerability.

Fig. 2
figure 2

Android app forgery process which exploits repackaging vulnerability

In this paper, this is referred to as “repackaging vulnerability.” For DEX files, as with Java applications, object files contain code information, making them vulnerable to reverse engineering. Consequently, code similar to the original source code can be obtained by decompiling bytecode that is run on the Dalvik VM. The attacker analyzes the code obtained by reverse-engineering, inserts malicious code, and then recompiles it to create a forged DEX file with which he/she can repackage and self-sign the app with his/her private key and then distribute the forged app.

2.4 Repackaging Attack

Reverse engineering for analyzing Android apps is done primarily through decompilation of the DEX file, which can be decompiled into either Java code or smali code [16], depending on the technique used.

To obtain the Java code, tools such as undx [19] and dex2jar [5] can be used to convert the Dalvik VM bytecode into JVM bytecode and a Java decompiler can then be used to recover the Java code. The Java class files have to undergo optimization when they are converted by the dx converter during compilation for use with the Dalvik VM, resulting in the advantage of obtaining Java code that is written in a high-level language. However, there is a shortcoming in that the decompilation result and the actual source code do not closely match. Furthermore, an identical development environment to that of the original source code must be set up in order to repackage, so this is not suitable for app modification purposes.

Obtaining the smali code, on the other hand, involves getting the code in a lower level language. In particular, it will be in the form of Dalvik VM assembly, which is mapped one-to-one with Dalvik VM bytecode [4]. Although analysis will take longer because it is in a low level language, there is the advantage that the development environment does not have to be set up to match that used for the original source code because the DEX file is created by directly converting the Dalvik VM instructions into Dalvik VM bytecode during repackaging. The latter is used in this study.

The reverse engineering process used when attacking the repackaging vulnerability using a decompiling technique is as follows.

  • Modification point search: The activity information, UI layout, and app execution flow are gathered and the points at which code is inserted are selected. Logcat [11] can be used to gather activity names and obtain information on activities that are run during app execution. The OnCreate function of the activities can then be decompiled in order to obtain the UI information and XML information used in the UI.

  • Decompilation: After extracting the DEX file in the APK file, a decompilation tool called baksmali [16] is used to generate the smali source code.

  • Code injection and modification: Code containing arbitrary Dalvik VM instructions is inserted at the modification point or the existing code is modified.

  • Manifest change: The package name is changed in the app manifest. When this is done, the app can be registered on the Android Market without conflicting with existing apps.

  • Self-signing: The modified app is self-signed to complete the repackaging.

3 Attack on Android Banking Apps

This section describes the repackaging attack that was carried out based on analysis of the major banking apps in Korea. Table 1 lists the notations used in this paper.

Table 1 Symbols used in this paper are described

3.1 Smartphone Banking Apps

Seven Android banking apps were examined in the experiments. Based on components in which processing requests and the resulting output are displayed, they can be classified into the following two types: Webview-based apps and Widget-based apps. Table 2 lists the features of the banking apps chosen for testing.

Table 2 Analysis of android banking apps in Korea

In general, money transfer using Android banking apps consist of the following four steps, as shown in Fig. 3.

Fig. 3
figure 3

Money transfer process in Android banking apps. The procedure consists of anti-virus checking, APK integrity checking, account holder checking, and money transfer service

Step 1 (Anti-virus Checking) This check is done before the banking apps are run to verify whether an anti-virus app is running. If no anti-virus app has yet been installed, the banking app invokes anti-virus installation and then executes the anti-virus app first. Figure 4 shows the sample code for checking whether an anti-virus app is installed.

Fig. 4
figure 4

Banking app routine for checking whether an anti-virus app is installed

Step 2 (APK Integrity Checking) This is the core part of checking for forgery or modification of the banking apps. The procedure is as follows. The banking app calculates the hash value from the original APK file using a hash function, i.e., \(h = H({\textit{APK}}_{org})\), and sends the APK integrity checking request (AIC_REQ) message containing h and APK version to the banking server. The banking server then retrieves the original APK hash value (i.e., \(h{^\prime }\)) with the APK version, which is kept in the banking server database. After checking whether \(h=h{^\prime }\), the banking server sends the APK integrity checking response (AIC_RES) message with the checking result to the banking app. Figure 5 shows a sample code for hashing the APK file using the SHA-256 hash function and sending the hash value to the designated URL using the APK integrity checking technique applied to N-bank.

Fig. 5
figure 5

APK integrity checking routine used in the N-bank app. It hashes the APK file using the SHA-256 hash function and sends the hash value to the designated URL

Step 3 (Account Holder Checking) Once the integrity-checking step of the APK file is cleared, the banking app checks the account holder information. It sends the banking server the account holder checking request (AHC_REQ) message containing the recipient’s account number \(({AC}_{R})\), the amount to be transferred ($), and the sender’s account passwords \(({\textit{PWD}}_{S})\). If all of the account information is correct, the banking server sends the account holder checking response (AHC_RES) message to the recipient with the recipient’s actual name \((R)\), the recipient’s bank identifier \(({\textit{ID}}_{B})\), and the amount allowed to be transferred after balance checking \(({\$}{^\prime })\). If the account information is incorrect, the banking server returns a NULL message.

Step 4 (Money Transfer Service) This is the actual money transfer step. The banking app constructs a money transfer service request (MTS_REQ) message with the sender’s name \((S)\), recipient’s name \((R)\), recipient bank identifier \(({\textit{ID}}_{B})\), amount \(({\$}{^\prime })\), and the personal security card number \(({\textit{PSC}}_{S})\). The sender then signs (MTS_REQ) with its private key. Upon receiving the signed (MTS_REQ) message, the banking server processes the money transfer service. The detailed process involved in this step is beyond the scope of this paper.

3.2 Repackaging Attack on Banking Apps

When attacking a banking app by exploiting a repackaging vulnerability, the attackers may attempt direct attacks that may cause financial loss for the user, such as unauthorized money transfers and stealing passwords. This section describes a particular type of attack in which a money transfer is made not to the intended recipient, but to the attacker, using a forged app.

The attack is carried out as follows (see Fig. 6). The anti-virus checking routine can be easily skipped. In the APK integrity-checking step, the forged app sends the hash value of the original APK file, not that of the forged APK file. It simply cheats the banking server. Regardless of what the (AIC_RES) message returns, the forged app proceeds with the forged APK and not the original APK. To obtain the intended recipient’s name and the attacker’s name, the forged app sends the (AHC_REQ) message to the banking server twice: one with the intended recipient account number \(({AC}_{R})\) and the other with the attacker account number \(({\textit{AC}}_{A})\). Owing to space constraints, we have skipped the step involving \({{\textit{AHC}}\_{\textit{REQ}}}({\textit{AC}}_{R},\, {\$},\, {\textit{PWD}}_{S})\) in Fig. 6. In the final step, the forged app requests the money transfer service with the attacker’s account information using the sender’s original security card information and the sender’s private key. When receiving the result from the banking server, it ignores that result containing the attacker’s account information. Instead, it displays the forged result with the intended recipient’s account information.

Fig. 6
figure 6

Cheating money transfer with forged apps which request the service with the attacker’s account information

After decompiling, the OnCreate method is analyzed in the activity class in order to obtain the UI information. The attacker can discover that the OnClick handler for the Button class (among the UI components) processes the money transfer service request and that the money transfer request confirmation details are outputted using TextView. The attacker can change the corresponding code to make it such that money is transferred to the attacker’s account when the user uses the money transfer service, while making it appear to the user as if money was correctly transferred to the intended recipient. The recipient’s information is shown to the user, although the forgery app actually does not check the account of the recipient that the user entered, but that of the attacker, as shown in Step 4. The user proceeds to the next step without suspicion, and information is also shown confirming that the money was transferred to the intended account in the last step showing the results of the money transfer, fooling the user. Figure 7 shows the modified code in the actual banking app.

Fig. 7
figure 7

Modified code injected in the forged banking app

The InjectedCode class inserted by the attacker swaps the account number, the bank name, and the recipient name. A swap routine is inserted into a routine that has finished the analysis in order to forge the money transfer service. The code modified as above is compiled using the smali tool to create a DEX file and the package name is modified in the manifest file in order to avoid package name conflict when registering on the market. The created DEX file and the manifest file are repackaged and self-signed with the attacker’s private key to complete the repackaging attack for the banking app.

4 Experimental Results

In this section, the attack technique proposed in Sect. 3 is applied to an actual banking app and the subsequent experimental results are described.

4.1 Attack Scenario

Figure 8 shows an attack scenario in which an attacker distributes a forged app so that when the user enters the recipient’s account in a money transfer, the remittance is made not to the intended recipient, but to the attacker himself without being recognized by the user.

Fig. 8
figure 8

Attack scenario. An attacker distributes a forged app so that the remittance is made not to the intended recipient, but to the attacker himself

4.2 Experimental Setup

The user equipment setup used for the experiment was Nexus One (Snap-dragon 1 GHz CPU; 512 MB RAM; Android 2.3.6). Logcat, which comes with the Android SDK, was used to inspect the activity classes to be forged. The smali and baksmali tools were used to forge the banking app. Jarsigner was used to self-sign the forged app.

4.3 Experiment Results

Figure 9 shows the execution screen of the forged W-bank app. The user is currently requesting that a money transfer be made to the recipient (i.e., Kim).

Fig. 9
figure 9

Money transfer request made to the recipient (i.e., Kim) using the forged W-bank app

Figure 10 shows that the money transfer was made to the recipient, as requested (i.e., Kim).

Fig. 10
figure 10

Money transfer response made to the recipient (i.e., Kim) using the forged W-bank app

However, as shown in Fig. 11, the money transfer was not made to the intended recipient (i.e., Kim), but to the attacker (i.e., Jung) instead. Besides the W-bank app, all of the seven banking apps were tested under the same attack scenario and the attack was found to be successful for all of them.

Fig. 11
figure 11

Attacker’s account information. The actual money transfer was made to the attacker (i.e., Jung)

It was also found that anti-virus products used by the tested Android banking apps could not detect forgery. Even if the signature DB of the anti-virus app was to be updated to detect forgery, the anti-virus installation routine can be skipped and easily bypassed in the forged app. In addition, banking apps use APK integrity checking by sending APK hash information to the server. This is also part of the code included in the app, so it was confirmed that the attacker can still make the forged app run as intended by sending the original APK hash value, rather than the hash value of the forged app, or by circumventing the check routine altogether. Accordingly, the security solutions used in today’s banking apps do all of their processing at the application layer; therefore, they fundamentally cannot prevent repackaging attacks, whose exploit is based on making changes to the app itself.

5 Countermeasures

This section describes countermeasures against repackaging attacks.

5.1 Self-Signing Restriction

Self-signing policy prevention can be considered as a countermeasure against repackaging attacks. The easiest way to do this is to change app signing from self-signing to signed-by-market and prevent app distribution without the market’s signature. Although this fundamentally eliminates repackaging attacks, it would violate Android’s open policy and the seamless update advantage would be lost. In addition, this method is not very practical because all software that has already been distributed to smartphone devices would have to be replaced with software that does not support self-signing. This restriction creates a requirement for a technique for maintaining compatibility with the existing system while addressing the vulnerability. One such technique is the multi-signature-based app signing scheme [9], which can minimize changes to the existing system while meeting the seamless update requirement.

5.2 Code Obfuscation

Obfuscation is a technique used for making reverse engineering of source code or machine code more difficult. Although it cannot make reverse engineering completely impossible, it can prevent exposure of logic or code by obstructing analysis. Obfuscation comes in two types according to the type of target:source code obfuscation and binary code obfuscation. Moreover, it is classified into layout obfuscation, data obfuscation, and control obfuscation, according to the specific techniques used. Proguard [14] is the default obfuscation tool provided by Android and is used for Java source obfuscation. That is, a DEX file is not directly obfuscated, but rather the class file is obfuscated and then a DEX file is created using the dx converter. Proguard supports layout obfuscation and changes class names, method names, and member variable names into meaningless, randomized character strings in order to obfuscate the code for class names and method names, etc. However, there is no change before and after obfuscation with regard to software control logic, so the attacker can discover the roles played by classes and methods by analyzing the software logic; the analysis just takes time in this case. In the example of K-bank app (see Table 2), although their banking app was obfuscated using Proguard, it unfortunately did not protect against our attack. To overcome this weakness, a logic obfuscation technique such as control obfuscation is necessary, but control obfuscation generally has the shortcoming of lowering code execution performance. Therefore, it is necessary to develop obfuscation techniques that do not impair performance in the limited smartphone environment while increasing the level of obfuscation.

5.3 Code Attestation

The Trusted Platform Module (TPM) [17] is one of the strongest security measures available for smartphone apps that deal with sensitive data, such as banking apps. It is one of hardware-based platform security solutions [10, 12]. Secure booting from the boot loader to the OS kernel and library module loading is made possible by TPM. Privilege isolation between apps is also made possible, along with remote attestation, which remotely checks platform integrity. In particular, remote attestation is a useful technique for checking whether the user app has been forged before financial data is exchanged between the banking server and the user app, such as in the banking app example. In addition, static integrity checking of binary execution code can be done on a smartphone and malicious forged apps can also be identified at execution time using remote attestation. Therefore, even though there would be increased costs from additional hardware, there is a need for seriously reviewing the introduction of a TPM-based app integrity verification technique.

6 Conclusion

Malicious software that can cause leakage of personal information and/or financial loss is rapidly on the rise. For example, security threats against smartphone banking apps can directly cause damage to users. In this paper, an experiment was done on the feasibility of exploiting repackaging attacks on banking apps provided by the major banks in South Korea, which are distributed on the Android Market. The forged banking apps were tested and it was confirmed that when the user uses the money transfer service, money is not transferred to the account of the intended recipient, but to that of the attacker. It was also found that security techniques currently in use to prevent this were completely ineffective. The reason for this is that they all run in the application layer, which means they can be bypassed when repackaging is done. Accordingly, binary code obfuscation and hardware-based code attestation were proposed as countermeasures for tackling the root cause of the problem.