反調試與破反調試筆記


 靜態反調試

反調試技術知識點

TEB 線程環境塊

TEB 是個結構體

 

TEB結構中的兩個重要成員

+0x000             NtTib :_NT_TIB . . .

+0x30                ProcessEnvironmentBlock :Ptr32_PEB

 

TEB 的Offet30移位處就是PEB的結構體指針

 

PEB 進程環境塊,每個進程都對應一個PEB結構體

 

 

NtTib   線程信息塊

結構體信息如下:

typedef struct _NT_TIB{

          struct     _EXCEPTION_REGISTRATION_RECORD *ExceptionList;

          PVOID StackBase;

          PVOID StackLimit;

          PVOID SubSystemTib;

          union {

                  PVOID FiberData;

                  DWORD Version;

          };

          PVOID ArbitraryUserPointer;

         struct     _NT_TIB *Self;

} NT_TIB;

typedef NT_TIB *PNT_TIB;

 

ExceptionList成員指向_EXCEPTION_REGISTRATION_RECORD結構體組成的鏈表,它用於WindowsOS的SEH, SEH是Wiondows操作系統中的結構化異常處理機制,常用於反調試技術。

Self成員是_NT_TIB結構體的自引用指針,它指向_NT_TIB結構體,又因為_NT_TIB是TEB結構體的第一個成員,所以它也是指向TEB結構體的指針(它里面存着TEB結構體的地址)。

 

使用Ntdll.NtCurrentTeb()API訪問TEB結構體,它返回當前線程的的TEB結構體的地址,通過OD看它的實現方法就是返回FS:[0x18]處的地址值(FS段寄存器用來指示當前線程的TEB結構體),而FS:0x18處正是Self指針,其含有的也正是TEB結構體的地址。

用一個公式總結:

FS:[0x18] = TEB.NtTib.Self = address of TIB = address of TEB = FS:0

 

 

 

所以:

FS:[0x18] = TEB起始地址

FS:[0x30] = PEB的起始地址

FS:[0] = TEB.NtTib.ExceptionList = address of SEH

 

就算不理解反正記住就行了。

 

PEB 進程環境塊

PEB中重要的幾個成員

 

+002         BeingDebugged               ;Uchar(可用於反調試技術)

...

+008         ImageBaseAddress           ;Ptr32 Void

...

+00c          Ldr                    ;Ptr32 _PEB_LDR_DATA(可用於反調試技術)

...

+018         ProcessHeap  ;Ptr32 Void(可用於反調試技術)

...

+068         NtGlobalFlag   ;uint4B(可用於反調試技術)

 

PEB.BeingDebugged

BeingDebugged的作用就是標識當前進程是否處於調試狀態,Kernel32.dll中的IsDebuggerPresent() API就是用來獲取該處的值的(是,則返回1;否,則返回0)

 

IsDebuggerPresent() API的匯編代碼形式

MOV EAX,DWORD PTR FS:[18]

MOV EAX,DWORD PTR DS:[EAX+30]

MOVZX EAX,BYTE PTR DS:[EAX+2]

RETN

 

該值在代碼逆向分析領域主要用於反調試技術。檢測該值,若進程處於調試中,則終止進程。

 

破解之法
只要借助OllyDbg調試器的編輯功能,將PEB.BeingDebugged的值修改為0(FALSE)即可。

 

PEB.ImageBaseAddress成員用來表示進程的ImageBase
GetModuleHandle()API用來獲取ImageBase。

將lpModuleName參數賦值為NULL,調用GetModuleHandle()函數將返回進程被加載的ImageBase

 

GetModuleHandle() API的部分代碼

MOV         EAX,DWORD PTR FS:[18]         ;FS:[18] = TEB

MOV         EAX,DWORD PTR DS:[EAX+30]     ;DS:[EAX+30] = PEB

MOV         EAX,DWORD PTR DS:[EAX+8]      ;DS:[EAX+8] = PEB.ImageBaseAddress

 

PEB.Ldr

PEB.Ldr成員是指向_PEB_LDR_DATA結構體的指針,_PEB_LDR_DATA結構體如下。

 

+000 Length                         :Uint4B

+004 Initialized                             :UChar

+008 SsHandle                       :Ptr32 Void

+00c InLoadOrderModulelist          :_LIST_ENTRY

+014 InMemoryOrderModulelist        :_LIST_ENTRY

+01c InInitializationOrderModulelist:               _LIST_ENTRY

+024 EntryInProgress                :Ptr32 Void

+028 ShutdownInProgress             :UChar

+02c ShutdownThreadId               :Ptr32 Void

 

當模塊(DLL)加載到進程后,通過PEB.Ldr成員可以直接獲得該模塊的加載基址,_PEB_LDR_DATA結構體中含有3個_LIST_ENTRY類型的成員,_LIST_ENTRY結構體如下。

 

typedef struct LIST_ENTRY{

        struct _LIST_ENTRY *Flink;

        struct _LIST_ENTRY *Bink;

}LIST_ENTRY,*PLIST_ENTRY;

 

 

從上述結構體可以看出,_LIST_ENTRY結構體提供雙向鏈表機制。鏈表中保存的是_LDR_DATA_TABLE_ENTRY結構體的信息,給結構體如下。

 

typedef struct _LDR_DATA_TABLE_ENTRY {

         PVOID Reserved1[2];

         LIST_ENTRY InMemoryOrderLinks;

         PVOID Reserved2[2];

         PVOID D1lBase;

         PVOID EntryPoint;

         PVOID Reserved3;

         Unicode_STRING Ful1D1lName;

         BYTE Reserved4[8];

         PVOID Reserved5[3];

         union{

                  ULONG CheckSum;

                  PVOID Reserved6;

         };

         ULONG TimeDateStamp;

}LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;

 

每個加載到進程中的DLL模塊都對應一個_LDR_DATA_TABLE_ENTRY結構體,這些結構體相互鏈接,最終形成了_LIST_ENTRY雙向鏈表。_PEB_LDR_DATA結構體中存在3種_LIST_ENTRY雙向鏈表,也就是說,存在多個_LDR_DATA_TABLE_ENTRY結構體,並且有三種鏈接方法可以將它們鏈接起來。

 

PEB.ProcessHeap & PEB.NtGolbalFlag

PEB.ProcessHeap與PEB.NtGlobalFlag成員(像PEB.BeingDebugged成員一樣)應用於反調試技術。若進程處於調試狀態,則ProcessHeap與NtGlobalFlag成員就持有特定值。由於它們具有這一個特征,所以常常應用於反調試技術。

 

PEB.ProcessHeap成員是指向HEAP結構體的指針,HEAP結構體如下。

+0x000 Entry   :_HEAP_ENTRY

+0x008 Signature     :Uint4B

+0x00c Flags    :Uint4B

+0x010 ForceFlags   :Uint4B

+0x014 VirtualMemoryThreshold :Uint4B

+0x018 SegmentReserve :Uint4B

+0x01c SegmentCommit :Uint4B

+0x020 DeCommitFreeBlockThreshold   :Uint4B

 

 

進程處於被調試狀態時,Flags(+0xC)與Force Flags(+ox10)成員被設置成特定的值。

PEB.ProcessHeap(PEB結構體中偏移0x18的位置)成員既可以從PEB結構體中直接獲得,也可以通過GetProcessHeap() API獲得。

GetProcessHeap() API代碼的匯編形式基本類似於IsDebuggerPresent(),按照TEB→PEB→PEB.ProcessHeap順序訪問的ProcessHeap

 

 

破解之法

只要將HEAP.Flags與HEAP.ForceFlags的值重新設置為2與0即可(HEAP.Flags=2,HEAP.ForceFlags=0)。

注意:該方法僅在WindowsXP系統中有效,Windows7系統不存在以上特征。此外,將運行中的進程附加到調試器時,也不會出現上述特征。

 

 

靜態反調試技術總結:

1.通過PEB.BeingDebugged 標識當前進程是否處於調試狀態

破解之法
只要借助OllyDbg調試器的編輯功能,將PEB.BeingDebugged的值修改為0(FALSE)即可。

 

2. Ldr(+0xC)

當調試時,在堆內存區會出現一些特殊的標識,標識他正在被調試,比如未使用 的內存全部填充為0XEEFEEEFE

PEB.Ldr 是指向的_PEB_LDR_DATA結構的指針,而_PEB_LDR_DATA 正好是在堆內存區域創建的,所以掃描該內存區可找到是否存在0XEEFEEEFE

 

破解之法

把填充的0XEEFEEEFE改成NULL即可

 

 

3. PEB.ProcessHeap

+0x000 Entry   :_HEAP_ENTRY

+0x008 Signature     :Uint4B

+0x00c Flags    :Uint4B

+0x010 ForceFlags   :Uint4B

+0x014 VirtualMemoryThreshold :Uint4B

+0x018 SegmentReserve :Uint4B

+0x01c SegmentCommit :Uint4B

+0x020 DeCommitFreeBlockThreshold   :Uint4B

調試時,Flags(+0xC) 與+0x010 ForceFlags 被設定成特定值

 

可以通過GetProcessHeap() API獲得ProcessHeap

進程正常運行,Flags=0x2,ForceFlags =0x0,被調試的時候就會改變

 

破解之法

把通過OD把他們的值改回正常的值即可

 

 

4.PEB.NtGolbalFlag

被調試時,NtGolbalFlag的成員會被設置成0x70,檢測該值就可以

破解之法

把他設置成0即可

 

 

5.NtQueryInformationProcess 

 

 

// NtQueryInformationProcess 函數原型

__kernel_entry NTSTATUS NtQueryInformationProcess(

  IN HANDLE           ProcessHandle,                               // 進程句柄

  IN PROCESSINFOCLASS ProcessInformationClass,                 // 檢索的進程信息類型

  OUT PVOID           ProcessInformation,                      // 接收進程信息的緩沖區指針

  IN ULONG            ProcessInformationLength,                   // 緩沖區指針大小

  OUT PULONG          ReturnLength                                         // 實際接收的進程信息大小

);

 

用法:為NtQueryInformationProcess  函數的第二個參數ProcessInformationClass 指定特定值並調用,相關信息就會設置到第三個參數ProcessInformation內

 

// PROCESSINFOCLASS 結構體原型

typedef enum _PROCESSINFOCLASS

{

    ProcessBasicInformation,                                           // 0x0

    ProcessQuotaLimits,

    ProcessIoCounters,

    ProcessVmCounters,

    ProcessTimes,

    ProcessBasePriority,

    ProcessRaisePriority,

    ProcessDebugPort,                                                        // 0x7

    ProcessExceptionPort,

    ProcessAccessToken,

    ProcessLdtInformation,

    ProcessLdtSize,

    ProcessDefaultHardErrorMode,

    ProcessIoPortHandlers,

    ProcessPooledUsageAndLimits,

    ProcessWorkingSetWatch,

    ProcessUserModeIOPL,

    ProcessEnableAlignmentFaultFixup,

    ProcessPriorityClass,

    ProcessWx86Information,

    ProcessHandleCount,

    ProcessAffinityMask,

    ProcessPriorityBoost,

    ProcessDeviceMap,

    ProcessSessionInformation,

    ProcessForegroundInformation,

    ProcessWow64Information,                                     // 0x1A

    ProcessImageFileName,                                                       // 0x1B

    ProcessLUIDDeviceMapsEnabled,

    ProcessBreakOnTermination,

    ProcessDebugObjectHandle,                                       // 0x1E

    ProcessDebugFlags,                                                              // 0x1F

    ProcessHandleTracing,

    ProcessIoPriority,

    ProcessExecuteFlags,

    ProcessResourceManagement,

    ProcessCookie,

    ProcessImageInformation,

    ProcessCycleTime,

    ProcessPagePriority,

    ProcessInstrumentationCallback,

    ProcessThreadStackAllocation,

    ProcessWorkingSetWatchEx,

    ProcessImageFileNameWin32,

    ProcessImageFileMapping,

    ProcessAffinityUpdateMode,

    ProcessMemoryAllocationMode,

    ProcessGroupInformation,

    ProcessTokenVirtualizationEnabled,

    ProcessConsoleHostProcess,

    ProcessWindowInformation,

    ProcessHandleInformation,

    ProcessMitigationPolicy,

    ProcessDynamicFunctionTableInformation,

    ProcessHandleCheckingMode,

    ProcessKeepAliveCount,

    ProcessRevokeFileHandles,

    ProcessWorkingSetControl,

    ProcessHandleTable,

    ProcessCheckStackExtentsMode,

    ProcessCommandLineInformation,

    ProcessProtectionInformation,

    ProcessMemoryExhaustion,

    ProcessFaultInformation,

    ProcessTelemetryIdInformation,

    ProcessCommitReleaseInformation,

    ProcessDefaultCpuSetsInformation,

    ProcessAllowedCpuSetsInformation,

    ProcessSubsystemProcess,

    ProcessJobMemoryInformation,

    ProcessInPrivate,

    ProcessRaiseUMExceptionOnInvalidHandleClose,

    ProcessIumChallengeResponse,

    ProcessChildProcessInformation,

    ProcessHighGraphicsPriorityInformation,

    ProcessSubsystemInformation,

    ProcessEnergyValues,

    ProcessActivityThrottleState,

    ProcessActivityThrottlePolicy,

    ProcessWin32kSyscallFilterInformation,

    ProcessDisableSystemAllowedCpuSets,

    ProcessWakeInformation,

    ProcessEnergyTrackingState,

    ProcessManageWritesToExecutableMemory,REDSTONE3

    ProcessCaptureTrustletLiveDump,

    ProcessTelemetryCoverage,

    ProcessEnclaveInformation,

    ProcessEnableReadWriteVmLogging,

    ProcessUptimeInformation,

    ProcessImageSection,

    ProcessDebugAuthInformation,

    ProcessSystemResourceManagement,

    ProcessSequenceNumber,

    ProcessLoaderDetour,

    ProcessSecurityDomainInformation,

    ProcessCombineSecurityDomainsInformation,

    ProcessEnableLogging,

    ProcessLeapSecondInformation,

    ProcessFiberShadowStackAllocation,

    ProcessFreeFiberShadowStackAllocation,

    MaxProcessInfoClass

} PROCESSINFOCLASS;

 

跟調試探測有關的的為:

ProcessDebugPort,                                                        // 0x7

ProcessDebugObjectHandle,                                       // 0x1E

ProcessDebugFlags,                                                              // 0x1F

 

 

ProcessDebugPort

進程在調試的時候的系統會為他分配調試端口,當PROCESSINFOCLASS的 ProcessDebugPort 的值為7,調用NtQueryInformationProcess 就可以獲取調試端口,如果沒有調試則返回為0

 

 

ProcessDebugObjectHandle

調試的時候會生成調試對象,當PROCESSINFOCLASS的ProcessDebugObjectHandle

 為0x1E時,第三個參數就可以獲取到調試對象句柄,否則該句柄為NULL

 

ProcessDebugFlags

當 ProcessDebugFlags為0x1F 時,第三個參數返回為0為被調試狀態,正常運行為1

 

 

破解之法

Hook NtQueryInformationProcess 函數修改返回值

 

基於環境檢測反調試
NtQuerySystemInformation

基於調試環境的反調試技術. NTQuerySystemInformation()API是一個系統函數, 可以獲取OS信息.

 

 

 

第一個參數SystemInformationClass傳入SystemKernelDebuggerInformation, 參數中指定需要系統信息類型,返回的時候會把結構體地址放在第二個參數里

 

當第一個參數傳入 0x23 (SystemInterruptInformation) 時,會返回一個 SYSTEM_KERNEL_DEBUGGER_INFORMATION 結構,里面的成員KdKdDebuggerEnable=1 和 KdDebuggerNotPresent 標志系統是否啟用內核調試。

 

破解之法

命令行執行 “bcdedit/debug off” 若重啟系統要用正常模式啟動

Xp下  系統中編輯boot.ini 文件。刪除 /debugport=com1 /baudrate=115200 /Debug  的值

 

 

 

NtQueryObject

除了識別進程是否被調試之外,其他的調試器檢測技術牽涉到檢查系統當中是否有調試器正在運行。逆向論壇中討論的一個有趣的方法就是檢查DebugObject類型內核對象的數量。這種方法之所以有效是因為每當一個應用程序被調試的時候,將會為調試對話在內核中創建一

個DebugObject類型的對象。

 

DebugObject的數量可以通過ntdll!NtQueryObject()檢索所有對象類型的信息而獲得。NtQueryObject接受5個參數,為了查詢所有的對象類型,ObjectHandle參數被設為NULL,ObjectInformationClass參數設為ObjectAllTypeInformation(3):

 

NTSTATUS NTAPI NtQueryObject(                                                                

IN    HANDLE                                         ObjectHandle,                              

IN    OBJECT_INFORMATION_CLASS   ObjectInformationClass,           

OUT   PVOID                                           ObjectInformation,                     

IN    ULONG                                           Length                                            ,

OUT   PULONG                                        ResultLength                             

)                                                                                                                            

這個API返回一個OBJECT_ALL_INFORMATION結構,其中NumberOfObjectsTypes成員為所有的對象類型在ObjectTypeInformation數組中的計數:

typedef struct _OBJECT_ALL_INFORMATION{

ULONG                                          NumberOfObjectsTypes;

OBJECT_TYPE_INFORMATION         ObjectTypeInformation[1];

}

檢測例程將遍歷擁有如下結構的ObjectTypeInformation數組:

typedef struct _OBJECT_TYPE_INFORMATION{

[00] UNICODE_STRING        TypeName;

[08] ULONG                          TotalNumberofHandles;

[0C] ULONG                  TotalNumberofObjects;

...more fields...

}

TypeName成員與UNICODE字符串"DebugObject"比較,然后檢查TotalNumberofObjects 或 TotalNumberofHandles 是否為非0值。

 

破解之法

Hook NtQueryObject

 

 

ZwSetInformationThread

可以用來將線程隱藏,從而使調試器接收不到信息

其原型如下:

NTSTATUS

NTAPI

ZwSetInformationThread (

    __in HANDLE ThreadHandle,

    __in THREADINFOCLASS ThreadInformationClass,

    __in_bcount(ThreadInformationLength) PVOID ThreadInformation,

    __in ULONG ThreadInformationLength

    );

//

// Thread Information Classes定義如下

//ntpsapi.h

typedef enum _THREADINFOCLASS {

    ThreadBasicInformation,

    ThreadTimes,

    ThreadPriority,

    ThreadBasePriority,

    ThreadAffinityMask,

    ThreadImpersonationToken,

    ThreadDescriptorTableEntry,

    ThreadEnableAlignmentFaultFixup,

    ThreadEventPair_Reusable,

    ThreadQuerySetWin32StartAddress,

    ThreadZeroTlsCell,

    ThreadPerformanceCount,

    ThreadAmILastThread,

    ThreadIdealProcessor,

    ThreadPriorityBoost,

    ThreadSetTlsArrayAddress,

    ThreadIsIoPending,

   ThreadHideFromDebugger,//這個就是用來將線程對調試器隱藏

    ThreadBreakOnTermination,

    ThreadSwitchLegacyState,

    ThreadIsTerminated,

    MaxThreadInfoClass

    } THREADINFOCLASS;

// end_ntddk end_ntifs

 

如下:ZwSetInformationThread(GetCurrentThread( ), ThreadHideFromDebugger, NULL, 0); 這樣就可以將當前線程對調試器隱藏了!

 

破解之法

Hook  ZwSetInformationThread

 

 

利用TLS技術,因為TLS回調函數會先於EP代碼執行,所以可以在該函數內部使用IsDebuggerPresent 等函數判斷是否在調試

 

 

還可以通過檢測OD的窗口、進程是否存在來判斷是否調試,判斷虛擬機進程等

 

 

 

 

 

 

 

 

 

 

 

動態反調試

SEH

在觸發異常時,若程序正常運行,會觸發異常處理程序,但若在調試過程中,調試器會接管異常處理,所以程序往往會故意觸發異常,讓調試器接管后執行無法正確運行的程序,若未調試,則會在異常程序那繼續執行程序

 

 正常運行:

轉到安裝的SEH處理函數中,該處理函數通過設置CONTEXT.Eip進行跳轉到正常運行的代碼段。

 

調試運行:

              調試器因為什么也不做走入程序終止/垃圾代碼段(極大消耗逆向人員精力)。

 

破解之法

通過OD等調試器的異常處理選項,對異常進行不處理,讓異常還給程序本身處理即可

 

SetUnhandledExceptionFilter

如果程序發生異常,SEH未處理或者不存在,那么系統就會運行最后一個異常處理器Top Level Exception Filter,彈出錯誤消息框,程序停止運行。

 

反調試技術的程序會:先特意觸發異常;進入UnhandledExceptionFilter()內部;再進入使用SetUnhandledException()注冊的頂級異常函數,即TopLevelExceptionFilter()API;判斷程序正常還是調試運行,以設置eip的值。

 

注意:UnhandledExceptionFilter()函數內部有ZwQueryInformationProcess()函數,見靜態反調試B)

 

破解之法

先解除UnhandledExceptionEilter()中的靜態反調試,然后看看程序打算注冊的新TopLevelExceptionFilter()函數打算返回到哪個地址。

 

 

通過時間判斷

在一段重要代碼執行前后進行執行時間判斷,若超過一定時間則認為被下了斷點或者單步執行,

 

破解之法

測試時間一般分兩類,1.Cpu計數 2采用系統實際時間

X86CPU中有一個TSC (time stamp counter 時間戳計數器)的64位寄存器,cpu對每個clock cycle 計數,然后保存到TSC。 RDTSC是一條匯編指令,用來把TSC值讀入EDX:EAX寄存器,TSC為64位,其高32位被保存在EDX,低32位保存在EAX

 

在OD里,遇到RDTSC指令,將其關鍵判斷條件或者值改寫即可

 

 

陷阱標志

陷進標志是EFLAGS 寄存器的第九個比特位 TF

TF=1  進入單步執行,cpu執行一條指令,會觸發EXCEPTION_SINGLE_STEP異常,然后陷進標志會清零,

破解之法:

OD調試選項設置忽略這個異常

 

 

 

 

 

INT2D

原為內核模式中用來觸發斷點的異常命令,也可以在用戶模式下觸發異常。

但是調試狀態下不會觸發異常,只會忽略。

他有個特征:在調試下他執行完INT2D指令后,會忽略下一個指令的第一個字節后繼續執行,在非調試模式下,會進入SE Handler

 

破解之法:

很多利用這個特征的方法通常會帶有cmp等判斷,通過修改判斷條件來達到目的

 

 

API斷點

一般斷API斷點都在API頭部入口,有些程序會檢測API頭部是否有0XCC等斷點標志來判斷是否被調試

 

破解之法

把斷點下在API中間位置或者其他位置

 

比較校驗和

比較特定代碼區域的校驗和值也用於反調試,比如在程序401000-401070 區域的校驗和是0x12346578,如果在這個區域內下斷,新的校驗和跟原來的就不一樣了,這就觸發了反調試

 

破解之法

最好的辦法還是修改CRC比較的邏輯

 

 

 

高級反調試技術:

1.     垃圾代碼

垃圾代碼中引入很多可以相互抵消的指令,減緩逆向人員的分析速度。

 

2.     擾亂代碼對齊

加入額外代碼,令分析程序錯誤解析。

比如415115-415119被調試器解析為一條指令,而前面程序有jmp到415116的,其實軟件本身是415116-415119為一條指令的。

3.     加密/解密

程序一部分代碼用於將其余部分代碼解密,以隱藏程序與數據。

注:反轉儲技術中,加密代碼被解碼為正常代碼后,有時會被再次加密,所以轉儲的代碼可能還是處於加密狀態。

特殊情況:代碼重組——指令修改程序的代碼。

4.     Stolen Bytes(Remove OEP)

顧名思義:

將源代碼OEP(一部分代碼)轉移到壓縮器/保護器創建的內存區域運行。

注:有些保護器先保存Stolen Bytes再運行,還有些保護器將它們直接從內存中刪除。

5.     API重定向

防止在API處被設下斷點

類似於API鈎取,將本來call API的地址CALL到另一個地址,另一個地址預先創建好和原先API同一個功能的代碼。

 

6.     Debug Blocker(Self Debugging)

調試模式下運行自身進程。

這種技術是自我創建技術(以子進程形式運行自身進程)的演進形式。

 

有如下優點:
        1.防止代碼調試,因為子進程運行實際的源代碼處於調試之中,原則上無法再使用其他調試器附加。(57章會講到一種方法破解)

        2.能夠控制子進程,因為對於調試進程發生的異常,調試器擁有優先處理權,所以可以把異常處理器的代碼放到調試進程中。——因此,想要調試子進程,要先斷開已有調試器的連接,而這樣子進程又無法執行。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM