您的位置:首页 > 运维架构 > Linux

Linux引导程序 grub简介

2010-11-25 12:01 369 查看
1. GRUB 介绍

计算机在启动的时候,首先由BIOS中的程序执行自检,自检通过后,就根据CMOS的配置找到第一个可启动磁盘的MBR中的Boot
Loader程序(一般在启动盘的第一个物理扇区,占416字节),并把控制权交给Boot Loader,由Boot
Loader进一步完成操作系统内核的加载。当Boot Loader找到内核之后,就把控制权交给操作系统内核,由内核继续完成系统的启动。

可以看出,Boot Loader 是计算机启动中第二个要执行的程序,它是引导操作系统的关键程序。可以引导操作系统的Boot
Loader主要有LiLo、GRUB以及Windows下的MBR程序。其中,GRUB是目前使用最为广泛,并且非常优秀的一款启动引导程序。

(1) GRUB特性

q 提供了图形和文本两种操作接口

q 提供文本格式可手工修改的配置文件

q 支持动态加载需要的模块

q 可以移植到不同的平台上

q 支持国际化语言,如英文,中文,日文汉文等多字节语言

q 跨平台的安装,允许从另一个平台上安装GRUB

q 支持rescue模式,可用于系统无法引导的情况

q 支持多种可执行文件格式,支持各种a.out格式和ELF格式

q 多文件系统识别。如BSD FFS,DOS FAT16,FAT32和Linux ext2fs

q 支持压缩文件的解压缩。能够解压缩被gzip压缩的文件

q 能够使用BIOS所检测到的全部RAM空间

q 支持硬盘的LBA模式,能够访问8GB以外的全部硬盘空间

q 支持网络引导,可以通过TFTP协议从网络上得到操作系统映象文件并引导

(2) GRUB对设备的命名

首先,GRUB对设备的命名必须包含在小括号(
)内;其次,GRUB不区分IDE硬盘和SCSI硬盘,统一使用hdx,其中x指定BIOS中硬盘的编号,并从0开始计数,而且IDE硬盘编号小于
SCSI硬盘;第三,GRUB用fdx指定软盘设备,x是软盘驱动器号。下面是一些GRUB对设备命名的举例:

q (fd0)表示第1个软盘

q (hd0,1)表示第1个硬盘的第2个分区

q (hd0,0)/boot/vmlinuz表示第1个硬盘的第一个分区下的boot/目录下的vmlinuz文件。如果没有指定某个分区,则表示使用整个设备,否则只使用指定的分区

q (hd0,2,a)专用于FreeBSD,FreeBSD有一个slice概念,把一个分区进一步分为几个slice,此处指明是第1块硬盘的第3个分区中的slice a

(3) GRUB的执行流程

GRUB的工作原理如图5.2所示。当系统加电后,固化在BIOS中的程序首先对系统硬件进行自检,自检通过后,就加载启动磁盘上的MBR,并将控制权交
给MBR中的程序(stage1),stage1执行,判断自己是否GRUB,如果是且配置了stage1_5,则加载stage1_5,否则就转去加载
启动扇区,接着,stage2被加载并执行,由stage2借助stage1_5驱动文件系统,并查找grub.conf,显示启动菜单供用户选择,然后
根据用户的选择或默认配置加载操作系统内核,并将控制权交给操作系统内核,由内核完成操作系统的启动。

图4-2 GRUB执行流程

从上面的叙述可以看出,GRUB涉及到几个重要的文件:

第一个就是stage1。它被安装在MBR扇区(0面0磁道的第1扇区),大小为512字节(446字节代码+64字节分区表+2字节标志55AA),它负责加载存放于0面0道第2扇区的start程序。

第二个是stage1_5。stage1_5负责识别文件系统和加载stage2,所以stage1_5往往有多个,以支持不同文件系统的读取。在安装
GRUB的时候,GRUB会根据当前/boot/分区类型,加载相应的stage1_5到0面0磁道的第3扇区。stage1_5是由start加载的。

第三个是stage2。它负责显示启动菜单和提供用户交互接口,并根据用户选择或默认配置加载操作系统内核。同前两个文件不同,stage2是存放在磁盘上/boot/grub下。

第四个是menu.lst(/boot/grub/grub.conf的链接)。grub.conf是一个基于脚本的文本文件,其中包含菜单显示的配置和
各个操作系统的内核加载配置。GRUB根据grub.conf显示启动菜单,提供同用户交互界面。GRUB正是根据用户选择或默认配置和
grub.conf的内核配置加载相应的内核程序,并把控制权交给内核程序,使得内核程序完成真正的操作系统的启动。

其它重要文件,GRUB除了上面叙述的主要文件之外,还包括支持交互功能的一些磁盘程序。主要包括/sbin/下的grub、grub-install、
grub-md5-crypt和grub-terminfo和/usr/bin/mbchk,以及/boot/grub下的设备映像文件
(device.map)和菜单背景图像文件(splash.xpm.gz)。

通过上面的分析总结,可以很容易地看出,GRUB实际上包含两部分,一部分被安装在磁盘的特殊扇区,另外一部分则以文件的形式存在。要让GRUB启动操作
系统,就必须首先把GRUB的stage1和stage1_5(根据文件系统自动选择是否安装)安装到磁盘的特殊扇区,另外,在磁盘的/boot
/grub下存在有grub.conf、device.map等文件和支持交互的程序,而且这些程序必须在PATH环境变量指定的路径中。具备了这些知
识,相信不管是安装、配置、备份或修复GRUB都不是件很难的是情。下面,就来逐个讲解这些知识。

2. 编译安装GRUB

一般情况下,当完成Linux操作系统的安装后,系统中已经安装好了LILO或GRUB引导程序。由于系统出现故障或需要更换LILO为GRUB时,需全
新或重新安装GRUB。如何安装和配置GRUB就是下面要介绍的内容。而有时候,GRUB出现了故障,但并不需要重新安装,从后面的内容中,读者也可以读
到如何修复GRUB的知识。

(1) 下载安装包

可以从ftp://alpha.gnu.org/gnu/grub/
下载GRUB的源码。具体安装方法请参考下面的内容,这里的安装过程都是在RHEL 4中进行的。

(2) 检查是否安装GRUB

#rpm -q grub

如果显示grub-0.95-3.5或其它版本的GRUB的信息,说明系统已经安装了,则执行如下命令首先将其卸载:

#rpm -e grub

(3) 编译源码安装

a.) 编译条件

要编译GRUB的源代码,系统必须具备以下条件:

q GCC2.95或者以上版本

q 安装了GNU Make

q binutils2.9.1.0.23或者个更高版本

q Texinfo 4.0或者更高版本

q Autoconf 2.5x

q Automake 1.7 或者更高版本

b.) 编译安装

这里,假设下载的GRUB源代码为grub-0.95.tar.gz,并放在~/(当前用户的主目录)下。通过编译源代码安装GRUB的基本过程如下:

#tar -zxvf grub-0.95.tar.gz #解压源代码

#cd grub-0.95 #转入grub目录

#./configure #生成Makefile文件

#make install #编译代码并安装

(4) 安装GRUB到MBR

GRUB的工作目录是在/boot/grub下,而make install并没将其安装到/boot/grub。所以,安装完成后要执行如下一些操作:

a) 把/usr/local/share/grub/i386-pc/目录下的所有文件统统拷贝到/boot/grub/目录下

#cp /usr/local/share/grub/i
4000
386-pc/* /boot/grub/

b) 在/boot/grub下创建grub.conf文件,并建立一个到grub.conf的软链接menu.lst

#cd /boot/grub

#touch grub.conf

#ln -s grub.conf menu.lst

注意!如果已经存在grub.conf,就最好不要再次创建,需要时直接修改即可。

c) 确认/usr/local/sbin和/usr/local/bin在PATH变量的值中,执行如下命令检查

#env |grep PATH

如果发现/usr/local/sbin和/usr/local/bin不在PATH变量中,可以通过如下命令修改:

#export PATH=$PATH /usr/local/sbin:/usr/local/bin

d) 安装GRUB到MBR

GRUB在启动中,被BIOS调用,只有放在MBR中才可以被调用,所以,GRUB要让BIOS调用,就必须安装在MBR中。实际上是将stage1安装到MBR中,也可能根据文件系统选择安装了stage1_5。下面,提供几个安装GRUB的例子:

#grub-install /dev/hda //将GRUB安装到第1块IDE硬盘的MBR

#grub-install /dev/sda //将GRUB安装到第1块SCSI硬盘的MBR

#grub-install /dev/fd0 //将GRUB安装到软盘

#grub-install /dev/hda1 //将GRUB安装到第1快硬盘的0扇区,当用其它引导程序引导系统时,往往选择这种方式,以免覆盖其它引导程序。

e) 在GRUB的命令行模式下安装GRUB

关于GRUB命令行模式及其操作方法请参考3小节的内容。在系统显示启动菜单时候按下c键,或者系统启动后在命令行执行/usr/sbin/grub程序,都可以进入GRUB的命令行模式。命令行模式下安装GRUB的基本过程如下:

q 指定启动设备

grub>root (hd0,0) #除了root后必须有空格,别的位置均不能有空格!

此处(hd0,0)是指第1块硬盘的第1个分区。如果不能确定包含GRUB的stage1文件的分区,可以通过find指令查找确定:

grub> find /boot/grub/stage1 #查找stage1

GRUB将会查找文件/boot/grub/stage1并显示包含这个文件的设备名,这个设备就是上面要用到的设备。

q 安装GRUB

grub> setup (hd0) #除了setup后必须有空格,别的位置均不能有空格!

这条命令将会在第1块硬盘的MBR安装GRUB,如果不想在MBR安装GRUB,而是希望将GRUB安装在某分区的引导扇区的话,可以用下面的命令安装:

grub> setup (hd0,0) #除了setup后必须有空格,别的位置均不能有空格!

这将会在第1块硬盘的第1个分区的引导扇区安装GRUB。

q 退出GRUB

grub>quit

f) 重启机器,新安装的GRUB生效

3. GRUB的交互操作

为了方便用户交互使用GRUB,GRUB提供了交互模式,下面分别作一介绍:

(1) 命令行模式

登陆Linux系统后,在命令行中输入grub,便可以进入到命令行模式。如图4-3所示。进入命令行模式后GRUB会给出一个命令提示符“grub>”,此时就可以键入命令,按回车执行。此模式下允许类似于Bash shell的命令行编辑功能:

q <C-f>或<右箭头键> 光标右移一个字符

q <C-b>或<左箭头键> 光标左移一个字符

q <C-a><HOME> 到这一行的开头

q <C-e>或<END> 到行尾

q <C-d>或<DEL> 删除光标处的字符

q <C-h>或<BackSpace> 删除光标左边的字符

q <C-k> 删除光标右边的所有字符(包括光标处的字符)

q <C-u> 删除光标左边的所有字符(包括光标处的字符)

q <C-y> 恢复上次删除的字符串到光标位置

q <C-p>或<向上键> 历史记录中的上一条命令

q <C-n>或<向下键> 历史记录中的下一条命令

图4-2
启动时GRUB命令行模式在命令行模式下<tab>键有补全命令的功能,如果你敲入了命令的前一部分,键入<tab>系统将列出
所有可能以你给出的字符串开头的命令。如果你给出了命令,在命令参数的位置按下<tab>键,系统将给出这条命令的可能的参数列表。

在计算机启动的时候,GRUB首先显示启动菜单,这是如果用户按键盘的“c”键,便进入如图4-4所示的命令行模式,它的操作和在Linux的命令行模式是一样的。

(2) 菜单模式

系统在启动时,如果找到/boot/grub/menu.lst,则grub显示grub并进入菜单模式,如图4-4所示。菜单模式下用户可以选择
要启动的操作系统,或者修改配置。菜单的定义在menu.lst文件中,也可以从菜单模式按<c>键进入命令行模式,并且可以
按<ESC>键从命令行模式返回菜单模式。菜单模式下按<e>键将进入菜单编辑模式。

(3) 菜单编辑模式

菜单编辑模式用来对菜单项进行编辑改变,其界面和菜单模式的界面十分类似,不同的是菜单中显示的是对应某个菜单项的命令列表。如果在编辑模式下按
下<ESC>,则取消所有当前对菜单的编辑并回到菜单模式下。在编辑模式下选中一个命令行,就可以对这条指令进行修改,修改完毕后按下回
车,GRUB将提示你确认并完成修改。如果你想在当前命令列表中增加一条命令,按<o>在当前命令的下面增加一条指令,按<O>
在当前命令前处增加一条指令,按<d>删除一条指令。

在实际中,菜单模式用于选择要启动的操作系统,菜单编辑模式用于临时修改编辑启动菜单,这样的修改可疑通过命令写入MBR活指定的分区,但并不影响
grub.conf。命令行模式也是一样,可以通过命令方式动态启动一个操作系统,同时也不影响grub.conf。所以,菜单编辑模式和命令行模式常常
用来安装GRUB到MBR或动态引导一个操作系统。而GRUB的配置文件,则是系统启动时GRUB程序必须加载的配置文件,这个文件中有关于GRUB的各
种配置。不需要用户每次启动都执行繁琐的命令了。

4. GRUB配置文件

grub.conf是GRUB的配置文件,其结构比较简单,可以分为两部分,第一步分是全局配置,另外一部分就是每个操作系统的启动配置。其中可以有多个操作系统的菜单配置。下面就是一个具体的例子。

#=================/boot/grub/grub.conf文件范例==================

timeout 30 # 等待用户选择菜单项的时间(以秒计),超时则引导默认的选项

default 0 # 默认选项,第一项

fallback 1 # 如果第一项出错,则启动下面的后备选项

splashimage=(hd0,0)/grub/splash.xpm.gz #GRUB启动画面

#以下是启动Linux的配置

titleRed Hat Linux Enterprise AS3 for syd168 #启动项的菜单标题

root (hd0,0) #指定根文件系统,第1块硬盘第1个扇区中的/boot。

kernel /vmlinuz-2.4.18 ro root=LABEL=/ #内核在/boot中

initrd /initrd-2.4.18-14.img #启动RAM盘在/boot下

#以下是启动Windows的配置,如果只有Linux就不需要

title Windows2003 Enterprise for syd168 #Windows启动菜单标题

root noverify(hd0,1) #该操作系统在hd0的第二分区,不mount

chainloader +1 #从第一个硬盘的第二个分区引导Windows

#=================/boot/grub/grub.conf文件范例==================

上面的例子,只是简单说明了GRUB中启动Linux和Windows的配置方法。更多的启动配置请参考下面内容。

5. 引导多系统配置

GRUB支持多操作系统引导。用GRUB引导后可以进入命令行模式或者菜单模式,可以通过灵活的命令行模式选择引导各个分区的操作系统,指定引导参数。
GRUB支持三种引导方法,一种是直接引导操作系统内核,另一种是通过chainload进行间接引导,第三种就是通过网络引导操作系统。

对于GRUB能够支持的Linux,FreeBSD,OpenBSD,NetBSD,GUN Mach等可以通过直接引导完成,但是对于GRUB不支持的操作系统(如Windows),需要用第二种方法chainload来完成。下面就分别来看看这几种引导方法:

(1) 直接引导

配置过程通常如下:

a) 用root命令设置包含操作系统内核的根设备

b) 用kernel命令装载内核映象文件,如果这个内核引导的时有参数的话,可以直接将参数加在内核文件名的后面

c) 用module或modulenounzip装载内核模块

d) boot开始引导

(2) chainload引导

a) 设置GRUB的根设备,用rootnoverify (hdx,y)指定

b) 开始引导,用chainloader +1指定,此处“+1”是指示GRUB读入分区的第一个扇区的引导记录。

c) 执行boot开始引导

以上是一般的chainloader方式,对于DOS和WINDOWS,可以简单地用两条指令进行引导:chainloader (hdx,y)+1,然后boot,其中x,y用来指明所在分区号。

(3) 从网络引导:

为了使GRUB能够支持从网络引导,需要在编译时打开网络支持选项(请参考源文件中的netboot/README.netboot)。另外,要在
网络中设置两个服务:动态IP服务(BOOTP、DHCP或RARP)和FTP服务。然后,分别针对不同的服务器BOOTP,DHCP或RARP运行
bootp,dhcp或rarp。如果一切设置无误的话GRUB就会给出IP,IP
netmask和TFTP服务器的IP和网关的IP地址。最后,从网上得到操作系统的映象文件。下面是一个例子:

grub> bootp

Probing...[NE*000]

NE2000 base ...

Address: 192.168.110.23 Netmask: 255.255.255.0

Server: 192.168.110.14 Gateway: 192.168.110.1

grub> root (nd)

grub> kernel /tftproot/gnumach.gz root=sd0s1

grub> module /tftproot/serverboot.gz

grub> boot

(4) 操作系统引导距离

a) GNU/Linux

grub> root (hd1,3)

grub> kernel /vmlinuz root=/dev/hda1

如果你需要指定内核启动参数的话,可以直接加到命令的最后面如:

grub> kernel /vmlinuz root=/dev/hda1 vga=ext

如果你使用initrd的话,在kernel命令之后执行:

grub> initrd /initrd

grub> boot

b) FreeBSD

GRUB能够直接装载.ELF和a.out两种格式的内核,但是由于FreeBSD的内核引导接口有时有较大的变动,所以,对FreeBSD最安全的引导方法是引导/boot/loader。

grub> root (hd0,a)

grub> kernel /boot/loader

grub> boot

c) NetBSD,OpenBSD,NetBSD

这三种系统的引导指令序列一样,如下:

q 用root命令设置根设备

q 用kernel装载内核

q 用boot'引导系统

d) DOS/Windows

grub> rootnoverify (hd0,0)

grub> chainloader +1

grub> boot

e) SCO UnixWare

grub> rootnoverify (hd1,0)

grub> chainloader --force +1

grub> makeactive

注意,最后的这条指令将设置Unix Ware分区为活动分区,这样要求你的GRUB安装在MBR,否则下次启动时将直接进入UnixWare而不会进入GRUB grub>

当然,如果每次引导都需要敲入命令的话实在是太麻烦了,因此,类似于LILO,GRUB提供了一个菜单方式,只要将这些命令放入配置文件中就可以实现菜单
方式的多引导。当然在菜单方式下你可以切换到命令模式下。GRUB引导时查找/boot/grub/menu.lst,如果存在这个文件的话,就根据这个
文件生成一个引导菜单,menu.lst文件格式请参考后面的内容。

6. GRUB的安全配置
对于Linux系统,root帐号有着之高无尚的权限。但即使root帐号没有被盗窃,黑客照样可能登陆系
统窃取机密。可以在启动的时候,通过在Linux启动菜单的kernel行最后加入“1”或“single”进入单用户模式,直接可以修改root密码。
另外,有时候一台计算机上安装了多个操作系统,有些系统必须在授权后才可以启动。

为了保护GRUB在未被授权下的修改和一些系统在授权下才可启动的目的,GRUB提供了密码验证功能,只有通过密码验证才能在启动时候进入命令行状态修改GRUB或启动需要密码验证的操作系统。

GRUB的菜单密码是在grub.conf配置文件中实现的。GRUB提供的密码级别有两种,一种是全局的密码,即进入命令行前都必须输入的密码,另外就是只针对修改特定菜单项时必须输入的密码。GRUB密码可以是明文的或MD5加密的。

如果是明文密码,格式为:password 明文密码串,如:

password 123456;

如果是MD5加密的密码,格式为:password --md5 md5密码串,如:

password --md5 XJjfsddf33444%%$^$^$###。下面是一个具体的例子:

#=================包含密码的grub.conf文件范例==================

password --md5 <进入GRUB命令行模式的密码>

timeout=30

default=0

title “Red Hat Enterprise Linux 4 for syd168”

password --md5 <启动RHEL 4验证密码>

root (hd0,1)

kernel /vmlinuz ro root=LABEL=/

initrd /initrd-xxx.img

title “Windows 2003 Enterprise Edition for syd168”

password --md5 <启动Windows 2003验证密码>

rootnoverify (hd0,0)

chainloader +1

#=================包含密码的grub.conf文件范例==================

对于这个配置,当GRUB显示菜单的时候,必须按下p并输入对应的密码才能进入命令模式,如果选择“Red Hat Enterprise
Linux 4 for syd168”并按下回车,会出现提示信息,要求输入密码,这时应该输入密码,密码正确后才可以启动该系统。

--md5告诉GRUB后面的内容是已经用md5算法加密过的了。所以GRUB会将用户输入的口令用MD5(由grub-crypt完成)加密后再与之比
较。要产生MD5密码,可以把在命令模式下用md5crypt命令或在shell下执行grub-md5-crypt得到的MD5加密串复制到配置文件中
即可。

7. GRUB的修复

GRUB虽然提供了方便的启动管理功能,但某些情况下,可能因为误操作或者系统故障导致GRUB被破坏或丢失。如何恢复被破坏的GRUB是很多读者头痛的问题。其实GRUB的修复并不是很难,只要懂得GRUB的基本工作原理,就可以很容易地修复它。

下面,我们介绍两种修复GRUB的方法,即用安装光盘和用备份软盘修复的方法。

(1) 用安装光盘修复GRUB

a.) 用安装光盘启动计算机

首先修改计算机的CMOS配置,并准备好RHEL 4的安装光盘。然后启动计算机,系统会自动从光盘启动。

b.) 选择rescue修复模式

当计算机启动后,会显示如图4-5所示的画面,在最后行输入如下命令并按回车:

boot:linux rescue

这时候,安装程序会自动进入紧急修复模式。首先显示语言,键盘等基本配置。建议语言选择中选择简体中文,后面会出现网络配置,可以选择不配置网络。随后会
出现图4-6的画面,提示查找系统中安装的RHEL
4并将其挂载在/mnt/sysimage下。这里直接按回车即可,随后出现图4-7,表示找到已经安装的RHEL
4,并要将其挂在在/mnt/sysimage下,而且提示可以将其切换为根。这里也是按回车即可。然后就进入Linux 的命令行状态。

c.) 改变根路径

按照上面的提示,首先切换目录/mnt/sysimage为根。输入如下命令即可:

#chroot /mnt/sysimage

这时候,/就和正常的Linux一样了。

d.) 运行grub修复GRUB

现在,就可以开始修复GRUB了。只要执行如下几个命令即可:

#grub #执行grub交互程序

grub>find /boot/grub/stage1 #查找stage1所在的设备

(hd0,0) #显示查到的结果

grub>root (hd0,0) #设置根设备

grub>setup (hd0) #安装GRUB 到MBR

grub>quit #退出GRUB

e.) 退出系统并重新启动系统

#exit #退出chroot

#ex
9e44
it #退出linux并重新启动

执行完上述两条命令后,系统就会重新启动。丢失的GRUB就再次出现了。当然,如果GRUB的破坏很利害,导致很多文件都丢失。则可以按照前面的指示,重新安装GRUB。在RHEL 4的安装光盘中本身就包含GRUB的安装包。

当然,也可以通过启动软盘修复GRUB。但现在计算机上使用软盘的几率已经很小了,所以这里就不再啰嗦了。当然,也可以通过可启动的U盘修复硬盘上的GRUB,由于篇幅的关系,这里讨论了。

*********************华丽的分划线*********************

忘了 root 密码还可以通过修改 Grub 进入单用户模式来重置密码, 忘了 Grub 密码怎么办呢?

  a. 进入Linux救援模式(resuce mode): 用光盘引导系统,在 "boot>" 提示符后输入 "linux rescue" 并回车即可。

  b. 如果没有使用md5 加密, 则直接查看/修改
"/mnt/sysimage/boot/grub/grub.conf" 中 "password xxxxxx" *
的密码或者直接删除这一句即可; 如果是md5 加密过, 则修改 "password --md5 xxxxxxxxxxxxxxxxxx"
为明文密码(修改为 "password xxxxxx")或直接删除这一句即可。

  c. 用 "exit" 命令退出 shell 后, 系统自动重启, 新设置即可生效。

  当然,如果你运行了 "chroot /mnt/sysimage" 命令重设了根分区的话,对应
路径则为 "/boot/grub/grub.conf"。

*********************华丽的分划线*********************

grup密码的破解:

密码放在/boot/grub/grub.conf

它是md5取哈希值存入 -- 其实就是不可逆的一种加密形式. 大概类似unix password中的crypt().

你要找一些字典进暴力破解.John the Ripper 是一个专业的密码破解工具

Linux密码破解与防护(视频下载):爱国者安全网 www.3800hk.com

*********************

可以通过设置GRUB的密码来使编辑GRUB的时候需要密码才能进行编辑。

进行系统后使用vi打开/etc/grub.conf这个GRUB的配置文件。

default=0

timeout=5

splashimage=(hd0,0)/grub/splash.xpm.gz

password=123456

 title Red Hat Enterprise Linux AS (2.6.9-42.EL)   root (hd0,0)

  kernel /vmlinuz-2.6.9-42.EL ro root=LABEL=/ rhgb quiet

  initrd /initrd-2.6.9-42.EL.img
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息