概述
WIN32程序每个进程都有4GB的虚拟空间,低2G为用户空间,是相互独立的,高2G为内核空间(从0x80000000开始的),所有进程共享。
x86架构将内存以每4KB为一页,称为页式管理,可供使用的物理内存:MmNumberOfPhysicalPages * 4 = 物理内存。用户空间不是真实存在的,只有需要使用它的时候操作系统才会在物理页上真正分配

对于不经常使用的物理页,操作系统会将其储存到虚拟内存(这个虚拟内存在硬盘上,不是用户的虚拟内存)上,再次需要访问时缺页异常,操作系统会处理异常为虚拟内存挂物理页。
私有内存
私有内存只有特定的进程可以访问,独享物理页
1 2 3 4 5 6 7 8 9
| LPVOID VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect );
|
内存大小一般分配为页的整数倍,一页为4KB,也就是0x1000,此处分配了2页内存。
当类型为MEM_RESERVE时,操作系统会分配线性地址,但不实际分配物理页,当为MEM_COMMIT时会分配物理页。保护属性可以允许内存是否可读,可写或可执行,具体宏可查看文档说明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<stdio.h> #include<Windows.h> #include<stdlib.h>
#define BUF_SIZE 0x1000
int main() {
LPVOID p = VirtualAlloc( NULL, BUF_SIZE * 2, MEM_COMMIT, PAGE_READWRITE );
VirtualFree(p, 0, MEM_RELEASE);
system("pause");
return 0; }
|
C语言中的malloc和C++里的new(new就是malloc加上一个构造函数),并没有真正申请内存,new也是调用malloc实现的,反汇编跟踪malloc会发现其最终会调用HeapAlloc,并没有进内核。不管是堆还是栈本质上都是私有内存。
映射内存
除了堆栈和VirtualAlloc分配的内存,其他的都是映射内存,所有进程都可以访问。
如果同名称内核对象已存在,其他进程通过OpenFileMapping也可以获取相同的mapfile内核对象,但关联线性地址之后返回的虚拟内存地址不一定相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include<stdio.h> #include<Windows.h> #include<stdlib.h>
#define BUF_SIZE 0x1000 #define MAPFILENAME TEXT("共享内存")
HANDLE g_hMapFile; LPTSTR g_lpBuff;
int main() {
getchar();
g_hMapFile= CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, MAPFILENAME);
g_lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
*(PDWORD)g_lpBuff = 0x12345678;
printf("%p", g_lpBuff);
getchar();
UnmapViewOfFile(g_lpBuff);
CloseHandle(g_hMapFile);
return 0; }
|
文件系统
相关API索引
卷相关
1 2 3 4 5 6 7 8
| GetLogIcalDrives();
GetLogIcalDriveStrings(buffsize,buf);
GetDriveType()
GetVolumeInformation();
|
文件夹相关
1 2 3 4 5
| CreateDirectory(); RemoveDirectory(); MoveFile(); GetCurrentDirectory(); SetCurrentDirectory();
|
文件操作相关
1 2 3 4 5 6 7 8 9
| CreateFile( ) DeleteFile(); CloseHandle(); GetFileSize(); ReadFile(); SetFilePointer(); WriteFile(); CopyFile(); FindFirstFile();
|
内存映射文件
将该文件通过物理页映射到虚拟内存,用虚拟内存对文件进行操作,不直接对本体进行IO操作,就像读写内存一样读写文件。操作大型文件时性能会很高。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| #include<stdio.h> #include<Windows.h> #include<stdlib.h>
#define MAPPINGNAME TEXT("共享内存")
DWORD mappingFile(LPCWSTR lpcFile) { HANDLE hFile; HANDLE hMapFile; DWORD dwFileMapSize; LPVOID lpAddr;
hFile = CreateFile( lpcFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (hFile == INVALID_HANDLE_VALUE) { CloseHandle(hFile); printf("创建失败:%d\n", GetLastError()); return 0; }
hMapFile = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, MAPPINGNAME );
if (hMapFile == NULL) { CloseHandle(hFile); printf("映射内存失败:%d\n", GetLastError()); return 0; }
lpAddr = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpAddr == NULL) { CloseHandle(hFile); CloseHandle(hMapFile); printf("关联线性地址失败:%d\n", GetLastError()); return 0; }
DWORD dwTest1 = *(PDWORD)lpAddr; DWORD dwTest2 = *(PDWORD)lpAddr + 0x1B8FC; printf("%x %x", dwTest1, dwTest2);
*(PDWORD)lpAddr = 0x41414141;
UnmapViewOfFile(lpAddr); CloseHandle(hMapFile); CloseHandle(hFile);
}
int main() {
mappingFile(TEXT("C:\\t.exe"));
return 0; }
|
写拷贝
MapViewOfFile关联线性地址时,如果第二个参数为FILE_MAP_COPY则为写拷贝,当写入文件时,操作系统会将一个副本放到一个新的物理页,从而不影响其他的进程。
调试工具下断点时本质上是将某一地址的指令修改为0xCC,如果不是写拷贝的话其他程序也会处于调试状态。
