RSS订阅 | 匿名投稿
您的位置:网站首页 > 内存 > 正文

delphi 读另一个进程的内存

作者:admin 来源: 日期:2011/8/14 9:13:21 人气: 标签:

 在大富翁笔记里找到的
觉得还不错就发上来分享下
在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
function TReadMemory.GetProcessInfo: TList;
var
ProcessInfoList : TList;
ProcessInfo   : PProcessInfo;
hSnapShot    : THandle;
mProcessEntry32 : TProcessEntry32;
bFound     : Boolean;
begin
ProcessInfoList:=TList.Create;
ProcessInfoList.Clear;
hSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
mProcessEntry32.dwSize := Sizeof(mProcessEntry32);
bFound := Process32First(hSnapShot, mProcessEntry32);
while bFound do
begin
New(ProcessInfo);
ProcessInfo.ProcessExe := mProcessEntry32.szExeFile;
ProcessInfo.ProcessId := mProcessEntry32.th32ProcessID;
ProcessInfoList.Add(ProcessInfo);
bFound := Process32Next(hSnapShot, mProcessEntry32);
end;
Result := ProcessInfoList;
end;
这里用到
1:CreateToolhelp32Snapshot()创建系统快照句柄(hSnapShot是我们声明用来保存
创建的快照句柄)
2:Process32First、Process32Next是用来枚举进程
{=============================================}
{=============内存查找=========================}
{=============================================}
function TReadMemoryFrm.StartSearch: Boolean;
var
ProcHandle:Integer;
begin
Result:=False;
ReadMemoryProgress.Position:=0;
if Not CheckInput then Exit;
if FileName=TabSheet1.Caption then //-----------------------------------------搜索次数>1次
begin
PParameter.FirstSearch:=False;
PParameter.Data:=StrToInt(EdtSearchData.Text);
end else
begin               //-----------------------------------------第一次搜索
PParameter.FirstSearch:=True;
if PParameter.ProcessHandle>0 then
CloseHandle(PParameter.ProcessHandle);
ProcHandle:=OpenProcess(PROCESS_ALL_ACCESS,false,StrToInt(EdtProcID.Text));
if ProcHandle>0 then
begin
PParameter.Data:=StrToInt(EdtSearchData.Text);
Case DataType.ItemIndex of
0:PParameter.DataType:=1;
1:PParameter.DataType:=2;
2:PParameter.DataType:=4;
end;
end else Exit;
FileName:=TabSheet1.Caption;
PParameter.ProcessHandle:=ProcHandle;
end;
SearchButton.Enabled:=False;
ToolSearchMemory.Enabled:=False;
MemoryAddrList.Clear;
PReadMemory.StartSearch;
Result:=True;
end;
1: HANDLE OpenProcess(
DWORD   dwDesiredAccess, // 希望获得的访问权限
BOOL    bInheritHandle, // 指明是否希望所获得的句柄可以继承
DWORD   dwProcessId // 要访问的进程ID
);
分析内存块
//------------------------------------------------------------------------------分析内存块
function TReadMemoryThread.GetMemoryRegion: Boolean;
var
TempStartAddress : DWord;
TempEndAddress  : DWord;
I,J,k      : Integer;
NewMemoryRegions : array [0..40000] of TmemoryRegion;
begin
Result:=False;
MemoryRegionsIndex := 0;
TempStartAddress  := 1*1024*1024;
TempEndAddress   := 2*1024*1024;
TempEndAddress   := TempEndAddress*1024;
While (VirtualQueryEx(PParameter.ProcessHandle,
pointer(TempStartAddress),
MBI,
sizeof(MBI))>0) and (TempStartAddress<TempEndAddress) do
begin
if (MBI.State=MEM_COMMIT)  then
begin
if (MBI.Protect=PAGE_READWRITE) or
(MBI.Protect=PAGE_WRITECOPY) or
(MBI.Protect=PAGE_EXECUTE_READWRITE) or
(MBI.Protect=PAGE_EXECUTE_WRITECOPY)
then
begin
PMemoryRegion[MemoryRegionsIndex].BaseAddress:=Dword(MBI.BaseAddress);
PMemoryRegion[MemoryRegionsIndex].MemorySize:=MBI.RegionSize;
Inc(MemoryRegionsIndex);
end;
end;
TempStartAddress:=Dword(MBI.BaseAddress)+MBI.RegionSize;
end;
if MemoryRegionsIndex=0 then Exit;
//------------------------------------------------------------------------------判断内存块是否过大
J:=0;
for i:=0 to MemoryRegionsIndex-1 do
begin
if PMemoryRegion.MemorySize>$FFFF then
begin
for K:=0 to PMemoryRegion.MemorySize div $FFFF do
begin
if K=PMemoryRegion.MemorySize div $FFFF+1 then
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion.BaseAddress+K*$FFFF;
NewMemoryRegions[j].MemorySize:=PMemoryRegion.MemorySize Mod $FFFF;
end else
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion.BaseAddress+K*$FFFF;
NewMemoryRegions[j].MemorySize:=$FFFF;
end;
Inc(J);
end;
end else
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion.BaseAddress;
NewMemoryRegions[j].MemorySize:=PMemoryRegion.MemorySize;
Inc(J);
end;
end;
//------------------------------------------------------------------------------数据转换
MemoryRegionsIndex:=j;
for i:=0 to MemoryRegionsIndex-1 do
begin
PMemoryRegion.MemorySize:=NewMemoryRegions.MemorySize;
PMemoryRegion.BaseAddress:=NewMemoryRegions.BaseAddress;
end;
Result:=True;
end;
1:查找的内存大小
TempStartAddress  := 1*1024*1024;
TempEndAddress   := 2*1024*1024;
TempEndAddress   := TempEndAddress*1024;
2:VirtualQueryEx :查询地址空间中内存地址的信息。
参数:
hProcess  进程句柄。
LpAddress  查询内存的地址。
LpBuffer  指向MEMORY_BASIC_INFORMATION结构的指针,用于接收内存信息。
DwLength  MEMORY_BASIC_INFORMATION结构的大小。
返回值:
函数写入lpBuffer的字节数,如果不等于sizeof(MEMORY_BASIC_INFORMATION)表示失败。
http://www.vckbase.com/vckbase/function/viewfunc.asp?id=139 讲了这个API的详细信息
{=============================================}
{=============开始查找=========================}
{=============================================}
procedure TReadMemoryThread.Execute;
var
//StopAddr,StartAddr:Dword;
BeginTime,EndTime:String;
I:Integer;
begin
inherited;
while Not Terminated do
begin
AddrCount    := 0;
if PParameter.FirstSearch then
begin
if Not GetMemoryRegion then Exit;
GetMaxMemoryRange;
GetMinMemoryRange;
SendMessage(APPHandle,WM_READMEMORY,RM_MAXPROGRESS,MemoryRegionsIndex);
BeginTime:=FloatToStr(CPUTimeCounterQPC);
for I:=0 to MemoryRegionsIndex-1 do
begin
FirstCheckMemory(PMemoryRegion.BaseAddress,PMemoryRegion.MemorySize);
end;
EndTime:=FloatToStr(CPUTimeCounterQPC);
SendMessage(APPHandle,
WM_READMEMORY,
RM_USETIME,
StrToInt(Copy(EndTime,1,Pos(&#39;.&#39;,EndTime)-1))-StrToInt(Copy(BeginTime,1,Pos(&#39;.&#39;,BeginTime)-1)));
SendMessage(APPHandle,WM_READMEMORY,RM_ADDRCOUNT,AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_FINISH,RM_FINISH);
end else
begin
SendMessage(APPHandle,WM_READMEMORY,RM_MAXPROGRESS,100);
BeginTime:=FloatToStr(CPUTimeCounterQPC);
for i:=0 to High(PSearchAgain) do
begin
SecondCheckMemory(PSearchAgain.DataAddr);
end;
EndTime:=FloatToStr(CPUTimeCounterQPC);
SendMessage(APPHandle,
WM_READMEMORY,
RM_USETIME,
StrToInt(Copy(EndTime,1,Pos(&#39;.&#39;,EndTime)-1))-StrToInt(Copy(BeginTime,1,Pos(&#39;.&#39;,BeginTime)-1)));
SendMessage(APPHandle,WM_READMEMORY,RM_ADDRCOUNT,AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_FINISH,RM_FINISH);
end;
Suspend;
end;
end;
//------------------------------------------------------------------------------第一次查询
function TReadMemoryThread.FirstCheckMemory(Addr:Integer;ReadCount:Integer): Boolean;
var
i:Integer;
Buffer:TByteArray;
LPDW:DWORD;
begin
//Result:=False;
SendMessage(APPHandle,WM_READMEMORY,RM_GETPOS,RM_GETPOS);
//ZeroMemory(@Buffer,Sizeof(Buffer));
//SetLength(Buffer,ReadCount);
if ReadProcessMemory(PParameter.processhandle,pointer(Addr),pointer(@(buffer)),ReadCount,Lpdw) then
begin
if Lpdw>0 then
begin
I:=1;
While I<=Lpdw do
begin
case PParameter.DataType of
1:
begin
if PByte(@(Buffer))^=PParameter.Data then
begin
PSearchResult.Data:=PParameter.Data;
PSearchResult.DataAddr:=Addr+i-1;
PSearchResult.DataType:=PParameter.DataType;
if AddrCount<=99 then
begin
PSearchAgain[AddrCount].Data:=PParameter.Data;
PSearchAgain[AddrCount].DataType:=PParameter.DataType;
PSearchAgain[AddrCount].DataAddr:=Addr+i-1;
end;
Inc(AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_GETADDR,RM_GETADDR);
end;
end;
2:
begin
if PWord(@(Buffer))^=PParameter.Data then
begin
PSearchResult.Data:=PParameter.Data;
PSearchResult.DataAddr:=Addr+i-1;
PSearchResult.DataType:=PParameter.DataType;
if AddrCount<=99 then
begin
PSearchAgain[AddrCount].Data:=PParameter.Data;
PSearchAgain[AddrCount].DataType:=PParameter.DataType;
PSearchAgain[AddrCount].DataAddr:=Addr+i-1;
end;
Inc(AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_GETADDR,RM_GETADDR);
end;
end;
4:
begin
if PLongword(@(Buffer))^=PParameter.Data then
begin
PSearchResult.Data:=PParameter.Data;
PSearchResult.DataAddr:=Addr+i-1;
PSearchResult.DataType:=PParameter.DataType;
if AddrCount<=99 then
begin
PSearchAgain[AddrCount].Data:=PParameter.Data;
PSearchAgain[AddrCount].DataType:=PParameter.DataType;
PSearchAgain[AddrCount].DataAddr:=Addr+i-1;
end;
Inc(AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_GETADDR,RM_GETADDR);
end;
end;
end;
Inc(I);
end;
end;
end;
Result:=True;
end;
//------------------------------------------------------------------------------多次查询
function TReadMemoryThread.SecondCheckMemory(Addr:Integer): Boolean;
var
Buffer:TByteArray1;
Lpdw:DWord;
begin
SendMessage(APPHandle,WM_READMEMORY,RM_GETPOS,RM_GETPOS);
if ReadProcessMemory(PParameter.processhandle,
pointer(Addr),
pointer(@(buffer[1])),
PParameter.DataType,Lpdw) then
begin
Case PParameter.DataType of
1:
begin
if PByte(@(Buffer))^=PParameter.Data then
begin
PSearchResult.Data:=PParameter.Data;
PSearchResult.DataAddr:=Addr;
PSearchResult.DataType:=PParameter.DataType;
Inc(AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_GETADDR,RM_GETADDR);
end;
end;
2:
begin
if PWord(@(Buffer))^=PParameter.Data then
begin
PSearchResult.Data:=PParameter.Data;
PSearchResult.DataAddr:=Addr;
PSearchResult.DataType:=PParameter.DataType;
Inc(AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_GETADDR,RM_GETADDR);
end;
end;
4:
begin
if PLongword(@(Buffer))^=PParameter.Data then
begin
PSearchResult.Data:=PParameter.Data;
PSearchResult.DataAddr:=Addr;
PSearchResult.DataType:=PParameter.DataType;
Inc(AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_GETADDR,RM_GETADDR);
end;
end;
end;
end;
Result:=True;
end;
1: ReadProcessMemory
http://www.vckbase.com/vckbase/funct ... sp?id=148 具体用法
参数
hProcess
目标进程的句柄,该句柄必须对目标进程具有PROCESS_VM_READ 的访问权限。
lpBaseAddress
从目标进程中读取数据的起始地址。 在读取数据前,系统将先检验该地址的数据是否可读,如果不可读,函数将调用失败。
lpBuffer
用来接收数据的缓存区地址。
nSize
从目标进程读取数据的字节数。
lpNumberOfBytesRead
实际被读取数据大小的存放地址。如果被指定为NULL,那么将忽略此参数。
返回值
如果函数执行成功,返回值非零。
如果函数执行失败,返回值为零。调用 GetLastError 函数可以获取该函数执行错误的信息。
如果要读取一个进程中不可访问空间的数据,该函数就会失败。
2:
PByte    = ^Byte;
PWord    = ^Word;
PLongword  = ^Longword;
数据类型指针
如果在内存中是:AA BB CC DD
那么读出来实际上:PByte (@(Buffer))^   AA
PWord(@(Buffer))^   BBAA
PLongword (@(Buffer))^ DDCCBBAA
{=============================================}
{=============修改内存=========================}
{=============================================}
procedure TReadMemoryFrm.ChangeMemoryClick(Sender: TObject);
var
LPDW:DWord;
NewData:Integer;
PDataType:Integer;
begin
if Not ElevPrivileges(False) Then
begin
DisMessage(&#39;提高程序权限失败&#39;);
Exit;
end;
if (EdtAddr.Text=&#39;&#39;) or (EdtDataType.Text=&#39;&#39;) or (EdtNewData.Text=&#39;&#39;) then
begin
DisMessage(&#39;请输入数据&#39;);
Exit;
end;
case EdtDataType.ItemIndex of
0:
begin
PDataType:=1;
end;
1:
begin
PDataType:=2;
end;
2:
begin
PDataType:=4;
end;
end;
try
NewData:=StrToInt(EdtNewData.Text);
if WriteProcessMemory(PParameter.ProcessHandle,
pointer(strtoint(&#39;$&#39;+EdtAddr.Text)),
@NewData,
PDataType,
LPDW) then
begin
DisMessage(&#39;修改成功&#39;);
end else
begin
DisMessage(&#39;修改失败&#39;);
end;
except
DisMessage(&#39;修改失败&#39;);
end;
end;
1:WriteProcessMemory
参数含义同ReadProcessMemory,其中hProcess句柄要有对进程的PROCESS_VM_WRITE和PROCESS_VM_OPERATION权限.lpBuffer为要写到指定进程的数据的指针.
2:因为有写内存是只读的你可以修改内存属性来修改内存
function TBaseHOOK.GetMemoryProperty(Addr:Pointer): DWord;
var
lpBuffer: TMemoryBasicInformation;
begin
Result:=0;
if VirtualQueryEx(DestHandle,Addr,lpBuffer,sizeof(lpBuffer))>0 then
begin
if lpBuffer.State=MEM_COMMIT then
begin
Result:=lpBuffer.Protect;
end;
end;
end;
MemoryProperty:=GetMemoryProperty(OldFun); {得到内存属性}
VirtualProtectEx(DestHandle
,OldFun
,8
,PAGE_READWRITE
,@GetCurrentProcessId);         {修改内存属性}
if Not WriteProcessMemory(DestHandle,
OldFun,
@FunJumpCode[FunIndex[FunName]].NewJmpCode,
8,
dwSize)then Exit;
VirtualProtectEx(DestHandle        {恢复内存属性}
,OldFun
,8
,MemoryProperty
,@GetCurrentProcessId);
unit UPubilcDefine;
interface
uses
Windows,Messages,SysUtils,ScktComp,Forms,ADODB,syncobjs;
const
WM_READMEMORY   = WM_USER+100;
RM_GETADDR     = 1;//-----------------------------------------------------得到地址
RM_GETPOS     = 2;//-----------------------------------------------------进度位置
RM_FINISH     = 4;//-----------------------------------------------------完成标志
RM_MAXPROGRESS   = 8;//-----------------------------------------------------最大进度
RM_ADDRCOUNT    = 16;//----------------------------------------------------地址总数
RM_USETIME     = 32;//----------------------------------------------------花费时间
RM_MEMORYSTARTADDR = 64;//----------------------------------------------------开始地址
RM_MEMORYENDADDR  = 128;//---------------------------------------------------结束地址
ReadSize      = 4*1024;//------------------------------------------------读取大小
type
TByteArray = array[1..$FFFF] of Byte;
TByteArray1 = array[1..1] of Byte;
TByteArray2 = array[1..2] of Byte;
TByteArray4 = array[1..4] of Byte;
PByte    = ^Byte;
PWord    = ^Word;
PLongword  = ^Longword;
TParameter = record//---------------------------------------------------------查询参数
Data:DWord;
DataType:Integer;
FirstSearch:Boolean;
ProcessHandle:THandle;
end;
TSearchResult = record//------------------------------------------------------查询结果
Data:Integer;
DataType:Integer;
DataAddr:Integer;
end;
TProcessInfo = record//-------------------------------------------------------进程信息
ProcessExe:String;
ProcessID:Integer;
end;
PProcessInfo=^TProcessInfo;
TMemoryRegion = record
BaseAddress:Dword;
MemorySize:Dword;
end;
var
PParameter:TParameter;
PSearchResult:TSearchResult;
PSearchAgain:Array[0..99] of TSearchResult;
APPHandle:LongWord;//---------------------------------------------------------主程序句柄
implementation
end.

读完这篇文章后,您心情如何?
0
0
0
0
0
0
0
0
本文网址: