VirtualProtect() 原型如下:
[C++] 纯文本查看 复制代码 BOOL WINAPI VirtualProtect(
__in LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flNewProtect,
__out PDWORD lpflOldProtect
);
函数可以改变调用进程虚拟地址空间中已提交页上的一段内存的保护属性。
第 1 个参数 lpAddress 是输入参数,是虚拟内存基地址。
第 2 个参数 dwSize 是输入参数,表示要改变内存区域的大小。
第 3 个参数 flNewProtect 是输入参数,给出了要设置的新的保护属性,可以为 PAGE_READONLY, PAGE_EXECUTE,PAGE_EXECUTE_READ 等。
第 4 个参数 lpflOldProtect 是输出参数,指向保存原保护属性值(DWORD),当其为 NULL 或 指向一个错误的变量时函数都将失败。
测试代码:
[C++] 纯文本查看 复制代码 #include "stdafx.h"
#include <locale.h>
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL, "CHS");
LPVOID lpStart = (LPVOID)0x10000000;
SIZE_T sizeVirtual = 8192;
DWORD dwOldProtect;
LPVOID lpAddress = VirtualAlloc(lpStart, sizeVirtual, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
if (lpAddress == NULL) {
printf ("VirtualAlloc Error : %d\n", GetLastError());
return (-1);
}
CopyMemory (lpAddress, TEXT("Hello Groad.net"), 2*_tcslen(TEXT("Hello Groad.net")));
_tprintf (TEXT("写入到内存空间的内容为:%s\n"), lpAddress);
_tprintf (TEXT("将内存属性更改为只读...并再次尝试写入\n"));
if (!VirtualProtect(lpAddress, 300, PAGE_READONLY, &dwOldProtect)) {
_tprintf (TEXT("VirtualProtect error : %d"), GetLastError());
return (-2);
}
//再次写入:
CopyMemory (lpAddress, TEXT("Hello Groad.net"), 2*_tcslen(TEXT("Hello Groad.net")));
运行程序后,会看到错误提示框,如下图所示:
这是因为内存页已经修改为只读属性。
将程序中去掉修改属性后的 CopyMemory() 函数,并在下面添加 VirtualQuery() 函数,打印出内存相关信息:
[C++] 纯文本查看 复制代码 MEMORY_BASIC_INFORMATION mbi; // 内存信息
VirtualQuery(lpAddress, &mbi, sizeof(mbi));
_tprintf (TEXT( "BaseAddress: 0x%.8x\nAllocationBase: 0x%.8x\nAllocationProtect: 0x%.8x\nRegionSize: %u\nState: 0x%.8x\nProtect: 0x%.8x\nType: 0x%.8x\n"),
mbi.BaseAddress, mbi.AllocationBase, mbi.AllocationProtect, mbi.RegionSize, mbi.State, mbi.Protect, mbi.Type);
运行输出:写入到内存空间的内容为:Hello Groad.net
BaseAddress: 0x10000000
AllocationBase: 0x10000000
AllocationProtect: 0x00000004
RegionSize: 4096
State: 0x00001000
Protect: 0x00000002
Type: 0x00020000 由上面的输出确实看到了内存的保护属性修改成功,即 0x2 值对应着 PAGE_READONLY 。 |