pc2g

 找回密码
 加入我们
搜索
热搜: 活动 交友 discuz
查看: 1982|回复: 0

去除 Flash 小游戏加密外壳 MochiCrypt

[复制链接]

2435

主题

218

回帖

8747

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
8747
发表于 2021-5-21 18:39:21 | 显示全部楼层 |阅读模式

pc2g,电脑好游戏 很多国外小游戏在加载的时候会在进度条旁边显示一个小锁头图标, 同时联网的情况下上面会显示广告.


使用 Flash 反编译工具打开这种 Flash, 无法获取游戏内的资源与程序逻辑.


这是因为 Flash 使用了 MochiCrypt 加壳. 在网上简单搜索了一下, 很久之前有一位叫 Cordy 的大神发布过一个解包工具, 但应该是由于 MochiCrypt 更新而导致无法解密, 大神的博客也早已注销. (在虚拟机里运行的原因是 Win10 下打开无法正常工作, 只显示一个空白窗体, 可见确实非常老了)


论坛搜了一圈也没搜到类似的内容, 没办法只能自己来研究一下. 使用免费开源的 JPEXS Free Flash Decompiler 打开, 研究一下, 发现这个叫做 Preloader 的类中代码量很多, 从构造函数入手, 发现 new 了一个 Loader, 并且注册了加载的事件:


这个加载事件里面大概就是进行一通配置然后开始加载, 可以看到 ads 字样, 应该是和广告有关:



往下翻翻, 这个叫做 finish 的函数吸引了我的注意. 先根据 PAYLOAD_NAME 获取一个 Payload 类, 然后通过这个类获取了一个字节数组:


之后开始对这个字节数组进行明显像是解密的位操作:


最后声明一个 Loader, 加载解密过后的 Payload 并展示在舞台上:


而被加载的 Payload 就在 SWF 的二进制数据中, 资源ID为 7 (对所有 MochiCrypt 加壳的 Flash 都是如此):


看起来非常简单. 由于本人不是非常熟悉 AS3, 决定使用 C# 语言写一个工具进行解包. 首先读取要解密的 SWF, 并分析其所有的Tag. 由于 Flash 文件格式较为复杂, 手动实现较为耗时, 使用现成的开源类库 SwfExtractor 进行读取. 这个类库并不支持二进制数据(DefineBinaryData) 的 Tag, 因此我自行修改了一个版本(可以在我的 GitHub 仓库找到). 以下为打开 SWF 文件并寻找 ID 为 7 的二进制数据:
[C#] 纯文本查看 复制代码
?
1
2
3
4
SwfParser swf = new SwfParser();
swf.Parse(data);
DefineBinaryData payloadTag = swf.FindTags<DefineBinaryData>().ToList().Find(i => i.CharacterID == 7);
byte[] payload = payloadTag.ExtractData();






这样名为 payload 的字节数组中存放的即为密文数据. 将上面 AS3 的解密函数改写为 C# 语法(两种语言语法大体相似, 改动不多). 其中 AS3 源代码存在 data.uncompress(); 一句, 查找得知 Flash 对 ByteArray 的压缩与解压使用 zlib 算法, 于是在 C# 的实现中使用开源类库 zlib.managed:
[C#] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
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
57
58
59
60
61
public static byte[] Decrypt(byte[] payload)
{
    List<byte> S = new List<byte>();
    int i = 0;
    int j = 0;
    int k = 0;
    int n = 0;
    int u = 0;
    int v = 0;

    n = payload.Length - 32;
    while (i < 256)
    {
        S.Add((byte)i);
        i++;
    }
    j = 0;
    i = 0;
    while (i < 256)
    {
        j = j + S + payload[n + (i & 31)] & 255;
        u = S;
        S = S[j];
        S[j] = (byte)u;
        i++;
    }
    if (n > 131072)
    {
        n = 131072;
    }
    j = 0;
    i = 0;
    k = 0;
    while (k < n)
    {
        i = i + 1 & 255;
        u = S;
        j = j + u & 255;
        v = S[j];
        S = (byte)v;
        S[j] = (byte)u;
        payload[k] = (byte)(payload[k] ^ S[u + v & 255]);
        k++;
    }

    byte[] buf = new byte[65535];
    int lastDecompressed = 0;
    using (Stream input = new MemoryStream(payload))
    using (MemoryStream output = new MemoryStream())
    using (ZOutputStream zlib = new ZOutputStream(output))
    {
        do
        {
            lastDecompressed = input.Read(buf, 0, buf.Length);
            zlib.Write(buf, 0, lastDecompressed);
            output.Flush();
        }
        while (lastDecompressed > 0);
        return output.ToArray();
    }
}






最后进行一些窗体与逻辑代码实现, 最终结果:


拖入一些 SWF 文件和非 SWF 文件, 获得预期的输出 (其中 2 和 3 是 MochiCrypt 加壳的动画, 1 未加壳, 4 根本不是 SWF 档. 脱壳后的 SWF 文件保存在源 SWF 文件同一路径下, 文件名为"源文件名_Unpacked.swf"):


使用 FFDec 打开脱壳后的 SWF 文件, 可以成功提取游戏资源:


工程文件已上传到GitHub, 如感觉有用欢迎给我点个Star:
https://github.com/whc2001/MochiCryptUnpacker

工具EXE下载:
链接: https://pan.baidu.com/s/1EYSV-vHbmFEEa-CNENLmvg 提取码: g6bb
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

Archiver|手机版|小黑屋|pc2g电脑好游戏

GMT+8, 2024-12-22 16:49 , Processed in 0.012458 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表