Unmantained C++ [Release][W*t*F]Codice Sorgente Decrypter/Crypter Game Client D: (C++)

Una guida contrassegnata come Unmantained contiene informazioni su un argomento obsoleto, non più utile o files non aggiornati da parte del creatore.
Stato
Discussione chiusa ad ulteriori risposte.

ImFamous

Utente Electrum
20 Giugno 2010
205
42
61
176
Ultima modifica da un moderatore:
Si tratta solo del codice dell'extractor. Non c'è alcun codice per ripackare i file, e non è totalmente in C (perchè di C++ qui non c'è proprio nulla), ma è per la maggior parte in assembly, tra l'altro con la notazione Intel e non AT&T, quindi andrà solo con il compiler microsoft. Sarebbe opportuno dire che il source è di pushedx di elitepvpers, che ha fatto un ottimo lavoro di estrazione del codice assembly dal launcher...
E comunque chi sa "smanettarci" già conosceva questo source, ma vabbè, se non altro la gente avrà un'occasione in più di imparare qualcosa (anche se dubito che capirà molto di quel codice assembly).

Codice:
/*
    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("[email protected]#$%^&*()+={}[]|\\:\";\'<>?,./") != 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);
}

//--------------------------------------------------------------------------
+1 Accettati v.v Se qualkuno magari ha anche il sorgente del launcher sarebbe più utile....

Per cambiare estensioni ai file:
- andate alla righa 677
Codice:
    if(!(eixName_[eixName_.size() - 1] == '\\' || eixName_[eixName_.size() - 1] == '/'))
    {
        eixName_ += "\\";
    }
    eixName_ += name;
    eixName_ += ".[COLOR=red][B]eix[/B][/COLOR]";

    std::string epkName_ = inFolder;
    if(!(epkName_[epkName_.size() - 1] == '\\' || epkName_[epkName_.size() - 1] == '/'))
    {
        epkName_ += "\\";
    }
    epkName_ += name;
    epkName_ += ".[B][COLOR=red]epk[/COLOR][/B]";
 

ricky92

Utente Emerald
6 Settembre 2008
1,142
23
835
503
Si tratta solo del codice dell'extractor. Non c'è alcun codice per ripackare i file, e non è totalmente in C (perchè di C++ qui non c'è proprio nulla), ma è per la maggior parte in assembly, tra l'altro con la notazione Intel e non AT&T, quindi andrà solo con il compiler microsoft. Sarebbe opportuno dire che il source è di pushedx di elitepvpers, che ha fatto un ottimo lavoro di estrazione del codice assembly dal launcher...
E comunque chi sa "smanettarci" già conosceva questo source, ma vabbè, se non altro la gente avrà un'occasione in più di imparare qualcosa (anche se dubito che capirà molto di quel codice assembly).
 

d3m0n3

Utente Gold
25 Ottobre 2009
440
21
235
254
Ultima modifica:
Grazie mille! :)

attento quando compili ci sono alcuni commenti che passano alla riga successiva a causa del copia incolla potrebbero crearti errori...

esempio:
Codice:
label12:        CMP ECX,0x20    JB 
label15        AND ECX,0x1F                                          [COLOR=#ff0000]//  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[/COLOR] 
   JNZ label16 
       CMP BYTE PTR DS:[ESI],0 
   JNZ label17label18:
 

DolceMorte

Utente Silver
10 Luglio 2011
20
4
2
54
attento quando compili ci sono alcuni commenti che passano alla riga successiva a causa del copia incolla potrebbero crearti errori...

esempio:
Codice:
label12:        CMP ECX,0x20    JB 
label15        AND ECX,0x1F                                          [COLOR=#ff0000]//  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[/COLOR] 
   JNZ label16 
       CMP BYTE PTR DS:[ESI],0 
   JNZ label17label18:

Okey :)
ma nn riesco a compilarlo :( quando finisce mi sottolinea tipo delle righe in rosso...
 

d3vil401

Utente Platinum
3 Gennaio 2009
2,077
106
1,055
1,041
era gia stato postato,devi correggere il titolo,il source è dell'estrattore non del game client...
inoltre questo source è stato creato interamente da pushedx e non è stato 'estratto/convertito'
 
Stato
Discussione chiusa ad ulteriori risposte.