當前位置:首頁 » 操作系統 » teb源碼

teb源碼

發布時間: 2022-06-11 13:06:40

① LoadLibrary一個DLL時,系統做了哪些事

上源代碼

主要功能:啟動NotePad,在NotePad進程里創建RemoteThread載入我們自己的DLL,DLL載入時創建一個托盤,SubClass NotePad的主窗口,在標題欄上畫一個Button。


HMODULE
LoadLibraryW(
LPCWSTR lpwLibFileName
)
{
return LoadLibraryExW( lpwLibFileName, NULL, 0 );
}

HMODULE
LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags
)

{
LPWSTR TrimmedDllName;
LPWSTR AllocatedPath;
NTSTATUS Status;
HMODULE hMole;
UNICODE_STRING DllName_U, AppPathDllName_U;
UNICODE_STRING AllocatedPath_U;
ULONG DllCharacteristics;
extern PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry;

TrimmedDllName = NULL;
DllCharacteristics = 0;
if (dwFlags & DONT_RESOLVE_DLL_REFERENCES) {
DllCharacteristics |= IMAGE_FILE_EXECUTABLE_IMAGE;
}

RtlInitUnicodeString(&DllName_U, lpwLibFileName);

//
// Quick check to see if dll being loaded is the main exe. For some reason
// hook stuff tends to do this and this is worst path through the loader
//

if ( !(dwFlags & LOAD_LIBRARY_AS_DATAFILE) && BasepExeLdrEntry && (DllName_U.Length == BasepExeLdrEntry->FullDllName.Length) ){
if ( RtlEqualUnicodeString(&DllName_U,&BasepExeLdrEntry->FullDllName,TRUE) ) {
return (HMODULE)BasepExeLdrEntry->DllBase;
}
}

//
// check to see if there are trailing spaces in the dll name (Win95 compat)
//
if ( DllName_U.Length && DllName_U.Buffer[(DllName_U.Length-1)>>1] == (WCHAR)' ') {
TrimmedDllName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), DllName_U.MaximumLength);
if ( !TrimmedDllName ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return NULL;
}
RtlCopyMemory(TrimmedDllName,DllName_U.Buffer,DllName_U.MaximumLength);
DllName_U.Buffer = TrimmedDllName;
while (DllName_U.Length && DllName_U.Buffer[(DllName_U.Length-1)>>1] == (WCHAR)' ') {
DllName_U.Buffer[(DllName_U.Length-1)>>1] = UNICODE_NULL;
DllName_U.Length -= sizeof(WCHAR);
DllName_U.MaximumLength -= sizeof(WCHAR);
}
}

//
// If DLL redirection is on for this application, we check to see if the DLL requested
// (without path qualification) exists in the app. (EXE) folder. If so, we load that.
// Else we fall back to regular search logic.
//

if (gDoDllRedirection && DllName_U.Length) {
Status = ComputeRedirectedDllName(&DllName_U, &AppPathDllName_U) ;
if(!NT_SUCCESS(Status)) {
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
}

BaseSetLastNTError(Status);
return NULL;
}

if (RtlDoesFileExists_U(AppPathDllName_U.Buffer)) {
DllName_U.Buffer = AppPathDllName_U.Buffer ;
DllName_U.MaximumLength = AppPathDllName_U.MaximumLength ;
DllName_U.Length = AppPathDllName_U.Length;
}
}

//
// Determine the path that the program was created from
//

AllocatedPath = BaseComputeProcessDllPath(
dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH ? DllName_U.Buffer : NULL,
GetEnvironmentStringsW()
);
if ( !AllocatedPath ) {
Status = STATUS_NO_MEMORY;
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
}
goto l;
}
RtlInitUnicodeString(&AllocatedPath_U, AllocatedPath);
try {
if (dwFlags & LOAD_LIBRARY_AS_DATAFILE) {
#ifdef WX86
// LdrGetDllHandle clears UseKnownWx86Dll, but the value is
// needed again by LdrLoadDll.
BOOLEAN Wx86KnownDll = NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll;
#endif
Status = LdrGetDllHandle(
AllocatedPath_U.Buffer,
NULL,
&DllName_U,
(PVOID *)&hMole
);
if (NT_SUCCESS( Status )) {
#ifdef WX86
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = Wx86KnownDll;
#endif
goto alreadyLoaded;
}

Status = BasepLoadLibraryAsDataFile( AllocatedPath_U.Buffer,
&DllName_U,
(PVOID *)&hMole
);
}
else {
alreadyLoaded:
Status = LdrLoadDll(
AllocatedPath_U.Buffer,
&DllCharacteristics,
&DllName_U,
(PVOID *)&hMole
);
}
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
TrimmedDllName = NULL;
}
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
if ( TrimmedDllName ) {
RtlFreeHeap(RtlProcessHeap(), 0, TrimmedDllName);
}
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
l:
if (gDoDllRedirection) {
// We would have led had we not been able to allocate this buffer in re-direction case.
RtlFreeHeap(RtlProcessHeap(), 0, AppPathDllName_U.Buffer);
}

if (!NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return NULL;
}
else {
return hMole;
}
}

NTSTATUS
BasepLoadLibraryAsDataFile(
IN PWSTR DllPath OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
)

{
WCHAR FullPath[ MAX_PATH ];
PWSTR FilePart;
HANDLE FileHandle;
HANDLE MappingHandle;
LPVOID DllBase;
PIMAGE_NT_HEADERS NtHeaders;
PTEB Teb;

Teb = NtCurrentTeb();

*DllHandle = NULL;
if (!SearchPathW( DllPath,
DllName->Buffer,
L".DLL",
MAX_PATH,
FullPath,
&FilePart
)
) {
return Teb->LastStatusValue;
}

FileHandle = CreateFileW( FullPath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL
);

if (FileHandle == INVALID_HANDLE_VALUE) {
return Teb->LastStatusValue;
}

MappingHandle = CreateFileMappingW( FileHandle,
NULL,
PAGE_READONLY,
0,
0,
NULL
);
CloseHandle( FileHandle );
if (MappingHandle == NULL) {
return Teb->LastStatusValue;
}

DllBase = MapViewOfFileEx( MappingHandle,
FILE_MAP_READ,
0,
0,
0,
NULL
);
CloseHandle( MappingHandle );
if (DllBase == NULL) {
return Teb->LastStatusValue;
}

NtHeaders = RtlImageNtHeader( DllBase );
if (NtHeaders == NULL) {
UnmapViewOfFile( DllBase );
return STATUS_INVALID_IMAGE_FORMAT;
}

*DllHandle = (HANDLE)((ULONG_PTR)DllBase | 0x00000001);
LdrLoadAlternateResourceMole(*DllHandle, FullPath);

return STATUS_SUCCESS;
}

NTSTATUS
LdrLoadDll (
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
){
return LdrpLoadDll(DllPath,DllCharacteristics,DllName,DllHandle,TRUE);
}

② GET參數怎麼用

後台解密使用且get能傳送255內位元組所推薦使用get傳遞參數參數通post據我web發經驗看能用get式傳都能轉post式看前台技術掌握

③ 手機qq空間背景圖片怎麼保存

QQ空間的背景圖片是無法直接保存到手機上,我可以推薦一個方法。先用手機截屏背景圖片,然後進行修剪,這樣也是可以拿到QQ空間背景圖片。

打開後保存就行了

④ 怎麼保存qq空間的背景圖片到手機上

QQ空間的背景圖片是無法直接保存到手機上,我可以推薦一個方法。


先用手機截屏背景圖片,然後進行修剪,這樣也是可以拿到QQ空間背景圖片。


把截屏的QQ空間背景圖片使用手機修剪功能來修剪,修剪後就剩下QQ空間背景圖片。

⑤ 病毒是怎麼寫出來的

匯編語言底層,靈活,速度快,體積小的優勢能將一個病毒程序發揮到極至,通常一個程序寫出來才幾千位元組就包含了所有的功能。一般一個病毒都有如下幾個功能:
一 代碼重定位

二 自己找到所需API地址

三 搜索文件、目錄

四 感染文件

五 破壞系統或文件(隨便你了)

其中一,二項功能是必要的,五項功能是可選的。而一個病毒程序感染文件的功能是它的核心,是衡量它質量的重要標准。

(一)代碼的重定位

一個變數或函數其實是一個內存地址,在編譯好後,程序中的指令通過變數或函數的內存地址再去存取他們,這個地址是個絕對地址。如果你將代碼插入到其他任何地方,再通過原來編譯時產生的地址去找他們就找不到了,因為他們已經搬家了。但是,在寫程序時考慮到這個問題,可以在代碼最開始,放上幾行代碼取得程序基地址,以後變數和函數作為偏移地址,顯式的加上這個基地址就能順利找到了,這就是重定位。就象這段代碼。

Call getbaseaddress

Getbaseaddress:pop ebx

Sub ebx,offset getbaseaddress

Mov eax,dword ptr [ebx+Var1]

如果使用宏匯編語言寫病毒,請盡量使用ebx做基地址指針,不要使用ebp,因為ebp在調用帶參數的函數時會改變。

(二)自己取得所需的API地址

一個win32程序文件,所調用的API函數地址,是由系統填入到程序文件中描述各類數據位置的數據結構中的。而病毒作為一個殘廢是享受不到這個待遇的。因為你在把病毒的代碼插入目標程序時沒有把這些描述數據存放位置的數據結構信息也弄進去。它被插入到其他目標程序後就成了只有代碼的殘廢兒童:(所以作為一個殘廢兒童,應當自力更生。自己搜尋自己需要的API地址。目標程序文件就包含了我們需要的東西,需要自己去找。目標程序文件只要還是win32程序,它的地址空間中就包含的有Kernel32.dll。如果找到了它,就能找到其他任何的東東。第一步,搜尋kernel32.dll的基地址。當然了,整個地址空間有4GB,可供搜索的用戶進程空間也有2GB。在2GB中搜索,太嚇人了。
在程序被載入後,載入程序會調用程序的主線程的第一條指令的位置。它使用的指令是CALL,就是說,程序還沒執行,堆棧區里就有了一個返回地址了,這個返回地址指向的是載入程序,而載入程序是包含在KERNEL32.dll中的,順著它向上找,就能找到kernel32.dll的基地址了。當然也不是一個位元組一個位元組的挨者找,而是一個頁面一個頁面地找。因為win32下,代碼或數據的開始位置總是頁面單位(windows平台下為4kb)對齊的。Kernel32.dll是一個PE文件,按比較PE文件dos簽名標志和PE簽名標志的方法找。另外還有個辦法是通過SHE技術找。這是最好的辦法了,前一個辦法因為堆棧是動態的原因不穩定,一般只能將獲取地址的代碼塊放在最開頭,這個方法完全是與堆棧無關的,放在哪裡執行都不會出錯,如果你的病毒需要用一些遠程線程之類的技術,最好用這個方法。
SHE結構,第一個成員指向下一個SEH結構,如果是最後一個那麼它的值就是0ffffffffh。第二個成員指向異常處理函數,如果是最後一個SHE結構且沒有指定的話,預設的是SetUnhandlederExceptionFilter函數地址。當異常觸發這個函數時就會彈出一個對話框,問你發不發送錯誤。98下顯示藍屏。這個函數是包含在KERNEL32.dll中的,只要取得它的地址向上找就能找到KERNEL32.dll的基地址了。在說SHE時總忘不了TEB,TEB是創建一個線程時分配的線程相關的數據結構,SHE只是它開頭第一個數據結構體而已。它還包含了其他許多重要的東西,TEB由FS段選擇器指向,有興趣的查查資料,這里篇幅原因就不再多說了。接著上面的,看看如何找SetUnhanderExceptionFilter函數地址。先根據「下一個」SHE結構的值定位到最後一個SHE結構,這時取出she處理函數的地址,就是SetUnHandleredEceptionFilter函數地址了,以頁面為單位向上找就可以找到Kernel32.dll了/

得到Kernel32.dll的基地址後,定位到它的導出表,找出GetProcAddress地址再利用GetProcAddress就能找到其他任何所需要的函數了。在搜索API時應該注意API的名字,API的名字實際的導出名字很有可能不是你調用時的名字,windows下很多API都有兩個版本ANSI版和UNICODE版,ANSI版函數名後綴帶個A,比如CreateWindowExA,,而UNICODE版的函數名帶個W後綴,比如CreateWindowExW。不過考慮到麻煩問題,現有的很多編譯器都不讓你寫後綴,只是在編譯的時候根據你程序是ANSI版的還是UNICODE版的自動改名字。Win2K以後的API函數都是Unicode 版本的,如果調用ANSI版本的函數,系統只是將函數中的字元串通過進程默認堆將其轉換成Unicode字元串,再調用Unicode版的API。Unicode是個發展方向,大家應該養成使用它的習慣而不是ANSI。

(三)搜索文件、目錄

主要是用FindFirstFile,FindNextFile,FindClose.這三個函數實現。值得注意的是在用「*.*」搜索字元串時得到的是程序文件所在目錄的所有文件和目錄。而GetCurrentDirectory取得的是系統當前的目錄。後者是隨時會隨著用戶的操作而改變的,前者只會隨著目標程序文件的位置改變而改變。搜索需要感染的目錄和文件時應該重點搜索windows安裝目錄(GetWindowsDirectory),系統目錄(GetSystemDIrectory),當前目錄(GetCurrentDirectory) ,當然程序當前目錄也是不可放過的,比如,把QQ感染了,QQ目錄底下那麼多常常使用的程序文件,比如珊瑚蟲外掛,郵箱工具等等都是你的盤中餐了。最喜歡感染的地方還是系統中各個進程所在的目錄,那些才是用戶最常用的,我的遂寧一號病毒是通過代碼插入的辦法做到這點的,很麻煩,且很不穩定。常常莫名其妙的使被插入進程在插入時結束掉,雖然可以用SHE避免,但是還是沒多大效果。

(四)感染文件

所謂感染就是將病毒程序的代碼插入到目標程序中,然後讓目標程序先執行病毒程序的代碼。

⑥ 網站裡面有幾個ASP文件看不懂

應該是VBScript.Encode加密了.
嘗試解密,再看一下是代碼是什麼.就知道了.

不過,倒著看,裡面有提權的字眼,可以肯定這是一個木馬文件了.

⑦ WinDbg怎麼用

什麼是WinDBG? WinDbg是微軟開發的免費源碼級調試工具。Windbg可以用於Kernel模式調試和用戶模式調試,還可以調試Dump文件。由於大部分程序員不需要做Kernel模式調試, 我在這篇文章中不會介紹Kernel模式調試。Kernel模式調試對學習Windows核心極有幫助。如果你對此感興趣,可以閱讀Inside Windows 2000和Windbg所帶的幫助文件。這篇文章得主要目的是介紹WINDBG的主要功能以及相關的命令。關於這些命令的詳細語法,請參閱幫助文件。對文章中提到的許多命令,WINDBG有相應的菜單選項。如何得到幫助在命令(Command)窗口中輸入.hh 命會調出幫助文件令。.hh keyword會顯示關於keyword的詳細命令。啟動DebuggerWindbg可以用於如下三種調試:遠程調試:你可以從機器A上調試在機器B上執行的程序。具體步驟如下:
? 在機器B上啟動一個調試窗口(Debug Session)。你可以直接在Windbg下運行一個程序或者將Windbg附加(Attach)到一個進程。? 在機器B的Windbg命令窗口上啟動一個遠程調試介面(remote):.server npipe:pipe=PIPE_NAMEPIPE_NAME是該介面的名字。? 在機器A上運行:windbg –remote npipe:server=SERVER_NAME,pipe=PIPE_NAMESERVER_NAME是機器B的名字。Dump文件調試:如果在你的客戶的機器上出現問題,你可能不能使用遠程調試來解決問題。你可以要求你的用戶將Windbg附加到出現問題的進程上,然後在命令窗口中輸入:
.mp /ma File Name創建一個Dump文件。在得到Dump文件後,使用如下的命令來打開它:windbg –z DUMP_FILE_NAME本地進程調試:你可以在Windbg下直接運行一個程序:
Windbg 「path to executable」 arguments 也可以將Windbg附加到一個正在運行的程序: Windbg –p 「process id」 Windbg –pn 「process name」 注意有一種非侵入(Noninvasive)模式可以用來檢查一個進程的狀態並不進程的執行。當然在這種模式下無法控制被調試程序的執行。這種模式也可以用於查看一個已經在Debugger控制下運行的進程。具體命令如下: Windbg –pv –p 「process id」 Windbg –pv –pn 「process name」 調試多個進程和線程如果你想控制一個進程以及它的子進程的執行,在Windbg的命令行上加上-o選項。Windbg中還有一個新的命令.childdbg 可以用來控制子進程的調試。如果你同時調試幾個進程,可以使用 | 命令來顯示並切換到不同的進程。在同一個進程中可能有多個線程。~命令可以用來顯示和切換線程。調試前的必備工作在開始調試前首先要做的工作是設置好符號(Symbols)路徑。沒有符號,你看到的調用堆棧基本上毫無意義。Microsoft的操作系統符號文件(PDB)是對外公開的。另外請注意在編譯你自己的程序選擇生成PDB文件的選項。如果設置好符號路徑後,調用堆棧看起來還是不對。可以使用lm, !sym noisy, !reload 等命令來驗證符號路徑是否正確。Windbg也支持源碼級的調試。在開始源碼調試前,你需要用.srcpath設置源代碼路徑。如果你是在生成所執行代碼的機器上進行調試,符號文件中的源碼路徑會指向正確的位置,所以不需要設置源代碼路徑。如果所執行代碼是在另一台機器上生成的,你可以將所用的源碼拷貝(保持原有的目錄結構)的一個可以訪問文件夾(可以是網路路徑)並將源代碼路徑設為該文件夾的路徑。注意如果是遠程調試,你需要使用.lsrcpath來設置源碼路徑。靜態命令:顯示調用堆棧:在連接到一個調試窗口後,首先要知道的就是程序當前的執行情況k* 命令顯示當前線程的堆棧。~*kb會顯示所有線程的調用堆棧。如果堆棧太長,Windbg只會顯示堆棧的一部分。.kframes可以用來設置預設顯示框架數。顯示局部變數:接下來要做通常是用dv顯示局部變數的信息。CTRL+ALT+V可以切換到更詳細的顯示模式。關於dv要注意的是在優化過的代碼中dv的輸出極有可能是不準確的。這時後你能做的就是閱讀匯編代碼來發現你感興趣的值是否存儲在寄存器中或堆棧上。有時後當前的框架(Frame)上可能找不到你想知道的數據。如果該數據是作為參數傳到當前的方法中的,可以讀一讀上一個或幾個框架的匯編代碼,有可能該數據還在堆棧的某個地址上。靜態變數是儲存在固定地址中的,所以找出靜態變數的值較為容易。.Frame(或者在調用堆棧窗口中雙擊)可以用來切換當前的框架。注意dv命令顯示的是當前框架的內容。你也可在watch窗口中觀察局部變數的值。顯示類和鏈表: dt可以顯示數據結構。比如dt PEB 會顯示操作系統進程結構。在後面跟上一個進程結構的地址會顯示該結構的詳細信息:dt PEB 7ffdf000。Dl命令可以顯示一些特定的鏈表結構。顯示當前線程的錯誤值:!gle會顯示當前線程的上一個錯誤值和狀態值。!error命令可以解碼HRESULT。搜索或修改內存:使用s 命令來搜索位元組,字或雙字,QWORD或字元串。使用e命令來修改內存。計算表達式:?命令可以用來進行計算。關於表達式的格式請參照幫助文檔。使用n命令來切換輸入數字的進制。顯示當前線程,進程和模塊信息:!teb顯示當前線程的環境信息。最常見的用途是查看當前線程堆棧的起始地址,然後在堆棧中搜索值。!peb顯示當前進程的環境信息,比如執行文件的路徑等等。lm顯示進程中載入的模塊信息。顯示寄存器的值:r命令可以顯示和修改寄存器的值。如果要在表達式中使用寄存器的值,在寄存器名前加@符號(比如@eax)。顯示最相近的符號:ln Address。如果你有一個C++對象的指針,可以用來ln來查看該對象類型。 查找符號:x命令可以用來查找全局變數的地址或過程的地址。x命令支持匹配符號。x kernel32!*顯示Kernel32.dll中的所有可見變數,數據結構和過程。查看lock:!locks顯示各線程的鎖資源使用情況。對調試死鎖很有用。查看handle:!handle顯示句柄信息。如果一段代碼導致句柄泄漏,你只需要在代碼執行前後使用!handle命令並比較兩次輸出的區別。有一個命令!htrace對調試與句柄有關的Bug非常有用。在開始調試前輸入:!htrace –enable 然後在調試過程中使用!htrace handle_value 來顯示所有與該句柄有關的調用堆棧。顯示匯編代碼:u。程序執行控制命令:設置代碼斷點:bp/bu/bm 可以用來設置代碼斷點。你可以指定斷點被跳過的次數。假設一段代碼KERNEL32!SetLastError在運行很多次後會出錯,你可以設置如下斷點: bp KERNEL32!SetLastError 0x100.在出錯後使用bl 來顯示斷點信息(注意粗體顯示的值):0 e 77e7a3b0 004f (0100) 0:*** KERNEL32!SetLastError重新啟動調試(.restart命令)並設置如下的斷點:bp Kernel32!SetLastError 0x100-0x4fDebugger會停在出錯前最後一次調用該過程的地方。你可以指定斷點被激活時Debugger應當執行的命令串。在該命令串中使用J命令可以用來設置條件斷點:bp `mysource.cpp:143` "j (poi(MyVar)」0n20) ''; 'g' "上面的斷點只在MyVar的值大於32時被激活(g命令條件斷點的用途極為廣泛。你可以指定一個斷點只在特殊的情況下被激活,比如傳入的參數滿足一定的條件,調用者是某個特殊的過程,某個全局變數被設為特殊的值等等。設置內存斷點:ba可以用來設置內存斷點。調試過程中一個常見的問題是跟蹤某些數據的變化。如下的斷點:ba w4 0x40000000 "kb; g"可以列印出所有修改0x40000000的調用堆棧。控製程序執行:p, pa,t, ta等命令可以用來控製程序的執行。控制異常和事件處理:Debugger的預設設置是跳過首次異常(first chance expcetion),在二次異常(second chance exception)時中斷程序的執行。sx命令顯示Debugger的設置。sxe和sxd可以改變Debugger的設置。 sxe clr可以控制Debugger在託管異常發生時中斷程序的執行。常用的Debugger事件有: av 訪問異常 eh C++異常 clr 託管異常 ld 模塊載入-c 選項可以用來指定在事件發生時執行的調試命令。

熱點內容
db2新建資料庫 發布:2024-09-08 08:10:19 瀏覽:170
頻率計源碼 發布:2024-09-08 07:40:26 瀏覽:778
奧迪a6哪個配置帶後排加熱 發布:2024-09-08 07:06:32 瀏覽:100
linux修改apache埠 發布:2024-09-08 07:05:49 瀏覽:208
有多少個不同的密碼子 發布:2024-09-08 07:00:46 瀏覽:566
linux搭建mysql伺服器配置 發布:2024-09-08 06:50:02 瀏覽:995
加上www不能訪問 發布:2024-09-08 06:39:52 瀏覽:811
銀行支付密碼器怎麼用 發布:2024-09-08 06:39:52 瀏覽:513
蘋果手機清理瀏覽器緩存怎麼清理緩存 發布:2024-09-08 06:31:32 瀏覽:554
雲伺服器的優點與缺點 發布:2024-09-08 06:30:34 瀏覽:734