貌似还没有分析过一个锁机病毒,来尝试一下。这个APK应该是用彼岸花锁机生成器制作的?要不然为什么要这样叫它。
这个应用伪装成手机上的通讯录App。
1. 第一层锁机
启动该应用后,会将手机声音调至最大并持续振动,发出不可描述的声音。救命,我用的真机啊。抓包并没有抓到什么,所以所有加解密操作都应该在这个App里面了。接下来就直接分析App吧。入口为MainActivity,那么就直接进入。
它启动了一个服务,进入MyService。
1 | // GG()函数的功能是删除file下的所有文件,重命名为DeleteFile |
进去看看如何实现封锁USB接口的。
将persist.sys.usb.config
置为none,在Windows中写入注册表项禁用USB接口,APK怎么能在Windows上写东西呢?
继续往下看if语句:
这个逻辑明显有问题,switch里面的参数不能是boolean类型。应该是Smali代码转成Java代码出错了,这时候可以更换反编译器或者直接看Smali代码。
jeb也太香了吧!还自动帮我们解码,上面的sdcard/和resume、resin都帮我们算出来了。回归正题,我们发现原来switch中根本不是boolean类型,而是int类型。
修改一下case的值就差不多了,得到一个二维数组。
继续往下看for循环:
ck就是[0,100000)的随机数,而识别码就是由它加密而成的。跑一下发现识别码就是ck本身,但要注意识别码是String类型,而ck是int类型。
继续看sb()
方法:
1 | public static int sb(int i) { |
这个直接复制求结果就好。当我们假定一个ck后,试一下执行得到我们需要输入密码。
特别奇怪是不是,一个根本得不到密码,另一个出来了非常多的密码。捋一下程序的逻辑,它一共执行了两次大循环,第一次是resume,第二次是resin。每个大循环里面又执行了4次中循环,中循环里面执行了5次小循环。所以按理来说,一个随机数可以得到40个密码。到底哪一个密码才能正确解密呢?
我们知道这个第一层锁机函数L()
是在onCreate()
函数中的,应用程序呈现给用户看到的界面已经是执行完onCreate()
后的事情了,所以正确的密码应该是最后一个。那为什么作者要设计这么“多余”的内容呢?我猜应该是用来迷惑人的,增加逆向者的工作量。
那么第一层锁机就被我们破解了,我们只需知道识别码就可以得到正确密码解锁。
2. 第二层锁机
第二层的整体结构与第一层差不多,而且还比第一层简单,直接将代码复制下来跑一遍就得到密码了。
3. 第三层锁机
canSU()
里面是什么呢?进去看看。
1 | public boolean canSU() { |
mount -o rw,remount /system
:以可读写的方式加载/system分区。
rm -rf /system/priv-app/cx.apk
:强制删除系统核心应用 cx.apk
。
rm -rf /system/app/cx.apk
:强制删除系统核心应用 cx.apk
。
mv /system/app/youqing /system/usr/keylayout
:将/system/app/youqing移动到/system/usr/keylayout。
mv /system/priv-app/hlx /system/priv-app/Settings
:将hlx重命名为Settings。
reboot
:重启。
/system/priv-app 中包括 Launcher,SystemUI,SettingsProvider 等,均是系统的核心应用,这些应用能使用系统级的权限,4.4 之前的所有 /system/app 下的软件都能使用系统级的权限,Google 这样做是把内置到系统的应用也做个级别的区别。放到 /system/priv-app 下的应用比放到 /system/app 下的应用可以声明获得更多的权限。
我们在之前的分析中并没有发现应用程序在这些地方执行过命令,所以canSU()
我们是不希望执行的。因此第三层的密码算法应该是"" + (v1 ^ cz)
。
同样复制代码修改一下就可以求得v1的值,进而得到密码。
需要注意的是letterToNumber()
在jeb中反编译错误,而Jadx中是正确的。看来还是不能盲目相信一个反编译器的编译结果。
去除浮窗后还是不停振动并发出不可描述的声音,赶紧把应用程序卸载即可,但被删除的文件找不回来了。
如果手机没有进行root,这个锁机软件在需要root权限的一些操作就可以避免,比如读写/system分区、强制删除系统APK等。由于现在的手机都默认没有root权限,所以锁机病毒几乎都灭绝了吧。