如何访问一个进程的内存空间[1]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 ypyrock 的 blog

           如何访问一个进程的内存空间
    在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

本文关键:delphi api
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top