進程啟動時主線程創建過程分析


VS2013編譯以下代碼:

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    int test = 1;
    test = 2;

    return 0;
}

使用CFF Explorer或者PEID打開編譯后生成的exe文件,查看imageBase和OEP,如下所示:

OEP:  0x00011073

image

ImageBase:0x00400000

image

所以該程序的啟動點在:0x00411073

該程序的區段信息如下所示:

image

將其載入OD,其載入地址並非00400000,所以載入OD后,alt+e,先看看主模塊的載入地址:

image

一般進程運行時都是先載入該exe文件,所以exe總能以其imagebase載入,但這里不知這個是為什么,這里可以不用管這個,直接以其載入地址0x00390000進行后面的分析,但是鄙人有強迫症,總想搞清楚這是為什么,所以先來看下為什么不能以imagebase載入。

聯想到安全機制ASLR,難道是這個原因?多次載入,果然發現多次載入時主模塊的載入地址每次都不同。。。

隱約記得VC6.0是不支持ASLR的,所以下面用VC6.0重新編譯以下代碼
#include "stdafx.h"

int main(int argc, char* argv[])
{
    printf("Hello World!\n");
    return 0;
}

果然,每次載入地址都是00400000,那么VS2013的ASLR是不是也可以關閉呢?記得好像哪里有說過可以關閉,找一找。。。

強大的網友:

---------------------------------------------------------------------------------------------------

通過加載程序時候不再使用固定的基址加載,從而干擾shellcode定位的一種保護機制

windows Vista出現后,ASLR 才真正開始發揮作用

VS2005 添加 /dynmicbase 就可以支持 ASLR

VS2008 linker->Randomized Base Address 設置

包含 映像隨機化,堆棧隨機化,PEB+TEB隨機化

---------------------------------------------------------------------------------------------------

image

果然,將其關閉,再次測試

備注:關閉后,少了一個區段reloc,這個此處不分析為什么

image

搞定,此處只是為了便於多次分析,所以關閉ASLR,正常情況,為了安全還是要將ASLR打開的



下面從基地址(0x00400000)開始分析,如下所示:

我們知道PE文件在內庫中是以1000h(一頁)對其,所以先看該頁:

image

。。。。。。

image

。。。。。。

end

這部分數據全是PE文件的結構數據,各種頭部,區段數據等,和本主題沒關系,繼續向下第二頁:

0x00401000,PEID和OD都可以知道這部分數據是.textbbs,

image

0x00401000---0x00402000這一頁內存,結果全是0,《程序員的自我修養》中說“.bbs”段存放的是為初始化的全局變量和局部靜態變量,這里沒有用到未初始化的全局變量和局部靜態變量,所以全是0.

下一個區段:.text(0x00411000

段在OEP,看OEP的代碼

image

這個是OD自動斷下來的第一條指令,查看堆棧:

image

去0x75DF3388看看

image

在此處3388處下F2斷點,Ctrl+F2重啟進程,在此處斷下來,發現堆棧中沒有任何信息,繼續向前走,我們在0x75DF3378和0x75DF337A處下斷點,重啟進程

image

先看從3385~338B

push 主線程參數;

call 主線程函數;(通過OEP做了一次跳板)

push 主線程返回值;

call ntdll.RtlExitUserThread

其源代碼應是:RtlExitUserThread((OEP[jmp到主線程入口main])(參數));

通過Windbg調試發現jnz kernel32.75DF6202處其實是:kernel32!RegSetValueExW+0x655 (75df6202),其功能自行百度,此處具體做了什么先不分析了。。。好復雜。。。

此時的堆棧信息如下:

image

此時第一條堆棧信息是當前函數的名字:即0x75DF3378是kernel32.BaseThreadInitThunk函數

在這四條堆棧信息中函數過程處下斷點,Crtl+F2

然而結果如下:

image

前面的位置斷不下來,所以從最后一條堆棧信息查看,結果如下:

image

原來此處是ntdll的入口,應該是類似於dllmain的,繼續看第二條堆棧信息:

image

表示不認識,第一條:

image

依舊不認識。

但是調試發現0x75DF3378會被調用兩次,第一次其實並未走到OEP,第二次才會call oep,所以此處再調試一次,等第二次調用0x75DF3378時,堆棧信息如下:

image

我們去0x77E49F40處看看:

image

初始化了異常處理鏈SEH,最終調用BaseThreadInitThunk,但是誰調用了0x77E49F2A?堆棧是空的?jmp?

上IDA?

結果發現ntdll不是以imagebase載入的,所以需要換算:77E49F2A-77E10000=39F2A

image

ntdll的imagebase:

image

所以7DE70000+39F2A=7DEA9F2A就是IDA中77E49F2A的位置。

結果如下:

image

所以,創建主線程的入口應該是ntdll!RtlUserThreadStart,至於其具體做了什么,可以在IDA中詳細查看,

這里再不分析了。

感覺好像丟了什么,算了,就這樣吧,睡了。

另附:Windows核心編程(第5版)153頁的以下代碼:

Void RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam)

{

__try{

               ExitThread((pfnStartAddr)(pvParam));

         }

__except(UnhandledExceptionFilter(GetExceptionInformation())){

         ExitProcess(GetExceptionCode());

//NOTE: We Never get here.

}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM