0x01 定義
main是C/C++的標准入口函數名,程序執行總是從main函數開始,如果有有其他函數,則完成對其他函數的調用后再返回到主函數,最后由main函數結束整個程序,其他函數是不能調用main函數的。在執行程序時,由系統先行調用main函數。
WinMain是windows API窗體程序的入口函數,該函數的功能是被系統調用,作為一個32位應用程序的入口點。WinMain函數應初始化應用程序,顯示主窗口,進入一個消息接收一發送循環,這個循環是應用程序執行的其余部分的頂級控制結構。
0x02 區別
二者在同一環境下的不同區別:
Windows支持兩種類型的應用程序:
一種是基於控制台用戶界面的應用程序(Console User Interface,簡稱CUI),
另一種是基於圖形用戶界面的程序(Graphic User Interface,簡稱GUI)。
0x03 函數詳解
3.1 main函數
在 Microsoft C 中,程序啟動時調用的函數稱為 main。 沒有針對 main 聲明的原型,可以用零個、兩個或三個參數對其進行定義:
int main( void )
int main( int argc, char *argv[] )
int main( int argc, char *argv[], char *envp[] )
其中三個參數的解釋如下:
argc 表示有多少個命令行參數,第一個就是執行程序名,所以argc最少為1。
argv 是具體程序運行的地址與相搭配的參數。
envp 是系統的環境變量,很少有介紹的。“名稱=值”的形式,以NULL結束。
3.2 winmain函數
WinMain是用於應用程序入口點的常規名稱,他的句法如下:
int __clrcall WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
);
其中四個參數的解釋如下:
hInstance 類型:HINSTANCE,應用程序當前實例的句柄,也就是他所處的基地址。
hPrevInstance 類型:HINSTANCE,應用程序先前實例的句柄。此參數始終為NULL。
lpCmdLine 類型:LPSTR,應用程序的命令行,不包括程序名稱。
nShowCmd 待定
0x04 實驗查找
這里用兩個程序分別進行查詢main函數與winmain函數:
-
Fport.exe --> main函數
-
360zipInst.exe --> winmain函數
單獨用IDA與OD進行查找:不過還是IDA方便理解一些
4.1 IDA查找main函數
ida打開之后,直接找到start:
反匯編查看偽代碼:這里可以看到它是以v7返回值退出的,着重看v7,大部分程序都是以主函數退出:
這里的sub_407D10函數其實就是main函數:
v7 = sub_407D10(dword_41BFC8, dword_41BFCC);
雙擊步入函數,里面存在相應的命令行顯示字符串:
整個的函數邏輯也會存在其中,我們再拿OD調試一下
4.2 OD查找main函數
F8單步運行到這里,觀察OD的棧面板窗口,程序運行到 main 函數時,經常會伴隨着棧的活動:
這三個數值,其實就是上面所介紹到的main函數的3個參數,來一一對應一下:
Arg1 對應的就是 argc ,表示有多少個命令行參數,第一個就是執行程序名,所以argc最少為1 這里的數值也是 = 00000001
選中 Arg2 ,追蹤一下數據:
可以看到數據面板窗口其中就存在着一個物理地址,而這個地址正好對應了 main函數中的 argv ,由於我們運行時,沒有搭配任何參數,所以參數為空。
同樣的方法,再來看一下Arg3,這里對應的就是相應的系統環境了:
三個參數的數值都可以對應上main函數的參數,那么這里的 Fport.00407D10 也就是整個程序的主入口了
為了進一步證明,F2下個斷點,F9運行到斷點處,F7進到函數里面:
相應的命令行字符串直接在旁邊顯示了出來,找對地方了!
4.3 IDA查找winmain函數
這里的操作與上面打開IDA的操作是類似的,直接找到start,進入其中,開啟反匯編,查看偽代碼:
這里同樣是着重看一下,程序是以哪個變量退出的:
很輕松就可以看到這里的變量是v5,后面緊跟着的就是winmain函數,進到函數里面看一下是不是主函數:
很明顯,這里的參數值,就是我們先前介紹的 winmain 的句法參數!
4.4 OD查找winmain函數
這里與上面查找main函數的方法亦是同理,F8單步運行到這里,觀察OD的棧面板窗口,程序運行到 main 函數時,經常會伴隨着棧的活動:
可以看到,在臨近exit時,上面出現了四個參數,其實這里的 Arg1 是上面所介紹的 hInstance ,應用程序當前實例的句柄,也就是他所處的基地址,在OD里面可以用 ALT+E
查看程序的基地址:
這里的基地址正好 = 00400000
再來看 Arg2 = 0 ,也對應了上面介紹的始終為 NULL 的 hPrevInstance
同理追蹤 Arg3 :
找到第三個參數:lpCmdLine 應用程序的命令行格式:
第四個參數無實意,為了證明此函數為 winmain函數,同樣的方法進到函數里面,查看其內容:
成功進入到程序主函數內!
0x05 參考鏈接
https://www.cnblogs.com/shucome/p/7572142.html
https://blog.csdn.net/m0_37925202/article/details/78944329
https://docs.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-winmain
https://docs.microsoft.com/zh-cn/cpp/c-language/arguments-to-main?view=vs-2019