上面的題目帶有“黑客”兩個字,請大家別誤會了,其實沒有多少是講黑客的,這完全是一篇菜鳥級的編程雜談,如果您已是高手,就不必在此浪費時間了 。
前幾天在網(wǎng)上看了“病毒”兄寫的《WIN下編程須知》一文,覺得在編程方面要寫出一篇適合初學者們看的入門級文章的確很重要,可惜病毒兄只在該文里介紹了線程、消息、句柄等幾個基本概念。很多初學者看了對編程還是感到很迷惑,一個從來沒有寫過程序的人如何入門?如何在短時間內(nèi)寫出自己的程序來?筆者帶著這些問題寫了這篇文章。這也是筆者在學習編程的初期所遇到的困惑,在此根據(jù)筆者的個人理解將其整理成文,希望能引起廣大菜鳥們的共鳴,對初學者們有所幫助。
從理論上說,任何一門語言都可以在任何一個系統(tǒng)上編程,只要找到該系統(tǒng)提供的“接口”和對系統(tǒng)內(nèi)部機制有深入的了解就可以了,至少我是這么認為的。正如c語言可以在windows下編程,也同樣可以在Linux上大放異彩一樣。
編程是一項很繁雜的工作,除了應(yīng)用編程工具之外,了解系統(tǒng)本身內(nèi)部工作機理非常重要,這是你寫出穩(wěn)定兼容的程序所必不可少的前提條件。你要在哪一種系統(tǒng)上編程就要對該系統(tǒng)的機制進行研究,至少你應(yīng)該知道一個程序在那個系統(tǒng)上是如何運行的。
一、了解Windows 內(nèi)部機制
Windows 是一個“基于事件的,消息驅(qū)動的”操作系統(tǒng)。
在Windows下執(zhí)行一個程序,只要用戶進行了影響窗口的動作(如改變窗口大小或移動、單擊鼠標等)該動作就會觸發(fā)一個相應(yīng)的“事件”。系統(tǒng)每次檢測到一個事件時,就會給程序發(fā)送一個“消息”,從而使程序可以處理該事件。每個Windows 應(yīng)用程序都是基于事件和消息的,而且包含一個主事件循環(huán),它不停地、反復(fù)地檢測是否有用戶事件發(fā)生。每次檢測到一個用戶事件,程序就對該事件做出響應(yīng),處理完再等待下一個事件的發(fā)生。Windows 下的應(yīng)用程序不斷地重復(fù)這一過程,直至用戶終止程序,用代碼來描述實際上也就是一個消息處理過程的while循環(huán)語句。
下面便簡單介紹一下與 Windows 系統(tǒng)密切相關(guān)的幾個基本概念:
⒈窗口:這是我要說的第一個概念。似乎是地球人都知道的事兒了,窗口是Windows本身以及Windows 環(huán)境下的應(yīng)用程序的基本界面單位,但是很多人都誤以為只有具有標題欄、狀態(tài)欄、最大化、最小化按鈕這樣標準的方框才叫窗口。其實窗口的概念很廣,例如按鈕和對話框等也是窗口哦,只不過是一種特殊的窗口罷了。從用戶的角度看,窗口就是顯示在屏幕上的一個矩形區(qū)域,其外觀獨立于應(yīng)用程序,事實上它就是生成該窗口的應(yīng)用程序與用戶間的直觀接口;從應(yīng)用程序的角度看,窗口是受其控制的一部分矩形屏幕區(qū)。應(yīng)用程序生成并控制與窗口有關(guān)的一切內(nèi)容,包括窗口的大小、風格、位置以及窗口內(nèi)顯示的內(nèi)容等。用戶打開一個應(yīng)用程序后,程序?qū)?chuàng)建一個窗口,并在那里默默地等待用戶的要求。每當用戶選擇窗口中的選項,程序即對此做出響應(yīng)。
⒉程序:通常說的程序都是指一個能讓計算機識別的文件,接觸得最多的便是.exe型的可執(zhí)行文件,這個不難理解。
⒊進程:說到進程,學過《操作系統(tǒng)》的人都很清楚,所謂進程就是應(yīng)用程序的執(zhí)行實例(或稱一個執(zhí)行程序)需要注意的是:進程是程序動態(tài)的描述,而上面說到的程序是靜態(tài)的描述,兩者有本質(zhì)的區(qū)別。舉個例子,從網(wǎng)上Down了一個瑞星殺毒軟件到C盤但沒有運行,那個.exe 可執(zhí)行文件叫做程序,它是一個二進制碼的文件。一旦雙擊了exe文件圖標運行程序,那個“正在運行著的瑞星殺毒”便稱為進程,它在雙擊的那一刻被系統(tǒng)創(chuàng)建,當你關(guān)機或者在任務(wù)欄的圖標上單擊鼠標右鍵選“退出”時,進程便消亡,徹底結(jié)束了生命。進程經(jīng)歷了由“創(chuàng)建”到“消亡”的生命期,而程序自始至終存在于你的硬盤上,不管你的機器是否啟動。
⒋線程:線程是進程中的一個執(zhí)行單元,同一個進程中的各個線程對應(yīng)于一組CPU指令、一組CPU寄存器以及一堆棧。進程本來就具有動態(tài)的含義,然而實質(zhì)上是通過線程來執(zhí)行體現(xiàn)的,從這個意義上說,Windows 中進程的動態(tài)性意義已經(jīng)不是很明顯了,只算是給程序所占的資源劃定一個范圍而已(個人觀點,純屬個人理解,不必引起爭議!),真正具有動態(tài)性意義的是線程。以前在大二學習操作系統(tǒng)課的時候就有個同學跟筆者提起這點,筆者還跟他駁得面紅耳赤呢!現(xiàn)在想想,覺得很有道理,不得不佩服那位同學對Windows內(nèi)部機制了解得如此清楚。之所以在此花那么多的篇幅說線程,是因為下面將要介紹到多線程編程技巧,如果不理解這點,那就很難應(yīng)用到實踐上,希望大家明白。
⒌消息:我們幾乎做每一個動作都會產(chǎn)生一個消息,在用鼠標指點江山的今天,鼠標被移動會產(chǎn)生WM_MOUSEMOVE消息,鼠標左鍵被按下會產(chǎn)生WM_LBUTTONDOWN的消息,鼠標右鍵按下便產(chǎn)生WM_RBUTTONDOWN消息等等。所有的這些都可以通過GetMessage,SendMessage等函數(shù)得到,以后的操作中我們會經(jīng)常接觸到這些函數(shù)。
⒍事件:何謂事件?從它的字面意思我們就可以明白它的含義,如在程序運行的過程中改變窗口的大小或者移動窗口等,都會觸發(fā)相應(yīng)的“事件”。
⒎句柄:單單一個“柄”字便可以解釋它的意思了,我們天氣熱搖扇子的時候只要抓住扇柄便可以控制整個扇子的運動了,在程序中也差不多是這個意思。通常一個句柄就可以傳遞我們所要做的事情。有經(jīng)驗的讀者肯定清楚,編寫程序總是要和各種句柄打交道的,句柄是系統(tǒng)用來標識不同對象類型的工具,如窗口、菜單等,這些東西在系統(tǒng)中被視為不同類型的對象,用不同的句柄將他們區(qū)分開來??纯碈++ 教材中是如何給句柄下定義的:“在Win32里,句柄是指向一個無值型對象(void *)的指針,是一個4字節(jié)長的數(shù)據(jù)”。雖然我對它的本質(zhì)是什么還是很迷惑,但我知道句柄并不是一個真正意義上的指針。從結(jié)構(gòu)上看,句柄的確是一個指針,盡管它沒有指向用于存儲某個對象的內(nèi)存位置(很多書都這么說,這正是我的迷惑所在),而實際上句柄指向的是一個包含了對該對象進行的引用的位置。在編程時,只要抓住了對象的句柄就可以對該對象進行操作了(我在《一個簡單木馬程序的編寫與偽裝策略》中說到的對QQ密碼的截獲就是要找到QQ登陸窗口的句柄后才開始截密行動的)。下面再舉個例子來說明句柄的運用:編一個程序,使QQ登陸窗口的號碼框和密碼框均變黑,相關(guān)代碼及解釋:
void __fastcall Tform1::formCreate(TObject *Sender) { HWND hCurWindow,HC,HE;//定義三個窗口句柄變量,hCurWindow用于存放QQ用戶登陸窗口的句柄,HC、HE分別存放 //號碼框和密碼框的句柄。 if((hCurWindow= FindWindow(NULL,"QQ用戶登錄"))!=0||(hCurWindow=FindWindow(NULL,"OICQ用戶登錄"))!=0) {//很明顯,調(diào)用FindWindow()函數(shù)去獲得QQ登陸窗口的句柄 String str; str.sprintf("0x%x",hCurWindow); } TCHAR wClassName[255];//類名變量 HC=GetWindow(hCurWindow, GW_CHILD);//得到號碼框的句柄 HE=GetWindow(HC, GW_HWNDNEXT);//接著得到密碼框的句柄 GetClassName(HE, wClassName, sizeof(wClassName));//得到類名 GetClassName(HC, wClassName, sizeof(wClassName));//得到類名 EnableWindow(HE,false);//使窗口失效 EnableWindow(HC,false);//使窗口失效 }
以上代碼在C++ Builder下編譯通過,只要運行次程序,QQ登陸窗口的號碼框和密碼框馬上變黑色,無非是EnableWindow()函數(shù)所起的作用。你還可以添加一個Timer控件,將上面的代碼copy到void __fastcall Tform1::Timer1Timer
(TObject *Sender)函數(shù)中,并在后邊加上這一句代碼:
SendMessage(hCurWindow,WM_CLOSE,0,0); 使QQ一啟動就關(guān)閉,讓別人永遠也用不了QQ,挺有趣兒的哦:).
⒏API與SDK:API是英文 Application Programming Interface 的簡稱,意為“應(yīng)用程序接口”,泛指系統(tǒng)為應(yīng)用程序提供的一系列接口函數(shù)。其實質(zhì)是程序內(nèi)的一套函數(shù)調(diào)用,在編程的時候可以直接調(diào)用,而不必知道其內(nèi)部實現(xiàn)的過程,只知道它的原型和返回值就可以了,此外,手頭經(jīng)常放著一本“Windows API大全”之類的書也是必不可少的,不然你根本不知道哪些API是干什么用的,瞎編也編不出什么東西來。在后面我們會介紹調(diào)用API編程的例子,調(diào)用API編程工作雖然煩瑣,但由于API函數(shù)都被封裝在dll庫里,程序只有在運行的時候才調(diào)用的,因此程序的體積小而且運行效率高。SDK是英文 Software Development Kit 的縮寫,指“軟件開發(fā)工具包”,在防火墻的設(shè)計中就經(jīng)常涉及到SDK。有關(guān)基本的概念就談這些,那些C/C++的基本語法、什么是面向?qū)ο蟮戎R請大家查閱相關(guān)的書,此類書籍各大書店已汗牛充棟,不再多敘。下面直接談?wù)務(wù)Z種和編程工具的選擇問題,這也是初學者們最迷惑的問題。
二、編程語言以及工具的選擇:
從上面的介紹我們對Windows 有了進一步的了解,現(xiàn)在就該開始行動了,選擇要學的語言和工具是第一步,而且是非常重要的一步工作,筆者建議一切以簡單、易接受為原則,不然你會自信心大減的,何必偏要跟自己過不去自討苦吃呢?在開始的時候很多人都感到迷惑,目前的編程語言那么多,有c、c++、c#、java、匯編、html等等,究竟學哪些好呢?最開始我該學什么呢?甚至有人將vc、c++ builder也列為兩種不同的語言!這些都是對編程語言缺乏了解造成的。筆者開始的時候也犯過同樣的錯誤,曾經(jīng)給自己寫過一份計劃書:先學c語言,接著學c++、c#、java、匯編、vb、vc、c++ builder……,哪一種語言用多少時間去專攻等等,現(xiàn)在回想起來覺得多么的可笑!只要學得精,一門就夠了。從實用的角度來講,C++ 是最好的選擇(個人意見,其實每一種語言都很好),而VC和C++ Builder是其相應(yīng)開發(fā)工具的兩大主流,筆者極力推薦初學者使用C++ Builder,因為很容易上手,如果一下子就用VC的話,也許會打擊你的自信心:)。
三、談?wù)劥龠M編程能力提高的兩個途徑
如果你是一個黑客技術(shù)的狂熱者的話,到雅虎去搜索黑客教程的時候就會發(fā)現(xiàn),很多的中文教程在談到如何進行黑客編程時,十有八九都會介紹以下兩大最佳途徑:一、讀程序;二、寫程序,并且都提出了教程作者的看法,下面我想談?wù)勥@方面的個人觀點。
⒈讀程序:我將讀程序放在前面是有原因的。在你沒有閱讀過一份完整的源代碼之前,你別指望能寫出有多好的程序來!這是對每一位初學者的忠告也是警告,而且必須具備一定的語言基礎(chǔ)知識,這里的基礎(chǔ)知識主要是指語法知識,最起碼要能讀懂別人的程序的每一行意思。有沒有程序的設(shè)計思想,在這個時期并不重要,只要具備一定的語法基礎(chǔ)就可以了,思想可以通過閱讀完別人的源程序后分析得來。記得在大一學習C語言的時候,我們都很重視語法的學習,整天都看教材、做練習,而且趕在老師的講課前預(yù)習,課后又復(fù)習鞏固,將一些語法點記得滾瓜爛熟,可后來一到做課程設(shè)計的時候,坐在電腦面前簡直是老鼠拖雞蛋—
無從下手了,而且不斷的問自己:“我平時的努力哪去了?語法都會了呀,怎么還是做不出程序來?”相信很多人都像筆者以前那樣,錯誤地以為學會了語法就等于掌握了編程。編程的能力包括經(jīng)驗、技巧、耐心等幾個因素,而并非想象中的那樣簡單,更不要以為編程就是簡簡單單的寫程序!其實學一門語言并不需要刻意去記那些條條框框的語法,在看代碼的時候,遇到了不明白的地方再去查相關(guān)的資料,一點一點補充基礎(chǔ)知識再配合源程序的思路,這時的理解才是最深刻的,我可以肯定地說,這個時候?qū)φZ法的接受程度絕對比你剛開始時的死記要強!讀程序也不能單純地讀,要真正做到“俯而讀,昂而思”。好的代碼是百讀不厭的,比如Shotgun的那道構(gòu)造洪水Ping攻擊的代碼,我至少讀了20遍。筆者喜歡將從網(wǎng)上搜集來的代碼打印到紙上(盡管學校的打印費貴得要命,打一份代碼就得花去十幾塊甚至幾十塊大洋~~~),然后邊看邊做好眉批,遇到一個新函數(shù)記下它的功能,一些忘記了的知識在旁邊標出來,還可以寫上對程序的看法等等。特別是遇到了一些新的API函數(shù),最好標出來,對你以后編程的時候也許會用得著,最后別忘了分析一下程序的思路,這樣對你以后編寫類似的程序很有幫助的。
⒉寫程序:問題可談到點子上了,學那么多語言,讀那么多程序最終還不是為了寫程序,做出適合需要的軟件來?“君子性非異也,善加于物也”,筆者認為一切從借鑒開始,先是修改別人的程序,等到有了一定的程度再寫出屬于自己的程序。剛開始寫程序,不要奢望一下子寫出很出色的程序來,“萬丈高樓平底起”,編程貴在動手,只要你動手去寫了,就算只有一句“printf(“Hello!”);”也是一次進步!此外,還要依照自身的能力循序漸進地寫,開始的時候?qū)懸稽c功能簡單的、篇幅短小的代碼,力求簡潔、完整,“麻雀雖小,但五臟俱全”,然后在此基礎(chǔ)上進行擴充,一點一點添加功能,下面筆者摘錄一位國內(nèi)一流編程高手、“豪杰超級解霸”的作者梁肇新的編程心得,請大家看
看一個成功的程序員是如何寫程序的,希望對廣大菜鳥有所啟發(fā):寫程序的方法:在Win98的環(huán)境中,先寫主干,用最少的代碼實現(xiàn)最基本的功能。然后一點點添加功能,每加一點都要調(diào)試。盡量少用動態(tài)分配、全局變量。充分利用操作系統(tǒng)直接提供的API。在Win98下調(diào)試通過之后,再在Win95下調(diào)試通過,然后是Win97,WindowsME,WinNT4.0。這樣才能寫出穩(wěn)定、快速的程序。
給程序員的建議:1、不要急于求成,這樣往往欲速不達。2、不要什么東西都想學,什么都沒掌握。3、每天都要自我總結(jié),分析自己的錯誤率和廢碼率,不斷加強自我管理。4、代碼格式很重要。代碼要規(guī)范、嚴謹,效率要高。5、不要盲從簡單的開發(fā)工具(這點筆者不是很同意,最起碼要有一定的功底的人才敢這么說)。6、有了成果要公開,不要舍不得,不然很快會過時的(以上兩段摘自《程序員》增值合訂本2001.上冊P18,請讀者前往參考)。
參考書籍:
《Windows C 程序設(shè)計》,清華大學出版社
《超級解霸梁肇新》,《程序員》合訂本
黑客編程的幾個基本技巧
以下將要談到的幾個基本技巧很重要,雖然對于編程高手來說這是在玩小孩子把戲,但對于一位初學者,掌握以下幾個技巧將為你的編程掃清道路,而且很容易編寫出有趣的程序,培養(yǎng)你對編程的興趣。
技巧⒈學會修改注冊表。
相信大家都知道當瀏覽了一些網(wǎng)頁惡意代碼,IE標題、默認主頁等被改得面目全非,這就是通過改動注冊表來更改系統(tǒng)設(shè)置的例子。Windows中的注冊表是個好東東,它是windows系統(tǒng)的靈魂,是許多軟件記錄數(shù)據(jù)的地方(當然也包括windows本身)。windows通過它記錄大量的數(shù)據(jù),然后在下一次啟動時再讀取相應(yīng)的數(shù)據(jù)來設(shè)置系統(tǒng)。通過控制注冊表就可以控制整個系統(tǒng),所以很多的黑客程序都在注冊表上動手腳(尤其是木馬程序和作惡劇程序),學會修改注冊表可以實現(xiàn)一些有趣而強大的功能。我們完全可以通過編程來操作注冊表,達到與手動更改注冊表編輯器產(chǎn)生一樣的效果。“超級兔子”中的大部分功能就是通過修改注冊表來完成的。操作注冊表有專門的API函數(shù),大家可以參考有關(guān)資料,下面筆者以C++ Builder為例說明如何在程序中操作注冊表:
程序二:編程修改IE標題內(nèi)容
新建一個工程,在Unit1.h文件中包含Registry單元: #include 然后就可以在.cpp文件操作注冊表了,接著來!在窗體的OnCreate()里加入以下代碼(你可以在try{}里面加入任何操作注冊表的代碼): TRegistry* Registry; Registry = new TRegistry();創(chuàng)建一個TRegistry類型的對象Registry,用于修改注冊表。 try{ Registry->RootKey = HKEY_CURRENT_USER;//設(shè)置主鍵,這是必不可少的,設(shè)置好主鍵后,就可以操作這個主 //鍵下所有的鍵值了。 if( Registry->OpenKey("Software\Microsoft\Internet Explorer\Main",FALSE))//調(diào)用OpenKey() //打開. //括號里所指的鍵 { Registry->WriteString("Window Title",”臺灣是中國的一部分,世界上只有一個中國!”); //調(diào)用WriteString()往注冊表里寫入IE標題 Registry->CloseKey();//關(guān)閉該鍵 } else {//如果打開失敗的話 Registry->CreateKey("Software\Microsoft\Internet Explorer\Main");//就調(diào)用CreateKey() //新建上述鍵 Registry->WriteString("Window Title","臺灣是中國的一部分,世界上只有一個中國!");//再寫入//IE標 //題內(nèi)容 Registry->CloseKey();//最后關(guān)閉該鍵,這個也不能忽視,它跟上面的OpenKey成對使用的}//End of try __finally {//要是出錯,跳到這里處理 Registry->CloseKey();//關(guān)閉所要打開的鍵 delete Registry;//銷毀Registry對象,釋放資源。 }
編譯運行上面的代碼就可以將IE的標題改為“臺灣是中國的一部分,世界上只有一個中國!”了。筆者寫了個小程序,可以測出當前的IE標題和默認主頁是什么,并可隨意修改他們,還可以禁止別人修改你的默認主頁和注冊表編輯器.。
技巧⒉調(diào)用API編程
其實這是最簡單的,API是系統(tǒng)在DLL里為我們提供的程序接口,可以直接調(diào)用的。只要我們有一本《Windows API大全》之類的書就足夠了,下面舉個簡單的例子:
程序三:調(diào)用API函數(shù)隱藏Windows的任務(wù)欄:
HWND WndHandle;//定義句柄類型變量
WndHandle=FindWindow("Shell_TrayWnd",NULL);//調(diào)用API函數(shù)FindWindow()獲得任務(wù)欄的句柄
ShowWindow(WndHandle,SW_HIDE);//再調(diào)用API函數(shù)ShowWindow()隱藏任務(wù)欄
大家看到,在上面調(diào)用API函數(shù)FindWindow()和ShowWindow()的過程中,只要我們知道函數(shù)的名字和括號里的參數(shù)是什么就行了,至于實現(xiàn)的過程不必理會,也輪不到我們這些菜鳥去理會:)學會調(diào)用API,你可以寫出功能強大的程序來,這一技巧對于初學者來說是必須掌握的(代碼請參考黑防光盤)。
技巧⒊多線程編程技術(shù)
通過上一篇的介紹,大家都很清楚線程的概念了,它是進程內(nèi)部的一個執(zhí)行單元(如一個函數(shù)等),上期說了那么多理論,現(xiàn)在該派上用場了。編寫多線程應(yīng)用程序是指使程序在運行時創(chuàng)建多個線程并發(fā)地運行于同一個進程中。今年6月份橫空出世的“中國黑客”病毒不是采用了全球獨創(chuàng)的“三線程技術(shù)”嗎?雖然筆者沒機會分析它的樣本代碼,但此種病毒的工作效率如此之高是與它的多線程技術(shù)分不開的。
使用多線程技術(shù)編程有如下優(yōu)點:
①提高CPU的利用率。由于多線程并發(fā)運行,可以使用戶在做一件事情的時候還可以做另外一件事。特別是在多個CPU的情況下,更可以充分地利用硬件資源的優(yōu)勢:將一個大任務(wù)分成幾個小任務(wù),由不同的CPU來合作完成。
②采用多線程技術(shù),可以設(shè)置每個線程的優(yōu)先級,調(diào)整工作的進度。
清楚了使用多線程技術(shù)的優(yōu)勢之后,下面便來談?wù)勅绾卧贑++ Builder環(huán)境下開發(fā)多線程的應(yīng)用程序,在C++Builder 環(huán)境中,通過 TThread 類就可以很方便地編寫多線程應(yīng)用程序(但不能直接使用,因此要派生新類),
具體流程如下:
從TThread 類派生出一個新的線程類->創(chuàng)建線程對象->設(shè)置線程對象的屬性項->掛起或喚醒線程(根據(jù)具體情況操作)->結(jié)束線程。要說明一點的是:在應(yīng)用程序中要合理地設(shè)置線程的優(yōu)先級。不要因為某些線程的優(yōu)先級很高而使其他一些線程因為等不到CPU的處理時間而被“餓死”,也不要因為線程的級別都差不多而導致的頻繁切換花費大量的CPU時間。(本段引自《C++ Builder 5 編程實例與技巧》P284)。
技巧⒋讓程序?qū)崿F(xiàn)后臺監(jiān)控
這是一個很基本的技巧。如果你是一個木馬程序的愛好者,當你閱讀眾多的木馬源程序的時候,就會發(fā)現(xiàn)100%的木馬程序都很注意自身的后臺監(jiān)控本領(lǐng),也就是隱身技術(shù),面對不同的系統(tǒng)要施展不同的對策才能實現(xiàn)。很多殺毒程序就采用了這種后臺監(jiān)控技術(shù),使程序隨著系統(tǒng)的啟動而運行,然后在后臺悄悄地監(jiān)視系統(tǒng)的一舉一動,一發(fā)現(xiàn)有不對路的程序就把它“揪”出來示眾。實現(xiàn)程序的后臺監(jiān)控技術(shù)有如下幾個關(guān)鍵:
①正常運行時,不顯示程序的窗體;
②系統(tǒng)每次啟動都自動運行程序一次;
③程序圖標不顯示在任務(wù)欄上;
④不顯示在按Ctrl+Alt+Del 調(diào)出的任務(wù)列表中;
⑤通過熱鍵可以調(diào)出隱藏的窗體
實現(xiàn)方法:對于①,要不顯示窗體,我們可以編輯WinMain函數(shù),設(shè)置ShowMainform值為False就可以隱藏程序的窗體了。參考代碼:Application->ShowMainform = false ;對于②,可以利用技巧1所介紹的方法修改注冊表,鍵值如下:HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun ,使用的是WriteString()方法。這是冰河等多種舊木馬慣用的啟動手段之一(當然還有文件關(guān)聯(lián)、注入dll等方法);對于③,要使程序圖標不顯示在任務(wù)欄上,也很簡單,調(diào)用API函數(shù)SetWindowLong 可以讓程序運行后不出現(xiàn)在任務(wù)欄里,不過要放在窗體的OnCreate()里面。代碼如下:
SetWindowLong(Application->Handle,GWL_EXstyle,WS_EX_TOOLWINDOW);
對于④,調(diào)用RegisterServiceProcess API 函數(shù)將程序注冊成為一個服務(wù)模式程序,讓它運行在較高的優(yōu)先級下,就不會出現(xiàn)在程序列表中(對Win9X有效,WinNT/2000/XP下無效)。具體的代碼請參考筆者的《一個簡單木馬程序的編寫與偽裝策略》一文,不在此重敘對于⑤,要先定義捕獲Windows消息WM_HOTKEY的鉤子函數(shù),然后向Windows 加入一個全局原子,并保留其句柄,最后向Windows登記熱鍵,這個可以調(diào)用API函數(shù)RegisterHotKey來實現(xiàn)。
技巧⒌使用定時觸發(fā)器
在C++ Builder 環(huán)境下,定時觸發(fā)器即Timer控件,有時候我們希望程序隔一段時間重復(fù)執(zhí)行相同的動作,比如對QQ密碼截獲的時候,就要隔一段間隔尋找一次QQ登錄窗口。在C++ Builder中,只要將執(zhí)行這些動作的代碼放到一個Timer中去就OK了。聽說“中國黑客”病毒運行幾分鐘后就自動創(chuàng)建一個新的線程,用于尋找OICQ的“發(fā)送消息”窗口,在10分鐘內(nèi)一直在找,一旦找到就將“去*****功”等帶有政治色彩的言論發(fā)送給受害者QQ上的好友,10分鐘后自動結(jié)束該線程。我想在查找“發(fā)送消息”窗口的10分鐘內(nèi)就運用了定時器,該病毒是用匯編開發(fā)的??墒窃贑++ Builder中是如何運用的呢?其實控件的出現(xiàn)使得編程變得很簡單,添加一個Timer控件,設(shè)置幾下控件的屬性,雙擊Timer控件,將代碼放到里面去就行了。程序執(zhí)行的時候,相隔指定的時間就重復(fù)執(zhí)行里面的代碼了。實際上筆者在上一期的“程序一”中尋找QQ登錄窗口時,就運用了定時器.有關(guān)編程技巧的介紹到此為止,請讀者參考另類書籍,掌握更多的黑客編程技巧,編寫出受歡迎的黑客程序來。
四、Socket 編程與網(wǎng)絡(luò)通信基礎(chǔ)
由于本文的主題是“黑客編程基礎(chǔ)”,而黑客是互連網(wǎng)上“來無影,去無蹤”的黑衣人,如冰河、網(wǎng)絡(luò)神偷等黑客程序都是基于互連網(wǎng)的,談黑客編程離開網(wǎng)絡(luò)編程就會大失其味。所以,下面接著談?wù)劸W(wǎng)絡(luò)編程,大凡基于網(wǎng)絡(luò)應(yīng)用的程序都離不開Socket。Socket 為套接字之意,是作為計算機與計算機之間通信的接口。有關(guān)Socket的概念在第6期《黑客防線》的《Socket 編程的基礎(chǔ)和基本過程》一文中有詳細的描述,請大家參考,不在此多敘。需要指出的是:Winsock 是訪問眾多的基層網(wǎng)絡(luò)協(xié)議的一種接口,在每個Win32平臺上,它都以不同的形式存在著,Winsock 是網(wǎng)絡(luò)編程的接口,不是協(xié)議,這是容易弄錯的地方?,F(xiàn)在來談?wù)刉insock 編程的過程,大凡在Win32平臺上的Winsock編程都要經(jīng)過下列的基本步驟:定義變量->獲得Winsock版本->加載Winsock庫->初始化->創(chuàng)建套接字->設(shè)置套接字選項->關(guān)閉套接字->卸載Winsock庫,釋放所有資源。下面以一道極其簡單的程序來說明如何進行Winsock編程。程序四:編一個程序來獲取本地機器的IP地址。使用Winsock提供的API函數(shù)是最基本的網(wǎng)絡(luò)技術(shù),為了給初學者看個清楚,筆者打算在Visual C++ 和C++ Builder下各寫一個,便于大家區(qū)分這兩種不同的編程工具的特性(對于本程序來說,他們都差不多,而對于某些通信程序,他們實現(xiàn)起來就相差很遠了,但本質(zhì)是差不多的)。先來看Visual C++ 下的源程序,實現(xiàn)步驟:打開Visual C++ ,從“File”菜單中的“New”新建一個工程,選中“Win 32 Console Application” ,意思是說生成的是Win32的控制臺程序。另外,初學者要注意一點:只要程序中用到了 Winsock API 函數(shù),都要在工程設(shè)置的Link 中增加 Ws2_32.lib 文件,不然程序?qū)⒉荒芡ㄟ^編譯,方法是:點擊“Project”菜單,選擇“Settings... ALT+F7” ,在彈出的“Project Settings”對話框右側(cè)選“Link”標簽,再在“ProjectOptions”下方的編輯框中增加Ws2_32.lib文件,點“OK”就可以了。
加載好文件之后,就可以在CheckIP.cpp文件里加入以下代碼了:
//-------Begin from ------------ //包含需要使用的頭文件 #include "stdafx.h" #include "windows.h" #include #include "stdio.h" #include "stdlib.h" #include "string.h" void CheckIP(void) //定義CheckIP()函數(shù),用于獲取本機IP地址 { WORD wVersionRequested;// WORD類型變量,用于存放Winsock版本的正確值SADATA wsaData; char name[255];//定義用于存放獲得的主機名的變量 CString ip;//定義IP地址變量 PHOSTENT hostinfo; wVersionRequested = MAKEWORD( 2, 0 ); //調(diào)用MAKEWORD()獲得Winsock版本的正確值,用于下面的加載Winsock庫 if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) { //現(xiàn)在是加載Winsock庫,如果WSAStartup()函數(shù)返回值為0,說明加載成功,程序可以繼續(xù) //往下執(zhí)行 if( gethostname ( name, sizeof(name)) == 0) { //如果成功地將本地主機名存放入由name參數(shù)指定的緩沖區(qū)中 if((hostinfo = gethostbyname(name)) != NULL) { //這是獲取主機名,如果獲得主機名成功的話,將返回一個指針,指向hostinfo,hostinfo //為PHOSTENT型的變量,下面即將用到這個結(jié)構(gòu)體 LPCSTR ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list); //調(diào)用inet_ntoa()函數(shù),將hostinfo結(jié)構(gòu)變量中的h_addr_list轉(zhuǎn)化為標準的點分表示的IP //地址(如192.168.0.1) printf("%sn",ip);//輸出IP地址 } } WSACleanup( );//卸載Winsock庫,并釋放所有資源 } } int main(int argc, char* argv[])//主函數(shù),程序的入口 { CheckIP();//調(diào)用CheckIP()函數(shù)獲得、輸出IP地址 return 0;//由于main()定義為int型,所以應(yīng)帶回一個int型的數(shù)值 } 下面接著來看看在C++ Builder 下如何實現(xiàn),其實兩者的思想是一樣的,只是在C++ Builder下實現(xiàn) 的界面友好點而已,實現(xiàn)方法:打開C++ Builder 5,默認情況下已經(jīng)新建一個工程,保存這個工程文件 就可以了,構(gòu)造如下面圖4所示的界面,在相應(yīng)之處添入下面的代碼即可程序代碼: //包含頭文件 #include #include #pragma hdrstop #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" Tform1 *form1; __fastcall Tform1::Tform1(TComponent* Owner) : Tform(Owner) { } void Tform1::GetHostIpAddress() {// GetHostIpAddress()獲得本機IP地址 struct hostent *thisHost; struct in_addr in; char MyName[80]; char *ptr; WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 0 ); err = WSAStartup( wVersionRequested, &wsaData ); if( err != 0 ) return; if(LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 ) { WSACleanup( ); return; } if(gethostname(MyName,80)==SOCKET_ERROR) return; if(!(thisHost=gethostbyname(MyName))) return; memset((void *)&in,sizeof(in),0); in.s_addr=*((unsigned long *)thisHost->h_addr_list[0]); if(!(ptr=inet_ntoa(in))) return; WSACleanup( ); Edit1->Text=AnsiString(ptr);} void __fastcall Tform1::formCreate(TObject *Sender) { GetHostIpAddress();} void __fastcall Tform1::Button1Click(TObject *Sender) {Close();//添加一個“確定”按鈕,點擊即關(guān)閉程序。}
程序在 C++ Builder 5 下編譯通過,通過比較你會發(fā)現(xiàn)他們是大同小異的,對于同一程序,
兩者工具各有秋千,至于選擇哪種由你決定,最好是兩者相得益彰?!芭R淵羨魚,不如退而結(jié)網(wǎng)”,雖說“通往電腦的路不止一條”,然而對于編程,道路卻只有一條,就是:動手去做,親身實踐。
兄弟,愿你成為一個出色的舵手,用代碼去駑駕電腦的世界,用編程去填充七彩的人生!