Entpacker Von Datein Source Code Frage



  • Hey Leute habe den Source Code Eines entpackers von .epk / .eix datein das sind datein aus den game Metin2 Könnte mit vielleicht wer Helfen Das es die datein auch wieder packt also z.b

    Ich entpacke die datei abc.epk und eix und er erstellt eine z.b .xml datei mit den inhalt der datein so das ich anhand der xml datei die daten wieder Packen kann

    Hier mal der Source Code

    /*
    	Metin2FileExtractor
    	pushedx
    	edxLabs
    
    	This program serves as a file extractor for the Metin2 data files. The
    	EIX files are the header files and the EPK files are the data files.
    	The data can be uncompressed, encrypted, and/or compressed. This code
    	shows how the client performs the logic.
    
    	This was a "for fun" project and done in about ~12 hours of work. I am
    	releasing this tool and the source code to the elitepvperss' Metin2 
    	community to help spread new knowledge. I have no immediate plans for 
    	a file editor at this time as I'm not playing the game or doing
    	anything with it. Maybe sometime later though.
    
    	I hope you enjoy!
    */
    
    #define _CRT_SECURE_NO_WARNINGS
    #include <windows.h>
    #include <stdio.h>
    #include <string>
    #include <vector>
    #include <sstream>
    
    //--------------------------------------------------------------------------
    
    // Dumps a complete archive
    bool DumpArchive(const char * inFolder, const char * name);
    
    //--------------------------------------------------------------------------
    
    int main(int argc, char * argv[])
    {
    	system("cls");
    	printf("Welcome to the Metin2 File Extractor!\n");
    	printf("This program was made by pushedx for the elitepvpers' Metin2 community.\n");
    	printf("This is a free tool for all to use.\n");
    	printf("It should work on the US/DE version files but Korea is not tested.\n");
    	printf("Enjoy :)\n\n");
    	if(argc != 3)
    	{
    		printf("Usage: Metin2FileExtractor <Path to PAK folder> <Archive title>\n");
    		printf("Examples:\n");
    		printf("\tMetin2FileExtractor \"C:\\Program Files\\Subagames\\Metin2\\pack\" BGM\n");
    		printf("\tMetin2FileExtractor \"C:\\Program Files\\Subagames\\Metin2\\pack\" PC\n");
    		printf("\tMetin2FileExtractor \"C:\\Program Files\\Metin2_Germany\\pack\" ETC\n");
    		printf("\tMetin2FileExtractor \"C:\\Program Files\\Metin2_Germany\\pack\" root\n");
    		system("pause");
    		return -1;
    	}
    	std::string safecheck = argv[2];
    	if(safecheck.find_first_of("!@#$%^&*()+={}[]|\\:\";\'<>?,./") != std::string::npos)
    	{
    		printf("Error: The Archive title (%s) contains invalid characters. The program will now exit.\n", argv[2]);
    		return -1;
    	}
    	printf("Beginning the archive dump. Please be patient while it finishes.\n\n");
    	bool result = DumpArchive(argv[1], argv[2]);
    	if(result == true)
    	{
    		printf("The archive dump was successful!\n");
    	}
    	else
    	{
    		printf("The archive dump was not successful.\n");
    	}
    	printf("Thank you for using the Metin2 File Extractor!\n");
    	system("pause");
    	return 0;
    }
    
    //--------------------------------------------------------------------------
    
    // The expected magic header value
    #define LZ_KEY 0x5A4F434D
    
    //--------------------------------------------------------------------------
    
    struct TEntry1
    {
    	DWORD index;
    	char filename[160];
    	DWORD dw1;
    	DWORD dw2;
    	DWORD dw3;
    	DWORD dwSrcSize;
    	DWORD unpackedCRC;
    	DWORD dwFileOffset;
    	BYTE packedType;
    	BYTE b2;
    	BYTE b3;
    	BYTE b4;
    };
    
    struct TEntry2
    {
    	DWORD header;
    	DWORD decryptedBlockSize;
    	DWORD compressedBlockSize;
    	DWORD decompressedBlockSize;
    };
    
    struct TEntry3
    {
    	DWORD header;
    	DWORD version;
    	DWORD fileCount;
    };
    
    //--------------------------------------------------------------------------
    
    // For decompressing (ripped from client)
    BYTE gLZOData[] = 
    {
    	0xB9, 0x9E, 0xB0, 0x02, 0x6F, 0x69, 0x81, 0x05, 
    	0x63, 0x98, 0x9B, 0x28, 0x79, 0x18, 0x1A, 0x00, 
    };
    
    // For decrypting (ripped from client)
    BYTE gLZOData2[] = 
    {
    	0x22, 0xB8, 0xB4, 0x04, 0x64, 0xB2, 0x6E, 0x1F, 
    	0xAE, 0xEA, 0x18, 0x00, 0xA6, 0xF6, 0xFB, 0x1C, 
    };
    
    //--------------------------------------------------------------------------
    
    // Utility decompress function
    __declspec(naked) void ASM_LZO_FUNC1()
    {
    	__asm
    	{
    		MOV EDX, DWORD PTR SS:[ESP + 0x08]
    		MOV ECX, DWORD PTR SS:[ESP + 0x04]
    		PUSH EBX
    		PUSH EBP
    		PUSH ESI
    		MOV ESI, DWORD PTR SS:[ESP + 0x18]
    		PUSH EDI
    		MOV EAX, 0xC6EF3720
    		MOV EDI, 0x20
    		LEA EBX, DWORD PTR DS:[EBX]
    LABEL1:
    		MOV EBX, EDX
    		SHR EBX, 0x5
    		MOV EBP, EDX
    		SHL EBP, 0x4
    		XOR EBX, EBP
    		MOV EBP, EAX
    		SHR EBP, 0x0B
    		AND EBP, 0x03
    		MOV EBP, DWORD PTR DS:[ESI + EBP * 0x04]
    		ADD EBP, EAX
    		ADD EBX, EDX
    		XOR EBX, EBP
    		SUB ECX, EBX
    		MOV EBX, ECX
    		SHR EBX, 0x05
    		MOV EBP, ECX
    		SHL EBP, 0x04
    		XOR EBX, EBP
    		ADD EAX, 0x61C88647
    		MOV EBP, EAX
    		AND EBP, 0x03
    		MOV EBP, DWORD PTR DS:[ESI + EBP * 0x04]
    		ADD EBX, ECX
    		ADD EBP, EAX
    		XOR EBX, EBP
    		SUB EDX, EBX
    		DEC EDI
    	JNZ LABEL1
    		MOV EAX, DWORD PTR SS:[ESP + 0x20]
    		POP EDI
    		POP ESI
    		POP EBP
    		MOV DWORD PTR DS:[EAX], EDX
    		MOV DWORD PTR DS:[EAX + 0x04], ECX
    		POP EBX
    		RETN
    	}
    }
    
    //--------------------------------------------------------------------------
    
    // Decompress function in the client
    __declspec(naked) void ASM_LZO_CHECKKEY()
    {
    	__asm
    	{
    		MOV EAX,DWORD PTR SS:[ESP + 0x10]
    		MOV ECX, EAX
    		AND ECX, 0x80000007
    	JNG LABEL1
    		DEC ECX
    		OR ECX, 0xFFFFFFF8
    		INC ECX
    LABEL1:
    	JE LABEL2
    		SUB EAX, ECX
    		ADD EAX, 8
    		MOV DWORD PTR SS:[ESP + 0x10],EAX
    	JMP LABEL3;
    LABEL2:
    		MOV DWORD PTR SS:[ESP + 0x10],EAX
    LABEL3:
    		PUSH EBX
    		MOV EBX, EAX
    		SAR EBX, 0x03
    		TEST EBX, EBX
    	JLE LABEL5
    
    		PUSH EBP
    		//MOV EBP, lzoData
    		MOV EBP, [ESP + 0x14]
    
    		PUSH ESI
    		//MOV ESI, inData
    		MOV ESI, [ESP + 0x14]
    
    		PUSH EDI
    		//MOV EDI, outBuffer
    		MOV EDI, [ESP + 0x14]
    LABEL4:
    		MOV EAX,DWORD PTR DS:[ESI]
    		MOV ECX,[ESI + 0x04]
    		PUSH EDI
    		PUSH EBP
    		PUSH EAX
    		PUSH ECX
    	CALL ASM_LZO_FUNC1
    		ADD ESP, 0x10
    		ADD EDI, 0x08
    		ADD ESI, 0x08
    		DEC EBX
    	JNZ LABEL4
    		MOV EAX,DWORD PTR SS:[ESP + 0x20]
    		POP EDI
    		POP ESI
    		POP EBP
    LABEL5:
    		POP EBX
    		RET
    	}
    }
    
    //--------------------------------------------------------------------------
    
    // Wrapper function to decompress data
    int LZObject_CheckKey(LPBYTE outBuffer, LPBYTE inData, LPBYTE lzoData, DWORD dwSize)
    {
    	int result = 1;
    	__asm
    	{
    		mov edx, dwSize
    
    		mov ecx, inData
    		sub ecx, 4
    
    		mov eax, lzoData
    
    		mov edi, outBuffer
    
    		push edx
    		push eax
    		push ecx
    		push edi
    
    		call ASM_LZO_CHECKKEY
    
    		MOV EDX, DWORD PTR DS:[EDI]
    		MOV EAX, LZ_KEY
    		ADD ESP, 0x10
    		CMP EDX, EAX
    		JE LABEL1
    		mov result, 0
    LABEL1:
    		NOP
    	}
    	return result;
    }
    
    //--------------------------------------------------------------------------
    
    // Ripped from the client via OllyDbg. It was tedious, but simple work since
    // you can set labels in OllyDbg for the new jump locations.
    __declspec(naked) void ASM_LZO_DECOMPRESS()
    {
    	__asm
    	{
    		MOV EAX,DWORD PTR SS:[ESP+0x08]
    		PUSH EBX
    		MOV EBX,DWORD PTR SS:[ESP+0x14]
    		PUSH EBP
    		PUSH ESI
    		MOV ESI,DWORD PTR SS:[ESP+0x10]
    		MOV DWORD PTR DS:[EBX],0x00
    		PUSH EDI
    		MOV CL,BYTE PTR DS:[ESI]
    		LEA EBP,DWORD PTR DS:[ESI+EAX]
    		MOV EAX,DWORD PTR SS:[ESP+0x1C]
    		CMP CL,0x11
    	JBE label1
    		AND ECX,0xFF
    		SUB ECX,0x11
    		INC ESI
    		CMP ECX,0x04
    	JB label2
    label3:
    		MOV DL,BYTE PTR DS:[ESI]
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    		INC ESI
    		DEC ECX
    	JNZ label3
    	JMP label4
    label1:
    		XOR ECX,ECX
    		MOV CL,BYTE PTR DS:[ESI]
    		INC ESI
    		CMP ECX,0x10
    	JNB label5
    		TEST ECX,ECX
    	JNZ label6
    		CMP BYTE PTR DS:[ESI],0x00
    	JNZ label7
    label8:
    		MOV DL,BYTE PTR DS:[ESI+0x01]
    		ADD ECX,0xFF
    		INC ESI
    		TEST DL,DL
    	JE label8
    label7:
    		XOR EDX,EDX
    		MOV DL,BYTE PTR DS:[ESI]
    		INC ESI
    		LEA ECX,DWORD PTR DS:[ECX+EDX+0x0F]
    label6:
    		MOV EDX,DWORD PTR DS:[ESI]
    		ADD ESI,0x04
    		MOV DWORD PTR DS:[EAX],EDX
    		ADD EAX,0x04
    		DEC ECX                                             //  Switch (cases 1..4)
    	JE label4
    		CMP ECX,0x04
    	JB label9
    label10:
    		MOV EDX,DWORD PTR DS:[ESI]                         //  Default case of switch 0055BACA
    		SUB ECX,0x04
    		MOV DWORD PTR DS:[EAX],EDX
    		ADD EAX,0x04
    		ADD ESI,0x04
    		CMP ECX,0x04
    	JNB label10
    		TEST ECX,ECX
    	JBE label4
    label11:
    		MOV DL,BYTE PTR DS:[ESI]
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    		INC ESI
    		DEC ECX
    	JNZ label11
    	JMP label4
    label9:
    		MOV DL,BYTE PTR DS:[ESI]                           //  Cases 2,3,4 of switch 0055BACA
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    		INC ESI
    		DEC ECX
    	JNZ label9
    label4:
    		XOR ECX,ECX                                         //  Case 1 of switch 0055BACA
    		MOV CL,BYTE PTR DS:[ESI]
    		INC ESI
    		CMP ECX,0x10
    	JNB label5
    		SHR ECX,0x02
    		MOV EDX,EAX
    		SUB EDX,ECX
    		XOR ECX,ECX
    		MOV CL,BYTE PTR DS:[ESI]
    		SHL ECX,0x02
    		SUB EDX,ECX
    		MOV CL,BYTE PTR DS:[EDX-0x801]
    		SUB EDX,0x0801
    		INC ESI
    		MOV BYTE PTR DS:[EAX],CL
    		INC EAX
    		INC EDX
    lable28:
    		MOV CL,BYTE PTR DS:[EDX]
    		MOV BYTE PTR DS:[EAX],CL
    		MOV DL,BYTE PTR DS:[EDX+0x01]
    		INC EAX
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    label14:
    		MOV CL,BYTE PTR DS:[ESI-0x02]
    		AND ECX,0x03
    	JE label1
    label2:
    		MOV DL,BYTE PTR DS:[ESI]
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    		INC ESI
    		DEC ECX
    	JNZ label2
    		XOR ECX,ECX
    		MOV CL,BYTE PTR DS:[ESI]
    		INC ESI
    label5:
    		CMP ECX,0x40                                          //  Switch (cases 0..3F)
    	JB label12
    		MOV EDX,ECX                                         //  Default case of switch label5
    		MOV EDI,EAX
    		SHR EDX,0x02
    		AND EDX,0x07
    		SUB EDI,EDX
    		XOR EDX,EDX
    		MOV DL,BYTE PTR DS:[ESI]
    		SHL EDX,0x03
    		SUB EDI,EDX
    		DEC EDI
    		INC ESI
    		SHR ECX,0x05
    		DEC ECX
    label25:
    		MOV DL,BYTE PTR DS:[EDI]
    		MOV BYTE PTR DS:[EAX],DL
    		MOV DL,BYTE PTR DS:[EDI+0x01]
    		INC EAX
    		INC EDI
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    		INC EDI
    label13:
    		MOV DL,BYTE PTR DS:[EDI]
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    		INC EDI
    		DEC ECX
    	JNZ label13
    	JMP label14
    label12:
    		CMP ECX,0x20
    	JB label15
    		AND ECX,0x1F                                          //  Cases 20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F,30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F of switch label5
    	JNZ label16
    		CMP BYTE PTR DS:[ESI],0
    	JNZ label17
    label18:
    		MOV DL,BYTE PTR DS:[ESI+0x01]
    		ADD ECX,0xFF
    		INC ESI
    		TEST DL,DL
    	JE label18
    label17:
    		XOR EDX,EDX
    		MOV DL,BYTE PTR DS:[ESI]
    		INC ESI
    		LEA ECX,DWORD PTR DS:[ECX+EDX+0x1F]
    label16:
    		XOR EDX,EDX
    		MOV EDI,EAX
    		MOV DX,WORD PTR DS:[ESI]
    		SHR EDX,0x02
    		SUB EDI,EDX
    		DEC EDI
    		ADD ESI,0x02
    	JMP label19
    label15:
    		CMP ECX,0x10
    	JB label20
    		MOV EDX,ECX                                         //  Cases 10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F of switch label5
    		MOV EDI,EAX
    		AND EDX,0x08
    		SHL EDX,0x0B
    		SUB EDI,EDX
    		AND ECX,0x07
    	JNZ label21
    		CMP BYTE PTR DS:[ESI],0x00
    	JNZ label22
    label23:
    		MOV DL,BYTE PTR DS:[ESI+0x01]
    		ADD ECX,0xFF
    		INC ESI
    		TEST DL,DL
    	JE label23
    label22:
    		XOR EDX,EDX
    		MOV DL,BYTE PTR DS:[ESI]
    		INC ESI
    		LEA ECX,DWORD PTR DS:[ECX+EDX+0x07]
    label21:
    		XOR EDX,EDX
    		MOV DX,WORD PTR DS:[ESI]
    		ADD ESI,0x02
    		SHR EDX,0x02
    		SUB EDI,EDX
    		CMP EDI,EAX
    	JE label24
    		SUB EDI,0x4000
    label19:
    		CMP ECX,0x06
    	JB label25
    		MOV EDX,EAX
    		SUB EDX,EDI
    		CMP EDX,0x04
    	JL label25
    		MOV EDX,DWORD PTR DS:[EDI]
    		ADD EDI,0x04
    		MOV DWORD PTR DS:[EAX],EDX
    		ADD EAX,0x04
    		SUB ECX,0x02
    label26:
    		MOV EDX,DWORD PTR DS:[EDI]
    		SUB ECX,0x04
    		MOV DWORD PTR DS:[EAX],EDX
    		ADD EAX,0x04
    		ADD EDI,0x04
    		CMP ECX,0x04
    	JNB label26
    		TEST ECX,ECX
    	JBE label14
    label27:
    		MOV DL,BYTE PTR DS:[EDI]
    		MOV BYTE PTR DS:[EAX],DL
    		INC EAX
    		INC EDI
    		DEC ECX
    	JNZ label27
    	JMP label14
    label20:
    		SHR ECX,0x02                                           //  Cases 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F of switch label5
    		MOV EDX,EAX
    		SUB EDX,ECX
    		XOR ECX,ECX
    		MOV CL,BYTE PTR DS:[ESI]
    		SHL ECX,0x02
    		SUB EDX,ECX
    		DEC EDX
    		INC ESI
    	JMP lable28
    label24:
    		MOV ECX,DWORD PTR SS:[ESP+0x1C]
    		SUB EAX,ECX
    		CMP ESI,EBP
    		MOV DWORD PTR DS:[EBX],EAX
    	JNZ label29
    		POP EDI
    		POP ESI
    		POP EBP
    		XOR EAX,EAX
    		POP EBX
    		RETN
    label29:
    		SBB EAX,EAX
    		POP EDI
    		AND AL,0xFC
    		POP ESI
    		POP EBP
    		ADD EAX, -4
    		POP EBX
    		RETN
    	}
    }
    
    //--------------------------------------------------------------------------
    
    // Decompress wrapper function
    void LZObject_Decompress(LPBYTE src, DWORD srcLen, LPBYTE dst, DWORD * ptrNewLen, void * workMemory)
    {
    	__asm
    	{
    		MOV EDI, src
    		MOV EAX, dst
    		push workMemory
    		MOV EDX, ptrNewLen
    		push EDX
    		MOV EDX, srcLen
    		PUSH EAX
    		PUSH EDX
    		ADD EDI, 4
    		PUSH EDI
    		call ASM_LZO_DECOMPRESS
    		ADD ESP, 0x14
    		TEST EAX, EAX
    		JE LABEL1
    		INT 3 // Error, don't continue
    LABEL1:
    		NOP
    	}
    }
    
    //--------------------------------------------------------------------------
    
    // Tokenizes a string into a vector
    std::vector<std::string> TokenizeString(const std::string& str, const std::string& delim)
    {
    	// http://www.gamedev.net/community/forums/topic.asp?topic_id=381544#TokenizeString
    	using namespace std;
    	vector<string> tokens;
    	size_t p0 = 0, p1 = string::npos;
    	while(p0 != string::npos)
    	{
    		p1 = str.find_first_of(delim, p0);
    		if(p1 != p0)
    		{
    			string token = str.substr(p0, p1 - p0);
    			tokens.push_back(token);
    		}
    		p0 = str.find_first_not_of(delim, p1);
    	}
    	return tokens;
    }
    
    //--------------------------------------------------------------------------
    
    // Saves the file to a specific folder based on the path. The root 
    // directory I choose to use is named 'output'.
    void SaveFile(const char * originalFilename, LPBYTE outBuffer, DWORD outBufferSize)
    {
    	std::stringstream dirPath;
    	std::vector<std::string> pathTokens = TokenizeString(originalFilename, "\\/");
    
    	dirPath << "output";
    	CreateDirectoryA(dirPath.str().c_str(), NULL);
    	dirPath << "\\";
    
    	size_t index = 0;
    	for(index = 0; index < pathTokens.size() - 1; ++index)
    	{
    		if(pathTokens[index].find_first_of(":") != std::string::npos)
    			continue;
    		dirPath << pathTokens[index];
    		CreateDirectoryA(dirPath.str().c_str(), NULL);
    		dirPath << "\\";
    	}
    
    	dirPath << pathTokens[index];
    
    	FILE * of = fopen(dirPath.str().c_str(), "wb");
    	if(of)
    	{
    		fwrite(outBuffer, 1, outBufferSize, of);
    		fclose(of);
    	}
    	else
    	{
    		printf("Could not save the file %s\n", dirPath.str().c_str());
    	}
    }
    
    //--------------------------------------------------------------------------
    
    // Dumps a complete archive. I have combined two sets of logic for this,
    // but you can separate them if you want a more unique tool that allows
    // you to extract individual files or explore the contents.
    bool DumpArchive(const char * inFolder, const char * name)
    {
    	HANDLE eixHandle = INVALID_HANDLE_VALUE;
    	HANDLE epkHandle = INVALID_HANDLE_VALUE;
    	SECURITY_ATTRIBUTES eixSecurity = {0};
    	SECURITY_ATTRIBUTES epkSecurity = {0};
    	DWORD eixFileSize = 0;
    	DWORD epkFileSize = 0;
    	HANDLE eixFileMapping = NULL;
    	HANDLE epkFileMapping = NULL;
    	LPBYTE eixFileBufferPtr = NULL;
    	LPBYTE epkFileBufferPtr = NULL;
    	bool bWasError = false;
    
    	std::string eixName_ = inFolder;
    	if(!(eixName_[eixName_.size() - 1] == '\\' || eixName_[eixName_.size() - 1] == '/'))
    	{
    		eixName_ += "\\";
    	}
    	eixName_ += name;
    	eixName_ += ".eix";
    
    	std::string epkName_ = inFolder;
    	if(!(epkName_[epkName_.size() - 1] == '\\' || epkName_[epkName_.size() - 1] == '/'))
    	{
    		epkName_ += "\\";
    	}
    	epkName_ += name;
    	epkName_ += ".epk";
    
    	const char * eixName = eixName_.c_str();
    	const char * epkName = epkName_.c_str();
    
    	eixSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
    	eixSecurity.bInheritHandle = TRUE;
    	eixSecurity.lpSecurityDescriptor = NULL;
    
    	epkSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
    	epkSecurity.bInheritHandle = TRUE;
    	epkSecurity.lpSecurityDescriptor = NULL;
    
    	// Open the files to access
    	while(bWasError == false)
    	{
    		eixHandle = CreateFileA(eixName, GENERIC_READ, FILE_SHARE_READ, &eixSecurity, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    		if(eixHandle == INVALID_HANDLE_VALUE)
    		{
    			printf("Could not open the %s file. The program will now exit.\n", eixName);
    			bWasError = true;
    			break;
    		}
    
    		epkHandle = CreateFileA(epkName, GENERIC_READ, FILE_SHARE_READ, &epkSecurity, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    		if(epkHandle == INVALID_HANDLE_VALUE)
    		{
    			printf("Could not open the %s file. The program will now exit.\n", epkName);
    			bWasError = true;
    			break;
    		}
    		break; // All done now
    	}
    
    	// Create the access handles for reading the files
    	while(bWasError == false)
    	{
    		// We need to store the size of the file for file mapping
    		eixFileSize = GetFileSize(eixHandle, NULL);
    		if(eixFileSize == INVALID_FILE_SIZE)
    		{
    			DWORD dwError = GetLastError();
    			if(dwError != NO_ERROR)
    			{
    				printf("There was an error [%i] getting the file size of the %s file. The program will now exit.\n", dwError, eixName);
    				bWasError = true;
    				break;
    			}
    		}
    
    		// We need to store the size of the file for file mapping
    		epkFileSize = GetFileSize(epkHandle, NULL);
    		if(epkFileSize == INVALID_FILE_SIZE)
    		{
    			DWORD dwError = GetLastError();
    			if(dwError != NO_ERROR)
    			{
    				printf("There was an error [%i] getting the file size of the %s file. The program will now exit.\n", dwError, epkName);
    				bWasError = true;
    				break;
    			}
    		}
    
    		// Create a file mapping object
    		eixFileMapping = CreateFileMapping(eixHandle, NULL, PAGE_READONLY, 0, eixFileSize, NULL);
    		if(eixFileMapping == 0)
    		{
    			printf("Could not create a file mapping object for the %s file. The program will now exit.\n", eixName);
    			bWasError = true;
    			break;
    		}
    
    		// Create a file mapping object
    		epkFileMapping = CreateFileMapping(epkHandle, NULL, PAGE_READONLY, 0, epkFileSize, NULL);
    		if(epkFileMapping == 0)
    		{
    			printf("Could not create a file mapping object for the %s file. The program will now exit.\n", epkName);
    			bWasError = true;
    			break;
    		}
    
    		// Create a file mapping view
    		eixFileBufferPtr = reinterpret_cast<LPBYTE>(MapViewOfFile(eixFileMapping, FILE_MAP_READ, 0, 0, eixFileSize));
    		if(eixFileBufferPtr == 0)
    		{
    			printf("Could not create a view of the the %s file. The program will now exit.\n", eixName);
    			bWasError = true;
    			break;
    		}
    
    		// Create a file mapping view
    		epkFileBufferPtr = reinterpret_cast<LPBYTE>(MapViewOfFile(epkFileMapping, FILE_MAP_READ, 0, 0, epkFileSize));
    		if(epkFileBufferPtr == 0)
    		{
    			printf("Could not create a view of the the %s file. The program will now exit.\n", epkName);
    			bWasError = true;
    			break;
    		}
    
    		break; // All done now
    	}
    
    	// Now we need to verify the files we just loaded
    	while(bWasError == false)
    	{
    		// We need at least 12 bytes
    		if(eixFileSize < 0x0C)
    		{
    			printf("The file size for the %s file is too small. The program will now exit.\n", eixName);
    			bWasError = true;
    			break;
    		}
    
    		// Verify the header
    		LPDWORD eixHeader = reinterpret_cast<LPDWORD>(eixFileBufferPtr);
    		if(*eixHeader != 0x444B5045) // Some hard coded check
    		{
    			// Important: This value is read from the client itself. If the client updates, this value
    			// would need to be updated as well if it ever changed.
    			if(*eixHeader != LZ_KEY)
    			{
    				printf("The file header for the %s file is incorrect. The program will now exit.\n", eixName);
    				bWasError = true;
    				break;
    			}
    
    			// Get a file header pointer from the buffer
    			TEntry2 * eixHeader = (TEntry2 *)eixFileBufferPtr;
    
    			// Store a pointer to the encrypted data
    			LPBYTE eixDataBuffer = eixFileBufferPtr + 0x14;
    
    			// We don't care about this check because we will create the
    			// buffers ourselves in dynamic memory. The game wants to be as
    			// efficient as possible though.
    			if(eixHeader->decompressedBlockSize <= 0x10000)
    			{
    			}
    
    			// Allocate space for the decompressed buffer
    			LPBYTE decompressedBuffer = new BYTE[eixHeader->decompressedBlockSize];
    			memset(decompressedBuffer, 0, eixHeader->decompressedBlockSize);
    
    			// If the contents of the file are not encrypted (no test data yet)
    			// So, not going to add the implementation at this time.
    			if(eixHeader->decryptedBlockSize == 0)
    			{
    				printf("[TODO] -- eixHeader of %s is not encrypted!\n", eixName);
    				bWasError = true;
    				delete [] decompressedBuffer;
    				break;
    			}
    
    			// We don't care about this check because we will create the
    			// buffers ourselves in dynamic memory. The game wants to be as
    			// efficient as possible though.
    			if(eixHeader->decryptedBlockSize < 0x2000)
    			{
    			}
    
    			// Create a buffer to decrypt the contents of the exi header into
    			LPBYTE compressedBuffer = new BYTE[eixHeader->decryptedBlockSize];
    			memset(compressedBuffer, 0, eixHeader->decryptedBlockSize);
    
    			// Try to decrypt the data
    			int result = LZObject_CheckKey(compressedBuffer, eixDataBuffer, gLZOData, eixHeader->decryptedBlockSize);
    			if(result == 0)
    			{
    				delete [] decompressedBuffer;
    				delete [] compressedBuffer;
    				printf("There was an error decrypting the data of the %s file. The program will now exit.\n", eixName);
    				bWasError = true;
    				break;
    			}
    
    			// Try to decompress the data now
    			DWORD finalSize = 0;
    			LZObject_Decompress(compressedBuffer, eixHeader->compressedBlockSize, decompressedBuffer, &finalSize, 0);
    
    			// Make sure the file size matches
    			if(finalSize != eixHeader->decompressedBlockSize)
    			{
    				delete [] decompressedBuffer;
    				delete [] compressedBuffer;
    				printf("There was an error decompressing the data of the %s file. The program will now exit.\n", eixName);
    				bWasError = true;
    				break;
    			}
    
    			// Get a pointer to the new file header
    			TEntry3 * entry3 = (TEntry3 *)decompressedBuffer;
    
    			// Check the file version
    			if(entry3->version != 2)
    			{
    				delete [] decompressedBuffer;
    				delete [] compressedBuffer;
    				printf("The version of the %s file is incorrect. Expected (%i) Actual (%i). The program will now exit.\n", eixName, 2, entry3->version);
    				bWasError = true;
    				break;
    			}
    
    			// Make sure we have a match in the number of entries and the expected block size
    			if(finalSize != (((entry3->fileCount + entry3->fileCount * 2) << 0x06) + 0x0C))
    			{
    				delete [] decompressedBuffer;
    				delete [] compressedBuffer;
    				printf("The pack index file size of the %s file is incorrect. The program will now exit.\n", eixName);
    				bWasError = true;
    				break;
    			}
    
    			// Store a pointer to the block of data
    			LPBYTE decompressedBlock = decompressedBuffer + 0x0C;
    
    			// If we have files to process
    			if(entry3->fileCount > 0)
    			{
    				// Build a filename for our dump file
    				std::string dumpFileName = eixName;
    				dumpFileName = dumpFileName.substr(1 + dumpFileName.find_last_of("\\/"));
    				dumpFileName = dumpFileName.substr(0, dumpFileName.find_first_of("."));
    				dumpFileName += "_dump.txt";
    
    				// Create the output file for the eix header dump
    				FILE * of = fopen(dumpFileName.c_str(), "w");
    				if(of == 0)
    				{
    					printf("There was an error creating the %s file. The header data will not be dumped.\n", dumpFileName.c_str());
    				}
    
    				// Loop through all of the files
    				for(DWORD x = 0; x < entry3->fileCount; ++x)
    				{
    					// Create a pointer to the file entry block
    					TEntry1 * pEntry = (TEntry1 *)decompressedBlock;
    
    					// Make sure there is a value here
    					if(pEntry->dw2 == 0)
    					{
    						printf("No dw2 field set for the file %s\n", pEntry->filename);
    						continue;
    					}
    
    					// Simple entry dump
    					if(of)
    					{
    						fprintf(of, "%i. ", pEntry->index);
    						fprintf(of, "%s\n", pEntry->filename);
    						fprintf(of, "[%.8X]", pEntry->dw1);
    						fprintf(of, "[%.8X]", pEntry->dw2);
    						fprintf(of, "[%.8X]", pEntry->dw3);
    						fprintf(of, "[%.8X]", pEntry->dwSrcSize);
    						fprintf(of, "[%.8X]", pEntry->unpackedCRC);
    						fprintf(of, "[%.8X]", pEntry->dwFileOffset);
    						fprintf(of, "[%.2X %.2X %.2X %.2X]", pEntry->packedType, pEntry->b2, pEntry->b3, pEntry->b4);
    						fprintf(of, "\n");
    					}
    
    					// Not compressed, no extra header
    					if(pEntry->packedType == 0)
    					{
    						SaveFile(pEntry->filename, epkFileBufferPtr + pEntry->dwFileOffset, pEntry->dwSrcSize);
    					}
    
    					// Header and compressed/encrypted
    					else
    					{
    						// Decompress
    						if(pEntry->packedType == 1)
    						{
    							// Calculate the data pointer to the entry data block
    							LPBYTE pDataPtr = epkFileBufferPtr + pEntry->dwFileOffset;
    
    							// Get a pointer to the header for this block
    							TEntry2 * pEntryHeader = (TEntry2*)pDataPtr;
    
    							// Make sure the header is correct
    							DWORD h = *(reinterpret_cast<LPDWORD>(pDataPtr));
    							if(h != LZ_KEY)
    							{
    								printf("The header for %s is incorrect. Expected (%x) Actual (%x).\n", pEntry->filename, LZ_KEY, h);
    								continue;
    							}
    
    							// Allocate memory for the uncompressed data
    							LPBYTE uncompressedData = new BYTE[pEntryHeader->decompressedBlockSize];
    							memset(uncompressedData, 0, pEntryHeader->decompressedBlockSize);
    
    							// Decompress the data
    							LZObject_Decompress(pDataPtr + 16, pEntryHeader->compressedBlockSize, uncompressedData, &finalSize, 0);
    
    							// Make sure the operation went right
    							if(finalSize != pEntryHeader->decompressedBlockSize)
    							{
    								printf("File size for %s differs from expected. Expected (%i) Actual (%i).\n", pEntry->filename, pEntryHeader->decompressedBlockSize, finalSize);
    							}
    							else
    							{
    								SaveFile(pEntry->filename, uncompressedData, pEntryHeader->decompressedBlockSize);
    							}
    
    							// Cleanup now
    							delete [] uncompressedData;
    						}
    
    						// Decrypt + Decompress
    						else if(pEntry->packedType == 2)
    						{
    							// Calculate the data pointer to the entry data block
    							LPBYTE pDataPtr = epkFileBufferPtr + pEntry->dwFileOffset;
    
    							// Get a pointer to the header for this block
    							TEntry2 * pEntryHeader = (TEntry2*)pDataPtr;
    
    							DWORD h = *(reinterpret_cast<LPDWORD>(pDataPtr));
    							if(h != LZ_KEY)
    							{
    								printf("The header for %s is incorrect. Expected (%x) Actual (%x).\n", pEntry->filename, LZ_KEY, h);
    								continue;
    							}
    
    							// Create a buffer for the decrypted data
    							LPBYTE decryptedData = new BYTE[pEntryHeader->decryptedBlockSize];
    							memset(decryptedData, 0, pEntryHeader->decryptedBlockSize);
    
    							// Decrypt the data
    							int result = LZObject_CheckKey(decryptedData, pDataPtr + 20, gLZOData2, pEntryHeader->decryptedBlockSize);
    							if(result == 0)
    							{
    								printf("There was an error decrypting the data for the %s file. It will be skipped.\n", pEntry->filename);
    								delete [] decryptedData;
    								continue;
    							}
    
    							// Create a buffer for the final uncompressed data
    							LPBYTE uncompressedData = new BYTE[pEntryHeader->decompressedBlockSize];
    							memset(uncompressedData, 0, pEntryHeader->decompressedBlockSize);
    
    							// Decompress
    							LZObject_Decompress(decryptedData, pEntryHeader->compressedBlockSize, uncompressedData, &finalSize, 0);
    
    							// Make sure the file sizes match
    							if(finalSize != pEntryHeader->decompressedBlockSize)
    							{
    								printf("File size for %s differs from expected. Expected (%i) Actual (%i)\n", pEntry->filename, pEntryHeader->decompressedBlockSize, finalSize);
    							}
    							else
    							{
    								SaveFile(pEntry->filename, uncompressedData, pEntryHeader->decompressedBlockSize);
    							}
    
    							// Cleanup now
    							delete [] decryptedData;
    							delete [] uncompressedData;
    						}
    					}
    					decompressedBlock += 0xC0; // next block
    				}
    
    				// Close our output file for the header dump file
    				if(of)
    				{
    					fclose(of);
    				}
    			}
    
    			// Cleanup
    			delete [] decompressedBuffer;
    			delete [] compressedBuffer;
    		}
    		else
    		{
    			// If we get here, we are using an unsupported type of file that
    			// was not accessible at the time this tool was written.
    			printf("[TODO] -- if(*eixHeader != 0x444B5045)\n");
    			bWasError = true;
    			break;
    		}
    
    		break; // All done now
    	}
    
    	// Cleanup
    
    	if(eixFileMapping != 0)
    		CloseHandle(eixFileMapping);
    	if(epkFileMapping != 0)
    		CloseHandle(epkFileMapping);
    
    	if(eixHandle != INVALID_HANDLE_VALUE)
    		CloseHandle(eixHandle);
    	if(epkHandle != INVALID_HANDLE_VALUE)
    		CloseHandle(epkHandle);
    
    	// Return the status
    	return (bWasError == false);
    }
    
    //--------------------------------------------------------------------------
    


  • Um das zu verstehen, braucht man aber mindestens ein kleines Datinum!



  • Was genau ist die Frage?



  • Na, Casi hat irgendwo im Internet den Quellcode für eine Funktion gefunden (mit Ansätzen von Reverse-Engineering) und nun sollen wir daraus die inverse Funktion bilden!



  • Lies dir mal bitte den Link in meiner Signatur gründlich durch. Und danach kauf dir bitte eine Tastatur mit Satzzeichen!


Log in to reply