jmp 远跳转绝对地址是怎么计算的?

VirtualRookit 2011-03-23 06:27:29
010BCDF3 6A 00 push 0
010BCDF5 6A 00 push 0
010BCDF7 6A 00 push 0
010BCDF9 6A 00 push 0
010BCDFB 68 03 CE 0B 01 push offset label_1 (10BCE03h)
010BCE00 FF 65 EC jmp dword ptr [hProc]
label_1:


//如上代码 hProc为MessageBoxA的地址..请问
010BCE00 FF 65 EC jmp dword ptr [hProc]
单步执行后如下:
76C4EA71 8B FF mov edi,edi
76C4EA73 55 push ebp

问: 绝对跳转地址新EIP(76C4EA71)是怎么由旧EIP(010BCE00 FF 65 EC)计算出来的?
就是绝对地址的计算方法(别讲些相对地址的计算方法,这个我懂)。哪位大牛给指点下,谢谢。
...全文
1113 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
VirtualRookit 2011-03-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 zara 的回复:]
上面 microDebug 的说法不对吧。这个 FF 65 EC 的 jmp 指令是 jmp dword ptr [ebp-14h] ,[ebp-14h] 一般是个局部变量嘛,其在源程序里的标号应该是 hProc 。从这段代码的作用来看,hProc 里保存了 MessageBoxA() 函数的入口地址,如果这个地址是在编译链接阶段就确定了的话,它就不可能存在于 [ebp-14h] 这样的局部变量所……
[/Quote]

对不起,各位,我以为这贴没人答了,所以几天没上。
哥们,你解了我的疑问:
FF 65 EC 的 jmp 指令是 jmp dword ptr [ebp-14h]
我对机器码到汇编的翻译不是懂很多,原先以为 FF(jmp) 65(长跳型) EC(问题就卡在EC),原先以为EC是跳转距离,通过一定算法计算出来的,现在才知道,原来这地址是从栈ebp-14h取出来的,也就是65与EC是一块的,其汇编意义即dword ptr [ebp-14h]..终于明白咯...至于那些啥导出表,重定位,静、动态链接的俺都懂,不会困在那咯。另,一并感谢各位。
jesterjy 2011-03-28
  • 打赏
  • 举报
回复
目标地址 - 当前地址 - 指令长度 = JMP后的偏移
lih618 2011-03-25
  • 打赏
  • 举报
回复
MessageBoxA是API函数,系统在运行EXE时会将程序所需要的所有DLL映射到EXE的运行空间中,所有涉及DLL中函数的地址都是系统计算的,EXE中有一张DLL导入表,程序调用DLL时是根据表中的地址进行调用的,系统在载入EXE时会修改表的内容
lih618 2011-03-25
  • 打赏
  • 举报
回复
window下程序使用的都是虚拟内存地址,通过系统查找内存页表和段表对虚拟地址进行换算之后才能生成物理地址
至于跳转地址,是汇编程序在汇编时计算的啊,汇编程序会将代码中所有的跳转根据汇编后的代码位置进行地址换算
microDebug 2011-03-25
  • 打赏
  • 举报
回复
说细一点吧,以下是一个debug版本的调用过程,其实,不管是静态还是动态,调用外部DLL时都是一样的:

0041139f 8bf4 mov esi,esp
004113a1 6a00 push 0
004113a3 683c574100 push offset Mes!`string' (0041573c)
004113a8 683c574100 push offset Mes!`string' (0041573c)
004113ad 6a00 push 0
004113af ff1530834100 call dword ptr [Mes!_imp__MessageBoxW (00418330)] ds:0023:00418330={USER32!MessageBoxW (77d66534)}
004113b5 3bf4 cmp esi,esp

观察这句:ff1530834100 call dword ptr [Mes!_imp__MessageBoxW (00418330)]
其实就是CALL 到了这个地址上00418330(在内存显示为30834100)。因为LZ给的代码是构造的代码,所以用JMP来实现了,事实上,可以用JMP来构造一个CALL。

现在看00418330地址的内容:
0:000> dd 00418330
00418330 77d66534 00000000 00000000 00000000
00418340 00000000 00000000 00000000 00000000
00418350 00000000 00000000 00000000 00000000
00418360 654d0215 67617373 786f4265 53550057
00418370 32335245 6c6c642e 01210000 5452435f
00418380 4354525f 494e495f 00005754 635f021b
00418390 69666e6f 72687467 6c646165 6c61636f
004183a0 01c70065 65735f5f 65737574 74616d72

JMP过去,就是77d66534,也就是ds:0023:00418330={USER32!MessageBoxW (77d66534)}的地址。

LZ大概想了解的就是:为什么CALL 00418330地址,EIP却跳到了77d66534地址上。就是这个道理了。

以上是静态调用的,动态调用也是一样,只是,将这里的00418330内容,放到了一个[ebp-xx]局部变量里。





microDebug 2011-03-25
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 zara 的回复:]
上面 microDebug 的说法不对吧。这个 FF 65 EC 的 jmp 指令是 jmp dword ptr [ebp-14h] ,[ebp-14h] 一般是个局部变量嘛,其在源程序里的标号应该是 hProc 。从这段代码的作用来看,hProc 里保存了 MessageBoxA() 函数的入口地址,如果这个地址是在编译链接阶段就确定了的话,它就不可能存在于 [ebp-14h] 这样的局部变量所……
[/Quote]

zara分析的仔细,FF 65 EC 反汇编后确实是引用了一个局部变量。
这说明,在这段程序里调用MessageBoxA的方法是动态调用的;
我上面说的是静态链接的情况。
zara 2011-03-25
  • 打赏
  • 举报
回复
上面 microDebug 的说法不对吧。这个 FF 65 EC 的 jmp 指令是 jmp dword ptr [ebp-14h] ,[ebp-14h] 一般是个局部变量嘛,其在源程序里的标号应该是 hProc 。从这段代码的作用来看,hProc 里保存了 MessageBoxA() 函数的入口地址,如果这个地址是在编译链接阶段就确定了的话,它就不可能存在于 [ebp-14h] 这样的局部变量所处的堆栈空间里,它应该是由上面的代码根据个什么手段获得而填入到这个变量里(从这个程序的类型来说,往往都是通过 LoadLibrary() 载入所在的模块,然后查看其导出函数表,找到对应的入口地址,进行基址修正而得到当前实际的入口地址),再被该 jmp 指令所引用的。另外,由导入函数方式确定的地址,在编译链接阶段也只是个猜测的可能的值,真正的实际值是在程序载入时被校正的,这是因为不同环境、不同版本的系统,对应于同一函数,其入口地址也可能不一样。
tanqing900920 2011-03-25
  • 打赏
  • 举报
回复
同意microDebug的说法,这里面有个类似8051PC(Programme Counter)的计数器,在编译的时候将标号和jump的字节数差值(补码)填入后面的字节, 在EXE里面是不会识别标号的,只认识相对位移(字节差),exe只是简单的跳好多个字节,明白?(其实这里面还有两个类别:前跳和后跳,两个方式有点区别哦)
microDebug 2011-03-25
  • 打赏
  • 举报
回复
补充一下:可以用IDA工具查看生成的EXE文件里的import table表验证。

另外LZ你用的是DEBUG版本,已经带符号了,如果是release版本,那这句jmp dword ptr [hProc]
就应该是 jmp dword ptr XXXXXXXX地址的样子
microDebug 2011-03-25
  • 打赏
  • 举报
回复
如果想确定的话,可以用IDA等工具打开EXE工具,查看import table表验证,呵呵
microDebug 2011-03-25
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 lih618 的回复:]
MessageBoxA是API函数,系统在运行EXE时会将程序所需要的所有DLL映射到EXE的运行空间中,所有涉及DLL中函数的地址都是系统计算的,EXE中有一张DLL导入表,程序调用DLL时是根据表中的地址进行调用的,系统在载入EXE时会修改表的内容
[/Quote]
答非所问!

客观一点来说,LZ你的问题是一个编译器link的问题;
10BCE00 FF 65 EC jmp dword ptr [hProc];这句是一个绝对地址跳转,但它不是在运行时计算出来的;而是在编译的时候已经确定了的;

MessageBoxA是User32.dll中的函数,对它的链接默认都是static链接;编译时,引用到外部DLL的export table的函数,都会在生成的exe的import table文件中记录下来。在程序运行时,就直接JMP过去了。

程序运行过程中的相对跳转(进跳转,远跳转)比较频繁,但是绝对跳转除了外部干预(指inject代码),大多都是在编译的时候就确定了的。这也就是为什么需要重定位,为什么会存在相对跳转的意义了。

建议LZ补全知识体系的结构。
但愿大家互相进修进修,大家对于破解都不是很了解,人们想学破解,可是去无从入手,所以决议为大家写1个破解初级读物的教程,但愿能大家了解破解有一些帮忙,但愿能有更多的人踏入破解的大门   1.低级,修改步伐,用ultraedit等东西修改exe文件,称暴力破解,略称爆破   中级,追出软体的注册码   高级,开具注册机   2.经常使用破解东西   (1)侦壳东西:PEiD   (2)消息联合的OllyDbg引领破解东西的新潮水   一,此刻咱们起首来进修下破解的开端,爆破~   1.侦壳   要破解1个软体起主要做的就是侦壳,要侦壳就要对壳有绝对似的了解,家喻户晓,软体作者用编程语言编著好软体后,是将它编译成扩展名为EXE的可执行文件编译为EXE的目的有两点:   (1)有一些版权信息需要掩护起来,不克不及让别人随心改动,如作者的姓名、软体名称等;   (2)需要给步伐"瘦身",从而利便存储、使用以及网上传道输送   为了编译,会用到一些软体它们能将可执行文件压缩以及对信息加密(图1),实现上面所说的两个功效,这些个软体称为加壳软体为软体加上的东东就称为"壳"加壳软体差别于一般的WinZIP、WinRAR等打包类压缩软体加壳软体是压缩可执行文件的,压缩后的文件可以直接运行   最多见的加壳软体有3个:ASPACK 、UPX、PEcompact终究它们是主流,据计数,用它们加壳的软体约占市面所有软体的90%!其它不经常使用的加壳软体有ASPROTECT、PETITE 、NEOLITE、TELOCK等软体最多见的编程语言是Delphello,Visual Basic(略称VB),Visual C++(略称VC)了解些编程的常识,会让破解更加轻车熟道   底下来讲侦壳,此刻比力经常使用侦壳软体就PeiD,他具备华美的图形界面外壳整合(新增到鼠标右键)功效令使用更加利便,撑持拖放操作配置时,务请将"扩展到鼠标右键"打上对号   其使用要领是,鼠标点住XX.exe,按鼠标右键,选"使用PEid扫描"便可;"壳"的信息就显示在底部   2.破解东西OD   有关OD的先容我把他放到附件里了,这个是看雪论坛的先容,是比力周全的,至少我感觉比我写的要好,所以大家根据他可以大好的了解OD   3.爆破实例   爆破是破解的开端,所说的爆破,就是指路程经过过程修改可执行文件的源文件,降临达相应的目的你半大白?呵呵,举个例子好了,好比说某同享软体,它比力用户输入的注册码,要是用户输入的,跟它路程经过过程用户名(或其它)算出来的注册码相等的话(也就是说用户输入的注册码不错了),那末它就会到注册乐成的处所去,不然就到堕落的处所去   大白过来了吧,咱们只要找到这个指令,把它修改成咱们需要的"造型",如许,咱们是否就可认随心所欲了?   一,破解时经常使用的汇编指令如下,汇编较弱者可先强行违住,以后就可逐步理解了   cmp a,b //比力a与b   mov a,b //把b的值送给a,使a=b   ret //归回主步伐   nop //无效用,英文"no operation"的简写,意思是"do nothellong"(呆板码90) (解释:ultraedit打开编辑exe文件时瞅见90,等同于汇编语句nop)   call //挪用子步伐,子步伐以ret末端   je 或jz //若相等则(呆板码74 或0F84)   jne或jnz //若不相等则(呆板码75或0F85)   jmp //无前提(呆板码EB)   jb //若小于则   ja //若大于则   jg //若大于则   jge //若大于等于则   jl //若小于则   jle //若小于等于则   pop xx //xx出栈   push xx //xx压栈   更为具体的指令请查阅汇编册本   4.破解常见修改,参看表1   汇编指令修改 相应的呆板码修改(路程经过过程16进制编辑器实现)   jnz/jne->nop 75->90   jnz/jne -> jmp 75-> EB   jz/je->nop 74->90   jz/je -> jmp 74-> EB   jnz -> jz 75->74 或 0F 85 -> 0F 84   jz -> jnz 74->75 或 0F 84 -> 0F 85   jnz -> jz 75->74 或 0F 85 -> 0F 84   je-> jne 74->75 或 0F 84 -> 0F 85   表1
目 录 第1篇 序 幕 单片机是什么?单片机有何用?如何系统学习单片机?单片机系统设计的流程是怎样的,需要掌握哪些辅助软件?本篇将针对这些问题一一阐述,为读者掀开单片机完全学习与应用的华丽序幕。 第1章 单片机在哪里 1.1 ■寻找单片机 1.1.1 电磁炉与单片机 1.1.2 MP3播放机与单片机 1.1.3 更多单片机 1.2 ■学习单片机 1.2.1 掌握单片机基础知识 1.2.2 理解单片机系统 1.2.3 成为单片机系统设计师 1.3 ■单片机之家 1.3.1 Intel 8051单片机 1.3.2 PIC单片机 1.3.3 AVR单片机 1.3.4 其他单片机 1.4 ■应用体验——数字温度计 1.4.1 数字温度计工作原理 1.4.2 体验数字温度计 1.5 ■实例解读——装小球系统 1.5.1 需求分析 1.5.2 系统框架 第2章 如何成为单片机系统设计师 2.1 ■需要准备哪些 2.1.1 综合素质 2.1.2 软件工具 2.1.3 硬件工具之一:面包板 2.1.4 硬件工具之二:万用板和 印制电路板 2.1.5 焊接工具 2.1.6 焊接方法 2.2 ■单片机系统设计流程 2.2.1 需求分析 2.2.2 电路设计 2.2.3 程序设计 2.2.4 系统调试 2.3 ■应用体验——单片机控制下的 发光二极管 2.3.1 发光二极管工作原理 2.3.2 单片机的控制 2.3.3 体验单片机控制发光二极管 2.4 ■实例解读——反应时间测试仪 2.4.1 需求分析 2.4.2 电路设计 2.4.3 程序设计 第3章 单片机系统登场 3.1 ■单片机系统组成 3.1.1 单片机本身 3.1.2 系统的构成 3.2 ■单片机系统抽丝剥茧 3.2.1 AT89S51单片机的“外衣” 3.2.2 AT89S51单片机的管脚 3.2.3 常见外设 3.3 ■元器件插曲之一:变压器 3.3.1 变压器基础知识 3.3.2 电源变压器 3.4 ■元器件插曲之二:二极管与整流 3.4.1 二极管基础知识 3.4.2 整流 3.4.3 整流全桥 3.5 ■元器件插曲之三:电容 3.5.1 电容基础知识 3.5.2 电容的种类 3.5.3 电源滤波 3.6 ■元器件插曲之四:三端稳压与 单片机系统电源 3.6.1 三端稳压基础知识 3.6.2 单片机系统电源方案一: 自制直流稳压电源 3.6.3 单片机系统电源方案二: 电源适配器 3.6.4 单片机系统电源方案三: USB口供电 3.7 ■元器件插曲之五:晶振与振荡器 3.7.1 晶振基础知识 3.7.2 振荡器 3.8 ■诠释单片机最简系统 3.8.1 单片机最简系统 3.8.2 电源端(VCC、GND) 3.8.3 时钟信号端(XTAL1、 XTAL2) 3.8.4 复位端(RST) 3.8.5 外部程序存储器访问控制端 ( ) 3.8.6 从最简系统出发 3.9 ■元器件插曲之六:电阻 3.9.1 电阻基础知识 3.9.2 电阻的参数和种类 3.9.3 电阻的分压、限流、上拉作用 3.10 ■从单片机最简系统开始设计 3.10.1 发光二极管交替发光 3.10.2 程序设计 3.10.3 初见汇编语言 3.10.4 初识指令 3.10.5 立即数 3.11 ■应用体验——发光二极管的交替 发光 3.11.1 控制交替发光的原理 3.11.2 体验交替发光 3.12 ■元器件插曲之七:开关 3.12.1 开关基础知识 3.12.2 常用开关 3.13 ■实例解读——与发光二极管的 交互 3.13.1 需求分析 3.13.2 电路设计 3.13.3 程序设计 3.13.4 延时子程序 第4章 单片机系统设计辅助软件 4.1 ■Proteus单片机系统仿真软件 4.1.1 Proteus软件界面 4.1.2 用Proteus仿真 Vision单片机程序开发4.2 ■ Vision软件界面4.2.1 4.2.2 新建和保存项目 4.2.3 向项目中添加文件 4.2.4 汇编程序,生成执行代码 4.2.5 生成下载到单片机的执行 代码HEX文件 Vision的调试及仿真功能4.3 ■ 4.3.1 调试界面 4.3.2 虚拟逻辑分析仪 4.4 ■应用体验——把程序下载到 单片机里 4.4.1 下载器与单片机 4.4.2 体验下载过程 4.5 ■实例解读——流水灯 4.5.1 需求分析 4.5.2 电路设计 4.5.3 软件设计 第2篇 揭 密 单片机的内部结构是怎样的?单片机开发经常会用到哪些电子技术和元器件知识?还有那困扰了很多人的单片机编程语言……本篇将生动地通过诸多实例带出单片机的基础知识,在遇到相关模拟电路、数字电路、元器件知识时会有及时的补充说明,带领读者一点点揭开单片机的神秘面纱。 第5章 单片机的触角——I/O口 5.1 ■何谓I/O口 5.1.1 I/O口的功能 5.1.2 I/O口与单片机的关系 5.1.3 I/O口的操作 5.2 ■元器件插曲之八:场效应管 5.2.1 JFET 5.2.2 MOSFET 5.3 ■元器件插曲之九:逻辑门 5.3.1 非门 5.3.2 或门 5.3.3 或非门 5.3.4 与门 5.3.5 与非门 5.3.6 异或门 5.3.7 缓冲器 5.4 ■元器件插曲之十:锁存器与触发器 5.4.1 门控D锁存器 5.4.2 边沿D触发器 5.5 ■I/O口结构探密 5.5.1 P1口 5.5.2 P3口 5.5.3 P0口 5.5.4 P2口 5.5.5 I/O口小结 5.6 ■应用体验——控制流水灯 5.6.1 功能与电路 5.6.2 体验控制流水灯 5.7 ■实例解读——晃晃灯 5.7.1 原理分析 5.7.2 需求分析 5.7.3 电路设计 5.7.4 软件设计 第6章 七段数码管显示 6.1 ■二进制与数据 6.1.1 二进制与数字 6.1.2 二进制与语音 6.1.3 二进制与图像 6.2 ■元器件插曲之十一:七段数码管 6.2.1 七段数码管原理 6.2.2 七段数码管显示数字 6.3 ■应用体验——计时器 6.3.1 功能与电路 6.3.2 体验计时器 6.4 ■元器件插曲之十二:蜂鸣器 6.4.1 蜂鸣器 6.4.2 蜂鸣器如何工作 6.5 ■元器件插曲之十三:三极管及 三极管开关 6.5.1 三极管基础 6.5.2 三极管的直流放大特性 6.5.3 三极管的直流增益 6.5.4 三极管的电流关系式 6.5.5 三极管开关 6.6 ■实例解读——带声音提示的秒表 6.6.1 需求分析 6.6.2 电路设计 6.6.3 开关抖动的处理 6.6.4 计时中数字的增加 6.6.5 软件设计 第7章 解剖单片机 7.1 ■单片机的功耗 7.1.1 运行功耗 7.1.2 I/O口驱动功耗 7.1.3 空闲模式 7.1.4 待机模式 7.2 ■单片机内部结构 7.2.1 从I/O口到内部结构 7.2.2 数据在内部交换 7.2.3 算术逻辑单元(ALU) Vision中观察寄存器7.2.4 在 7.3 ■单片机的程序存储器 7.3.1 整体结构 7.3.2 程序下载到哪里 7.3.3 片内程序存储器 7.3.4 程序计数器PC 7.3.5 是片内还是片外程序存储器 Vision中观察程序存储器7.3.6 在 7.4 ■单片机的数据存储器 7.4.1 片内数据存储器 7.4.2 工作寄存器区(00H~1FH) 7.4.3 位寻址区(20H~2FH) 7.4.4 开放区(30H~7FH) Vision中观察数据存储器7.4.5 在 7.5 ■单片机的特殊功能寄存器 7.5.1 特殊功能寄存器分布图 7.5.2 特殊功能寄存器的功能 7.5.3 特殊功能寄存器的字节操作 7.5.4 特殊功能寄存器的位操作 Vision中观察特殊功能7.5.5 在 寄存器 7.6 ■应用体验——用取表方式实现 流水灯 7.6.1 取表法 7.6.2 取表法小结 7.6.3 体验流水灯 7.7 ■实例解读——直接驱动七段 数码管 7.7.1 需求分析 7.7.2 电路设计 7.7.3 软件设计 第8章 单片机与汇编指令 8.1 ■汇编语言真面目 8.1.1 汇编语言与高级语言 8.1.2 从汇编程序到执行代码 8.1.3 伪指令 8.2 ■指令的执行 8.2.1 振荡周期、机器周期、指令 周期 8.2.2 指令的执行 8.3 ■寻址方式 8.3.1 直接寻址 8.3.2 间接寻址 8.3.3 寄存器寻址 8.3.4 寄存器特征寻址 8.3.5 立即寻址 8.3.6 变址寻址 8.4 ■指令分类 8.4.1 指令概述 8.4.2 指令的长度 8.5 ■算术运算指令 8.5.1 加法指令——ADD A, <src-byte> 8.5.2 带进位的加法指令——ADDC A, <src-byte> 8.5.3 带借位的减法指令——SUBB A,<src-byte> 8.5.4 自增/自减指令——INC <byte> / DEC <byte> 8.5.5 乘法指令——MUL AB 8.5.6 除法指令——DIV AB 8.5.7 十进制调整指令——DA A 8.6 ■逻辑运算指令 8.6.1 与操作——ANL <dest-byte>,<src-byte> 8.6.2 或操作——ORL <dest-byte>,<src-byte> 8.6.3 异或操作——XRL <dest-byte>, <src-byte> 8.6.4 累加器A清0操作——CLR A 8.6.5 累加器A取反操作——CPL A 8.6.6 累加器A位移动操作——RL、 RLC、RR、RRC 8.6.7 累加器A高低位交换操作 ——SWAP A 8.7 ■数据装载指令 8.7.1 片内数据装载指令——MOV   <dest>, <src> 8.7.2 数据指针DPTR装载指令 ——MOV DPTR, #data16 8.7.3 堆栈指令——PUSH、POP 8.7.4 数据交换指令——XCH、 XCHD 8.7.5 片外数据装载指令——MOVX   <dest>, <src> 8.7.6 查表指令——MOVC  <dest>, <src> 8.8 ■布尔指令 8.8.1 清0、置1、取反操作——CLR、 SETB、CPL 8.8.2 布尔逻辑运算指令——ANL、 ORL 8.8.3 位数据装载指令——MOV <dest-bit>,<src-bit> 8.8.4 布尔指令——JC、JNC、 JB、JNB、JBC 8.9 ■调用子程序指令 8.9.1 长调用指令——LCALL 8.9.2 绝对调用指令——ACALL 8.9.3 返回指令——RET、RETI 8.10 ■与循环指令 8.10.1 无条件指令——LJMP、 AJMP、SJMPJMP 8.10.2 条件指令——JZ、JNZ 8.10.3 比较指令——CJNE <dest-byte>, <src-byte>, rel 8.10.4 循环指令——DJNZ <byte>,<rel-addr> 8.10.5 无操作指令——NOP 8.11 ■应用体验——七段数码管的串行 控制技术 8.11.1 串行与并行传输 8.11.2 串行控制七段数码管 8.11.3 程序设计 8.12 ■实例解读——指令应用(程序) 实例 8.12.1 数据求和 8.12.2 减法与二进制的二补数 8.12.3 异或操作指令XRL用于比较 寄存器数值 8.12.4 利用布尔指令产生矩形波 信号 8.12.5 布尔指令应用于控制

9,506

社区成员

发帖
与我相关
我的任务
社区描述
Windows专区 安全技术/病毒
社区管理员
  • 安全技术/病毒社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧