// 内存管理_VirtualAlloc.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
int _tmain(int argc, _TCHAR* argv[])
{
// 内存管理函数
//VirtualAlloc( );
//HeapCreate( );
//CreateFileMapping( );
//MapViewOfFile( );
//
//malloc( );
//new int;
LPVOID pBuff = NULL;
// 预定内存
// 预定之后, 内存状态就变成预定状态(reserve), 但还没有和物理内存进行关联
// 因此不能往这种状态的内存中进行读写操作.
// 预定之后, 需要进行提交才能对内存进行读写.
// 要释放预定的内存, 需要使用VirtualFree,并使用MEM_RELEASE标志
// 如果分配的大小不够一个内存分配粒度(64Kb),则函数会向上取整到64Kb
pBuff = VirtualAlloc( NULL , /*申请在指定地址上预定内存.*/
1024*64*3 , /*预定3个分配粒度单位的内存*/
MEM_RESERVE , /*预定内存的标志,保留*/
PAGE_NOACCESS /*内存分页属性,在预定时无法设置内存分页属性*/
);
if( pBuff == NULL ) {
printf( "预定内存失败\n" );
}
// 尝试写入刚刚预定的内存,
__try {
*(DWORD*)pBuff = 0;
}
__except( EXCEPTION_EXECUTE_HANDLER ) {
printf( "预定的内存必须经过提交才能使用\n" );
}
// 将预定的内存提交到物理内存.
// 提交之后, 内存状态就从预定状态(reserve)变成提交状态(commit)
// 提交之后, 预定的内存就能够和关联物理内存, 就能够对这种状态内存
// 进行读写操作(如果这块内存支持读/写权限的话).
// 如果想要取消提交, 可以使用VirtualFree函数并传入MEM_DECOMMIT
// 来取消提交.
// 应当注意的是, 提交之时, 提交的首地址必须是以内存分页粒度进行对齐
// 的, 内存的大小理应也是内存分页粒度的倍数. 如果首地址不是内存分页
// 粒度的倍数, 则函数内部会向下取整到内存分页粒度的倍数,
// 如果内存地址不足一个内存分页, 函数内部会自动向上取整到内存分页粒度
// 的倍数.
// 内存分页粒度一般是4096Kb
pBuff = VirtualAlloc( pBuff , /* 要和物理内存进行关联的虚拟地址. */
4096 , /* 需要关联的字节数 */
MEM_COMMIT , /* 提交的到物理内存的标志,设置为提交 */
PAGE_READWRITE /*虚拟内存分页属性:可读可写*/
);
// 尝试写入刚刚申请出来的内存
*(DWORD*)pBuff = 0;
pBuff = VirtualAlloc((LPVOID)((DWORD)pBuff+4096), /* 要和物理内存进行关联的虚拟地址. */
4096, /* 需要关联的字节数 */
MEM_COMMIT, /* 提交的到物理内存的标志,设置为提交 */
PAGE_READWRITE /*虚拟内存分页属性:可读可写*/
);
*(DWORD*)pBuff = 0;
// 将保留和提交同时进程.
LPVOID pBuff2;
pBuff2 = VirtualAlloc(NULL,
64 * 1024,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE
);
// 取消提交到物理内存的虚拟内存.
// 取消提交后, 可以再次使用VirtualAlloc再次提交
VirtualFree( pBuff , /*开始地址*/
4096 , /*取消提交的字节数*/
MEM_DECOMMIT /*取消提交的标志*/
);
// 释放预定的内存
// 释放时, 释放的地址必须是调用VirtualAlloc预定内存所返回的内存首地址
// 大小必须是0
// 释放之后, 内存状态就被设置为闲置状态(free)
VirtualFree( pBuff ,
0 ,
MEM_RELEASE );
// 查询一个地址的内存状态
MEMORY_BASIC_INFORMATION mbi = { 0 };
/*
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress; // 要查询的地址
PVOID AllocationBase; //地址的所在内存块的首地址
DWORD AllocationProtect;// 分配的内存分页属性
SIZE_T RegionSize; // 所在区域的大小
DWORD State; // 内存的状体(闲置,保留,提交)
DWORD Protect; // 内存分配的内存分页属性
DWORD Type; // 映射方式(private,image,mapped)
} MEMORY_BASIC_INFORMATION
*/
HMODULE hMod = GetModuleHandle(NULL);
VirtualQuery((LPVOID)((DWORD)hMod + 500) ,/*需要查询的地址*/
&mbi, /*接收查询结果的结构体*/
sizeof(mbi)/*结构体的字节数*/
);
VirtualQuery((LPVOID)0x401000,
&mbi, /*接收查询结果的结构体*/
sizeof(mbi)/*结构体的字节数*/);
if (mbi.State == MEM_FREE)// MEM_FREE,MEM_COMMIT,MEM_RESERVE
{
VirtualAlloc((LPVOID)0x401000, 64 * 1024, MEM_RESERVE | MEM_COMMIT, 0);
}
return 0;
}
====================
// 内存管理_遍历虚拟内存.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
using std::list;
enum MEMORYSTATE {
e_stat_free = MEM_FREE ,
e_stat_reserve = MEM_RESERVE ,
e_stat_commit = MEM_COMMIT
};
enum MEMORYTYPE {
e_type_image = MEM_IMAGE ,
e_type_mapped = MEM_MAPPED ,
e_type_private = MEM_PRIVATE ,
};
typedef struct VMINFO {
DWORD address;
DWORD size;
MEMORYSTATE state;
}VMINFO;
void queryVirtualMemoryStatue( HANDLE hProcess , list* memoryStatue ) {
MEMORY_BASIC_INFORMATION mbi = { 0 };
VMINFO statue = { 0 };
DWORD dwAddress = 0;
DWORD dwSize = 0;
BOOL bRet = FALSE;
while( 1 ) {
bRet = VirtualQueryEx( hProcess ,
(LPCVOID)dwAddress ,
&mbi ,
sizeof( MEMORY_BASIC_INFORMATION ) );
if( bRet == FALSE )
break;
statue.address = dwAddress;
statue.state = (MEMORYSTATE)mbi.State;
dwSize = mbi.RegionSize;
// 输出内存状态,
// 内存状态用于描述虚拟内存有没有和物理存储器进行关联.
// 或是否被预定.
// free : 闲置,没有预定,没有和物理存储器关联
// reserve: 保留,被预定,没有和物理存储器关联
// commit : 提交,已经和物理存储器关联
switch( statue.state ) {
case e_stat_free:
printf( "0x%08X : Free\n" , statue.address );
break;
case e_stat_reserve:
printf( "0x%08X : reserve\n" , statue.address );
break;
case e_stat_commit:
printf( "0x%08X : commit\n" , statue.address );
break;
}
// 如果内存地址已经提交到物理内存,则遍历提交到的每一个内存块.
if( statue.state == e_stat_commit ) {
dwSize = 0;
LPVOID dwAllocationBase = mbi.AllocationBase;
DWORD dwBlockAddress = (DWORD)dwAddress;
while( 1 ) {
bRet = VirtualQueryEx( hProcess ,
(LPCVOID)dwBlockAddress ,
&mbi ,
sizeof( MEMORY_BASIC_INFORMATION ) );
if( bRet == FALSE ) {
break;
}
// 判断遍历出来的内存块是否是同一块.(看它们的分配的首地址是否相等.)
// 如果不是,则跳出循环.
if( mbi.AllocationBase != dwAllocationBase )
break;
printf( "\t0x%08X " , dwBlockAddress );
// 输出内存类型
// 内存类型表示虚拟内存是以何种方式和物理存储器进行关联
// image : 是从影像文件中映射而来
// mapped : 内存映射
// private: 私有内存,其它进程无法访问.
switch( mbi.Type ) {
case e_type_image:
printf( " 类型: image " );
break;
case e_type_mapped:
printf( " 类型: mapped " );
break;
case e_type_private:
printf( " 类型: private " );
break;
default:
break;
}
// 输出内存分页属性
// 内存分页属性用于表示内存分页能够进行何种访问,如读,写,执行,写时拷贝.
if (mbi.Protect == 0)
printf("---");
else if (mbi.Protect & PAGE_EXECUTE)
printf("E--");
else if (mbi.Protect & PAGE_EXECUTE_READ)
printf("ER-");
else if (mbi.Protect & PAGE_EXECUTE_READWRITE)
printf("ERW");
else if (mbi.Protect & PAGE_READONLY)
printf("-R-");
else if (mbi.Protect & PAGE_READWRITE)
printf("-RW");
else if (mbi.Protect & PAGE_WRITECOPY)
printf("WCOPY");
else if (mbi.Protect & PAGE_EXECUTE_WRITECOPY)
printf("EWCOPY");
// 输出内存块的大小.
printf( " 大小:0x%X\n", mbi.RegionSize );
// 索引到下一个内存块
dwBlockAddress += mbi.RegionSize;
// 累加内存块的大小
dwSize += mbi.RegionSize;
}
}
statue.size = dwSize;
memoryStatue->push_back( statue );
// 遍历下一块虚拟内存.
dwAddress += dwSize;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
list vmList;
queryVirtualMemoryStatue( GetCurrentProcess( ) , &vmList );
return 0;
}
==========================
// 内存管理_修改内存分页属性.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
DWORD handleException( void *pBuff , DWORD dwOldProtect ) {
// 将内存属性修改回原来的属性
VirtualProtect( pBuff , 10 * sizeof( DWORD ) , dwOldProtect , &dwOldProtect );
// 返回EXCEPTION_CONTINUE_EXECUTION时, 会在异常发生点再次执行代码.
return EXCEPTION_CONTINUE_EXECUTION;
}
int _tmain(int argc, _TCHAR* argv[])
{
// 1. 得到进程句柄
HANDLE hDict = OpenProcess(PROCESS_VM_READ| PROCESS_VM_WRITE| PROCESS_VM_OPERATION,
FALSE,
1452);
// 2. 读取进程内存
TCHAR buff[512] = { 0 };
DWORD dwRead;
ReadProcessMemory( hDict ,
(LPVOID)0x5AE6538 ,
buff ,
20 ,
&dwRead );
wprintf(L"%s", buff);
//3. 写进程内存
WriteProcessMemory(hDict,
(LPVOID)0x5AE6538,
L"哈哈哈",
7,
&dwRead);
LPBYTE pDictBuff ;
pDictBuff = (LPBYTE)VirtualAllocEx( hDict ,
NULL ,
64 * 1024 ,
MEM_RESERVE | MEM_COMMIT ,
PAGE_READWRITE);
// 释放远程进程内存.
VirtualFreeEx(hDict, pDictBuff, 64 * 1024, MEM_DECOMMIT);
// 直接读写其它进程内存地址时, 实际上修改的是本进程的
// 虚拟内存地址.
//*pDictBuff = 10;
//VirtualProtectEx(hDict,
// (LPVOID)0x5AE6538,
// 10,
// PAGE_READONLY,
// &dwRead);
// 修改内存分页
DWORD* pBuff = new DWORD;
*pBuff = 0x12345678;
DWORD dwOldProtect = 0;
// 将当前执行代码的内存分页属性修改为只读
VirtualProtect( pBuff, /*需要和内存分页粒度对齐.如果不对齐,函数会自动向下取整*/
sizeof(DWORD), /*需要和内存分页粒度对齐,如果不对齐,会自动向上取证*/
PAGE_READONLY,
&dwOldProtect /*将旧的内存分页属性输出*/
);
HANDLE hProc = OpenProcess(PROCESS_VM_OPERATION,
FALSE,
512) ;
VirtualProtectEx(hProc,/*要修改的目标进程句柄*/
(LPVOID)0x1000,/*目标进程中的虚拟地址*/
sizeof(DWORD), /*需要和内存分页粒度对齐,如果不对齐,会自动向上取证*/
PAGE_READONLY,
&dwOldProtect /*将旧的内存分页属性输出*/
);
//__try {
// 尝试修改内存, 但这次会失败,因为没有写的权限
*pBuff = 0x87654321;
//}
//__except( handleException(pBuff,dwOldProtect) ) {
//}
return 0;
}
=============================
// 内存管理_操作其它进程的内存.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwPid = 0;
HANDLE hCalc = NULL;
LPVOID pRemoteBuff = NULL;
// 根据窗口句柄获取进程pid
GetWindowThreadProcessId( FindWindow( NULL , _T( "计算器" ) ) , &dwPid );
if( dwPid == 0 ) {
STARTUPINFO si = { sizeof( STARTUPINFO ) };
PROCESS_INFORMATION pi = { 0 };
CreateProcess( _T( "win32calc.exe" ) , 0 , 0 , 0 , 0 , 0 , 0 , 0 , &si , &pi );
hCalc = pi.hProcess;
}
else {
hCalc = OpenProcess( PROCESS_VM_OPERATION | PROCESS_VM_WRITE ,
FALSE ,
dwPid );
if( hCalc == NULL )
return 0;
}
// 在其它进程中开辟内存空间
pRemoteBuff = VirtualAllocEx( hCalc , /* 要开辟内存空间的进程句柄,句柄必须有PROCESS_VM_OPERATION权限 */
NULL , /* 在指定地址处开辟内存空间,传NULL表示由系统自己选择 */
4096 , /* 开辟的小 */
MEM_RESERVE | MEM_COMMIT , /* 开辟空间的标志 */
PAGE_EXECUTE_READWRITE /* 内存分页的保护属性 */
);
if( pRemoteBuff == NULL ) {
printf( "在远程进程开辟内存失败\n" );
return 0;
}
// 将数据写入内存
DWORD dwWrite = 0;
WriteProcessMemory( hCalc ,
pRemoteBuff ,
"Hello 15PB" ,
20 ,
&dwWrite );
printf( "可以使用windbg附加计算器,使用以下命令查看内存地址: da 0x%08X\n" , pRemoteBuff );
system( "pause" );
// 释放内存
VirtualFreeEx( hCalc , pRemoteBuff , 0 , MEM_RELEASE );
// 关闭句柄
CloseHandle( hCalc );
return 0;
}
===============================
// 内存管理_堆.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
class Tank {
private:
static HANDLE m_hHeap; // 堆的句柄
static int m_nHeapReferenceCount; // 在堆上创建对象的个数
private:
int m_nX;
int m_nY;
int m_nDirection;
int m_nId;
public:
// 重载new运算符
void* operator new( size_t nSize ){
// 创建堆
if( m_nHeapReferenceCount == 0 ) {
// 创建堆.
m_hHeap = HeapCreate( 0 , 0 , 0 );
}
// 增加堆中的对象个数.
++m_nHeapReferenceCount;
// 在堆中分配一块内存来保存对象.
return HeapAlloc( m_hHeap , 0 , sizeof( Tank ) );
}
// 重载delete运算符
void operator delete( void* pObj ) {
if( pObj == NULL )
return ;
// 在堆中释放对象的空间.
HeapFree( m_hHeap , 0 , pObj );
// 减掉一个堆中对象个数.
--m_nHeapReferenceCount;
// 如果堆中没有对象了, 销毁堆.
if( m_nHeapReferenceCount <= 0 ) {
// 销毁堆.
HeapDestroy( m_hHeap );
m_hHeap = NULL;
}
}
};
HANDLE Tank::m_hHeap; // 堆的句柄
int Tank::m_nHeapReferenceCount; // 在堆上创建对象的个数
int _tmain(int argc, _TCHAR* argv[])
{
//HeapCreate HeapAlloc(new), HeapFree(delete);
//HANDLE hHeap = HeapCreate(0, 0, 0);
//int* pArray = (int*)HeapAlloc(hHeap,
// 0,
// 10 * sizeof(int)
// );
HANDLE hHeap = NULL;
Tank* pTank = NULL;
// 创建一个堆
hHeap = HeapCreate( 0 , /* 创建堆的标志, 不使用任何特殊标志 */
0 , /* 堆的初始大小, 如果是0,则默认为一个内存分页的大小 */
0 /* 堆的最大大小, 如果是0,则堆的大小可以自动增长.*/
);
if( hHeap == NULL ) {
printf( "创建堆失败\n" );
return 0;
}
// 从堆中分配内存, 就如同使用new 或 malloc一样.
pTank = (Tank*)HeapAlloc( hHeap , /*堆的句柄*/
HEAP_ZERO_MEMORY , /*分配时把内存初始化为0*/
sizeof( Tank ) /*分配的大小*/
);
if( pTank == NULL ) {
printf( "在堆中申请内存失败\n" );
}
HeapFree( hHeap , 0 , pTank );
// 使用重载的new 和 delete
Tank* pTank1= new Tank( );
delete pTank1;
return 0;
}
=============================
// 内存管理_文件映射.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
int _tmain(int argc, _TCHAR* argv[])
{
// 文件映射步骤:
// 1. 打开文件(内核对象)
// 2. 创建文件映射对象(内核对象)
// 3. 将文件映射对象映射到虚拟内存.
HANDLE hFile = 0;
// 1. 打开文件.
hFile = CreateFile( L"内存管理_文件映射.cpp" ,
GENERIC_ALL ,
FILE_SHARE_READ ,
NULL ,
OPEN_EXISTING ,
FILE_ATTRIBUTE_NORMAL ,
NULL
);
if( hFile == INVALID_HANDLE_VALUE ) {
printf( "文件不存在\n" );
return 0;
}
DWORD dwHigSize = 0;
DWORD dwLowSize = GetFileSize( hFile , &dwHigSize );
// 2. 创建文件映射对象
HANDLE hMapping = CreateFileMapping( hFile , /* 被映射的文件对象 */
NULL , /* 安全描述符 */
PAGE_READWRITE,/* 映射到内存后的内存分页属性 */
dwHigSize , /* 映射的大小的高32位 */
dwLowSize , /* 映射大小的低32位 */
NULL /* 文件映射对象的全局名字 */
);
if( hMapping == NULL ) {
printf( "创建文件映射对象失败\n" );
CloseHandle( hFile );
return 0;
}
// 3. 将文件映射对象映射到内存.
LPVOID pBuff = NULL;
pBuff = MapViewOfFile( hMapping , /* 文件映射对象 */
FILE_MAP_ALL_ACCESS, /* 权限 */
0 , /* 映射到内存的文件偏移(低32位) */
0 , /* 映射到内存的文件偏移(高32位) */
50 /* 映射到内存的字节数 */
);
if( pBuff == NULL ) {
printf( "将文件内容映射到内存时失败\n" );
// 关闭文件映射
CloseHandle( hMapping );
CloseHandle( hFile );
}
// 修改内存, 同时也会影响文件
strcpy( (char*)pBuff , "Hello World\r\n" );
FlushViewOfFile(pBuff, 20);
// 取消映射
UnmapViewOfFile( pBuff );
// 关闭文件映射
CloseHandle( hMapping );
// 关闭文件
CloseHandle( hFile );
return 0;
}
=========================
// 006-01-内存管理_文件映射.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
int main()
{
HANDLE hMapping;
// 创建一个文件映射对象,可以不和任何文件进行关联
// 在Global空间中创建对象的名称需要用到管理员权限
hMapping = CreateFileMapping(INVALID_HANDLE_VALUE,/*文件句柄*/
NULL,
PAGE_READWRITE,
0,
4096,
L"Global\\15pb_wenjianyingshe");
// 将文件映射对象映射到进程的虚拟地址空间中
LPBYTE pBuff =
(LPBYTE)MapViewOfFile(hMapping,
FILE_MAP_READ | FILE_MAP_WRITE,
0, /*映射的偏移高32位*/
0,/*映射的偏移低32位*/
4096/*映射的字节数*/);
UnmapViewOfFile(pBuff);
CloseHandle(hMapping);
return 0;
}
===========================
// 006-02-内存管理_打开映射对象.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
int main()
{
// 打开文件映射对象
HANDLE hMap =
OpenFileMapping(GENERIC_READ | GENERIC_WRITE,
FALSE,
L"Global\\15pb_wenjianyingshe");
// 将文件映射对象映射到进程的虚拟地址空间中
LPBYTE p = (LPBYTE)MapViewOfFile(hMap,
FILE_MAP_READ | FILE_MAP_WRITE,
0,
0,
4096);
*(DWORD*)p = 0xFFFFFFFF;
UnmapViewOfFile(p);
CloseHandle(hMap);
return 0;
}