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!