MemoryModule閱讀與PE檔案解析(三)

2021-07-30 01:36:56 字數 3560 閱讀 6958

前面我們提到乙個函式 copysections ,該函式將檔案中的段拷貝到我們申請的記憶體中,並按照記憶體頁面的大小進行對齊。拷貝過程中設定了每個段的physicaladdress的值為該段的虛擬位址,用於後面的操作。

要理解這個段,首先應該理解_image_section_header

中  的聯合體

union misc;

其中virtualsize(程式中使用的是physicaladdress)我覺得virtualsize更加準確。這個virtualsize 指的是這個段,在載入進記憶體之後的實際大小,而_image_section_header

中的sizeofrawdata 指的是該段磁碟中已經初始化了的資料大小,該大小按照檔案粒度對齊之後的大小,如果該節只包含未初始化的資料,大小為0。

static

bool

copysections(const

unsigned

char *data, size_t

size, pimage_nt_headers

old_headers, pmemorymodule

module)

// 這裡申請記憶體的時候直接使用了codebase+section->virtualaddress,之所以這樣做,是為了使pe檔案在加載入記憶體之後保持其格式,函式之所以成功,因為前面已經從codebase開始預留了整個檔案的空間

dest = codebase +section->virtualaddress;

// note: on 64bit systems we truncate to 32bit here butexpand

// again later when "physicaladdress" is used.

section->misc.physicaladdress = (dword) ((uintptr_t) dest &0xffffffff);

// 在這之後,physicaladdress就是這個段的虛擬位址。

memset(dest, 0, section_size);

}// section is empty

continue;

}if (!checksize(size, section->pointertorawdata +section->sizeofrawdata))

// 提交記憶體塊並拷貝資料

dest = (unsigned

char *)module->alloc(codebase + section->virtualaddress,

section->sizeofrawdata,

mem_commit,

page_readwrite,

module->userdata);

if (dest == null)

dest = codebase + section->virtualaddress;

memcpy(dest, data + section->pointertorawdata,section->sizeofrawdata);

// note: on 64bit systems we truncate to32bit here but expand

// again later when"physicaladdress" is used.

section->misc.physicaladdress = (dword) ((uintptr_t) dest &0xffffffff);

}return

true;

}題外話:我們都知道,pe 檔案的載入是通過記憶體對映檔案來實現的,但是不同於普通的作為資料的對映檔案,pe 檔案的記憶體對映檔案對應的控制區物件後面的每個子記憶體區物件都對應於pe 檔案中的乙個段,而普通的資料型的記憶體對映檔案對應的控制區物件後面的子記憶體區物件都對應的是一定大小的檔案的一部分,詳情請參考

接下來我們看乙個函式,finalizesections 該函式的注釋為:根據段頭標記記憶體頁,並釋放標記為「可廢棄」的段。

static

bool

finalizesections(pmemorymodule

module)

else

sectiondata.size = (((uintptr_t)sectionaddress) +((uintptr_t) sectionsize)) - (uintptr_t)sectiondata.address;

continue;

}if (!finalizesection(module, §iondata))

sectiondata.address = sectionaddress;

sectiondata.alignedaddress = alignedaddress;

sectiondata.size = sectionsize;

sectiondata.characteristics = section->characteristics;

}sectiondata.last = true;

if (!finalizesection(module, §iondata))

return

true;

}上面的操作對每個段都進行了finalizesection操作,該函式如下,操作如注釋所示

static

bool

finalizesection(pmemorymodule

module, psectionfinalizedata

sectiondata)

if (sectiondata->characteristics & image_scn_mem_discardable)

return

true;

}//

得到讀寫執行屬性

executable = (sectiondata->characteristics & image_scn_mem_execute) != 0;

readable =   (sectiondata->characteristics& image_scn_mem_read) != 0;

writeable =  (sectiondata->characteristics& image_scn_mem_write) != 0;

protect = protectionflags[executable][readable][writeable];

if (sectiondata->characteristics & image_scn_mem_not_cached)

// 改變頁面的訪問標識

if (virtualprotect(sectiondata->address, sectiondata->size, protect,&oldprotect) == 0)

return

true;

這樣我們就理解了函式的注釋的含義:改變每個段的保護屬性,並將段頭部中包含有「可以將此資源釋放」標識的記憶體頁釋放。

我們可以看到

重定向段標記為可**,這很好理解,我們使用它進行重定向項的修復之後,我們就可以將其釋放。

閱讀與思考

閱讀與思考 豆瓣上有人問起平常是怎麼看書的,遂總結了幾點。想起許久沒寫部落格 因為好書太多,時間不夠 遂貼上來也算一篇 p 閱讀的方法 舉乙個例子 以前我讀書是流水帳式的,現在我一定會先把目錄很仔細的看一看,目錄往往包含了最高層的知識結構,然後我會挑選看上去最有趣的部分閱讀,如果發現需要用到前面的內...

閱讀與思考

1.學習和思考的過程中常問自己的幾個問題 你的問題到底是什麼?提醒自己思考不要偏離問題。設想自己正在將東西講給別人聽 有聲思考 能否講出來是判斷是否真正理解的最佳辦法 3.1 設想需要講給乙個不懂的人聽。迫使自己去挖掘知識背後最本質 往往也是最簡單的解釋 時常反省和注意自己的思維過程。尤其是當遇到無...

閱讀與生活

在我的生命當中,閱讀一度佔據著重要地位.去年 2007年 我剛出世孩子擊敗閱讀成為我生活中最重要的部分.最近,它好像又要重新站起來了.我喜歡這種感覺.有些人閱讀是為了找工作,有些人是為了打發時間,有些人則純粹是為了娛樂.這些原因都不重要,重要的是你在閱讀.但是才工作或即將要工作的朋友們常常搞錯了方向...