Windows内存管理学习笔记(一)—— 线性地址的管理
Windows內(nèi)存管理學(xué)習(xí)筆記(一)—— 線性地址的管理
- 用戶空間線性地址的管理
- 實驗一:理解用戶空間線性地址管理
- Private Memory
- 實驗二:理解Private Memory
- 堆
- 實驗三:理解堆
- Mapped Memory
- 實驗四:理解共享內(nèi)存
- 實驗五:理解共享文件
- Mapped Exe
- 實驗六:理解Mapped Exe
- 總結(jié)
用戶空間線性地址的管理
基本概念:每一個進(jìn)程都有一個4GB的線性地址空間
描述:
申請內(nèi)存的兩種方式:
進(jìn)程空間地址劃分:
注意:
1)只有用戶模式區(qū)是用戶能夠訪問的
2)所謂的“無法訪問”只是目標(biāo)地址沒有被掛上有效的物理頁(詳見保護(hù)模式章節(jié))
3)通常,當(dāng)我們需要申請一塊內(nèi)存時,通過系統(tǒng)提供的API去申請
4)當(dāng)我們申請一塊內(nèi)存時,系統(tǒng)需要對這塊內(nèi)存做記錄,表示它已經(jīng)被申請了,之后再進(jìn)行申請時,系統(tǒng)就不會再分配這塊地址給我們了
5)在內(nèi)核層,通過一塊鏈表,將所有未進(jìn)行分配的空間的地址串起來,當(dāng)我們需要分配空間時,在這一塊鏈表中尋找
6)內(nèi)核空間線性地址管理相對簡單(參考《Windows內(nèi)核原理與實現(xiàn)》)
7)本章主要介紹用戶空間線性地址管理(相對復(fù)雜)
實驗一:理解用戶空間線性地址管理
1)使用WinDbg查看進(jìn)程列表
命令:!process 0 0
2)定位一個exe程序
3)查看EPROCESS結(jié)構(gòu)體
命令:dt _EPROCESS 86360440
ntdll!_EPROCESS......+0x11c VadRoot : 0x8656ef48 Void //入口點,進(jìn)去后是搜索二叉樹//每一個節(jié)點記錄了一塊已被占用的線性地址空間//對應(yīng)_MMVAD結(jié)構(gòu)體......4)查看MMVAD結(jié)構(gòu)體
命令:dt _MMVAD 0x8656ef48
nt!_MMVAD+0x000 StartingVpn : 0x400 //重要,以頁為單位,后面添上三個0即是當(dāng)前節(jié)點所描述的線性地址的起始位置+0x004 EndingVpn : 0x42b //重要,以頁為單位,后面添上三個0即是當(dāng)前節(jié)點所描述的線性地址的結(jié)束位置+0x008 Parent : (null) //根節(jié)點,不存在父節(jié)點+0x00c LeftChild : 0x86237d60 _MMVAD //左子樹+0x010 RightChild : 0x863e6a20 _MMVAD //右子樹+0x014 u : __unnamed //對應(yīng)_MMVAD_FLAGS結(jié)構(gòu)體+0x018 ControlArea : 0x86610220 _CONTROL_AREA //包含該節(jié)點所對應(yīng)的線性地址被誰占用等信息+0x01c FirstPrototypePte : 0xe11e1048 _MMPTE+0x020 LastContiguousPte : 0xfffffffc _MMPTE+0x024 u2 : __unnamed5)查看CONTROL_AREA結(jié)構(gòu)體
命令:dt _CONTROL_AREA 0x86610220
nt!_CONTROL_AREA+0x000 Segment : 0xe11e1008 _SEGMENT+0x004 DereferenceList : _LIST_ENTRY [ 0x0 - 0x0 ]+0x00c NumberOfSectionReferences : 1+0x010 NumberOfPfnReferences : 0x13+0x014 NumberOfMappedViews : 1+0x018 NumberOfSubsections : 6+0x01a FlushInProgressCount : 0+0x01c NumberOfUserReferences : 2+0x020 u : __unnamed+0x024 FilePointer : 0x863219d0 _FILE_OBJECT //若為空,表示線性地址指向真正的物理頁+0x028 WaitingForDeletion : (null) +0x02c ModifiedWriteCount : 0+0x02e NumberOfSystemCacheViews : 06)查看FILE_OBJECT結(jié)構(gòu)體
命令:dt _FILE_OBJECT 0x863219d0
ntdll!_FILE_OBJECT......+0x030 FileName : _UNICODE_STRING "\Documents and Settings\User\桌面\test\Debug\test.exe"//線性地址屬于主模塊......7)查看MMVAD_FLAGS結(jié)構(gòu)體
命令:kd> dt _MMVAD_FLAGS 86237d60+0x14
nt!_MMVAD_FLAGS+0x000 CommitCharge : 0y0000000000000000111 (0x7)+0x000 PhysicalMapping : 0y0+0x000 ImageMap : 0y1 //為1表示鏡像文件(可執(zhí)行文件),0表示其他+0x000 UserPhysicalPages : 0y0+0x000 NoChange : 0y0+0x000 WriteWatch : 0y0+0x000 Protection : 0y00111 (0x7) //表示內(nèi)存權(quán)限為EXECUTE_WRITECOPY+0x000 LargePages : 0y0+0x000 MemCommit : 0y0+0x000 PrivateMemory : 0y0 //0表示Mapped Memory8)遍歷所有節(jié)點
命令:!vad 0x8656ef48
VAD Level Start End Commit 86237d60 1 10 10 1 Private READWRITE 85e1adc0 2 20 20 1 Private READWRITE 866df830 3 30 12f 3 Private READWRITE 86320ac0 4 130 132 0 Mapped READONLY Pagefile section, shared commit 0x3 86425598 5 140 23f 4 Private READWRITE 867c49d0 6 240 24f 6 Private READWRITE 862ff800 7 250 25f 0 Mapped READWRITE Pagefile section, shared commit 0x3 864bcad8 8 260 275 0 Mapped READONLY \WINDOWS\system32\unicode.nls 86348070 9 280 2c0 0 Mapped READONLY \WINDOWS\system32\locale.nls 863ec958 10 2d0 310 0 Mapped READONLY \WINDOWS\system32\sortkey.nls 86673f10 11 320 325 0 Mapped READONLY \WINDOWS\system32\sorttbls.nls 85dd0b40 12 330 370 0 Mapped READONLY Pagefile section, shared commit 0x41 86425fe8 13 380 38f 5 Private READWRITE 86588948 14 390 392 0 Mapped READONLY \WINDOWS\system32\ctype.nls 8656ef48 0 400 42b 7 Mapped Exe EXECUTE_WRITECOPY \Documents and Settings\JinXiangcheng\桌面\test\Debug\test.exe 862664c0 2 7c800 7c91d 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\kernel32.dll 863e6a20 1 7c920 7c9b2 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\ntdll.dll 862f4cb0 3 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile section, shared commit 0x7 8633aa60 2 7ffa0 7ffd2 0 Mapped READONLY Pagefile section, shared commit 0x33 8648b448 3 7ffdb 7ffdb 1 Private READWRITE 86244d88 4 7ffdf 7ffdf 1 Private READWRITE Total VADs: 21, average level: 6, maximum depth: 14 Total private commit: 0x27 pages (156 KB) Total shared commit: 0x81 pages (516 KB)總結(jié):
1)所有的線性地址空間是需要管理的(哪些地址是占用的,哪些地址是未占用的)
2)所有用戶線性地址空間通過搜索二叉樹進(jìn)行管理(占用大小,占用方式,內(nèi)存屬性)
4)所有已占用的線性地址可以分為兩類
5)傳統(tǒng)的模塊隱藏技術(shù),終究會在VadRoot中留下痕跡,假設(shè)摘除,操作系統(tǒng)會誤認(rèn)為該地址空間未被分配,從而產(chǎn)生非預(yù)期中的錯誤
Private Memory
描述:通過VirtualAlloc/VirtualAllocEx申請的內(nèi)存,叫做Private Memory
LPVOID VirtualAlloc{LPVOID lpAddress, // 要分配的內(nèi)存區(qū)域的地址,填0則隨機(jī)分配一塊符合條件的地址DWORD dwSize, // 分配的大小,4kb對齊DWORD flAllocationType, // 分配的類型// MEM_RESERVE:只保留線性地址,不分配物理頁// MEM_COMMIT:既保留線性地址,又分配物理頁DWORD flProtect // 該內(nèi)存的初始保護(hù)屬性 };實驗二:理解Private Memory
1)編譯并運行以下代碼
#include <stdio.h> #include <windows.h>LPVOID lpAddress;int main() {printf("程序運行了...內(nèi)存還沒有申請\n");getchar();lpAddress = VirtualAlloc(NULL, 0x1000*2, MEM_COMMIT, PAGE_READWRITE);printf("內(nèi)存地址:%x\n", lpAddress);getchar();return 0; }2)遍歷VadRoot
kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** ...... Failed to get VadRoot PROCESS 86498ca0 SessionId: 0 Cid: 026c Peb: 7ffd3000 ParentCid: 0b80DirBase: 0e800380 ObjectTable: e2abfd10 HandleCount: 18.Image: test.exe kd> dt _EPROCESS 86498ca0 ntdll!_EPROCESS......+0x11c VadRoot : 0x86543ed8 Void...... kd> !vad 0x86543ed8 VAD Level Start End Commit 8621f160 1 10 10 1 Private READWRITE 866d04e0 2 20 20 1 Private READWRITE 86591aa8 3 30 12f 3 Private READWRITE 862f9658 4 130 132 0 Mapped READONLY Pagefile section, shared commit 0x3 865d7920 5 140 23f 3 Private READWRITE 85decda0 6 240 24f 6 Private READWRITE 862d7068 7 250 25f 0 Mapped READWRITE Pagefile section, shared commit 0x3 862df620 8 260 275 0 Mapped READONLY \WINDOWS\system32\unicode.nls 85e009d0 9 280 2c0 0 Mapped READONLY \WINDOWS\system32\locale.nls 85e4b6b0 10 2d0 310 0 Mapped READONLY \WINDOWS\system32\sortkey.nls 86588988 11 320 325 0 Mapped READONLY \WINDOWS\system32\sorttbls.nls 865e7bb8 12 330 370 0 Mapped READONLY Pagefile section, shared commit 0x41 8642b528 13 380 38f 5 Private READWRITE 8665e1b0 14 390 392 0 Mapped READONLY \WINDOWS\system32\ctype.nls 86543ed8 0 400 42c 8 Mapped Exe EXECUTE_WRITECOPY \Documents and Settings\JinXiangcheng\桌面\test\Debug\test.exe 865feaf8 2 7c800 7c91d 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\kernel32.dll 85df5180 1 7c920 7c9b2 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\ntdll.dll 86487da0 3 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile section, shared commit 0x7 863b1100 2 7ffa0 7ffd2 0 Mapped READONLY Pagefile section, shared commit 0x33 863ef410 3 7ffd3 7ffd3 1 Private READWRITE 8640f148 4 7ffdf 7ffdf 1 Private READWRITE Total VADs: 21, average level: 6, maximum depth: 14 Total private commit: 0x27 pages (156 KB) Total shared commit: 0x81 pages (516 KB)3)繼續(xù)運行程序,查看分配到的地址
4)再次遍歷VadRoot,觀察變化
堆
描述:
實驗三:理解堆
1)編譯并運行以下代碼(在首行設(shè)置斷點)
#include <stdio.h> #include <windows.h>int x = 0x1234;int main() {int y = 0x5678;int *z = (int*)malloc(sizeof(int)*128);printf("全局變量:%x\n", &x);printf("棧:%x\n", &y);printf("堆:%x\n", z);getchar();return 0; }2)查看當(dāng)前進(jìn)程的VadRoot
3)繼續(xù)運行程序,觀察結(jié)果
4)再次查看VadRoot,發(fā)現(xiàn)并無任何變化
結(jié)論:
Mapped Memory
描述:
1)通過CreateFileMapping映射的內(nèi)存,叫做Mapped Memory,一個進(jìn)程中大部分的內(nèi)存都屬于Mapped Memory
2)Mapped Memory可以分為兩類
3)無論是共享內(nèi)存還是文件,在底層實現(xiàn)都是一樣的,當(dāng)我們需要共享物理頁的時候,系統(tǒng)只需將物理頁準(zhǔn)備好,當(dāng)我們需要共享文件時,系統(tǒng)先將物理頁準(zhǔn)備好,然后將物理頁與文件進(jìn)行關(guān)聯(lián)
實驗四:理解共享內(nèi)存
1)編譯并運行以下代碼(進(jìn)程A)
#include <stdio.h> #include <windows.h>#define MapFileName "共享內(nèi)存"int main() {//內(nèi)核對象:1.物理頁 2. 文件//準(zhǔn)備一塊內(nèi)存,若第一個參數(shù)為INVALID_HANDLE_VALUE(-1)表示共享物理頁HANDLE g_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUFSIZ, MapFileName);//將物理頁與線性地址進(jìn)行映射LPTSTR g_lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFSIZ);*(PDWORD)g_lpBuff = 0x12345678;printf("A進(jìn)程寫入地址,內(nèi)容:%p - %x", g_lpBuff, *(PDWORD)g_lpBuff);getchar();return 0; }2)查看進(jìn)程A的執(zhí)行結(jié)果
3)查看進(jìn)程A的VadRoot
4)保持進(jìn)程A運行,編譯并運行以下代碼(進(jìn)程B)
5)查看進(jìn)程B執(zhí)行結(jié)果
6)查看進(jìn)程B的VadRoot
實驗五:理解共享文件
1)編譯并運行以下代碼(在return處設(shè)置斷點)
#include <stdio.h> #include <windows.h>int main() {//內(nèi)核對象:1.物理頁 2. 文件HANDLE g_hFile = CreateFile("C:\\NOTEPAD.EXE",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); HANDLE g_hMapFile = CreateFileMapping(g_hFile,NULL,PAGE_READWRITE,0, BUFSIZ,NULL);//將物理頁與線性地址進(jìn)行映射LPTSTR g_lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFSIZ);return 0; }2)查看g_lpBuff的地址
3)查看當(dāng)前進(jìn)程的VadRoot
Mapped Exe
描述:
實驗六:理解Mapped Exe
1)編譯并運行以下代碼(在return處設(shè)置斷點)
#include <stdio.h> #include <windows.h>int main() {HMODULE hModule = LoadLibrary("C:\\NOTEPAD.EXE");return 0; }2)查看當(dāng)前進(jìn)程的VadRoot
總結(jié)
1)線性地址分為三類:私有內(nèi)存 | 共享內(nèi)存 | 共享文件
2)共享內(nèi)存和共享文件本質(zhì)相同,都是分配了一塊物理頁,不同的是共享文件將物理頁和文件關(guān)聯(lián)了起來
3)傳統(tǒng)的模塊隱藏技術(shù)很難在VadRoot中進(jìn)行隱藏(脫鉤可能會導(dǎo)致程序崩潰),除非通過VirtualAlloc分配私有內(nèi)存,手動將文件進(jìn)行拉伸與貼入等一系列操作,此時能夠大大增加尋找該模塊的難度
思考:當(dāng)使用VirtualAlloc進(jìn)行模塊隱藏并且抹去特征時,如何找到這個模塊?
答案:內(nèi)存搜索
總結(jié)
以上是生活随笔為你收集整理的Windows内存管理学习笔记(一)—— 线性地址的管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows异常学习笔记(五)—— 未
- 下一篇: Windows内存管理学习笔记(二)——