程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 如何訪問一個進程的內存空間

如何訪問一個進程的內存空間

編輯:Delphi
在WIN32中,每個應用程序都可“看見”4GB的線性地址空間,其中最開始的
  4MB和最後的2GB由操作系統保留,剩下不足2GB的空間用於應用程序私有空間。
  具體分配如下:0xFFFFFFFF-0xC0000000的1GB用於VxD、存儲器管理和文件系統;
  0xBFFFFFFF-0x80000000的1GB用於共享的WIN32 DLL、存儲器映射文件和共享存
  儲區;0x7FFFFFFF-0x00400000為每個進程的WIN32專用地址;0x003FFFFF-
  0x00001000為MS-DOS 和 WIN16應用程序;0x00000FFF-0x00000000為防止使用
  空指針的4,096字節。以上都是指邏輯地址,也就是虛擬內存。
      虛擬內存通常是由固定大小的塊來實現的,在WIN32中這些塊稱為“頁”,
  每頁大小為4,096字節。在Intel CPU結構中,通過在一個控制寄存器中設置一位
  來啟用分頁。啟用分頁時CPU並不能直接訪問內存,對每個地址要經過一個映射
  進程,通過一系列稱作“頁表”的查找表把虛擬內存地址映射成實際內存地址。
  通過使用硬件地址映射和頁表WIN32可使虛擬內存即有好的性能而且還提供保護。
  利用處理器的頁映射能力,操作系統為每個進程提供獨立的從邏輯地址到物理地
  址的映射,使每個進程的地址空間對另一個進程完全不可見。WIN32中也提供了
  一些訪問進程內存空間的函數,但使用時要謹慎,一不小心就有可能破壞被訪問
  的進程。本文介紹如何讀另一個進程的內存,寫內存與之相似,完善一下你也可
  以做個 FPE 之類的內存修改工具。好吧,先准備好編程利器Delphi 和 參考手
  冊 MSDN ,開始了!
    ReadProcessMemory 讀另一個進程的內存,原形如下:
      BOOL ReadProcessMemory(
      HANDLE hProcess,         // 被讀取進程的句柄;
      LPCVOID lpBaseAddress,      // 讀的起始地址;
      LPVOID lpBuffer,         // 存放讀取數據緩沖區;
      DWord nSize,         // 一次讀取的字節數;
      LPDWord lpNumberOfBytesRead // 實際讀取的字節數;
    );
  hProcess 進程句柄可由OpenProcess 函數得到,原形如下:
    HANDLE OpenProcess(
      DWord dwDesiredAccess, // 訪問標志;
      BOOL bInheritHandle,   // 繼承標志;
      DWord dwProcessId      // 進程ID;
    );
  當然,用完別忘了用 CloseHandle 關閉打開的句柄。
  讀另一個進程的內存 dwDesiredAccess 須指定為 PROCESS_VM_READ ,
  寫另一個進程的內存 dwDesiredAccess 須指定為 PROCESS_VM_WRITE ,
  繼承標志無所謂,進程ID可由 Process32First 和 Process32Next 得到,
  這兩個函數可以枚舉出所有開啟的進程,這樣進程的信息也就得到了。
  Process32First 和 Process32Next是由 TLHelp32 單元提供的,需在
  uses 裡加上TLHelp32。ToolsHelp32 封裝了一些訪問堆、線程、進程等
  的函數,只適用於Win9x,原形如下:
    BOOL WINAPI Process32First(
      HANDLE hSnapshot      // 由 CreateToolhelp32Snapshot 返回
                               的系統快照句柄;
      LPPROCESSENTRY32 lppe // 指向一個 PROCESSENTRY32 結構;
    );
    BOOL WINAPI Process32Next(
      HANDLE hSnapshot      // 由 CreateToolhelp32Snapshot 返回
                               的系統快照句柄;
      LPPROCESSENTRY32 lppe // 指向一個 PROCESSENTRY32 結構;
    );
  hSnapshot 由 CreateToolhelp32Snapshot 返回的系統快照句柄;
  CreateToolhelp32Snapshot 原形如下:
    HANDLE WINAPI CreateToolhelp32Snapshot(
      DWord dwFlags,      // 快照標志;
      DWord th32ProcessID // 進程ID;
    );
  現在需要的是進程的信息,所以將 dwFlags 指定為 TH32CS_SNAPPROCESS,
  th32ProcessID 忽略;PROCESSENTRY32 結構如下:
    typedef struct tagPROCESSENTRY32 {
      DWord dwSize;             // 結構大小;
      DWord cntUsage;           // 此進程的引用計數;
      DWord th32ProcessID;      // 進程ID;
      DWord th32DefaultHeapID;  // 進程默認堆ID;
      DWord th32ModuleID;       // 進程模塊ID;
      DWord cntThreads;         // 此進程開啟的線程計數;
      DWord th32ParentProcessID;// 父進程ID;
      LONG  pcPriClassBase;     // 線程優先權;
      DWord dwFlags;            // 保留;
      char szExeFile[MAX_PATH]; // 進程全名;
    } PROCESSENTRY32;
  至此,所用到的主要函數已介紹完,實現讀內存只要從下到上依次調用
  上述函數即可,具體參見原代碼:

  procedure TForm1.Button1Click(Sender: TObject);
  var
    FSnapshotHandle:THandle;
    FProcessEntry32:TProcessEntry32;
    Ret : BOOL;
    ProcessID : integer;
    ProcessHndle : THandle;
    lpBuffer:pByte;
    nSize: DWord;
    lpNumberOfBytesRead: DWord;
    i:integer;
    s:string;
  begin
    FSnapshotHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
      //創建系統快照
    FProcessEntry32.dwSize:=Sizeof(FProcessEntry32);
      //先初始化 FProcessEntry32 的大小
    Ret:=Process32First(FSnapshotHandle,FProcessEntry32);
    while Ret do
    begin
      s:=ExtractFileName(FProcessEntry32.szExeFile);
      if s='KERNEL32.DLL' then
      begin
        ProcessID:=FProcessEntry32.th32ProcessID;
        s:=';
        break;
      end;
      Ret:=Process32Next(FSnapshotHandle,FProcessEntry32);
    end;
     //循環枚舉出系統開啟的所有進程,找出“Kernel32.dll”
    CloseHandle(FSnapshotHandle);
    Memo1.Lines.Clear ;
    memo1.lines.add('Process ID '+IntToHex(FProcessEntry32.th32ProcessID,8));
    memo1.lines.Add('File name '+FProcessEntry32.szExeFile);
      ////輸出進程的一些信息
    nSize:=4;
    lpBuffer:=AllocMem(nSize);
    ProcessHndle:=OpenProcess(PROCESS_VM_READ,false,ProcessID);
    memo1.Lines.Add ('Process Handle '+intTohex(ProcessHndle,8));
    for i:=$00800001 to $0080005f do
    begin
      ReadProcessMemory(
                       ProcessHndle,
                       Pointer(i),
                       lpBuffer,
                       nSize,
                       lpNumberOfBytesRead
                       );
      s:=s+intTohex(lpBuffer^,2)+' ';
        //讀取內容
      if (i mod 16) =0 then
      begin
        Memo1.Lines.Add(s);
        s:=';
      end;
        //格式化輸出
    end;
    FreeMem(lpBuffer,nSize);
    CloseHandle(ProcessHndle);
     //關閉句柄,釋放內存
  end;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved