cocos2dx资源目录完全加密混淆方案

1,加密,采用blowfish或其他
2,自定是32个字符的混淆code
3,对文件做blowfish加密,入口文件加密前将混淆code按约定格式(自定义的文件头或文件尾部)写入到文件
4,遍历资源目录,对每个文件做md5混淆,混淆原始串=“相对路径”+“文件名”+混淆code,
    文件改名并且移动到资源目录根目录,清除原始目录
    入口文件除外,因为入口文件也混淆的话就只能把混淆code写入到加密程序中,不方便频繁修改,留个入口文件就能在程序运行最开始的地方读取到混淆code
5,引擎c++代码层修改文件检索,CCFileUtils::fullPathForFilename,获取md5混淆后的文件名,混淆原始串=“相对路径”+“文件名”+混淆code
6,拿到目标文件名后,blowfish对文件数据解码读取文件

因为混淆用的md5,混淆码是写在加密后的入口文件内的,所以破解出文件名就只能解开入口文件,但入口文件的加密过的,加密解密以及加密code是在c++层面做的,只通过资源或者脚本文件不可能破解出来,除非有能力把C++代码反编译出来.
是否有其他更牛逼的手段破解不知道,但总归现在这种方式已经将破解代价提到很高了,目的已经达到

脚本范例

require 'optparse'
require 'digest/md5'
require 'fileutils'
require './utils'

jobs = 1
OptionParser.new do |cfg|
	cfg.banner = "Usage:"
	cfg.on('-j', '--jobs num', 'jobs num')	{ |v| jobs = v.to_i }
end.parse!

dir = ARGV.shift()
# dir = 'E:/WorkSpace/Kapai/Games/xjlqiming/build/data'
raise if not jobs >= 1
raise if not dir
puts "加密目录:"+dir

#获取混淆串
key = ARGV.shift

#输出目录
out = ARGV.shift
if out
	puts dir,out
	u_copy_underDir dir,out
	dir = out
end
dir = u_UTF8 dir
dir = u_win2Utf dir

files = Dir.glob %Q[#{dir}/**/*]
files.delete_if do |f|
	name_slice = f.split "data/"
	name = f.sub name_slice[0]+"data/",""
	name.length == 32 and not name.index('.')
end

files.delete_if do |f|
not File.file? f or
	f.end_with? ".plist" or
	f.end_with? ".ttf" or
	f.end_with? ".mp3" or
	f.end_with? ".caf" or
	f.end_with? ".wav" or 
	f.end_with? "config/Config.xml" or
	f.end_with? "config/ServerConfig.xml"
end

job_files = []
(0...jobs).each { |i| job_files[i] = [] }
raise if not job_files.length() == jobs

files.each_index do |i|
	job_files[i%jobs].push files[i]
end

job_threads = []
(0...jobs).each do |i|
	job_threads[i] = Thread.start(i) do |i|
		job_files[i].each() do |f|
			print "\n加密文件#{f} "
			cmd = %Q[#{File.dirname(__FILE__)}/encryption.exe e "#{f}"]
			if key and key.length == 32 then cmd = cmd + " #{key}" end
			puts cmd
			if not system cmd then
				raise "ERROR:"+cmd
			end
		end
	end
	job_threads[i].abort_on_exception = true
end

(0...jobs).each do |i|
	job_threads[i].join
end

puts "开始混淆......................#{key}"
sleep 3
if key and key.length == 32 then
	job_threads = []
	(0...jobs).each do |i|
		job_threads[i] = Thread.start(i) do |i|
			job_files[i].each() do |f|
				next if f =~ /script\/main.lua/
				#只保留相对路径
				name_slice = f.split "data/"
				name = f.sub name_slice[0]+"data/",""
				raise "name 为空" unless name 
				#跳过已经混淆的文件
				next if name.length == 32 and not name.index('.')
				#添加混淆串
				print "文件混淆#{name}"
				name = name + key if key
				md5 = Digest::MD5.new
				md5_name = md5.hexdigest name
				raise "生成混淆代码失败" unless md5_name
				#避免文件占用,先打开一下尝试状态
				File.open(f) do |ff| end
				FileUtils.mv f,"#{dir}/#{md5_name}",:verbose => true,:force => true
			end
		end
		job_threads[i].abort_on_exception = true
	end

	(0...jobs).each do |i|
		job_threads[i].join
	end
end

#删除空目录
sleep 3
puts "清除空目录.................."
files = Dir.glob %Q[#{dir}/**/*]
files.each_index do |index|
	f = files[index]
	if File.directory? f then
		file_count = 0
		arr = Dir.glob %Q[#{f}/**/*]
		arr.each_index do |i|
			file_count = file_count + 1 unless File.directory? arr[i]
		end
		FileUtils.rm_r f,:verbose => true,:force => true if file_count == 0
	end
end


 

引擎文件检索修改示例
 

std::string CCFileUtils::fullPathForFilename(const char* pszFileName)
{
    CCAssert(pszFileName != NULL, "CCFileUtils: Invalid path");

	std::string strFileName = pszFileName;
	if (strFileName == "cc_2x2_white_image" || strFileName == "cc_fps_images"){
		return pszFileName;
	}

    if (isAbsolutePath(pszFileName))
    {
        //CCLOG("Return absolute path( %s ) directly.", pszFileName);
        return pszFileName;
	}
	else
	{
		int index = strFileName.find("script/logo.lua");
		if (   strFileName.find(".plist") == -1
			&& strFileName.find(".ttf") == -1
			&& strFileName.find(".mp3") == -1
			&& strFileName.find(".caf") == -1
			&& strFileName.find(".wav") == -1
			&& strFileName.find("script/main.lua") == -1)
		{
			if (m_data_key != NULL && m_data_key->size() > 0)
			{
				string a;
				for (int i = 0; i < m_data_key->size(); ++i){
					a = a + (char)((*m_data_key)[i]);
				}
				strFileName = strFileName + a;
				strFileName = Md5Encode(strFileName);
			}
		}
	}
    
    // Already Cached ?
    std::map<std::string, std::string>::iterator cacheIter = m_fullPathCache.find(pszFileName);
    if (cacheIter != m_fullPathCache.end())
    {
        //CCLOG("Return full path from cache: %s", cacheIter->second.c_str());
        return cacheIter->second;
    }
    
    // Get the new file name.
	std::string newFilename = getNewFilename(strFileName.c_str());

    string fullpath = "";
    
    for (std::vector<std::string>::iterator searchPathsIter = m_searchPathArray.begin();
         searchPathsIter != m_searchPathArray.end(); ++searchPathsIter) {
        for (std::vector<std::string>::iterator resOrderIter = m_searchResolutionsOrderArray.begin();
             resOrderIter != m_searchResolutionsOrderArray.end(); ++resOrderIter) {
            
            //CCLOG("\n\nSEARCHING: %s, %s, %s", newFilename.c_str(), resOrderIter->c_str(), searchPathsIter->c_str());
            
            fullpath = this->getPathForFilename(newFilename, *resOrderIter, *searchPathsIter);
            
            if (fullpath.length() > 0)
            {
                // Using the filename passed in as key.
                m_fullPathCache.insert(std::pair<std::string, std::string>(pszFileName, fullpath));
                //CCLOG("Returning path: %s", fullpath.c_str());
                return fullpath;
            }
        }
    }
    
    CCLOG("cocos2d: fullPathForFilename: No file found at %s Possible missing file.", pszFileName);

    // The file wasn't found, return the file name passed in.
    return pszFileName;
}

blowfish加密解密

Blowfish *bl = new Blowfish();
	dataBuffer key = {
		我是敏感数据,不能泄漏 };
	dataBuffer default_head_info = {
		我是敏感数据,不能泄漏
	};
	dataBuffer default_data_key;
	if (argc >= 4){
		string code = argv[3];
		default_data_key.resize(head_datakey_size);
		for (int i = 0; i < head_datakey_size; i++){
			default_data_key[i] = code.at(i);
		}
	}

	bl->SetKey(&key[0], key.size());

	dataBuffer src_data, dest_data;
	getFileData(src_data, fileName);
	if (src_data.size() == 0){
		return -1;
	}

	unsigned int size = src_data.size();
	dest_data.resize(size);
	unsigned int len = 0;
	bool is_file_crypted = parseBFFileInfo(&src_data[0], size, &len);

	if (method == "e"){
		if (is_file_crypted){
			return 0;
		}

		unsigned int off_head_size = head_info_size + head_datakey_size;
		dataBuffer head(off_head_size, 0), head_encrypted(off_head_size, 0),data_key(head_datakey_size,0);
		if (default_data_key.size() == head_datakey_size){
			copy(default_head_info.begin(), default_head_info.end(), head.begin());
			copy(default_data_key.begin(), default_data_key.end(), data_key.begin());
			copy(data_key.begin(), data_key.end(), head.begin() + head_info_size);

			bl->Encrypt(&head_encrypted[0], &head[0], head.size());
			bl->SetKey(&data_key[0], data_key.size());
		}
		else
		{
			off_head_size = 0;
		}

		int s1 = dest_data.size();
		make_64bit_align(dest_data);
		bl->Encrypt(&dest_data[0], &src_data[0], dest_data.size(), s1);

		FILE* file = fopen(fileName.c_str(), "wb");
		if (!file)
		{
			return -1;
		}

		if (off_head_size == head_info_size + head_datakey_size){
			fwrite(&head_encrypted[0], sizeof(dataBuffer::value_type), head_encrypted.size(), file);
		}
		fwrite(&dest_data[0], sizeof(dataBuffer::value_type), dest_data.size(), file);
		fwrite(&size, sizeof(size), 1, file);
		fwrite(&c_bf_magic, sizeof(c_bf_magic), 1, file);
		fclose(file);
	}
	
	if (method == "d"){
		if (!is_file_crypted){
			return 0;
		}

		dataBuffer head_encrypted(src_data.begin(), src_data.begin() + head_info_size + head_datakey_size), head(head_info_size + head_datakey_size);
		bl->Decrypt(&head[0], &head_encrypted[0], head_info_size + head_datakey_size);
		dataBuffer head_info(head.begin(), head.begin() + head_info_size), data_key(head.begin() + head_info_size, head.begin() + head_info_size + head_datakey_size);
		if (head_info == default_head_info){
			bl->SetKey(&data_key[0], data_key.size());
			dest_data.resize(size - c_bf_info_size - head_info_size - head_datakey_size);
			bl->Decrypt(&dest_data[0], &src_data[0] + head_info_size + head_datakey_size, dest_data.size());
		}
		else{
			bl->Decrypt(&dest_data[0], &src_data[0], size - c_bf_info_size);
		}
		
		FILE* file = fopen(fileName.c_str(), "wb");
		if (!file)
		{
			return -1;
		}

		fwrite(&dest_data[0], sizeof(dataBuffer::value_type), len, file);
		fclose(file);
	}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值