1. 程式人生 > 其它 >記憶體對映檔案(程序通訊)

記憶體對映檔案(程序通訊)

記憶體對映檔案用於程序通訊的概念

  許多應用程式會在執行過程中建立一些資料,並需要將這些資料傳輸給其他程序,或與其他程序共享這些資料。如果為了共享資料而必須讓應用程式在磁碟上建立資料檔案並把資料儲存在檔案中,那將非常不方便。

  Microsoft意識到了這一點,並加入了相應的支援,讓系統能夠建立以頁交換檔案為後備儲存器的記憶體對映檔案,這樣就不需要用磁碟上專門的檔案來作為後備儲存器了。這種方法和為磁碟檔案建立記憶體對映檔案的方法幾乎完全相同,甚至更簡單。一方面,由於不必建立或開啟一個專門的磁碟檔案,因此不需要呼叫CreateFile。我們只需要像原來那樣呼叫CreateFileMapping,並將INVALID_HANDLE_VALUE作為hFile引數傳入。這告訴系統我們建立的檔案對映物件的物理儲存器不是磁碟上的檔案,而是希望系統從頁交換檔案中調撥物理儲存器。

所需分配的儲存器大小由CreateFileMapping的dwMaximumSizeHigh和dwMaxinumSizeLow引數決定。

  記憶體檔案對映是Windows的一種記憶體管理方法,提供了一個統一的記憶體管理特徵,使應用程式可以通過記憶體指標對磁碟上的檔案進行訪問,其過程就如同對載入了檔案的記憶體的訪問。通過檔案對映這種使磁碟檔案的全部或部分內容與程序虛擬地址空間的某個區域建立對映關聯的能力,可以直接對被對映的檔案進行訪問,而不必執行檔案I/O操作也無需對檔案內容進行緩衝處理。

一、記憶體對映檔案可以分為兩種

  (1)一種是普通的檔案,它需要一個普通的檔案控制代碼,用於快速的讀寫檔案,這種檔案的資料在程序退出後會儲存在硬碟上,所以程序在下次執行時可以得到之前的資料;


  (2)另一種是頁檔案,當建立記憶體對映檔案的時候傳入無效的控制代碼,這時會把頁檔案當作臨時的共享儲存空間,當程序退出後這些資料是不會儲存下來的。因為共享記憶體通常只關注執行期間的資料共享,所以一般是使用這種記憶體對映檔案。

二、記憶體對映檔案在用於程序通訊時分為兩種

  命名檔案對映物件(為物件命名)、匿名檔案對映物件(複製物件控制代碼)

三、記憶體對映檔案在用於程序通訊概念圖

 

 

 

 


 

記憶體對映檔案用於程序通訊的流程

要使用記憶體對映檔案,需要執行下面三個步驟。
  (1)建立或開啟一個檔案核心物件,該物件標識了我們想要用作記憶體對映檔案的那個磁碟檔案。
  (2)建立一個檔案對映核心物件(file-mapping kernel object)來告訴系統檔案的大小以及我們打算如何訪問檔案。
  (3)告訴系統把檔案對映物件的部分或全部對映到程序的地址空間中。

用完記憶體對映檔案之後,必須執行下面三個步驟來做清理工作。
  (1)告訴系統從程序地址空間中取消對檔案對映核心物件的對映。
  (2)關閉檔案對映核心物件。
  (3)關閉檔案核心物件。

一、建立或開啟檔案核心物件

我們總是通過呼叫CreateFile函式來建立或開啟一個檔案核心物件:

HANDLE CreateFile(
LPCTSTR lpFileName, // 想建立的或開啟的檔案的名稱(既可以包含路徑,也可以不包含路徑)
DWORD dwDesiredAccess, // 如何訪問檔案內容;0(獲得檔案屬性)、GENERIC_READ、GENERIC_WRITE、GENERIC_READ|GENERIC_WRITE
DWORD dwShareMode, // 如何共享這個檔案
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全屬性
DWORD dwCreationDispostion , 
DWORD dwFlagsAndAttributes, 
HANDLE hTemplateFile);

關於第二引數:
  0 表示該物件的裝置查詢訪問許可權。應用程式可以在不訪問裝置的情況下查詢裝置屬性。
  GENERIC_READ 該物件的讀訪問許可權。可以從檔案中讀取資料並移動檔案指標。結合GENERIC_WRITE進行讀寫訪問。
  GENERIC_WRITE 物件的寫訪問許可權。資料可以寫入檔案,檔案指標可以移動。結合GENERIC_READ進行讀寫訪問。

關於第三引數:

  0 想要獨佔對檔案的訪問,使其他程序無法開啟同一檔案
  FILE_SHARE_READ 物件的後續開啟操作只有在請求讀訪問時才會成功。
  FILE_SHARE_WRITE 物件的後續開啟操作只有在請求寫訪問時才會成功。

如果CreateFile成功地建立或打開了指定的檔案,它會返回一個檔案核心物件的控制代碼。否則,它返回INVALID_HANDLE_VALUE。

二、建立檔案對映的核心物件

呼叫CreateFile是為了告訴作業系統檔案對映的物理儲存器所在的位置。傳入的路徑是檔案在磁碟(也可以是網路或光碟)上所在的位置,檔案對映物件的物理儲存器來自該檔案。現在我們必須告訴系統檔案對映物件需要多大的物理儲存器。為了達到這一目的,必須調CreateFileMapping。

這個函式為指定的檔案建立一個命名或未命名的檔案對映物件。

HANDLE CreateFileMapping(
HANDLE hFile, // 需要對映到程序空間的檔案的控制代碼,如果是通過檔案對映物件進行程序間通訊,這個引數可以傳INVALID_HANDLE_VALUE
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 指向SECURITY_ATTRIBUTES結構體,它用於檔案對映核心物件,一般傳NULL
DWORD flProtect, // 對映的頁面要指定的保護屬性
DWORD dwMaximumSizeHigh, // 描述記憶體對映檔案最大的大小:由SizeHigh(高32位)和SizeLow(低32位,如下)組成
DWORD dwMaximumSizeLow, // 描述記憶體對映檔案最大的大小:由SizeHigh(高32位,如上)和SizeLow(低32位)組成
LPCTSTR lpName );    // 檔案對映物件的名稱

記憶體對映檔案的物理儲存器來自於磁碟上的檔案,而不是從系統的頁交換檔案中分配的。建立一個檔案對映物件的時候,系統不會預訂一塊地址空間區域並把檔案對映到該區域中

關於第三引數:

   

關於第四五引數:

  CreateFileMapping函式的主要目的是為了確保有足夠的物理儲存器可供檔案對映物件使用。這兩個引數告訴系統記憶體對映檔案的最大大小,以位元組為單位。由於Windows支援的最大檔案大小可以用64位整數表示,因此這裡必須使用兩個32位值,其中引數dwMaximumSizeHigh表示高32位,而引數dwMaximumSizeLow則表示低32位。對小於4GB的檔案來說, dwMaximumSizeHigh始終為0。

 

三、將檔案的資料對映到程序的地址空間

在建立了檔案對映物件之後,還需要為檔案的資料預訂一塊地址空間區域並將檔案的資料作為物理儲存器調撥給區域。這可以通過呼叫MapViewOfFile來實現。這個函式返回這塊區域的地址。

這個函式將一個檔案的檢視對映到呼叫程序的地址空間。

LPVOID MapViewOfFile( 
HANDLE hFileMappingObject, // 檔案對映物件的控制代碼,呼叫Create/OpenFileMapping返回的
DWORD dwDesiredAccess, // 如何訪問資料
DWORD dwFileOffsetHigh, // 關於將檔案中哪個位元組對映到檢視中的第一個位元組
DWORD dwFileOffsetLow, // 關於將檔案中哪個位元組對映到檢視中的第一個位元組
DWORD dwNumberOfBytesToMap );    // 把資料檔案中的多少對映到檢視中

關於第二引數:

   

關於第三四引數:

  把檔案的一個檢視對映到程序的地址空間中時,必須告訴系統兩件事情。第一,我們必須告訴系統應該把資料檔案中的哪個位元組對映到檢視中的第一個位元組。這是通過引數dwFileOffsetHigh和dwFileOfsetLow來指定的。由於Windows支援的檔案大小最大可以到16 EB,因此編移量也必須用64位值來指定,其中高32位的部分由dwFileOffsetHigh表示,而低32位的部分則由dwFileOffsetLow表示。注意,檔案的偏移量必須是系統分配粒度的整數倍。(到目前為止,在所有版本的Windows中,分配粒度全部都是64 KB)

 

四、從程序的地址空間撤銷對檔案資料的對映

不再需要把檔案的資料對映到程序的地址空間中時,可以呼叫下面的函式來釋放記憶體區域:

  BOOL UnmapviewofFile (PVOID pvBaseAddress);

這個函式唯一的引數pvBaseAddress用來指定區域的基地址,它必須和MapViewOfFile的返回值相同。確定呼叫UnmapViewOfFile,如果不這樣做,在程序終止之前,區域將得不,到釋放。在呼叫MapViewOFile的時候,系統總是會在程序的地址空間中預訂一塊新的區域,它不會釋放之前預訂的任何區域。

如果需要確保所做的修改已經被寫入到磁碟中,那麼可以呼叫FlushViewOfFile,這個函式用來強制系統把部分或全部修改過的資料寫回到磁碟中


這個函式向磁碟寫入檔案對映檢視內的一個位元組範圍。

BOOL FlushViewOfFile( 
LPCVOID lpBaseAddress, // 記憶體對映檔案的檢視中第一個位元組的地址
DWORD dwNumberOfBytesToFlush );    // 想重新整理的位元組數

 

五、關閉檔案對映物件和檔案物件

呼叫CloseHandle關閉兩個控制代碼

 


程序通訊 --- 命名記憶體對映檔案

建立命名檔案對映物件函式內部呼叫了CreateFileMapping函式建立一個命名記憶體物件,並通過MapViewOfFile函式用於對映一塊虛擬記憶體,得到虛擬地址;

開啟命名檔案對映物件函式內部呼叫了OpenFileMapping函式開啟對映物件,並通過MapViewOfFile函式用於對映一塊虛擬記憶體,得到虛擬地址;

A程序

//建立一個命名記憶體對映物件
if (SunCreateMemroyMappingEx(ACCESS_WRITE, 0, 0x1000, _T("SHINE"), &MappingHandle, &VirtualAddress) == FALSE)

BOOL SunCreateMemroyMappingEx(
DWORD ReadOrWrite,
DWORD MaximumSizeHigh,    
DWORD MaximumSizeLow,    
LPCTSTR ObjectName,
_Out_ LPHANDLE MappingHandle,
_Out_ ULONG_PTR* VirtualAddress)

引數解釋:

//DWORD MaximumSizeHigh,
DWORD MaximumSizeLow,
如果低位MaximumSizeLow存的是0x1000,代表檔案大小0x1000(4096bytes),
且如果此時高位MaximumSizeHigh為1,代表低位的0x1000全部填滿,向高位進1,代表檔案大小4G(4096BYTES),
如果此時高位MaximumSizeHigh為10的話,檔案大小共10x4g;


//LPCTSTR ObjectName
物件名ObjectName只能用GUID(全球唯一身法碼,網絡卡)


//LPHANDLE MappingHandle 返回值(不能傳空)
//ULONG_PTR* VirtualAddress 被修改的記憶體(不能傳空)

//內部呼叫
CreateFileMapping函式建立一個命名記憶體物件
MapViewOfFile函式用於對映一塊虛擬記憶體,得到虛擬地址

 

B程序

//開啟命名檔案對映物件
if (SunOpenMemoryMappingEx(ACCESS_WRITE, FALSE, _T("SHINE"), &MappingHandle, &VirtualAddress) == FALSE)

BOOL SunOpenMemoryMappingEx(
OPERATION ReadOrWrite, 
BOOL IsInheritHandle, 
LPCTSTR ObjectName,
_Out_ LPHANDLE MappingHandle,
_Out_ ULONG_PTR* VirtualAddress)

引數解釋:

//LPCTSTR ObjectName(不能傳空),傳A程序建立時的OjectName
//LPHANDLE MappingHandle:返回值(不能傳空)
//ULONG_PTR* VirtualAddress:被修改的記憶體(不能傳空)

//內部呼叫
OpenFileMapping函式開啟對映物件
MapViewOfFile函式用於對映一塊虛擬記憶體,得到虛擬地址

 

詳細程式碼

A程序:

#include "Process(A).h"


void _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
    setlocale(LC_ALL, "chs");
    _tprintf(_T("我是程序A:\r\n"));
    Sub_1();   //命名物件

    _tprintf(_T("Input AnyKey To Exit\r\n"));
    _gettchar();
    _gettchar();
    return;
}

void Sub_1()
{

    HANDLE        MappingHandle = NULL;
    ULONG_PTR    VirtualAddress = NULL;


    DWORD       LastError = 0;
    //Mapping 對映
    //Image   映象
    //PageSize 0x1000 4096Bytes 


    //建立一個命名記憶體對映物件
    if (SunCreateMemroyMappingEx(ACCESS_WRITE, 0, 0x1000, _T("SHINE"), &MappingHandle, &VirtualAddress) == FALSE)
    {
        LastError = GetLastError();
    }
    else
    {
        __try
        {
            
            memcpy((LPVOID)VirtualAddress, _T("我將無我,不負人民"), sizeof(TCHAR)*(_tcslen(_T("我將無我,不負人民")) + 1));
            //將資料拷貝到記憶體中    (對映

            if (VirtualAddress != NULL)
            {
                _tprintf(_T("%s\r\n"), (TCHAR*)VirtualAddress);
            }
            
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
            LastError = GetExceptionCode();
        }
    

    }
    _tprintf(_T("Input AnyKey To Continue\r\n"));
    _gettchar();
    if(VirtualAddress!=NULL)
    {
        _tprintf(_T("%s\r\n"), (TCHAR*)VirtualAddress);
    }
    SunUnmapMemoryEx(MappingHandle, VirtualAddress); 
    //消亡對映物件
    
    return;
}



/*建立一個命名檔案對映物件*/
BOOL SunCreateMemroyMappingEx(OPERATION ReadOrWrite, DWORD MaximumSizeHigh, 
    DWORD MaximumSizeLow, LPCTSTR ObjectName, 
    _Out_ LPHANDLE MappingHandle, _Out_ ULONG_PTR* VirtualAddress)
{
    DWORD DesiredAccess = 0;    //期待如何使用
    DWORD Protect = 0;            //保護屬性
    HANDLE v1 = NULL;
    LPVOID v5 = NULL;
    int    LastError = 0;

    //MappingHandle,VirtualAddress不能傳空
    if (MappingHandle == NULL || VirtualAddress == NULL)
    {
        LastError = ERROR_INVALID_PARAMETER;

        goto Exit;
    }

    //讀寫屬性設定
    if (ReadOrWrite == ACCESS_READ)
    {
        Protect = PAGE_READONLY;
        DesiredAccess = SECTION_MAP_READ;
    }
    else if (ReadOrWrite == ACCESS_WRITE)
    {

        Protect = PAGE_READWRITE;
        DesiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE;
    }
    else
    {
        LastError = ERROR_INVALID_PARAMETER;
        goto Exit;
    }

    __try
    {
        //建立一個命名記憶體物件

        //SunctionObject //MappingObject

        v1 = CreateFileMapping(INVALID_HANDLE_VALUE, 
            NULL, Protect, MaximumSizeHigh, MaximumSizeLow, ObjectName);
        if (v1 != NULL)
        {

            *MappingHandle = v1;//v1賦值給返回值變數


            //通過控制代碼獲得對映的虛擬記憶體
            v5 = MapViewOfFile(v1, DesiredAccess, 0, 0, 0);

            if (v5 != NULL)
            {
                (*VirtualAddress) = (ULONG_PTR)v5;

                return TRUE;
            }
        }

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        LastError = GetExceptionCode();

        goto Exit;
    }
Exit:
    SetLastError(LastError);
    return FALSE;
}


/*消亡對映物件*/
void SunUnmapMemoryEx(_In_ HANDLE MappingHandle, _In_ ULONG_PTR VirtualAddress)
{
    __try
    {
        if (UnmapViewOfFile((void*)VirtualAddress))
        {
            SunCloseHandle(MappingHandle);
        }

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        SetLastError(GetExceptionCode());
    }

}


bool SunCloseHandle(HANDLE HandleValue)
{
    DWORD HandleFlags;
    if (GetHandleInformation(HandleValue, &HandleFlags)
        && (HandleFlags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != HANDLE_FLAG_PROTECT_FROM_CLOSE)
        return !!CloseHandle(HandleValue);
    return false;
}
 

 

B程序:

#include "Process(B).h"



void _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
    setlocale(LC_ALL, "chs");

    _tprintf(_T("我是程序B:\r\n"));
    Sub_1();   //命名物件



    _tprintf(_T("Input AnyKey To Exit\r\n"));
    _gettchar();
    _gettchar();
    return;
}

void Sub_1()
{
    HANDLE        MappingHandle = NULL;
    ULONG_PTR    VirtualAddress = NULL;
    DWORD       LastError = 0;

    //開啟命名檔案對映物件
    if (SunOpenMemoryMappingEx(ACCESS_WRITE, FALSE, _T("SHINE"), &MappingHandle, &VirtualAddress) == FALSE)
    {
        GetLastError();
    }
    else
    {



        __try
        {

            _tprintf(_T("%s\r\n"), (TCHAR*)VirtualAddress);            //輸出A程序曾寫入的記憶體
            memcpy((LPVOID)VirtualAddress, _T("為人民服務"), sizeof(TCHAR)*(_tcslen(_T("為人民服務")) + 1));    
            //B程序重新寫這塊記憶體,之後A程序再輸出一次,結果為"為人民服務",而不是"我將無我,不負人民"
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            LastError = GetExceptionCode();
        }    

    }
    SunUnmapMemoryEx(MappingHandle, VirtualAddress);
    return;
}

/*開啟命名檔案對映物件*/
BOOL SunOpenMemoryMappingEx(OPERATION ReadOrWrite, BOOL IsInheritHandle, 
    LPCTSTR ObjectName, _Out_ LPHANDLE MappingHandle,_Out_ ULONG_PTR* VirtualAddress)
{
    DWORD DesiredAccess = 0;
    HANDLE v1 = NULL;
    LPVOID v5 = NULL;
    int    LastError = 0;

    
    if (ObjectName == NULL || MappingHandle == NULL || VirtualAddress == NULL)
    {
        LastError = ERROR_INVALID_PARAMETER;

        goto Exit;
    }
    if (ReadOrWrite == ACCESS_READ)
    {

        DesiredAccess = SECTION_MAP_READ;

    }
    else if (ReadOrWrite == ACCESS_WRITE)
    {


        DesiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE;
    }
    else
    {
        LastError = ERROR_INVALID_PARAMETER;

        goto Exit;
    }



    __try
    {
        v1 = OpenFileMapping(DesiredAccess, IsInheritHandle, ObjectName);
        if (v1 != NULL)
        {

            *MappingHandle = v1;

            //MapViewOfFile函式用於對映一塊虛擬記憶體,得到虛擬地址
            v5 = MapViewOfFile(v1, DesiredAccess, 0, 0, 0);

            if (v5 != NULL)
            {
                (*VirtualAddress) = (ULONG_PTR)v5;

                return TRUE;
            }
        }

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        LastError = GetExceptionCode();

        goto Exit;
    }

Exit:
    SetLastError(LastError);
    return FALSE;
}
void SunUnmapMemoryEx(HANDLE MappingHandle, ULONG_PTR VirtualAddress)
{
    __try
    {
        if (UnmapViewOfFile((void*)VirtualAddress))
        {
            SunCloseHandle(MappingHandle);
        }

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        SetLastError(GetExceptionCode());
    }

}
bool SunCloseHandle(HANDLE HandleValue)
{
    DWORD HandleFlags;
    if (GetHandleInformation(HandleValue, &HandleFlags)
        && (HandleFlags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != HANDLE_FLAG_PROTECT_FROM_CLOSE)
        return !!CloseHandle(HandleValue);
    return false;
}

 


 

程序通訊 --- 匿名記憶體對映檔案

建立匿名檔案對映物件和建立命名的相同,只不過ObjectName傳NULL;

開啟匿名檔案對映物件要用到暴力搜尋控制代碼表獲得A程序的物件控制代碼,根據物件控制代碼獲得其建立的匿名檔案對映物件的MappingHandle,再通過拷貝DuplicateHandle函式獲得對映物件控制代碼;


A程序

//建立時同命名檔案對映物件,只不過ObjectName傳NULL
//建立一個匿名記憶體對映物件
if (SunCreateMemroyMappingEx(ACCESS_WRITE, 0, 0x1000, NULL, &MappingHandle, &VirtualAddress) == FALSE)

BOOL SunCreateMemroyMappingEx(
DWORD ReadOrWrite,
DWORD MaximumSizeHigh,    
DWORD MaximumSizeLow,    
LPCTSTR ObjectName,
_Out_ LPHANDLE MappingHandle,
_Out_ ULONG_PTR* VirtualAddress)

引數解釋:

//DWORD MaximumSizeHigh,
DWORD MaximumSizeLow,
如果低位MaximumSizeLow存的是0x1000,代表檔案大小0x1000(4096bytes),
且如果此時高位MaximumSizeHigh為1,代表低位的0x1000全部填滿,向高位進1,代表檔案大小4G(4096BYTES),
如果此時高位MaximumSizeHigh為10的話,檔案大小共10x4g;


//LPCTSTR ObjectName 物件名傳NULL
//LPHANDLE MappingHandle 返回值(不能傳空)
//ULONG_PTR* VirtualAddress 被修改的記憶體(不能傳空)

//內部呼叫
CreateFileMapping函式建立一個命名記憶體物件
MapViewOfFile函式用於對映一塊虛擬記憶體,得到虛擬地址

 B程序

暴力搜尋控制代碼表獲得A程序的物件控制代碼,根據物件控制代碼獲得其建立的匿名檔案對映物件的MappingHandle(本程式碼中還未涉及暴力搜尋),這裡就先拿A程序Pid獲取A程序控制代碼,並且傳入A程序中的MappingHandle。

//根據目標程序的ID開啟目標程序
ProcessHandle = SunOpenProcess(PROCESS_DUP_HANDLE, FALSE, ProcessIdentify);

 

拷貝DuplicateHandle函式獲得對映物件控制代碼

  根據A程序控制代碼和A的MappingHandle控制代碼值,從A控制代碼表

//DuplicateHandle獲取程序虛擬空間地址
BOOL IsOk = DuplicateHandle(ProcessHandle, MappingHandle, GetCurrentProcess(), &v1, 0, FALSE, DUPLICATE_SAME_ACCESS);

 

詳細程式碼

A程序:

#include "Process(A).h"



void _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
    setlocale(LC_ALL, "chs");

    Sub_1();  
    _tprintf(_T("Input AnyKey To Exit\r\n"));
    _gettchar();
    _gettchar();
    return;
}

void Sub_1()
{

    HANDLE        MappingHandle  = NULL;
    ULONG_PTR    VirtualAddress = NULL;

    __try
    {
        
        //建立一個匿名記憶體對映物件
        if (SunCreateMemroyMappingEx(ACCESS_WRITE, 0, 0x1000, NULL, &MappingHandle, &VirtualAddress) == FALSE)
        {
            goto Exit;
        }
        else
        {
            //獲得當前程序ID
            _tprintf(_T("當前程序Identify:%d\r\n"), GetCurrentProcessId());
            _tprintf(_T("當前程序建立(SunctionObject)的核心物件控制代碼:%d\r\n"),MappingHandle);
            _tprintf(_T("執行Process(B)程式\r\n"));
            memcpy((LPVOID)VirtualAddress, _T("我將無我,不負人民"), sizeof(TCHAR)*(_tcslen(_T("我將無我,不負人民")) + 1));

            _tprintf(_T("Input AnyKey To Continue\r\n"));
            _gettchar();
            _tprintf(_T("%s\r\n"), (TCHAR*)VirtualAddress);

        }

    
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        SetLastError(GetExceptionCode());
    }


Exit:

    if (MappingHandle!=NULL&&VirtualAddress!=NULL)
    {
        SunUnmapMemoryEx(MappingHandle,VirtualAddress);
    }

    
    return;
}
BOOL SunCreateMemroyMappingEx(DWORD ReadOrWrite,DWORD MaximumSizeHigh,
    DWORD MaximumSizeLow,LPCTSTR ObjectName,LPHANDLE MappingHandle,ULONG_PTR* VirtualAddress)
{
    DWORD DesiredAccess = 0;    //期待如何使用
    DWORD Protect = 0;            //保護屬性
    HANDLE v1 = NULL;
    LPVOID v5 = NULL;
    int    LastError = 0;

    //MappingHandle,VirtualAddress不能傳空
    if (MappingHandle == NULL || VirtualAddress == NULL)
    {
        LastError  = ERROR_INVALID_PARAMETER;

        goto Exit;
    }
    //讀寫屬性設定
    if (ReadOrWrite == ACCESS_READ)
    {
        Protect = PAGE_READONLY;
        DesiredAccess = SECTION_MAP_READ;

    }
    else if (ReadOrWrite == ACCESS_WRITE)
    {

        Protect = PAGE_READWRITE;
        DesiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE;
    }
    else
    {
        LastError = ERROR_INVALID_PARAMETER;

        goto Exit;
    }

    __try
    {
        //建立一個匿名記憶體物件
            //Protect記憶體讀寫屬性
        v1 = CreateFileMapping(INVALID_HANDLE_VALUE, 
            NULL, Protect, MaximumSizeHigh,MaximumSizeLow,ObjectName);
        if (v1 != NULL)
        {
            //函式呼叫成功    
            *MappingHandle = v1;


            //通過控制代碼獲取虛擬地址
            v5 = MapViewOfFile(v1, DesiredAccess, 0, 0, 0);

            if (v5 != NULL)
            {
                (*VirtualAddress) = (ULONG_PTR)v5;

                return TRUE;
            }
        }
        
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        LastError = GetExceptionCode();

        goto Exit;
    }
Exit:
    SetLastError(LastError);
    return FALSE;
}

/*消亡對映物件*/
void SunUnmapMemoryEx(HANDLE MappingHandle, ULONG_PTR VirtualAddress)
{
    __try
    {
        //UnmapViewOfFile函式:回收虛擬地址
        if (UnmapViewOfFile((void*)VirtualAddress))
        {
            SunCloseHandle(MappingHandle);
        }

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        SetLastError(GetExceptionCode());
    }
    
}
bool SunCloseHandle(HANDLE HandleValue)
{
    DWORD HandleFlags;
    if (GetHandleInformation(HandleValue, &HandleFlags)
        && (HandleFlags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != HANDLE_FLAG_PROTECT_FROM_CLOSE)
        return !!CloseHandle(HandleValue);
    return false;
}

 

B程序:

#include "Process(B).h"

BOOL __EnableDebugPrivilege = TRUE;
void _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
    setlocale(LC_ALL, "chs");
    
    Sub_1(); 
    _tprintf(_T("Input AnyKey To Exit\r\n"));
    _gettchar();
    _gettchar();
    return;
}

void Sub_1()
{
    HANDLE      ProcessIdentify = 0;
    HANDLE    MappingHandle = NULL;
    ULONG_PTR    VirtualAddress = NULL;
    HANDLE      v1 = NULL;
    HANDLE      ProcessHandle = NULL;

    _tprintf(_T("輸入Process(A)程序Identify與核心物件的控制代碼值\r\n"));

    __try
    {

        //如何知道程序
        _tscanf(_T("%d"), &ProcessIdentify);
        _tscanf(_T("%d"), &MappingHandle);


        //根據目標程序的ID開啟目標程序
        ProcessHandle = SunOpenProcess(PROCESS_DUP_HANDLE, FALSE, ProcessIdentify);
        if (ProcessHandle == NULL)
        {
            goto Exit;
        }

        //Anti策略
        //DuplicateHandle獲取程序虛擬空間地址
        BOOL IsOk = DuplicateHandle(ProcessHandle, MappingHandle, 
            GetCurrentProcess(), &v1, 0, FALSE, DUPLICATE_SAME_ACCESS);
        
        if ((VirtualAddress = (ULONG_PTR)MapViewOfFile(v1,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0))==NULL)
        {
            int LastError = GetLastError();
            goto Exit;
        }
        else
        {
            _tprintf(_T("%s\r\n"), (TCHAR*)VirtualAddress);
            memcpy((LPVOID)VirtualAddress, _T("為人民服務"), sizeof(TCHAR)*(_tcslen(_T("為人民服務")) + 1));

        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        SetLastError(GetExceptionCode());
    }
Exit:
    if (ProcessHandle!=NULL)
    {
        SunCloseHandle(ProcessHandle);
    }
    if (v1!=NULL)
    {
        SunUnmapMemoryEx(v1,VirtualAddress);
    }

    return;
}


void SunUnmapMemoryEx(HANDLE MappingHandle, ULONG_PTR VirtualAddress)
{
    __try
    {
        if (UnmapViewOfFile((void*)VirtualAddress))
        {
            SunCloseHandle(MappingHandle);
        }

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        SetLastError(GetExceptionCode());
    }
    
}


bool SunCloseHandle(HANDLE HandleValue)
{
    DWORD HandleFlags;
    if (GetHandleInformation(HandleValue, &HandleFlags)
        && (HandleFlags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != HANDLE_FLAG_PROTECT_FROM_CLOSE)
        return !!CloseHandle(HandleValue);
    return false;
}


DWORD SunEnableSunDebugPrivilege(HANDLE ProcessHandle, BOOL IsEnable)
{
    DWORD  LastError;
    HANDLE TokenHandle = 0;

    if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
    {
        LastError = GetLastError();
        if (TokenHandle)
            CloseHandle(TokenHandle);
        return LastError;
    }
    TOKEN_PRIVILEGES TokenPrivileges;
    memset(&TokenPrivileges, 0, sizeof(TOKEN_PRIVILEGES));
    LUID v1;
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &v1))
    {
        LastError = GetLastError();
        CloseHandle(TokenHandle);
        return LastError;
    }
    TokenPrivileges.PrivilegeCount = 1;
    TokenPrivileges.Privileges[0].Luid = v1;
    if (IsEnable)
        TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        TokenPrivileges.Privileges[0].Attributes = 0;
    AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
    LastError = GetLastError();
    CloseHandle(TokenHandle);
    return LastError;
}


HANDLE SunOpenProcess(DWORD DesiredAccess, BOOL IsInheritHandle, HANDLE ProcessIdentify)
{
    if (__EnableDebugPrivilege)
    {
        SunEnableSunDebugPrivilege(GetCurrentProcess(), TRUE);
    }
    
    
    HANDLE ProcessHandle = OpenProcess(DesiredAccess, IsInheritHandle, (DWORD)ProcessIdentify);

    DWORD LastError = GetLastError();
    
    
    
    if (__EnableDebugPrivilege)
    {
        SunEnableSunDebugPrivilege(GetCurrentProcess(), FALSE);
    }
    SetLastError(LastError);
    return ProcessHandle;
}