cocos2dx-Lua引擎遊戲指令碼及圖片資源解密與DUMP
分析目標
下面分析的主要是少年三國志。
Lua指令碼解密與DUMP
LuaJit IDA分析呼叫樹:
AppDelegate::applicationDidFinishLaunching(AppDelegate *__hidden this) EXPORT _ZN11AppDelegate29applicationDidFinishLaunchingEv
cocos2d::CCLuaEngine::defaultEngine(cocos2d::CCLuaEngine *__hidden this) EXPORT _ZN7cocos2d11CCLuaEngine13defaultEngineEv
cocos2d::CCLuaEngine::init(cocos2d::CCLuaEngine *__hidden this)
EXPORT _ZN7cocos2d11CCLuaEngine4initEvcocos2d::CCLuaStack::create(cocos2d::CCLuaStack *__hidden this)
EXPORT _ZN7cocos2d10CCLuaStack6createEvcocos2d::CCLuaStack::init(cocos2d::CCLuaStack *__hidden this)
EXPORT _ZN7cocos2d10CCLuaStack4initEvcocos2dx_lua_loader
cocos2d::CCLuaStack::lua_loadbuffer(lua_State , char const, int, char const*)
EXPORT ZN7cocos2d10CCLuaStack14lua_loadbufferEP9lua_StatePKciS4
cocos2d::CCLuaStack::lua_loadbuffer先呼叫以下函式解密: cocos2d::extra::CCCrypto::decryptUF(uchar ,int,int ,int *) EXPORT ZN7cocos2d5extra8CCCrypto9decryptUFEPhiPiS3
最後再呼叫:luaL_loadbuffer
因此可以直接對luaL_loadbuffer進行HOOK,進而DUMP出Lua指令碼,網上搜索函式宣告:
int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name);
進而實現HOOK程式碼:
//orig function copy
int (*luaL_loadbuffer_orig)(void *L, const char *buff, int size, const char *name) = NULL;
//local function
int luaL_loadbuffer_mod(void *L, const char *buff, int size, const char *name) {
LOGD("[dumplua] luaL_loadbuffer name: %s lua: %s", name, buff);
return luaL_loadbuffer_orig(L, buff, size, name);
}
void hook() {
LOGD("[dumplua] hook begin");
void *handle = dlopen("libgame.so", RTLD_NOW);
if (handle == NULL) {
LOGE("[dumplua]dlopen err: %s.", dlerror());
return;
}else{
LOGD("[dumplua] libgame.so dlopen OK!");
}
void *pluaL_loadbuffer = dlsym(handle, "luaL_loadbuffer");
if (pluaL_loadbuffer == NULL){
LOGE("[dumplua] lua_loadbuffer not found!");
LOGE("[dumplua] dlsym err: %s.", dlerror());
}else{
LOGD("[dumplua] luaL_loadbuffer found!");
MSHookFunction(pluaL_loadbuffer, (void *)&luaL_loadbuffer_mod, (void **)&luaL_loadbuffer_orig);
}
}
執行後攔截到的輸出資訊:
01-05 19:29:27.674 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: assets/scripts/main.lua lua:
function __G__TRACKBACK__(errorMessage)
print("----------------------------------------")
print("LUA ERROR: " .. tostring(errorMessage) .. "\n")
local traceback = debug.traceback("", 2)
print(traceback)
print("----------------------------------------")
--只有G_Report初始過後才會對錯誤日誌做處理
if G_Report ~= nil then
G_Report:onTrackBack(errorMessage, traceback)
end
if SHOW_EXCEPTION_TIP and uf_notifyLayer ~= nil then
uf_notifyLayer:getDebugNode():removeChildByTag(10000)
local text = tostring(errorMessage)
require("upgrade.ErrMsgBox").showErrorMsgBox(text)
end
end
function traceMem(desc)
if desc == nil then
desc = "memory:"
end
if CCLuaObjcBridge then
local callStaticMethod = CCLuaObjcBridge.callStaticMethod
local ok, ret = callStaticMethod("NativeProxy", "getUsedMemory", nil)
if ok then
pri
01-05 19:29:27.679 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.AntiAddictionLayer lua: LJ-
01-05 19:29:27.679 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.ComSdkUtils lua: LJA
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.config lua: LJ�
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.ConfigLayer lua: LJ]
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.EffectNode_Upgrade lua: LJ�
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.ErrMsgBox lua: LJP
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.game lua: LJ�
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.NativeCallUtils lua: LJ�
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.NativeProxy lua: LJ�
01-05 19:29:27.684 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.Patcher lua: LJ�
01-05 19:29:27.689 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.SplashLayer lua: LJ-
01-05 19:29:27.689 13191-13215/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: upgrade.upgrade lua: LJ6
可見,有些Lua指令碼是原始碼形式,有些是LuaJit編譯的,可以改寫以上程式碼把指令碼DUMP到檔案中再進一步分析,此處略。
資源解密與DUMP
主要函式: cocos2d::CCImage::initWithImageFile呼叫 cocos2d::CCImage::initWithImageData
但是IDA分析發現initWithImageData會呼叫cocos2d::extra::CCCrypto::decryptXXTEA和cocos2d::extra::CCCrypto::decryptUF進行解密,最後再載入圖片資源。以下是initWithImageData部分程式碼:
if ( s )
{
v12 = (unsigned __int8 *)strlen(s);
v13 = (void *)cocos2d::extra::CCCrypto::decryptXXTEA(v9, v11, (int)s, v12, (int)v24, v22);
v14 = v13;
if ( v13 )
v9 = (cocos2d::extra::CCCrypto *)v13;
goto LABEL_28;
}
v14 = 0;
if ( (signed int)a3 > 3 && *(_BYTE *)this == 85 && *((_BYTE *)this + 1) == 70 )
{
v25 = 0;
cocos2d::extra::CCCrypto::decryptUF(this, (int)a3, (int)&v25, v24, v21);
v15 = v25 >> 4;
if ( (v25 & 0xFu) <= 9 )
*(_DWORD *)(v8 + 36) = v25 & 0xF;
switch ( v15 )
{
case 1:
v16 = 1067030938;
break;
case 2:
v16 = 1068708659;
也即會呼叫cocos2d::extra::CCCrypto::decryptXXTEA和cocos2d::extra::CCCrypto::decryptUF進行解密操作。我們看下cocos2d::extra::CCCrypto::decryptUF這個函式,通過IDA的F5外掛,並不斷修改變數名可以獲得一個比較清晰的C程式碼。
int __fastcall cocos2d::extra::CCCrypto::decryptUF(cocos2d::extra::CCCrypto *pInBuff, int nlen, int a3, int *pOutLen, int *name)
{
cocos2d::extra::CCCrypto *pInBuff2; // r5@1
int *pOutLen2; // r7@1
int v7; // r3@4
int v8; // r6@5
int v9; // r1@6
int result; // r0@9
int v11; // r4@10
int v12; // r6@12
int v13; // r6@15
signed int v14; // r0@19
int v15; // [sp+0h] [bp-28h]@5
int v16; // [sp+0h] [bp-28h]@10
int v17; // [sp+4h] [bp-24h]@5
pInBuff2 = pInBuff;
pOutLen2 = pOutLen;
if ( nlen <= 3 )
{
v14 = 1;
return -v14;
}
if ( *(_BYTE *)pInBuff != 'U' || *((_BYTE *)pInBuff + 1) != 'F' )
{
v14 = 2;
return -v14;
}
*(_DWORD *)a3 = *((_BYTE *)pInBuff + 2);
v7 = *((_BYTE *)pInBuff + 3);
if ( v7 == 1 )
{
v15 = nlen - 5;
v17 = *((_BYTE *)pInBuff + 4);
v8 = 0;
while ( v8 < v15 )
{
v9 = (v8++ + v17) % 0x21;
*(_BYTE *)pInBuff2 = *((_BYTE *)pInBuff2 + 5) ^ byte_6D192C[v9];
pInBuff2 = (cocos2d::extra::CCCrypto *)((char *)pInBuff2 + 1);
}
*pOutLen2 = v15;
}
else
{
result = 0;
if ( v7 != 2 )
return result;
v11 = 0;
v16 = *((_BYTE *)pInBuff2 + 4);
do
{
*((_BYTE *)pInBuff2 + v11) = *((_BYTE *)pInBuff2 + nlen + v11 - 5) ^ byte_6D192C[(v11 + v16) % 33 + 33];
++v11;
}
while ( v11 != 5 );
v12 = nlen - 10;
if ( nlen - 10 > 95 )
v12 = 95;
v13 = v12 + 4;
while ( v13 >= v11 )
{
*((_BYTE *)pInBuff2 + v11) ^= byte_6D192C[(v11 + v16) % 33 + 33];
++v11;
}
*pOutLen2 = nlen - 5;
}
return 0;
}
其實看到這裡應該也是比較容易逆向分析出解密的演算法的,應該說比較簡單,可以直接寫一個指令碼來解密assets裡的資源。但是為了保證通用性,還是寫HOOK程式碼比較好。
本來分析以為最終都會呼叫_initWithWebpData、_initWithJpgData、_initWithBpgData、_initWithPngData、_initWithTiffData、_initWithRawData這些函式的,但是實際上分別HOOK後並沒有被攔截,所以最後還是HOOK了下cocos2d::extra::CCCrypto::decryptUF。
static string g_strDataPath;
static int g_nCount = 1;
string getNextFilePath(const char *fileExt) {
char buff[100] = {0};
++g_nCount;
sprintf(buff, "%s/cache/%d%s", g_strDataPath.c_str(), g_nCount, fileExt);
return buff;
}
bool saveFile(const void* addr, int len, const char *outFileName)
{
bool bSuccess = false;
FILE* file = fopen(outFileName, "wb+");
if (file != NULL) {
fwrite(addr, len, 1, file);
fflush(file);
fclose(file);
bSuccess = true;
chmod(outFileName, S_IRWXU | S_IRWXG | S_IRWXO);
}else{
LOGE("[%s] fopen failed, error: %s", __FUNCTION__, dlerror());
}
return bSuccess;
}
//hook decryptUF
int (*decryptUF_orig)(void *pInBuff, int len, int *n, int *poutlen, char *name) = NULL;
int decryptUF_mod(void *pInBuff, int len, int *n, int *poutlen, char *name) {
int ret = decryptUF_orig(pInBuff, len, n, poutlen, name);
saveFile(pInBuff, *poutlen, getNextFilePath(".png").c_str());
return ret;
}
void hook() {
//hook decryptUF
void *decryptUF = dlsym(handle, "_ZN7cocos2d5extra8CCCrypto9decryptUFEPhiPiS3_");
if ( decryptUF==NULL ) {
LOGE("[dumplua] _ZN7cocos2d5extra8CCCrypto9decryptUFEPhiPiS3_ (decryptUF) not found!");
LOGE("[dumplua] dlsym err: %s.", dlerror());
}else{
LOGD("[dumplua] _ZN7cocos2d5extra8CCCrypto9decryptUFEPhiPiS3_ (decryptUF) found!");
MSHookFunction(decryptUF, (void *)&decryptUF_mod, (void **)&decryptUF_orig);
}
}
我這裡圖方便把所有解密的資料都DUMP為/data/data/packagename/cache目錄下副檔名為PNG的檔案了,最後通過指令碼從手機中批量提取出解密後的檔案:
#coding:utf-8
import os
for i in range(1, 10000):
cmd = 'adb pull /data/data/com.youzu.android.snsgz/cache/' + str(i) +'.png' + ' e:\\test'
os.system(cmd)
其實通過上面的分析就可以知道,圖片資源的解密和Lua的解密都是呼叫了相同的函式,因此解密出的檔案不全是圖片,還有寫LuaJit的指令碼檔案,用十六進位制編輯器開啟就可以看到LJ開頭的魔法數字。
全民水滸
全民水滸這個比較簡單,資源直接沒加密處理,解壓縮APK檔案就可以在assets目錄下查看了。Lua指令碼可以通過HOOK函式luaL_loadbuffer獲得,而且可以看出只是對編譯的Lua指令碼做了簡單的加密,可以直接DUMP出來,相對少年三國志稍微弱了一些。
01-05 20:04:16.569 17729-17886/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: require "UpdateScene.lua" lua: require "UpdateScene.lua"
01-05 20:04:16.574 17729-17886/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: UpdateScene.lua lua: LuaQ
01-05 20:04:16.574 17729-17886/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: Modal.lua lua: LuaQ
01-05 20:04:16.574 17729-17886/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: UIDefine.lua lua: LuaQ
01-05 20:04:16.574 17729-17886/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: MessageBox.lua lua: LuaQ
01-05 20:04:16.579 17729-17886/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: SoundManager.lua lua: LuaQ
01-05 20:04:16.579 17729-17886/? D/SUBSTRATEHOOK: [dumplua] luaL_loadbuffer name: SoundConfig.lua lua: LuaQ
相關推薦
cocos2dx-Lua引擎遊戲指令碼及圖片資源解密與DUMP
分析目標 少年三國志,包名:com.youzu.android.snsgz 全民水滸,包名:com.tencent.Q108 下面分析的主要是少年三國志。 Lua指令碼解密與DUMP LuaJit IDA分析呼叫樹: AppDelegate:
cocos2dx 3.0 使用TexturePacker對圖片資源加密
遊戲開發過程中要涉及到大量的圖片,使用TexturePacker可以把小圖合成大圖。這是我們使用最多的功能,但是TexturePacker還帶有對圖片加密的功能。之前還是對加密不慎瞭解,今天在網上搜了下然後自己親手寫了,所以寫下來分享下。 把圖片匯入到Text
cocos2dx lua轉luac的問題(32位與64位不相容問題)
兩種思路: 1、LuaJit 轉luac,生成的bytecode,是按照32位生成的。在64位的機器上是不支援的。(新版本的LuaJit 已經支援了64位。可更新新版本的LuaJit, 用新版本LuaJit生成對應的luajit-mac) 2、原生的Lua5.1.4 生成
Java併發包原始碼學習系列:CLH同步佇列及同步資源獲取與釋放
[toc] ## 本篇學習目標 - 回顧CLH同步佇列的結構。 - 學習獨佔式資源獲取和釋放的流程。 ## CLH佇列的結構 我在[Java併發包原始碼學習系列:AbstractQueuedSynchronizer#同步佇列與Node節點](https://www.cnblogs.com/summer
Lua筆記:Sprite及ImageView型別替換新的圖片資源
------------------- Sprite及ImageView型別替換新的圖片資源 ---------------------- --Sprite型別 local img = cc
Java版AVG遊戲開發入門示例[3]——指令碼引擎的製作及應用
根據wikipedia的解釋:指令碼語言(Script language,scripting language,scripting programming language),是為了縮短傳統的編寫-編譯-連結-執行(edit-compile-link-run)過程而建立
Lua遊戲逆向及破解方法介紹
初始 成對 參數 很多 技術 邏輯 重寫 源碼 sem Lua遊戲逆向及破解方法介紹 背景介紹 隨著手遊的發展,越來越多的Cocos-lua端遊開發者轉移到手遊平臺。Lua腳本編寫邏輯的手遊也是越來越多,如夢幻西遊、刀塔傳奇、開心消消樂、遊龍英雄、奇跡暖暖、疾風獵
Mac OSX 10.13 手動編譯Quick-cocos2dx Lua遊戲APK
bubuko 手動編譯 class mac osx post img mac os cos http Mac OSX 10.13 手動編譯Quick-cocos2dx Lua遊戲APK
使用python指令碼實現iOS圖片資源壓縮
最近公司有一個新的需求,要把程式碼進行瘦身,這篇部落格記錄下如何對圖片進行壓縮的。 原理: 寫一個指令碼,把圖片資料夾'.xcassets'的所有檔案遍歷出來,然後使用一個第三方的演算法把圖片壓縮後再替換回去 成果: 由於在該工程中的png圖片已經壓縮過了,這次只壓縮了jgp為字尾的圖片,可以看出,還
Cocos2d-x Lua引擎製作的遊戲程式碼加密
在Mac OS中的終端鍵入:cocos luacompile -h,可以獲得這個命令的幫助: usage: cocos luacompile [-h] [-v] [-s SRC_DIR_ARR] [-d DST_DIR] [-e] &nbs
Android studio2.0在app中設定背景圖片及新增圖片資源
我還處於摸索階段,也是在慢慢倒騰,持續更新,希望能幫助到有需要的人 首先將需要的圖片轉成png格式(png格式的圖片顏色過渡平滑且支援透明度),牆紙或啟動畫面的圖片資源儲存為jpg格式。 將圖片儲存到相應的工程之下,不要放錯了。 某工程/app/src/m
cocos2dx 圖片資源加密
圖片加密使用xxtea來加密,加密祕鑰自己定,思路就是自己使用程式碼首先將圖片加密,在程式中使用的時候,在載入圖片資源處再將資源解密 加密程式碼如下: 首先要載入標頭檔案 2、將圖片加密 bool jiamiImg(string inputFileName,string
圖片資源加密,Lua檔案加密
轉自:http://www.cnblogs.com/zisou/p/cocos2dxJQ-67.html 遊戲開發中常遇到資源保護的問題。 目前遊戲開發中常加密的檔案型別有:圖片,Lua檔案,音訊等檔案,而其實加密也是一把雙刃劍。 需要安全那就得耗費一定的資源去實
cocos2dx-lua在android上實現生成及掃描二維碼
首先說明下,生成二維碼是用android原生的BitMatrix和Bitmap類來生成的,而掃描二維碼用到了google官方的zxing包(core.jar)。 這裡我把所有生成二維碼的程式碼和lua呼叫的掃描二維碼方法都放在了專案->frameworks->
cocos2dx引擎版本問題,由圖片導致android系統出現Unable to access asset data: -1 從而導致崩潰
這個問題是因為pkm圖片壓縮造成的,需要在生成pkm的時候新增引數 -slow 採用慢速生成,首先確定是哪張圖造成的,然後把這張圖採用慢速壓縮就ok了 其實修改一下texturepacker打包時候的引數有時候也能解決,但具有不確定性,而在壓縮pkm的時候採用慢速方式能夠完
學著做的第一個小遊戲 flappyBrid 飛翔的小鳥 有圖片資源
<!DOCTYPE html> <html> <head> <title>飛鳥</title> <style type="text/css"> /* 不同核心*/ @-webkit-keyfra
【COCOS2DX-LUA 指令碼開發之六】利用Lua強轉函式解決使用CCNode報錯或無法正常使用以及簡單介紹 quick-cocos2d-x 與 OpenQuick 兩款Lua免費開源框架
Him 的Cocos2dx-Lua群中有童鞋出現一個問題,問題是當他在Lua專案中利用Lua建立一個區域性變數CCSprite或者CCLayer等CCNode,然後在其他的函式中通過其索引取出之前建立過的CCSprite或CCLayer等,取出後進行設定設定透明、座標、縮放、
一個簡單的基於OpenGL的Lua的遊戲引擎的例項
學習了幾天Lua,今天突然想為Lua寫一個簡單的遊戲引擎方便使用Lua單獨的開發遊戲,下面是一個基本的程式碼(很簡單), Lua的程式碼也測試通過了但還不完整,稍候再發上來程式碼如下:#define PENQ_LUAGAME #include <string.h>
kbengine服務端引擎+cocos2dx搭建網路遊戲
原始碼:https://github.com/cnsoft/kbengine_cocos2dx_demo 什麼是KBEngine? 一款開源的遊戲服務端引擎,使用簡單的約定協議就能夠使客戶端與服務端進行互動,使用KBEngine外掛能夠快速與(Unity3D, OGR
利用觀察者模式實現Cocos2DX-lua遊戲中的訊息管理系統
http://blog.csdn.net/operhero1990/article/details/48575487 遊戲中某些物件往往需要及時獲知其他特定物件狀體的改變。為降低類之間的耦合度,可以建立訊息管理系統,實現訊息的集中與分發。觀察者