您好,歡迎進入深圳市穎特新科技有限公司官方網(wǎng)站!
為什么要用”真正”這個詞?因為我們從學(xué)C語言開始,都會先明白這個道理,即C語言有且僅有一個main函數(shù),main函數(shù)是C語言的入口點和出口點。ǹ梢詤⒖>http://www.dotcpp.com/wp/184.htmll)不光C語言如此,C++也如此,甚至無論黑窗口的控制臺程序和Windows應(yīng)用程序,都是從main函數(shù)或者WinMain函數(shù)開始執(zhí)行,這當(dāng)然沒錯,但事實上main函數(shù)僅僅是一個C語言語法規(guī)定的入口點,而不是真正的程序入口,因為它也有函數(shù)返回值!它也需要被調(diào)用!所以,今天我們將帶大家去揭秘main函數(shù)之前的代碼,去看看真正的啟動函數(shù)是什么!來讓大家深入理解C語言程序,方便大家日后的逆向?qū)W習(xí)!
由于大多數(shù)情況下,我們在VC環(huán)境下,常常C/C++混編,或控制臺程序和windows應(yīng)用程序都有接觸,同時會因為編碼方式的區(qū)分如ANSI或者Unicode編碼啟動函數(shù)還各不相同,為保持簡單、純粹。我們今天僅僅討論ANSI編碼控制臺程序下純C語言的程序入口分析。
事實上,在VC6編譯器下,ANSI編碼環(huán)境下C語言的真正啟動函數(shù)名叫做mainCRTStarup,英語好的同學(xué)應(yīng)該可以明白一些,Starup就是初始化、啟動的意思,其實也可以根據(jù)這點明白這個函數(shù)作用就是在C語言啟動之前做一些必要的工作,如堆棧初始化、獲得主函數(shù)的參數(shù)等等。
還是本著我們“實踐教學(xué)”的原則,我們還是以實踐、做實驗來驗證和理解我們的知識,由于關(guān)系到函數(shù)間調(diào)用的關(guān)系,我們應(yīng)該聯(lián)想到VC6編譯器帶給我們的;厮莨δ。有興趣的同學(xué)可以參考VC6斷點調(diào)試之窗口監(jiān)視(內(nèi)存監(jiān)視、寄存器和;厮荩╤ttp://www.dotcpp.com/wp/545.html)依次View – Debug Windows-> Call Stack
通過編譯器提供的棧回溯功能可以看到程序啟動后的調(diào)用過程,如下:
通過斷點提示,我們看到目前程序位于main函數(shù)第四行?梢钥吹缴弦淮问潜籱ainCRTStartup函數(shù)調(diào)用,在第206行的25個字節(jié)偏移處開始調(diào)用,再之前就是KERNEL32了,它是windows系統(tǒng)三大主要文件之一。軟件系統(tǒng)層面的調(diào)用就到此為止了。
因為大多數(shù)逆向分析工具基本都會從這里開始,所以我們也重點研究mainCRTStartup函數(shù)的原理。幸運的是,VC6編譯器為我們提供了mainCRTStartup函數(shù)的源碼,但需要大家安裝完整版才可以看到,不然只能看到反匯編代碼。
這里我們摘錄一部分主要的mainCRTStartup代碼,供大家參考學(xué)習(xí):
以上語法依舊是C語言,大家可以自行對照注釋進行理解,熟悉main函數(shù)在調(diào)用前的一些準備工作,可以總結(jié)如下:
1.GetVersion函數(shù):獲取當(dāng)前運行平臺的版本號。控制臺下則為MS-DOS的版本信息。
2._heap_inith函數(shù):用于初始化堆空間。在函數(shù)實現(xiàn)中使用HeapCreate申請堆空間
3.GetCommandLineA函數(shù):獲取命令行參數(shù)信息的首地址
4._crtGetEnvironmentStringA函數(shù):獲取環(huán)境變量信息的首地址
5._setargv函數(shù):此函數(shù)根據(jù)GetCommandLineA獲取命令行參數(shù)信息的首地址并進行參數(shù)分析 注意主函數(shù)的參數(shù)就在這里獲得!
6._setenvp函數(shù):此函數(shù)根據(jù)_crtGetEnvironmentStringA函數(shù)獲取環(huán)境變量信息的首地址進行分析。
7._cinit函數(shù):用于全局變量數(shù)據(jù)和浮點數(shù)寄存器的初始化。
大家可以對比代碼加注釋深入理解main函數(shù)啟動前的準備工作,來加深程序啟動的機制理解。
通過觀察,在_cinit()函數(shù)之后,我們可以看到有主函數(shù)的調(diào)用語句mainret = main(_argc,_argv,_environ),現(xiàn)在知道主函數(shù)的返回值給誰了吧?
至此,我們最熟悉的main函數(shù)就出現(xiàn)了,怎么樣,大家連起來了嗎?
如果還能理解,我們接下來做一個更改入口函數(shù)的實驗,來加深大家的學(xué)習(xí)。如下:
編譯器工具欄 Project – Setting – Link – Output 如下圖:
在入口點出輸入你想自定義的函數(shù)名,比如起名MyDotcpp,將替換掉mainCRTStartup函數(shù),重新被KERNEL32調(diào)用,main函數(shù)作為C語言語法入口點,被MyDotcpp調(diào)用,如圖:
重新打開;厮莶榭凑{(diào)用情況,可以看到入口函數(shù)已經(jīng)被更改掉了:
當(dāng)然,這里我們定義的MyDotcpp函數(shù)僅僅用來測試更改入口函數(shù),正如mainCRTStartup之前描述的代碼一般,入口函數(shù)擁有更多的比如初始化堆空間、浮點數(shù)等功能,如果我們這里在多加一些如開辟內(nèi)存等語句,運行將會報錯,大家可以親自上機嘗試。
掃碼關(guān)注我們
傳真:0755-82591176
郵箱:vicky@yingtexin.net
地址:深圳市龍華區(qū)民治街道民治大道973萬眾潤豐創(chuàng)業(yè)園A棟2樓A08