【手游】封神大主宰 美术资源加密分析

这是一款Q萌系横版封神榜题材策略手游


0x00 先用WinHex看看被加密了的游戏资源

\assets\MyResources\originalRes\background

\assets\MyResources\originalRes\background_UI

\assets\MyResources\originalRes\cardresources

以上3个文件夹里的图片都被加密了texturePacker文件夹里有2个图片加密了,其他的都是没有加密



0x01 在IDA中分析\lib\armeabi\libcocos2dcpp.so

这里分享一个小经验,一般cocos2dx的游戏我会先在IDA查看getFileData和initWithImageData这2个方法,很多游戏调用解密的方法就在这里(机率还是挺高的)

这个游戏加密方法用的是XXTea(Tea的变种算法),算法不难只要找到Key就行了,先看看这个游戏的解密图片的流程

cocos2d::CCFileUtilsAndroid::getFileData(char const*,char const*,ulong *)

    ↓

cocos2d::CCFileUtilsAndroid::doGetFileData(char const*,char const*,ulong *,bool)

    ↓

cocos2d::ZipFile::getFileData(std::string const&,ulong *)

    ↓

cocos2d::ZipFile::getFileData(std::string const&,ulong *,cocos2d::ZipFilePrivate *)

    ↓

ResourcesDecode::decodeData(uchar *,ulong,ulong *)

    ↓

xxtea_decrypt



上图红框中sub_6A6E5268这个方法就是XXTea的解密算法v8这个参数就是Key


0x02 关于XXTea算法自己问谷个度娘吧,我这里就不细说了,关键是如何找到这个Key

每个加密文件前29字节都是20151108.fengshen.sunlong.com,在IDA中搜索相关字符串


双击看看在哪里引用了


跳转到AppDelegate::applicationDidFinishLaunching这个方法中


这时已经很明了,key就是sunlong,20151108.fengshen.sunlong.com是为了识别被加密的文件


0x03 下面给出关键代码

XXTea.cs(XXTea算法C#版)

public class XXTea
{
    public static byte[] Encrypt(byte[] Data, byte[] Key)
    {
        if (Data.Length == 0)
        {
            return Data;
        }

        return ToByteArray(Encrypt(TouintArray(Data, true), TouintArray(Key, false)), false);
    }

    public static byte[] Decrypt(byte[] Data, byte[] Key)
    {
        if (Data.Length == 0)
        {
            return Data;
        }
        return ToByteArray(Decrypt(TouintArray(Data, false), TouintArray(Key, false)), true);
    }

    private static uint[] Encrypt(uint[] v, uint[] k)
    {
        int n = v.Length - 1;
        if (n < 1)
        {
            return v;
        }
        if (k.Length < 4)
        {
            uint[] Key = new uint[4];
            k.CopyTo(Key, 0);
            k = Key;
        }
        uint z = v[n], y = v[0], delta = 0x9E3779B9, sum = 0, e;
        int p, q = 6 + 52 / (n + 1);
        while (q-- > 0)
        {
            sum = unchecked(sum + delta);
            e = sum >> 2 & 3;
            for (p = 0; p < n; p++)
            {
                y = v[p + 1];
                z = unchecked(v[p] += (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
            }
            y = v[0];
            z = unchecked(v[n] += (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
        }
        return v;
    }

    private static uint[] Decrypt(uint[] v, uint[] k)
    {
        int n = v.Length - 1;
        if (n < 1)
        {
            return v;
        }
        if (k.Length < 4)
        {
            uint[] Key = new uint[4];
            k.CopyTo(Key, 0);
            k = Key;
        }
        uint z = v[n], y = v[0], delta = 0x9E3779B9, sum, e;
        int p, q = 6 + 52 / (n + 1);
        sum = unchecked((uint)(q * delta));
        while (sum != 0)
        {
            e = sum >> 2 & 3;
            for (p = n; p > 0; p--)
            {
                z = v[p - 1];
                y = unchecked(v[p] -= (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
            }
            z = v[n];
            y = unchecked(v[0] -= (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z));
            sum = unchecked(sum - delta);
        }
        return v;
    }

    private static uint[] TouintArray(byte[] Data, bool IncludeLength)
    {
        int n = (((Data.Length & 3) == 0) ? (Data.Length >> 2) : ((Data.Length >> 2) + 1));
        uint[] Result;
        if (IncludeLength)
        {
            Result = new uint[n + 1];
            Result[n] = (uint)Data.Length;
        }
        else
        {
            Result = new uint[n];
        }
        n = Data.Length;
        for (int i = 0; i < n; i++)
        {
            Result[i >> 2] |= (uint)Data[i] << ((i & 3) << 3);
        }
        return Result;
    }

    private static byte[] ToByteArray(uint[] Data, bool IncludeLength)
    {
        int n;
        if (IncludeLength)
        {
            n = (int)Data[Data.Length - 1];
        }
        else
        {
            n = Data.Length << 2;
        }
        byte[] Result = new byte[n];
        for (int i = 0; i < n; i++)
        {
            Result[i] = (byte)(Data[i >> 2] >> ((i & 3) << 3));
        }
        return Result;
    }
}

这里是调用XXTea解密的关键代码

//遍历查找文件
public void FindFile(string dirPath) //参数dirPath为指定的目录 
{
    DirectoryInfo Dir = new DirectoryInfo(dirPath);
    try
    {
        //查找子目录 
        foreach (DirectoryInfo d in Dir.GetDirectories())
        {
            FindFile(Dir + "\\" + d.ToString());
        }

        //查找文件 
        foreach (FileInfo f in Dir.GetFiles("*.*"))
        {
            ReadFile(f);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

//读取加密文件
private void ReadFile(FileInfo f)
{
    using (FileStream inStream = new FileStream(f.FullName, FileMode.Open, FileAccess.ReadWrite))
    {
        byte[] bytes = new byte[inStream.Length];
        inStream.Read(bytes, 0, bytes.Length);
        inStream.Close();

        if (Encoding.Default.GetString(bytes).Contains("20151108.fengshen.sunlong.com"))
        {
            byte[] encryptByte = new byte[bytes.Length - 29];
            Array.Copy(bytes, 29, encryptByte, 0, bytes.Length - 29);
            byte[] keyByte = Encoding.Default.GetBytes("sunlong");
            byte[] decryptByte = XXTea.Decrypt(encryptByte, keyByte);

            OutResFile(f, decryptByte, Path.GetExtension(f.FullName));
        }
    }
}

//输出文件
private void OutResFile(FileInfo f, byte[] bytes, string extension)
{
    string outPath = Path.Combine(f.DirectoryName, Path.GetFileNameWithoutExtension(f.FullName) + extension);

    using (FileStream outStream = new FileStream(outPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
    {
        outStream.Seek(0, SeekOrigin.Begin);
        outStream.Write(bytes, 0, bytes.Length);
    }
}


资源提取源码

链接:http://pan.baidu.com/s/1mi9AXRi 密码:4402

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值