病毒和木馬的隱藏手段

一. 無處可尋的病毒

大學生張雲畢業後在一家公司擔任計算機維護員的工作,這天主任把他找去維修一台出現異常的計算機,這台計算機上什麼程序都未運行,可是機內安裝的卡巴斯基殺毒軟件卻在不停的提示在系統目錄發現特洛伊木馬程序,而後自動進行查殺,可是剛查殺完畢就又跳出了同樣的提示,一旦斷開網絡連接,這個現象立刻終止,再連接網絡,立即再次提示發現特洛伊木馬程序……如此反覆循環,最終導緻任何正常工作都無法進行。由於機器上儲存有大量重要資料和數據庫,如果要重裝系統,後面的環境恢復工作必將十分龐大,主任通過殺毒軟將無法解決,只好把所有希望都寄托在這名小夥子身上了。

張雲信心十足的坐下來,憑著他往日積累的手工檢測和查殺病毒的經驗,很快就清理了一堆惡意程序和流氓軟件,在經過幾次慎重檢查所有涉及的啟動項都沒有異常程序後,張雲再次把網絡給連接上了,正欲離開辦公室,身後卡巴斯基發現病毒的嘶叫聲猛的嚇了他一跳,怎麼還有病毒?張雲茫然不知所措了……

二. 永無休止的躲藏

隱藏是病毒的天性,在業界對病毒的定義裡,「隱蔽性」就是病毒的一個最基本特徵,任何病毒都希望在被感染的計算機中隱藏起來不被發現,因為病毒都只有在不被發現的情況下,才能實施其破壞行為。為了達到這個目的,許多病毒使用了各種不同的技術來躲避反病毒軟件的檢驗,這樣就產生了各種各樣令普通用戶頭痛的病毒隱藏形式。

由於木馬後門的行為特徵已具備病毒條件,因此本文將木馬後門也統一歸納為病毒來描述。

開山鼻祖:隱藏窗口 & 隱藏進程 & 隱藏文件

在計算機流行的早期,計算機病毒和木馬後門等危害程序在普通用戶範圍的普及並不是很廣泛,這個時期的用戶群對計算機和網絡安全的防範意識可以說是幾乎沒有的,普通用戶的系統也多為脆弱的windows 95/98系列和電話線撥號的慢速網絡,而那一段時間正是外國木馬「bo」和國產木馬雛形「冰河」、「netspy」等在如今看來各方面技術都頗為簡單的遠程控制軟件大行其道的黃金時期,很多用戶根本就沒有防火牆和殺毒軟件(即使有,也是以殺cih的為主),即使遠方的黑客把用戶的計算機翻了個底朝天,用戶也不會有所察覺,這一時期接觸此類技術的人相對較少,因此並未造成如今這個病毒到處蔓延的局面。

因為這個階段國內用戶的機器環境仍然以windows 9x為主流,所以病毒編寫者們並不需要消耗太多的腦筋就可以做到讓病毒悄無聲息運行的效果,並讓它在alt+del+ctrl呼出的任務管理器中不可見。

我們都知道,在windows下運行的程序界面都被定義為「窗口」,程序通過這個途徑與用戶產生交互,每個完整的程序都必須擁有至少一個窗口,但是如果編寫者將這個窗口在運行期間設置為「不可見」呢?這樣一來,用戶就不會察覺到這個程序在桌面上運行了,但是如果有一定經驗的用戶打開任務管理器,他就會因為發現系統裡多出來的進程而產生懷疑,因此病毒編寫者在這個時期採取了初級形式的隱藏手段:隱藏進程。

其實所謂隱藏進程,是利用微軟未公開的一個api(application programming interface,應用程序接口)函數「registerserviceprocess」將自身註冊為「服務進程」,而恰巧windows 9x中的任務管理器是不會顯示此類進程的,結果就被病毒鑽了空子,讓「冰河」等木馬在國內大部分普通用戶的機器上安家落戶。

而早期後門技術裡,還有一個最基本的行為就是隱藏文件,與今天的各種隱藏手段相比,它可謂是「不入流」級別了——這裡提到的「隱藏」,就是簡單的將文件屬性設置為「隱藏」而已,除此之外,再無別的保護手段了,然而,由於系統設計時為了避免初學者胡亂刪除文件而默認「不顯示系統和隱藏文件」的做法(到了windows 2000/xp時代,這個做法更升級到「隱藏受保護的系統文件」了),卻恰好給這些病毒提供了天然的隱身場所——大部分對電腦操作不熟悉的用戶根本不知道「隱藏文件」的含義,更別提設置為「顯示所有文件」了,在那個安全軟件廠商剛開始探索市場的時代,用戶更是不會留意太多安全產品及其實際含義,因而這個時期成了各種初期木馬技術發展的重要階段,利用這種手段製作的木馬被統稱為「第一代木馬」。



以現在的技術和眼光看來,這些早期技術作品的發現和清理是相對較簡單的了,因為它們採用的「進程隱藏」技術在nt體繫上的windows2000/xp/2003等操作系統上已經無效了,直接使用系統自帶的任務管理器便能發現和迅速終止進程運行,而後在「控制面板」——「文件夾選項」裡面設置「顯示所有文件」和取消「隱藏受保護的系統文件」,就能發現那個被隱藏起來的木馬程序了。對於windows 9x用戶,使用任意一款第三方的進程管理工具如「windows優化大師」的進程管理組件即可輕鬆發現。

繼續發展:使用線程注射技術的dll木馬

雖然現在使用「線程注射」的木馬病毒和流氓軟件已經遍地開花了,但是從那個混沌時代經歷過來的人都不會忘記首個採用「線程注射」的dll木馬「廣外幽靈」在當時所帶來的恐懼,「線程注射」到底是種什麼東西呢?下面就讓我們來詳細講解一下。

首先,用戶可能不會瞭解「線程」(thread)的意思,而要講解「線程」,就不能不先提到「進程」(process)的概念。許多剛接觸計算機的用戶無法理解「進程」是什麼東西:常常聽到高手說打開任務管理器關閉某某進程,但是一看到任務管理器列表裡的一堆東西,頭就大了。許多用戶知道使用任務管理器關閉一些失去響應的任務,但是如果某個任務沒有在「應用程序」列表裡出現,用戶就不知所措了。到底什麼是「進程」呢?「進程」是指一個可執行文件在運行期間請求系統在內存裡開闢給它的數據信息塊,系統通過控制這個數據塊為運行中的程序提供數據交換和決定程序生存期限,任何程序都必須擁有至少一個進程,否則它不被系統承認。進程從某一方面而言就是可執行文件把自身從存儲介質複製在內存中的映像,它通常和某個在磁盤上的文件保持著對應關係,一個完整的進程信息包括很多方面的數據,我們使用進程查看工具看到的「應用程序」選項卡包含的是進程的標題,而「進程」選項卡包含的是進程文件名、進程標識符、佔用內存等,其中「進程文件名」和「進程標識符」是必須掌握的關鍵,「進程標識符」是系統分配給進程內存空間時指定的唯一數字,進程從載入內存到結束運行的期間裡這個數字都是保持不變的,而「進程文件名」則是對應著的介質存儲文件名稱,根據「進程文件名」我們就可以找到最初的可執行文件位置。
任務管理器的「應用程序」項裡列出來的「任務」,是指進程在桌面上顯示出來的窗口對象,例如用戶打開word 2003撰寫文檔,它的進程「winword.exe」會創建一個在桌面上顯示的前台窗口,這個窗口就是任務管理器裡看得見的「任務」了,而實際上真正在運行的是進程「winword.exe」。並不是所有的進程都會在任務管理器裡留下「任務」的,像qq、msn和所有後台程序,它們並不會在任務列表裡出現,但是你會在進程列表裡找到它們,如果要它們在任務列表裡出現該怎麼辦呢?只要讓它們產生一個在桌面上出現的窗體就可以了,隨便打開一個好友聊天,就會發現任務列表裡終於出現了qq的任務。因此,真正科學的終止程序執行方案是針對「進程」來結束程序的運行,而不是在任務列表裡關閉程序,因為木馬作者們是不會讓自己的木馬在任務列表裡出現的,但是進程列表裡一般人都是逃不過的。

而「線程」,則是在一個進程裡產生的多個執行進度實例,舉個簡單例子,一個網絡文件傳輸程序如果只有一個線程(單線程)運作,那麼它的執行效率會非常低下,因為它既需要從網絡上讀取文件數據,又需要把文件保存到磁盤,同時還需要繪製當前傳輸進度條,由於在代碼的角度裡這些操作只能一條條的順序執行,程序就不能很好的做到在保存數據的同時繪製傳輸進度條,即使程序員將其勉強湊到一塊執行,在用戶方面看來,這個程序的響應會非常緩慢甚至直接崩潰,而「多線程」技術則是為了解決這種問題而產生的,採用「多線程」技術編寫的應用程序在運行時可以產生多個同時執行的操作實例,例如一個採用「多線程」技術的網絡文件傳輸程序就能同時分出三個進度來同時執行網絡數據傳輸、文件保存操作和繪製傳輸進度條的操作,於是在用戶看來,這個程序運行非常流暢,這就是線程的作用。在程序運行時,只能產生一個進程,但是在這個進程的內存空間(系統為程序能正常執行而開闢的獨立內存領域)裡,可以產生多個線程,其中至少有一個默認的線程,被稱為「主線程」,它是程序主要代碼的運行部分。

那麼,「線程注射」又是什麼含義呢?其實它的全稱是「遠程線程注射」(remotethread injection),通常情況下,各個進程的內存空間是不可以相互訪問的,這也是為程序能夠穩定運行打下基礎,這個訪問限制讓所有進程之間互相獨立,這樣一來,任何一個非系統關鍵進程發生崩潰時都不會影響到其他內存空間裡的進程執行,從而使nt架構的穩定性遠遠高於win9x架構。但是在一些特定的場合裡,必須讓進程之間可以互相訪問和管理,這就是「遠程線程」技術的初衷,這個技術實現了進程之間的跨內存空間訪問,其核心是產生一個特殊的線程,這個線程能夠將一段執行代碼連接到另一個進程所處的內存空間裡,作為另一個進程的其中一個非核心線程來運行,從而達到交換數據的目的,這個連接的過程被稱為「注射」(injection)。遠程線程技術好比一棵寄生在大樹上的蔓籐,一旦目標進程被注射,這段新生的線程就成為目標進程的一部分代碼了,只要目標進程不被終止,原進程無論是否還在運行都不會再影響到執行結果了。

與「線程注射」離不開的是「hook」技術,這個「hook」,又是什麼呢?其官方定義如下:

鉤子(hook),是windows消息處理機制的一個平台,應用程序可以在上面設置子程以監視指定窗口的某種消息,而且所監視的窗口可以是其他進程所創建的。當消息到達後,在目標窗口處理函數之前處理它。鉤子機制允許應用程序截獲處理window消息或特定事件。

鉤子實際上是一個處理消息的程序段,通過系統調用,把它掛入系統。每當特定的消息發出,在沒有到達目的窗口前,鉤子程序就先捕獲該消息,亦即鉤子函數先得到控制權。這時鉤子函數即可以加工處理(改變)該消息,也可以不作處理而繼續傳遞該消息,還可以強制結束消息的傳遞。



在這裡,木馬編寫者首先把一個實際為木馬主體的dll文件載入內存,然後通過「線程注射」技術將其注入其他進程的內存空間,最後這個dll裡的代碼就成為其他進程的一部分來實現了自身的隱藏執行,通過調用「hook」機制,這個dll木馬便實現了監視用戶的輸入輸出操作,截取有用的資料等操作。這種木馬的實際執行體是一個dll文件,由於windows系統自身就包含著大量的dll文件,誰也無法一眼看出哪個dll文件不是系統自帶的,所以這種木馬的隱蔽性又提高了一級,而且它的執行方式也更加隱蔽,這是由windows系統自身特性決定的,windows自身就是大量使用dll的系統,許多dll文件在啟動時便被相關的應用程序加載進內存裡執行了,可是有誰在進程裡直接看到過某個dll在運行的?因為系統是把dll視為一種模塊性質的執行體來調用的,它內部只包含了一堆以函數形式輸出的模塊,也就是說每個dll都需要由一個用到它的某個函數的exe來加載,當dll裡的函數執行完畢後就會返回一個運行結果給調用它的exe,然後dll進程退出內存結束這次執行過程,這就是標準的dll運行週期,而採用了「線程注射」技術的dll則不是這樣,它們自身雖然也是導出函數,但是它們的代碼是具備執行邏輯的,這種模塊就像一個普通exe,只是它不能直接由自身啟動,而是需要有一個特殊作用的程序(稱為加載者)產生的進程把這個dll的主體函數載入內存中執行,從而讓它成為一個運行中的木馬程序。瞭解windows的用戶都知道,模塊是緊緊依賴於進程的,調用了某個模塊的進程一旦退出執行,其加載的dll模塊也就被迫終止了,但是在dll木馬裡,這個情況是不會因為最早啟動的exe被終止而發生的,因為它使用了「遠程線程注射」技術,所以,在用戶發現異常時,dll木馬早就不知道被注入哪個正常進程裡了,即使用戶發現了這個木馬dll,也無法把它終止,因為要關閉它就必須在那麼多的系統進程裡找到被它注射的進程,並將其終止,對一般用戶來說,這是個不可能完成的任務。

自從「廣外幽靈」開創了dll木馬時代的先河以來,現在採用線程注射的dll木馬和惡意程序已經隨處可見了,除了普遍被採用的另行編寫dll加載器程序躲在啟動項裡運行加載dll主體之外,「求職信」還帶來了一種比較少見的通過註冊表「hkey_local_machine\software\microsoft\windows nt\currentversion\windows\appinit_dlls」項目加載自身dll的啟動方法,而相對於以上幾種早期方法,現在更有一種直接利用系統服務啟動自身的木馬程序,這才是真正的難纏!

「服務」是windows系統的一大核心部分,在nt架構系統中,服務是指執行指定系統功能的程序、例程或進程,以便支持其他程序,尤其是底層(接近硬件)程序。通過網絡提供服務時,服務可以在active directory中發佈,從而促進了以服務為中心的管理和使用。服務是一種應用程序類型,它在後台運行。服務應用程序通常可以在本地和通過網絡為用戶提供一些功能,例如客戶端/服務器應用程序、web服務器、數據庫服務器以及其他基於服務器的應用程序。 「服務」自身也是一種程序,由於使用的領域和作用不同,服務程序也有兩種形式:exe和dll,採用dll形式的服務是因為dll能實現hook,這是一些服務必需的數據交換行為,而nt架構系統採用一個被稱為「svchost.exe」的程序來執行dll的加載過程,所有服務dll都統一由這個程序根據特定分組載入內存,然而,如今越來越多病毒作者瞄上了這個系統自帶的加載器,因為它永遠也不能被查殺。

病毒作者將木馬主體寫成一個符合微軟開發文檔規範的服務性質dll模塊文件,然後通過一段安裝程序,將木馬dll放入系統目錄,並在服務管理器(scm)裡註冊自身為通過svchost.exe加載的服務dll組件之一,為了提高隱蔽性,病毒作者甚至直接替換系統裡某些不太重要而默認開啟的服務加載代碼,如「distributed link tracking client」,其默認的啟動命令是「svchost -k netsvcs」,如果有個病毒替換了啟動命令為自己建立的分組「netsvsc」,即「svchost -k netsvsc」,在這種旁門左道加社會工程學的攻勢下,即使是具備一般查毒經驗的用戶也難以在第一時間內察覺到問題出自服務項,於是病毒得以成功逃離各種查殺。

目前被發現使用此方法的木馬已經出現,其中一個進程名為「ad1.exe」的廣告程序就是典型例子,它通過替換「distributed link tracking client」服務的svchost啟動項來躲過一般的手工查殺,同時它自身還是個病毒下載器,一旦系統感染了這個惡意程序,各種木馬都有可能光臨你的機器。

要清理dll木馬,用戶需要借助於sysinternals出品的第三方進程管理工具「process explorer」,利用它的「find handle or dll」功能,能迅速搜索到某個dll依附的進程信息並終結,讓dll失去載體後就能成功刪除,而dll木馬的文件名為了避免和系統dll發生衝突,一般不會起得太專業,甚至有「safaf.dll」、「est.dll」這樣的命名出現,或者在某些系統下根本不會出現的文件名,如「kernel.dll」、「rundll32.dll」等。除了使用「process explorer」查找並終止進程以外,還可以用icesword強行卸載某個進程裡的dll模塊來達到效果。


對於服務性質的dll,我們仍然使用「process explorer」進行查殺,由於它的層次結構,用戶可以很直觀的看到進程的啟動聯繫,如果一台機器感染了殺不掉的頑固木馬,有經驗的用戶做的第一件事情就是禁止掉不相關或者不重要的程序和服務在開機時運行,然後使用「process explorer」觀察各個進程的情況,通過svchost.exe啟動的dll木馬雖然狡猾,但是它釋放出exe文件運行時,一切都暴露了:一個svchost.exe服務進程執行了一個ad1.exe,還有比這更明顯的嗎?

svchost的分組信息位於註冊表的「hkey_local_machine\software\microsoft\windows nt\currentversion\svchost」項目,這是svchost加載dll時的分組依據,如果用戶發現了一個奇怪的分組信息,那就要提高警惕了。

隱藏技術發展的顛峰:rootkit木馬

隨著安全技術的發展和計算機用戶群的技術提高,一般的木馬後門越來越難生存,於是一部分有能力的後門作者把眼光投向了系統底層——ring 0。位於ring 0層的是系統核心模塊和各種驅動程序模塊,所以位於這一層的木馬也是以驅動的形式生存的,而不是一般的exe。後門作者把後門寫成符合wdm規範(windows driver model)的驅動程序模塊,把自身添加進註冊表的驅動程序加載入口,便實現了「無啟動項」運行。一般的進程查看器都只能枚舉可執行文件exe的信息,所以通過驅動模塊和執行文件結合的後門程序便得以生存下來,由於它運行在ring 0級別,擁有與系統核心同等級的權限,因此它可以更輕易的把自己隱藏起來,無論是進程信息還是文件體,甚至通訊的端口和流量也能被隱藏起來,在如此強大的隱藏技術面前,無論是任務管理器還是系統配置實用程序,甚至系統自帶的註冊表工具都失去了效果,這種木馬,就是讓人問之色變的rootkit。

要瞭解rootkit木馬的原理,就必須從系統原理說起,我們知道,操作系統是由內核(kernel)和外殼(shell)兩部分組成的,內核負責一切實際的工作,包括cpu任務調度、內存分配管理、設備管理、文件操作等,外殼是基於內核提供的交互功能而存在的界面,它負責指令傳遞和解釋。由於內核和外殼負責的任務不同,它們的處理環境也不同,因此處理器提供了多個不同的處理環境,把它們稱為運行級別(ring),ring讓程序指令能訪問的計算機資源依次逐級遞減,目的在於保護計算機遭受意外損害——內核運行於ring 0級別,擁有最完全最底層的管理功能,而到了外殼部分,它只能擁有ring 3級別,這個級別能操作的功能極少,幾乎所有指令都需要傳遞給內核來決定能否執行,一旦發現有可能對系統造成破壞的指令傳遞(例如超越指定範圍的內存讀寫),內核便返回一個「非法越權」標誌,發送這個指令的程序就有可能被終止運行,這就是大部分常見的「非法操作」的由來,這樣做的目的是為了保護計算機免遭破壞,如果外殼和內核的運行級別一樣,用戶一個不經意的點擊都有可能破壞整個系統。

由於ring的存在,除了由系統內核加載的程序以外,由外殼調用執行的一般程序都只能運行在ring 3級別,也就是說,它們的操作指令全部依賴於內核授權的功能,一般的進程查看工具和殺毒軟件也不例外,由於這層機制的存在,我們能看到的進程其實是內核「看到」並通過相關接口指令(還記得api嗎?)反饋到應用程序的,這樣就不可避免的存在一條數據通道,雖然在一般情況下它是難以被篡改的,但是不能避免意外的發生,rootkit正是「製造」這種意外的程序。簡單的說,rootkit實質是一種「越權執行」的應用程序,它設法讓自己達到和內核一樣的運行級別,甚至進入內核空間,這樣它就擁有了和內核一樣的訪問權限,因而可以對內核指令進行修改,最常見的是修改內核枚舉進程的api,讓它們返回的數據始終「遺漏」rootkit自身進程的信息,一般的進程工具自然就「看」不到rootkit了。更高級的rootkit還篡改更多api,這樣,用戶就看不到進程(進程api被攔截),看不到文件(文件讀寫api被攔截),看不到被打開的端口(網絡組件sock api被攔截),更攔截不到相關的網絡數據包(網絡組件ndis api被攔截)了,我們使用的系統是在內核功能支持下運作的,如果內核變得不可信任了,依賴它運行的程序還能信任嗎?

但即使是rootkit這一類恐怖的寄生蟲,它們也並非所向無敵的,要知道,既然rootkit是利用內核和ring 0配合的欺騙,那麼我們同樣也能使用可以「越權」的檢查程序,繞過api提供的數據,直接從內核領域裡讀取進程列表,因為所有進程在這裡都不可能把自己隱藏,除非它已經不想運行了。也就是說,內核始終擁有最真實的進程列表和主宰權,只要能讀取這個原始的進程列表,再和進程api枚舉的進程列表對比,便能發現rootkit進程,由於這類工具也「越權」了,因而對rootkit進行查殺也就不再是難事,而rootkit進程一旦被清除,它隱藏自身的措施也就不復存在,內核就能把它「供」出來了,用戶會突然發現那個一直「找不到」的rootkit程序文件已經老實的呆在文件管理器的視圖裡了。這類工具現在已經很多,例如icesword、patchfinder、gdb等。

道高一尺,魔高一丈,因為目前的主流rootkit檢測工具已經能檢測出許多rootkit木馬的存在,因此一部分rootkit作者轉而研究rootkit檢測工具的運行檢測算法機制,從而製作出新一代更難被檢測到的木馬——futo rootkit。

國產優秀檢測工具icesword在futo面前敗下陣來,因為futo編寫者研究的檢測工具原型就是一款與之類似的black & light,所以我們只能換用另一款rootkit檢測工具darkspy,並開啟「強力模式」,方可正常查殺rootkit。

但是由於檢測機制的變化,darkspy要檢測到futo的存在,就必須保證自己的驅動比futo提前加載運行,這就涉及到優先級的問題,也是讓業界感覺不太滿意的一種方式,因為這樣做的後果會導緻系統運行效率下降,不到緊急關頭,都不要輕易採用這種方法,然而現在的瑞星卡卡助手所推廣的「破甲」技術,實現原理是與之類似的,它也會對系統造成一定影響,因而,這個介於安全和效率之間的選擇,唯有留給用戶自己思考了。



另一種隱藏:給自己做個「殼」

今年底,國內殺毒軟件廠商瑞星推出了2007測試版,細心的用戶應該都能觀察到,瑞星這次更新的重點基本在於「脫殼技術」,這個「殼」是什麼,為什麼廠商那麼重視呢?

「殼」(shell),顧名思義,就是一種包裹容器,在計算機方面,它指一種把應用程序壓縮精簡或者加密處理後用自身代碼形成一個新程序的技術,「殼」在運行時將自身包裹的程序資源釋放到內存中執行,就恢復了原來程序的面目,由於「殼」的初衷就是加密和精簡程序文件的體積,因此許多殺毒軟件其實根本無法檢測出一個加了殼的病毒,因為針對「殼」而產生的脫殼技術相對複雜,如何完善的檢測出大部分被「殼」處理過的病毒一直是業界的難題,利用這一特點,一部分病毒利用「殼」把自身包裹起來,因為殺毒軟件對其無能為力,病毒便能先發制人,把殺毒軟件消滅以後才釋放真實的病毒文件運行感染,這種明目張膽的隱藏可謂惡毒。

由於各種原因,我們只能等待殺毒廠商提供一套完善的解決方案,因為手工脫殼對於一般用戶來說是非常不實際的。

大雜燴:混合型木馬

「灰鴿子」,國內一款優秀的遠程控制工具,同時也是危害廣大用戶的木馬病毒,它是目前主流的一種結合了rootkit驅動、遠程線程注射的混合型dll木馬,它將兩個技術整合起來,最終形成了這種在正常模式下無法發現進程和文件的強大後門。

針對此類病毒,用戶需要結合icesword和process explorer等工具發現被篡改的ssdt和木馬dll文件,而後進入安全模式刪除。現在已經有流氓軟件掌握了高優先級啟動方法,使得其在安全模式下也能正常運作,如果遭遇這種惡劣病毒,用戶只能求助於dos了。

三. 「進化論」和「安全威脅」

病毒技術一刻不停的發展著,與之相對的反病毒技術也在追逐,這場貓和老鼠的大戰永遠不會停止,戰爭過後,留下的是面目全非的操作系統。雖然從某個角度來看,這種技術追逐會給業界帶來無數種計算機科技發展的可能,但是,普通用戶要在網絡上被迫「適者生存」的時代,還是不要到來的好。
創作者介紹

習慣成失落...

zerosmall 發表在 痞客邦 PIXNET 留言(0) 人氣()