Oyunalani Ekibi

S4 League Resource Files B261910yeol

üye olduğunuzda e-mailinize aktivasyon kodu gelicektir eğer aktif etmezseniz kullanıcı adı şifre yazsanız bile giremezsiniz ancak admin sitedeyse ve görürse aktif edebilir

Join the forum, it's quick and easy

Oyunalani Ekibi

S4 League Resource Files B261910yeol

üye olduğunuzda e-mailinize aktivasyon kodu gelicektir eğer aktif etmezseniz kullanıcı adı şifre yazsanız bile giremezsiniz ancak admin sitedeyse ve görürse aktif edebilir

Oyunalani Ekibi

Would you like to react to this message? Create an account in a few clicks or log in to continue.

    S4 League Resource Files

    Admin
    Admin
    Üst Düzey Admin
    Üst Düzey Admin


    Profil Bilgileri
    Mesaj Sayısı Mesaj Sayısı : 3516
    Kayıt tarihi Kayıt tarihi : 13/06/09
    Nerden Nerden : küçükyalı
    Yaş Yaş : 34
    Profil Alt

    S4 League Resource Files Empty S4 League Resource Files

    Mesaj tarafından Admin Cuma Ocak 01, 2010 7:26 pm

    Hello everyone,

    I think nobody knows me, but I'm a member of the Underground here.
    Since I will resign from hacking S4, I want to make my hacks public to
    share with everyone. I stopped playing S4 League long ago, so I don't
    care much about S4League anymore.

    What I want to share with you is the decryption of the S4League
    resource files. It is also used for decrypting the network traffic, but
    you have to figure that out yourself.

    Ok, lets start with the resource.s4hd file. It contains the internal
    file names and the crc value of the decrypted/uncompressed file and
    it's compressed and encrypted by a key.

    The key is

    Code:

    0x82, 0x53, 0x43, 0x4C, 0x2B, 0x0D, 0x37, 0xD7,
    0xD9, 0xD8, 0x1B, 0x6D, 0xA0, 0xC3, 0x2B, 0xEE,
    0x45, 0x88, 0x1A, 0xA6, 0x18, 0x1D, 0x9D, 0x38,
    0x2A, 0x55, 0x03, 0x1D, 0xCD, 0xA6, 0x73, 0x07,
    0xED, 0x8D, 0xC5, 0xDB, 0xA3, 0xBD, 0xB6, 0xD5

    Only the first 32 values are used. They use the LZO compression library.

    The filename in the _resources folder is the crc as hex value. The files are compressed and encrypted with the same key.

    Files that end with .x4 are special. They are compressed and encrypted
    again, but with the whole 40 byte key above. X4 files contain many
    parameters of the game, like height of jump, gravity, prices for shop
    items and many more...

    AFAIK, the CRC is not checked when reading the files from disk. The CRC
    is the CRC32 of the internal name and the CRC32 of the
    uncompressed/decrypted file. Both are encrypted with the key above.
    They really know how to reuse code. [Resimleri görebilmek için üye olun veya giriş yapın.]

    I add the source code of a program to this post that contains the
    functions for decrypting the resource files. To prevent easy leaching,
    you have to figure out how to use it yourself. But I'm sure, someone
    will make a pretty filebrowser for this game. [Resimleri görebilmek için üye olun veya giriş yapın.] Oh, and you need the miniLZO files for compiling.

    If you have an older installation of S4League that was patched several
    times, the clean resource function is very useful. It deletes all
    unused files from the _resources folder, which saved me 1.5 GB disk
    space.

    Code like this has been around for months, so we already had our fun, now they can fix it. [Resimleri görebilmek için üye olun veya giriş yapın.]
    I bet they need around 2 months to fix it and everyone has to download
    the full game again. I give no support for this code and I will not fix
    it, when they change something. I'm out of the game.

    Now the code:



    Spoiler:






    Code:

    #include "windows.h"
    #include "minilzo.203\minilzo.h"

    class DecryptUtils {
    private:


    BYTE static const Key[];
    DWORD *CRCTable;

    protected:
    DWORD* readDWORD(BYTE** pointer) {
    DWORD* p = (DWORD*)*pointer;
    (*pointer)+=4;
    return p;
    }

    bool decryptX4(DWORD size, BYTE * data)
    {
    DWORD i = 0;
    while ( i < size )
    {
    *data = ((signed int)*data >> 1) & 0x7F | (unsigned __int8)(((*data & 1) << 7) & 0x80);
    *data++ ^= Key[i++ % 40];
    }
    return true;
    }

    bool encryptX4(DWORD size, BYTE* data) {
    DWORD i = 0;

    while ( i < size )
    {
    *(BYTE *)data ^= Key[i % 40];
    *(BYTE *)data = (unsigned __int8)(2 * *(BYTE *)data & 0xFE) | ((*(BYTE *)data & 0x80) >> 7) & 1;
    ++data;
    ++i;
    }
    return true;
    }

    bool decryptCapped256(DWORD size, BYTE* data) {
    int sizeCapped;
    int i = 0;

    if ( size >= 256 )
    sizeCapped = 256;
    else
    sizeCapped = size;

    while ( i < sizeCapped )
    {
    *data = ((signed int)*data >> 1) & 0x7F | (unsigned __int8)(((*data & 1) << 7) & 0x80);
    *data++ ^= Key[i++ % 32];
    }
    return true;
    }

    bool encryptCapped256(DWORD size, BYTE* data) {
    int sizeCapped;
    int i = 0;

    if ( size >= 256 )
    sizeCapped = 256;
    else
    sizeCapped = size;

    while ( i < sizeCapped )
    {
    *(BYTE *)data ^= Key[i % 32];
    *(BYTE *)data = (unsigned __int8)(2 * *(BYTE *)data & 0xFE) | ((*(BYTE *)data & 0x80) >> 7) & 1;
    ++data;
    ++i;
    }
    return true;
    }

    int compress(DWORD sizeIN, BYTE* dataIN, DWORD* sizeOUT, BYTE* dataOUT) {
    BYTE* dict = (BYTE*)malloc(0x10000);
    return lzo1x_1_compress(dataIN, sizeIN, dataOUT, sizeOUT, dict);
    }

    int decompress(DWORD sizeIN, BYTE* dataIN, DWORD* sizeOUT, BYTE* dataOUT) {
    return lzo1x_decompress_safe(dataIN, sizeIN, dataOUT, sizeOUT, NULL);
    }

    bool swapBytes(DWORD size, BYTE *data) {
    int sizeCapped;
    int i = 0;
    BYTE swap;
    int j;

    if ( size >= 128 )
    sizeCapped = 128;
    else
    sizeCapped = size;

    while ( i < sizeCapped / 2 )
    {
    j = size - 1 - i;
    swap = data[j];
    data[j] = data[i];
    data[i++] = swap;
    }
    return true;
    }

    DWORD crc32(BYTE *data, DWORD length)
    {
    register unsigned long crc;
    unsigned long i;

    crc = 0xFFFFFFFF;
    for (i = 0; i < length; i++)
    {
    crc = ((crc >> Cool & 0x00FFFFFF) ^ CRCTable[(crc ^ *data++) & 0xFF];
    }
    return (crc ^ 0xFFFFFFFF);
    }

    void crc32gentab ()
    {
    unsigned long crc, poly;
    int i, j;
    CRCTable = new DWORD[256];

    poly = 0xEDB88320L;
    for (i = 0; i < 256; i++) {
    crc = i;
    for (j = 8; j > 0; j--) {
    if (crc & 1) {
    crc = (crc >> 1) ^ poly;
    } else {
    crc >>= 1;
    }
    }
    CRCTable[i] = crc;
    }
    }
    };

    struct FolderFileHeader {
    char FileName[256];
    unsigned __int64 CRC;
    DWORD FileSize;
    DWORD Unknown;
    };

    struct Buffer {
    DWORD Size;
    BYTE* Data;
    };

    class Folder : public DecryptUtils {
    private:

    static const char* Name;
    FILE* Handle;
    int Size;
    BYTE* Data;
    bool Initialized;
    BYTE* Pointer;
    BYTE* FileStart;
    DWORD* Version;
    DWORD* NumberOfFiles;
    FolderFileHeader* FileHeader;
    bool Decrypted;
    void DecryptFolder();
    Buffer OpenFileCRC(char* crc, DWORD realSize);
    Buffer DecryptX4(Buffer data);

    public:
    Folder();
    ~Folder();
    void List();
    Buffer OpenFile(char * name);
    __int64 GenerateCRC(Buffer data, char * name);
    void CleanResources();
    };

    const BYTE DecryptUtils::Key[] = { // Only the first 40 keys copied from S4
    0x82, 0x53, 0x43, 0x4C, 0x2B, 0x0D, 0x37, 0xD7,
    0xD9, 0xD8, 0x1B, 0x6D, 0xA0, 0xC3, 0x2B, 0xEE,
    0x45, 0x88, 0x1A, 0xA6, 0x18, 0x1D, 0x9D, 0x38,
    0x2A, 0x55, 0x03, 0x1D, 0xCD, 0xA6, 0x73, 0x07,
    0xED, 0x8D, 0xC5, 0xDB, 0xA3, 0xBD, 0xB6, 0xD5
    };

    const char* Folder::Name = "resource.s4hd";

    Folder::Folder() {
    this->Initialized = false;
    this->Decrypted = false;
    // Open Resource File
    int errorNumber = fopen_s(&(this->Handle), this->Name, "rb");
    if (errorNumber != 0 || this->Handle == NULL) {
    printf("Error reading file %s. ErrorNr: %u\n", this->Name, errorNumber);
    //return errorNumber;
    return;
    }
    fseek(this->Handle, 0, SEEK_END);
    this->Size = ftell(this->Handle);
    rewind(this->Handle);
    if (this->Size < Cool {
    printf("File %s must have at least 8 bytes in size.\n", this->Name);
    fclose(this->Handle);
    return;
    }

    // Read Resource File into memory
    this->Data = (BYTE*) malloc(this->Size);
    if (this->Data == NULL) {
    printf("Could not alloc memory of size %u bytes.\n", this->Size);
    }
    int readBytes = fread_s(this->Data, this->Size, 1, this->Size, this->Handle);
    if (readBytes != this->Size) {
    printf("Expected to read %u bytes, but read %u bytes.\n", this->Size, readBytes);
    fclose(this->Handle);
    free(this->Data);
    return;
    }

    // Read Version and number of Files;
    this->Pointer = this->Data;
    this->Version = readDWORD(&this->Pointer);
    if (*(this->Version) != 1) {
    printf("First DWORD of %s has to be 1, Pentavision changed the format.\n", this->Name);
    fclose(this->Handle);
    free(this->Data);
    return;
    }
    this->NumberOfFiles = readDWORD(&this->Pointer);
    this->FileStart = this->Pointer;
    this->Initialized = true;
    DecryptFolder();
    }

    Folder::~Folder() {
    if (this->Initialized && this->Handle != NULL) {
    fclose(this->Handle);
    free(this->Data);
    }
    }

    void Folder::DecryptFolder() {
    if (!this->Initialized) return;

    DWORD fileCounter = *this->NumberOfFiles;
    BYTE* endOfFile = this->Data + this->Size;
    this->FileHeader = new FolderFileHeader[fileCounter];
    int i = 0;

    while (fileCounter >= 0 && this->Pointer < endOfFile) {
    DWORD * headerBlockSize = readDWORD(&this->Pointer);
    if (*headerBlockSize + this->Pointer > endOfFile) {
    printf("Length of header block size bigger than available memory. Size is %u at %u.\n", *headerBlockSize, this->Pointer - this->Data - sizeof(DWORD));
    return;
    }
    decryptCapped256(*headerBlockSize, this->Pointer);
    swapBytes(*headerBlockSize, this->Pointer);
    DWORD headerSize = sizeof(FolderFileHeader);
    decompress(*headerBlockSize, this->Pointer, &headerSize, (BYTE*)&this->FileHeader[i]);
    decryptCapped256(headerSize, (BYTE*)&this->FileHeader[i]);
    swapBytes(headerSize, (BYTE*)&this->FileHeader[i]);
    this->Pointer+= *headerBlockSize;
    fileCounter--;
    i++;
    }
    this->Decrypted = true;
    }

    void Folder::List() {
    if (!this->Initialized || !this->Decrypted) return;

    for (DWORD i = 0; i < *this->NumberOfFiles; ++i) {
    printf("Filename: %s \nFile-CRC: %I64X\nReal File-Size: %u\nUnknown: %X\n", this->FileHeader[i].FileName, this->FileHeader[i].CRC, this->FileHeader[i].FileSize, this->FileHeader[i].Unknown);
    }
    }

    Buffer Folder::OpenFile(char *name) {
    Buffer ret;
    ret.Data = 0;
    ret.Size = 0;
    if (!this->Initialized || !this->Decrypted) return ret;

    for (DWORD i = 0; i < *this->NumberOfFiles; ++i) {
    if (strncmp(name, this->FileHeader[i].FileName, 256) == 0) {
    char* fileName = new char[29];
    sprintf_s(fileName, 29, "_resources\\%I64X", this->FileHeader[i].CRC);
    Buffer data = OpenFileCRC(fileName, this->FileHeader[i].FileSize);
    if (data.Data==0) return data;
    Buffer ret = data;
    if (strstr(this->FileHeader[i].FileName, ".x4")!=0) {
    ret = DecryptX4(data);
    free(data.Data);
    }
    delete fileName;
    return ret;
    }
    }
    return ret;
    }

    Buffer Folder::DecryptX4(Buffer data) {
    Buffer x4;
    x4.Size = *((DWORD*)data.Data);
    data.Data+=4;
    data.Size-=4;
    x4.Data = (BYTE*) malloc(x4.Size);
    if (x4.Data == NULL) {
    printf("Could not alloc memory of size %u bytes.\n", x4.Size);
    }
    decryptX4(data.Size, data.Data);
    decompress(data.Size, data.Data, &x4.Size, x4.Data);
    data.Data -= 4;
    return x4;
    }

    Buffer Folder::OpenFileCRC(char *crc, DWORD realSize) {
    FILE* handle;
    Buffer d;
    d.Data = 0;
    d.Size = 0;
    int errNo = fopen_s(&handle, crc, "rb");
    if (errNo != 0 || handle == NULL) {
    printf("Error reading file %s. ErrorNr: %u\n", crc, errNo);
    return d;
    }


    fseek(handle, 0, SEEK_END);
    d.Size = ftell(handle);
    rewind(handle);


    d.Data = (BYTE*) malloc(d.Size);
    if (d.Data == NULL) {
    printf("Could not alloc memory of size %u bytes.\n", d.Size);
    }

    int readBytes = fread_s(d.Data, d.Size, 1, d.Size, handle);
    if (readBytes != d.Size) {
    printf("Expected to read %u bytes, but read %u bytes.\n", d.Size, readBytes);
    fclose(handle);
    free(d.Data);
    return d;
    }
    swapBytes(d.Size, d.Data);
    Buffer real;
    real.Size = realSize;
    real.Data = (BYTE*) malloc(real.Size);
    if (real.Data == NULL) {
    printf("Could not alloc memory of size %u bytes.\n", real.Size);
    }
    decompress(d.Size, d.Data, &real.Size, real.Data);
    decryptCapped256(real.Size, real.Data);
    free(d.Data);
    fclose(handle);
    return real;
    }

    __int64 Folder::GenerateCRC(Buffer data, char* name) {
    crc32gentab();
    __int64 dataCRC = crc32(data.Data, data.Size);
    __int64 nameCRC = crc32((BYTE*)name, strlen(name));
    __int64 crc = dataCRC | (nameCRC << 32);
    encryptCapped256(8, (BYTE*)&crc);
    return crc;
    }

    void Folder::CleanResources() {
    if (!this->Initialized || !this->Decrypted) return;

    int e = system("dir _resources >nul");
    if (e != 0) return;
    rename("_resources", "_resources.bkp");
    system("mkdir _resources");
    for (DWORD i = 0; i < *this->NumberOfFiles; ++i) {
    char* oldName = new char[100];
    sprintf_s(oldName, 100, "_resources.bkp\\%I64X", this->FileHeader[i].CRC);
    char* newName = new char[100];
    sprintf_s(newName, 100, "_resources\\%I64X", this->FileHeader[i].CRC);
    rename(oldName, newName);
    delete oldName;
    delete newName;
    }
    printf("You can now remove the folder _resources.bkp from the S4League Folder.\n");
    }

    int main(int argc, char* argv[])
    {
    if (argc <= 1) {
    printf("Usage:\n");
    printf("program.exe list \t\t\t\t\tList files\n");
    printf("program.exe clean \t\t\t\t\tClean resources\n");
    printf("program.exe extract filename \t\t\t\tExtract file\n");
    printf("program.exe crc external_file internal_filename \tGenerate CRC\n");
    }
    if (argc == 2) {
    if (strcmp("list", argv[1]) == 0) {
    Folder* folder = new Folder();
    folder->List();
    }
    if (strcmp("clean", argv[1]) == 0) {
    Folder* folder = new Folder();
    folder->CleanResources();
    }
    }
    if (argc == 3) {
    if (strcmp("extract", argv[1])==0) {
    Folder* folder = new Folder();
    Buffer file = folder->OpenFile(argv[2]);
    printf("%s",file.Data);
    }
    }
    if (argc == 4) {
    if (strcmp("crc", argv[1])==0) {
    Folder* folder = new Folder();
    FILE* handle;
    Buffer d;
    d.Data = 0;
    d.Size = 0;

    int errNo = fopen_s(&handle, argv[2], "rb");
    if (errNo != 0 || handle == NULL) {
    printf("Error reading file %s. ErrorNr: %u\n", argv[2], errNo);
    return 1;
    }

    fseek(handle, 0, SEEK_END);
    d.Size = ftell(handle);
    rewind(handle);

    d.Data = (BYTE*) malloc(d.Size);
    if (d.Data == NULL) {
    printf("Could not alloc memory of size %u bytes.\n", d.Size);
    }

    int readBytes = fread_s(d.Data, d.Size, 1, d.Size, handle);
    if (readBytes != d.Size) {
    printf("Expected to read %u bytes, but read %u bytes.\n", d.Size, readBytes);
    fclose(handle);
    free(d.Data);
    return 1;
    }
    __int64 crc = folder->GenerateCRC(d, argv[3]);
    printf("CRC: %I64X", crc);
    }
    }
    return 0;
    }








    Edit: Let me add the code as C#:



    Spoiler:

      Forum Saati Perş. Mayıs 02, 2024 11:47 am