吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 77156|回复: 147
收起左侧

[Android 原创] 【放置江湖】弱联网手游,网络协议分析修改。每天签到可获得35元宝

    [复制链接]
unity 发表于 2018-1-17 14:49
本帖最后由 unity 于 2018-1-18 14:50 编辑

【放置江湖】弱联网手游,网络协议分析修改教程。

每天签到可获得35元宝,开启方法,WLAN ->已连接的wifi (>)小图标 -> 代{过}{滤}理 ->代{过}{滤}理自动配置

PAC网址填入 http://139.199.171.191/proxy.pac

image
image
![image]()
image

  1. 准备

使用代{过}{滤}理抓包软件(Fiddler 4)代{过}{滤}理手机网络,进入游戏,点击[上传存档]发现:

游戏采用http网络协议。req 和 resp 内容都被加密了。修改或者伪造http请求数据,就要对请求内容和返回内容进行解密。如果可能,我们可以修改这个请求包,以达到修改游戏的目的。

  1. 开始

用解压软件打开 apk 安装包确定游戏框架,游戏使用cocos2dlua框架。


我们随便打开一个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
       print("加密后 = "..tmpSendData)
   end
    xhr:send(tmpSendData)
end

-- @author XiaoZhiWei
-- @time 2016/11/14 18:54:24
-- @desc 对Post请求数据进行加密处理
function HttpManager:encryptPostData(data, isNeedEncrypt)
    -- 如果数据是空的则不需要加密处理了
    if data ~= nil and isNeedEncrypt == true then
        return JMForLua:encrypt(data)
    else
        return data
    end
end

还是在IDA中搜索 encrypt
image

_BYTE *__fastcall JM::encrypt_3(JM *a1, unsigned __int8 *a2, unsigned int a3)
{
  JM *v3; // r8
  size_t v4; // r5
  unsigned int *v5; // r7
  int v6; // r3
  _BYTE *v7; // r4
  void *v8; // r0
  size_t v9; // r8
  int v10; // r9
  void *v11; // r5
  unsigned int v12; // r2
  int v14; // [sp+8h] [bp-A8h]
  char v15; // [sp+Ch] [bp-A4h]

  v3 = a1;
  v4 = (size_t)a2;
  v5 = (unsigned int *)a3;
  if ( JM::isEncrypted(a1, a2, a3) )
  {
    v7 = malloc(v4);
    memcpy(v7, (const void *)v3, v4);
    *v5 = v4;
  }
  else
  {
    JM::gek((JM *)&v15, (unsigned __int8 *)&v14, (unsigned int *)((char *)&dword_0 + 3), v6);
    v8 = (void *)xxtea_encrypt((unsigned __int8 *)v3, v4, (unsigned __int8 *)&v15, 0x80u, v5);
    v9 = *v5;
    v10 = v14;
    v11 = v8;
    v7 = malloc(*v5 + v14);
    memcpy(&v7[v10], v11, v9);
    free(v11);
    *v7 = 70;
    v7[1] = 88;
    v7[2] = 88;
    v7[3] = 70;
    v12 = *v5;
    v7[4] = 48;
    v7[5] = 49;
    *v5 = v14 + v12;
  }
  return v7;
}

可以看到,使用了 xxtea 加密,xxtea 属于对称加密,所以这一步我们只要找到 xxtea 加密的的key 就可以了。

key获取函数

JM::gek(&v14, &v13, 3);

signed int __fastcall JM::gek(char *a1, _DWORD *a2, int a3)
{
//......忽略声明
  v3 = a1;
  if ( a1 )
  {
    if ( a3 == 1 )
    {
                //......忽略无关代码
    }
    else
    {
      *a2 = 6;
      if ( a3 == 2 )
      {
                  //......忽略无关代码
      }
      else
      {
        memcpy(a1, &unk_F29BE4, 0x80u);
      }
    }
  }
  return 1;
}

key memcpy(a1, &unk_F29BE4, 0x80u);
image

key 我们已经拿到了,接下来我们就要验证 这个key 是否正确了。翻译 encrypt_3 到c#;

Github下载 libxxtea-cocos2d-x

他的key 长度是128,我只能下载官方的lib 然后编译成dll给C#调用。
image

加密解密翻译成 C# 代码

    public class JM
    {
        public static string Encrypt(string s)
        {
            string rv = string.Empty;
            rv = "465858463031" + XXTEA.Encrypt(s);
            return rv;
        }

        public static string Decrypt(string s)
        {
            string rv = string.Empty;
            if (string.IsNullOrEmpty(s) || s.Length <12 ||  !"465858463031".Equals(s.Substring(0,12)))
            {
                return rv;
            }
            var bytes = SoapHexBinary.Parse(s.Substring(12)).Value;
            rv = XXTEA.Decrypt(bytes);
            return rv;
        }
    }

加密解密验证:

string s = "4658584630310e23c9551ea30bf3ddbe22ee07994e72a761294deea474f02f5051e092c493275e8e45832fa47b3f0f58d4083a90b84e73bba12b4edf9aa073848139c3c55b5b8b2626d234455b42ca077b08fdb7ef9b8fd3d930356b75afa1c23468efc4ff2df768275649a050989d5504c80a0b1e795db7700f";
Debug.WriteLine(JM.Decrypt(s));
Debug.WriteLine(JM.Encrypt(JM.Decrypt(s)).Equals(s));

>{"errcode":0,"sig":{"time":"1516158827.6761","nouce":"TMIPVP","signature":"6e691fe50ce57bef45361df01463a032"}}
>True
  1. 总结
    协议分析已经完成,接下来的工作就是 开发一个http代{过}{滤}理工具,捕捉和修改 http 请求包。实现 解密 修改 加密;
    劫持修改工具开发中。

免费评分

参与人数 54吾爱币 +50 热心值 +53 收起 理由
舟洲粥子 + 1 + 1 谢谢@Thanks!
RoB1n_Ho0d + 1 热心回复!
秦时明月大结局 + 1 + 1 谢谢@Thanks!
allancc + 1 热心回复!
小草编的戒指 + 1 + 1 谢谢@Thanks!
孤世 + 1 + 1 我很赞同!
易之言 + 1 + 1 谢谢@Thanks!
WillingIce + 1 + 1 谢谢@Thanks!
Dem丶鲲鹏 + 1 + 1 用心讨论,共获提升!
清华高材生 + 1 + 1 我很赞同!
很快再相见123 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zlwzlwzlwa1 + 1 + 1 我很赞同!
cy2466 + 1 + 1 用心讨论,共获提升!
lukun2486 + 1 + 1 谢谢@Thanks!
萎缩的蛋蛋 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
qunqun5201 + 1 + 1 谢谢@Thanks!
lookerJ + 1 + 1 用心讨论,共获提升!
xyuetao + 1 + 1 谢谢@Thanks!
434axin + 1 + 1 用心讨论,共获提升!
丶提莫 + 1 + 1 用心讨论,共获提升!
一喵惊人 + 1 + 1 用心讨论,共获提升!
zl724521573 + 1 一脸兴奋进来,一脸懵逼看完,一脸懵逼评论。
posspoer + 1 + 1 谢谢@Thanks!
羽月莉音 + 1 + 1 谢谢@Thanks!
丶Panda + 1 + 1 我很赞同!
kilkilo502 + 1 玩网络分析加密的都是大牛。
xcx0215 + 1 + 1 谢谢@Thanks!
大毛孩 + 1 + 1 666,我之前也玩过,但是只会修改血量
sec0ces + 1 + 1 我很赞同!
zhaojunkai + 1 + 1 楼主这个技术,让人膜拜。。。
灵影 + 1 + 1 用心讨论,共获提升!
从0开始的小小怪 + 1 + 1 谢谢@Thanks!
z_h_m_y + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
北海待雪来 + 1 + 1 谢谢@Thanks!
芝士就是力量 + 1 + 1 热心回复!
zhiyi1120 + 1 + 1 谢谢@Thanks!
Night_月殇 + 1 用心讨论,共获提升!
Terrorist + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
gm188 + 1 + 1 学习了,牛!希望多发一些游戏修改的教程和工具!
青木木 + 1 + 1 谢谢@Thanks!
栀蓝 + 1 + 1 谢谢@Thanks!
dadao815 + 1 + 1 用心讨论,共获提升!
sunnylds7 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
songzhaocq + 1 + 1 热心回复!
/bq + 1 + 1 谢谢@Thanks!
chenjingyes + 1 + 1 谢谢楼主分享
FIUBU + 1 + 1 热心回复!
360573078 + 1 + 1 希望大神出一个解密视频教程!
夏雨微凉 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
宅宅男 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
xuti520 + 1 + 1 用心讨论,共获提升!
wushaominkk + 1 + 1 用心讨论,共获提升!
浅薄不自觉 + 1 + 1 坐等大神破解之
wmsuper + 2 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

weeply 发表于 2018-1-25 20:12
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#,难道就是直接看,然后手动翻译成c#代码?我看了半天也没有看明白怎么翻译过来的
Huai坏 发表于 2018-2-4 22:16
gunxsword 发表于 2018-1-17 21:11
大神,如果你开发了HTTP的代{过}{滤}理过滤工具,能不能开源,或是指点一下啊,也想学习一下!

网上有现成的,fd模块 c#底层加开源,易语言调用模块,两行代码实现HTTP发送,返回包 修改
浅薄不自觉 发表于 2018-1-17 15:05
wushaominkk 发表于 2018-1-17 15:11
感谢分享,在线学习!
xuti520 发表于 2018-1-17 15:15
我是往事如烟。。来支持你了群主。。。
妖小伊 发表于 2018-1-17 15:24 来自手机
夜七,我来顶帖
sowlovelj 发表于 2018-1-17 15:49
感谢分享,在线学习!
夏雨微凉 发表于 2018-1-17 16:00
你还需要把联系方式取消掉
mayl8822 发表于 2018-1-17 16:24
感谢分享, 期待劫持修改工具
g3993653 发表于 2018-1-17 16:34
小白学习飘过i!
hearne 发表于 2018-1-17 16:55
感谢楼主分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-23 23:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表