• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

C++ I need a encrypt my .spr

Joined
Aug 15, 2014
Messages
143
Reaction score
24
I have special itens and sprites in my cliente.

Someone knows a way to hide or difficult players to get the sprites?

Thanks.
 
encrypt it using otcv8. is not 100% secure there' are few people that knows how decrypt it, but it will be hard for many others
 
not 100% secure there' are few people that knows how decrypt it
Code to decrypt OTCv8 (free version) files is 85 lines in C++ and it all can be copied from leaked OTCv8 repository.
Lua files are compiled (hard to read/edit), but .spr is in normal .spr format after decrypting.

You can make .spr harder to read (encrypt etc.), but you can't make it unreadable for other OTSes. Your client - .exe file you deliver to every player - must contain algorithm to decrypt .spr and encryption key, to make client work.

Only way to make it unreadable, would be to create own format to keep sprites (different than .spr format) and implement code to read it in client. That way only your client - with secret source file - could read your file with sprites.
 
Code to decrypt OTCv8 (free version) files is 85 lines in C++ and it all can be copied from leaked OTCv8 repository.
Lua files are compiled (hard to read/edit), but .spr is in normal .spr format after decrypting.

You can make .spr harder to read (encrypt etc.), but you can't make it unreadable for other OTSes. Your client - .exe file you deliver to every player - must contain algorithm to decrypt .spr and encryption key, to make client work.

Only way to make it unreadable, would be to create own format to keep sprites (different than .spr format) and implement code to read it in client. That way only your client - with secret source file - could read your file with sprites.
In which file?
 
In which file?
Decrypt file contents (string buffer):
otcv8-The-Josh-Wife-Edition/resourcemanager.cpp at main · Stephany-The-Josh-Wife/otcv8-The-Josh-Wife-Edition (https://github.com/Stephany-The-Josh-Wife/otcv8-The-Josh-Wife-Edition/blob/main/src/framework/core/resourcemanager.cpp#L1025-L1065)

Function that exactly decrypts (g_crypt.bdecrypt) is Crypt::bdecrypt from:
otcv8-The-Josh-Wife-Edition/crypt.cpp at main · Stephany-The-Josh-Wife/otcv8-The-Josh-Wife-Edition (https://github.com/Stephany-The-Josh-Wife/otcv8-The-Josh-Wife-Edition/blob/main/src/framework/util/crypt.cpp#L505-L526)

Skip adler32 check. Print code.
Make it into project that loads file content and decrypt it ex. (otland fails to load my code formatting, wtf) - my 85 lines:
C++:
#include <string>
#include <zlib.h>
#include <iostream>
#include <fstream>
#include <sstream>

#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

void bdecrypt(uint8_t *buffer, int len, uint64_t k)
{
uint32_t const key[4] = {(uint32_t)(k >> 32), (uint32_t)(k & 0xFFFFFFFF), 0xDEADDEAD, 0xB00BEEEF};
uint32_t y, z, sum;
uint32_t *v = (uint32_t *) buffer;
unsigned p, rounds, e;
int n = (len - len % 4) / 4;
if (n < 2) {
 return;
    }
rounds = 6 + 52 / n;
sum = rounds * DELTA;
y = v[0];
 do {
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--) {
z = v[p - 1];
y = v[p] -= MX;
        }
z = v[n - 1];
y = v[0] -= MX;
 sum -= DELTA;
} while (--rounds);
}

int m_customEncryption = 0;

bool decryptBuffer(std::string &buffer)
{
if (buffer.size() < 5) {
 return true;
    }

if (buffer.substr(0, 4).compare("ENC3") != 0) {
 return false;
    }

uint64_t key = *(uint64_t * ) & buffer[4];
uint32_t compressed_size = *(uint32_t * ) & buffer[12];
uint32_t size = *(uint32_t * ) & buffer[16];
uint32_t adler = *(uint32_t * ) & buffer[20];

if (compressed_size < buffer.size() - 24) {
 return false;
    }

bdecrypt((uint8_t * ) & buffer[24], compressed_size, key);
std::string new_buffer;
new_buffer.resize(size);
unsigned long new_buffer_size = new_buffer.size();
if (uncompress((uint8_t *) new_buffer.data(), &new_buffer_size, (uint8_t * ) & buffer[24], compressed_size)
        != Z_OK) {
 return false;
    }

buffer = new_buffer;
 return true;
}

int main()
{
std::string data("");

std::ifstream t("/bin/init.lua");
std::stringstream buffer;
buffer << t.rdbuf();
data = buffer.str();

if (decryptBuffer(data)) {
std::cout << "WORKED" << std::endl;
std::cout << data << std::endl;
} else {
std::cout << "FAILED" << std::endl;
    }
return 0;
}
In my test-case, it was docker container that copied file init.lua (/bin/init.lua inside container) inside docker and decrypted it into file.lua using:
Code:
docker build . -t test && docker run test > file.lua
 
Someone told me - on Discord - that he has decompiler for Lua compiler, but did not post link to it yet. Just told me to use Luraph (https://lura.ph/) to secure OTS files.
Can you decompile included textedit.lua from Askara v4 and post what you get?

@Jpstafe
Included my single file OTCv8-decrypt I've made on weekend.
Loads init.lua (ex. Askara v4 init.lua) and decrypts it into file.lua using Docker:
Code:
docker build . -t test && docker run test > file.lua
You can put Tibia.spr contents in place of init.lua and it will decrypt it into file.lua with decrypted Tibia.spr content (or edit Dockerfile).
 

Attachments

@kor
Looks like OTCv8 encrypted content.
So now only servers that paid for OTCv8 encryption - custom encryption - are safe from basic file decryption.
 
Someone told me - on Discord - that he has decompiler for Lua compiler, but did not post link to it yet. Just told me to use Luraph (https://lura.ph/) to secure OTS files.
Can you decompile included textedit.lua from Askara v4 and post what you get?

@Jpstafe
Included my single file OTCv8-decrypt I've made on weekend.
Loads init.lua (ex. Askara v4 init.lua) and decrypts it into file.lua using Docker:
Code:
docker build . -t test && docker run test > file.lua
You can put Tibia.spr contents in place of init.lua and it will decrypt it into file.lua with decrypted Tibia.spr content (or edit Dockerfile).
incredible tool, how to use with other files_ i tried for example decrypt files from my client and it decrypted init.lua but not other lua files even if i renamed them as init.lua
 
I want someone to help me hide my .dat .spr files from custom client.
I interested and pay for it

I think to create only a archive .exe that compress the files.
But is possible do it without risk of malware?
Thanks
 
Last edited:
incredible tool, how to use with other files_ i tried for example decrypt files from my client and it decrypted init.lua but not other lua files even if i renamed them as init.lua
Files need to be compied into container or you could use docker volumes for that, see Dockerfile:
Lua:
COPY init.lua /bin/init.lua
 
In case you would need not 100% secure encryption for Cipsoft client, please contact me, so I might be able to help you aswell.
Is possible to encrypt it at 100% works till clients 13x , giving an error while trying to read it and you cannot open it with any kind of program
 
For anyone finding it hard to add OTCv8 encryption or are looking for an alternative there's also this Option for loading data/modules/init.lua from encrypted zip · Source61/otclient-encrypted@ce7eb31 (https://github.com/Source61/otclient-encrypted/commit/ce7eb31b929be27e0c418a24884512be98ee1b4d)
This encryption method was made directly for edubart otclient and should be easier to implement.
The password is trivial to decrypt if stored as a string literal ("abcdefg") but should be harder to find and read if generated in complicated ways, even using string.push_back(char) is safer than a string literal since it won't pop up in the string literal window in Ghidra or likely Ida either.
 
@NvSo Remember that LuaJIT bytecodes varies between versions and build modes (GC64) so remember to use same version.
Regarding your issue, how did you get that error (and when/where do you see it)?


Python:
def _read_prototypes(state, prototypes):
    while not state.stream.eof():
        prototype = ljd.bytecode.prototype.Prototype()

        if not ljd.rawdump.prototype.read(state, prototype):
            if state.stream.eof():
                break
            else:
                errprint("Failed to read prototype")
                return False

        prototypes.append(prototype)

    return True

Maybe it's not simple luac but also encrypted?
 
Back
Top