真实恶意APP简要分析

本篇文章仅用于技术交流学习和研究,使用文章中的技术用于非法目的和破坏后果自负

MoqHao

https://mp.weixin.qq.com/s?__biz=Mzk1NzE0ODUyOA==&mid=2247491702&idx=1&sn=7dd9cd77e07e971d4736aa4568ad8636&source=41#wechat_redirect

https://ti.dbappsecurity.com.cn/info/9213

通过短信传播,伪装成Chrome浏览器更新欺骗用户下载,通过base64编码将恶意dex文件隐藏于资源目录,创建本地代理来窃取Google账户登录凭证,且具备远程控制感染机的能力,主要通过替换合法金融类APP为钓鱼APP,来窃取用户银行及理财APP登录凭证

步骤

  1. 该恶意木马伪装成Chrome浏览器更新包来欺骗用户下载,并且该恶意木马运行后会不断提示用户激活其设备管理员权限,一旦其设备管理员权限被激活,该恶意木马就隐藏自身的图标
  2. assets下面的bin base64解密后得到恶意dex文件
  3. 申请大量敏感权限,同时注册大量广播,用于窃取用户手机状态信息
  4. 获取并解密C&C服务器地址,连接成功后会更新用户设备信息和状态信息到C2服务器,该恶意木马使用加密的WebSocket协议来和C&C服务器通信,恶意木马和C&C服务器各自实现了自己的RPC函数供对方调用。恶意木马实现的RPC函数可发送钓鱼信息给手机联系人等
  5. 该恶意木马除了收集受害用户的手机硬件相关信息和手机状态信息,还会窃取受害用户的Google账户凭证。在恶意木马筛选出google账户后,会弹出警告对话框,等受害用户点击确定后,恶意木马就会打开浏览器,跳转到自定义的本地钓鱼页面
  6. 该恶意木马会遍历受害用户本机安装的APP信息,以确定受害用户是否安装有特定的银行类APP。如果有的话,就会从C&C服务器下载对应的伪装银行木马,待对应的伪装银行木马下载完成后,就提示用户升级。伪装银行木马运行后,会卸载掉受害用户本机原始合法的银行APP来偷梁换柱

发展

该攻击活动始于一条看似无害的日文短信,声称快递投递失败,并引导收件人点击一个缩短的URL。点击链接后,用户会被重定向到针对其设备类型定制的钓鱼页面,当iOS用户访问链接时,他们会被引导到具有地区特定URL的钓鱼页面,这些假冒的Apple ID登录页面通过拒绝用户的初始密码尝试来窃取凭证,营造出合法性的假象。对于Android用户,恶意APK直接从Apple的合法iCloud基础设施下载,攻击者利用这一点来托管恶意软件

为了进一步掩盖其操作,攻击者依赖动态DNS服务和VK等中介平台。C2地址被编码在VK用户资料中,作为掩盖C2服务器真实位置的中介

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class ProxyApplication extends Application {

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);

try {
// 获取 ActivityThread 对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);

// 获取 mBoundApplication 字段(包含ApplicationInfo等)
Field mBoundApplicationField = activityThreadClass.getDeclaredField("mBoundApplication");
mBoundApplicationField.setAccessible(true);
Object mBoundApplication = mBoundApplicationField.get(currentActivityThread);

// 获取 LoadedApk
Class<?> appBindDataClass = mBoundApplication.getClass();
Field infoField = appBindDataClass.getDeclaredField("info");
infoField.setAccessible(true);
Object loadedApk = infoField.get(mBoundApplication);

// 设置 Application.className
Field appInfoField = loadedApk.getClass().getDeclaredField("mApplicationInfo");
appInfoField.setAccessible(true);
ApplicationInfo appInfo = (ApplicationInfo) appInfoField.get(loadedApk);
appInfo.className = "com.example.real.RealApplication"; // 替换为真实的 Application

// 移除旧 Application
Field mInitialApplicationField = activityThreadClass.getDeclaredField("mInitialApplication");
mInitialApplicationField.setAccessible(true);
mInitialApplicationField.set(currentActivityThread, null);

// 清除 mAllApplications 中的旧 Application
Field mAllApplicationsField = activityThreadClass.getDeclaredField("mAllApplications");
mAllApplicationsField.setAccessible(true);
List<Application> mAllApplications = (List<Application>) mAllApplicationsField.get(currentActivityThread);
mAllApplications.clear();

// 重新创建新的 Application 并调用 onCreate
Application realApp = (Application) Class.forName("com.example.real.RealApplication")
.getDeclaredConstructor()
.newInstance();
realApp.attachBaseContext(base);
realApp.onCreate();

} catch (Exception e) {
e.printStackTrace();
}
}
}

窃密app夜魅

app来自一个不明链接,需要输入手机号以及一个ID,app涉及少儿不宜内容,诱导性很强

关键字符串base64加密

采用一代壳思路,现在看不到MainActivity,运行后用ClassLoader加载

用正则表达式匹配特殊字符串,python解密后得到真正java文件

aes解密资源文件得到压缩包,解压后xor运算得到dex,查看MainActivity用同样的方法base64解密后发现远程服务器地址和网络请求及其相关内容


真实恶意APP简要分析
https://j1ya-22.github.io/2025/06/01/真实恶意APP简要分析/
作者
j1ya
发布于
2025年6月1日
许可协议