搜索
收藏本站 玩家讨论交流 联机必备 繁体切换 开启辅助访问
发新帖 回复
发新帖

MPQ新的地图加密方法,kill-mpqMaster

时间:2016-8-29 20:07 0 1203 | 复制链接 |
最近研究MPQ.
...
需要引用的内容是一些前辈通过技术,逆向工程,反汇编技术等等方法所获得的,由于某种非人力不可抗拒因素,这里不能列出他们的名字,抱歉!
...
MPQ文件是一种压缩包(pack)格式,它可以单独存在如*.mpq,也可以寄存在其他文件中如*.w3m,*.w3x
它有一个标准的32byte的header:
  • struct TMPQHeader
  • {
  •     DWORD dwMpqFlag;
  •     DWORD dwHeaderSize;
  •     DWORD dwArchiveSize;
  •     USHORT wFormatVersion;
  •     USHORT wBlockSize;
  •     DWORD dwHashTablePos;
  •     DWORD dwBlockTablePos;
  •     DWORD dwHashTableSize;
  •     DWORD dwBlockTableSize;
  • };

[color=rgb(51, 102, 153) !important]复制代码




其中dwMqpFlag是一个常量,它的值为'MPQ',用来定位MPQ在寄主文件中的文件头位置。这个地址将作为MPQ包的基地址。
MPQ使用HashTable-BlockTable来定位一个文件在MPQ包中的位置,当然它们是经过确定密钥加密后放如MPQ包中的,以逃脱明文存放的危险。
在MPQ中的加密算法分两种:
1),摘要加密:把不定长度数据转化为定长的数据,hash算法得到一个DWORD
2),对称加密:把不定长度数据按DWORD转换为同样长度的数据。
上面两种加密在MPQ中会用到密钥,以确保Hash算法的更不可预料性和对称加密的密钥。
MPQ使用的密钥有5组,每组密钥(长0x100个DWORD)被全部用于某次加密。密钥是确定的,是可以在加密之前计算出来并且保持不变的常量。计算方法相当有规律:
  • DWORD cryptTable[0x500]
  • void prepareCryptTable()
  • {
  •     DWORD dwHih, dwLow,seed = 0x00100001,index1 = 0,index2 = 0, i;
  •     for(index1 = 0; index1 < 0x100; index1++)
  •     {
  •         for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
  •         {
  •             seed = (seed * 125 + 3) % 0x2AAAAB;
  •             dwHih= (seed & 0xFFFF) << 0x10;
  •             seed = (seed * 125 + 3) % 0x2AAAAB;
  •             dwLow= (seed & 0xFFFF);
  •             cryptTable[index2] = (dwHih| dwLow);
  •         }
  •     }
  • }

[color=rgb(51, 102, 153) !important]复制代码




然后就可以使用MPQ中的加密函数了。
  • DWORD HashString(char *lpszFileName,DWORD dwCryptIndex)
  • {
  •     unsigned char *key = (unsigned char *)lpszFileName;
  •     DWORD seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
  •     int ch;
  •     while(*key != 0)
  •     {
  •         ch = toupper(*key++);
  •         seed1 = cryptTable[(dwCryptIndex<< 8) + ch] ^ (seed1 + seed2);
  •         seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
  •     }
  •     return seed1;
  • }

[color=rgb(51, 102, 153) !important]复制代码




这个Hash函数被用来Hash一个filename根据密钥0,密钥1,密钥2获得三个Hash:Hash,Hash1,Hash2.
其中Hash被用来在HashTable中定位。Hash%HashTableSize就是索引。
  • struct TMPQHash
  • {
  •     DWORD dwHash1;
  •     DWORD dwHash2;
  •     USHORT lcLocale;
  •     USHORT wPlatform;
  •     DWORD dwBlockIndex;//0xFFFFFFFEh,0xFFFFFFFFh表示该HashItem无效.
  • };

[color=rgb(51, 102, 153) !important]复制代码




当然很可能几个不同的filename对应到了一个索引,这时就依靠Hash1,Hash2来校验。
只要找到Hash1和Hash2都符合的HashItem就读取BlockIndex并进入BlockTable,否则校验下一个HashItem。由此可见MPQ的设计比较科学!如果检查一个MPQ中不存在的filename是否在MPQ包中,花费的时间是相当可观的,将会查询完整个HashTable。
  • struct TMPQBlock
  • {
  •     DWORD dwFilePos;
  •     DWORD dwCSize;
  •     DWORD dwFSize;
  •     DWORD dwFlags;
  • };

[color=rgb(51, 102, 153) !important]复制代码




只在BlockTable中才纪录了有用的信息。把BlockTable和HashTable分离开,这充分体现了MPQ设计的科学性:如果把任何一个BlockItem中的属性放到HashTable中都会降低MPQ的安全性。
到这儿整个文件的定位工作就完了,下面仅仅需要根据Flags来分析文件采用的存储方式:
默认密钥加密,种子带文件长度和文件名修正的加密;
PKware压缩,Wave压缩,多方式压缩,不压缩。
...


下面进入正题


通过上面的简单引用的资料,我们不难发现MPQ设计所贯彻的根本特性:
1,拥有MPQ文件是不能得知MPQ中存在哪些文件的。内部listfile是不可靠的。
2,只有知道文件名(包括路径)才能够访问MPQ中的文件。其他任何方法都不可靠。

我们看一下地图的加密史:(顺序没有严格按照时间先后组合)
1,没有加密,直接发布WE生成的map。这时候出现了免CD的WE。
2,使用工具删除WE专用数据,使WE无法打开map。但是这时候出现了w3mMaster。
3,删除listfile,导入外部文件。这时候出现了winMPQ,MPQworkshop。
4,如将MPQheader中的headerSize修改使其不等于20,就能阻止一些MPQ处理程序,因为这些处理程序通过'MPQ'和headerSize==20来定位MPQheader。
5,移动war3map.j的位置到Script/下,优化j文件。这时候出现了jassShopPro。
6,使用slk技术消解w3u之类文件。这时候大家借助论坛知道了slk可以用Excel2000打开。
7,就是今天我要介绍的加密方法了。
...




说了这么久到底今天要介绍的加密方法是怎么样的呢?
请大家鲜花献上!鼓起掌声...



通过上面的简单引用的资料,我们不难发现MPQ设计所贯彻的根本特性:
1,拥有MPQ文件是不能得知MPQ中存在哪些文件的。内部listfile是不可靠的。
2,只有知道文件名(包括路径)才能够访问MPQ中的文件。其他任何方法都不可靠。

目前的破+解工具:
w3mMaster对付使用slk技术的地图和自身原因(作者不再更新)力不从心。
能开加密地图的WE(最早由某war3业余爱好者用汇编修改WE而成,本人亲自见证),事实上在刚出来的时候很管用,后来出现的大多数加密地图仍然无法打开,出现数据错误,内存不足等。
mpqMaster类统称MPQ处理程序:MPQ破+解得之完美以至于目前该类工具是最有效的工具。
...
而本人今天要介绍的方法就是能够对付mpqMaster类的加密方法。
...


说了这么久到底今天要介绍的加密方法是怎么样的呢?
请大家鲜花献上!鼓起掌声...



其实是运用了MPQ自身设计上的一个小特性,一个MPQ处理程序的作者都简单应付而忽略的小特性:
她就是:
不能通过MPQ包得知MPQ包中存储的文件的个数!!!
几乎所有目前的MPQ处理程序都强制性的具备的功能:枚举MPQ包中文件。
它们通过简单的判断blockTalbe大小和一些有效性判断来分析一个MPQ包中存在的文件个数。
但是虽然对于标准的MPQ生成程序生成的MPQ包管用,却无法处理非标准的MPQ包。
能够让war3读取而不能使用MPQ处理程序打开的例子不是有一个吗?!
另外一个由于MPQ设计上而使MPQ处理程序所具备的特性:
如果HashTable大小确定了,那么MPQ包最大容纳文件个数也就确定了
综合上面两个特性不难得出今天本人要介绍的方法:


...请大家鲜花献上!鼓起掌声...


修改MPQheader中blockTableSize(位址在0x0000021C,DWORD)使其大于HashTableSize。
这只是一个简单的修改,但是她确实能kill掉mpqMaster,本人已经测试过了。该方法处理过的地图war3能够正确读图并进行游戏,但是mpqMaster无法打开。估计其他MPQ处理程序也如此。
不过只是一个简单的修改破+解者也可能手动把该数据改回来。
我们需要一个工具真正的对HashTable-blockTalbe进行处理。(我正在开发这个工具。)
我们把实际存储的blockTable的大小也改到比HashTable还要大,并且把hashTable-blockTable在保证关联的情况下打乱一下顺序,使通过手工修改blockTableSize的方法失效,而war3依然能够识别。因为war3只读取它想要读取的文件。
另外为了防止新的破+解工具,我们还可以把一些失效的hashItem,blockItem变成有效。
还可以加大hashTableSize让万能listfile打开MPQ变得龟速。
上面就简单的介绍了一下新的加密方法,当然能加密就能破+解!
我们可以设计专门破+解war3map的工具
仿war3的处理方式来处理map,依次读取map中的基本文件。
再从这些基本文件中分析出其他文件的filename。
最关键的还是使用相应的修改器来修改这些file。
然后把修改过的东西连同map中有用的file即读取出的file压成一个map。
当然这个工具对于会编程并且拥有MPQ“绝密”资料的人来说易如反掌!不过我相信拥有那样技术的人是拥有那样的觉悟不会去开发那样的程序来破+解那样的加密地图的。
不过总有那么些垃圾存在,我就是其中之一,我准备在加密工具完成后再在工具上集成解密功能。
不过希望在那之前得到bj签名的算法。以方便保护一个拥有作者的劳动果实的地图。
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

快速回复 返回列表 返回顶部