Light紫星 发表于 2023-2-14 18:13

某游戏的另类lua加密方式的解密

本帖最后由 Light紫星 于 2023-2-15 09:47 编辑

某游戏的另类lua加密方式的解密
今日下午,群中一个小伙伴突然发了一个data.lua文件,并且问是什么编码,我下载一看,内容是加密的,但是有个头“FFSZ”,当时心想,这不是xxtea吗,有手就行啊,然后让小伙伴发来apk给我,遂有此贴。


目标apk包名:Y29tLmZ1bnBsdXMuZmFtaWx5ZmFybWNoaW5hLmh1YXdlaQ==


下载打开一看,是个农场类游戏,然后看一下lib目录,32和64位的都有,就拿arm64-v8a目录下手吧,里面就三个so文件,有一个最大的30多m,叫libgame.so,ok,不用想就知道今天的目标就是它了。


拖入ida,等加载(大文件ida加载是真的慢啊,不知道各位有没有加速的方式),然后搜索xxtea,ok有xxtea_decrypt字样,点进去,看一下参数,然后直接hook,hook代码如下:


# -*- coding: utf-8 -*-
import codecs
import frida
import sys
import threading

str_host = '192.168.1.10:9999'
manager = frida.get_device_manager()
device = manager.add_remote_device(str_host)

pending = []
sessions = []
scripts = []
event = threading.Event()

jscode = """   

function readStdString(str){
    var isTiny = (str.readU8() & 1) == 0;
    if(isTiny){
      return str.add(1).readUtf8String();
    }
    return str.add(2*Process.pointerSize).readPointer().readUtf8String();
}

function inline_hook() {
    while(1)
    {
      var so_addr = Module.findBaseAddress("libgame.so");
      console.log("so_addr:", so_addr);
      if (so_addr) {
          var addr = Module.findExportByName("libgame.so", "xxtea_decrypt")
          console.log("addr:", addr);
          if(!addr)
          {
            continue;
          }
            Interceptor.attach(new NativePointer(addr), {
            onEnter: function (args)
            {
               console.log("xxtea key:",readCString(args));
            },
            onLeave: function (retval)
            {   
            
            }
      });
      

      break;
    }
   
    }
}

inline_hook()

"""

pid = device.spawn(["com.funplus.familyfarmchina.huawei"])

session = device.attach(pid)
print(" Attach Application id:",pid)
device.resume(pid)
script = session.create_script(jscode)
print(' Running CTF')
script.load()
sys.stdin.read()
Hook成功,看到打印出ffs字样,嗯,这应该就是key了,下载一个xxtea解密工具,设置参数,解密:


如图,所有文件全部解密失败,此时我眉头一皱,心想事情并不简单,难道是key错了,还是根本就不是xxtea的加密方式,此时,回到ida,从xxtea_decrypt往上找
好的,我们找到了cocos2dx_lua_loader,然后看了一下流程,key设置成ffs,然后解密,好像是没错,但是和我们测试的结果不一致,所以整体看一下这个函数的流程,此函数如下:__int64 __fastcall cocos2dx_lua_loader(__int64 a1)
{
const char *v2; // x20
__int64 v3; // x0
const char *v4; // x20
unsigned __int64 v5; // x21
__int64 v6; // x22
const char *v7; // x21
__int64 v8; // x0
const char *v9; // x8
const char *v10; // x23
__int64 v11; // x24
__int64 v12; // x0
const char *v13; // x24
__int64 first_of; // x0
cocos2d::CCFileUtils *v15; // x0
__int64 v16; // x0
const char *v17; // x1
unsigned __int8 *v18; // x0
unsigned __int8 *v19; // x20
__int64 v20; // x0
__int64 ProcessedBuffSize; // x21
__int64 ProcessedBuffData; // x1
const char *v23; // x3
const char *v24; // x21
char v25; // w22
const char *v26; // x23
__int64 v27; // x3
const char *v28; // x2
const char *v29; // x21
char v30; // w22
const char *v31; // x23
const char *v32; // x4
const char *v33; // x3
__int64 v34; // x0
__int64 v35; // x22
unsigned __int64 *v36; // x23
void *v37; // x21
unsigned __int64 v38; // x4
const char *v39; // x3
const char *v40; // x22
char v41; // w23
const char *v42; // x24
__int64 v43; // x3
const char *v44; // x2
const char *v45; // x22
char v46; // w23
const char *v47; // x24
const char *v48; // x4
const char *v49; // x3
__int64 v50; // x0
__int64 v51; // x22
int *v52; // x23
void *v53; // x21
unsigned __int64 v54; // x4
const char *v55; // x3
const char *v56; // x22
char v57; // w23
const char *v58; // x24
__int64 v59; // x3
const char *v60; // x2
const char *v61; // x22
char v62; // w23
const char *v63; // x24
const char *v64; // x4
const char *v65; // x3
const char *v66; // x21
unsigned __int64 v67; // x23
unsigned __int64 v68; // x0
const char *v69; // x3
const char *v70; // x21
char v71; // w22
const char *v72; // x23
__int64 v73; // x3
const char *v74; // x2
const char *v75; // x21
char v76; // w22
const char *v77; // x23
const char *v78; // x4
const char *v79; // x3
const char *v81; // x23
__int64 v82; // x0
const char *v83; // x21
unsigned __int64 v84; // x23
unsigned __int64 v85; // x0
const char *v86; // x21
unsigned __int64 v87; // x23
unsigned __int64 v88; // x0
const char *v89; // x21
unsigned __int64 v90; // x23
unsigned __int64 v91; // x0
const char *v92; // x21
unsigned __int64 v93; // x23
unsigned __int64 v94; // x0
const char *v95; // x21
unsigned __int64 v96; // x23
unsigned __int64 v97; // x0
const char *v98; // x21
unsigned __int64 v99; // x23
unsigned __int64 v100; // x0
const char *v101; // x21
unsigned __int64 v102; // x23
unsigned __int64 v103; // x0
const char *v104; // x21
unsigned __int64 v105; // x23
unsigned __int64 v106; // x0
const char *v107; // x21
char v108; // w22
const char *v109; // x23
__int64 v110; // x3
const char *v111; // x2
const char *v112; // x21
char v113; // w22
const char *v114; // x23
const char *v115; // x4
const char *v116; // x3
const char *v117; // x23
__int64 v118; // x0
const char *v119; // x23
__int64 v120; // x0
const char *v121; // x23
__int64 v122; // x0
const char *v123; // x23
__int64 v124; // x0
const char *v125; // x23
__int64 v126; // x0
const char *v127; // x23
__int64 v128; // x0
const char *v129; // x23
__int64 v130; // x0
const char *v131; // x23
__int64 v132; // x0
_BYTE v133; // BYREF
__int64 v134; // BYREF
__int128 v135; // BYREF
const char *v136; //
unsigned __int64 v137; // BYREF
__int128 v138; // BYREF
const char *v139; //

v2 = (const char *)luaL_checklstring(a1, 1LL, 0LL);
v138 = 0uLL;
v139 = 0LL;
v3 = std::char_traits<char>::length(v2);
std::string::__init(&v138, v2, v3);
if ( (v138 & 1) != 0 )
    v4 = v139;
else
    v4 = (char *)&v138 + 1;
if ( (v138 & 1) != 0 )
    v5 = *((_QWORD *)&v138 + 1);
else
    v5 = (unsigned __int64)(unsigned __int8)v138 >> 1;
v6 = std::char_traits<char>::length(".lua");
v7 = &v4;
v8 = std::__find_end<bool (*)(char,char),char const*,char const*>(
         v4,
         v7,
         ".lua",
         &aLua,
         std::char_traits<char>::eq);
if ( (v6 == 0 || v8 != (_QWORD)v7) && v8 - (_QWORD)v4 != -1 )
{
    std::string::basic_string(&v135, &v138, 0LL, v8 - (_QWORD)v4, &v138);
    LOBYTE(v134) = 0;
    if ( (v138 & 1) != 0 )
    {
      std::char_traits<char>::assign(v139, v134);
      *((_QWORD *)&v138 + 1) = 0LL;
    }
    else
    {
      std::char_traits<char>::assign((char *)&v138 + 1, v134);
      LOBYTE(v138) = 0;
    }
    std::string::reserve(&v138, 0LL);
    v9 = v136;
    v136 = 0LL;
    v139 = v9;
    v138 = v135;
    v135 = 0uLL;
    std::string::~string(&v135);
}
while ( 1 )
{
    v10 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
    v11 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
    v12 = std::char_traits<char>::length(".");
    if ( !v12 )
      break;
    if ( !v11 )
      break;
    v13 = &v10;
    first_of = std::__find_first_of_ce<char const*,char const*,bool (*)(char,char)>(
               v10,
               v13,
               ".",
               &aFerrorInFuncti_1677,
               std::char_traits<char>::eq);
    if ( (const char *)first_of == v13 || first_of - (_QWORD)v10 == -1 )
      break;
    std::string::replace((int)&v138, first_of - (_DWORD)v10, 1, "/");
}
v15 = (cocos2d::CCFileUtils *)std::string::append((int)&v138, ".lua");
v137 = 0LL;
v16 = cocos2d::CCFileUtils::sharedFileUtils(v15);
if ( (v138 & 1) != 0 )
    v17 = v139;
else
    v17 = (char *)&v138 + 1;
v18 = (unsigned __int8 *)(*(__int64 (__fastcall **)(__int64, const char *, const char *, unsigned __int64 *))(*(_QWORD *)v16 + 32LL))(
                           v16,
                           v17,
                           "rb",
                           &v137);
v19 = v18;
if ( v18 )
{
    if ( v137 >= 4 )
    {
      switch ( *(_DWORD *)v18 )
      {
      case 0x43534646:
          FunPlus::CDesDecryptor::CDesDecryptor((FunPlus::CDesDecryptor *)&v135);
          memset(v134, 0, 24);
          v20 = std::char_traits<char>::length("FP_F_ENC");
          std::string::__init(v134, "FP_F_ENC", v20);
          FunPlus::CDesDecryptor::setKey(&v135, v134);
          std::string::~string(v134);
          FunPlus::CCryptor::setForceUse64Bit((FunPlus::CCryptor *)&v135, 1);
          if ( (FunPlus::CDecryptor::processBuffer((FunPlus::CDecryptor *)&v135, v19 + 4, v137 - 4) & 1) != 0 )
          {
            ProcessedBuffSize = FunPlus::CCryptor::getProcessedBuffSize((FunPlus::CCryptor *)&v135);
            ProcessedBuffData = FunPlus::CCryptor::getProcessedBuffData((FunPlus::CCryptor *)&v135);
            if ( (v138 & 1) != 0 )
            v23 = v139;
            else
            v23 = (char *)&v138 + 1;
            if ( (unsigned int)luaL_loadbuffer(a1, ProcessedBuffData, ProcessedBuffSize, (__int64)v23) )
            {
            v24 = (const char *)lua_tolstring(a1, 1LL, 0LL);
            v25 = v138;
            v26 = v139;
            v27 = lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
            if ( (v25 & 1) != 0 )
                v28 = v26;
            else
                v28 = (char *)&v138 + 1;
            cocos2d::CCLog((cocos2d *)"error loading module %s from file %s :\n\t%s", v24, v28, v27);
            v29 = (const char *)lua_tolstring(a1, 1LL, 0LL);
            v30 = v138;
            v31 = v139;
            v32 = (const char *)lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
            if ( (v30 & 1) != 0 )
                v33 = v31;
            else
                v33 = (char *)&v138 + 1;
            luaL_error(a1, "error loading module %s from file %s :\n\t%s", v29, v33, v32);
            }
            FunPlus::CDesDecryptor::~CDesDecryptor((FunPlus::CDesDecryptor *)&v135);
LABEL_99:
            operator delete[](v19);
            goto LABEL_100;
          }
          FunPlus::CDesDecryptor::~CDesDecryptor((FunPlus::CDesDecryptor *)&v135);
          break;
      case 0x5A534646:
          FunPlus::CDesDecryptor::CDesDecryptor((FunPlus::CDesDecryptor *)v134);
          v136 = 0LL;
          v135 = 0uLL;
          v34 = std::char_traits<char>::length("FP_F_ENC");
          std::string::__init(&v135, "FP_F_ENC", v34);
          FunPlus::CDesDecryptor::setKey(v134, &v135);
          std::string::~string(&v135);
          FunPlus::CCryptor::setForceUse64Bit((FunPlus::CCryptor *)v134, 1);
          if ( (FunPlus::CDecryptor::processBuffer((FunPlus::CDecryptor *)v134, v19 + 4, v137 - 4) & 1) != 0 )
          {
            v35 = FunPlus::CCryptor::getProcessedBuffSize((FunPlus::CCryptor *)v134);
            v36 = (unsigned __int64 *)FunPlus::CCryptor::getProcessedBuffData((FunPlus::CCryptor *)v134);
            *(_QWORD *)&v135 = *(int *)v36;
            v37 = (void *)operator new[](v135);
            if ( (FunPlus::CCompressUtil::UnCompress(
                  (FunPlus::CCompressUtil *)v37,
                  &v135,
                  v36 + 1,
                  (const void *)(((v35 << 32) - 0x800000000LL) >> 32),
                  v38) & 1) != 0 )
            {
            if ( (v138 & 1) != 0 )
                v39 = v139;
            else
                v39 = (char *)&v138 + 1;
            if ( (unsigned int)luaL_loadbuffer(a1, (__int64)v37, v135, (__int64)v39) )
            {
                v40 = (const char *)lua_tolstring(a1, 1LL, 0LL);
                v41 = v138;
                v42 = v139;
                v43 = lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
                if ( (v41 & 1) != 0 )
                  v44 = v42;
                else
                  v44 = (char *)&v138 + 1;
                cocos2d::CCLog((cocos2d *)"error loading module %s from file %s :\n\t%s", v40, v44, v43);
                v45 = (const char *)lua_tolstring(a1, 1LL, 0LL);
                v46 = v138;
                v47 = v139;
                v48 = (const char *)lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
                if ( (v46 & 1) != 0 )
                  v49 = v47;
                else
                  v49 = (char *)&v138 + 1;
                luaL_error(a1, "error loading module %s from file %s :\n\t%s", v45, v49, v48);
            }
            operator delete[](v37);
            FunPlus::CDesDecryptor::~CDesDecryptor((FunPlus::CDesDecryptor *)v134);
            goto LABEL_99;
            }
            operator delete[](v37);
          }
          FunPlus::CDesDecryptor::~CDesDecryptor((FunPlus::CDesDecryptor *)v134);
          break;
      case 0x457:
          FunPlus::CXXTeaDecryptor::CXXTeaDecryptor((FunPlus::CXXTeaDecryptor *)v133);
          v136 = 0LL;
          v135 = 0uLL;
          v50 = std::char_traits<char>::length("ffs");
          std::string::__init(&v135, "ffs", v50);
          FunPlus::CXXTeaDecryptor::setKey(v133, &v135);
          std::string::~string(&v135);
          if ( (FunPlus::CXXTeaDecryptor::processBuffer((FunPlus::CXXTeaDecryptor *)v133, v19 + 4, v137 - 4) & 1) != 0 )
          {
            v51 = FunPlus::CCryptor::getProcessedBuffSize((FunPlus::CCryptor *)v133);
            v52 = (int *)FunPlus::CCryptor::getProcessedBuffData((FunPlus::CCryptor *)v133);
            *(_QWORD *)&v135 = *v52;
            v53 = (void *)operator new[](v135);
            if ( (FunPlus::CCompressUtil::UnCompress(
                  (FunPlus::CCompressUtil *)v53,
                  &v135,
                  (unsigned __int64 *)(v52 + 1),
                  (const void *)(((v51 << 32) - 0x400000000LL) >> 32),
                  v54) & 1) != 0 )
            {
            if ( (v138 & 1) != 0 )
                v55 = v139;
            else
                v55 = (char *)&v138 + 1;
            if ( (unsigned int)luaL_loadbuffer(a1, (__int64)v53, v135, (__int64)v55) )
            {
                v56 = (const char *)lua_tolstring(a1, 1LL, 0LL);
                v57 = v138;
                v58 = v139;
                v59 = lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
                if ( (v57 & 1) != 0 )
                  v60 = v58;
                else
                  v60 = (char *)&v138 + 1;
                cocos2d::CCLog((cocos2d *)"error loading module %s from file %s :\n\t%s", v56, v60, v59);
                v61 = (const char *)lua_tolstring(a1, 1LL, 0LL);
                v62 = v138;
                v63 = v139;
                v64 = (const char *)lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
                if ( (v62 & 1) != 0 )
                  v65 = v63;
                else
                  v65 = (char *)&v138 + 1;
                luaL_error(a1, "error loading module %s from file %s :\n\t%s", v61, v65, v64);
            }
            operator delete[](v53);
            FunPlus::CXXTeaDecryptor::~CXXTeaDecryptor((FunPlus::CXXTeaDecryptor *)v133);
            goto LABEL_99;
            }
            operator delete[](v53);
          }
          FunPlus::CXXTeaDecryptor::~CXXTeaDecryptor((FunPlus::CXXTeaDecryptor *)v133);
          break;
      }
    }
    if ( (v138 & 1) != 0 )
      v66 = v139;
    else
      v66 = (char *)&v138 + 1;
    if ( (v138 & 1) != 0 )
      v67 = *((_QWORD *)&v138 + 1);
    else
      v67 = (unsigned __int64)(unsigned __int8)v138 >> 1;
    v68 = std::char_traits<char>::length("/");
    if ( v67 >= v68 )
    {
      if ( !v68
      || (v81 = &v66,
            v82 = std::__search<bool (*)(char,char),char const*,char const*>(
                  v66,
                  v81,
                  "/",
                  &asc_1A19AA4,
                  std::char_traits<char>::eq),
            v81 != (const char *)v82)
      && v82 - (_QWORD)v66 != -1 )
      {
      v83 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
      v84 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
      v85 = std::char_traits<char>::length("common/");
      if ( v84 < v85
          || v85
          && ((v117 = &v83,
               v118 = std::__search<bool (*)(char,char),char const*,char const*>(
                        v83,
                        v117,
                        "common/",
                        &aSpineCommon,
                        std::char_traits<char>::eq),
               v117 == (const char *)v118)
         || v118 - (_QWORD)v83 == -1) )
      {
          v86 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
          v87 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
          v88 = std::char_traits<char>::length("game_loading/");
          if ( v87 < v88
            || v88
            && ((v119 = &v86,
               v120 = std::__search<bool (*)(char,char),char const*,char const*>(
                        v86,
                        v119,
                        "game_loading/",
                        &aGameLoading,
                        std::char_traits<char>::eq),
               v119 == (const char *)v120)
             || v120 - (_QWORD)v86 == -1) )
          {
            v89 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
            v90 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
            v91 = std::char_traits<char>::length("version_logo");
            if ( v90 < v91
            || v91
            && ((v121 = &v89,
                   v122 = std::__search<bool (*)(char,char),char const*,char const*>(
                            v89,
                            v121,
                            "version_logo",
                            &aVersionLogo,
                            std::char_traits<char>::eq),
                   v121 == (const char *)v122)
               || v122 - (_QWORD)v89 == -1) )
            {
            v92 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
            v93 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
            v94 = std::char_traits<char>::length("fast_switch/");
            if ( v93 < v94
                || v94
                && ((v123 = &v92,
                     v124 = std::__search<bool (*)(char,char),char const*,char const*>(
                              v92,
                              v123,
                              "fast_switch/",
                              &aFastSwitch,
                              std::char_traits<char>::eq),
                     v123 == (const char *)v124)
               || v124 - (_QWORD)v92 == -1) )
            {
                v95 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
                v96 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
                v97 = std::char_traits<char>::length("ab_test/");
                if ( v96 < v97
                  || v97
                  && ((v125 = &v95,
                     v126 = std::__search<bool (*)(char,char),char const*,char const*>(
                              v95,
                              v125,
                              "ab_test/",
                              &aAbTest_0,
                              std::char_traits<char>::eq),
                     v125 == (const char *)v126)
                   || v126 - (_QWORD)v95 == -1) )
                {
                  v98 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
                  v99 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
                  v100 = std::char_traits<char>::length("novice_guide/");
                  if ( v99 < v100
                  || v100
                  && ((v127 = &v98,
                         v128 = std::__search<bool (*)(char,char),char const*,char const*>(
                                  v98,
                                  v127,
                                  "novice_guide/",
                                  &aNoviceGuide,
                                  std::char_traits<char>::eq),
                         v127 == (const char *)v128)
                     || v128 - (_QWORD)v98 == -1) )
                  {
                  v101 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
                  v102 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
                  v103 = std::char_traits<char>::length("neighbor/");
                  if ( v102 < v103
                      || v103
                      && ((v129 = &v101,
                           v130 = std::__search<bool (*)(char,char),char const*,char const*>(
                                    v101,
                                    v129,
                                    "neighbor/",
                                    &aNeighbor_1,
                                    std::char_traits<char>::eq),
                           v129 == (const char *)v130)
                     || v130 - (_QWORD)v101 == -1) )
                  {
                      v104 = (v138 & 1) != 0 ? v139 : (char *)&v138 + 1;
                      v105 = (v138 & 1) != 0 ? *((_QWORD *)&v138 + 1) : (unsigned __int64)(unsigned __int8)v138 >> 1;
                      v106 = std::char_traits<char>::length("spine-lua/");
                      if ( v105 < v106
                        || v106
                        && ((v131 = &v104,
                           v132 = std::__search<bool (*)(char,char),char const*,char const*>(
                                    v104,
                                    v131,
                                    "spine-lua/",
                                    &aSpineLua,
                                    std::char_traits<char>::eq),
                           v131 == (const char *)v132)
                         || v132 - (_QWORD)v104 == -1) )
                      {
                        v107 = (const char *)lua_tolstring(a1, 1LL, 0LL);
                        v108 = v138;
                        v109 = v139;
                        v110 = lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
                        if ( (v108 & 1) != 0 )
                        v111 = v109;
                        else
                        v111 = (char *)&v138 + 1;
                        cocos2d::CCLog((cocos2d *)"error loading module %s from file %s :\n\t%s", v107, v111, v110);
                        v112 = (const char *)lua_tolstring(a1, 1LL, 0LL);
                        v113 = v138;
                        v114 = v139;
                        v115 = (const char *)lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
                        if ( (v113 & 1) != 0 )
                        v116 = v114;
                        else
                        v116 = (char *)&v138 + 1;
                        luaL_error(a1, "error loading module %s from file %s :\n\t%s", v112, v116, v115);
                      }
                  }
                  }
                }
            }
            }
          }
      }
      }
    }
    if ( (v138 & 1) != 0 )
      v69 = v139;
    else
      v69 = (char *)&v138 + 1;
    if ( (unsigned int)luaL_loadbuffer(a1, (__int64)v19, v137, (__int64)v69) )
    {
      v70 = (const char *)lua_tolstring(a1, 1LL, 0LL);
      v71 = v138;
      v72 = v139;
      v73 = lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
      if ( (v71 & 1) != 0 )
      v74 = v72;
      else
      v74 = (char *)&v138 + 1;
      cocos2d::CCLog((cocos2d *)"error loading module %s from file %s :\n\t%s", v70, v74, v73);
      v75 = (const char *)lua_tolstring(a1, 1LL, 0LL);
      v76 = v138;
      v77 = v139;
      v78 = (const char *)lua_tolstring(a1, 0xFFFFFFFFLL, 0LL);
      if ( (v76 & 1) != 0 )
      v79 = v77;
      else
      v79 = (char *)&v138 + 1;
      luaL_error(a1, "error loading module %s from file %s :\n\t%s", v75, v79, v78);
    }
    goto LABEL_99;
}
if ( (v138 & 1) != 0 )
    cocos2d::CCLog((cocos2d *)"can not get file data of %s", v139);
else
    cocos2d::CCLog((cocos2d *)"can not get file data of %s", (const char *)&v138 + 1);
LABEL_100:
std::string::~string(&v138);
return 1LL;
}
通过分析,我们知道,他先是读入lua文件,然后判断文件头,根据不同的文件头走不同的流程,我们的文件头是FFSZ,走的应该是des解密的流程,des解密之后还有一个zlib的解压缩,ok按照这个思路开始写代码。 一开始写的时候,我去掉文件头直接des解密,但是得出来的结果一直不符合预期,所以我直接跳过了12个字节重新解密,别问我为什么跳过12个字节,我也是猜的,然后解密出的结果,第九个字节刚好是789c,标准的zlib头,这里再进行zlib解压,好家伙,直接出明文了,解密代码如下:import pyDes,base64,zlib
from pyDes import des, ECB
def des_descrypt(s,KEY):
    secret_key = KEY
    iv = secret_key
    k = des(secret_key, ECB,IV=iv, pad=None)
    de = k.decrypt(s)
    return de

f=open('data.lua','rb').read()
f=f
ret = des_descrypt(f,b'FP_F_ENC')

new_data = zlib.decompress(ret)

print(new_data)

open('data_decrypt.lua','wb').write(new_data)
看一下解密出来的文件,完美!

好了,至此此文件的解密完成,总结一下,平常我们遇到的都是xxtea的lua加密,但是这个lua的so里面虽然也有xxtea,但是用了des加密并且进行了压缩,所以遇到lua的游戏的时候不要慌,冷静分析,也是可以搞定的

最后附一下常见各种压缩算法的头特征:
gzip 1f 8b 08
lzma 6c 00
zlib 78 9c

独木君 发表于 2023-2-14 18:15

情人节快乐{:301_997:}

LineCat 发表于 2023-2-16 11:57

大佬好,我也有一个cocos2d的游戏不知道是什么加密方法,以下是我目前所知的内容:
apk的assets文件夹中有三个文件夹,“32”“64”“release”,前两个存放了一个数据库文件,里面用navicat查看后是所有游戏资源的索引,有源位置和加密后的位置,“release”文件夹内就是加密后的全部资源。我起初也觉得这或许是xxtea,但是一直没有什么进展。加密的资源中有许多是明文,比如json、awb和plist,加密的文件似乎只有png和lua(luac)。这两个文件只有前七个字节是相同的,是这些“@Y#Q+G&”,我自己在这方面的经验实在是少之又少,想听听大佬的意见

侃遍天下无二人 发表于 2023-2-14 18:37

本帖最后由 侃遍天下无二人 于 2023-2-14 18:52 编辑

大老,情人节被群友白嫖是一种什么样的体验?

wasm2023 发表于 2023-2-14 18:59

厉害了,我的哥

8jUmJL 发表于 2023-2-14 20:11

{:1_893:}{:1_893:}{:1_893:}{:1_893:}厉害!!!!!

daoxun 发表于 2023-2-14 20:18

厉害了 我的哥

taoxwl666 发表于 2023-2-14 21:24

原来如此,学到了

正己 发表于 2023-2-14 21:35

表哥带带{:301_975:}

Pwaerm 发表于 2023-2-14 22:00

啊啊啊 高手

佩服佩服佩服

takklong 发表于 2023-2-14 22:39

大佬牛逼{:1_921:}
页: [1] 2 3 4
查看完整版本: 某游戏的另类lua加密方式的解密