吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5046|回复: 1
收起左侧

[其他转载] [zz]驱动对象设备对象设备栈乱杂谈

[复制链接]
zzage 发表于 2009-9-10 20:04
作者: JIURL

主页: http://jiurl.yeah.net  

用有限的几句话就舒舒服服的建立起对驱动对象和设备对象的概念是不可能的。刚开始是一片模糊,了解的多了,慢慢就清楚。下面的内容会使你对他们了解的清楚些。
  为了后面的叙述方便,首先列出驱动对象和设备对象的结构。
  驱动对象结构 DRIVER_OBJECT ,定义如下
  struct _DRIVER_OBJECT (sizeof=168)
  +00 int16 Type
  +02 int16 Size
  +04 struct _DEVICE_OBJECT *DeviceObject
  +08 uint32 Flags
  +0c void *DriverStart
  +10 uint32 DriverSize
  +14 void *DriverSection
  +18 struct _DRIVER_EXTENSION *DriverExtension
  +1c struct _UNICODE_STRING DriverName
  +1c uint16 Length
  +1e uint16 MaximumLength
  +20 uint16 *Buffer
  +24 struct _UNICODE_STRING *HardwareDatabase
  +28 struct _FAST_IO_DISPATCH *FastIoDispatch
  +2c function *DriverInit
  +30 function *DriverStartIo
  +34 function *DriverUnload
  +38 function *MajorFunction[28]
  DDK 中有对于一些域的说明
  [00] IRP_MJ_CREATE
  [01] IRP_MJ_CREATE_NAMED_PIPE
  [02] IRP_MJ_CLOSE
  [03] IRP_MJ_READ
  [04] IRP_MJ_WRITE
  [05] IRP_MJ_QUERY_INFORMATION
  [06] IRP_MJ_SET_INFORMATION
  [07] IRP_MJ_QUERY_EA
  [08] IRP_MJ_SET_EA
  [09] IRP_MJ_FLUSH_BUFFERS
  [0a] IRP_MJ_QUERY_VOLUME_INFORMATION
  [0b] IRP_MJ_SET_VOLUME_INFORMATION
  [0c] IRP_MJ_DIRECTORY_CONTROL
  [0d] IRP_MJ_FILE_SYSTEM_CONTROL
  [0e] IRP_MJ_DEVICE_CONTROL
  [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL
  [10] IRP_MJ_SHUTDOWN
  [11] IRP_MJ_LOCK_CONTROL
  [12] IRP_MJ_CLEANUP
  [13] IRP_MJ_CREATE_MAILSLOT
  [14] IRP_MJ_QUERY_SECURITY
  [15] IRP_MJ_SET_SECURITY
  [16] IRP_MJ_POWER
  [17] IRP_MJ_SYSTEM_CONTROL
  [18] IRP_MJ_DEVICE_CHANGE
  [19] IRP_MJ_QUERY_QUOTA
  [1a] IRP_MJ_SET_QUOTA
  [1b] IRP_MJ_PNP
  struct _DRIVER_EXTENSION (sizeof=24)
  +00 struct _DRIVER_OBJECT *DriverObject
  +04 function *AddDevice
  +08 uint32 Count
  +0c struct _UNICODE_STRING ServiceKeyName
  +0c uint16 Length
  +0e uint16 MaximumLength
  +10 uint16 *Buffer
  +14 struct _IO_CLIENT_EXTENSION *ClientDriverExtension
  设备对象结构 DEVICE_OBJECT ,定义如下
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type
  +02 uint16 Size
  +04 int32 ReferenceCount
  +08 struct _DRIVER_OBJECT *DriverObject
  +0c struct _DEVICE_OBJECT *NextDevice
  +10 struct _DEVICE_OBJECT *AttachedDevice
  +14 struct _IRP *CurrentIrp
  +18 struct _IO_TIMER *Timer
  +1c uint32 Flags
  +20 uint32 Characteristics
  +24 struct _VPB *Vpb
  +28 void *DeviceExtension
  +2c uint32 DeviceType
  +30 char StackSize
  +34 union __unnamed62 Queue
  +34 struct _LIST_ENTRY ListEntry
  +34 struct _LIST_ENTRY *Flink
  +38 struct _LIST_ENTRY *Blink
  +34 struct _WAIT_CONTEXT_BLOCK Wcb
  +34 struct _KDEVICE_QUEUE_ENTRY WaitQueueEntry
  +34 struct _LIST_ENTRY DeviceListEntry
  +34 struct _LIST_ENTRY *Flink
  +38 struct _LIST_ENTRY *Blink
  +3c uint32 SortKey
  +40 byte Inserted
  +44 function *DeviceRoutine
  +48 void *DeviceContext
  +4c uint32 NumberOfMapRegisters
  +50 void *DeviceObject
  +54 void *CurrentIrp
  +58 struct _KDPC *BufferChainingDpc
  +5c uint32 AlignmentRequirement
  +60 struct _KDEVICE_QUEUE DeviceQueue
  +60 int16 Type
  +62 int16 Size
  +64 struct _LIST_ENTRY DeviceListHead
  +64 struct _LIST_ENTRY *Flink
  +68 struct _LIST_ENTRY *Blink
  +6c uint32 Lock
  +70 byte Busy
  +74 struct _KDPC Dpc
  +74 int16 Type
  +76 byte Number
  +77 byte Importance
  +78 struct _LIST_ENTRY DpcListEntry
  +78 struct _LIST_ENTRY *Flink
  +7c struct _LIST_ENTRY *Blink
  +80 function *DeferredRoutine
  +84 void *DeferredContext
  +88 void *SystemArgument1
  +8c void *SystemArgument2
  +90 uint32 *Lock
  +94 uint32 ActiveThreadCount
  +98 void *SecurityDescriptor
  +9c struct _KEVENT DeviceLock
  +9c struct _DISPATCHER_HEADER Header
  +9c byte Type
  +9d byte Absolute
  +9e byte Size
  +9f byte Inserted
  +a0 int32 SignalState
  +a4 struct _LIST_ENTRY WaitListHead
  +a4 struct _LIST_ENTRY *Flink
  +a8 struct _LIST_ENTRY *Blink
  +ac uint16 SectorSize
  +ae uint16 Spare1
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension
  +b4 void *Reserved
  DDK 中有对于一些域的说明
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type
  +02 uint16 Size
  +04 struct _DEVICE_OBJECT *DeviceObject
  +08 uint32 PowerFlags
  +0c *Dope
  +10 uint32 ExtensionFlags
  +14 void *DeviceNode
  +18 struct _DEVICE_OBJECT *AttachedTo
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink
  +20 struct _LIST_ENTRY *Blink
  有一个载入内存的驱动程序文件,就会有一个驱动对象(DRIVER_OBJECT)。
  比如,驱动 i8042prt 是在系统初始化阶段,IO 管理器调用函数 nt!IopLoadDriver 载入的。nt!IopLoadDriver 读取注册表,获得驱动程序文件 i8042prt.SYS 的路径,将这个文件载入内存。之后会调用 nt!ObCreateObject 创建一个驱动对象,并初始化这个驱动对象。
  设备对象(DEVICE_OBJECT)由驱动创建。一个驱动可以创建多个设备对象(DEVICE_OBJECT)。通过驱动对象(DRIVER_OBJECT),可以找到由该驱动创建的所有设备对象(DEVICE_OBJECT)。一个驱动创建的所有设备对象(DEVICE_OBJECT)链成一条链,该驱动的驱动对象(DRIVER_OBJECT)可以找到这个链。一个设备对象(DEVICE_OBJECT)也可以找到创建它的驱动的驱动对象(DRIVER_OBJECT)。下面我们使用 WinDbg 实际观察驱动 i8042prt 的情况,i8042prt 是完成 ps/2 键盘驱动主要功能的驱动程序。
  在这里我们先做个说明,对于同时插有 ps/2 键盘和 ps/2 鼠标的计算机上, i8042prt 会创建两个设备对象,一个用于键盘,一个用于鼠标。
  首先我们从命名对象地址空间,找到 i8042prt 的 DRIVER_OBJECT 的地址
  kd> !object \driver\i8042prt
  Object: fe4f69f0 Type: (fe4ec3e0) Driver
  ObjectHeader: fe4f69d8
  HandleCount: 0 PointerCount: 5
  Directory Object: fe51bf30 Name: i8042prt
  下面我们看 i8042prt 的 DRIVER_OBJECT 中的内容
  kd> !strct driver_object fe4f69f0
  struct _DRIVER_OBJECT (sizeof=168)
  +00 int16 Type = 0004
  +02 int16 Size = 00a8
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4D3BA0
  // 注意 DeviceObject 链上的第一个设备对象
  +08 uint32 Flags = 00000012
  +0c void *DriverStart = FE1BD000
  +10 uint32 DriverSize = 00021000
  +14 void *DriverSection = FE4F6CC8
  +18 struct _DRIVER_EXTENSION *DriverExtension = FE4F6A98
  +1c struct _UNICODE_STRING DriverName
  +1c uint16 Length = 0020
  +1e uint16 MaximumLength = 0020
  +20 uint16 *Buffer = E127FE88
  +24 struct _UNICODE_STRING *HardwareDatabase = 80541FC0
  +28 struct _FAST_IO_DISPATCH *FastIoDispatch = 00000000
  +2c function *DriverInit = FE1D8000
  +30 function *DriverStartIo = FE1BF444
  +34 function *DriverUnload = FE1CB920
  +38 function *MajorFunction[28] = FE1CB000
  80425354
  FE1CB14E
  80425354
  80425354
  80425354
  80425354
  80425354
  80425354
  FE1BE558
  80425354
  80425354
  80425354
  80425354
  FE1CB243
  FE1BE667
  80425354
  80425354
  80425354
  80425354
  80425354
  80425354
  FE1D2C63
  FE1D3633
  80425354
  80425354
  80425354
  FE1D1BFB
  我们看到了 DeviceObject 上的第一个设备对象的地址 FE4D3BA0 ,我们使用 WinDbg 的 !devobj 命令,来获得一些信息
  kd> !devobj FE4D3BA0
  Device object (fe4d3ba0) is for:
  \Driver\i8042prt DriverObject fe4f69f0
  Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
  DevExt fe4d3c58 DevObjExt fe4d3ed8
  ExtensionFlags (0xc0000000)
  Unknown flags 0xc0000000
  AttachedDevice (Upper) fe4d3a60 \Driver\vmmouse
  AttachedTo (Lower) fe4dd610 \Driver\ACPI
  Device queue is not busy.
  从获得的信息来看,这是用于鼠标的那个设备对象,下面我们看这个设备对象 DEVICE_OBJECT 中的具体内容
  kd> !strct device_object FE4D3BA0
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 0338
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
  // 正是 \Driver\i8042prt 的驱动对象的地址
  +0c struct _DEVICE_OBJECT *NextDevice = FE4F5020
  // DeviceObject 链的下一个
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4D3A60
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  我们看到了设备对象 +0c struct _DEVICE_OBJECT *NextDevice 处是 DeviceObject 链上的下一个设备对象的地址,值为 FE4F5020 ,我们使用 WinDbg 的 !devobj 命令,来获得一些信息
  kd> !devobj FE4F5020
  Device object (fe4f5020) is for:
  \Driver\i8042prt DriverObject fe4f69f0
  Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
  DevExt fe4f50d8 DevObjExt fe4f5358
  ExtensionFlags (0xc0000000)
  Unknown flags 0xc0000000
  AttachedDevice (Upper) fe4f5df0 \Driver\Kbdclass
  AttachedTo (Lower) fe4dd730 \Driver\ACPI
  Device queue is not busy.
  从获得的信息来看,这是用于键盘的那个设备对象,下面我们看这个设备对象 DEVICE_OBJECT 中的具体内容
  kd> !strct device_object FE4F5020
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 0338
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
  // 正是 \Driver\i8042prt 的驱动对象的地址
  +0c struct _DEVICE_OBJECT *NextDevice = 00000000
  // 为空,表明链结束了。
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5DF0
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  我们观察初始化时,看到 i8042prt 调用 IoCreateDevice 创建设备对象,并且 IoCreateDevice 会把新创建的这个设备对象,链入驱动的设备链中。
  现在我们对驱动对象和设备对象之间的联系,做一个总结,
  驱动调用 IoCreateDevice 创建设备对象,一个驱动创建的所有设备对象链成一个链,这个链以空表示结束。驱动对象通过 +04 struct _DEVICE_OBJECT *DeviceObject 可以找到这个链。设备对象通过 +0c struct _DEVICE_OBJECT *NextDevice 链在一起。设备对象通过 +08 struct _DRIVER_OBJECT *DriverObject 可以找到创建它的驱动的驱动对象。
  下面我们来讲讲设备栈。一个物理设备的驱动任务,通常由几个驱动程序一层一层的共同完成。每层一个设备对象,他们联系在一起,组成一个设备栈。一个设备栈上的设备对象,从上自下,联系在一起。从下自上,也联系在一起。我们以 ps/2 键盘驱动为例,使用 WinDbg 来观察它的设备栈,以及他们如何联系在一起。
  ps/2 键盘驱动的设备栈,大概就是这个样子
  kd> !devstack fe4f5020
  !DevObj !DrvObj !DevExt ObjectName
  fe4f5df0 \Driver\Kbdclass fe4f5ea8 KeyboardClass0
  > fe4f5020 \Driver\i8042prt fe4f50d8
  fe4dd730 \Driver\ACPI fe507468 0000000e
  !DevNode fe4fed68 :
  DeviceInst is "ACPI\PNP0303\4&5289e18&0"
  ServiceName is "i8042prt"
  最上面的 DEVICE_OBJECT 地址为 fe4f5df0,属于驱动 \Driver\Kbdclass
  中间的 DEVICE_OBJECT 地址为 fe4f5020,属于驱动 \Driver\i8042prt
  最下面的 DEVICE_OBJECT 地址为 fe4dd730,属于驱动 \Driver\ACPI
  下面我们看这3个设备对象,如何联系在一起。
  最上面一层的 DEVICE_OBJECT
  kd> !devobj fe4f5df0
  Device object (fe4f5df0) is for:
  KeyboardClass0 \Driver\Kbdclass DriverObject fe4f6330
  Current Irp fe43a1c8 RefCount 0 Type 0000000b Flags 00002044
  DevExt fe4f5ea8 DevObjExt fe4f5fd8
  ExtensionFlags (0000000000)
  AttachedTo (Lower) fe4f5020 \Driver\i8042prt
  Device queue is busy -- Queue empty.
  看到这个设备对象有名字,叫 KeyboardClass0 ,属于驱动 Kbdclass
  kd> !strct device_object fe4f5df0
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 01e8
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F6330
  // 正是 kbdclass 的 DRIVER_OBJECT 的地址
  +0c struct _DEVICE_OBJECT *NextDevice = 00000000
  +10 struct _DEVICE_OBJECT *AttachedDevice = 00000000
  // 为空结束,表示上面没有其它设备对象了
  +14 struct _IRP *CurrentIrp = FE43A1C8
  ...
  +ae uint16 Spare1 = 0000
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4F5FD8
  // 它的 DEVOBJ_EXTENSION 在 FE4F5FD8
  +b4 void *Reserved = 00000000
  kd> !strct DEVOBJ_EXTENSION FE4F5FD8
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type = 000d
  +02 uint16 Size = 0000
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4F5DF0
  +08 uint32 PowerFlags = 00000010
  +0c *Dope = 00000000
  +10 uint32 ExtensionFlags = 00000000
  +14 void *DeviceNode = 00000000
  +18 struct _DEVICE_OBJECT *AttachedTo = FE4F5020
  // 下面一层的设备对象为 FE4F5020
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink = 00000000
  +20 struct _LIST_ENTRY *Blink = 00000000
  中间层的 DEVICE_OBJECT
  kd> !devobj fe4f5020
  Device object (fe4f5020) is for:
  \Driver\i8042prt DriverObject fe4f69f0
  Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
  DevExt fe4f50d8 DevObjExt fe4f5358
  ExtensionFlags (0xc0000000)
  Unknown flags 0xc0000000
  AttachedDevice (Upper) fe4f5df0 \Driver\Kbdclass
  AttachedTo (Lower) fe4dd730 \Driver\ACPI
  Device queue is not busy.
  看到这个设备对象没有名字,属于驱动 i8042prt
  kd> !strct device_object fe4f5020
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 0338
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
  // 正是 i8042prt 的 DRIVER_OBJECT 的地址
  +0c struct _DEVICE_OBJECT *NextDevice = 00000000
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5DF0
  // 上面一层的设备对象
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  +ae uint16 Spare1 = 0001
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4F5358
  // 它的 DEVOBJ_EXTENSION 在 FE4F5358
  +b4 void *Reserved = 00000000
  kd> !strct DEVOBJ_EXTENSION FE4F5358
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type = 000d
  +02 uint16 Size = 0000
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4F5020
  +08 uint32 PowerFlags = 00000000
  +0c *Dope = 00000000
  +10 uint32 ExtensionFlags = c0000000
  +14 void *DeviceNode = 00000000
  +18 struct _DEVICE_OBJECT *AttachedTo = FE4DD730
  // 下面一层的设备对象
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink = 00000000
  +20 struct _LIST_ENTRY *Blink = 00000000
  最下面一层的 DEVICE_OBJECT
  kd> !devobj fe4dd730
  Device object (fe4dd730) is for:
  0000000e \Driver\ACPI DriverObject fe4e8ad0
  Current Irp 00000000 RefCount 1 Type 00000032 Flags 00001040
  DevExt fe507468 DevObjExt fe4dd7e8 DevNode fe4fed68
  ExtensionFlags (0000000000)
  AttachedDevice (Upper) fe4f5020 \Driver\i8042prt
  Device queue is not busy.
  看到这个设备对象有名字,叫 0000000e ,属于驱动 acpi
  kd> !strct device_object fe4dd730
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 00b8
  +04 int32 ReferenceCount = 00000001
  +08 struct _DRIVER_OBJECT *DriverObject = FE4E8AD0
  // 正是 acpi 的 DRIVER_OBJECT 的地址
  +0c struct _DEVICE_OBJECT *NextDevice = FE4DD850
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5020
  // 上面一层的设备对象
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  +ae uint16 Spare1 = 0001
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4DD7E8
  // 它的 DEVOBJ_EXTENSION 在 FE4DD7E8
  +b4 void *Reserved = 00000000
  kd> !strct DEVOBJ_EXTENSION FE4DD7E8
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type = 000d
  +02 uint16 Size = 0000
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4DD730
  +08 uint32 PowerFlags = 00000010
  +0c *Dope = 00000000
  +10 uint32 ExtensionFlags = 00000000
  +14 void *DeviceNode = FE4FED68
  +18 struct _DEVICE_OBJECT *AttachedTo = 00000000
  // 为空结束,表示下面没有其它设备对象了
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink = 00000000
  +20 struct _LIST_ENTRY *Blink = 00000000
  从上自下。\Device\KeyboardClass0(DRIVER_OBJECT 是 kbdclass)可以找到 没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)。没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)可以找到 \Device\0000000e(DRIVER_OBJECT 是 ACPI)。
  从下自上。\Device\0000000e(DRIVER_OBJECT 是 ACPI) 可以找到 没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)。没有名字地址为fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)可以找到 \Device\KeyboardClass0(DRIVER_OBJECT 是 ACPI)。
  现在我们对设备栈上的设备对象之间的联系,做一个总结,
  设备栈上的设备对象,从上自下,通过 DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct _DEVICE_OBJECT *AttachedTo 联系在一起。
  设备栈上的设备对象,从下自上,通过 DEVICE_OBJECT 的 +10 struct _DEVICE_OBJECT *AttachedDevice 联系在一起。
  在观察键盘驱动的初始化过程中,我们看到了设备栈是如何建立起来的。
  驱动 i8042prt ,驱动 kbdclass 分别调用 IoAttachDeviceToDeviceStack ,把自己相应的设备对象加入到键盘设备栈中。IoAttachDeviceToDeviceStack 会设置 DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct _DEVICE_OBJECT *AttachedTo 和 DEVICE_OBJECT 的 +10 struct _DEVICE_OBJECT *AttachedDevice ,把两个对象联系在一起。并设置新加入的设备对象的 +30 char StackSize。
  晕了吧
  欢迎交流,欢迎交朋友,
  欢迎访问
  主页 http://jiurl.yeah.net http://jiurl.nease.net 论坛 http://jiurl.cosoft.org.cn/forum
  f啊k,不带你们这样的啊,有好事不叫我。

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

tt031026 发表于 2009-9-10 20:31
帮你顶一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-17 04:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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