黑客與C語言
「黑客」這個詞想必我們已經如雷貫耳了。我們一聽到黑客通常在大腦中的印象就是一群穿著黑衣,躲在小屋裡偷偷用著數台電腦針對某組計算機,神不知鬼不覺地進行攻擊。他們通常會攻入一些網路或系統,潛伏在一些大型網站,窺探甚至竊取用戶隱私,比如竊取你的QQ號、微信號、你的郵箱,諸如此類的事情。他們通常擁有高超的技術,於無形中做很多我們或驚嘆或驚嚇的事。他們就像《海盜船》的Jack船長一樣分明是「惡勢力」,卻又詭異、神秘,有超強的能力,而好萊塢中各類電影和電視劇對黑客的渲染更是使我們對他們的世界充滿了探究的意願。
其實黑客有時候也是統稱,也有灰客、白客。然而,以上這只是狹義上的黑客,其實在現在的英語中用Cracker來描述這種專門搞計算機系統以及網路系統破壞的人。而廣義上講,黑客(Hacker)對於程序員而言其實是指精通於計算機以及計算機網路的人。所以這麼一來我們就能理解為何許多偉大的系統締造者、編程語言締造者能被稱為黑客了,儘管他們並不是以破壞系統而聞名。
1. Unix系統創始人Dennis Ritchie
這裡首先介紹的就是大名鼎鼎的Dennis Ritchie,於2011年12月逝世。他是偉大的Unix系統的創始人,同時也是著名經典的C編程語言的締造者。曾在1983年從ACM獲得圖靈獎。在早些時候,Unix系統其實是用彙編語言開發的,那個時候Dennis Ritchie與另一個偉大的黑客Ken Thompson(現就職於Google,並打造了Go語言)在貝爾實驗室一起實現了在DEC生產的PDP-7計算機上的Unix系統。那時,他倆準備將此操作系統移植到PDP-11上。剛開始,PDP-11上的Unix系統仍然是用彙編語言開發的,但是因為PDP-11與PDP-7的變化還是有不少的,所以那時候開發者打算用B語言來重寫該系統。B語言是由Ken Thompson從BCPL編程語言簡化而來的。然而,B語言無法很好利用PDP-11上的某些特性,比如位元組定址,這就使得Dennis Ritchie與Ken Thompson一起打造了更靈活、更強大的C編程語言。而C語言一開始也就是針對PDP-11計算機上的Unix系統而打造的。在1972年,Unix中的大部分代碼都用C語言重寫。到1973年,引入了結構體類型 struct 之後,C語言就基本成型了,因為它足夠強大,所以足以擔當Unix系統內核大部分功能的實現。而此時的C語言也被稱作為「K&R C」。
當然,Dennis Ritchie也有他調皮的一面。在早期開發的Unix系統中,他特意留了一些後門。其他開發者用自己賬號登錄系統之後,他們發現自己的文件或某些資料被改動過,一直很納悶。他們後來通過排查,發現了當時Unix系統的一個漏洞,把它堵上後,但沒過多久自己的賬號又被侵入了。後來才知道,原來是Dennis Ritchie在C語言編譯器上埋下了後門,所以只要他們用編譯器編一次程序,那麼漏洞就會自動生成,哈哈……這個也讓筆者聯想起前兩年很多iOS開發者通過百度網盤下載帶有後門的Xcode,使得很多App受到木馬侵襲,而且該木馬能躲過Apple的代碼審核機制。儘管該漏洞破壞性不大,因為iOS系統以及iOS設備處理器的本身運行安全機制很厲害,不過這也說明了來自編譯器的後門是防不勝防的。
2. Linux系統內核締造者Linus Torvalds
下面說的這位黑客應該大家非常熟悉了,就是大名鼎鼎的Linus Torvalds,Linux系統內核的締造者,Git版本管理工具的締造者。Linus Torvalds從1988到1996年在自己祖國芬蘭的赫爾辛基大學修完了碩士學位。在此期間,他看了Andrew Tanenbaum的一本書《Operating Systems: Design and Implementation》,在此書中Andrew描述的是MINIX系統,該系統是Unix剝離下來的一個用於教學的版本。此時,由於在芬蘭很難獲得軟體,所以這也促成了Linus Torvalds喜歡自己動手的習慣,他購買了一套Sinclair QL,然後自己為它寫了一套彙編器以及編輯器,然後自己獨立編寫了一個類似吃豆人(Pac-Man)的小遊戲,稱為Cool Man。在1991年,他購買了基於Intel 80386的IBM PC,同時在此之前也收到了MINIX的一個拷貝,從而他就開始了在Intel 80386上的Linux內核開發。Linux的第一個版本正式版本1.0在1994年3月14號發布。在2005年,Linus創建了Git這一版本控制系統(VCS)的開源項目,基於GPLv2許可證。現在我們看到很多項目、工具以及網站都會默認使用Git工具進行版本控制,包括Xcode,GitHub等等。
當然,Linus Torvalds跟不少程序員一樣,也有偏執、狂傲的一面。比如在開發Git項目過程中,有位開發者表示Git項目用的都是純C語言而不是C++表示不可理解,而且也直言不諱:「別拿可移植性說事,那是屁話」。並且還指出,蠻力地直接操作文本,既啰嗦又易錯,而且很難跟上高層代碼邏輯。當時Linus Torvalds對此發出了強烈的不滿!他一上來也爆粗口——「YOU * are full of bull shit」,緊接著他開始炮轟C++了,哈哈。大致意思如下:
C++是一種可怕的語言。而且因為有大量不夠標準的程序員在使用而使情況更糟,以至於極容易產生徹頭徹尾的垃圾(total and utter crap)。老實說,選擇C就是為了把C++程序員踢出去。……我有這樣的結論,任何喜歡用C++而不是C開發項目的程序員可能都是我希望踢出去的人,免得他們來搞亂我參與的項目。C++會導致非常非常糟糕的設計選擇。你們這些C++程序員總是一上來就用語言的那些』漂亮的』庫特性比如STL、Boost和其他徹頭徹尾的垃圾,這可能對你們的程序有所『幫助』,但是卻會導致:
(1)當庫無法工作時無窮無盡的折磨(別跟我說什麼STL尤其是Boost很穩定而且可移植性很好,那全是屁話,而且一點都不可笑)
(2)低效的抽象編程模型,可能在兩年之後你會注意到有些抽象效果不怎麼樣,但是所有代碼已經依賴於圍繞它設計的『漂亮』對象模型了,如果不重寫應用程序,就無法改正。
呵呵,其實Linus說得也確實沒錯。對於一些系統級項目,使用C++甚至更高級的編程語言可能反而會使整個項目難以維護,因為當代碼量上升的時候,很多設計需要圍繞原有的設計模型進行。這就好比洗衣機的滾筒,洗衣的次數多了,滾筒上就會慢慢沾滿各種碎衣料,然後越滾越多。C語言的設計理念就是專註於功能模塊,而不是以某個特定的設計模型為中心展開堆碼,這也是C語言的靈活性所在。
以上我們談到的是Hacker這個詞,他是一個名詞,用於表示某類人。而我們日常所說的黑客還能做動詞使用,其實也就是對應英語中Hack這個單詞。Hack本意是劈、砍、亂踢這類意思,因而當它用於計算機系統時就是指對系統進行猛烈攻擊,從而找到其漏洞。現在由於Hack的使用範圍又廣了,它還能用於編程語言。像Apple在2014年推出Swift編程語言時就稱它為Hackable programming language。這裡的Hackable就是說該編程語言是可用來做各種另類玩法的,在現有語法體系中能玩出令人意想不到的效果,寫出驚世駭俗的代碼來。而C語言也是Hackable的。因為它靈活、強大,不死板,所以我們很多時候可以用C語言的語法糖實現各種相當不錯的API封裝以及功能實現。我這裡舉兩個簡單的例子。
像我們用C語言在開發一套程序時,有時為了調試方便會自己定義一個用於列印輸出日誌的介面,在調試模式將它開啟,在發布模式將它屏蔽。對於遵循C99的編譯器,我們通常會這麼定義:
#ifdef DEBUG
#define DEBUG_LOG(...) (void)printf(__VA_ARGS__)
#else
#define DEBUG_LOG(...) (void)0
#endif
而對於不遵循C99標準的C語言編譯器,並且不能使用不定參數個數的宏定義時我們如何定義呢?我們初步能想到的是以下這種方式:
#ifdef DEBUG
#define DEBUG_LOG (void)printf
#else
#define DEBUG_LOG (void)
#endif
這種定義方式基本沒什麼問題。不過當我們碰到以下這種代碼時,這種定義方式在發布模式下的行為會與前面C99模式的有所不同。
int a = 10;
DEBUG_LOG("a = %d
", ++a);
我們請注意看,這裡在DEBUG_LOG中對所要列印的變數a進行了遞增操作,從而使得變數a在調用DEBUG_LOG之前產生了副作用。依照C99那種定義方式,在發布模式下,由於整個DEBUG_LOG(…)這個宏被定義為了 (void)0,所以這裡面的表達式都不會被擴展出來,因此++a這個表達式是不存在於源代碼中的。而在上面C90模式下的實現方式由於沒有屏蔽++a這個表達式,從而會使它產生副作用。那如果我們想在發布模式下與C99那種形式一樣屏蔽掉DEBUG_LOG宏中所有表達式的副作用該如何實現呢?其實非常簡單!在C90中就已經有了編譯時行為的操作符——sizeof!sizeof操作符內的表達式在C90中是不會產生任何副作用的。同時,由於對於列印函數來說,必定存在一個表示字元串的表達式,因此我們也無需擔心傳入的表達式是否可能為void表達式。所以我們可以在發布模式下這麼定義DENUG_LOG:
#define DEBUG_LOG (void)sizeof
非常神奇吧~正因為C語言有各種形式的類型、操作符、預處理器的存在,所以我們可以用它實現多種功能,從而達到自己期望的效果。
我們再舉一個例子,是關於聯合體的。聯合體是個好東東!它一般用於抽象數據類型,從而可使得該數據類型在某一特定場合是一種類型,再另一種特定場合又是另一種類型,但是所佔的存儲空間是其中最大的成員那個。所以它既能做到類型抽象的作用,同時也能縮減存儲空間,對於一些系統開發而言很有幫助。我們下面想定義一個聯合體類型的常量數組,但是該常量數組中每個元素的數據類型可能是不同的。在遵循C99標準的代碼中我們可能會這麼寫:
static const union MyData
{
int i;
float f;
}sc_list[] = {
{.i = 10},
{.f = 0.5f},
{.i = 20}
};
如果是在不遵循C99標準的C語言中該如何表示呢?我們這裡能看到,第二個元素是直接對f單精度浮點類型的成員進行初始化,所以如果我們直接寫0.5f那由於其實元素是int類型,編譯器仍然會將它轉為int類型,從而變為整數0。其實如果我們知道在當前C語言環境中倘若單精度浮點用的是遵循IEEE754規格化浮點數表示的話,那麼我們可以直接用IEEE754對二進位浮點數的表示來做替換。這裡,0.5在IEEE754標準中32位單精度浮點的表示為0x3F000000,所以我們可以用以下代碼進行替代:
static const union MyData
{
int i;
float f;
}sc_list[] = {
10,
0x3F000000,
20
};
這就是一種Hack方法。感謝各位能看完此貼,本貼主要討論了關於黑客的一些科普介紹,並且沒有針對計算機與網路系統攻擊做詳細介紹。因為此類文章其實也已經有不少了,這裡提供一篇比較不錯的關於緩存溢出攻擊的文章,講得比較詳細:http://www.cnblogs.com/fanzhidongyzby/archive/2013/08/10/3250405.html
此外,如果大家想了解Linus Torvalds「炮轟」C++更詳細的信息,可見此貼:http://os.51cto.com/art/200709/55562.htm。
C語言最為一門更接近硬體底層的高級編程語言具有非常良好的抽象力、表達力和靈活性。此外,它具有非常高效的運行時性能。所以C語言從1970年直到現在都作為系統級編程的首要編程語言。C語言博大精深,其思想也奠定了後續眾多語言的設計基礎,Linux/Unix、Windows、PHP、Redis、Android內核等你耳熟能詳的系統、語言或者軟體都是基於C,可以說「無C語言,不編程」。
作者介紹:zenny_chen,C語言與彙編語言重度用戶與擁躉者,現任上海證大喜馬拉雅高級工程師,曾任安沃傳媒移動客戶端及HTML5技術研發總監兼首席科學家。多年高性能計算、嵌入式系統與移動互聯網實踐經驗,深諳實時操作系統內核、設備驅動研發,對各種處理器架構、多媒體高性能計算編程以及移動端開發如數家珍,同時精通計算機底層基礎技術與各種編程語言,尤其精通C/C++,Java、Objective-C以及Swift!現任CocoaChina社區的Swift編程語言討論區以及代碼例子區的版主;App Store以及Mac App Store中CPU Dasher的作者。著有《C語言編程魔法書:基於C11標準》《OpenCL異構並行計算:原理、機制與優化實踐》。
點擊展開全文
※外媒:中國「BAT」格局面臨終結 京東何以掀翻百度?
※Google Talk/Gchat謝幕,強制性接盤的Hangouts是怎樣的?
※好的API都有哪些特點?你能做到幾點
※亞馬遜最高級別華人科學家加盟阿里的任小楓是誰?
TAG:CSDN |
※精通C語言的黑客才是真正的黑客
※C語言編程入門:用C語言輸出九九乘法表
※C 語言的封裝
※語言:朗誦藝術中的語言技巧
※C 語言 繼承
※文學語言與生活語言
※C 的語言編程
※語言的魔方:語言塑造文化
※漫談歐洲的語言與漢語的方言
※喝酒五語言:豪言壯語,花言巧語,胡言亂語、不言不語,自言自語
※「知言善用」:生活中的語言藝術
※說話的語言藝術
※濫用與語言靈魂之殤
※網易有道CEO周楓:Go語言繼承了C語言的靈活簡單
※王威廉組滿分CVPR論文:遵照自然語言指令的室內導航
※溝通 語言的藝術
※中軟國際哈爾濱ETC:雲之旅應從使用同一種雲語言開始
※周麗艷:語言與意義的悖論——《詞語的孩子》中的語言主題
※中國遊客在國外機場客串播音員用中文播音,網友:贊!祖國的語言
※《刺客信條:奧德賽》配音語言中沒有希臘語