首页
社区
课程
招聘
[求助]IAT 的位置可以改变不?
发表于: 2012-8-13 17:55 5658

[求助]IAT 的位置可以改变不?

2012-8-13 17:55
5658
正常程序

0040102A  |.  6A 40                 push    40                               ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
0040102C  |.  68 2C204200           push    0042202C                         ; |Title = "Test"
00401031  |.  68 1C204200           push    0042201C                         ; |Text = "Hello World"
00401036  |.  6A 00                 push    0                                ; |hOwner = NULL
00401038  |.  FF15 ACA24200         call    dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA

这个就是 MessageBoxA 内存地址
0042A2AC >EA 07 D5 77 00 00 00 00 00 00 00 00 00 00 00 00  ?誻............

修改后的程序

将 输入表 中的 FirstThunk 偏移了 0x10h 的位置
载入OD         内存地址已经出来 说明改的 输入表 数据没有错误
0042A2AC  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0042A2BC >EA 07 D5 77 00 00 00 00 00 00 00 00 00 00 00 00  ?誻............
0042A2CC  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

// 这里的数据 依然指向 42A2AC的位置
0040102A  |.  6A 40                 push    40
0040102C  |.  68 2C204200           push    0042202C                         ;  ASCII "Test"
00401031  |.  68 1C204200           push    0042201C                         ;  ASCII "Hello World"
00401036  |.  6A 00                 push    0
00401038  |.  FF15 ACA24200         call    dword ptr [42A2AC]

IAT位置可以修改不.. 还需要操作哪些?

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 223
活跃值: (516)
能力值: ( LV13,RANK:520 )
在线值:
发帖
回帖
粉丝
2
iat 可以移动,

但是很复杂.

给你提供两个思路.
1. 利用反汇编引擎找出所有数据.修改.
2. 把iat清空, 利用veh一个个捕获.把所有异常的地址,纪录下来,做成一个表,就像relocation那样.
然后再修改表格中地址指向的数据, 即 "IAT"

不知道对你有没有帮助.
2012-8-13 19:05
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
可以,只要不违反原则,不占据有效数据地址的话,神马空白地方都可以
2012-8-13 19:27
0
雪    币: 7115
活跃值: (639)
能力值: (RANK:1290 )
在线值:
发帖
回帖
粉丝
4
很简单的。 遍历代码节把所有引用找出来 然后记录。 修改以后在重新自己填充一遍就OK。 貌似我OPEN SOURCE过
2012-8-14 13:43
0
雪    币: 7115
活跃值: (639)
能力值: (RANK:1290 )
在线值:
发帖
回帖
粉丝
5
貌似以前没在论坛上发过。    以下是加解密函数。 很简单遍历代码节把引用都找出来判断是否是IAT的范围内 是就抽出来记录。 解密时重新构造表填充。 再把原先的位置指定到新的位置  收功。
/*
 * 介绍:
 *    力量解密引入表
 * 
 * 参数:
 *    pMem:要保护函数的映射
 *    addrOrigImageBase:要保护函数原先的基地址
 *    pImportProtect:引入表保护结构指针
 *    bOnFile:是否是文件
 *    ofJmpTableRva:新的引入跳转表的RVA
 */
PREFERENCE_IMPORT_TABLE_ADDRESS __API__ PowerEncryptImportTable(__memory pMem, __address addrOrigImageBase, PIMPORT_PROTECT pImportProtect, __bool bOnFile, __offset ofJmpTableRva) {
    __byte bXor = 0;
    __memory pCodeStart = NULL;
    __integer iCodeSize = 0;
    __integer iProcCount = 0, iLibCount = 0, iIndex = 0;
    __address addrImageBase = 0;
    __address addrCurrOrigImageBase = 0;
    __address OrigJmpAddressTable[__MAX_JMP_ADDRESS_TABLE_COUNT__] = {0};
    __bool JmpAddressTableMakeSure[__MAX_JMP_ADDRESS_TABLE_COUNT__] = {0};//用于确认当前位置是否被占用
    JMPTABLE_TO_ADDRESS JmpTableToAddressList[__MAX_JMP_ADDRESS_TABLE_COUNT__] = {0};
    __integer iJmpAddressTableCount = 0;
    __dword *pJmpAddressTableRva = NULL;
    __address addrNowAddress = 0;
    PIMAGE_NT_HEADERS pNtHdr = NULL;
    PIMAGE_DATA_DIRECTORY pImageImportDataDirectory = NULL;
    PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor = NULL;
    ud_t ud_obj = {0};
    PREFERENCE_IMPORT_TABLE_ADDRESS pReferenceImportTableAddres = NULL;
    PREFERENCE_IMPORT_TABLE_ADDRESS *pCurrReferenceImportTableAddresPoint = &pReferenceImportTableAddres;

    // 初始化数据
    pImageImportDataDirectory = ExistDataDirectory(pMem, IMAGE_DIRECTORY_ENTRY_IMPORT);
    if (!pImageImportDataDirectory)
        return NULL;

    /*
     * 获取目标映射的基地址
     * 要修复的基地址可以通过函数的参数addrOrigImageBase指定,如果addrOrigImageBase == 0xFFFFFFFF则使用
     * addrImageBase,如果addrOrigImageBase != 0xFFFFFFFF,则使用addrOrigImageBase
     */
    pNtHdr = GetNtHeader(pMem);
    addrImageBase = pImportProtect->addrImageBase;

    // 获取目标文件代码段的地址与长度
    if (bOnFile) {
        //addrImageBase = (__address)(pNtHdr->OptionalHeader.ImageBase);
        pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(pMem + Rva2Raw(pMem, pImageImportDataDirectory->VirtualAddress));
        pCodeStart = pMem + GetEntryPointSection(pMem)->PointerToRawData;
    } else {
        //addrImageBase = (__address)pMem;
        pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)__RvaToVa__(pMem, pImageImportDataDirectory->VirtualAddress);
        pCodeStart = pMem + GetEntryPointSection(pMem)->VirtualAddress;
    }
    iCodeSize = GetEntryPointSection(pMem)->Misc.VirtualSize;
    __logic_memset__(JmpAddressTableMakeSure, FALSE, __MAX_JMP_ADDRESS_TABLE_COUNT__);

    // 设置IMAGE_PROTECT
    bXor = (__byte)GenerateRandomNumber();//随机生成出一个KEY
    pImportProtect->bXor = bXor;

    // 将引入表信息存入IMPORT_PROTECT结构
    // 有些程序只适用FirstThunk
    while (pImageImportDescriptor->FirstThunk) {
        __address addrCurrAddress = 0;
        __dword dwCurrRva = 0;
        __char *svDllName = NULL;
        PIMAGE_THUNK_DATA pTdIn = NULL;
        PIMAGE_THUNK_DATA pTdOut = NULL;
        if (bOnFile)
            svDllName = (__char *)(pMem + Rva2Raw(pMem, pImageImportDescriptor->Name));
        else
            svDllName = (__char *)__RvaToVa__(pMem, pImageImportDescriptor->Name);

        EncryptIATCallBack(iLibCount, LIB_NAME, (__memory)svDllName, __logic_strlen__(svDllName), FALSE, 0, (__void *)pImportProtect);

        // 填充引入表地址
        if (bOnFile) {
            pTdIn = (PIMAGE_THUNK_DATA)(pMem + Rva2Raw(pMem, pImageImportDescriptor->OriginalFirstThunk));
            pTdOut = (PIMAGE_THUNK_DATA)(pMem + Rva2Raw(pMem, pImageImportDescriptor->FirstThunk));
            // 没有OriginalFirstThunk的情况
            if ((__memory)pTdIn == pMem)
                pTdIn = pTdOut;
        } else {
            pTdIn = (PIMAGE_THUNK_DATA)__RvaToVa__(pMem, pImageImportDescriptor->OriginalFirstThunk);
            pTdOut = (PIMAGE_THUNK_DATA)__RvaToVa__(pMem, pImageImportDescriptor->FirstThunk);
            // 没有OriginalFirstThunk的情况
            if ((__memory)pTdIn == pMem)
                pTdIn = pTdOut;
        }
        
        iProcCount = 0;
        if (addrOrigImageBase == __USE_DEF_IMAGEBASE_AS_ORIG__)
            addrCurrOrigImageBase = addrImageBase;
        else
            addrCurrOrigImageBase = addrOrigImageBase;
        addrCurrAddress = __RvaToVa__(addrCurrOrigImageBase, pImageImportDescriptor->FirstThunk);

        // 加密函数
        while (pTdIn->u1.Function) {
            // 随机取出一个要放入的位置
            __integer iOffsetTableIndex = RandJmpAddress(&JmpAddressTableMakeSure);

            // 获取新的FirstThunk
            __dword dwNewFirstThunk = (__dword)(ofJmpTableRva + iOffsetTableIndex * sizeof(__address));
            OrigJmpAddressTable[iJmpAddressTableCount] = addrCurrAddress;
            JmpTableToAddressList[iJmpAddressTableCount].addrAddress = addrCurrAddress;
            // 合成新的引入地址表偏移
            JmpTableToAddressList[iJmpAddressTableCount].dwNewRva = dwNewFirstThunk;
            iJmpAddressTableCount++;//跳入表计数

            // 以序号引出还是以函数名引出
            if (pTdIn->u1.Ordinal & IMAGE_ORDINAL_FLAG32) {
                __word wOrd = pTdIn->u1.Ordinal;
                EncryptIATCallBack(iIndex, PROC_NAME, (__memory)&wOrd, 2, TRUE, dwNewFirstThunk, (__void *)pImportProtect);
            } else {
                __char *szProcName = NULL;
                PIMAGE_IMPORT_BY_NAME pIbn = NULL;
                if (bOnFile)
                    pIbn = (PIMAGE_IMPORT_BY_NAME)(pMem + Rva2Raw(pMem, pTdIn->u1.AddressOfData));
                else
                    pIbn = (PIMAGE_IMPORT_BY_NAME)__RvaToVa__(pMem, pTdIn->u1.AddressOfData);
                szProcName = (__char *)(pIbn->Name);
                EncryptIATCallBack(iIndex, PROC_NAME, (__memory)szProcName, __logic_strlen__(szProcName), FALSE, dwNewFirstThunk, (__void *)pImportProtect);
            }
            // 下一个函数
            addrCurrAddress += sizeof(__address);
            iProcCount++;//函数计数增加
            iIndex++;//索引计数增加
            pTdIn++;
            pTdOut++;
        }/* end while */
        
        // 在下一个DLL之前,记录当前库所有的API数量
        pImportProtect->iApiNumberInThisLibrary[iLibCount] = iProcCount;
        // 下一个DLL
        pImageImportDescriptor++;
        iLibCount++;
    }/* end while */

    pJmpAddressTableRva = &(pImportProtect->dwFirstThunkList);

    // 验证
    if (iIndex != pImportProtect->iApiNameCrc32Count)
        return NULL;

    // 进行随机混淆
    ud_init(&ud_obj);
    ud_set_input_buffer(&ud_obj, pCodeStart, iCodeSize);//默认一个函数的最大长度为4096
    ud_set_mode(&ud_obj, 32);
    ud_set_syntax(&ud_obj, UD_SYN_INTEL);
    while (ud_disassemble(&ud_obj)) {
        __memory pFileSaveAddress = NULL;
        struct ud_operand *pCurrOperand = NULL;
        /*
         * 找到拥有内存访问能力的指令,如果指令访问的内存地址在表中的话,则将其改写为新的内存
         * 地址
         */
        if (ud_obj.operand[0].type != UD_NONE) {
            // 如果拥有操作数
            __integer iOperandCount = 0;

            ///*
            // * 这里仅处理MOV,CALL,JMP 三条指令
            // * 因为不同编译只有这三条指令会对引入表造成访问
            // */
            //if (ud_obj.mnemonic == UD_Imov) {
            //    if ((ud_obj.operand[1].type == UD_OP_MEM) && (ud_obj.operand[1].base == UD_NONE) && \
            //        (ud_obj.operand[1].index == UD_NONE) && (ud_obj.operand[1].size == 32)) {
            //            pCurrOperand = &(ud_obj.operand[1]);
            //            pFileSaveAddress = (__memory)(ud_obj.inp_buff) - sizeof(__dword);
            //    }
            //} else if ((ud_obj.mnemonic == UD_Icall) || (ud_obj.mnemonic == UD_Ijmp)) {
            //    if ((ud_obj.operand[0].type == UD_OP_MEM) && (ud_obj.operand[0].base == UD_NONE) && \
            //        (ud_obj.operand[0].index == UD_NONE) && (ud_obj.operand[0].offset) && (ud_obj.operand[0].size == 32)) {
            //            pCurrOperand = &(ud_obj.operand[0]);
            //            pFileSaveAddress = (__memory)(ud_obj.inp_buff) - sizeof(__dword);
            //    }
            //}

            //////////////////////////////////////////////////////////////////////////
            // 2012.2.10 修改为 所有指令只要有内存访问
            // 形如:xxx dword ptr [address]
            //      xxx dword ptr [address], reg
            //      xxx reg, dword ptr [address]
            if ((ud_obj.operand[0].type == UD_OP_MEM) && (ud_obj.operand[0].base == UD_NONE) && \
                (ud_obj.operand[0].index == UD_NONE) && (ud_obj.operand[0].offset) && (ud_obj.operand[0].size == 32)) {
                    pCurrOperand = &(ud_obj.operand[0]);
                    pFileSaveAddress = (__memory)(ud_obj.inp_buff) - sizeof(__dword);
            }
            else if ((ud_obj.operand[1].type == UD_OP_MEM) && (ud_obj.operand[1].base == UD_NONE) && \
                (ud_obj.operand[1].index == UD_NONE) && (ud_obj.operand[1].size == 32)) {
                    pCurrOperand = &(ud_obj.operand[1]);
                    pFileSaveAddress = (__memory)(ud_obj.inp_buff) - sizeof(__dword);
            }

            if (pFileSaveAddress) {
                __memory pCurrInstFileAddress = ud_obj.inp_buff - ud_obj.inp_ctr;
                /*
                 * 如果是内存访问操作
                 * 取出地址与跳转地址表中进行检索
                 */
                __address addrTargetAddress = (__address)(pCurrOperand->lval.sdword);
                __dword dwNowRva = GetNewRvaFromJmpAddressTable(addrTargetAddress, &JmpTableToAddressList, iJmpAddressTableCount);
                if (dwNowRva != __NOT_IN_JMPADDRESSTABLE__) {
                    addrNowAddress = addrImageBase + dwNowRva;
                    *(__address *)pFileSaveAddress = addrNowAddress;//重新设置

                    // 设置一个引入表引用结构
                    (*pCurrReferenceImportTableAddresPoint) = (PREFERENCE_IMPORT_TABLE_ADDRESS)__logic_new__(REFERENCE_IMPORT_TABLE_ADDRESS, 1);
                    if (bOnFile) {
                        (*pCurrReferenceImportTableAddresPoint)->ofReferenceRVA = Raw2Rva(pMem, (__integer)(pFileSaveAddress - pMem));
                        (*pCurrReferenceImportTableAddresPoint)->addrReferenceMemAddress = addrImageBase + Raw2Rva(pMem, (__integer)(pCurrInstFileAddress - pMem));
                    } else {
                        (*pCurrReferenceImportTableAddresPoint)->ofReferenceRVA = (__integer)(pFileSaveAddress - pMem);
                        (*pCurrReferenceImportTableAddresPoint)->addrReferenceMemAddress = addrImageBase + (__integer)(pCurrInstFileAddress - pMem);
                    }
                    (*pCurrReferenceImportTableAddresPoint)->pReferenceFileAddress = pCurrInstFileAddress;
                    __logic_memcpy__(&((*pCurrReferenceImportTableAddresPoint)->ud_obj), &ud_obj, sizeof(ud_t));

                    // 增加引用引入表内存指令RVA,如果大于最大的计数则加密引入表失败直接退出
                    if (pImportProtect->iImportTableReferenceAddressCount >= __MAX_IMPORT_REFERENCE_COUNT__) {
                        // 释放已经分配的内存
                        ReleaseReferenceImportTableAddress(&pReferenceImportTableAddres);
                        return NULL;
                    }/* end if */
                    pImportProtect->ofImportTableReferenceAddressRVA[pImportProtect->iImportTableReferenceAddressCount] = (*pCurrReferenceImportTableAddresPoint)->ofReferenceRVA;
                    pImportProtect->ofAPINowRVA[pImportProtect->iImportTableReferenceAddressCount] = dwNowRva;
                    (pImportProtect->iImportTableReferenceAddressCount)++;

                    // 移动到下一个
                    pCurrReferenceImportTableAddresPoint = &((*pCurrReferenceImportTableAddresPoint)->pNext);
                }
            }/* end if */
        }/* end if */
    }

    pImportProtect->ofJmpTableRva = ofJmpTableRva;//设置新跳转表的RVA
    // 销毁原先的引入表
    if (bOnFile)
        DeleteDataDirectoryObject(pMem, IMAGE_DIRECTORY_ENTRY_IMPORT);
    else
        DeleteDataDirectoryObjectOnMemMap(pMem, IMAGE_DIRECTORY_ENTRY_IMPORT);

    return pReferenceImportTableAddres;
}

/*
 * 介绍:
 *    解密引入地址表,此函数在目标文件中调用,用于修复
 *
 * 参数:
 *    pArg:力量解密引入表参数结构
 */
__bool __API__ PowerDecryptImportTable(PPOWERDECRYPTIMPORTTABLE_ARG pArg) {
    PIMPORT_PROTECT pImportProtect = NULL;
    FPAddThunkCodeStub pAddThunkCodeStub = NULL;
    __byte bXor = 0;
    HMODULE hDll = NULL, hCurrDll = NULL;
    __integer i = 0, j = 0, iIndex = 0;
    __integer iLength = 0;
    __char *pLibName = NULL;
    __char LibName[64] = {0};
    __dword dwLibNameCrc32 = 0;
    __bool bDllIsProtect = FALSE;

    __PrintDbgInfo_OutputDbgString__("Entry PowerDecryptImportTable");

    // 初始化数据
    pImportProtect = pArg->pImportProtect;
    pAddThunkCodeStub = pArg->pAddThunkCodeStub;
    bXor = pImportProtect->bXor;//获取密钥的解密密码

    for (i = 0; i < pImportProtect->iLibraryKeyCount; i++) {
        __dword dwKey = 0;
        __memory pKey = NULL;

        dwKey = pImportProtect->dwLibraryKeyList[i];//解密密钥
        pKey = (__memory)&dwKey;

        XorKey4Bytes(pKey, bXor);
        iLength = pImportProtect->iLibraryNameLengthList[i];
        __logic_memset__(LibName, 0, 64);
        pLibName = pImportProtect->LibraryNameList[i];
        XorArray(dwKey, (__memory)pLibName, (__memory)LibName, iLength);//解密

        // 获取库名的CRC32值
        dwLibNameCrc32 = crc32((__memory)LibName, iLength);

        // 加载并重映射DLL
        hCurrDll = g_pLoadLibraryA(LibName);

        // 如果是在保护内的库则重新映射
        if (ThisValueIsInList(dwLibNameCrc32, pImportProtect->dwProtectDllCrc32List, pImportProtect->iProtectDllCrc32Count)) {
            // 查看是否是排除在执行DllMain的库
            if (ThisValueIsInList(dwLibNameCrc32, pImportProtect->dwProtectDllCallDllMainCrc32List, pImportProtect->iProtectDllCallDllMainCrc32Count))
                hDll = (HMODULE)RemapDll((__memory)hCurrDll, g_pVirtualAlloc, TRUE);
            else
                hDll = (HMODULE)RemapDll((__memory)hCurrDll, g_pVirtualAlloc, FALSE);

            // 设置此DLL经过保护
            bDllIsProtect = TRUE;
        } else {
            hDll = (HMODULE)hCurrDll;

            // 设置此DLL未经过保护
            bDllIsProtect = FALSE;
        }

        // 获取API地址
        for (j = 0; j < pImportProtect->iApiNumberInThisLibrary[i]; j++) {
            __memory pHashData = NULL;
            __address addrImageBase = 0;
            __dword dwFirstThunk = 0;
            __address *paddrOut = NULL;

            pHashData = (__memory)&(pImportProtect->dwApiNameCrc32List[iIndex]);
            addrImageBase = pImportProtect->addrImageBase;
            dwFirstThunk = pImportProtect->dwFirstThunkList[iIndex];
            paddrOut = (__address *)(addrImageBase + (__address)dwFirstThunk);

            if (pImportProtect->bIsOrdList[iIndex]) {
                __dword dwOrd = pImportProtect->dwApiNameCrc32List[iIndex] & 0xFFFF;//取低2字节
                __PrintDbgInfo_OutputDbgString__("Already goto xGetProcAddressByHash by API ord");
                *paddrOut = (__address)xGetProcAddressByHash(hDll, (__memory)dwOrd, 2, DecrypterHashFunc);
            } else {
                __PrintDbgInfo_OutputDbgString__("Already goto xGetProcAddressByHash by API name hash value");
                *paddrOut = (__address)xGetProcAddressByHash(hDll, pHashData, sizeof(__address), DecrypterHashFunc);
            }

            // 在需要抽取的API列表中找寻
            __PrintDbgInfo_OutputDbgString__("Already goto ThisApiIsInProtectList");
            if (ThisValueIsInList(pImportProtect->dwApiNameCrc32List[iIndex], &(pImportProtect->dwProtectApiCrc32List), pImportProtect->iProtectApiCrc32Count)) {
                __memory pNowAddress = NULL;
                __memory pNewAddress = NULL;
                __offset ofOffset = 0;
                //__integer iProcSize = 0;

                pNowAddress = (__memory)(*paddrOut);

                // 计算这个函数的长度
                //iProcSize = SimpleCalcThisProcedureLength(pNowAddress);

                if (pAddThunkCodeStub) {
                    pNewAddress = pAddThunkCodeStub((__address)pNowAddress);
                    if (!pNewAddress) goto _default_add_thunk_code_stub;//如果为空则直接转入默认处理
                } else {
                    _default_add_thunk_code_stub:
                    // 产生一个中间函数
                    pNewAddress = __logic_new_size__(0x10);
                    // 计算偏移
                    ofOffset = CalcCurrOffsetFromAddress(32, (__address)pNowAddress, (__address)pNewAddress, 5);
                    *(__byte *)pNewAddress = 0xE9;
                    *(__offset *)(pNewAddress + 1) = ofOffset;
                }

                // 重新设定地址
                *paddrOut = (__address)pNewAddress;
            }

            // 增加索引计数
            iIndex++;
        }/* end for */

        // 如果在保护范围内则清除这个DLL的无用信息
        if (bDllIsProtect) {
            __PrintDbgInfo_OutputDbgString__("Already goto ClearRemapDllUnSafeInfo");
            ClearRemapDllUnSafeInfo(hDll);
        }/* end if */
    }

    // 检验
    if (iIndex != pImportProtect->iApiNameCrc32Count)
        return FALSE;

    // 这里开启一个非常重要就是修订目标代码节要引用的
    __PrintDbgInfo_OutputDbgString__("Fix target code reference API memory address");
    {
        __integer i = 0;
        __memory pMem = NULL;
        
        pMem = (__memory)(pImportProtect->addrImageBase);

        for (i = 0; i < pImportProtect->iImportTableReferenceAddressCount; i++) {
            __address *pReference = NULL;
            __address addrNowAddress = 0;

            // 获得引用的地址
            pReference = (__address *)(pMem + pImportProtect->ofImportTableReferenceAddressRVA[i]);
            addrNowAddress = (__address)(pMem + pImportProtect->ofAPINowRVA[i]);

            // 设置
            *pReference = addrNowAddress;
        }/* end for */
    }

    __PrintDbgInfo_OutputDbgString__("Exit PowerDecryptImportTable");
    return TRUE;
}
2012-8-14 14:18
0
雪    币: 125
活跃值: (161)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
LS碉堡了。。。
2012-8-15 09:40
0
雪    币: 81
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
Mark~ 看下版主思路~
2012-8-15 09:49
0
游客
登录 | 注册 方可回帖
返回
//