标题: krkr2加解密插件编写方法
keakon
会员
Rank: 1
TomoFansClub会长


UID 153
精华 0
积分 273
帖子 180
阅读权限 5
注册 2007-4-8
 
发表于 2007-9-21 13:43  资料  短消息  加为好友 
krkr2加解密插件编写方法

一、
关于为什么要加密,以及加密的方法就不详述了。前者,每人都有自己的理由,比如保护自己的版权;后者请翻翻论坛的老帖。

插件的编写需要会用VC++6.0,能用C/C++写程序(并不需要会写WIN32程序);否则可以54该文了。以上。

二、
要加/解密XP3文件,还是先来研究下XP3文件的结构吧。(了解就行了,并不用理解)
以下部分摘自别人的资料:

QUOTE:
文件开头是文件标志,为"XP3"
偏移11处是文件信息表的位置,uint64
从上面的值指示跳到文件信息表处,有以下一个结构:
struct    sXP3Info
{
    byte_t    zlib; // 文件信息表是否用zlib压缩过
    uint64    psize; // 文件信息表在包文件中的大小
#if zlib
    uint64    rsize; // 文件信息表解压后的大小
#endif
    byte_t    fileInfo[psize]; // 文件信息表数据
};

成功获取文件信息表数据后可以得到以下一组结构的数组,用于描述包中文件的信息:
struct    sXP3File
{
    uint32    tag1; // 标志1,"File" 0x656c6946
    uint64    fileSize; // 文件信息数据大小

    uint32    tag2; // 标志2,"info" 0x6f666e69
    uint64    infoSize; // 文件基本数据大小
    uint32    protect; // 估计是表示此文件是否加过密
    uint64    rsize; // 文件原始大小
    uint64    psize; // 文件包中大小
    uint16    nameLen; // 文件名长度(指的是UTF-16字符个数)
    wchar_t fileName[nameLen]; // 文件名(UTF-16LE编码,无0结尾)

    uint32    tag3; // 标志3,"segm" 0x6d676573
    uint64    segmSize; // 文件段数据大小
    uint32    compress; // 文件是否用zlib压缩过
    uint64    offset; // 文件开始的位置
    uint64    rsize;
    uint64    psize;
#if fileSize - infoSize - segmSize - 24 > 0
    uint32    tag4; // 标志4,"adlr" 0x726c6461
    uint64    adlrSize; // 文件附加数据大小,一般是4
    uint32    key; // 附加数据,用于加密
#endif
};

这些数据显示,XP3文件会有个文件信息表,存储了其中的文件信息。
这些信息中,某些可以用于加/解密。

三、
Miliardo様已经在《关于加密插件的编写》(http://kcddp.keyfc.net/bbs/viewthread.php?tid=272)中翻译了一个例子,就从这开始编写加密插件吧。

运行VC++6.0,新建一个win32 dynamic-link library项目。
再新建一个C++ source file,文件名最好取为xp3enc.cpp(否则需把输出文件改名为xp3enc.dll),将《关于加密插件的编写》一文的第一段代码复制进去,保存。
再新建一个文本文件,把第2段代码复制进去,保存为xp3enc.def。
打开xp3enc.cpp,选择“build-build xp3enc.dll”,这样就应该生成好加密插件了。

用同样的方法新建个dll项目,将第3、4段代码分别保存成cpp和def文件。
然后下载吉里吉里外部C++接口库(http://kcddp.keyfc.net/bbs/viewthread.php?tid=273),解压后添加到该工程内。
最后build成dll文件,改后缀名为tpm文件(或选“project-settings-link”,把output file name改为tpm文件,当然也能改路径。)

再用上述2个文件测试下加密结果吧,方法就不说了,自己翻帖。
成功的话就可以继续了,否则我也没什么好说的了。

四、
下面开始分析这2个文件吧,先从加密开始。

对于我们来说,唯一要写的就是XP3ArchiveAttractFilter_v2这个函数,所以这里只介绍它。


函数声明就不说了,必须这么写。
注释已经很清楚了,加密时可以用到4个值:
hash是解密后的文件hash值,这个编写解密插件时也能获取,所以我们可以用它来加密。
buffer是该块的指针。加密时,1个文件可能被分成多个块,每个块对应一个buffer。
offset是该块的块头与文件头的偏移量。对于该块的第i个字节,它对于文件头的偏移量应为offset+i字节。
bufferlen是该块的长度,因为解密时可能块长不是一样的,所以一般不会用这个来加密(否则没法解密了)。

再研究这句吧:


然后是解密。也只研究1个函数:TVPXP3ArchiveExtractionFilter。


注释中也能看到,我们可以获取5个参数。
FileHash等于加密时用到的hash变量。
Buffer是解密时的块。据我分析,解密时应该是XP3内包含多个文件,每个文件分成多个块。
Offset是该块的块头与XP3中对应文件的文件头的偏移量。
BufferSize是该块大小,可能和加密时的bufferlen不同,所以一般不用。
SizeOfSelf是结构体的大小,用于检查的。

再分析下函数的主体:


补充下异或的常识吧:
a ^ b ^ b == a。

因此就完成解密了。

五、
下面开始做我们自己的加解密插件吧。
先补充下解密的常识。解密函数必须是加密函数的反函数,即对于数据data,加密后为code(data),解密后为encode(code(data)),其值应等于data。

反函数有很多,比如异或和异或,加和减,循环左移和循环右移等。但有些反函数可能会丢失数据,如乘和除,乘方和对数,正切和反正切,左移和右移,所以这些一般是不能用的。

另外反函数是可以组合的。比如f2'(f1'(f1(f2(data)))) == data。('用于表示反函数,因为没法写上标的-1)。也就是只要按相反的顺序解密就行了。

下面来试着做吧。
1.先来最简单的,所有的数都加1。

        for(int i = 0; i < bufferlen; i++) ((unsigned char*)buffer)[i] += 1;

相应的解密插件为

        for(tjs_uint i = 0; i < info->BufferSize; i++)
                ((unsigned char *)info->Buffer)[i] -= 1;

忘说了unsigned char类型的数据,值为[0, 255],处于2端时,0 - 1 == 255,255 + 1 == 0,所以这个是没问题的。

2.再改为与偏移量相加吧。

        for(int i = 0; i < bufferlen; i++) ((unsigned char*)buffer)[i] += (i + offset);

解密插件为

        for(tjs_uint i = 0; i < info->BufferSize; i++)
                ((unsigned char *)info->Buffer)[i] -= (i + info->Offset);

记住别忘了加offset,因为加解密时分块可能不一样。

3.接下来试试循环左/右移。


相应的加密插件,循环部分就不写了。

left = encode << (8 - (offset % 8));
right = encode >> (offset % 8);
encode = left | right;

当然,循环移位可以用汇编来实现,但我感觉汇编还没这段C代码快,所以就不给例子了。

4.然后再试试分段加密。

if (offset == 12)
{
        code ^= 34;
}
else if (offset == 56)
{
        code ^= 78;
}
else
{
        code ^= 90;
}

解密代码实际是一样的,所以不重复了。

5.接着来试试交换每个字节的第2和第8位。


解密时仍然是相同的代码,不重复了。也可以试着用汇编,我是懒得用了。

6.最后试试怎么用伪随机数加密吧。
先补充下常识。C/C++库中的随机函数是伪随机数,使用前要先设定种子。对于相同的种子,生成的随机数列是相同的。
所以我们只要给加密与解密相同的种子,就能生成相同的随机数列了。而这个种子自然可以直接选hash。
另外,别忘了文件可能很大,如果加密1个1G的文件,就得计算10亿次随机数了。我们当然不会这么做,其实只要一段随机数就足够了。
下面来看看实际的代码。


解密代码实际和加密非常相似,大家有兴趣自己试试吧。

六、
其实还有很多方法可以用,大家开动脑筋想想自己的算法吧,我只是提个思路而已。其实随意几个算法组合起来就已经够难破解了。
另外,解密时必须能够直接得到1个文件任意偏移量出的实际值。也就是说解密文件a的第100个字节时,不能依赖该文件其他字节的值,如第99个字节。
最后别忘了发布时设置为release模式,不然会带很多调试信息,使插件变大变慢,而且易破解。如果还想进一步保护的话,可以试试加壳,但千万别清除导出表(即def文件生成的信息),不然无法使用。

[ 本帖最后由 keakon 于 2007-9-21 13:56 编辑 ]





在我眼中,只要萌的都是loli。不管她有多老,是男的也好,是机器人也罢,就算没有实体,我也一定要萌上她!
智代after PS2汉化移植完毕
顶部
 



清除 Cookies - 联系我们 - [Key Fans Club] the Council of Doujin-game Development and Promotion - Archiver - WAP
Powered by Discuz! 5.5.0 © 2001-2006 Comsenz Inc.
Processed in 0.022785 second(s), 9 queries , Gzip enabled
粤ICP备05060595号
[ 当前模板 - 天高云淡 v 设计制作 - 七星论坛 v 请使用1024*768或以上分辨率浏览本模板 ]
请勿删除或修改此处版权图示