首页
社区
课程
招聘
[分享]进程、线程遍历、线程激活拦截和简单文件保护
发表于: 2014-5-31 10:08 11495

[分享]进程、线程遍历、线程激活拦截和简单文件保护

2014-5-31 10:08
11495
好多天了,都在自己码字,百度,google 查的都烦了。不过为了学习忍了。
再次记上一篇笔记,这些代码很多前辈都写过,写的不好,大家请轻拍
今天笔记说的是,进程遍历 线程遍历,以及 特定模块线程拦截(不知道拦截对不对,我是这么理解的了)
文件保护感觉算不上,大家还是不要看了,本人新手,求轻拿轻放
第一部分:进程、线程遍历


/*********************************************枚举进程线程 通过Eprocess*****************************************/
//函数、结构体声明
typedef struct _SYSTEM_THREAD_INFORMATION {
  LARGE_INTEGER           KernelTime;
  LARGE_INTEGER           UserTime;
  LARGE_INTEGER           CreateTime;
  ULONG                   WaitTime;
  PVOID                   StartAddress;
  CLIENT_ID               ClientId;
  KPRIORITY               Priority;//优先级
  LONG                    BasePriority;
  ULONG                   ContextSwitchCount;
  ULONG                   State;
  KWAIT_REASON            WaitReason;
}SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;

typedef struct _SYSTEM_PROCESS_INFORMATION {
  ULONG                   NextEntryOffset;
  ULONG                   NumberOfThreads;
  LARGE_INTEGER           Reserved[3];
  LARGE_INTEGER           CreateTime;
  LARGE_INTEGER           UserTime;
  LARGE_INTEGER           KernelTime;
  UNICODE_STRING          ImageName;
  KPRIORITY               BasePriority;
  HANDLE                  ProcessId;
  HANDLE                  InheritedFromProcessId;
  ULONG                   HandleCount;
  ULONG                   Reserved2[2];
  ULONG                   PrivatePageCount;
  VM_COUNTERS             VirtualMemoryCounters;
  IO_COUNTERS             IoCounters;
  SYSTEM_THREAD_INFORMATION           Threads[0];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
#define  SystemProcessInformation 5 //5 号函数

extern "C" NTSYSAPI
  NTSTATUS
  NTAPI
  ZwQuerySystemInformation (
  __in ULONG SystemInformationClass,
  __out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
  __in ULONG SystemInformationLength,
  __out_opt PULONG ReturnLength
  );
#define  SystemModuleInformation 11 //11 号函数
typedef struct _SYSTEM_MODULE_INFORMATION {
  ULONG Reserved [2]; 
  PVOID Base; 
  ULONG Size; 
  ULONG Flags; 
  USHORT Index; 
  USHORT Unknown; 
  USHORT LoadCount; 
  USHORT ModuleNameOffset; 
  CHAR ImageName [256]; 
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; 

typedef struct { 
  ULONG  dwNumberOfModules; 
  SYSTEM_MODULE_INFORMATION  smi[1]; 
} MODULES, *PMODULES; 


char * GetTreadModuleNameByAddress(ULONG threadStartAddress)
{
  PMODULES moduleStruct;
  DWORD RealSize;
  NTSTATUS status;
  //先调用一次获取大小
  ULONG MaxAddress;
  ULONG MinAddress;
  char *ModuleName;
  status=ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&RealSize);
  if(status==STATUS_INFO_LENGTH_MISMATCH)
  {
    moduleStruct=(PMODULES)ExAllocatePool(NonPagedPool,RealSize);//申请同等大小的内存,存放
    status=ZwQuerySystemInformation(SystemModuleInformation,moduleStruct,RealSize,&RealSize);
    if(status==STATUS_SUCCESS)
    {
      //DbgPrint("Module Count: %d \r\n",moduleStruct->dwNumberOfModules);
      
      for (int i=0;i<moduleStruct->dwNumberOfModules;i++)
      {
        MinAddress = (ULONG) moduleStruct->smi[i].Base;
        MaxAddress =(ULONG) ((ULONG) moduleStruct->smi[i].Base + moduleStruct->smi[i].Size);
        ModuleName = moduleStruct->smi[i].ImageName ;
        //DbgPrint("Module Name: %s Base:%x \r\n",moduleStruct->smi[i].ImageName,moduleStruct->smi[i].Base);
        if(threadStartAddress>MinAddress && threadStartAddress <= MaxAddress)
        {
          goto _End;
        }
      }
    }
    _End:
    //释放内存
    ExFreePool(moduleStruct);
    moduleStruct=NULL;
  }
  return ModuleName;
}

//typedef struct _CLIENT_ID {
//  HANDLE UniqueProcess;
//  HANDLE UniqueThread;
//} CLIENT_ID;
//typedef CLIENT_ID *PCLIENT_ID;
//增加了模块显示
void EnumProcessListAndThreadByEPRPCESS()
{
  PSYSTEM_PROCESS_INFORMATION psysInfo;
  PVOID dataBuffer=NULL;
  DWORD DwSzie=0;
  NTSTATUS status;
  ANSI_STRING ProcesNameStr;
  UNICODE_STRING ProcessUnName;
  status = ZwQuerySystemInformation(SystemProcessInformation,NULL,0,&DwSzie);
  if(status==STATUS_INFO_LENGTH_MISMATCH)
  {
    dataBuffer=ExAllocatePool(NonPagedPool,DwSzie);
    status=ZwQuerySystemInformation(SystemProcessInformation,dataBuffer,DwSzie,&DwSzie);
    if (NT_SUCCESS(status))
    {
      psysInfo=(PSYSTEM_PROCESS_INFORMATION)dataBuffer;
      while(1)
      {
        RtlInitUnicodeString(&ProcessUnName,psysInfo->ImageName.Buffer);
        RtlUnicodeStringToAnsiString(&ProcesNameStr,&ProcessUnName,TRUE);
        DbgPrint("PID: %d ,ProcessName: %ws \r\n",psysInfo->ProcessId,psysInfo->ImageName.Buffer);
        if(strcmp(ProcesNameStr.Buffer,"System")==0)
        {
          DbgPrint("***************************线程信息Start*********************** \r\n");
          PEPROCESS CurrentProcess;
          PKPROCESS Kprocess;
          PETHREAD _thread;
          PKTHREAD kThread;
          LIST_ENTRY *LCink;
          LIST_ENTRY *LNink;
          CLIENT_ID *_CLIENT_ID;
          DWORD ThreadID=0;
          DWORD ThreadStartAddress;
          DWORD ThreadTeb;
          char *ModuleName;
          PsLookupProcessByProcessId(psysInfo->ProcessId,&CurrentProcess);
          if(CurrentProcess)
          {
            Kprocess=(PKPROCESS)CurrentProcess;
            LCink=(LIST_ENTRY *)((ULONG)Kprocess+0x50);
            LNink=LCink->Flink;
            while(LNink!=LCink)
            {
              _thread=(PETHREAD)((ULONG)LNink-0x1b0);
              kThread=(PKTHREAD)_thread;
                /*kd> dt _CLIENT_ID
                nt!_CLIENT_ID
                +0x000 UniqueProcess    : Ptr32 Void
                +0x004 UniqueThread     : Ptr32 Void*/
              //ThreadID=*(ULONG *)((*(ULONG *)((ULONG)_thread+0x1EC))+0x4);
              _CLIENT_ID=(PCLIENT_ID)((ULONG)_thread+0x1EC);
              ThreadID=(DWORD)(_CLIENT_ID->UniqueThread);
              ThreadStartAddress=*(ULONG *)((ULONG)_thread+0x224);
              ThreadTeb=*(ULONG *)((ULONG)kThread+0x20);
              ModuleName = GetTreadModuleNameByAddress(ThreadStartAddress);

              DbgPrint("线程ID:%d EPROCESS: %x TEB: %08x ,StartAddress:%08x  ModuleName : %s\r\n",ThreadID,_thread,ThreadTeb,ThreadStartAddress,ModuleName);
              LNink=LNink->Flink;
            }
          }
          DbgPrint("***************************线程信息End************************* \r\n");
        }
        //枚举系统进程的线程

        if(psysInfo->NextEntryOffset==0)
        {
          break;
        }
        psysInfo=(PSYSTEM_PROCESS_INFORMATION)((ULONG)psysInfo+psysInfo->NextEntryOffset);
      }
    }
  }

}

/*********************************************枚举进程线程 通过Eprocess*****************************************/


说明:进程遍历直接通过 ZwQuerySystemInformation 函数的第 5 号功能,来枚举。
ZwQuerySystemInformation 的更多功能,请参考wrk 。
线程遍历采用 PKPROCESS 和 PETHREAD 来遍历。
(我的理解 : PEPROCESS 头部 就是 PKPROCESS ,PETHREAD 头部就是PKTHREAD, wrk 中有定义。 )
PKPROCESS + 0x50 是 LIST_ENTRY 一个链表 ThreadListHead 指向的是  PKTHREAD + 0x1b0 的地方。
遍历时,获取到ThreadListHead  通过遍历链表得到每个线程的PKTHREAD  然后得到线程的具体信息。详细的看代码。
这里加上了 线程模块的显示,不过只是实现了系统进程中线程模块的显示。实现方式,通过线程的开始地址,去比较每个模块的BASE 和 BASE + SIZE 。如果在此区间,就说明线程在此模块中。
模块的遍历使用 ZwQuerySystemInformation 11号功能。

第二部分:HookKiReadyThread 遍历拦截线程

/**********************************Hook KiReadyThread 拦截 线程 激活 Start*******************************************/
ULONG KiReadyThreadHookAddr;
ULONG KiReadyThreadJmpAddr;
//dt _ETHREAD
//  nt!_ETHREAD
//  +0x000 Tcb              : _KTHREAD
//  +0x1c0 CreateTime       : _LARGE_INTEGER
//  +0x1c0 NestedFaultCount : Pos 0, 2 Bits
//  +0x1c0 ApcNeeded        : Pos 2, 1 Bit
//  +0x1c8 ExitTime         : _LARGE_INTEGER
//  +0x1c8 LpcReplyChain    : _LIST_ENTRY
//  +0x1c8 KeyedWaitChain   : _LIST_ENTRY
//  +0x1d0 ExitStatus       : Int4B
//  +0x1d0 OfsChain         : Ptr32 Void
//  +0x1d4 PostBlockList    : _LIST_ENTRY
//  +0x1dc TerminationPort  : Ptr32 _TERMINATION_PORT
//  +0x1dc ReaperLink       : Ptr32 _ETHREAD
//  +0x1dc KeyedWaitValue   : Ptr32 Void
//  +0x1e0 ActiveTimerListLock : Uint4B
//  +0x1e4 ActiveTimerListHead : _LIST_ENTRY
//  +0x1ec Cid              : _CLIENT_ID
//  +0x1f4 LpcReplySemaphore : _KSEMAPHORE
//  +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
//  +0x208 LpcReplyMessage  : Ptr32 Void
//  +0x208 LpcWaitingOnPort : Ptr32 Void
//  +0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
//  +0x210 IrpList          : _LIST_ENTRY
//  +0x218 TopLevelIrp      : Uint4B
//  +0x21c DeviceToVerify   : Ptr32 _DEVICE_OBJECT
//  +0x220 ThreadsProcess   : Ptr32 _EPROCESS
//  +0x224 StartAddress     : Ptr32 Void
//  +0x228 Win32StartAddress : Ptr32 Void
//  +0x228 LpcReceivedMessageId : Uint4B
//  +0x22c ThreadListEntry  : _LIST_ENTRY
ULONG TpModuleStartAddr=0;
ULONG TpModuleSize=0;
BYTE OldKiReadyData[5]={0};
BYTE JmpKiReadyData[5]={0xe9,0,0,0,0};

extern "C" BOOLEAN
  PsIsThreadTerminating(
  __in PETHREAD Thread
  );
//根据KeSetEventBoostPriority 获取 KiReadThread 地址,通过特征码搜索
//KeSetEventBoostPriority 是ntoskrnl导出的函数,KiReadThread未导出
ULONG GetKiReadyThreadAddr()
{
  UNICODE_STRING UncodeStr;
  RtlInitUnicodeString(&UncodeStr,L"KeSetEventBoostPriority");
  //1.先获取 KeSetEventBoostPriority
  ULONG KeSetEventBoostPriorityAddr=(ULONG)MmGetSystemRoutineAddress(&UncodeStr);
  DbgPrint("KeSetEventBoostPriority Address:%x",KeSetEventBoostPriorityAddr);
  //开始搜索特征码:
  PCHAR p=(char *)KeSetEventBoostPriorityAddr;
  //88566e          mov     byte ptr [esi+6Eh],dl
  //c6466d10        mov     byte ptr [esi+6Dh],10h
  //884e33          mov     byte ptr [esi+33h],cl
  //807e6f04        cmp     byte ptr [esi+6Fh],4
  ULONG KiReadyThreadAddr=0;
  for (int i=0;i<400;i++,p++)
  {
    //DbgPrint("字节:%x",(*p));
    if(*(p+1)==0x56 && 
      *(p+2)==0x6e &&
      *(p+4)==0x46 &&
      *(p+5)==0x6d &&
      *(p+6)==0x10 &&
      *(p+8)==0x4e &&
      *(p+9)==0x33 &&
      *(p+11)==0x7e &&
      *(p+12)==0x6f &&
      *(p+13)==0x04)
    {
      ULONG AbuAddr=(ULONG)(p+34);
      KiReadyThreadAddr=AbuAddr+(*((WORD *)(p+35)))+5;//获取的是相对函数的相对偏移(计算hook 是一样的道理)
      DbgPrint("KiReadyThread Addr: %x",KiReadyThreadAddr);
      break;
    }
  }
  return KiReadyThreadAddr;
}


//过滤函数s
int _stdcall IsPassThread(IN PKTHREAD Thread)
{
  PETHREAD Ethread;
  ULONG StartAddressThread=0;
  ULONG StartOffset=0x224;
  if(!MmIsAddressValid(Thread))
  {
    return 0;
  }
  if(PsIsThreadTerminating((PETHREAD)Thread))
  {
    return 0;
  }
  Ethread=(PETHREAD)Thread;
  if(!MmIsAddressValid((PULONG)((ULONG)Ethread+StartOffset)))
  {
    return 0;
  }
  StartAddressThread=*((ULONG *)((ULONG)Ethread+StartOffset));
  if(TpModuleStartAddr>0 && TpModuleSize>0 )
  {
    if(StartAddressThread>TpModuleStartAddr && StartAddressThread<=TpModuleStartAddr+TpModuleSize )
    {
      DbgPrint("TesSafe.sys 线程:开始地址-> %x\r\n",StartAddressThread);
    }
  }
  return 0;
}
__declspec (naked) MyHookKiReadyThreadFun()
{
  __asm
  {
    mov   edi,edi
      push  ebp
    mov   ebp,esp
    pushad
    pushfd
    push ecx
    call IsPassThread
    cmp eax,0 //如果不是0就跳,说明是拦截的函数
    jnz _PassThread
    popfd
    popad
    jmp KiReadyThreadJmpAddr
_PassThread:
    popfd
    popad
    ret 
  }
}
VOID
  NotifyRoutineTp(
  IN PUNICODE_STRING FullImageName,
  IN HANDLE ProcessId,                // pid into which image is being mapped
  IN PIMAGE_INFO ImageInfo
  )
{
  if(strEnd(FullImageName->Buffer,L"TesSafe.sys"))
  {
    DbgPrint("TesSafe.sys-> BASE : %x \r\n",ImageInfo->ImageBase);
    TpModuleStartAddr=(ULONG)(ImageInfo->ImageBase);
    TpModuleSize=(ULONG)(ImageInfo->ImageSize);
  }
}
NTSTATUS HookKiReadyThread()
{
  KiReadyThreadHookAddr=GetKiReadyThreadAddr();
  if(KiReadyThreadHookAddr)
  {
    //1.先加载系统回调
    PsSetLoadImageNotifyRoutine(NotifyRoutineTp);
    RtlCopyMemory(OldKiReadyData,(VOID *)KiReadyThreadHookAddr,5);
    KiReadyThreadJmpAddr=KiReadyThreadHookAddr+5;
    *(ULONG *)(&JmpKiReadyData[1])=(ULONG)MyHookKiReadyThreadFun-KiReadyThreadHookAddr-5;
    POFF();
    RtlCopyMemory((VOID *)KiReadyThreadHookAddr,JmpKiReadyData,5);
    PON();
    DbgPrint("KiReadyThread Hook 成功!\r\n");
  }else
  {
    DbgPrint("KiReadyThread Hook 失败!\r\n");
  }
  return STATUS_SUCCESS;
}

NTSTATUS UnHookKiReadyThread()
{
  PsRemoveLoadImageNotifyRoutine(NotifyRoutineTp);
  POFF();
  RtlCopyMemory((VOID *)KiReadyThreadHookAddr,OldKiReadyData,5);
  PON();
  DbgPrint("KiReadyThread UnHook 成功!\r\n");
  return STATUS_SUCCESS;
}

/**********************************Hook KiReadyThread 拦截 线程 激活 End*******************************************/


说明: 本次实验用的 T某P 当作例子。
先加载一个 系统回调 NotifyRoutineTp 监视一下 sys 的加载。
发现加载了,立刻HOOK KiReadyThread 拦截 线程的激活。
HOOK KiReadyThread:因为KiReadyThread  是未导出的,我的方法是在wrk 中搜索次函数,查看是否在某个导出函数调用了KiReadyThread ,然后通过特征码搜索的方式获取 KiReadyThread  函数首地址,本次使用的是KeSetEventBoostPriority 导出函数。
导出函数获取首地址的方法 MmGetSystemRoutineAddress
搜索的特征码:
//88566e          mov     byte ptr [esi+6Eh],dl
//c6466d10        mov     byte ptr [esi+6Dh],10h
//884e33          mov     byte ptr [esi+33h],cl
//807e6f04        cmp     byte ptr [esi+6Fh],4
不清楚的话,可以在windbg中看一下。
HOOK 和处理的细节看代码。 

第三部分:Hook IoCreateFile 保护文件不被打开

/*************************************文件保护Hook IoCreateFile Start********************************************/

ULONG FunaddrIoCreateFile=0;
ULONG JmpAddrIoCreateFile=0;

BYTE OldDataIoCreateFile[5]={0};
BYTE JmpDataIoCreateFile[5]={0xE9,0,0,0,0};

typedef NTSTATUS 
  (__stdcall *NewIoCreateFile)(
  OUT PHANDLE FileHandle,
  IN ACCESS_MASK DesiredAccess,
  IN POBJECT_ATTRIBUTES ObjectAttributes,
  OUT PIO_STATUS_BLOCK IoStatusBlock,
  IN PLARGE_INTEGER AllocationSize OPTIONAL,
  IN ULONG FileAttributes,
  IN ULONG ShareAccess,
  IN ULONG Disposition,
  IN ULONG CreateOptions,
  IN PVOID EaBuffer OPTIONAL,
  IN ULONG EaLength,
  IN CREATE_FILE_TYPE CreateFileType,
  IN PVOID ExtraCreateParameters OPTIONAL,
  IN ULONG Options
  );

NewIoCreateFile _NewIoCreateFile;

__declspec (naked) void IoCreateFileHookFun(...)
{
  __asm
  {
    mov     edi,edi
    push    ebp
    mov     ebp,esp
    jmp JmpAddrIoCreateFile;
  }
}

ULONG strEnd(PWCHAR dest,PWCHAR sub)
{
  if (dest == NULL && sub == NULL)
    return 0;
  int ulDest = wcslen(dest);
  int ulSub = wcslen(sub);

  if (ulSub == 0 || ulSub > ulDest)
    return 0;
  return !wcscmp(&dest[ulDest - ulSub],sub);
}

NTSTATUS MyIoCreateFile(
  OUT PHANDLE FileHandle,
  IN ACCESS_MASK DesiredAccess,
  IN POBJECT_ATTRIBUTES ObjectAttributes,
  OUT PIO_STATUS_BLOCK IoStatusBlock,
  IN PLARGE_INTEGER AllocationSize OPTIONAL,
  IN ULONG FileAttributes,
  IN ULONG ShareAccess,
  IN ULONG Disposition,
  IN ULONG CreateOptions,
  IN PVOID EaBuffer OPTIONAL,
  IN ULONG EaLength,
  IN CREATE_FILE_TYPE CreateFileType,
  IN PVOID ExtraCreateParameters OPTIONAL,
  IN ULONG Options
  )
{
  NTSTATUS status;
  ANSI_STRING      FullNameAnsi;
  _NewIoCreateFile=(NewIoCreateFile)IoCreateFileHookFun;
  status=_NewIoCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,Disposition,CreateOptions,EaBuffer,EaLength,CreateFileType,ExtraCreateParameters,Options);
  if(MmIsAddressValid(ObjectAttributes))
  {
    if(MmIsAddressValid(ObjectAttributes->ObjectName) && ObjectAttributes->ObjectName->Buffer!=NULL)
    {
      RtlUnicodeStringToAnsiString(&FullNameAnsi,ObjectAttributes->ObjectName,TRUE);
      if(strstr(FullNameAnsi.Buffer,"myx123123.txt"))
      {
        DbgPrint("OpenFileName:%Z",&FullNameAnsi);
        *(DWORD *)FileHandle=-1;
        return STATUS_ACCESS_DENIED;
      }
      //DbgPrint("OpenFileName:%ws",ObjectAttributes->ObjectName->Buffer);
    }
  }
  return status;
}

NTSTATUS HookIoCreateFile()
{
  //获取函数地址
  UNICODE_STRING FunName;
  RtlInitUnicodeString(&FunName,L"IoCreateFile");
  FunaddrIoCreateFile=(ULONG)MmGetSystemRoutineAddress(&FunName);
  if(FunaddrIoCreateFile)
  {
    DbgPrint("IoCreateFile 函数地址:%x ",FunaddrIoCreateFile);
    RtlCopyMemory(OldDataIoCreateFile,(PVOID)FunaddrIoCreateFile,5);
    JmpAddrIoCreateFile=FunaddrIoCreateFile+5;
    *((ULONG *)(&JmpDataIoCreateFile[1]))=(ULONG)MyIoCreateFile-FunaddrIoCreateFile-5;
    POFF();
    RtlCopyMemory((PVOID)FunaddrIoCreateFile,JmpDataIoCreateFile,5);
    PON();
  }else
  {
    DbgPrint("IoCreateFile 函数获取失败!");
    return 0;
  }
  return 1;

}

NTSTATUS UnHookIoCreateFile()
{
  POFF();
  RtlCopyMemory((PVOID)FunaddrIoCreateFile,OldDataIoCreateFile,5);
  PON();
  return 1;
}

/*************************************文件保护Hook IoCreateFile End********************************************/

说明:这个就比较简单了,直接过滤一下 要操作的文件名就好了。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 2
支持
分享
最新回复 (8)
雪    币: 2861
活跃值: (3879)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
简单文件保护
2014-5-31 10:10
0
雪    币: 255
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
好文章,沙发支持
2014-5-31 10:10
0
雪    币: 459
活跃值: (398)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
4
怎么也感觉不对 这一部分可以忽略不看
2014-5-31 10:14
0
雪    币: 44
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
内容有点多,,要是分批发,一点点发就看起来比较舒服
2014-5-31 17:08
0
雪    币: 44
活跃值: (186)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
果断顶楼主一下。。。LZ可不可以交个朋友交流交流下心德呀
2014-5-31 22:39
0
雪    币: 459
活跃值: (398)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
7
乐于交朋友~~
2014-5-31 22:46
0
雪    币: 1305
活跃值: (228)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
8
lz,又见lz分享笔记了,能交个朋友吗?
2014-6-1 00:25
0
雪    币: 44
活跃值: (186)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
lz好像发了个邮件给我都没有收到啊,
2014-6-1 12:49
0
游客
登录 | 注册 方可回帖
返回
//