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
ImageBase:0x00400000
所以該程序的啟動點在:0x00411073
該程序的區段信息如下所示:
將其載入OD,其載入地址並非00400000,所以載入OD后,alt+e,先看看主模塊的載入地址:
一般進程運行時都是先載入該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隨機化
---------------------------------------------------------------------------------------------------
果然,將其關閉,再次測試
備注:關閉后,少了一個區段reloc,這個此處不分析為什么
搞定,此處只是為了便於多次分析,所以關閉ASLR,正常情況,為了安全還是要將ASLR打開的
下面從基地址(0x00400000)開始分析,如下所示:
我們知道PE文件在內庫中是以1000h(一頁)對其,所以先看該頁:
。。。。。。
。。。。。。
end
這部分數據全是PE文件的結構數據,各種頭部,區段數據等,和本主題沒關系,繼續向下第二頁:
0x00401000,PEID和OD都可以知道這部分數據是.textbbs,
0x00401000---0x00402000這一頁內存,結果全是0,《程序員的自我修養》中說“.bbs”段存放的是為初始化的全局變量和局部靜態變量,這里沒有用到未初始化的全局變量和局部靜態變量,所以全是0.
下一個區段:.text(0x00411000)
段在OEP,看OEP的代碼
這個是OD自動斷下來的第一條指令,查看堆棧:
去0x75DF3388看看
在此處3388處下F2斷點,Ctrl+F2重啟進程,在此處斷下來,發現堆棧中沒有任何信息,繼續向前走,我們在0x75DF3378和0x75DF337A處下斷點,重啟進程
先看從3385~338B
push 主線程參數;
call 主線程函數;(通過OEP做了一次跳板)
push 主線程返回值;
call ntdll.RtlExitUserThread
其源代碼應是:RtlExitUserThread((OEP[jmp到主線程入口main])(參數));
通過Windbg調試發現jnz kernel32.75DF6202處其實是:kernel32!RegSetValueExW+0x655 (75df6202),其功能自行百度,此處具體做了什么先不分析了。。。好復雜。。。
此時的堆棧信息如下:
此時第一條堆棧信息是當前函數的名字:即0x75DF3378是kernel32.BaseThreadInitThunk函數
在這四條堆棧信息中函數過程處下斷點,Crtl+F2
然而結果如下:
前面的位置斷不下來,所以從最后一條堆棧信息查看,結果如下:
原來此處是ntdll的入口,應該是類似於dllmain的,繼續看第二條堆棧信息:
表示不認識,第一條:
依舊不認識。
但是調試發現0x75DF3378會被調用兩次,第一次其實並未走到OEP,第二次才會call oep,所以此處再調試一次,等第二次調用0x75DF3378時,堆棧信息如下:
我們去0x77E49F40處看看:
初始化了異常處理鏈SEH,最終調用BaseThreadInitThunk,但是誰調用了0x77E49F2A?堆棧是空的?jmp?
上IDA?
結果發現ntdll不是以imagebase載入的,所以需要換算:77E49F2A-77E10000=39F2A
ntdll的imagebase:
所以7DE70000+39F2A=7DEA9F2A就是IDA中77E49F2A的位置。
結果如下:
所以,創建主線程的入口應該是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.
}
}


















