某游戏的另类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
情人节快乐{:301_997:} 大佬好,我也有一个cocos2d的游戏不知道是什么加密方法,以下是我目前所知的内容:
apk的assets文件夹中有三个文件夹,“32”“64”“release”,前两个存放了一个数据库文件,里面用navicat查看后是所有游戏资源的索引,有源位置和加密后的位置,“release”文件夹内就是加密后的全部资源。我起初也觉得这或许是xxtea,但是一直没有什么进展。加密的资源中有许多是明文,比如json、awb和plist,加密的文件似乎只有png和lua(luac)。这两个文件只有前七个字节是相同的,是这些“@Y#Q+G&”,我自己在这方面的经验实在是少之又少,想听听大佬的意见 本帖最后由 侃遍天下无二人 于 2023-2-14 18:52 编辑
大老,情人节被群友白嫖是一种什么样的体验? 厉害了,我的哥 {:1_893:}{:1_893:}{:1_893:}{:1_893:}厉害!!!!! 厉害了 我的哥 原来如此,学到了 表哥带带{:301_975:} 啊啊啊 高手
佩服佩服佩服
大佬牛逼{:1_921:}