随笔 - 97, 文章 - 22, 评论 - 81, 引用 - 0
数据加载中……

Pygame游戏开发 之五

Pygame游戏开发之五

小试牛刀

大部分游戏都会对图像文件进行加密,这样你就很难看到它的图片信息,游戏就更加添加了神秘感。有加密自然有解密,所谓山外青山楼外楼,再高的加密手段都可以被破解,加密只是提高技术门槛,让一部分人看不到你的图片资源。

在进行加密之前,让我们首先把文件的结构组织一下,用文件夹来管理各类文件。

root/

       dat/

              Animation/

              Background/

              Control/

              Monster/

              Player/

       img/

              Animation/

              Background/

              Control/

              Monster/

              Player/

       snd/

       src/

              Tools/

其中root表示游戏的根目录,imgdat分别表示加密前和加密后的图片文件的目录,其下有相同的目录结构,snd用于存放声音文件,src存放的是后缀是.py.pyc等的python源文件。并且我们将加密的程序放在Tools目录下。

       首先我们要大致了解加密的过程,所谓加密就是先将数据以二进制的形式从文件中读进来,然后采用适当的加密算法将数据变成另外一种形式的数据,再存到文件中,这样原本的文件格式就被当前数据替换掉了。这里我们是对img中所有的后缀为png的文件加密,然后存到dat文件中,因为要对大批量文件进行处理,最好的方法是采用批处理。

       我们在Tools文件夹下建立一个Process.bat的批处理文件,并且对其进行编辑,写下以下命令:

1     cd ../../img/

2     dir /s /b *.png > ../src/Tools/FileName.txt

3     cd ..

4     xcopy /s /t img dat

5     cd src/Tools/

6     encode.exe FileName.txt img dat

命令cd后跟一个目录表示改变当前目录,如果跟的是“..”则表示跳到当前目录的父目录下,例如第1句表示从Tools/目录连跳两层到root下并且进入img目录中,然后我们利用第2条命令将所有需要加密的文件的文件名输出到Tools目录下的FileName.txt文件中。

dir *.png > file 表示将当前文件下所有后缀为png的文件的文件信息输出到file文件中。但是它包含文件信息不止文件名,所以可以采用/b开关,表示采用空格式(Blank,没有标题信息或摘要),并且要求当前目录以及子目录的png文件都要输出,只要添加/s开关即可。

然后我们回到root文件夹下,将img下的子文件夹全部复制到dat文件夹下,但是不复制文件,可以采用xcopy命令来实现。

最后调用encode.exeFileName.txt文件中列出的文件加密后输出到dat文件夹下。encode.exe是我自己写的一个加密的小程序,这里为了方便我用C语言来实现。

       代码如下:

#include <string>

#include 
<vector>

using namespace std;

 

#define key 367

FILE 
*fpSourceFile;

FILE 
*fpReadFile, *fpWriteFile;

char szReadFileName[ MAX_PATH ];

vector 
<char> vec;

 

string Replace(string Src, string from, string to) {

       
string Tmp;

       
string::size_type nCount = Src.find(from);

       
if(nCount != string::npos) {

              Tmp 
= Src.substr(0, nCount);

              Tmp 
= Tmp + to + "\\" + Src.substr(nCount + from.size() + 1);

              nCount 
= Tmp.find(".");

              
if(nCount != string::npos)

                     Tmp 
= Tmp.substr(0, nCount+1);

              
return Tmp + "zty";

       }


       
return "";

}


 

int main(int argc, char* argv[]) {

       
int i;

       
if(argc == 4{

              fpSourceFile 
= fopen(argv[1], "rt");

              
while(fgets(szReadFileName, MAX_PATH, fpSourceFile)) {

                     szReadFileName[ strlen(szReadFileName) 
- 1 ] = '\0';

                     fpReadFile 
= fopen(szReadFileName, "rb");

                     
if(fpReadFile) {

                            fseek(fpReadFile, 
0, SEEK_END);

                            
long nFileSize = ftell(fpReadFile);

                            fseek(fpReadFile, 
0, SEEK_SET);

                            vec.resize(nFileSize);

                            fread((
void *)&vec[0], nFileSize, 1, fpReadFile);

                            
for(i = 0; i < vec.size(); i++{

                                   vec[i] 
= (vec[i] ^ key);

                            }


                            fclose(fpReadFile);

                            
string outFile = Replace(string(szReadFileName), string(argv[2]), string(argv[3]));

                            fpWriteFile 
= fopen(outFile.c_str(), "wb");

                            fwrite((
void *)&vec[0], nFileSize, 1, fpWriteFile);

                            fclose(fpWriteFile);

                     }


              }


              fclose(fpSourceFile);

       }
else {

              printf(
"请运行Process.bat文件\n");

       }


       
return 0;
}


       起初,读入的数据是存到vec这个向量中的,然后我们通过遍历vec的每一个字节对数据进行加密,加密的方法很多,这里采用最简单的异或(二进制位相同为0,不同为1)方式,这样解密也比较简单。来看一个例子:

       对于102(二进制表示为1100110),我们将它和给定的key(十进制367、二进制表示为101101111)值进行异或,如下:

       001100110 102

101101111 367

—————

       100001001 265

原本的数据102就转化成了和原先看似无关的数据265,如此一来,将所有的数据加密完毕后,原本的图像文件的文件头信息也被毁了,根本无法用常用的图像工具打开。加密的目的就达到了。当然如果加密完后连你自己也不知道怎么解密,那么这件事情就没意义了…-_-|||,所以我们还要对加密好数据进行解密,当然这要在程序中控制。

       这个只需将原先的load_image函数进行一个修改即可。

def load_image(file) :

       do_load()

       return Surface

 

       do_load()函数首先要用二进制方式读取file文件,并且通过read()接口得到文件中所有的二进制数据,通过tell()接口得到文件的大小。

       然后利用以下的循环就可以将数据进行解密了。

    i = 0

    data = []

    while i < filesize :

        data.append( chr( (ord(filedata[i]) ^ key) % 256 ) )

        i += 1

data = ''.join(data)

在这里因为用的是异或操作,所以解密和加密的过程是一样的,因为异或满足结合律,一个数异或上它本身等于0,任何数异或0等于它本身。于是可以这样想,某个数据异或了key(加密的过程),再异或一次key(解密的过程),就好比:Num^key^key = Num^(key^key) = Num^0=Num这样原先的数据就恢复了。

因为python中没有字符的概念,我们可以通过ord(‘x’) 得到’x’ASCII码,进行解密操作后,再用chr(num)得到num的字符形式,最后将所有的字符数据通过join接口连接到一起变成数据流,然后通过write接口将它暂存到buf.png文件中,再调用pygame.image.load('buf.png')将它读入,就得到了file对应的Surface。(未完待续)

posted on 2011-05-01 16:40 英雄哪里出来 阅读(3913) 评论(0)  编辑 收藏 引用 所属分类: Pygame


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理