程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> c程序的啟動過程的反匯編分析

c程序的啟動過程的反匯編分析

編輯:關於C語言

c程序的啟動過程的反匯編分析


0x01 工具准備

1.最簡c代碼一只,

int main(){

return 0;}

2.ollydbg

3.VC++6.0

4.GCC(mingw)

0x02 代碼分析

int main()

{

return 0;

}

在gcc下,添加-nostdlib編譯選項,即鏈接器不鏈接標准庫,會提示以下錯誤信息:

D:\Backup\我的文檔\src>gcc main.c -nostdlib-o main.exe

C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccmSU3wr.o:main.c:(.text+0x9): undefined re

ference to `__main'

collect2.exe: error: ld returned 1 exit status

關於-nostdlib編譯選項,只有命令行指定的項才傳遞給鏈接器。標准啟動文件和庫都不會傳遞給鏈接器。該選項隱式打開選項-nostartfiles 和-nodefaultlibs。該選項也可以寫作--no-standard-libraries。

在gcc執行匯編之後,在鏈接部分,當只打開選項-nostartfiles時,結果正常,未出現錯誤信息。而在-nodefaultlibs選項中,提示很多錯誤信息。

\

說明main函數,依賴了一些系統標准庫文件,在鏈接的時候,需要到了一些函數,例如pre_cpp_init、check_managed_app、pre_c_init、_tmainCRTStartup、_InterlockedCompareExchangePointer、duplicate_ppstrings、WinMainCRTStartup、mainCRTStartup、_mingw_prepare_except_fr_msvcr80_and_higher….

匯編裡面的_main就是C語言裡面的main,是因為匯編器和C編譯器對符號的命名差一個下劃線。

鏈接器會在系統標准庫文件,類似於/lib/crt2.o的文件中,尋找_start符號,然後在_start中執行創建堆對象,棧,打開系統預先提供的設備,將argv,argc參數傳入main函數,然後調用main函數。

0x03 vc main函數反匯編分析

1: int main()

2: {

00401010 push ebp //在堆棧上保存EBP

00401011 mov ebp,esp //將堆棧當前位置給EBP,以在堆棧結構中存儲值時的參考點

00401013 sub esp,40h //分配空間

00401016 push ebx //保存數據段值

00401017 push esi //源地址指針

00401018 push edi //目的地址指針

00401019 lea edi,[ebp-40h] //裝入有效地址,用來得到局部變量和函數參數的指針。這裡[ebp-40h]就是基地址再向下偏移40h,就是前面說的為本地變量留出的空間的起始地址;將這個值裝載入edi寄存器,從而得到局部變量的地址

0040101C mov ecx,10h //在ecx寄存器存儲10h

00401021 mov eax,0CCCCCCCCh

00401026 rep stos dword ptr [edi] //初始化局部變量空間,ds:[edi]

3: return 0;

00401028 xor eax,eax

4: }

0040102A pop edi //恢復所有寄存器的值

0040102B pop esi

0040102C pop ebx

0040102D mov esp,ebp //恢復堆棧

0040102F pop ebp

00401030 ret //返回到源EIP地址

Vc查看調用棧,可以看到在main函數之前,系統還啟動了mainCRTStartup函數,這個函數是控制台環境下多字節編碼的啟動函數。在kernel32.dll中地址7c816fd7處調用了mainCRTStartup函數。

main() line 2

mainCRTStartup() line 206 + 25 bytes

KERNEL32! 7c816fd7()

0x04 ollydbg反匯編分析


Od載入,如圖所示。

\


堆棧窗口如圖所示。

\


通過堆棧,可以看到kelnel32調用了入口函數(mainCRTStartup),對於od來說,main函數並不是Entry point,而是mainCRTStartup函數。

一直單步,單步到00401146處,od分析為調用GetVersion函數,獲取當前運行平台的版本號,因為是控制台程序,所以獲取版本號為ms-dos的版本信息。

繼續單步,單步到0040119E處,單步進入,可以看到有HeapCreate申請堆空間函數,大小由傳遞的參數決定,並且該call裡有HeapDestroy銷毀堆函數。因此0040119E為初始化堆空間,如圖所示。

\


在004011C0處,od分析為GetCommandLineA函數,獲取命令行參數信息的首地址。

進入下面的那個call後,可以看到GetEnvironmentStringsW和GetEnvironmentStrings函數,獲取環境變量的首地址,如圖所示。以Unicode編碼形式返回到寄存器和堆棧中,最後采用WideCharToMultiByte函數將Unicode字符串到一個多字節字符串,

M8觍?ff鷌?9Z喎?http://book.2cto.com閱讀《c++反匯編與逆向分析技術揭秘》,在閱讀到第三章認識啟動函數,找到用戶入口時,得知main函數之前系統要做一些准備工作,再加上上學期學的C語言程序入口函數不是main函數,而是_start函數,這不禁引發了一些思考,到底編譯器在編譯和系統執行程序的時候發生了什麼,因此想以實例進行一定的分析。在思考的過程中,有些涉及到了編譯器的知識,包括它如何工作的,匯編之後又是如何鏈接的,這一部分內容不太熟悉,這一方面得掌握編譯原理的知識,還得學習編譯器的相關內容。那些東西還沒學,因此不免有一些缺憾。了解反匯編的一些內容,可以更深層次的理解相對底層的一些東西,包括棧,堆和寄存器的數據交換。另外並未使用到神器IDA,利用IDA會更好地靜態分析一些函數。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved