吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 62590|回复: 247
收起左侧

[原创] idapython获取微信GIF动图

    [复制链接]
ZjyCjy 发表于 2018-5-6 18:00
本帖最后由 ZjyCjy 于 2018-5-6 18:03 编辑

最近一周都没课了。emm,闲来无事想从微信上下一波表情包。然而微信在我不知不觉中更新了。以前的套路没法用了,于是自己就花时间研究了一下。特记此文。
使用的工具主要是IDA,分析的对象是PC新版微信客户端,目标是获取GIF动图。
ps:我这指的GIF是指微信表情商店里的表情(只能发送给别人,没办法保存到本地)

老版微信如何保存GIF

做这件事情的起因就是发现我PC上的微信自己更新了,那么就先安利一下老版本如何截取GIF图片。我使用的是PC版的微信客户端,有关Android版的不在讨论范围内。

首先我们找到PC版的用户配置文件夹。一般在文档文件夹下,以微信id表示账号。如下图所示。
wx

其中的CustomEmotions就是老版本微信缓存的GIF位置,当我们登陆PC版微信,然后用手机给别人发图的时候。消息同会同步到PC上,其中的GIF图片被处理后保存到这个文件夹内。具体是怎样处理的我也忘了,好像就是改GIF文件头部,其他没有变化。这样我们就能得到GIF了。

新版微信对GIF缓存做了什么处理

但是微信更新后,此时CustomEmotions文件夹内不会保存任何东西,甚至删除该文件夹也不会影响微信接受消息。这时所有的GIF被保存到CustomEmoV1文件夹内,而且均被加密处理。为了演示效果,我首先将该文件夹清空,然后用手机给别人发图(手动滑稽),效果如下图所示。

wx2

此时PC上同步显示图片,同时GIF被保存到CustomEmoV1文件夹内,如下图所示。

wx3

很明显,一张GIF对于一个文件,文件名32位长,可能是MD5。然后我们选择一个文件打开。

wx4

可以看到文件头被修改成V1MMWX,WX肯定指的就是微信了,V1MM不知道是什么,应该是微信开发人员定义的格式。不仅如此,熟悉GIF格式的童鞋也不难发现,除了文件头,下面的内容也被加密了。

下面我就讲一下我是怎么分析这个文件的。

如何分析加密数据

首先看一下文件的大小是否发生变化。这里我要解释一下的是,我以前曾经从老版的微信上获取过GIF,这些GIF我都保存了,所以可以直接用该GIF和加密后的GIF进行对比,就不截图了。对比的结果是:加密后的大小比加密前的大小多7字节。

如何看待这7个字节

  • 我认为其中有6个字节是V1MMWX这个文件头造成的影响。
  • 对100KB左右的文件来说,加密是需要时间的,但是微信是即时通讯工具,开发人员应该不会使用复杂的加密算法。
  • 整体上来说,加密前后数据量大小是一致的。

基于以上三点,我猜测就是一个简单的亦或加密。然后我用python的xortool分析了一下该文件。

wx5

然后自动分析出极大可能解,这里它给出了一个key是0x2b('+')。

wx6

最后我将得到的文件和原始文件比对。

wx7

惊人的发现!除了前0x3ff字节不一样,后面的字节都是一样的,也就是说,加密的方式其中之一就是亦或。具体就是对文件从0x400开始的字节亦或0x2b。

到现在为止,我已经知道了文件后面一部分的加密方式,如何解密前面一部分呢?我认为还是要抓住V1MM这个文件头,因为这个头是开发人员固定的,那么这个值应该是个明文,或者说是应该是某个exe或者dll中.rdata段的(我只能期望它不是SMC之类动态生成的了)于是我就去微信安装目录下找这个字符串在哪。
结合exe和dll的名称、以及更新日期,我很幸运的找到了。

wx8

找到之后很显然要干什么了。开IDA吧。

开始分析WeChatWin.dll

由于这个dll相当的大,IDA分析了很久才完,我也是第二次分析这么大的东西(第一次是某CTF的tensorflow),话不多说,直接shift+f12找V1MM字符串的位置。然后我就惊了,ida没找到,估计是类型不对吧。无奈,只好手工定位了。第一次失败了,忘了是FOA了,要转成RVA。算了,直接定位到.rdata基址,直接用偏移,终于发现了V1MM的位置。

wx9

然后就交叉引用,发现有三处,其中2处由同一个函数引用(另外一处应该是CRT或者编译器函数)进入这个函数分析。直接f5后,能发现关键的几行代码,如下图所示。

wx10

这几行就是GIF加密后保存的地方了,首先将6字节的V1MMMX复制到cipher指针指向的首地址,然后是2个move函数,也可以理解是memcpy。而且第一个是从cipher指针指向首地址向后移动6字节开始的,那肯定就是上文中未解密的部分了。第二个move又是从第一个move结束的地方开始的,那就是上文提到的异或算法了。

由于这段是最后部分,加密都处理完了,我们需要往上看,同时整体把握这个函数的作用。

wx11

可以发现,该函数应该是一个BOOL类型的函数,若处理成功则返回1,否则返回0。还能发现的是,cipher虽然是个局部变量,但在函数第一行可以发现它被指向了该函数的第二个参数,考虑到是BOOL类型的函数,函数只能返回一个值,那么对这个处理的函数而言,只有可能将文件句柄作为参数传入,修改后才能有效。也就是说该函数的第一个参数应该是文件句柄,而指向加密内容的第二个参数应该是加密后的指针所指向的地方。
还有一些地方指的思考,比如a1[1]这个地方的值是什么。

if ( a1[1] <= 0 )
   return 0;

在函数一开始,就比较a1[1]这个地方的值,小于0则直接返回,我猜测是是文件大小的意思。后面的代码直接验证了我的猜想。

wx12

看到了熟悉的0x3ff,上文已经提到了,加密的GIF前面0x3ff的加密方式还是未知的,这里直接比较a1[1]和0x3ff的大小,其实就是判断GIF的大小,如果比0x3ff小,那么v7变量就不能想0x3ff,而是文件的大小。也就是说如果GIF本身大小不超过0x3ff,就不会使用第二部分的异或加密。

struct a
{
    int* file;
    int size;
}

分析完这部分,我们可以将该函数的第一个参数转换成结构体,第一个值是文件内容指针,第二个值是文件的大小。关于这个值怎么得到并传入该函数的,不是我们分析的重点。

wx13

回过头来再看最后一部分传入的第二个参数,其实我们就能分别找到那2个加密的函数。其中绿色框中的2个函数就是加密的2个函数。
我们先看第二个函数,也就是异或那个。

第二段加密-异或

wx14

进入这个函数就能看到,很明显的取了一个byte(0x2b),然后循环异或,具体的过程我就不分析了,只是验证一下,因为最开始的时候我已经用xortool自动分析出来了。有兴趣的可以分析一下,或者动态调试一下看看是怎么加密的。

第一段加密-rsa

这个第一段加密很复杂,emm看着就不想分析了,看见一串明文crypto\\rsa\\rsa_lib.c更是让我感到绝望。

wx15

wx16

哇,是真的绝望。。。
然后就没有然后了,我是没有分析下去。应该是解密不了的。毕竟输出的是一个缓存文件,如果要分析微信是否能读取GIF缓存,或者说读取的格式是怎样的,我的功力还不够。。。(我要弃坑,我要转web)
讲道理,上面的路已经不通了,下面开始想想别的方法。

如何获取GIF

其实方法我刚刚已经提示了,因为这个函数接受的参数就是完整的GIF,这个结构体上面也解释了,只要获取这个结构体就能拿到完整的GIF。因此,我们返回到原来那个函数的入口点,看什么时候结构体参数被引用。

wx17

显然就是这里了,在将参数传给edi后,后面就判断结构体的第二个属性,即文件长度是否大于0。如果我们能在dll每次运行到这里的时候获取这两个数据,然后dump指定内存,就能拖出这个GIF图,也就不需要解密了。然后我动态调试了很多次,幸运的是并没有触发什么反调试和异常,使用的方式是idapython,首先是手动加载。

location = GetRegValue('edi')
sizeptr = GetRegValue('edi') + 0x4
start = Dword(location)
n = Dword(sizeptr)
f = open(os.path.join(savepath, str(count)) + '.gif', 'wb')
for i in xrange(n):
    f.write(chr(Byte(start + i)))
f.close()

然后每次都发个图给别人,PC就会缓存,然后GIF就会被保存下来了。如果每次都是手动加载的话,我记得这段代码是没问题的。但是不想每次都由我自己来下断点然后dump,为了实现自动化,自己也是学习了一波idapython来自定义Debugger Hook。

idapython的Debugger Hooks

主要用于Hook IDA 内部的调试器,同时可以自定义调试功能。结构如下

class DbgHook(DBG_Hooks):
    def dbg_process_start(self, pid, tid, ea, name, base, size):
        return
    def dbg_process_exit(self, pid, tid, ea, code):
        return
    def dbg_library_load(self, pid, tid, ea, name, base, size):
        return
    def dbg_bpt(self, tid, ea):
        return

安装hook的方式如下

debugger = DbgHook()
debugger.hook()

一开始我是在dbg_process_start来自动插入断点的,但是后来发现效果并不会,这一点我之后会说明。

我通过定义了MyDbgHook来继承DBG_Hooks,再次载入上面的脚本运行,结果却是这样的。

wx18

文件里写的都是0xff。除了这种情况还会发生发送多个图片,获取的GIF均是同一个的离奇事件。查了半天不知道哪里出了原因。最后翻idapython的资料,最后发现是api使用不当,但是具体是为什么也没有资料,感觉Dword(ea)和DbgDword(ea)之类的都差不多,可能一个前面有dbg所以是dbg专用的吗。
更新后的脚本。

location = GetRegValue('edi')
sizeptr = GetRegValue('edi') + 0x4
start = DbgDword(location)
n = DbgDword(sizeptr)
f = open(os.path.join(savepath, str(count))+'.gif','wb')
for i in xrange(n):
    f.write(chr(Byte(start+i)))
f.close()

运行结果如下图。

wx19

更新后,效果好了很多,但是还是有问题,有的能显示,有的GIF显示不了,于是又查了一波idapython资料,最后发现还是api使用不当。。。Byte(ea)、DbgByte(ea)还有DbgRead(ea,n),其实功能都是一样的,可能是Dbg的方式影响了某些API的实现,导致出现了很多问题。
再次更新脚本。

location = GetRegValue('edi')
sizeptr = GetRegValue('edi') + 0x4
print "
  • \tGif location:[%08x],sizeptr:[%08x]"% (location, sizeptr) start = DbgDword(location) n = DbgDword(sizeptr) print "
  • \tGif start:[%08x],n:[%08x]"% (start, n) dump = DbgRead(start,n) f = open(os.path.join(self.savepath, str(self.count))+'.gif','wb') f.write(dump) f.close() self.count += 1
  • ida日志输出如下图。

    wx20

    运行结果如下图。

    wx21

    完整代码及说明

    代码的几点说明:

    • dbg_process_start是最先加载的,在这里下断点会导致问题。
    • Modules()用于遍历整个环境中的模块,一开始我是想通过这个下断点的,后来发现DBG_Hooks已经提供了类似的函数,就是dbg_library_load,由于我的目标是WeChatWin.dll,当其加载的时候下断点就行了。
    • 下断点的方式是通过偏移量来实现的,考虑到ASLR或者其他不可抗因素,直接VA下断不可行,通过模块BA+0x1000+offsite来实现,0x1000就是.text的VirtualAddress,详细可以参照PE中的节表。
    • Dbg模式下请使用ida python对应的API,否则如上文所述会导致未知情况。如将Dword(ea)替换成DbgDword(ea)。
    # coding:utf-8
    __author__='zjgcjy'
    
    from idaapi import *
    from idautils import *
    from idc import *
    import os
    
    # 没用到,效果不好,或者说dbg_library_load更方便
    def Modules():
        mod = idaapi.module_info_t()
        result = idaapi.get_first_module(mod)
        while result:
            yield idaapi.object_t(name=mod.name, size=mod.size, base=mod.base, rebase_to=mod.rebase_to)
            result = idaapi.get_next_module(mod)
    
    class MyDbgHook(DBG_Hooks):
        #GIF计数
        count = 0
        #保存目录
        savepath = "C:\\Users\\xxxxxx\\Desktop\\emotion"
        keyLocation = 0
    
        def dbg_process_start(self, pid, tid, ea, name, base, size):
            #不要在这里插入断点
            #for i in Modules():
            #   if 'WeChatWin.dll' in i.name:
            #       print "module:[%s]\tsize:[%#x]\tbase:[%#x]\tend:[%#x]" %(i.name, i.size, i.base, i.rebase_to)
            #       self.keyLocation = i.base
            #self.keyLocation += 0x247970
            #AddBpt(self.keyLocation)
            #print 'keybreakpoint:[%#x]' % self.keyLocation
            print "MyDbgHook : Process started, pid=%d tid=%d name=%s" % (pid, tid, name)
    
        def dbg_process_exit(self, pid, tid, ea, code):  
            print "MyDbgHook : Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code)
    
        def dbg_library_load(self, pid, tid, ea, name, base, size):  
            print "MyDbgHook : Library loaded: pid=%d tid=%d name=%s base=%x" % (pid, tid, name, base)
            # 对WeChatWin.dll下断点
            if 'WeChatWin.dll' in name:
                self.keyLocation = base
                self.keyLocation = self.keyLocation + 0x1000 + 0x247970
                AddBpt(self.keyLocation)
                print 'keybreakpoint:[%#x]' % self.keyLocation
    
        def dbg_library_unload(self, pid, tid, ea, info):  
            print "MyDbgHook : Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info)
            return 0  
    
        def dbg_bpt(self, tid, ea):
            print "MyDbgHook : Break point at %s[0x%x] pid=%d" % (GetFunctionName(ea), ea, tid)
            #是否到了关键的地址
            if GetRegValue('eip') == self.keyLocation :
                location = GetRegValue('edi')
                sizeptr = GetRegValue('edi') + 0x4
                print "
  • \tGif location:[%08x],sizeptr:[%08x]"% (location, sizeptr)             start = DbgDword(location)             n = DbgDword(sizeptr)             print "
  • \tGif start:[%08x],n:[%08x]"% (start, n)             dump = DbgRead(start,n)             f = open(os.path.join(self.savepath, str(self.count))+'.gif','wb')             f.write(dump)             f.close()             self.count = self.count + 1         else:             print "[%x] - [%x]" %(GetRegValue('eip'),self.keyLocation)         idaapi.continue_process()           return 0       def dbg_suspend_process(self):           print "MyDbgHook : Process suspended"     def dbg_step_into(self):           print "MyDbgHook : Step into"         self.dbg_step_over() debughook = MyDbgHook()   debughook.hook() print "ok"
  • 写在最后

    通过ida python实现了获取微信GIF的功能,自动化脚本,加载模块自动下断,dump文件。只需要在手机上发送GIF,保存目录下就能得到对应的GIF。速度可以说是很快的。

    战果

    wx22

    点评

    点个赞~  发表于 2018-6-12 13:53
    很好,学习了,曾经有过这个想法,没有啥思路,感谢  发表于 2018-6-7 16:19
    ~  发表于 2018-5-26 05:28
    这么详细的教程才是有参考价值的帖子。不像有些帖子真是为了显示自己的厉害二失去了参考的意义。  发表于 2018-5-7 15:55

    免费评分

    参与人数 166吾爱币 +179 热心值 +160 收起 理由
    kingpink + 1 + 1 谢谢@Thanks!
    runapp + 1 + 1 谢谢@Thanks!
    reeye + 1 + 1 我很赞同!
    何故 + 3 + 1 用心讨论,共获提升!
    yaksacn2001 + 1 + 1 技术贴必须顶
    FuYunx + 1 + 1 大神请收下我的膝盖!
    weitao4112 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    涛之雨 + 1 我很赞同!
    aikhanlee + 1 谢谢@Thanks!
    greydsky + 1 + 1 用心讨论,共获提升!
    13297398667 + 1 谢谢@Thanks!
    hyc120500 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    星期日 + 1 + 1 我居然看完了整个教程,说得太好了。
    nalansitan + 1 + 1 我很赞同!
    iXi + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    xu6456338 + 1 + 1 用心讨论,共获提升!
    shelher + 3 + 1 用心讨论,共获提升!
    幻想只能想 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    ashajia + 1 + 1 我很赞同!
    yanjingtu + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    、Psycho + 1 + 1 谢谢@Thanks!
    fhwangyinan + 1 + 1 用心讨论,共获提升!
    流浪的猫眼石 + 2 + 1 大神一枚~~~
    wyl0205 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    mei + 1 + 1 谢谢@Thanks!
    刺心 + 2 + 1 强的一逼。力推
    老张有大梦想 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    umum + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    181842 + 1 + 1 这么好的帖子,必须赞一下
    快乐交友 + 1 + 1 谢谢@Thanks!
    ztech + 1 + 1 谢谢@Thanks!
    tong000 + 1 + 1 这么好的帖子,必须赞一下
    52_pojie_52 + 1 + 1 热心回复!
    wushaominkk + 3 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    yer + 1 + 1 谢谢@Thanks!
    ingdear + 1 + 1 热心回复!
    Evi1knit + 1 + 1 谢谢@Thanks!
    德仁先生 + 1 + 1 谢谢@Thanks!
    2202171 + 1 我很赞同!
    锦衣夜行说 + 1 我很赞同!
    nihao7758 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    pqzhen9999 + 1 + 1 谢谢@Thanks!
    yxz + 1 + 1 谢谢@Thanks!
    o0dc0o + 1 + 1 鼓励转贴优秀软件安全工具和文档!
    moerben + 1 + 1 文章写得很好,干货满满。感谢帖主的无私分享
    蓦留 + 1 + 1 文章很棒,分析的也很详细!
    635419450 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    他化自在天子 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    吃鸡王 + 1 + 1 我很赞同!
    lchbjji + 1 + 1 谢谢@Thanks!
    Ww吾爱破解 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
    i-ii + 1 + 1 谢谢@Thanks!
    Rick_Fang + 1 + 1 我很赞同!
    shanhuyi + 1 + 1 谢谢@Thanks!
    白菜的菜 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
    a3887387 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
    我是兔斯基 + 1 + 1 老哥 厉害,但是我看不懂哇
    jnez112358 + 1 + 1 谢谢@Thanks!
    suadzh + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    zzzain46 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    ming1332236 + 1 + 1 用心讨论,共获提升!
    jgwkg + 1 + 1 我很赞同!
    sunbeat + 2 + 1 我很赞同!
    余洛侠 + 1 + 1 谢谢@Thanks!
    孟坤软件 + 2 + 1 我很赞同!
    我是菜鸟我先灰 + 1 + 1 用心讨论,共获提升!
    wdzj + 1 + 1 非常不错,分析的很到位。
    cs00678 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    ec0li + 1 + 1 谢谢@Thanks!
    txt + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    小小小小小_达 + 1 + 1 少有的技术贴
    yuridexiaoyu + 1 + 1 热心回复!
    蓝洛水深 + 1 + 1 谢谢@Thanks!
    森林生灵 + 1 + 1 我很赞同!
    911061873 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    gaucnet + 1 + 1 我很赞同!
    Aries15123 + 1 + 1 谢谢@Thanks!
    为你存在 + 1 + 1 一脸懵逼的看完了.
    飞鸽传书 + 1 + 1 谢谢@Thanks!
    无名zz + 1 + 1 谢谢@Thanks!
    zhaoxishm + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    石晓一格莱 + 1 我很赞同!
    snake88888 + 1 + 1 谢谢@Thanks!
    child_lu + 1 + 1 用心讨论,共获提升!
    LzSkyline + 2 + 1 用心讨论,共获提升!
    嘉嘉大仙 + 1 + 1 我很赞同!
    测试中…… + 2 + 1 用心讨论,共获提升!
    54556 + 1 + 1 我很赞同!
    夏日已末 + 1 + 1 我很赞同!
    太上忘情 + 2 + 1 感觉好厉害的样子,能出工具吗,菜如我就只能装老版本来提取
    一坛老酒 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    夏雨微凉 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    noth + 1 + 1 我很赞同!
    clovemevv + 1 + 1 我很赞同!
    科学家玩家 + 1 + 1 我很赞同!
    zy1234 + 1 + 1 用心讨论,共获提升!
    viekst + 1 + 1 我很赞同!
    ╰Tang + 1 + 1 用心讨论,共获提升!
    hf5240376 + 1 + 1 谢谢@Thanks!
    山顶的一棵草 + 1 明天来总部上班!

    查看全部评分

    本帖被以下淘专辑推荐:

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

    77254076 发表于 2018-5-6 18:34
    楼主分析的很强 虽然我看不到
    能不能搞个小程序之类的 给我们咸鱼用用呢? 嘿嘿
    包子入侵866 发表于 2019-8-9 21:53
    大佬这是什么问题
    D:\ProgramData\Anaconda3\python.exe C:/Users/Administrator/.PyCharm2019.1/config/scratches/scratch.py
      File "C:/Users/Administrator/.PyCharm2019.1/config/scratches/scratch.py", line 33
        print "MyDbgHook : Process started, pid=%d tid=%d name=%s"%(pid, tid, name)
                                                                 ^
    SyntaxError: invalid syntax
    远水涵秋 发表于 2018-5-6 18:08
    楼主分析得好详细,佩服。
    是否可以做一个小程序给我等菜鸟呢?谢谢
    爱国小枫枫 发表于 2018-5-6 18:09
    楼主666 学习了
    trombonist 发表于 2018-5-6 18:16
    支持一下!!!!!!!!!!
    中间人 发表于 2018-5-6 18:35
    好强大,支持
    qqqwww0078 发表于 2018-5-6 18:37
    这也太详细了吧 这是大神 学到了
    头像被屏蔽
    荦陌。 发表于 2018-5-6 18:40 来自手机
    真正的大神啊
     楼主| ZjyCjy 发表于 2018-5-6 19:03
    远水涵秋 发表于 2018-5-6 18:08
    楼主分析得好详细,佩服。
    是否可以做一个小程序给我等菜鸟呢?谢谢

    没思路唉。。。我之后在看看吧
     楼主| ZjyCjy 发表于 2018-5-6 19:06
    77254076 发表于 2018-5-6 18:34
    楼主分析的很强 虽然我看不到
    能不能搞个小程序之类的 给我们咸鱼用用呢? 嘿嘿

    还没有思路。。。写不出
    您需要登录后才可以回帖 登录 | 注册[Register]

    本版积分规则

    返回列表

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

    GMT+8, 2024-12-22 16:03

    Powered by Discuz!

    Copyright © 2001-2020, Tencent Cloud.

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