微信小游戏

有人做过微信小游戏资源解密?小游戏平台的
有大佬做过小游戏资源加密后的解密步骤的?帮看一下,谢谢

这个你得出钱,才有人帮你,而且价格还不低吧

可以参考这个开源项目和社区帖子做一下:
https://github.com/zhitaocai/CocosCreator-Build-Encrypt

没必要,解密代码肯定也在代码里面。现在AI逆向拆包解密,一分钟都不要内裤都给你扒干净

当然,防一些用不起AI的人还是有点用。这种东西确实,不花钱没人会好心告诉你完整方案。反正整体不难

web和native 我自己已经搞定上线, 剩下小程序。ai年代了,这玩意门槛不高。我小程序搞一下,直接免费公布

…这种只要知道在哪里做解密。就能搞,估摸应该和web一样。web和native 我自己已经搞定上线, 剩下小程序。我小程序搞一下,直接免费公布

别人辛苦做的项目,这样反编译一下换成自己的 这样能行?ai这么强了,自己发挥创意不好吗?

分享一下web的方案老哥

那你还来问 :sweat_smile: :sweat_smile: :sweat_smile:

人性就是这样,他就是要占你便宜!

笑死,国内环境纯自研的有几个人?不都是靠“借鉴”。某些大企业都带头,都懒得喷了

哈哈,借鉴没有错,但是你搞别人的代码 还很光荣,别人一样搞你,搞来搞去

?理解问题?我是加密自己公司的游戏项目的资源

没弄过微信小游戏加密。本意想问做过的能直接点一下哪里做解密.省的琢磨

这台点电脑只有ios相关的。贴一下xor加密。 不过你问ai就有

“”"

Cocos资源加密工具 - 纯XOR版本(跨平台一致)

强制使用XOR加密,不依赖任何外部库

适用于微信小游戏、Web、iOS、Android全平台

“”"

import os

import sys

import struct

import hashlib

import time

import shutil

from pathlib import Path

print(“✓ 使用纯XOR加密(跨平台一致,无依赖)”)

class XorOnlyEncryptor:

"""纯XOR加密器,Windows/Mac/Linux/微信小游戏完全兼容"""



def __init__(self, key="my_secret_key_123"):

    self.key = self._process_key(key)

    self.backup_dir = ".backup_encrypt"



def _process_key(self, key):

    """处理密钥,生成固定长度的密钥流种子"""

    if isinstance(key, str):

        key = key.encode('utf-8')

   

    # 使用SHA256生成32字节密钥(作为XOR的重复密钥)

    return hashlib.sha256(key).digest()



def _xor_crypt(self, data, iv=None):

    """

    XOR加密/解密函数(对称操作)

    使用密钥流进行XOR,IV用于增加随机性

    """

    if iv is None:

        iv = os.urandom(16)

   

    # 将密钥和IV混合生成密钥流种子

    seed = self.key + iv

   

    # 生成与数据等长的密钥流(通过重复哈希)

    key_stream = self._generate_keystream(seed, len(data))

   

    # XOR操作

    result = bytearray(len(data))

    for i in range(len(data)):

        result[i] = data[i] ^ key_stream[i]

   

    return bytes(result), iv



def _generate_keystream(self, seed, length):

    """生成伪随机密钥流(基于SHA256的CTR模式)"""

    keystream = bytearray()

    counter = 0

   

    while len(keystream) < length:

        # 将种子和计数器组合

        data = seed + struct.pack('<Q', counter)

        # 使用SHA256生成伪随机块

        block = hashlib.sha256(data).digest()

        keystream.extend(block)

        counter += 1

   

    return bytes(keystream[:length])



def encrypt_data(self, data):

    """加密数据 - 强制使用XOR"""

    try:

        # 格式: [CCXE][原始长度4字节][IV16字节][加密数据]

        magic = b'CCXE'  # XOR加密标识

       

        # 生成随机IV(增加安全性,即使相同明文也不同密文)

        iv = os.urandom(16)

       

        # XOR加密

        encrypted_data, _ = self._xor_crypt(data, iv)

       

        # 打包原始长度

        size = struct.pack('<I', len(data))

       

        return magic + size + iv + encrypted_data

       

    except Exception as e:

        print(f"加密出错: {e}")

        raise



def decrypt_data(self, data):

    """解密数据"""

    if len(data) < 8:

        return data

   

    magic = data[:4]

   

    if magic == b'CCXE':

        try:

            original_size = struct.unpack('<I', data[4:8])[0]

            iv = data[8:24]

            encrypted = data[24:]

           

            # XOR解密(与加密相同的操作)

            original_data, _ = self._xor_crypt(encrypted, iv)

           

            if len(original_data) != original_size:

                print(f"  警告: 解密后长度不匹配")

           

            return original_data[:original_size]  # 确保长度正确

           

        except Exception as e:

            print(f"XOR解密失败: {e}")

            return data

   

    elif magic == b'CCEN':

        print(f"  警告: 检测到旧AES格式文件,尝试兼容解密...")

        # 尝试兼容旧AES格式(简单XOR解密,可能不完整)

        try:

            original_size = struct.unpack('<I', data[4:8])[0]

            if len(data) > 24:

                # 跳过IV,尝试XOR解密

                encrypted = data[24:]

            else:

                encrypted = data[8:]

           

            # 简单XOR解密(使用原始密钥)

            result = bytearray(encrypted)

            key_len = len(self.key)

            for i in range(len(result)):

                result[i] ^= self.key[i % key_len]

           

            return bytes(result[:original_size])

        except:

            pass

   

    # 不是加密文件或解密失败

    return data



def is_encrypted_file(self, filepath):

    """检查文件是否已加密"""

    try:

        with open(filepath, 'rb') as f:

            header = f.read(8)

            if len(header) >= 8:

                magic = header[:4]

                return magic in [b'CCXE', b'CCEN']

    except:

        pass

    return False



def _backup_file(self, filepath):

    """备份文件"""

    try:

        backup_dir = os.path.join(os.path.dirname(filepath), self.backup_dir)

        os.makedirs(backup_dir, exist_ok=True)

       

        with open(filepath, 'rb') as f:

            data = f.read()

       

        filename = os.path.basename(filepath)

        timestamp = int(time.time())

        backup_name = f"{filename}.{timestamp}.bak"

        backup_path = os.path.join(backup_dir, backup_name)

       

        with open(backup_path, 'wb') as f:

            f.write(data)

       

        return backup_path

    except Exception as e:

        print(f"备份失败 {filepath}: {e}")

        return None



def _find_latest_backup(self, filepath):

    """查找最新的备份"""

    try:

        backup_dir = os.path.join(os.path.dirname(filepath), self.backup_dir)

        if not os.path.exists(backup_dir):

            return None

       

        filename = os.path.basename(filepath)

        backups = []

       

        for f in os.listdir(backup_dir):

            if f.startswith(filename + ".") and f.endswith(".bak"):

                parts = f.split('.')

                if len(parts) >= 2:

                    try:

                        backup_time = int(parts[-2])

                        backups.append((backup_time, os.path.join(backup_dir, f)))

                    except ValueError:

                        continue

       

        if backups:

            backups.sort(reverse=True)

            return backups[0][1]

    except:

        pass

    return None



def encrypt_file(self, filepath, backup=True):

    """加密单个文件(原地加密)"""

    try:

        if not os.path.exists(filepath):

            print(f"文件不存在: {filepath}")

            return False

       

        if self.is_encrypted_file(filepath):

            print(f"⏭️  已加密: {os.path.basename(filepath)}")

            return True

       

        backup_path = None

        if backup:

            backup_path = self._backup_file(filepath)

            if backup_path:

                print(f"  📁 备份: {os.path.basename(backup_path)}")

       

        with open(filepath, 'rb') as f:

            original_data = f.read()

       

        original_size = len(original_data)

       

        encrypted_data = self.encrypt_data(original_data)

        encrypted_size = len(encrypted_data)

       

        with open(filepath, 'wb') as f:

            f.write(encrypted_data)

       

        size_info = f"{original_size/1024:.1f}KB → {encrypted_size/1024:.1f}KB"

        change = f"+{(encrypted_size-original_size)/1024:.1f}KB"

        print(f"✅ 加密: {os.path.basename(filepath)} ({size_info}, {change})")

       

        return True

       

    except Exception as e:

        print(f"❌ 加密失败 {filepath}: {e}")

       

        if backup:

            latest_backup = self._find_latest_backup(filepath)

            if latest_backup and os.path.exists(latest_backup):

                try:

                    with open(latest_backup, 'rb') as f:

                        backup_data = f.read()

                    with open(filepath, 'wb') as f:

                        f.write(backup_data)

                    print(f"  🔄 已从备份恢复")

                except:

                    pass

       

        return False



def decrypt_file(self, filepath, restore_backup=False):

    """解密单个文件"""

    try:

        if not os.path.exists(filepath):

            print(f"文件不存在: {filepath}")

            return False

       

        if not self.is_encrypted_file(filepath):

            print(f"⏭️  未加密: {os.path.basename(filepath)}")

            return False

       

        if restore_backup:

            latest_backup = self._find_latest_backup(filepath)

            if latest_backup and os.path.exists(latest_backup):

                try:

                    with open(latest_backup, 'rb') as f:

                        backup_data = f.read()

                    with open(filepath, 'wb') as f:

                        f.write(backup_data)

                    print(f"✅ 从备份恢复: {os.path.basename(filepath)}")

                    return True

                except Exception as e:

                    print(f"备份恢复失败: {e}")

       

        with open(filepath, 'rb') as f:

            encrypted_data = f.read()

       

        original_size = len(encrypted_data)

       

        decrypted_data = self.decrypt_data(encrypted_data)

        decrypted_size = len(decrypted_data)

       

        with open(filepath, 'wb') as f:

            f.write(decrypted_data)

       

        size_info = f"{original_size/1024:.1f}KB → {decrypted_size/1024:.1f}KB"

        change = f"-{(original_size-decrypted_size)/1024:.1f}KB"

        print(f"✅ 解密: {os.path.basename(filepath)} ({size_info}, {change})")

       

        return True

       

    except Exception as e:

        print(f"❌ 解密失败 {filepath}: {e}")

        return False



def process_directory(self, directory, extensions=None, recursive=True):

    """处理目录"""

    if extensions is None:

        # 统一使用小写,避免大小写问题

        extensions = {'.png', '.jpg', '.jpeg'}

   

    if not os.path.exists(directory):

        print(f"❌ 目录不存在: {directory}")

        return []

   

    if not os.path.isdir(directory):

        print(f"❌ 不是目录: {directory}")

        return []

   

    print(f"📁 处理目录: {directory}")

    print(f"📄 文件类型: {', '.join(sorted(extensions))}")

    print(f"🔍 模式: XOR加密(跨平台一致)")

    print("=" * 60)

   

    processed_files = []

   

    if recursive:

        for root, dirs, files in os.walk(directory):

            if self.backup_dir in root:

                continue

           

            for file in files:

                file_ext = os.path.splitext(file)[1].lower()

                if file_ext in extensions:

                    filepath = os.path.join(root, file)

                    relative_path = os.path.relpath(filepath, directory)

                   

                    if self.encrypt_file(filepath, backup=True):

                        processed_files.append(relative_path)

    else:

        for item in os.listdir(directory):

            filepath = os.path.join(directory, item)

            if os.path.isfile(filepath):

                file_ext = os.path.splitext(item)[1].lower()

                if file_ext in extensions:

                    if self.encrypt_file(filepath, backup=True):

                        processed_files.append(item)

   

    return processed_files

def clean_all_backup_folders(root_path="."):

"""

递归删除root_path下所有名为.backup_encrypt的文件夹及其内容

"""

deleted_count = 0

error_count = 0



print(f"\n🧹 开始清理所有 .backup_encrypt 文件夹...")

print(f"🔍 扫描路径: {os.path.abspath(root_path)}")

print("-" * 60)



for root, dirs, files in os.walk(root_path, topdown=False):

    for dir_name in dirs:

        if dir_name == ".backup_encrypt":

            backup_path = os.path.join(root, dir_name)

           

            if not os.path.exists(backup_path):

                continue

           

            try:

                backup_files = [f for f in os.listdir(backup_path) if f.endswith('.bak')]

                file_count = len(backup_files)

               

                shutil.rmtree(backup_path)

                print(f"🗑️  已删除: {backup_path} ({file_count} 个备份文件)")

                deleted_count += 1

            except PermissionError:

                print(f"❌ 权限不足,无法删除: {backup_path}")

                error_count += 1

            except Exception as e:

                print(f"❌ 删除失败 {backup_path}: {e}")

                error_count += 1



print("-" * 60)

if deleted_count > 0:

    print(f"✅ 清理完成!共删除 {deleted_count} 个备份文件夹")

else:

    print(f"ℹ️  未发现 .backup_encrypt 文件夹")



if error_count > 0:

    print(f"⚠️  清理过程中出现 {error_count} 个错误")



return deleted_count, error_count

def main():

"""主函数"""

# 检查是否只清理模式

clean_only_mode = "--clean-only" in sys.argv



# 固定设置

FIXED_KEY = "my_secret_key_123"



# 获取当前脚本所在目录

script_dir = os.path.dirname(os.path.abspath(__file__))

# 构建目标路径: 当前脚本目录/build

target_path = os.path.join(script_dir, "build")



# 如果build目录不存在,尝试使用当前目录

if not os.path.exists(target_path):

    print(f"⚠️  build目录不存在,使用当前目录: {script_dir}")

    target_path = script_dir



os.chdir(target_path)

print("🔐 资源加密工具 - XOR专用版(跨平台一致)")

print(f"🔑 密钥: {FIXED_KEY}")

print(f"📁 目标路径: {target_path}")



# 如果是只清理模式

if clean_only_mode:

    print("🧹 模式: 仅清理备份文件夹")

    print("=" * 60)

    clean_all_backup_folders(target_path)

    print("\n✅ 清理操作完成!")

    return



print("=" * 60)



# 创建加密器(强制XOR)

encryptor = XorOnlyEncryptor(FIXED_KEY)



# 自动加密目标路径

processed_files = encryptor.process_directory(

    target_path,

    extensions={'.png', '.jpg', '.jpeg'},

    recursive=True

)



# 显示结果

print("\n" + "=" * 60)

print(f"✅ 加密完成!")

print(f"📊 已加密文件数: {len(processed_files)}")



if processed_files:

    print(f"\n📄 已加密的文件:")

    for i, file in enumerate(processed_files[:20]):

        print(f"  {i+1:3d}. {file}")

    if len(processed_files) > 20:

        print(f"  ... 还有 {len(processed_files)-20} 个文件")



# 显示备份信息

backup_dir = os.path.join(target_path, encryptor.backup_dir)

if os.path.exists(backup_dir):

    backup_files = [f for f in os.listdir(backup_dir) if f.endswith('.bak')]

    backup_count = len(backup_files)

    if backup_count > 0:

        print(f"\n📁 备份目录: {backup_dir}")

        print(f"📦 备份文件数: {backup_count}")

        print(f"💡 如需恢复,备份文件已保存在以上目录中")



# 自动清理所有.backup_encrypt文件夹

print("\n" + "=" * 60)

print("🧹 开始清理所有备份文件夹...")

deleted, errors = clean_all_backup_folders(target_path)



if deleted > 0:

    print(f"\n✅ 已自动清理 {deleted} 个备份文件夹")

    if errors == 0:

        print("💡 所有备份文件已删除,无法再恢复原始文件")

else:

    print("\nℹ️  未发现需要清理的备份文件夹")

if name == “main”:

main()
1赞

解密就是在读取图片的位置,我这电脑只有native的代码了,你满看着自己做一下web
void Image::initEncryptionKey() {

if (s_keyInitialized) {

    return;

}



// 设置默认密钥

setEncryptionKey("my_secret_key_123");

}

bool Image::isEncryptedData(const unsigned char* data, uint32_t dataLen) {

if (!data || dataLen < 8) {

    return false;

}



// 检查魔术头

if (memcmp(data, MAGIC_AES, 4) == 0) {

    return true;  // AES加密

}



if (memcmp(data, MAGIC_XOR, 4) == 0) {

    return true;  // XOR加密

}



return false;

}

uint32_t Image::getOriginalSizeFromHeader(const unsigned char* header) {

if (!header) {

    return 0;

}



// 小端序读取原始大小

uint32_t size = 0;

size = header[4];

size |= (uint32_t)header[5] << 8;

size |= (uint32_t)header[6] << 16;

size |= (uint32_t)header[7] << 24;



return size;

}

unsigned char* Image::xorDecrypt(const unsigned char* encryptedData, uint32_t dataLen, uint32_t& outLen) {

outLen = dataLen;



if (!encryptedData || dataLen == 0 || s_encryptionKey.empty()) {

    CC_LOG_ERROR("[Image] XOR decrypt invalid params");

    return nullptr;

}



unsigned char* result = (unsigned char*)malloc(dataLen);

if (!result) {

    CC_LOG_ERROR("[Image] XOR decrypt malloc failed");

    return nullptr;

}



// XOR解密

for (uint32_t i = 0; i < dataLen; ++i) {

    result[i] = encryptedData[i] ^ s_encryptionKey[i % s_encryptionKey.size()];

}



return result;

}

unsigned char* Image::aesDecrypt(const unsigned char* encryptedData, uint32_t dataLen,

                            const unsigned char* iv, uint32_t& outLen) {

outLen = 0;



if (!encryptedData || dataLen == 0 || !iv || s_encryptionKey.size() < 16) {

    CC_LOG_ERROR("[Image] AES decrypt invalid params");

    return nullptr;

}

#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC

// iOS/Mac使用CommonCrypto

unsigned char* result = (unsigned char*)malloc(dataLen + kCCBlockSizeAES128);

if (!result) {

    CC_LOG_ERROR("[Image] AES decrypt malloc failed");

    return nullptr;

}



size_t decryptedLen = 0;

CCCryptorStatus status = CCCrypt(kCCDecrypt,

                                kCCAlgorithmAES,

                                kCCOptionPKCS7Padding,

                                s_encryptionKey.data(),

                                s_encryptionKey.size(),

                                iv,

                                encryptedData,

                                dataLen,

                                result,

                                dataLen + kCCBlockSizeAES128,

                                &decryptedLen);



if (status != kCCSuccess) {

    CC_LOG_ERROR("[Image] AES decrypt failed: %d", status);

    free(result);

    return nullptr;

}



outLen = static_cast<uint32_t>(decryptedLen);

return result;

#else

// 其他平台暂时只支持XOR加密

CC_LOG_ERROR("[Image] AES decrypt not supported on this platform");

return nullptr;

#endif

}

unsigned char* Image::decryptImageData(const unsigned char* data, uint32_t dataLen, uint32_t& outLen) {

outLen = 0;



if (!data || dataLen < 8 || !s_keyInitialized) {

    CC_LOG_ERROR("[Image] Decrypt invalid parameters");

    return nullptr;

}



// 检查加密类型

if (memcmp(data, MAGIC_AES, 4) == 0) {

    // AES加密格式: [CCEN][size][IV16][encrypted data]

    if (dataLen < 24) {  // 至少需要魔术头4 + 大小4 + IV16

        CC_LOG_ERROR("[Image] AES data too short: %u", dataLen);

        return nullptr;

    }

   

    // 获取原始大小

    uint32_t originalSize = getOriginalSizeFromHeader(data);

   

    // 提取IV和数据

    const unsigned char* iv = data + 8;

    const unsigned char* encryptedData = data + 24;

    uint32_t encryptedLen = dataLen - 24;

   

    // AES解密

    unsigned char* result = aesDecrypt(encryptedData, encryptedLen, iv, outLen);

   

    if (result && outLen != originalSize) {

        CC_LOG_WARNING("[Image] AES decrypted size mismatch: expected %u, got %u",

                   originalSize, outLen);

    }

   

    return result;

   

} else if (memcmp(data, MAGIC_XOR, 4) == 0) {

    // XOR加密格式: [CCXE][size][encrypted data]

    if (dataLen < 8) {

        CC_LOG_ERROR("[Image] XOR data too short: %u", dataLen);

        return nullptr;

    }

   

    // 获取原始大小

    uint32_t originalSize = getOriginalSizeFromHeader(data);

   

    // XOR解密

    const unsigned char* encryptedData = data + 8;

    uint32_t encryptedLen = dataLen - 8;

   

    unsigned char* result = xorDecrypt(encryptedData, encryptedLen, outLen);

   

    if (result && outLen != originalSize) {

        CC_LOG_WARNING("[Image] XOR decrypted size mismatch: expected %u, got %u",

                   originalSize, outLen);

    }

   

    return result;

}



CC_LOG_ERROR("[Image] Not encrypted data");

return nullptr;

}

// 修改initWithImageData函数

bool Image::initWithImageData(const unsigned char *data, uint32_t dataLen) { //NOLINT(misc-no-recursion)

bool ret = false;

do {

    CC_BREAK_IF(!data || dataLen <= 0);

   

    // 初始化密钥

    initEncryptionKey();

   

    unsigned char *processedData = const_cast<unsigned char *>(data);

    uint32_t processedDataLen = dataLen;

    unsigned char *decryptedData = nullptr;

   

    // 检查是否需要解密

    if (isEncryptedData(data, dataLen)) {

        CC_LOG_DEBUG("[Image] Detected encrypted image data, decrypting...");

       

        uint32_t decryptedLen = 0;

        decryptedData = decryptImageData(data, dataLen, decryptedLen);

       

        if (decryptedData && decryptedLen > 0) {

            processedData = decryptedData;

            processedDataLen = decryptedLen;

            //printf("[Image] 解密成功: %u -> %u 字节\n", dataLen, decryptedLen);

            CC_LOG_DEBUG("[Image] Decrypted: %u -> %u bytes", dataLen, decryptedLen);

        } else {

            //printf("[Image] 解密失败!\n");

            CC_LOG_ERROR("[Image] Failed to decrypt image data");

            // 解密失败,尝试使用原始数据

        }

    }else {

        //printf("[Image] 非加密文件,直接处理\n");

    }

   

    unsigned char *unpackedData = nullptr;

    uint32_t unpackedLen = 0;

    // 检测并解压压缩文件

    if (ZipUtils::isCCZBuffer(processedData, processedDataLen)) {

        unpackedLen = ZipUtils::inflateCCZBuffer(processedData, processedDataLen, &unpackedData);

    } else if (ZipUtils::isGZipBuffer(processedData, processedDataLen)) {

        unpackedLen = ZipUtils::inflateMemory(processedData, processedDataLen, &unpackedData);

    } else {

        unpackedData = processedData;

        unpackedLen = processedDataLen;

    }

    _fileType = detectFormat(unpackedData, unpackedLen);

    switch (_fileType) {

        case Format::PNG:

            ret = initWithPngData(unpackedData, unpackedLen);

            break;

        case Format::JPG:

            ret = initWithJpgData(unpackedData, unpackedLen);

            break;

#if CC_USE_WEBP

        case Format::WEBP:

            ret = initWithWebpData(unpackedData, unpackedLen);

            break;

#endif

        case Format::PVR:

            ret = initWithPVRData(unpackedData, unpackedLen);

            break;

        case Format::ETC:

            ret = initWithETCData(unpackedData, unpackedLen);

            break;

        case Format::ETC2:

            ret = initWithETC2Data(unpackedData, unpackedLen);

            break;

        case Format::ASTC:

            ret = initWithASTCData(unpackedData, unpackedLen);

            break;

        case Format::COMPRESSED:

            ret = initWithCompressedMipsData(unpackedData, unpackedLen);

            break;

        default:

            break;

    }

    // 清理内存

    if (unpackedData != processedData) {

        free(unpackedData);

    }

   

    // 如果解密了数据,需要释放解密内存

    if (decryptedData != nullptr) {

        free(decryptedData);

    }

   

} while (false);

return ret;

}

1赞

这是只能获取素材么

:sweat_smile: 好像你说的对