whc2001 发表于 2019-2-3 17:33

去除 Flash 小游戏加密外壳 MochiCrypt

本帖最后由 whc2001 于 2019-2-3 17:40 编辑

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


使用 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 的二进制数据:

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:

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();
    }
}

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


拖入一些 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

完毕, 感谢观看.

Hmily 发表于 2019-2-3 23:08

这个看起来不是加密,而是打包吧?不看分析过程确实不知道。

whc2001 发表于 2019-2-4 03:50

oriwqz 发表于 2019-2-4 01:30
楼主能不能帮忙看看这个swf文件
https://pan.baidu.com/s/1vzlo8ee9wzC-CbIOidMvjg

你这个没加壳, 是混淆了, 用我帖子里那个反编译工具可以打开, 但是标识符全都是乱码. 可以用 工具->反混淆->重命名无效标识符 来把乱码换成ASCII文本(如package_01, var_02之类), 但是标识符原来是什么是不可能恢复了, 只能靠看代码逻辑猜用途.

新人类 发表于 2019-2-3 17:47

沙发,认真学习

bdrdc 发表于 2019-2-3 19:05

这个不错,好好研究研究.......

ii丶BigBreast 发表于 2019-2-3 19:15

牛逼啊兄嘚

多幸运遇见baby 发表于 2019-2-3 19:17

欢迎分析讨论交流,吾爱破解论坛有你更精彩!

fsf359 发表于 2019-2-3 19:22

谢谢。很好。。

lkylovehs 发表于 2019-2-3 20:08

牛逼啊高手

lei001xin 发表于 2019-2-3 20:31

感谢分享

oriwqz 发表于 2019-2-4 01:30

楼主能不能帮忙看看这个swf文件
https://pan.baidu.com/s/1vzlo8ee9wzC-CbIOidMvjg
页: [1] 2 3 4 5 6 7 8
查看完整版本: 去除 Flash 小游戏加密外壳 MochiCrypt