我们随便打开一个lua脚本文件,发现游戏脚本已经被加密了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来的工作我们就需要对lua脚本文件进行解密,lua手游脚本解密的方法有很多,网上也有非常多的教程。我在之前也发过一篇,关于本游戏的的解密教程,大家可以做参考。

解密lua脚本后,让游裸奔。我们通过对http协议头的一些参数进行搜索,定位到 HttpManager.lua 文件。

设置协议头,实现代码。和我们抓包的结果一致。


local localTime = 0



-- 初始化时间戳

--[[

1 同一帧内不能出现两次相同的时间戳

2 使用最新的时间戳

]]

function HttpManager:setWebTime(time)

    if PRINT_MODE == 1 then

        print("time = "..time)

    end

    localTime = time

end



function HttpManager:updateWebTime()

    localTime = localTime + 0.0001

end



-- @author XiaoZhiWei

-- @time 2016/11/14 11:49:21

-- @desc 设置头信息

local function setHeader(xhr, headers)

    local time = localTime

    -- 得到nouce and sig

    local nouce, sig = HttpManager:getNouceAndSig(time)



    -- 默认头

    local sendHeaders =

        {

            uuid = Game:getIdfv(),

            userid = User:getUserId(),

            sig = sig,

            time = time,

            nouce = nouce,

            device = Game:getDevInfo(),

            ver = Game:getVersion(),

            hotver = Game:getHotVersion(),

            platform = Game:getPlatformId(),

            timezone = Helper:mathFloor((28800 - Helper:getTimeZone()) / 3600),

            channel = Game:getChannelId(),

            package = Game:getPackageId(),

        }



    if Game:getPlatformId() == "android" then

        sendHeaders.pkname = SdkMethod:getPackageName()

        sendHeaders.pksig = SdkMethod:getSignature()

    end



    -- 覆盖头

    for k, v in pairs(Helper:getDef(headers, {})) do

        sendHeaders[k] = v

    end



    -- 设置头

    for k, v in pairs(sendHeaders) do

        if PRINT_MODE == 1 then

            print("sendHeaders["..k.."]= "..tostring(v))

        end

        xhr:setRequestHeader(k, v)

    end

end



-- @author XiaoZhiWei

-- @time 2016/11/14 11:10:58

-- @desc 获取随机nouce 以及加密 sig

function HttpManager:getNouceAndSig(time)

    local nouce = ""

    for i = 1, 6 do

        local index = math.random(65, 122)

        while (index > 90 and index < 97) or index == 101 do

            index = math.random(65, 122)

        end

        nouce = nouce..string.char(index)

    end

    local sig = YXHelper:doMd5ForHttpRequest(nouce, time)

    if PRINT_MODE == 1 then

        print("sig = "..tostring(sig))

        print("nouce = "..tostring(nouce))

    end

    return nouce, sig

end

分析

  • time: 1516158302.0023 localTime = localTime + 0.0001 一个基于时间和次数的设置。

  • sig: 27347124073b9e2933fb1f7dd971f200 sig = YXHelper:doMd5ForHttpRequest(nouce, time) 一个基于时间和随机文本的请求签名。

我们重点分析:YXHelper:doMd5ForHttpRequest 在lua解密的文件夹里面是搜不到这个函数的实现,这个方法在 native 里面实现;

我们用 IDA 打开 libcocos2dlua.so 搜索 doMd5ForHttpRequest

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

code:


int __fastcall YXHelper::doMd5ForHttpRequest(int a1, int a2, int a3)

{

  int v3; // r9

  int v4; // r6

  int v5; // r8

  unsigned int i; // r7

  const void *v7; // r10

  size_t v8; // r8

  void *v9; // r9

  int v10; // r7

  char v12; // [sp+Ch] [bp-FCh]

  const void *v13; // [sp+10h] [bp-F8h]

  int v14; // [sp+14h] [bp-F4h]

  int v15; // [sp+18h] [bp-F0h]

  int v16; // [sp+1Ch] [bp-ECh]

  char v17; // [sp+20h] [bp-E8h]

  char v18; // [sp+B8h] [bp-50h]

  char v19[20]; // [sp+C8h] [bp-40h]



  v3 = a2;

  v4 = a1;

  v5 = a3;

  sub_E67C0C(&v13, "ed24bd36b1a87f60bebaca65538a590c", &v14);

  v14 = 0;

  v15 = 0;

  v16 = 0;

  std::vector<std::string,std::allocator<std::string>>::push_back(&v14, v3);

  std::vector<std::string,std::allocator<std::string>>::push_back(&v14, v5);

  std::vector<std::string,std::allocator<std::string>>::push_back(&v14, &v13);

  YXHelper::sortStringList(&v14);

  sub_E66AE0(&v13, &unk_F20BD8);

  for ( i = 0; i < (v15 - v14) >> 2; ++i )

    sub_E65B98(&v13, v14 + 4 * i);

  MD5_Init(&v17);

  v7 = v13;

  v8 = *((_DWORD *)v13 - 3);

  v9 = malloc(*((_DWORD *)v13 - 3));

  memcpy(v9, v7, v8);

  MD5_Update(&v17, v9, v8);

  memset(v19, 0, 0x11u);

  MD5_Final(v19, &v17);

  sub_E67C0C(v4, &unk_F20BD8, &v12);

  v10 = 0;

  do

  {

    sprintf(&v18, "%02x", (unsigned __int8)v19[v10]);

    sub_E65AA0(v4, &v18);

    ++v10;

  }

  while ( v10 != 16 );

  free(v9);

  std::vector<std::string,std::allocator<std::string>>::~vector(&v14);

  sub_E65714(&v13);

  return v4;

}

翻译成C#代码


        private string GetNouceAndSig(string nouce, string time)

        {

            List<string> list = new List<string>();

            list.Add("ed24bd36b1a87f60bebaca65538a590c");

            list.Add(nouce);

            list.Add(time);

            list.Sort();

            string s = string.Join(string.Empty, list);

            using ( var md5 = MD5.Create())

            {



                byte[] md =  md5.ComputeHash(Encoding.UTF8.GetBytes(s));

                return BitConverter.ToString(md).Replace("-", String.Empty).ToLower();

            }

        }



        GetNouceAndSig("1516158302.0023", "pDKFkg")

        > 27347124073b9e2933fb1f7dd971f200

OK,验证通过。

接下来 我们对 POST 提交数据 和 resp 返回数据进行分析。


-- @author TangJian

-- @desc

function HttpManager:post(url, sendData, headers, callback, isNeedWait, isNeedEncrypt)

    self:updateWebTime() -- 刷新时间



    isNeedWait = Helper:getDef(isNeedWait, false) -- 等待默认为false

    -- 检查url是否齐全

    if string.find(url, DOMAIN) == nil and string.find(url, "api/service_ios/") == nil then

        url = DOMAIN..url

    end



    -- 需要等待的处理

    local waitingLayer = nil

    if isNeedWait then

        waitingLayer = WaitingLayer:createInRunningScene()

    end



    -- 请求处理开始

    if PRINT_MODE == 1 then

        print("toUrl = "..tostring(toUrl))

    end



    -- 创建请求

    local xhr = cc.XMLHttpRequest:new()

    xhr.responseType = cc.XMLHTTPREQUEST_RESPONSE_STRING

    xhr:open("post", url, true)

    xhr:registerScriptHandler(

    function()

        -- 移除waitingLayer

        if isNeedWait and waitingLayer then

            waitingLayer:hideAndRemoveSelf()

        end



        -- 校验response

        local response, text 

        if string.find(url, "upload_error_msg") ~= nil or string.find(url, "upload_user_file_5/fankui") ~= nil then

            response, text = xhr.response, xhr.status

        else

            response, text = self:getDecyptResponseWithCheckCheat(url, xhr.response, xhr.status)

        end

        -- 校验response

        -- local response, text = self:getDecyptResponseWithCheckCheat(url, xhr.response, xhr.status)

        -- response 无法获取,直接弹出错误信息文本

        -- if response == nil then

        --     PopText(text)

        -- else

        -- end

        response = Helper:getDef(response, "")

        if PRINT_MODE == 1 then

            print("response:"..tostring(xhr.response))

            print("Decyptresponse:"..tostring(response))

            print("status:"..tostring(xhr.status))

            print( "url = "..url )

        end



        if callback then

            callback(response, xhr.status)

        end

    end)



    -- 设置超时

    xhr.timeout = 999



    -- 设置头

    setHeader(xhr, headers)



    -- 发送请求

    local tmpSendData = sendData

    if type(tmpSendData) == "table" then

        tmpSendData = json.encode(tmpSendData)

    else

        tmpSendData = tostring(tmpSendData)

    end



    if PRINT_MODE == 1 then

        print("加密前 = "..tmpSendData)

    end

    --加密处理

   tmpSendData = self:encryptPostData(tmpSendData ,isNeedEncrypt)

   if PRINT_MODE == 1 then



## 小结

有了这么多优秀的开发工具,可以做出更高质量的Android应用。

当然了,“**打铁还需自身硬**”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。

在这里我也分享一份大佬自己收录整理的**Android学习PDF+架构视频+面试文档+源码笔记**,还有**高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料**这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

这么多优秀的开发工具,可以做出更高质量的Android应用。

当然了,“**打铁还需自身硬**”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。

在这里我也分享一份大佬自己收录整理的**Android学习PDF+架构视频+面试文档+源码笔记**,还有**高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料**这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐