⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 common.cpp

📁 魔兽解压DBC的一些功能代码,专门用来分解魔兽客户端所使用的代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 *  common.c -- shared functions used by mpq-tools.
 *
 *  Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  $Id: common.c,v 1.12 2004/02/12 00:42:54 mbroemme Exp $
 */
#define _CRT_SECURE_NO_DEPRECATE
//#include <dirent.h>
#include <sys/stat.h>
//#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mpq.h"
#include "common.h"
#include <ctype.h>

/*
 *  This function decrypts a MPQ block.
 */
int libmpq_decrypt_block(mpq_archive *mpq_a, unsigned int *block, unsigned int length, unsigned int seed1) {
	unsigned int seed2 = 0xEEEEEEEE;
	unsigned int ch;

	/* Round to unsigned int's */
	length >>= 2;
	while (length-- > 0) {
		seed2    += mpq_a->buf[0x400 + (seed1 & 0xFF)];
		ch        = *block ^ (seed1 + seed2);
		seed1     = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
		seed2     = ch + seed2 + (seed2 << 5) + 3;
		*block++  = ch;
	}
	return LIBMPQ_TOOLS_SUCCESS;
}

/*
 *  This function decrypts the hashtable for the
 *  file informations.
 */
int libmpq_decrypt_hashtable(mpq_archive *mpq_a, unsigned char *pbKey) {
	unsigned int seed1 = 0x7FED7FED;
	unsigned int seed2 = 0xEEEEEEEE;
	unsigned int ch;			/* One key character */
	unsigned int *pdwTable = (unsigned int *)(mpq_a->hashtable);
	unsigned int length = mpq_a->header->hashtablesize * 4;

	/* Prepare seeds */
	while (*pbKey != 0) {
		ch = toupper(*pbKey++);
		seed1 = mpq_a->buf[0x300 + ch] ^ (seed1 + seed2);
		seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
	}

	/* Decrypt it */
	seed2 = 0xEEEEEEEE;
	while (length-- > 0) {
		seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
		ch     = *pdwTable ^ (seed1 + seed2);
		seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
		seed2  = ch + seed2 + (seed2 << 5) + 3;
		*pdwTable++ = ch;
	}
	return LIBMPQ_TOOLS_SUCCESS;
}

/*
 *  This function decrypts the blocktable.
 */
int libmpq_decrypt_blocktable(mpq_archive *mpq_a, unsigned char *pbKey) {
	unsigned int seed1 = 0x7FED7FED;
	unsigned int seed2 = 0xEEEEEEEE;
	unsigned int ch;			/* One key character */
	unsigned int *pdwTable = (unsigned int *)(mpq_a->blocktable);
	unsigned int length = mpq_a->header->blocktablesize * 4;

	/* Prepare seeds */
	while(*pbKey != 0) {
		ch = toupper(*pbKey++);
		seed1 = mpq_a->buf[0x300 + ch] ^ (seed1 + seed2);
		seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
	}         

	/* Decrypt it */
	seed2 = 0xEEEEEEEE;
	while(length-- > 0) {
		seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
		ch     = *pdwTable ^ (seed1 + seed2);
		seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
		seed2  = ch + seed2 + (seed2 << 5) + 3;
		*pdwTable++ = ch;
	}
	return LIBMPQ_TOOLS_SUCCESS;
}

int libmpq_read_listfile(mpq_archive *mpq_a, FILE *fp) {
	int mpq_size;
	int mpq_ht_size;
	int mpq_bt_size;
	int mpq_blocksize;
	int mpq_files;
	int mpq_csize;
	int mpq_fsize;
	int entries;
	char listdb_version[10];
	char libmpq_version[10];
	int listdb_temp_version = 0;
	int libmpq_temp_version = 0;

	/* first check header and version */
	if (libmpq_conf_get_value(fp, "LIBMPQ_VERSION", mpq_a->mpq_l->mpq_version, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_version))) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	} else {

		/* copy to temp buffer for removing . characters */
		sprintf(listdb_version, (char *)mpq_a->mpq_l->mpq_version);

		/* remove . characters from listfile version */
		libmpq_conf_delete_char(listdb_version, ".");

		/* get libmpq version */
		sprintf(libmpq_version, "%i%i%i",LIBMPQ_MAJOR_VERSION, LIBMPQ_MINOR_VERSION, LIBMPQ_PATCH_VERSION);

		/* convert to number */
		listdb_temp_version = atoi(listdb_version);
		libmpq_temp_version = atoi(libmpq_version);

		/* check if installed libmpq version is valid for listfile version */
		if ((libmpq_temp_version < listdb_temp_version) || (libmpq_temp_version == 0) || (listdb_temp_version == 0)) {
			return LIBMPQ_CONF_EFILE_VERSION;
		}
	}

	/* check listfile header, the following entries must be set */
	if (libmpq_conf_get_value(fp, "MPQ_SIZE", &mpq_size, LIBMPQ_CONF_TYPE_INT, 0)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_HASHTABLE_SIZE", &mpq_ht_size, LIBMPQ_CONF_TYPE_INT, 0)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_BLOCKTABLE_SIZE", &mpq_bt_size, LIBMPQ_CONF_TYPE_INT, 0)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_BLOCKSIZE", &mpq_blocksize, LIBMPQ_CONF_TYPE_INT, 0)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_FILES", &mpq_files, LIBMPQ_CONF_TYPE_INT, 0)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_COMPRESSED_SIZE", &mpq_csize, LIBMPQ_CONF_TYPE_INT, 0)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_UNCOMPRESSED_SIZE", &mpq_fsize, LIBMPQ_CONF_TYPE_INT, 0)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_NAME", mpq_a->mpq_l->mpq_name, LIBMPQ_CONF_TYPE_CHAR, PATH_MAX)) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}
	if (libmpq_conf_get_value(fp, "MPQ_TYPE", mpq_a->mpq_l->mpq_type, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_type))) {
		return LIBMPQ_CONF_EFILE_CORRUPT;
	}

	/* these are optional parameters, if they are empty we set the struct members empty */
	libmpq_conf_get_value(fp, "MPQ_GAME", mpq_a->mpq_l->mpq_game, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_game));
	libmpq_conf_get_value(fp, "MPQ_GAME_VERSION", mpq_a->mpq_l->mpq_game_version, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_game_version));

	/* check if we found a valid listfile for the given archive */
	if (mpq_a->header->hashtablesize == mpq_ht_size && mpq_a->header->blocktablesize == mpq_bt_size && mpq_a->blocksize == mpq_blocksize && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_ARCHIVE_SIZE) == mpq_size && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) == mpq_files && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_COMPRESSED_SIZE) == mpq_csize && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_UNCOMPRESSED_SIZE) == mpq_fsize) {

		/* check if the filelist is correct */
		if (!libmpq_conf_get_array(fp, "FILE_NAMES", (char ***)&mpq_a->mpq_l->mpq_files, &entries)) {

			/* we have a corrupt filelist, so return */
			return LIBMPQ_CONF_EFILE_LIST_CORRUPT;
		} else {

			/* now check if filelist entries matches number of files in the archive. */
			if (entries != libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES)) {
				libmpq_free_listfile((char **)mpq_a->mpq_l->mpq_files);
				mpq_a->mpq_l->mpq_files = NULL;
				return LIBMPQ_CONF_EFILE_LIST_CORRUPT;
			}
		}
	}

	return LIBMPQ_TOOLS_SUCCESS;
}

/*
 *  This function frees up the space reserved by libmpq_get_listfile()
 */
int libmpq_free_listfile(char **filelist) {
	int i = 0;
	while (filelist[i]) {
		free(filelist[i++]);
	}
	free(filelist);

	return LIBMPQ_TOOLS_SUCCESS;
}

/*
 *  This function reads the directory and the subdirectories
 *  of the listfile database and adds a entry to the lisfile
 *  array.
 */
/*int libmpq_detect_listfile_rec(char path[PATH_MAX], char ***filelist, int *fl_count, int *fl_size) {
	char nextpath[PATH_MAX];
	DIR *dp = opendir(path);
	FILE *fp;
	struct dirent *entry;
	struct stat statbuf;
	char buf[LIBMPQ_CONF_BUFSIZE];

	if (dp == NULL) {
		return LIBMPQ_CONF_EOPEN_DIR;
	} else {
		while ((entry = readdir(dp)) != NULL) {
			if (strncmp(entry->d_name, ".", 1) == 0 || strncmp(entry->d_name, "..", 2) == 0) {
				continue;
			}
			if (strnlen(path, PATH_MAX) + strnlen(entry->d_name, PATH_MAX) + 2 > sizeof nextpath) {
				continue;
			}

			snprintf(nextpath, PATH_MAX, "%s/%s", path, entry->d_name);

			// check if file extension matches listdb file extension
			if (strncmp(&entry->d_name[strlen(entry->d_name) - strlen(LIBMPQ_CONF_EXT)], LIBMPQ_CONF_EXT, strlen(LIBMPQ_CONF_EXT)) == 0) {

				// check if it is really a listdb file
				if ((fp = fopen(nextpath, "r")) != NULL ) {
					while (fgets(buf, LIBMPQ_CONF_BUFSIZE, fp) != NULL) {
						char *line;

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

						// skip whitespace
						for (line = buf; isspace(*line); line++) {
							continue;
						}

						// skip empty line
						if (line[0] == '\0') {
							continue;
						}

						// skip comments
						if (line[0] == '#') {
							continue;
						}

						//search for listdb header; dirty but works :)
						if (!strncasecmp(line, LIBMPQ_CONF_HEADER, strlen(LIBMPQ_CONF_HEADER))) {

							// set the next filelist entry to a copy of the file path
							(*filelist)[(*fl_count)++] = strdup(nextpath);

							// increase the array size
							if ((*fl_count) == (*fl_size)) {
								(*filelist) = realloc((*filelist), ((*fl_size) + LIBMPQ_CONF_FL_INCREMENT) * sizeof(char *));
								(*fl_size) += LIBMPQ_CONF_FL_INCREMENT;
							}

							// header found so we could stop reading the file.
							break;
						}
					}
					fclose(fp);
				}
			}

			if (stat(nextpath, &statbuf) < 0) {
				continue;
			}

			// if entry ia a subdirectory, read it
			if (S_ISDIR(statbuf.st_mode)) {
				libmpq_detect_listfile_rec(nextpath, filelist, fl_count, fl_size);
			}
		}
		closedir(dp);
	}

	return LIBMPQ_TOOLS_SUCCESS;
}
*/

/*
 *  This functions tries to get file decryption key. The trick comes from block
 *  positions which are stored at the begin of each compressed file. We know the
 *  file size, that means we know number of blocks that means we know the first
 *  int value in block position. And if we know encrypted and decrypted value,
 *  we can find the decryption key.
 */
int libmpq_detect_fileseed(mpq_archive *mpq_a, unsigned int *block, unsigned int decrypted) {
	unsigned int saveseed1;
	unsigned int temp = *block ^ decrypted;		/* temp = seed1 + seed2 */
	int i = 0;
	temp -= 0xEEEEEEEE;				/* temp = seed1 + mpq_a->buf[0x400 + (seed1 & 0xFF)] */

	for (i = 0; i < 0x100; i++) {			/* Try all 255 possibilities */
		unsigned int seed1;
		unsigned int seed2 = 0xEEEEEEEE;
		unsigned int ch;

		/* Try the first unsigned int's (We exactly know the value) */
		seed1  = temp - mpq_a->buf[0x400 + i];
		seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
		ch     = block[0] ^ (seed1 + seed2);

		if (ch != decrypted) {
			continue;
		}

		/* Add 1 because we are decrypting block positions */
		saveseed1 = seed1 + 1;

		/*
		 *  If OK, continue and test the second value. We don't know exactly the value,
		 *  but we know that the second one has lower 16 bits set to zero
		 *  (no compressed block is larger than 0xFFFF bytes)
		 */
		seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
		seed2  = ch + seed2 + (seed2 << 5) + 3;
		seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
		ch     = block[1] ^ (seed1 + seed2);
		if ((ch & 0xFFFF0000) == 0) {
			return saveseed1;
		}
	}
	return LIBMPQ_TOOLS_SUCCESS;
}

/*
 *  This function initialize the decryption buffer
 */
int libmpq_init_buffer(mpq_archive *mpq_a) {
	unsigned int seed   = 0x00100001;
	unsigned int index1 = 0;
	unsigned int index2 = 0;
	int i;

	memset(mpq_a->buf, 0, sizeof(mpq_a->buf));

	/* Initialize the decryption buffer. */
	for (index1 = 0; index1 < 0x100; index1++) {
		for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100) {
			unsigned int temp1, temp2;
			seed  = (seed * 125 + 3) % 0x2AAAAB;
			temp1 = (seed & 0xFFFF) << 0x10;

			seed  = (seed * 125 + 3) % 0x2AAAAB;
			temp2 = (seed & 0xFFFF);

			mpq_a->buf[index2] = (temp1 | temp2);
		}
	}
	return LIBMPQ_TOOLS_SUCCESS;
}

/*
 *  This functions fills the mpq_hash structure with the
 *  hashtable found in the MPQ file. The hashtable will
 *  be decrypted for later use.
 */
int libmpq_read_hashtable(mpq_archive *mpq_a) {
	unsigned int bytes = 0;
	int rb = 0;

	/*
	 *  Allocate memory. Note that the block table should be as large as the
	 *  hash table. (for later file additions)
	 */
	mpq_a->hashtable = (mpq_hash *)malloc(sizeof(mpq_hash) * mpq_a->header->hashtablesize);

	if (!mpq_a->hashtable) {
		return LIBMPQ_EALLOCMEM;
	}

	/* Read the hash table into the buffer */
	bytes = mpq_a->header->hashtablesize * sizeof(mpq_hash);

	#ifdef WIN32
		_lseeki64(mpq_a->fd, mpq_a->header->hashtablepos, SEEK_SET);
	#else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -