windows 访问控制模型(一)

来源:互联网 发布:windows vista32位下载 编辑:程序博客网 时间:2024/05/18 01:36

最近研究了下windows的访问控制模型,于是想写篇博客加深下印象。有些内容直接转子互联网(已标记)


下面内容转自:

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

标 题: 【原创】白话windows之 访问控制模型(Access Control Model)
作 者: ddlx
时 间: 2013-06-10,21:38:41
链 接: http://bbs.pediy.com/showthread.php?t=173381

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


当一个线程使用Open*打开一个内核对象时,会发生什么?

有两种可能:

1. 打开成功,拿到句柄

2. 打开失败

这不是废话么?!为啥打开失败呢?有两种可能:

1. 当前线程不具有指定的特权

2.  权限不足(由dwDesiredAccess参数指定权限)

这个时候就引入了今天的主题:令牌(包含特权列表)和安全描述符(描述用户权限)。


Token

token是什么?对了,他就是一个令牌。就像原先钦差大臣手里面的上方宝剑一样,上可惩天子,下可斩贪官!所以千万不要小看它哦亲~。那Token中都有些神马东东呢?

先看一下他的数据结构:

代码:
lkd> dt nt!_token   +0x000 TokenSource      : _TOKEN_SOURCE   +0x010 TokenId          : _LUID   +0x018 AuthenticationId : _LUID   +0x020 ParentTokenId    : _LUID   +0x028 ExpirationTime   : _LARGE_INTEGER   +0x030 TokenLock        : Ptr32 _ERESOURCE   +0x038 AuditPolicy      : _SEP_AUDIT_POLICY   +0x040 ModifiedId       : _LUID   +0x048 SessionId        : Uint4B   +0x04c UserAndGroupCount : Uint4B   +0x050 RestrictedSidCount : Uint4B   +0x054 PrivilegeCount   : Uint4B   +0x058 VariableLength   : Uint4B   +0x05c DynamicCharged   : Uint4B   +0x060 DynamicAvailable : Uint4B   +0x064 DefaultOwnerIndex : Uint4B   +0x068 UserAndGroups    : Ptr32 _SID_AND_ATTRIBUTES   +0x06c RestrictedSids   : Ptr32 _SID_AND_ATTRIBUTES   +0x070 PrimaryGroup     : Ptr32 Void   +0x074 Privileges       : Ptr32 _LUID_AND_ATTRIBUTES   +0x078 DynamicPart      : Ptr32 Uint4B   +0x07c DefaultDacl      : Ptr32 _ACL   +0x080 TokenType        : _TOKEN_TYPE   +0x084 ImpersonationLevel : _SECURITY_IMPERSONATION_LEVEL   +0x088 TokenFlags       : Uint4B   +0x08c TokenInUse       : UChar   +0x090 ProxyData        : Ptr32 _SECURITY_TOKEN_PROXY_DATA   +0x094 AuditData        : Ptr32 _SECURITY_TOKEN_AUDIT_DATA   +0x098 OriginatingLogonSession : _LUID   +0x0a0 VariablePart     : Uint4B
可以看出包含的东西很多:会话Id、用户和组列表、特权列表、默认DACL等。这些都有什么用呢?

会话Id,用户和组列表这些告诉我们Token是属于哪个用户的。

特权列表,这个是表示该Token都可以干哪些坏事,拥有的权限越多越牛B哈哈

我们既然知道了Token是何方神圣了,那谁可以拥有Token呢?对了,只有进程和线程才能拥有!

每一个进程都拥有一个Token(这个是必须有的),该Token叫主令牌。可以从父进程处继承,也可以是后来设置的,使用NtSetInformationProcess,Class=ProcessAccessToken。

每个线程可以拥有一个ImpersonationToken(模仿令牌)。该令牌不是必须的,线程可以不拥有模仿令牌。

由此看来一个线程最多拥有2个令牌:主令牌和模仿令牌,最少拥有一个令牌:主令牌。

设置线程的模仿令牌的方法:NtSetInformationThread, calss=ThreadImpersonationToken。

既然有了主令牌,模仿令牌有什么用呢?

当一个线程要加载一个驱动,但发现主令牌没有加载驱动特权,它就可以模仿主令牌,然后在模仿令牌中加入加载驱动特权

当一个线程想要打开一个文件,但是该文件只有User2用户才能打开,主令牌却是属于User1用户。这时候可以模仿一个User2用户的令牌,这样就可以打开该文件了。

下面我们看一下都有哪些特权

代码:
SeAssignPrimaryTokenPrivilegeSeAuditPrivilegeSeBackupPrivilegeSeChangeNotifyPrivilegeSeCreateGlobalPrivilegeSeCreatePagefilePrivilegeSeCreatePermanentPrivilegeSeCreateSymbolicLinkPrivilegeSeCreateTokenPrivilegeSeDebugPrivilegeSeEnableDelegationPrivilegeSeImpersonatePrivilegeSeIncreaseBasePriorityPrivilegeSeIncreaseQuotaPrivilegeSeIncreaseWorkingSetPrivilegeSeLoadDriverPrivilegeSeLockMemoryPrivilegeSeMachineAccountPrivilegeSeManageVolumePrivilegeSeProfileSingleProcessPrivilegeSeRelabelPrivilegeSeRemoteShutdownPrivilegeSeRestorePrivilegeSeSecurityPrivilegeSeShutdownPrivilegeSeSyncAgentPrivilegeSeSystemEnvironmentPrivilegeSeSystemProfilePrivilegeSeSystemtimePrivilegeSeTakeOwnershipPrivilegeSeTcbPrivilegeSeTimeZonePrivilegeSeTrustedCredManAccessPrivilegeSeUndockPrivilegeSeUnsolicitedInputPrivilege
哈哈,好多哦,这么多特权,并不都会在Token中出现。不在Token中出现的特权,是没办法再次添加到该Token中的!。

简单说明一下常见的。其他的看MSDN吧:http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

SeCreateGlobalPrivilege


创建全局的特权。这个特权直接影响到你可不可以创建一个有名字的全局事件、互斥量、内存区等。

SeDebugPrivilege

调试特权。顾名思义,跟调试有关。该特权直接影响到你能否打开系统进程如system、winlogin.exe等,并调试他们。

SeLoadDriverPrivilege

加载驱动特权。想加载驱动?那就必须有改权限。

SeImpersonatePrivilege

模仿特权。要想设置线程的模仿令牌,就要有该权限

SeCreateTokenPrivilege

创建令牌特权。没有该特权,就无法创建一个新的令牌。


一个Token中的特权列表中,已经指明该Token可以拥有哪些特权。不过有些特权并不是置位有效的,如果要使用该特权,需要使用SetTokenInformation修改。但是,特权列表中没有的特权,是不能添加进去的(当然你非要添加的话还是有办法的)!

下面我们用windbg看一下windbg.exe的Token

代码:
lkd> !process 0 1 windbg.exePROCESS 89031da0  SessionId: 0  Cid: 0c68    Peb: 7ffdb000  ParentCid: 0530    DirBase: 09f602e0  ObjectTable: e1f25ba0  HandleCount:  86.    Image: windbg.exe    VadRoot 88c553c0 Vads 87 Clone 0 Private 2296. Modified 3959. Locked 1.    DeviceMap e20447c8    Token                             e108d258    ElapsedTime                       02:26:28.813    UserTime                          00:00:01.171    KernelTime                        00:00:06.078    QuotaPoolUsage[PagedPool]         92740    QuotaPoolUsage[NonPagedPool]      3600    Working Set Sizes (now,min,max)  (1803, 50, 345) (7212KB, 200KB, 1380KB)    PeakWorkingSetSize                3848    VirtualSize                       60 Mb    PeakVirtualSize                   61 Mb    PageFaultCount                    7861    MemoryPriority                    BACKGROUND    BasePriority                      8    CommitCharge                      2704lkd> !token e108d258_TOKEN e108d258TS Session ID: 0User: S-1-5-21-2025429265-1682526488-1801674531-1005Groups:  00 S-1-5-21-2025429265-1682526488-1801674531-513    Attributes - Mandatory Default Enabled  01 S-1-1-0    Attributes - Mandatory Default Enabled  02 S-1-5-32-544    Attributes - Mandatory Default Enabled Owner  03 S-1-5-32-545    Attributes - Mandatory Default Enabled  04 S-1-5-4    Attributes - Mandatory Default Enabled  05 S-1-5-11    Attributes - Mandatory Default Enabled  06 S-1-5-5-0-5125624    Attributes - Mandatory Default Enabled LogonId  07 S-1-2-0    Attributes - Mandatory Default Enabled Primary Group: S-1-5-21-2025429265-1682526488-1801674531-513Privs:  00 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default  01 0x000000008 SeSecurityPrivilege               Attributes -  02 0x000000011 SeBackupPrivilege                 Attributes -  03 0x000000012 SeRestorePrivilege                Attributes -  04 0x00000000c SeSystemtimePrivilege             Attributes -  05 0x000000013 SeShutdownPrivilege               Attributes -  06 0x000000018 SeRemoteShutdownPrivilege         Attributes -  07 0x000000009 SeTakeOwnershipPrivilege          Attributes -  08 0x000000014 SeDebugPrivilege                  Attributes - Enabled  09 0x000000016 SeSystemEnvironmentPrivilege      Attributes -  10 0x00000000b SeSystemProfilePrivilege          Attributes -  11 0x00000000d SeProfileSingleProcessPrivilege   Attributes -  12 0x00000000e SeIncreaseBasePriorityPrivilege   Attributes -  13 0x00000000a SeLoadDriverPrivilege             Attributes - Enabled  14 0x00000000f SeCreatePagefilePrivilege         Attributes -  15 0x000000005 SeIncreaseQuotaPrivilege          Attributes -  16 0x000000019 SeUndockPrivilege                 Attributes - Enabled  17 0x00000001c SeManageVolumePrivilege           Attributes -  18 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default  19 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default Authentication ID:         (0,4e3f87)Impersonation Level:       AnonymousTokenType:                 PrimarySource: User32             TokenFlags: 0x89 ( Token in use )Token ID: 4f3891           ParentToken ID: 0Modified ID:               (0, 4ffaa5)RestrictedSidCount: 0      RestrictedSids: 00000000


SecurityDescriptor

安全描述符(sd)是访问控制模型的灵魂。所有的内核对象都拥有安全描述符。包括Token内核对象。

先看一下安全描述符的结构:

代码:
lkd> dt nt!_Security_Descriptor   +0x000 Revision         : UChar   +0x001 Sbz1             : UChar   +0x002 Control          : Uint2B   +0x004 Owner            : Ptr32 Void   +0x008 Group            : Ptr32 Void   +0x00c Sacl             : Ptr32 _ACL   +0x010 Dacl             : Ptr32 _ACL
安全描述符存放在内核对象的对象头结构(每个内核对象由两部分构成,一个是相同结构的对象头,还有一个不同结构的对象体)中:

代码:
lkd> dt nt!_Object_Header   +0x000 PointerCount     : Int4B   +0x004 HandleCount      : Int4B   +0x004 NextToFree       : Ptr32 Void   +0x008 Type             : Ptr32 _OBJECT_TYPE   +0x00c NameInfoOffset   : UChar   +0x00d HandleInfoOffset : UChar   +0x00e QuotaInfoOffset  : UChar   +0x00f Flags            : UChar   +0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION   +0x010 QuotaBlockCharged : Ptr32 Void   +0x014 SecurityDescriptor : Ptr32 Void   +0x018 Body             : _QUAD  //对象体(可知对象体地址 - 4 即为安全描述符的地址)
_Object_Header结构vista以后有了不少的变化,但是用来存放安全描述符的偏移位置没变,还是0x014

先简要介绍一下sd。   sd中描述了用户Sid,DACL、SACL。

SACL是系统访问控制列表,是用来做审计用的,一般不用关心。

DACL是自主访问控制列表,记录了哪些用户可以(/不可以)以何种方式访问该对象。

安全描述符查看方法:

1. 在对象上查看其属性。如文件,点击右键选择“属性”,找到“安全”选项卡,点击“高级”按钮。弹出的对话筐中,“权限”选项卡就是DACL,"审核"选项卡是SACL,“所有者”是Owner、Group。

2. 用windbg的!sd指令

代码:
lkd> !object \BaseNamedObjects\ShimSharedMemoryObject: e1acd3a8  Type: (896732b0) Section    ObjectHeader: e1acd390 (old version)    HandleCount: 15  PointerCount: 16    Directory Object: e15289d0  Name: ShimSharedMemorylkd> !sd poi(e1acd3a8-4)&ffffffff8     //这里低三位取0 不是很懂ReadVirtual: e1a94680 not properly sign extendedReadVirtual: e1a94680 not properly sign extendedReadVirtual: e1a94690 not properly sign extendedReadVirtual: e1a94690 not properly sign extendedReadVirtual: e1a94664 not properly sign extendedReadVirtual: e1a94664 not properly sign extended->Revision: 0x1->Sbz1    : 0x0->Control : 0x8004            SE_DACL_PRESENT            SE_SELF_RELATIVE->Owner   : S-1-5-32-544->Group   : S-1-5-18->Dacl    : ->Dacl    : ->AclRevision: 0x2->Dacl    : ->Sbz1       : 0x0->Dacl    : ->AclSize    : 0x1c->Dacl    : ->AceCount   : 0x1->Dacl    : ->Sbz2       : 0x0->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE->Dacl    : ->Ace[0]: ->AceFlags: 0x0->Dacl    : ->Ace[0]: ->AceSize: 0x14->Dacl    : ->Ace[0]: ->Mask : 0x0003001f->Dacl    : ->Ace[0]: ->SID: S-1-1-0->Sacl    :  is NULL
当打开一个对象时,会从线程所拥有的令牌中(如果存在模仿令牌则使用模仿令牌,否则使用主令牌)获取用户名和用户所在组列表,与对象的安全描述符中的DACL比较,这个时候会发生如下情况之一:

1. 对象的DACL==Null,则线程拥有完全的访问权限。

2. 对象的DACL不为Null,但是AceCount ==0(ACE,访问控制项),则拒绝任何线程访问。

3. 遍历DACL,找到跟令牌中用户或组一致的Ace,如果该Ace指明没有拥有制定的访问权限,则直接退出安全检查函数,并拒绝该线程访问。

4. 遍历DACL,没找到跟令牌中用户或组一致的Ace,并拒绝该线程访问。

5. 遍历DACL,找到跟令牌中用户或组一致的Ace,如果该Ace指明拥有制定的访问权限,则直接退出安全检查函数,并允许该线程访问。


为了更好的理解sd,给大家举个例子:

代码:
#include <windows.h>#include <sddl.h>BOOL InitSecurityDescriptor( SECURITY_ATTRIBUTES& sa, TCHAR* pszSD ){    sa.nLength = sizeof(SECURITY_ATTRIBUTES);    sa.bInheritHandle = FALSE;     return ConvertStringSecurityDescriptorToSecurityDescriptor(                pszSD,                SDDL_REVISION_1,                &(sa.lpSecurityDescriptor),                NULL);}void ReleaseSecurityDescriptor( SECURITY_ATTRIBUTES& sa ){    LocalFree(sa.lpSecurityDescriptor);}int _tmain(int argc, _TCHAR* argv[]){    SECURITY_ATTRIBUTES sa;    //创建一个局部名字事件(由于是局部的,多会话时,每个会话都创建一个同名的事件)    //第一个参数SECURITY_ATTRIBUTES传NULL,则使用进程TOKEN的默认DACL。    //默认DACL有两个ACE    //ACE1: 当前用户,拥有全部权限(读、写)    //ACE2: system用户,拥有全部权限(读、写)    HANDLE hEvent1 = CreateEvent( NULL, FALSE, FALSE, TEXT("Event1"));    //创建一个局部名字事件,与上面是等价的    //"D:(D;;GR;;;WD)(A;;GW;;;WD)" 的意思是: DACL添加Everyone用户,拒绝读,允许写权限    InitSecurityDescriptor( sa, TEXT("D:(D;;GR;;;WD)(A;;GW;;;WD)") );    HANDLE hEvent2 = CreateEvent( &sa, FALSE, FALSE, TEXT("Local\\Event2"));    ReleaseSecurityDescriptor(sa);    HANDLE hEventX = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("Local\\Event2"));    if( hEventX != NULL )    {        printf( "进入这里,有权限\n" );        CloseHandle(hEventX);    }    hEventX = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("Local\\Event2"));    if( hEventX == NULL )    {        printf( "进入这里,无权限。gle:%d\n", GetLastError() );    }    //创建一个全局名字事件    //由于其只给当前用户和system分配了权限,所以虽然是全局事件,但是其他会话也是无法访问的    HANDLE hEvent3 = CreateEvent( NULL, FALSE, FALSE, TEXT("Global\\Event3"));    //手动创建一个SECURITY_ATTRIBUTES,使用SDDL语法    //D:(A;;GA;;;WD) 的意思是: DACL添加Everyone用户,并让其拥有全部权限    InitSecurityDescriptor( sa, TEXT("D:(A;;GA;;;WD)") );    //创建一个全局名字事件,可以被其他会话访问    HANDLE hEvent4 = CreateEvent( &sa, FALSE, FALSE, TEXT("Global\\Event4"));    ReleaseSecurityDescriptor(sa);    printf( "%p, %p, %p, %p\n", hEvent1, hEvent2, hEvent3, hEvent4 );    getchar();    CloseHandle(hEvent1);    CloseHandle(hEvent2);    CloseHandle(hEvent3);    CloseHandle(hEvent4);    return 0;}
上述例子在会话1中运行后结果:
代码:
lkd> !object \Sessions\1\BaseNamedObjects\Event1Object: 89584ac8  Type: (896762f8) Event    ObjectHeader: 89584ab0 (old version)    HandleCount: 1  PointerCount: 2    Directory Object: e19721e0  Name: Event1lkd> !sd poi(89584ac8-4)&fffffff8->Revision: 0x1->Sbz1    : 0x0->Control : 0x8004            SE_DACL_PRESENT            SE_SELF_RELATIVE->Owner   : S-1-5-21-2025429265-1682526488-1801674531-1006//当前用户Sid->Group   : S-1-5-21-2025429265-1682526488-1801674531-513//管理员组Sid->Dacl    : ->Dacl    : ->AclRevision: 0x2->Dacl    : ->Sbz1       : 0x0->Dacl    : ->AclSize    : 0x64->Dacl    : ->AceCount   : 0x3->Dacl    : ->Sbz2       : 0x0->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE//允许->Dacl    : ->Ace[0]: ->AceFlags: 0x0->Dacl    : ->Ace[0]: ->AceSize: 0x14->Dacl    : ->Ace[0]: ->Mask : 0x001f0003//完全控制权限->Dacl    : ->Ace[0]: ->SID: S-1-5-18//system Sid->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE->Dacl    : ->Ace[1]: ->AceFlags: 0x0->Dacl    : ->Ace[1]: ->AceSize: 0x24->Dacl    : ->Ace[1]: ->Mask : 0x001f0003->Dacl    : ->Ace[1]: ->SID: S-1-5-21-2025429265-1682526488-1801674531-1006//会话1用户的Sid->Dacl    : ->Ace[2]: ->AceType: ACCESS_ALLOWED_ACE_TYPE->Dacl    : ->Ace[2]: ->AceFlags: 0x0->Dacl    : ->Ace[2]: ->AceSize: 0x24->Dacl    : ->Ace[2]: ->Mask : 0x001f0003->Dacl    : ->Ace[2]: ->SID: S-1-5-21-2025429265-1682526488-1801674531-1006->Sacl    :  is NULLlkd> !object \Sessions\1\BaseNamedObjects\Event2Object: 893db418  Type: (896762f8) Event    ObjectHeader: 893db400 (old version)    HandleCount: 1  PointerCount: 2    Directory Object: e19721e0  Name: Event2lkd> !sd poi(893db418-4)&fffffff8->Revision: 0x1->Sbz1    : 0x0->Control : 0x8004            SE_DACL_PRESENT            SE_SELF_RELATIVE->Owner   : S-1-5-21-2025429265-1682526488-1801674531-1006->Group   : S-1-5-21-2025429265-1682526488-1801674531-513->Dacl    : ->Dacl    : ->AclRevision: 0x2->Dacl    : ->Sbz1       : 0x0->Dacl    : ->AclSize    : 0x30->Dacl    : ->AceCount   : 0x2->Dacl    : ->Sbz2       : 0x0->Dacl    : ->Ace[0]: ->AceType: ACCESS_DENIED_ACE_TYPE//拒绝->Dacl    : ->Ace[0]: ->AceFlags: 0x0->Dacl    : ->Ace[0]: ->AceSize: 0x14->Dacl    : ->Ace[0]: ->Mask : 0x00020001//读权限->Dacl    : ->Ace[0]: ->SID: S-1-1-0//Everyone SID->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE->Dacl    : ->Ace[1]: ->AceFlags: 0x0->Dacl    : ->Ace[1]: ->AceSize: 0x14->Dacl    : ->Ace[1]: ->Mask : 0x00020002//写权限->Dacl    : ->Ace[1]: ->SID: S-1-1-0->Sacl    :  is NULLlkd> !object \BaseNamedObjects\Event3Object: 8945d7d0  Type: (896762f8) Event    ObjectHeader: 8945d7b8 (old version)    HandleCount: 1  PointerCount: 2    Directory Object: e15289d0  Name: Event3lkd> !sd poi(8945d7d0-4)&fffffff8->Revision: 0x1->Sbz1    : 0x0->Control : 0x8004            SE_DACL_PRESENT            SE_SELF_RELATIVE->Owner   : S-1-5-21-2025429265-1682526488-1801674531-1006->Group   : S-1-5-21-2025429265-1682526488-1801674531-513->Dacl    : ->Dacl    : ->AclRevision: 0x2->Dacl    : ->Sbz1       : 0x0->Dacl    : ->AclSize    : 0x40->Dacl    : ->AceCount   : 0x2->Dacl    : ->Sbz2       : 0x0->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE->Dacl    : ->Ace[0]: ->AceFlags: 0x0->Dacl    : ->Ace[0]: ->AceSize: 0x24->Dacl    : ->Ace[0]: ->Mask : 0x001f0003->Dacl    : ->Ace[0]: ->SID: S-1-5-21-2025429265-1682526488-1801674531-1006->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE->Dacl    : ->Ace[1]: ->AceFlags: 0x0->Dacl    : ->Ace[1]: ->AceSize: 0x14->Dacl    : ->Ace[1]: ->Mask : 0x001f0003->Dacl    : ->Ace[1]: ->SID: S-1-5-18->Sacl    :  is NULLlkd> !object \BaseNamedObjects\Event4Object: 8912ca78  Type: (896762f8) Event    ObjectHeader: 8912ca60 (old version)    HandleCount: 1  PointerCount: 2    Directory Object: e15289d0  Name: Event4lkd> !sd poi(8912ca78-4)&fffffff8->Revision: 0x1->Sbz1    : 0x0->Control : 0x8004            SE_DACL_PRESENT            SE_SELF_RELATIVE->Owner   : S-1-5-21-2025429265-1682526488-1801674531-1006->Group   : S-1-5-21-2025429265-1682526488-1801674531-513->Dacl    : ->Dacl    : ->AclRevision: 0x2->Dacl    : ->Sbz1       : 0x0->Dacl    : ->AclSize    : 0x1c->Dacl    : ->AceCount   : 0x1->Dacl    : ->Sbz2       : 0x0->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE->Dacl    : ->Ace[0]: ->AceFlags: 0x0->Dacl    : ->Ace[0]: ->AceSize: 0x14->Dacl    : ->Ace[0]: ->Mask : 0x001f0003->Dacl    : ->Ace[0]: ->SID: S-1-1-0->Sacl    :  is NULL

0 0
原创粉丝点击