windows内存管理

// 内存管理_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;
}

你可能感兴趣的:(windows内存管理)