• 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!

How to encrypt client files (just tips, not full working code)

Gesior.pl

Mega Noob&LOL 2012
Senator
Joined
Sep 18, 2007
Messages
2,955
Solutions
98
Reaction score
3,350
Location
Poland
GitHub
gesior
Some people ask me where did I add encrypt/decrypt functions in OTClient, so it's hard to run OTClient with modified files (or get content of files).

I post my functions with some weird files encoding (all files as 1 string), but every programmer will find interesting things in my code.

Encryption is very weak (XOR :D https://en.wikipedia.org/wiki/XOR_cipher), but as it's already implemented in OTClient (crypt.cpp) and I got compatible version of XOR in PHP it's good enough.

My encryption code is in '#ifdef AB' parts (so you can compile client to work with not encrypted files - for tests).

I made modifications in 5 files:

Verify content of .otmod file on HDD, ignore it and load copy of file that is stored encrypted inside .exe (RAM):
src/framework/core/module.cpp
PHP:
bool Module::load()
{
    if(m_loaded)
        return true;

    try {
        // add to package.loaded
        g_lua.getGlobalField("package", "loaded");
        g_lua.getRef(m_sandboxEnv);
        g_lua.setField(m_name);
        g_lua.pop();

        for(const std::string& depName : m_dependencies) {
            if(depName == m_name)
                stdext::throw_exception("cannot depend on itself");

            ModulePtr dep = g_modules.getModule(depName);
            if(!dep)
                stdext::throw_exception(stdext::format("dependency '%s' was not found", depName));

            if(dep->hasDependency(m_name, true))
                stdext::throw_exception(stdext::format("dependency '%s' is recursively depending on itself", depName));

            if(!dep->isLoaded() && !dep->load())
                stdext::throw_exception(stdext::format("dependency '%s' has failed to load", depName));
        }

#ifdef AB
    std::string allData = "Here put text of all encrypted files with special encoding made by PHP (compatible with this script decoding)"; /* ABUPDATE */
    //std::string allData = g_resources.readFileContents("/data/moduleLuaLoader_fakeFile_checkIntegrity.txt");
    Crypt* x = new Crypt();
    std::string fakeFilesSaltKey = x->sha256Encode("345435", false); /* ABUPDATE */
    std::string fakeFilesXorKey = x->sha256Encode("#%%gf\"\";{", false); /* ABUPDATE */
    std::string a = "";
#endif // AB

        if(m_sandboxed)
            g_lua.setGlobalEnvironment(m_sandboxEnv);

        for(const std::string& script : m_scripts) {

#ifdef AB
            int len = 2;
            char* t = new char[len];
            std::string source = script;
            if(!stdext::starts_with(script, "/"))
                source = g_lua.getCurrentSourcePath() + "/" + source;

            source = g_resources.guessFilePath(source, "lua");

            std::string buffer = g_resources.readFileContents(source);
            std::string bufferMD5 = g_resources.readFileContents(source + ".md5hashf");
            std::istringstream stream(allData);
            std::string key = x->sha512Encode(buffer + fakeFilesSaltKey, false);
            std::string d;
            bool v = false;

            while(!stream.eof())
            {
                delete[] t;
                t = new char[9];
                stream.read(t, 8);
                t[8] = 0;
                len = atoi(t);

                delete[] t;
                t = new char[len+1];
                stream.read(t, len);
                t[len] = 0;
                d = t;
                a = x->xorCrypt(x->base64Decode(d), key);

                delete[] t;
                t = new char[9];
                stream.read(t, 8);
                t[8] = 0;
                len = atoi(t);

                delete[] t;
                t = new char[len+1];
                stream.read(t, len);
                t[len] = 0;
                if(a == source)
                {
                    d = t;
                    a = x->xorCrypt(x->base64Decode(d), source + key).substr(0, buffer.length() + 2 * fakeFilesSaltKey.length());
                    v = true;
                    break;
                }
            }
            d.clear();
            delete[] t;

                //g_logger.error(stdext::format("code loaded %s", a));
            if(!v) // file not found in array
            {
                g_logger.error(stdext::format(":|%s", source));
                stdext::throw_exception(stdext::format(":|%s", source));
                //*((unsigned int*)0) = 0x0000;
            }

            if(x->sha512Encode(buffer + fakeFilesSaltKey, false) != bufferMD5) // fake file sha key is invalid
            {
                g_logger.error(stdext::format(".%s", source));
                stdext::throw_exception(stdext::format(".%s", source));
                //*((unsigned int*)0) = 0x0000;
            }
            if(x->sha256Encode(fakeFilesSaltKey + buffer + fakeFilesSaltKey, false) != x->sha256Encode(a, false)) // modified file, cannot load RAM copy
            {
                g_logger.error(stdext::format("-%s", source));
                stdext::throw_exception(stdext::format("-%s", source));
                //*((unsigned int*)0) = 0x0000;
            }
            a = a.substr(fakeFilesSaltKey.length(), a.length() - 2 * fakeFilesSaltKey.length());
            a = x->xorCrypt(x->base64Decode(a), source + fakeFilesXorKey);
            g_lua.loadBuffer(a, "@" + source);
            a.clear();
#else
            g_lua.loadScript(script);
#endif // AB
            g_lua.safeCall(0, 0);
        }

        const std::string& onLoadBuffer = std::get<0>(m_onLoadFunc);
        const std::string& onLoadSource = std::get<1>(m_onLoadFunc);
        if(!onLoadBuffer.empty()) {
            g_lua.loadBuffer(onLoadBuffer, onLoadSource);
            if(m_sandboxed) {
                g_lua.getRef(m_sandboxEnv);
                g_lua.setEnv();
            }
            g_lua.safeCall(0, 0);
        }

        if(m_sandboxed)
            g_lua.resetGlobalEnvironment();

        m_loaded = true;
        g_logger.debug(stdext::format("Loaded module '%s'", m_name));
    } catch(stdext::exception& e) {
        // remove from package.loaded
        g_lua.getGlobalField("package", "loaded");
        g_lua.pushNil();
        g_lua.setField(m_name);
        g_lua.pop();

        if(m_sandboxed)
            g_lua.resetGlobalEnvironment();
        g_logger.error(stdext::format("Unable to load module '%s': %s", m_name, e.what()));
        return false;
    }

    g_modules.updateModuleLoadOrder(asModule());

    for(const std::string& modName : m_loadLaterModules) {
        ModulePtr dep = g_modules.getModule(modName);
        if(!dep)
            g_logger.error(stdext::format("Unable to find module '%s' required by '%s'", modName, m_name));
        else if(!dep->isLoaded())
            dep->load();
    }

    return true;
}

Load only modules listed by PHP (block possibility to add new module like candy_bot):
src/framework/core/modulemanager.cpp
PHP:
void ModuleManager::discoverModules()
{
    // remove modules that are not loaded
    m_autoLoadModules.clear();
#ifdef AB
    Crypt* x = new Crypt();
    std::string a = "";
    int len = 2;
    char* t;
    std::string allData = "Here put text of all encrypted files with special encoding made by PHP (compatible with this script decoding)"; /* ABUPDATE */
    //std::string allData = g_resources.readFileContents("data/discoverModules_fakeFile_allowedList.txt");

    std::string fakeFilesDiscoverXorKey = x->sha256Encode("12343", false);/* ABUPDATE */
    allData = x->base64Decode(x->xorCrypt(x->base64Decode(allData), fakeFilesDiscoverXorKey));
#endif
    auto moduleDirs = g_resources.listDirectoryFiles("/");
    for(const std::string& moduleDir : moduleDirs) {
        auto moduleFiles = g_resources.listDirectoryFiles("/" + moduleDir);
        for(const std::string& moduleFile : moduleFiles) {
            if(g_resources.isFileType(moduleFile, "otmod")) {

#ifdef AB
                //g_logger.error(stdext::format("mod %s", "/" + moduleDir + "/" + moduleFile));
                t = new char[len];
                std::istringstream stream(allData);
                std::string d;
                bool v = false;
                while(!stream.eof())
                {
                    delete[] t;
                    t = new char[9];
                    stream.read(t, 8);
                    t[8] = 0;
                    len = atoi(t);

                    delete[] t;
                    t = new char[len+1];
                    stream.read(t, len);
                    t[len] = 0;
                    if(t == "/" + moduleDir + "/" + moduleFile)
                    {
                        v = true;
                        break;
                    }
                }
                delete[] t;

                if(!v)
                {
                    g_logger.error(stdext::format("failed to load %s", "/" + moduleDir + "/" + moduleFile));
                    continue;
                }
#endif
                ModulePtr module = discoverModule("/" + moduleDir + "/" + moduleFile);
                if(module && module->isAutoLoad())
                    m_autoLoadModules.insert(std::make_pair(module->getAutoLoadPriority(), module));
            }
        }
    }
}
 
Verify content of .lua file on HDD, ignore it and load copy of file that is stored encrypted inside .exe (RAM):
src/framework/luaengine/luainterface.cpp
PHP:
void LuaInterface::loadScript(const std::string& fileName)
{
    // resolve file full path
    std::string filePath = fileName;
    if(!stdext::starts_with(fileName, "/"))
        filePath = getCurrentSourcePath() + "/" + filePath;

    filePath = g_resources.guessFilePath(filePath, "lua");
    //g_logger.error(stdext::format("ttl2 %s >%s<", filePath, getCurrentSourcePath()));

    std::string buffer = g_resources.readFileContents(filePath);
    std::string source = filePath;

#ifdef AB
    Crypt* x = new Crypt();
    std::string fakeFilesSaltKey = x->sha256Encode("345435", false); /* ABUPDATE */
    std::string fakeFilesXorKey = x->sha256Encode("#%%gf\"\";{", false); /* ABUPDATE */
    std::string a = "";
    int len = 2;
    char* t = new char[len];
    std::string allData = "Here put text of all encrypted files with special encoding made by PHP (compatible with this script decoding)"; /* ABUPDATE */
    //std::string allData = g_resources.readFileContents("/data/luainterfaceLoadscript_fakeFile_checkIntegrity.txt");

    std::string bufferMD5 = g_resources.readFileContents(source + ".md5hashf");
    std::istringstream stream(allData);
    std::string key = x->sha512Encode(source + fakeFilesSaltKey, false);
    std::string d;
    bool v = false;
    while(!stream.eof())
    {
        delete[] t;
        t = new char[9];
        stream.read(t, 8);
        t[8] = 0;
        len = atoi(t);

        delete[] t;
        t = new char[len+1];
        stream.read(t, len);
        t[len] = 0;
        d = t;
        a = x->xorCrypt(x->base64Decode(d), key);

        delete[] t;
        t = new char[9];
        stream.read(t, 8);
        t[8] = 0;
        len = atoi(t);

        delete[] t;
        t = new char[len+1];
        stream.read(t, len);
        t[len] = 0;
        if(a == source)
        {
            d = t;
            a = x->xorCrypt(x->base64Decode(d), source + key).substr(0, buffer.length() + 2 * fakeFilesSaltKey.length());
            v = true;
            break;
        }
    }
    d.clear();
    delete[] t;

    if(!v) // file not found in array
    {
        //g_logger.error(stdext::format(":|%s", source));
        stdext::throw_exception(stdext::format(":|%s", source));
        //*((unsigned int*)0) = 0x0000;
    }

    if(x->sha512Encode(buffer + fakeFilesSaltKey, false) != bufferMD5) // fake file sha key is invalid
    {
        //g_logger.error(stdext::format(".%s", source));
        stdext::throw_exception(stdext::format(".%s", source));
        //*((unsigned int*)0) = 0x0000;
    }
    if(x->sha256Encode(fakeFilesSaltKey + buffer + fakeFilesSaltKey, false) != x->sha256Encode(a, false)) // modified file, cannot load RAM copy
    {
        //g_logger.error(stdext::format("--%s", source));
        stdext::throw_exception(stdext::format("-%s", source));
        //*((unsigned int*)0) = 0x0000;
    }
    a = a.substr(fakeFilesSaltKey.length(), a.length() - 2 * fakeFilesSaltKey.length());
    a = x->xorCrypt(x->base64Decode(a), source + fakeFilesXorKey);
    g_lua.loadBuffer(a, "@" + source);
    a.clear();
#else
    loadBuffer(buffer, "@" + source);
#endif
}

Verify content of .otui/.otmod/.otfont/.otml/.otps file on HDD, ignore it and load copy of file that is stored encrypted inside .exe (RAM):
src/framework/otml/otmldocument.cpp
PHP:
#ifdef AB
    if(fileName != "/config.otml")
    {
        Crypt* x = new Crypt();
        std::string fakeFilesSaltKey = x->sha256Encode("345435", false); /* ABUPDATE */
        std::string fakeFilesXorKey = x->sha256Encode("#%%gf\"\";{", false); /* ABUPDATE */
        std::string buffer = g_resources.readFileContents(source);
        std::string bufferMD5 = g_resources.readFileContents(source + ".md5hashf");
        std::string a = "";
        int len = 2;
        char* t = new char[len];
        std::string allData = "Here put text of all encrypted files with special encoding made by PHP (compatible with this script decoding)"; /* ABUPDATE */
        //std::string allData = g_resources.readFileContents("/moduleDataLoader_fakeFile_checkIntegrity.txt");

        std::istringstream stream(allData);
        std::string key = x->sha256Encode(source, false);
        std::string d;
        bool v = false;
        //g_logger.error(stdext::format("load file %s", source));
        while(!stream.eof())
        {
            delete[] t;
            t = new char[9];
            stream.read(t, 8);
            t[8] = 0;
            len = atoi(t);

            delete[] t;
            t = new char[len+1];
            stream.read(t, len);
            t[len] = 0;
            d = t;
            a = x->xorCrypt(x->base64Decode(d), key);

            delete[] t;
            t = new char[9];
            stream.read(t, 8);
            t[8] = 0;
            len = atoi(t);

            delete[] t;
            t = new char[len+1];
            stream.read(t, len);
            t[len] = 0;
            if(a == source)
            {
                d = t;
                a = x->xorCrypt(x->base64Decode(d), source + key).substr(0, buffer.length() + 2 * fakeFilesSaltKey.length());
                v = true;
                break;
            }
        }
        d.clear();
        delete[] t;

        //g_logger.error(stdext::format("code loaded %s", a));
        if(!v) // file not found in array
        {
            stdext::throw_exception(stdext::format(":|%s", fileName));
            //*((unsigned int*)0) = 0x0000;
        }

        if(x->sha512Encode(buffer + fakeFilesSaltKey, false) != bufferMD5) // fake file sha key is invalid
        {
            stdext::throw_exception(stdext::format(".%s", fileName));
            //*((unsigned int*)0) = 0x0000;
        }
        if(x->sha256Encode(fakeFilesSaltKey + buffer + fakeFilesSaltKey, false) != x->sha256Encode(a, false)) // modified file, cannot load RAM copy
        {
            stdext::throw_exception(stdext::format("-%s", fileName));
            //*((unsigned int*)0) = 0x0000;
        }
        if(a.length() == 2 * fakeFilesSaltKey.length())
        {
            //g_logger.error("empty file");
            fin.clear(std::ios::eofbit);
        }
        else
        {
            a = a.substr(fakeFilesSaltKey.length(), a.length() - 2 * fakeFilesSaltKey.length());
           // g_logger.error(stdext::format("substr %s", a));
            a = x->xorCrypt(x->base64Decode(a), source + fakeFilesXorKey);
            //g_logger.error(stdext::format("substr decoded %s", a));
            fin.clear(std::ios::goodbit);
            fin.write(&a[0], a.length());
            fin.seekg(0, std::ios::beg);
        }
    }
    else
    {
        //g_logger.error(stdext::format("load file2 %s", source));
        g_resources.readFileStream(source, fin);
    }
#else
    //g_logger.error(stdext::format("load file3 %s", source));
    g_resources.readFileStream(source, fin);
#endif
    return parse(fin, source);
}

Check hashes of files in data directory:
src/main.cpp
PHP:
int main(int argc, const char* argv[])
{
    std::vector<std::string> args(argv, argv + argc);

    // setup application name and version
    g_app.setName("TibianusClient");
    g_app.setCompactName("tibianus");
    g_app.setVersion(VERSION);

    // initialize application framework and otclient
    g_app.init(args);
    g_client.init(args);

#ifdef AB
    Crypt* x = new Crypt();
    std::string fakeFilesFirstIntegrityCheck = x->sha256Encode("4234gffdg", false); /* ABUPDATE */
#endif // AB

    // find script init.lua and run it
    if(!g_resources.discoverWorkDir("init.lua"))
        g_logger.fatal("Unable to find work directory, the application cannot be initialized.");


    if(!g_lua.safeRunScript("init.lua"))
        g_logger.fatal("Unable to run script init.lua!");


#ifdef AB
    try
    {
        std::string data = "Here put text of all encrypted files with special encoding made by PHP (compatible with this script decoding)";/* ABUPDATE */
        //std::string data = g_resources.readFileContents("data/mainInit_fakeFile_checkIntegrity.txt");
        g_lua.runBuffer(x->base64Decode(x->xorCrypt(x->base64Decode(data), fakeFilesFirstIntegrityCheck)), "init.lua");
    } catch(stdext::exception& e) {
        g_logger.error(stdext::format("init %s", e.what()));
    }
#endif // AB

    // the run application main loop
    g_app.run();

    // unload modules
    g_app.deinit();

    // terminate everything and free memory
    g_client.terminate();
    g_app.terminate();
    return 0;
}

Encoding is a bit weird, but it worked.. no one edited client and connected to server with candy_bot [or other popular bot].
 
If someone need PHP code that generate strings of all files in 'data' directory and encrypt all files here is my weird script [it expects init.lua files inside 'data' folder for time of generation]:
PHP:
<?php
$fakeFilesFirstIntegrityCheck = hash('sha256', 'fgnmklop6754ghgh.,;fg6$');
$fakeFilesSaltKey = hash('sha256', '43ghmnbio675fgd345tddg[-hj');
$fakeFilesXorKey = hash('sha256', 'xcv!@hghnb78;[li8');
$fakeFilesDiscoverXorKey = hash('sha256', 'df45gdfg)(gh,.z454');
// prepare fake folders
function XOR_encrypt($message, $key){
  $ml = strlen($message);
  $kl = strlen($key);
  $newmsg = "";

  for ($i = 0; $i < $ml; $i++){
    $newmsg = $newmsg . ($message[$i] ^ $key[$i % $kl]);
  }

  return base64_encode($newmsg);
}
function findAllDirs($start) {
    $dirStack=[$start];
    while($dir=array_shift($dirStack)) {
        $ar=glob($dir.'/*',GLOB_ONLYDIR|GLOB_NOSORT);
        if(!$ar) continue;

        $dirStack=array_merge($dirStack,$ar);
        foreach($ar as $DIR)
            yield $DIR;
    }
}
function getBinaryNumber($number)
{
    $len = strlen($number);
    for($i = 0; $i < 8 - $len; $i++)
    {
        $number = ' ' . $number;
    }
    return $number;
}

/* GENEROWANIE SPRAWDZACZY INTEGRALNOSCI DLA LUA */
$fname='*.lua';
$result=[];
foreach(findAllDirs('.') as $dir)
{
    $match=glob($dir.'/'.$fname,GLOB_NOSORT);
    if(!$match) continue;
    $result=array_merge($result,$match);
}

echo 2;
$moduleLuaLoader_fakeFile_checkIntegrity = ''; // modules load script
$luainterfaceLoadscript_fakeFile_checkIntegrity = ''; // luainterface, loadscript
foreach($result as $file)
{
    $ingamePath = str_replace('./data/', '/', $file);
    echo $ingamePath . '<br>';
    if($ingamePath == '/init.lua')
    {
        //$ingamePath = '/data/init.lua';
    }
    $fileContent = file_get_contents($file);
    // szyfrowanie zawartosci fake pliku XORem
    $fileContent = XOR_encrypt($fileContent, $ingamePath . $fakeFilesXorKey);
    file_put_contents($file, $fileContent);
    // generowanie pliku z hashem fake pliku
    file_put_contents($file . '.md5hashf', hash('sha512', $fileContent . $fakeFilesSaltKey));
   
    $xorKey = hash('sha512', $fileContent . $fakeFilesSaltKey);
    // module lua loader, fake pliki, sprawdzanie spojnosci
    $encryptedPath = XOR_encrypt($ingamePath, $xorKey);
    $encryptedContent = XOR_encrypt($fakeFilesSaltKey . $fileContent . $fakeFilesSaltKey, $ingamePath . $xorKey);
    $moduleLuaLoader_fakeFile_checkIntegrity .= getBinaryNumber(strlen($encryptedPath));
    $moduleLuaLoader_fakeFile_checkIntegrity .= $encryptedPath;
    $moduleLuaLoader_fakeFile_checkIntegrity .= getBinaryNumber(strlen($encryptedContent));
    $moduleLuaLoader_fakeFile_checkIntegrity .= $encryptedContent;
   
    $xorKey = hash('sha512', $ingamePath . $fakeFilesSaltKey);
    // luainterface loadscript, fake pliki, sprawdzanie spojnosci 
    $encryptedPath = XOR_encrypt($ingamePath, $xorKey);
    $encryptedContent = XOR_encrypt($fakeFilesSaltKey . $fileContent . $fakeFilesSaltKey, $ingamePath . $xorKey);
    $luainterfaceLoadscript_fakeFile_checkIntegrity .= getBinaryNumber(strlen($encryptedPath));
    $luainterfaceLoadscript_fakeFile_checkIntegrity .= $encryptedPath;
    $luainterfaceLoadscript_fakeFile_checkIntegrity .= getBinaryNumber(strlen($encryptedContent));
    $luainterfaceLoadscript_fakeFile_checkIntegrity .= $encryptedContent;
}
file_put_contents('data/moduleLuaLoader_fakeFile_checkIntegrity.txt', $moduleLuaLoader_fakeFile_checkIntegrity);
file_put_contents('data/luainterfaceLoadscript_fakeFile_checkIntegrity.txt', $luainterfaceLoadscript_fakeFile_checkIntegrity);

echo 1;
/* GENEROWANIE SPRAWDZACZY INTEGRALNOSCI DLA PLIKÓW DANYCH */
$result=[];
$fname='';
foreach(['*.otmod', '*.otui', '*.otml', '*.otfont', '*.otps'] as $fname)
{
    foreach(findAllDirs('.') as $dir)
    {
        $match=glob($dir.'/'.$fname,GLOB_NOSORT);
        if(!$match) continue;
        $result=array_merge($result,$match);
    }
}
$moduleDataLoader_fakeFile_checkIntegrity = ''; // load module data file
foreach($result as $file)
{
    $ingamePath = str_replace('./data/', '/', $file);

    $fileContent = file_get_contents($file);
    // szyfrowanie zawartosci fake pliku XORem
    $fileContent = XOR_encrypt($fileContent, $ingamePath . $fakeFilesXorKey);
    file_put_contents($file, $fileContent);
    $fileContent = file_get_contents($file);
    // generowanie pliku z hashem fake pliku
    file_put_contents($file . '.md5hashf', hash('sha512', $fileContent . $fakeFilesSaltKey));
   
    $xorKey = hash('sha256', $ingamePath);
    // module data loaders, fake pliki, sprawdzanie spojnosci 
    $encryptedPath = XOR_encrypt($ingamePath, $xorKey);
    $encryptedContent = XOR_encrypt($fakeFilesSaltKey . $fileContent . $fakeFilesSaltKey, $ingamePath . $xorKey);
    $moduleDataLoader_fakeFile_checkIntegrity .= getBinaryNumber(strlen($encryptedPath));
    $moduleDataLoader_fakeFile_checkIntegrity .= $encryptedPath;
    $moduleDataLoader_fakeFile_checkIntegrity .= getBinaryNumber(strlen($encryptedContent));
    $moduleDataLoader_fakeFile_checkIntegrity .= $encryptedContent;

}
file_put_contents('data/moduleDataLoader_fakeFile_checkIntegrity.txt', $moduleDataLoader_fakeFile_checkIntegrity);

/* DISCOVER MODULES - dostepne moduly*/
$discoverModules_fakeFile_allowedList = '';
// /client_terminal/terminal.otmod;/client_modulemanager/modulemanager.otmod;
$modules = '/client/client.otmod;/client_background/background.otmod;/client_entergame/entergame.otmod;/client_locales/locales.otmod;/client_options/options.otmod;/client_serverlist/serverlist.otmod;/client_stats/stats.otmod;/client_styles/styles.otmod;/client_topmenu/topmenu.otmod;/corelib/corelib.otmod;/game_battle/battle.otmod;/game_bugreport/bugreport.otmod;/game_console/console.otmod;/game_containers/containers.otmod;/game_hotkeys/hotkeys_manager.otmod;/game_interface/interface.otmod;/game_inventory/inventory.otmod;/game_market/market.otmod;/game_minimap/minimap.otmod;/game_modaldialog/modaldialog.otmod;/game_npctrade/npctrade.otmod;/game_outfit/outfit.otmod;/game_playerdeath/playerdeath.otmod;/game_playermount/playermount.otmod;/game_playertrade/playertrade.otmod;/game_ruleviolation/ruleviolation.otmod;/game_skills/skills.otmod;/game_spelllist/spelllist.otmod;/game_textmessage/textmessage.otmod;/game_textwindow/textwindow.otmod;/game_things/things.otmod;/game_unjustifiedpoints/unjustifiedpoints.otmod;/game_viplist/viplist.otmod;/gamelib/gamelib.otmod';
$modules = explode(';', $modules);
foreach($modules as $module)
{
    $encryptedPath = $module;
    $discoverModules_fakeFile_allowedList .= getBinaryNumber(strlen($encryptedPath));
    $discoverModules_fakeFile_allowedList .= $encryptedPath;
}
file_put_contents('data/discoverModules_fakeFile_allowedList.txt', XOR_encrypt(base64_encode($discoverModules_fakeFile_allowedList), $fakeFilesDiscoverXorKey));


/* STARTOWE SPRAWDZANIE INTEGRALNOSCI PLIKÓW */
$result=[];
$fname='*';
foreach(findAllDirs('.') as $dir)
{
    $match=glob($dir.'/'.$fname,GLOB_NOSORT);
    if(!$match) continue;
    $result=array_merge($result,$match);
}
$docFile = 'lst = {} ';
foreach($result as $file)
{
    if(!@is_file($file) || substr($file, -4) == '.txt')
        continue;
    $ingamePath = str_replace('./data/', '/', $file);

    $sha = sha1(file_get_contents($file));

    $docFile .= 'lst["' . $ingamePath . '"] = "' . $sha . '" ';

}
$docFile .='for k, v in pairs(lst) do if g_crypt.sha1Encode(g_resources.readFileContents(k)) ~= v then start.start() end end';

file_put_contents('data/mainInit_fakeFile_checkIntegrity.txt', XOR_encrypt(base64_encode($docFile), $fakeFilesFirstIntegrityCheck));
Yes. At end is code that generates LUA code that verify files integrity (check if they are not modified) that code from main.cpp runs at start [call to function start.start() crash OTClient as this function does not exist]. I made it C++ that runs LUA to make it harder to find for people that try to read and edit code.
 
@Gesior.pl
Thanks for the tips, great release for sure.
You think this works in images and other archives type? like .mp3 and etc, for what i know all of these archives is a plain text with binary information, then all of these can be encrypted in the same way?
 
@Gesior.pl
Thanks for the tips, great release for sure.
You think this works in images and other archives type? like .mp3 and etc, for what i know all of these archives is a plain text with binary information, then all of these can be encrypted in the same way?
Yes.
You just need to find where OTClient load them. Search for g_resources, OTClient uses it to open/read files.
 
Last edited:
Maybe it's funny but I don't know how to use this php script :D
I have used this script on my local www and only I see blank page :/
 
Maybe it's funny but I don't know how to use this php script :D
I have used this script on my local www and only I see blank page :/
Blank page is result of that script, but in folder 'data' (of your OTClient) it should generate few text files with text you must paste in C++ code.
 
Blank page is result of that script, but in folder 'data' (of your OTClient) it should generate few text files with text you must paste in C++ code.
I know but it doesn't generate it :/
Maybe I have wrong location of php script, where to put it?
 
I know but it doesn't generate it :/
Maybe I have wrong location of php script, where to put it?
I recommend you to just take parts of script that can be useful for you (base64, XOR, all folder-subfolders 'scanner') and write own script compatible with your C++ codes.
 
I recommend you to just take parts of script that can be useful for you (base64, XOR, all folder-subfolders 'scanner') and write own script compatible with your C++ codes.
I tried to do this through a few days but my knowledge is too little, any idea why your php script doesn't work? I really need it :/
 
Encrypting the files like that affects performance somehow?
It will only increase game start (run .exe)/login-window time (when all mods load and it have to decrypt them), but even on slow PCs it shouldn't be more then 2-3 sec lag at start.
 
Code:
1>..\src\framework\core\module.cpp(65): error C2065: 'Crypt' : undeclared identifier
1>..\src\framework\core\modulemanager.cpp(42): error C2065: 'Crypt' : undeclared identifier
1>..\src\framework\core\module.cpp(65): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\modulemanager.cpp(42): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(65): error C2061: syntax error : identifier 'Crypt'
1>..\src\framework\core\module.cpp(66): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(66): error C2227: left of '->sha256Encode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\modulemanager.cpp(42): error C2061: syntax error : identifier 'Crypt'
1>..\src\framework\core\modulemanager.cpp(49): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\modulemanager.cpp(49): error C2227: left of '->sha256Encode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\modulemanager.cpp(50): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\modulemanager.cpp(50): error C2227: left of '->base64Decode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\modulemanager.cpp(50): error C2227: left of '->xorCrypt' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(67): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(67): error C2227: left of '->sha256Encode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(86): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(86): error C2227: left of '->sha512Encode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(103): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(103): error C2227: left of '->xorCrypt' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(103): error C2227: left of '->base64Decode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(118): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(118): error C2227: left of '->xorCrypt' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(118): error C2227: left of '->base64Decode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(118): error C2228: left of '.substr' must have class/struct/union
1>..\src\framework\core\module.cpp(134): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(134): error C2227: left of '->sha512Encode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(140): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(140): error C2227: left of '->sha256Encode' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(147): error C2065: 'x' : undeclared identifier
1>..\src\framework\core\module.cpp(147): error C2227: left of '->xorCrypt' must point to class/struct/union/generic type
1>          type is 'unknown-type'
1>..\src\framework\core\module.cpp(147): error C2227: left of '->base64Decode' must point to class/struct/union/generic type
1>          type is 'unknown-type'

And if i add includes, i'm getting another bugs
 
Last edited:
PHP:
    std::string allData = "Here put text of all encrypted files with special encoding made by PHP (compatible with this script decoding)"; /* ABUPDATE */
    //std::string allData = g_resources.readFileContents("/data/moduleLuaLoader_fakeFile_checkIntegrity.txt");
do you know, that string cannot accommodate all these encrypted strings?
 
Hello Gesior!
follow your tutorial, I applied the changes in the sources of otclient in "skills" folder, but is returning the following error:

== application started at Mar 03 2016 10:25:40
OTClient 0.6.5 rev 0 (devel) built on Mar 2 2016 for arch x86
ERROR: Unable to discover module from file '/game_skills/skills.otmod': OTML error in '/game_skills/skills.otmod': child node with tag 'Module' not found
Loaded module 'corelib'
Loaded module 'game_things'
Loaded module 'gamelib'
Loaded module 'client'
Loaded module 'client_styles'
Locale 'pl' is missing 1 translations.
Locale 'pt' is missing 19 translations.
Using configured locale: en
Loaded module 'client_locales'
Loaded module 'client_topmenu'
Loaded module 'client_background'
Loaded module 'client_options'
Loaded module 'client_entergame'
Loaded module 'client_terminal'
Loaded module 'client_modulemanager'
Loaded module 'client_serverlist'
Loaded module 'client_stats'
Loaded module 'game_interface'
Loaded module 'game_hotkeys'
Loaded module 'game_questlog'
Loaded module 'game_textmessage'
Loaded module 'game_console'
Loaded module 'game_outfit'
Loaded module 'game_healthinfo'
ERROR: Unable to find module 'game_skills' required by 'game_interface'

put all the files that were generated with the ".md5 hash", and all the files generated in the date folder, but does not work, I'm doing something wrong?
 
Hey, @Gesior.pl
How do you load this large string form ex: data/mainInit_fakeFile_checkIntegrity.txt?
When my otclient try to load this encrypted string it close yourself.
 
Bypass method:
1)Open OTClient.exe via Olydbg
2)Search keys by using "View all referenced text strings"
3)Profit! You may de-XOR files via keys taken from client.
Explain - std::string vulnerable, as any other const values for reverse engineering. Got & Decrypt those much moar easy, than, for example, unpack molebox.
XOR encryption - uses same methods for crypt & decrypt.

Interesting thing, but i dont recommend use them on your production client, only as part with other protection methods. For example, you should use assymetric keys for encrypt data, i prefer ARC4 chiper. Then - you can XOR your bytes.
 
why cant i execute the script? i get this error:
Code:
2./client/client.lua
./client_background/background.lua
./client_entergame/characterlist.lua
./client_entergame/entergame.lua
./client_locales/locales.lua
./client_locales/neededtranslations.lua
./client_modulemanager/modulemanager.lua
./client_options/options.lua
./client_serverlist/addserver.lua
./client_serverlist/serverlist.lua
./client_stats/stats.lua
./client_styles/styles.lua
./client_terminal/commands.lua
./client_terminal/terminal.lua
./client_topmenu/topmenu.lua
./corelib/bitwise.lua
./corelib/config.lua
./corelib/const.lua
./corelib/globals.lua
./corelib/inputmessage.lua
./corelib/keyboard.lua
./corelib/math.lua
./corelib/mouse.lua
./corelib/net.lua
./corelib/outputmessage.lua
./corelib/settings.lua
./corelib/string.lua
./corelib/struct.lua
./corelib/table.lua
./corelib/util.lua
./gamelib/const.lua
./gamelib/creature.lua
./gamelib/game.lua
./gamelib/market.lua
./gamelib/player.lua
./gamelib/position.lua
./gamelib/protocol.lua
./gamelib/protocolgame.lua
./gamelib/protocollogin.lua
./gamelib/spells.lua

Fatal error: Maximum execution time of 30 seconds exceeded in C:\xampp\htdocs\update\modules\encrypt.php on line 13
 
Back
Top