shakesky
驱动牛犊
驱动牛犊
  • 注册日期2006-03-16
  • 最后登录2011-06-25
  • 粉丝0
  • 关注0
  • 积分581分
  • 威望69点
  • 贡献值0点
  • 好评度58点
  • 原创分0分
  • 专家分0分
阅读:2249回复:8

请tooflat版主进来看看

楼主#
更多 发布于:2007-07-09 17:48
我参考了你的流加密代码sfilter,写了如下东西,结果运行蓝屏,请指教
NTSTATUS
SfCreate (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This function filters create/open operations.  It simply establishes an
    I/O completion routine to be invoked if the operation was successful.

Arguments:

    DeviceObject - Pointer to the target device object of the create/open.

    Irp - Pointer to the I/O Request Packet that represents the operation.

Return Value:

    The function value is the status of the call to the file system's entry
    point.

--*/

{
    NTSTATUS status;
    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
    PFILE_OBJECT FileObject = IrpSp->FileObject;
    PAGED_CODE();

    //
    //  If this is for our control device object, don't allow it to be opened.
    //

    if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {

        //
        //  Sfilter doesn't allow for any communication through its control
        //  device object, therefore it fails all requests to open a handle
        //  to its control device object.
        //
        //  See the FileSpy sample for an example of how to allow creates to 
        //  the filter's control device object and manage communication via
        //  that handle.
        //

        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
        Irp->IoStatus.Information = 0;

        IoCompleteRequest( Irp, IO_NO_INCREMENT );

        return STATUS_INVALID_DEVICE_REQUEST;
    }

    ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));

    //
    //  If debugging is enabled, do the processing required to see the packet
    //  upon its completion.  Otherwise, let the request go with no further
    //  processing.
    //

    if (!FlagOn( SfDebug, SFDEBUG_DO_CREATE_COMPLETION |
                          SFDEBUG_GET_CREATE_NAMES|
                          SFDEBUG_DISPLAY_CREATE_NAMES )) {

        //
        //  Don't put us on the stack then call the next driver
        //

        IoSkipCurrentIrpStackLocation( Irp );

        return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );

    } else {
    
        KEVENT waitEvent;

        //
        //  Initialize an event to wait for the completion routine to occur
        //

        KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );

        //
        //  Copy the stack and set our Completion routine
        //

        IoCopyCurrentIrpStackLocationToNext( Irp );

        IoSetCompletionRoutine(
            Irp,
            SfCreateCompletion,
            &waitEvent,
            TRUE,
            TRUE,
            TRUE );

        //
        //  Call the next driver in the stack.
        //

        status = IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );

        //
        //  Wait for the completion routine to be called
        //

        if (STATUS_PENDING == status) {

            NTSTATUS localStatus = KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, NULL);
            ASSERT(STATUS_SUCCESS == localStatus);
        }

        //
        //  Verify the IoCompleteRequest was called
        //

        ASSERT(KeReadStateEvent(&waitEvent) ||
               !NT_SUCCESS(Irp->IoStatus.Status));

        //
        //  Retrieve and display the filename if requested
        //

        if (FlagOn(SfDebug,
                   (SFDEBUG_GET_CREATE_NAMES|SFDEBUG_DISPLAY_CREATE_NAMES))) {

            SfDisplayCreateFileName( Irp );
        }

        //
        //  Save the status and continue processing the IRP
        //

        status = Irp->IoStatus.Status;

        IoCompleteRequest( Irp, IO_NO_INCREMENT );
        {
            POST_CREATE_WORKER_CONTEXT WorkerCtx;
            PFILE_CONTEXT FileCtxPtr = NULL;
            FileCtxPtr = ExAllocatePoolWithTag( NonPagedPool, 
                                                   sizeof( FILE_CONTEXT ),
                                                   SFLT_POOL_TAG );

            if(FileCtxPtr==NULL)
                return status;
            
            FileCtxPtr->RefCount = 1;

            KeInitializeEvent(&FileCtxPtr->Event, SynchronizationEvent, TRUE);

            ExInitializeWorkItem(&WorkerCtx.WorkItem, SfIsEncryptFlagExist, &WorkerCtx);
            WorkerCtx.DeviceObject = DeviceObject;
            WorkerCtx.FileObject = FileObject;
            KeInitializeEvent(&WorkerCtx.Event, NotificationEvent, FALSE);
            WorkerCtx.FileContext = FileCtxPtr;
            //WorkerCtx.NewElement = NewElement;
                
            if (KeGetCurrentIrql() == PASSIVE_LEVEL)
                SfIsEncryptFlagExist(&WorkerCtx);
            else
            {
                ExQueueWorkItem(&WorkerCtx.WorkItem, DelayedWorkQueue);
                KeWaitForSingleObject(&WorkerCtx.Event, Executive, KernelMode, FALSE, NULL);
            }
            ExFreePool(FileCtxPtr);
        }
        return status;
    }
}

NTSTATUS
SfIsEncryptFlagExist(IN PVOID Context)
{
    PPOST_CREATE_WORKER_CONTEXT WorkerCtx = Context;
    NTSTATUS Status;
    IO_STATUS_BLOCK  IoStatus={0};
    UCHAR Buff[512]={0};
    //PACKAGERINFO packagerinfo;    //包信息
    int nPackagerLen;
    WCHAR EncryptFlagFile[MAX_PATH*2] = {L'\0'};
    LARGE_INTEGER ByteOffset;
    PFILE_CONTEXT FileCtxPtr = WorkerCtx->FileContext;
    
    KeWaitForSingleObject(&FileCtxPtr->Event, Executive, KernelMode, FALSE, NULL);

    wcscpy(EncryptFlagFile,L"\\??\\");
    //wcscat(EncryptFlagFile,WorkerCtx->FileContext->Name);
    //if(wcscmp(WorkerCtx->FileContext->Name,L"c:\\test\\test.txt")==0)
    {
        nPackagerLen=0;
    }
    //if(wcscmp(WorkerCtx->FileContext->Name,L"C:\\test\\test.txt")==0)
    {
        nPackagerLen=0;
    }

    ByteOffset.QuadPart=0;
    IoStatus.Status = STATUS_SUCCESS;
    IoStatus.Information = 0;
    Status =SfIssueReadWriteIrpSynchronously(WorkerCtx->DeviceObject
        ,WorkerCtx->FileObject,IRP_MJ_READ,&IoStatus,Buff,
        sizeof(Buff),&ByteOffset,0);
    if (!NT_SUCCESS(Status))
    {
        if (STATUS_END_OF_FILE == Status)
        {
            WorkerCtx->FileContext->EncryptFlagExist=FALSE;
            Status = STATUS_SUCCESS;
        }
        KeSetEvent(&FileCtxPtr->Event, IO_NO_INCREMENT, FALSE);
        KeSetEvent(&WorkerCtx->Event, IO_NO_INCREMENT, FALSE);
        
        return Status;
    }
//    memcpy(&packagerinfo,Buff,sizeof(PACKAGERINFO));
//    if(memcmp(packagerinfo.btflags,"ftsafe",6)==0)
//    {
//        WorkerCtx->FileContext->EncryptFlagExist=TRUE;
//        memcpy(WorkerCtx->FileContext->Key,"123456",6);//解密密钥
//        WorkerCtx->FileContext->Key[6]=0;
//    }
//    else
//        WorkerCtx->FileContext->EncryptFlagExist=FALSE;

    KeSetEvent(&FileCtxPtr->Event, IO_NO_INCREMENT, FALSE);
    KeSetEvent(&WorkerCtx->Event, IO_NO_INCREMENT, FALSE);
    return Status;
    
}

NTSTATUS
SfIssueReadWriteIrpSynchronously(
    IN PDEVICE_OBJECT DeviceObject,
    IN PFILE_OBJECT FileObject,
    IN ULONG MajorFunction,
    IN PIO_STATUS_BLOCK IoStatus,
    IN PVOID Buffer,
    IN ULONG Length,
    IN PLARGE_INTEGER ByteOffset,
    IN ULONG IrpFlags
    )
{
    PIRP Irp = NULL;
    PIO_STACK_LOCATION IrpSp = NULL;
    KEVENT Event;
    NTSTATUS Status;

    ASSERT((MajorFunction == IRP_MJ_READ) || (MajorFunction == IRP_MJ_WRITE));
    
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    Irp = IoBuildSynchronousFsdRequest(
        MajorFunction,
        DeviceObject,
        Buffer,
        Length,
        ByteOffset,
        &Event,
        IoStatus
        );
    if (!Irp)
        return STATUS_INSUFFICIENT_RESOURCES;

    Irp->Flags |= IrpFlags;

    IrpSp = IoGetNextIrpStackLocation(Irp);
    IrpSp->FileObject = FileObject;

    Status = IoCallDriver(DeviceObject, Irp);
    if (STATUS_PENDING == Status)
    {
        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
    }

    return IoStatus->Status;
}
蓝屏信息如下:BugCheck 7E, {c0000005, 804f9810, f9e7aad8, f9e7a7d8}

ANALYSIS: Kernel with unknown size. Will force reload symbols with known size.
ANALYSIS: Force reload command: .reload /f ntoskrnl.exe=FFFFFFFF804D5000,1F2700,3D6DE35C
***** Kernel symbols are WRONG. Please fix symbols to do analysis.

Probably caused by : ntoskrnl.exe ( nt!ExFreeToPagedLookasideList+9d )

Followup: MachineOwner
---------

nt!DbgBreakPointWithStatus+0x4:
805113fa cc              int     3
kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
This is a very common bugcheck.  Usually the exception address pinpoints
the driver/function that caused the problem.  Always note this address
as well as the link date of the driver/image that contains this address.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 804f9810, The address that the exception occurred at
Arg3: f9e7aad8, Exception Record Address
Arg4: f9e7a7d8, Context Record Address

Debugging Details:
------------------

***** Kernel symbols are WRONG. Please fix symbols to do analysis.


MODULE_NAME: nt

FAULTING_MODULE: 804d5000 nt

DEBUG_FLR_IMAGE_TIMESTAMP:  3d6de35c

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - "0x%08lx"

FAULTING_IP:
nt!ExFreeToPagedLookasideList+9d
804f9810 8b4024          mov     eax,dword ptr [eax+24h]

EXCEPTION_RECORD:  f9e7aad8 -- (.exr 0xfffffffff9e7aad8)
ExceptionAddress: 804f9810 (nt!ExFreeToPagedLookasideList+0x0000009d)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 00000124
Attempt to read from address 00000124

CONTEXT:  f9e7a7d8 -- (.cxr 0xfffffffff9e7a7d8)
eax=00000100 ebx=806ca190 ecx=00000000 edx=00000000 esi=f7bb0c20 edi=806ca158
eip=804f9810 esp=f9e7aba0 ebp=f9e7acf0 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010246
nt!ExFreeToPagedLookasideList+0x9d:
804f9810 8b4024          mov     eax,dword ptr [eax+24h] ds:0023:00000124=????????
Resetting default scope

DEFAULT_BUCKET_ID:  WRONG_SYMBOLS

BUGCHECK_STR:  0x7E

LAST_CONTROL_TRANSFER:  from 80581d00 to 804f9810

STACK_TEXT:  
WARNING: Stack unwind information not available. Following frames may be wrong.
f9e7acf0 80581d00 f7bb0c20 00000000 00000000 nt!ExFreeToPagedLookasideList+0x9d
f9e7ad34 804ef99d 81bbc298 8054fda0 81bbeda8 nt!FsRtlAcquireFileExclusive+0xd
f9e7ad74 804ee629 81bbc298 00000000 81bbeda8 nt!KeReadStateEvent+0xa5
f9e7adac 8057d73a 81bbc298 00000000 00000000 nt!KeInsertQueue+0xfc
f9e7addc 805134c1 804ee556 00000000 00000000 nt!CcUnpinDataForThread+0x66d
00000000 00000000 00000000 00000000 00000000 nt!KeProfileInterruptWithSource+0x28e


FOLLOWUP_IP:
nt!ExFreeToPagedLookasideList+9d
804f9810 8b4024          mov     eax,dword ptr [eax+24h]

SYMBOL_STACK_INDEX:  0

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  ntoskrnl.exe

SYMBOL_NAME:  nt!ExFreeToPagedLookasideList+9d

STACK_COMMAND:  .cxr 0xfffffffff9e7a7d8 ; kb

BUCKET_ID:  WRONG_SYMBOLS

Followup: MachineOwner
---------
这啥原因呀,难道下发自己的IRP有问题,屏蔽下发IRP后就没问题了。。。
shakesky
驱动牛犊
驱动牛犊
  • 注册日期2006-03-16
  • 最后登录2011-06-25
  • 粉丝0
  • 关注0
  • 积分581分
  • 威望69点
  • 贡献值0点
  • 好评度58点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-07-10 09:43
自己顶一个
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-07-10 13:18
你是在IoCompleteRequest( Irp, IO_NO_INCREMENT );
后进行处理的,这时候可能这个FileObject已经不存在了,这是问题一。

另外如果这个FileObject是从栈上分配,用缓冲IO去读文件,会导致cache mgr对这个文件进行缓冲处理。当这个FileObject从栈上释放掉,cache mgr再操作备份的FileObject时,就会蓝屏,这是问题二。
shakesky
驱动牛犊
驱动牛犊
  • 注册日期2006-03-16
  • 最后登录2011-06-25
  • 粉丝0
  • 关注0
  • 积分581分
  • 威望69点
  • 贡献值0点
  • 好评度58点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-07-10 13:44
感谢tooflat回答,但我看你的代码也是在完成例程后对file_object对象进行操作的,下面代码为你的
Status = SfForwardIrpSyncronously(DevExt->AttachedToDeviceObject, Irp);//这里完成例程
        if (NT_SUCCESS(Status) && (STATUS_REPARSE != Status))
        {
            FILE_CONTEXT FileCtx;
            PFILE_CONTEXT FileCtxPtr = NULL;
            BOOLEAN NewElement = FALSE;

            FileCtx.FsContext = FileObject->FsContext;

            ExAcquireFastMutex(&DevExt->FsCtxTableMutex);

            FileCtxPtr = RtlLookupElementGenericTable(&DevExt->FsCtxTable, &FileCtx);
            if (FileCtxPtr)
                ++FileCtxPtr->RefCount;
            else
            {
                FileCtxPtr = RtlInsertElementGenericTable(
                    &DevExt->FsCtxTable,
                    &FileCtx,
                    sizeof(FILE_CONTEXT),
                    &NewElement
                    );

                FileCtxPtr->RefCount = 1;

                ASSERT(FileName);
                wcscpy(FileCtxPtr->Name, FileName);

                KeInitializeEvent(&FileCtxPtr->Event, SynchronizationEvent, TRUE);
            }

            ExReleaseFastMutex(&DevExt->FsCtxTableMutex);

            ExInitializeWorkItem(&WorkerCtx.WorkItem, SfPostCreateWorker, &WorkerCtx);
            WorkerCtx.DeviceObject = DeviceObject;
            WorkerCtx.FileObject = FileObject;
            KeInitializeEvent(&WorkerCtx.Event, NotificationEvent, FALSE);
            WorkerCtx.FileContext = FileCtxPtr;
            WorkerCtx.NewElement = NewElement;
                
            if (KeGetCurrentIrql() == PASSIVE_LEVEL)
                SfPostCreateWorker(&WorkerCtx);
            else
            {
                ExQueueWorkItem(&WorkerCtx.WorkItem, DelayedWorkQueue);
                KeWaitForSingleObject(&WorkerCtx.Event, Executive, KernelMode, FALSE, NULL);
            }
我的与你的好像没有区别呀!
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2007-07-10 14:56
看看IoCompleteRequest是在什么调用的
shakesky
驱动牛犊
驱动牛犊
  • 注册日期2006-03-16
  • 最后登录2011-06-25
  • 粉丝0
  • 关注0
  • 积分581分
  • 威望69点
  • 贡献值0点
  • 好评度58点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2007-07-10 16:38
我改了还是不行
NTSTATUS
SfCreate (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This function filters create/open operations.  It simply establishes an
    I/O completion routine to be invoked if the operation was successful.

Arguments:

    DeviceObject - Pointer to the target device object of the create/open.

    Irp - Pointer to the I/O Request Packet that represents the operation.

Return Value:

    The function value is the status of the call to the file system's entry
    point.

--*/

{
    NTSTATUS status;
    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
    PFILE_OBJECT FileObject = IrpSp->FileObject;
    PAGED_CODE();

    //
    //  If this is for our control device object, don't allow it to be opened.
    //

    if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) {

        //
        //  Sfilter doesn't allow for any communication through its control
        //  device object, therefore it fails all requests to open a handle
        //  to its control device object.
        //
        //  See the FileSpy sample for an example of how to allow creates to 
        //  the filter's control device object and manage communication via
        //  that handle.
        //

        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
        Irp->IoStatus.Information = 0;

        IoCompleteRequest( Irp, IO_NO_INCREMENT );

        return STATUS_INVALID_DEVICE_REQUEST;
    }

    ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));

    //
    //  If debugging is enabled, do the processing required to see the packet
    //  upon its completion.  Otherwise, let the request go with no further
    //  processing.
    //

    if (!FlagOn( SfDebug, SFDEBUG_DO_CREATE_COMPLETION |
                          SFDEBUG_GET_CREATE_NAMES|
                          SFDEBUG_DISPLAY_CREATE_NAMES )) {

        //
        //  Don't put us on the stack then call the next driver
        //

        IoSkipCurrentIrpStackLocation( Irp );

        return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );

    } else {
    
        KEVENT waitEvent;

        //
        //  Initialize an event to wait for the completion routine to occur
        //

        KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );

        //
        //  Copy the stack and set our Completion routine
        //

        IoCopyCurrentIrpStackLocationToNext( Irp );

        IoSetCompletionRoutine(
            Irp,
            SfCreateCompletion,
            &waitEvent,
            TRUE,
            TRUE,
            TRUE );

        //
        //  Call the next driver in the stack.
        //

        status = IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp );

        //
        //  Wait for the completion routine to be called
        //

        if (STATUS_PENDING == status) {

            NTSTATUS localStatus = KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, NULL);
            ASSERT(STATUS_SUCCESS == localStatus);
        }

        //
        //  Verify the IoCompleteRequest was called
        //

        ASSERT(KeReadStateEvent(&waitEvent) ||
               !NT_SUCCESS(Irp->IoStatus.Status));

        //
        //  Retrieve and display the filename if requested
        //

        if (FlagOn(SfDebug,
                   (SFDEBUG_GET_CREATE_NAMES|SFDEBUG_DISPLAY_CREATE_NAMES))) {

            SfDisplayCreateFileName( Irp );
        }

        //
        //  Save the status and continue processing the IRP
        //

     
        ///*****添加by lrf
        do{
            POST_CREATE_WORKER_CONTEXT WorkerCtx;
            PFILE_CONTEXT FileCtxPtr = NULL;
            if (IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE)
            {
                    //
                    // We don't care about directories
                    //
                    //ExFreeToPagedLookasideList(&gFileNameLookAsideList, FileName);
                
                break;
            }

            FileCtxPtr = ExAllocatePoolWithTag( NonPagedPool, 
                                                   sizeof( FILE_CONTEXT ),
                                                   SFLT_POOL_TAG );

            if(FileCtxPtr==NULL)
                break;
            
            FileCtxPtr->RefCount = 1;

            KeInitializeEvent(&FileCtxPtr->Event, SynchronizationEvent, TRUE);

            ExInitializeWorkItem(&WorkerCtx.WorkItem, SfIsEncryptFlagExist, &WorkerCtx);
            WorkerCtx.DeviceObject = DeviceObject;
            WorkerCtx.FileObject = FileObject;
            KeInitializeEvent(&WorkerCtx.Event, NotificationEvent, FALSE);
            WorkerCtx.FileContext = FileCtxPtr;
            //WorkerCtx.NewElement = NewElement;
                
            if (KeGetCurrentIrql() == PASSIVE_LEVEL)
                SfIsEncryptFlagExist(&WorkerCtx);
            else
            {
                ExQueueWorkItem(&WorkerCtx.WorkItem, DelayedWorkQueue);
                KeWaitForSingleObject(&WorkerCtx.Event, Executive, KernelMode, FALSE, NULL);
            }
            ExFreePool(FileCtxPtr);
        }while (FALSE);

        status = Irp->IoStatus.Status;
        IoCompleteRequest( Irp, IO_NO_INCREMENT );
        return status;
    }
}
tooflat大侠,帮忙呀
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2007-07-10 17:09
不清楚什么原因,有可能就是我上面说的问题二,改成用内存映射方式读试试。
另外你的调试符号有问题。
shakesky
驱动牛犊
驱动牛犊
  • 注册日期2006-03-16
  • 最后登录2011-06-25
  • 粉丝0
  • 关注0
  • 积分581分
  • 威望69点
  • 贡献值0点
  • 好评度58点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2007-07-10 22:32
内存映射方式?如何实现亚,还请tooflat再度出手指点
shakesky
驱动牛犊
驱动牛犊
  • 注册日期2006-03-16
  • 最后登录2011-06-25
  • 粉丝0
  • 关注0
  • 积分581分
  • 威望69点
  • 贡献值0点
  • 好评度58点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2007-07-12 09:44
期待
游客

返回顶部