吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 98600|回复: 251
上一主题 下一主题
收起左侧

[Android 原创] unity游戏生成与修改so文件教程

    [复制链接]
跳转到指定楼层
楼主
迷之裙摆 发表于 2017-6-21 23:52 回帖奖励
本帖最后由 迷之裙摆 于 2018-1-27 21:14 编辑

本文主要介绍如何对unity3d引擎制作的游戏进行修改。包含了apk文件安装后在手机中的位置分析、修改游戏时遇见内联函数之坑时的解决办法,以及so文件的原理介绍与解析修改。并将实例教学如何修改unity3d游戏(想学崩坏3修改的同学请注意啦)。教程是给入门新手看的,请大神绕道勿喷。文章的核心内容在最后利用Il2CppDumper的部分,前面清楚的话可直接绕到最后看。(因为手机截图下来的图片分辨率太大。看起来排版会不太舒服,可以直接到文章最后下载文档查看,排版会舒服很多)
基础知识
0x1.apk安装后在手机中的目录
apk安装后会在两个包下生成相关包:data/data/、data/app/。

这里拿网易云音乐的安装目录举例。Data/App目录下通常会有三个文件:
1.lib文件夹(包含so库文件)、
2.oat文件夹(OAT文件是一种android私有ELF文件格式,它不仅包含有从DEX文件翻译而来的本     地机器指令,还包含有原来的DEX文件内容。这使得我们无需重新编译原有的APK就可以让它正常地在ART 里面运行
3.base.apk启动包。【其中apk启动包是不允许重命名或删除的,因为app运行时其实就是链接到这个启动包,然后才能继续启动操作。这个启动包用beyond对比后可以发现,与原安装包没有任何不同,所以就相当与apk的原版安装包】。
    
                                 


Data/data目录下一般是存储lib文件夹(保护so库文件)以及其他数据文件、缓存等。只需要知道这里的lib实际上与data/app目录下的lib目录中内容是一样的。  
游戏在运行的时候,一般都会载入dada/data目录中的lib与data/app中的lib,通常来说只需要修改data/data中的lib文件夹中的so文件即可达到成功修改的效果。当然也有一小部分游戏根本不读取data/data目录下的lib文件夹,待会会讲到。
      
0x2.Unity3D中的资源路径

Application.dataPath

此属性用于返回程序的数据文件所在文件夹的路径。例如在Editor中就是Assets了。

Application.streamingAssetsPath

此属性用于返回流数据的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径。

Application.persistentDataPath

此属性用于返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。

Application.temporaryCachePath

此属性用于返回一个临时数据的缓存目录。
android平台

Application.dataPath

/data/app/xxx.xxx.xxx.apk

Application.streamingAssetsPath

jar:file:///data/app/xxx.xxx.xxx.apk/!/assets

Application.persistentDataPath

/data/data/xxx.xxx.xxx/files

Application.temporaryCachePath

/data/data/xxx.xxx.xxx/cache
IOS平台

Application.dataPath

Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data

Application.streamingAssetsPath

Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw

Application.persistentDataPath

Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents

Application.temporaryCachePath

Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches

0x3.C#的inline内联函数优化
虽然C#不支持inline,但是JIT支持自动inline,即将IL转成真正机器码时,会自动将某些函数进行inline展开,只是条件非常苛刻,网上提到JIT自动进行inline展开的一些选择依据:
1)函数内部有循环语句、catch语句等复杂结构,都不做inline优化。
2)函数体比较长的不做inline优化,只有比较简单的才可能inline优化。(有人说IL不足32字节才做inline),
2)编译成机器码时,inline展开的代码比函数调用更短的,一定做inline。(注:如果参数多而代码少,就符合此情况)
这里为什么要讲内联函数呢,加入如果游戏中有一个读取人物攻击力的函数,其内部代码十分简单,结果被编译为机器码的时候变为了内联函数。那么这个时候要来修改就十分麻烦了,因为你找到那个读取人物攻击力的函数是没有用的,修改了也是白修改,只能到每一处调用这个函数的地方逐行修改。
好了,说了这么多,下面从开始unity3d游戏开发的的角度逐渐逆向分析。

一、通过unity3d打包生成libil2cpp.so:
1.如何识别u3d游戏?打开解压包,如果lib文件夹下有libunity.so就证明这是一个unity3d游戏。
2.要修改Unity3d游戏,首先就要对其游戏代码存放位置有一个基本的了解。Unity3d生成游戏的游戏主逻辑一般放在三个地方:libil2cpp.so、Assembly-CSharp.dll、lua脚本。
【对于libil2cpp.so来说:我们知道,unity3d最大的一个特点是一次制作,多平台部署,而这一核心功能是靠Mono实现的。但是在2014年年中的时候,Unity3D引出了IL2CPP的概念,IL2CPP,英文意思即Intermediate Language to cpp,就是把IL中间语言转换成CPP文件。】
上面所说的这三个地方通常来说是唯一的,即只会出现一种情况。这是由unity3d引擎的生成方式决定的。下面通过开发者的角度对unity3d生成游戏进行实例讲解:

新建unity3d工程,工程命名为HelloCPP!:


利用ugui创建两个text,一个为“CoinUI”显示“金币”,一个为“Coin”显示金币值,并创建脚本GameManager,绑定在MainCamera中。

脚本GameManager代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;


public class GameManager : MonoBehaviour {


    private GameObject coin;
void Start () {
        coin = GameObject.Find("Coin");

}
    private int GetCoin()
    {
        return 50;
            
    }
    public void ChangeCoin()
    {
        float v = GetCoin();
        coin.GetComponent<Text>().text = v.ToString();
    }
}
方法与按钮事件绑定。那么当点击按钮的时候就会更新一次</font>ui。</font></font></font>

代码中的GetCoin方法放回一个50的数值,当游戏运行起来的时候,脚本会将ui界面中Coin的值改为50,如下:


好了,游戏逻辑已经写完了,保存场景,直接打包,点击主菜单file>BuildSetting进入打包界面,选择转化为android平台,并点击playersetting进入配置界面:
这里我把PackageName设置为com.hellocpp。
然后页面下拉,找到scriptingbackend:




这里的scriptingBackend就是设置生成游戏的游戏逻辑存放方式,如果选择默认的Mono2x的话,会在反编译后的apk的assets\bin\Data\Managed目录下找到Assembly-CSharp.dll文件,也就是大多数unity游戏逻辑存放的位置,这种情况下,lib文件夹下是没有libil2cpp.so文件的。如果是选择IL2CPP的话,会在lib文件夹下生成libil2cpp.so文件,并在assets\bin\Data\Managed\Metadata目录下生成global-metadata.dat配置文件。


对于生成Assembly-CSharp.dll文件的情况来说,用reflector很容易修改,这里略过,直接讲解生成libil2cpp.so文件的情况。把生成的apk直接拖入ide中反编译,进入根目录后,进入lib文件夹中观察。

二、对生成的apk进行反编译分析

直接把apk拖入ide,然后进入lib文件夹查看




生成了两个文件夹,一个是armeabi-v7a,即arm架构,一个为x86,是因特尔架构。我们这里进入arm文件夹中分析。
【有时会有人问,为什么so修改后模拟器运行闪退,无法正常运行?这种情况多半是因为你只修改了arm文件夹下的so,所以只能在大部分真机中运行,因为真机多半是arm架构的,而模拟器是因特尔架构的,所以在模拟器上运行会奔溃。】

可以看到,里面一共三个文件,其中libunity与libmain是unity的内部文件,我们不需要去管它,现在只需要知道这里确实生成了libil2cpp.so即可。

好了,现在我们要分析修改这个apk,手机中运行起来我们发现其显示金币为50,我们现在来修改其数值。



按照国际惯例,先在ide中搜索字符串“金币”,发现没有结果,于是判断游戏逻辑在so中,我们再搜索loadlibrary,然后发现了里面唯一用到的原生方法是在libmain中,然后估计就有人去分析libmain.so文件了,但libmain.so里面其实是没有游戏核心逻辑的,这只是unity内部的一些库,真正的游戏核心逻辑是在libil2cpp.so中,这个库文件实在载入libmain后才被调用的。
所以,碰到unity游戏,一定要先看看lib文件夹下是否有libil2cpp.so,如果有的话,直接分析这个so就行了,从smali分析存粹是浪费体力。
打开IDA,载入so,搜索coin,会发现依然找不到相关函数,推测在jni中动态加载,然而搜索jni也是找不到任何函数。在view-A面板中寻找,发现大多数函数只有一个函数尾,而函数头似乎被可以“掐”掉了。



三、对Il2CppDumper.exe工具的介绍
出现上述情况的原因与unity引擎中的MetadataCache.cpp相关,打开u3d目录,可找到MetadataCache.cpp:


意思就是在生成libil2cpp.so时,u3d同时会在目录assets\bin\Data\Managed\Metadata下生产资源文件global-metadata.dat。游戏中使用的字符串都被保存在了一个叫global-metadata.dat的资源文件里,只有在动态运行时才会将这些字符串读入内存。这使得用IDA对游戏进行静态分析变得更加困难。那么为了解决这个困难,有人造了轮子,即Il2CppDumper.exe。此可读取global-metadata.dat文件中的信息,并与libil2cpp.so结合起来。


相关源码可看国外大神的分析:还原使用IL2CPP编译的unity游戏的symbol(一)
【https://www.nevermoe.com/?p=572】以及(github:https://github.com/nevermoe/unity_metadata_loader)与github:https://github.com/Perfare/Il2CppDumper)

好了,如果你觉得这个看起来过于麻烦的话,可以直接略过,只要学会使用其工具化下来的exe就行了。

这里为了方便下载直接使用,我已经把exe文件生成出来了,会直接打包到百度云。
这个exe文件主要是通过对global-metadata.dat与so文件的结合自动生成相关函数与其对应在ida中的偏移地址。(相关原理其实就是分析global-metadata.dat,这里是自动帮我们省去了这个步骤)。

使用方法:
打开Il2CppDumper.exe,会弹出一个窗口,第一个选择lib2cpp.so,第二个选择global-metadata.dat,然后按下键盘键2,就会自动完成后续的操作了。





生成的文件就是这个dump.cs,我们点进去后直接搜索coin,定位到这里:


下面的数字就是偏移量,复制511f50后进入ida,按g键进入到相关地址
发现代码没有展开的话,按一下c键就可以了。

可以看到,他这里是返回了50。那么,这个时候我们就兴奋了,这里就是我们要修改的地方!讲道理把这里的0x32修改为0xFF00后,我们在游戏中点击按钮,显现的值就应该变为65280了:

用hex二进制修改器修改后,命名为libil2cpp改.so。
接下来可以直接把so替换掉原so然后打包回编译,但这种办法遇到apk有签名验证或其他乱七八糟的检验时不好操作。这里我们使用另一种部分,即先安装apk到手机,然后进去根目录下去手动把so给替换掉(手机需root)。

把apk与修改后的so一起扔进手机:





安装apk后,先打开来看看,点击按钮后,金币为50


好了,接下来就是替换so了。在前面的基础知识中我们讲到,apk安装后,会在data/data与data/app下分别生成自己的包文件。并且两个文件夹下都有lib,里面封装了一样的so库文件。那么我们是去替换哪一个呢?答案:两个都试试。
因为有些app只读取data/app/com.hellocpp目录下的lib文件夹信息,不读取data下的文件夹信息,比如这个apk。你会发现你直接把data/data下的com.hellocpp包给删掉也是完全可以运行的,但是如果你删了app目录下的com.hellocpp/lib,立刻无法运行。
我们把原so重命名为libil2cpp.so原,然后把改后的so命名为libil2cpp.so

大功告成,我们重新打开游戏,然后会发现。
没有任何变化(心凉)


正常情况这样修改后就应该会成功了的,但是这里为什么依然没有任何变化呢。
这里又涉及到前面说的基础知识,当这种情况发生的时候,很可能就是函数内联了。
你修改函数本体是没有任何效果的,因为这个函数被调用它的函数内置了。你必须找到所有调用这个函数的地方,去找到相关点修改。这个就需要去看汇编代码了。
我们也可以动态调试的时候在getcoin()方法处下一个断点,然后ida动态调试,会发现按钮按下时确实没有断下来(限于篇幅请读者自行尝试)。或者我们直接把那个函数本体给nop掉,会发现程序依旧正常运行,这都说明了函数确实内联了。

内联了的函数很难分析,我遇到了就只能跑路,这里只是点出其位置,再深入的分析就要去好好读代码了,不多分析(如果有大神会的话麻烦评论区指点指点)

这里我直接找到这个地方,改为mov r0,0

再次替换后运行结果确实变为0了:



实例二
好了,分析完上面这个核心处存在内联函数的apk,我们下面来一个最常见的apk修改实例。
仍然是上面这个apk的功能,但不同的是为了防止其编译的时候又被当成内联函数编译了,我在方法GetCoin()内增加了一个循环和几个debug,确保其不被当作内联。其他功能不变。依旧是在GetCoin()中返回50,然后在ChangeCoin()修改ui界面的数值。
代码如下:


然后同样步骤打包生成apk,但把包名改为了com.HellobanInline
生成apk后直接扔进ide中反编译,然后把global-metadata.dat与libil2cpp.so拿出来,用Il2CppDumper.exe把函数名生成出来:

打开dump.cs,搜索GetCoin()


函数位置在偏移511d48上。

因为方法是返回一个int值的数值,我们直接让其返回0xff00,也就是65280.


用hex二进制文件修改后把文件命名【libil2cpp改.so】。与apk一起扔到手机中。
Apk安装完成后,进入data/app中的包com.HellobanInline-1的lib/arm中,把【libil2cpp改.so】复制进来,重命名如下:
【这里对为什么包名后面有一个-1做一下解释:这是因为复制版本覆盖。一般来说第一次安装的话包名后缀-1,第二次覆盖安装就会多一个相同包名后缀为-2,再次覆盖安装又会变为-1……】
                  

好了,大功告成,这个时候充满期待的打开apk吧。点击按钮后数值已经由50变为了65280!
效果图:







    市面上绝大部分游戏都是直接生成c#方法名后到ida中直接修改就生效了,像实例一的比较少见,但有助与深入理解。
    一般生成方法名后,就看修改经验或游戏开发经验了,比较火的u3d游戏有很多,比如崩坏3的修改,你可以搜索方法名“GetBaseAttack”,修改为一个超大值,那么你人物就一击十几亿,防御十几亿,生命十几亿了。对于崩二的话,其加了爱加密的壳,并且似乎有检验so是否被篡改,若有高人能跳过检测希望能告诉我一下,十分感谢!然后再其他的游戏修改也都是这套路,多多熟悉就会了。

    大概就这些内容吧,自己罗里吧嗦的,感觉篇幅有点累赘了。






    百度云链接:链接:https://pan.baidu.com/s/1htaB64k 密码:xrf3    解压密码www.52pojie.cn
    world文档:  http://pan.baidu.com/s/1i5EC5pj 密码:ja84

图片1.png (78.43 KB, 下载次数: 18)

图片1.png

点评

理论实战,从何起从何止说得明明白白,佩服~~  发表于 2018-2-3 12:39
楼主太屌太无私,期待楼主分享更多教程。  发表于 2017-8-29 20:55

免费评分

参与人数 89吾爱币 +86 热心值 +85 收起 理由
peter336620 + 1 + 1 热心回复!
sylainy + 1 + 1 实际上HEX那里是怎样修改的?能详细一点点吗?
lovFlov + 2 谢谢@Thanks!
Erop + 1 + 1 我很赞同!
HarunaPr + 1 + 1 谢谢@Thanks!
一不小心就丶 + 1 + 1 谢谢@Thanks!
tigerxiao + 1 + 1 谢谢@Thanks!
payon + 1 + 1 我很赞同!
878510 + 1 + 1 第一次不回复赚1吾爱币直接送分
q739806133 + 1 + 1 用心讨论,共获提升!
我为什么那么帅 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
dwq308 + 1 + 1 用心讨论,共获提升!
charlie428 + 1 + 1 用心讨论,共获提升!
违规昵称85 + 1 + 1 谢谢@Thanks!
经纪人老宋 + 1 + 1 谢谢@Thanks!
快乐交友 + 1 + 1 我很赞同!
猫KsWeb点Cc + 1 + 1 热心回复!
kilkilo502 + 1 我很赞同!
hoory + 1 + 1 谢谢@Thanks!
black90 + 1 + 1 谢谢@Thanks!
yikuaiyingbi + 1 + 1 热心回复!
voiov + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
蔡啊川 + 1 + 1 用心讨论,共获提升!
haio1186 + 1 + 1 谢谢@Thanks!
as657366738 + 1 + 1 内联代码 可以通过 本体特征码搜索 结合动态调试确认位置
风随 + 1 + 1 谢谢@Thanks!
77012345789 + 1 + 1 我很赞同!
卖血上网 + 1 + 1 热心回复!
baixingjian8 + 1 + 1 楼主太屌太无私,期待楼主分享更多教程。
刘以坤 + 1 + 1 我的妈呀 好复杂 看来还是得从基础开始
爷单身1却潇洒 + 1 + 1 谢谢@Thanks!
木堇 + 1 + 1 我很赞同!
debugbaby + 1 + 1 我很赞同!
long7854874 + 1 + 1 谢谢@Thanks!
大帅哥 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
13525 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
捨嘚 + 1 + 1 谢谢@Thanks!
7963147 + 1 + 1 用心讨论,共获提升!
sensMe + 1 + 1 用心讨论,共获提升!
浅忆万人敬仰 + 1 + 1 谢谢分享,正在学这个
kesshei + 1 + 1 我很赞同!
色调分离 + 1 + 1 热心回复!
是我太过冲动 + 1 + 1 热心回复!
从0开始的小小怪 + 1 + 1 谢谢@Thanks!
envisocy + 1 + 1 用心讨论,共获提升!
LzSkyline + 1 + 1 解压密码好评..
温华 + 1 + 1 热心回复!
mike_spdb + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
zy1234 + 1 + 1 谢谢@Thanks!
siuhoapdou + 1 + 1 谢谢@Thanks!
h080294 + 1 + 1 热心回复!
zhuzaiting + 1 + 1 谢谢@Thanks!
Lullaby. + 1 + 1 我很赞同!
幻想Fly + 1 + 1 我很赞同!
fruitg + 1 谢谢@Thanks!
2864095098 + 1 热心回复!
djzhao + 1 + 1 用心的教程,赞一个
weichao983 + 1 + 1 热心回复!
流年回忆 + 1 + 1 谢谢@Thanks!
kelibaba + 2 + 1 经典极品教程.必须顶一个
peter_king + 1 谢谢@Thanks!
在那悠远的穹 + 1 + 1 谢谢@Thanks!
宰相 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
幸福丶九尾 + 1 + 1 热心回复!
byxiaoxie + 2 + 1 谢谢@Thanks!
莉姐 + 1 + 1 热心回复!
95535916 + 1 + 1 谢谢@Thanks!
h19981126g + 1 + 1 热心回复!
很快再相见123 + 1 + 1 我很赞同!
Gleam + 1 + 1 用心讨论,共获提升!
旧年白白白 + 1 + 1 谢谢@Thanks!
灵影 + 1 + 1 膜拜大佬 共同进步
思念是一种病丶 + 1 + 1 我很赞同!
SomnusXZY + 1 + 1 热心回复!
qaz003 + 1 谢谢@Thanks!
独行风云 + 1 + 1 谢谢@Thanks!
另类飞翔 + 2 + 1 热心回复!
1451345234 + 1 + 1 超级棒!!!!
aa38123 + 1 + 1 热心回复!
yyhf + 1 热心回复!
夏雨微凉 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
宇翾菌 + 1 找了好久关于so文件修改方法的文章 原来在这里
dj1149 + 1 + 1 我很赞同!
Glimmer + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
木子木泗 + 1 热心回复!
sumith + 1 + 1 我很赞同!
雫Hao洋洋 + 1 热心回复!
lertty + 1 + 1 我很赞同!
羊之心羽 + 1 + 1 已答复!

查看全部评分

本帖被以下淘专辑推荐:

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

推荐
艾莉希雅 发表于 2017-6-25 17:02
茂.茂 发表于 2017-6-25 11:57
迷之裙摆 发表于 2017-6-24 22:16
那个问题看了你给的代码后清楚了,好奇那是什么工具编译出来的,居然那 ...

mov     eax, 23333
ret
数字自己改……IDA可以直接改x86汇编的
push    ebp
mov     ebp, esp
mov     eax, 23333
pop     ebp
ret
你喜欢的话这样子写也行……

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
茂.茂 + 1 + 1 谢谢@Thanks!

查看全部评分

推荐
 楼主| 迷之裙摆 发表于 2017-7-8 14:15 |楼主
茂.茂 发表于 2017-7-7 08:00
艾莉希雅 发表于 2017-7-6 22:08
最后救一次……就酱……
你把头补好啊AF 1B B1 FA 15

二次覆盖可过验证

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
茂.茂 + 1 + 1 热心回复!

查看全部评分

推荐
艾莉希雅 发表于 2017-7-6 22:08
茂.茂 发表于 2017-7-6 13:45
楼主 今天崩坏3更新后 dump不能用了


最后救一次……就酱……
你把头补好啊AF 1B B1 FA 15


再说下去出人命了

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
茂.茂 + 1 + 1 我很赞同!

查看全部评分

沙发
 楼主| 迷之裙摆 发表于 2017-6-21 23:58 |楼主
打包下来的百度云链接:
链接:http://pan.baidu.com/s/1i5Hur2H 密码:viqv
3#
艾莉希雅 发表于 2017-6-22 00:09
https://www.perfare.net/759.html
这东西……其实是国内dalao的玩具……
4#
z529943198 发表于 2017-6-22 10:20
学习了涨知识了
5#
tbwin658 发表于 2017-6-22 10:23
过来学习一下。
6#
夏雨微凉 发表于 2017-6-22 12:45
插眼~    以后过来学习
7#
zhirc 发表于 2017-6-22 12:59
感谢分享,支持一下
8#
fengmapleye 发表于 2017-6-22 14:01
哇这个  你是要和米忽悠正面刚么
9#
茂.茂 发表于 2017-6-22 18:17
大佬我在别人改的崩坏3so文件基础上修改了getbaseattack ,发现要么没有攻击力 要么只能是变态版的8000多攻击,也就是别人改好的数据。我自己一改 就会失效 ,不知道这是为什么。 求指教。谢谢!
10#
 楼主| 迷之裙摆 发表于 2017-6-22 18:29 |楼主
茂.茂 发表于 2017-6-22 18:17
大佬我在别人改的崩坏3so文件基础上修改了getbaseattack ,发现要么没有攻击力 要么只能是变态版的8000多攻 ...

你没改成功吧?so要放在dada/dada目录下。或者可能你找到的函数位置不对。好像是在什么avatardata下的getbaseattack函数
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-18 17:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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