成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++入口不是main?知乎上打起來了!

開發 后端
PE文件中有一個叫OEP的術語便是指的程序入口點。所謂入口點顧名思義就是主線程最開始執行的地方,許多病毒加殼技術其中一點就是對這個OEP進行處理。

[[427646]]

知乎上居然有人為了C++的入口函數到底是什么打了起來!

至于打的有多激烈我就不知道了,我們來關注這個問題本身。

你說main函數是入口,那main是被誰調用的呢?

他說mainCRTStartup是入口,那mainCRTStartup又是被誰調用的呢?

從進程創建說起

一切的一切,讓我們從創建進程開始說起。

進程創建完成后,接著會創建主線程,這是進程中第一個開始執行代碼的線程。

主線程創建后,就得到了時間片,開始參與系統的線程調度,那么程序從哪里開始執行呢?

在Windows平臺,C++代碼編譯后的可執行文件叫PE文件。

PE文件中有一個叫OEP的術語便是指的程序入口點。所謂入口點顧名思義就是主線程最開始執行的地方,許多病毒加殼技術其中一點就是對這個OEP進行處理。

現在,我們來使用工具PEID來看一個程序(VC8.0編譯)的OEP如圖:

0x00011078乃是RVA(相對虛擬地址),要看在進程地址空間中真正的起始地址,還得加上PE文件的映射基址,默認為0x00400000,不過,可以通過編譯器選項進行調整。不知道也沒關系,將程序放入OllyDbg,在內存映射中可以看到程序的映射基址:

由圖看到映射基址是0x00400000。

那么由前面所述,程序執行的第一條指令應該位于0x00400000 + 0x00011078 = 0x00411078。

沒錯,就是這樣。

切換到OllyDbg的主窗口,我們發現了,程序確實初始停在了這里,并且這里是一條jmp指令。

我們到Jmp的目的地0x00411800去看看那里是什么東東?

這是什么東西?先賣個關子,總之,這里是程序進來之后真正做的第一件事。

main函數被誰調用?

換個思路,我們打開VS2008寫一個簡單的程序,程序做什么并不重要,我們要看它的啟動原理。

注意看調用堆棧窗口,因為我是使用UNICODE編碼環境,故_tmain()就是wmain(),如果是ANSI編碼就是最開始學程序時的main()函數了。

以前寫程序就想過一個問題,我們寫的所有函數都會被我們自己直接或間接調用,但有一個函數例外,那就是main()函數。我們寫了它但從不會去調用它,事實上也不可能去調用它。

從調用堆棧看到,我們的wmain函數是被_tmainCRTStartup函數調用的,這是個什么東西?再往前推是wmainCRTStartup調用的_tmainCRTStartup。這兩個函數是做什么的,他們之間有什么關系?

雙擊調用堆棧里的項即可轉到對應的源代碼,我們可以發現,這兩個函數是在crtexe.c文件中實現的。閱讀源碼可以發現,有四個啟動函數分別是:

  • mainCRTStartup() ANSI + 控制臺程序
  • wmainCRTStartup() UNICODE + 控制臺程序
  • WinMainCRTStartup() ANSI + GUI程序
  • wWinMainCRTStartup() UNICODE + GUI程序

這一點在《windows核心編程》中也有提到。不過我們可以更進一步一窺它們的實現代碼:

就這么簡單,先調用了__security_init_cookie(),然后是我們前面看到的_tmainCRTStartup()。

第一個函數是做什么的呢?這個是微軟在VS2003后引入的防止緩沖區溢出攻擊的技術。簡單的說就是在調用函數的時候在棧里安裝一個隨機的cookie值,這一cookie值在內存的一個地方有備份,函數調用完成后需要檢測這個cookie和備份的一不一致,以此來判斷有沒有棧溢出發生。那么,這個函數就是來初始化這個備份區域的數據的。

然后第二個函數調用_initterm()進行全局變量、對象初始化。之后,我們可以看到才是真正調用了我們的main()/wmain()/WinMain()/wWinMain()的地方。饒了一大圈,回答了開始的疑問了。

這兩個函數是編譯器在生成可執行文件的時候給我們鏈接進來的。

至此,我們來看看第一個函數wmainCRTStartup的匯編代碼。如圖:

請注意和我們前面使用OllyDbg調試時的圖對比:

發現沒有?一樣的!我們之前留的那個問題的答案想必已經出來了:

程序一進來從OEP處執行了jmp指令,這條指令轉向了wmainCRTStartup開始了程序真正的起點!

結論

編譯生成的exe文件,雙擊運行后,建立新進程的地址空間,然后主線程開始運行。

程序一進來通過jmp指令來到前面列出的四個啟動函數,它們再調用最終的啟動器_tmainCRTStartup。

這個啟動器干了幾件大事,分別是,使用GetStartupInfo獲取進程啟動信息,然后使用_inititem初始化全局變量和對象,最后調用我們main、wmain、WinMain、wWinMain進入我們的程序。。。

所以,從編程語言的角度來說,main函數就是入口函數,這一點毋庸置疑。至于mainCRTStartup,則是VC++這個編譯器額外增加的包含C/C++運行時庫初始化操作在內的封裝函數,可以算可執行文件的入口函數。

說明:這里談到的是使用VC2008編譯器生成的exe文件形態(不同的VC版本可能情況有所不同),至于Linux上的ELF文件,情況則更不一樣。

最后給大家留一個思考題:

進程創建后,又是從哪里進入到OEP的呢?

前面我們說了,OEP是程序運行的入口,是一切的起點。那在進入入口之前,進程又在干什么?

這個問題有點類似于:在宇宙大爆炸之前,世界是怎么樣的?

本文轉載自微信公眾號「編程技術宇宙」,可以通過以下二維碼關注。轉載本文請聯系編程技術宇宙公眾號。

 

責任編輯:武曉燕 來源: 編程技術宇宙
相關推薦

2022-03-30 10:00:22

大廠流量互聯網

2024-01-09 11:52:23

Rust開發函數

2010-01-19 14:28:41

C++ main()函

2010-01-27 13:31:10

C++ main()函

2019-11-25 11:03:19

互聯網數據技術

2018-12-13 11:32:55

知乎裁員調整

2023-11-27 16:26:20

mainC語言

2025-02-11 09:12:55

2017-11-20 10:21:17

量子點顯示器OLED

2023-09-24 23:44:10

C++類型安全

2017-06-16 21:00:02

Python爬蟲

2011-04-19 17:36:12

C++

2015-03-20 10:00:34

LinuxCC++

2023-06-27 07:20:45

2017-05-24 15:07:19

Python爬蟲爬取

2023-07-18 18:14:51

云原生軟件架構

2020-06-11 18:35:23

C++編程語言

2015-11-04 09:06:11

知乎融資騰訊

2015-07-21 15:22:20

點贊仿知乎按鈕動畫

2024-09-20 08:20:20

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久精品成人 | 国产91综合 | 四色成人av永久网址 | 国产精品伦理一区二区三区 | 精品国产不卡一区二区三区 | 日韩免费1区二区电影 | 欧美vide| 色资源站 | 欧美精品久久一区 | 亚洲视频在线看 | 欧美精品一区二区在线观看 | 国产在线小视频 | 日本三级电影在线免费观看 | 亚洲一卡二卡 | av毛片 | 精品国产1区2区3区 在线国产视频 | 观看毛片 | 99久久日韩精品免费热麻豆美女 | 黄色av网站免费看 | 成人h视频在线 | 一区二区在线观看免费视频 | 久久久久久久久国产 | 精品久久一区 | 精品一区二区免费视频 | 一区二区在线观看免费视频 | 精品视频一区二区三区 | 欧美视频在线播放 | 久久国产精品网 | 日韩在线观看网站 | 国产欧美在线一区 | 精精国产视频 | 国产在线观 | 一级片在线免费播放 | 国产欧美一区二区三区在线看 | 亚洲精品乱码久久久久久按摩观 | 欧美激情在线一区二区三区 | 中文字幕精品视频 | 国产精品视频999 | 一级毛片视频免费观看 | 91精品国产91久久久久久不卞 | 国产欧美精品一区二区三区 |