yyn 发表于 2021-5-21 18:39:21

去除 Flash 小游戏加密外壳 MochiCrypt

很多国外小游戏在加载的时候会在进度条旁边显示一个小锁头图标, 同时联网的情况下上面会显示广告.
https://attach.52pojie.cn/forum/201902/03/173635tomccozw2eoifect.png

使用 Flash 反编译工具打开这种 Flash, 无法获取游戏内的资源与程序逻辑.
https://attach.52pojie.cn/forum/201902/03/173636mcuu9ue9ffbi4424.png

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

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

这个加载事件里面大概就是进行一通配置然后开始加载, 可以看到 ads 字样, 应该是和广告有关:
https://attach.52pojie.cn/forum/201902/03/173639ouzdgbug4oo474o4.png
https://attach.52pojie.cn/forum/201902/03/173640pumtiiusdcsuwqij.png

往下翻翻, 这个叫做 finish 的函数吸引了我的注意. 先根据 PAYLOAD_NAME 获取一个 Payload 类, 然后通过这个类获取了一个字节数组:
https://attach.52pojie.cn/forum/201902/03/173641gi3db6sj3ed23y3w.png

之后开始对这个字节数组进行明显像是解密的位操作:
https://attach.52pojie.cn/forum/201902/03/163106hncxboneotqzhw56.png

最后声明一个 Loader, 加载解密过后的 Payload 并展示在舞台上:
https://attach.52pojie.cn/forum/201902/03/163109fldez9nph97pvlp9.png

而被加载的 Payload 就在 SWF 的二进制数据中, 资源ID为 7 (对所有 MochiCrypt 加壳的 Flash 都是如此):
https://attach.52pojie.cn/forum/201902/03/163243agcwu5cocruw4ggw.png

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

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:
纯文本查看 复制代码
?

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 & 255;
      u = S;
      S = S;
      S = (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;
      S = (byte)v;
      S = (byte)u;
      payload = (byte)(payload ^ S);
      k++;
    }

    byte[] buf = new byte;
    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();
    }
}







最后进行一些窗体与逻辑代码实现, 最终结果:
https://attach.52pojie.cn/forum/201902/03/171054bbjnwc5z8jfdwv1d.png

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

使用 FFDec 打开脱壳后的 SWF 文件, 可以成功提取游戏资源:
https://attach.52pojie.cn/forum/201902/03/171235sb40d7qqs9szqszh.png

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

工具EXE下载:
链接: https://pan.baidu.com/s/1EYSV-vHbmFEEa-CNENLmvg 提取码: g6bb
页: [1]
查看完整版本: 去除 Flash 小游戏加密外壳 MochiCrypt