在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 ,Now begin
{=============================================}
{=============的到进程的ID=====================}
{=============================================}
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;
本文来自Delphi之窗,原文地址:http://www.52delphi.com
这里用到
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[i].MemorySize>$FFFF then
begin
for K:=0 to PMemoryRegion[i].MemorySize div $FFFF do
begin
if K=PMemoryRegion[i].MemorySize div $FFFF+1 then
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion[i].BaseAddress+K*$FFFF;
NewMemoryRegions[j].MemorySize:=PMemoryRegion[i].MemorySize Mod $FFFF;
end else
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion[i].BaseAddress+K*$FFFF;
NewMemoryRegions[j].MemorySize:=$FFFF;
end;
Inc(J);
end;
end else
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion[i].BaseAddress;
NewMemoryRegions[j].MemorySize:=PMemoryRegion[i].MemorySize;
Inc(J);
end;
end;
//---------------------------------------------------数据转换
MemoryRegionsIndex:=j;
for i:=0 to MemoryRegionsIndex-1 do
begin
PMemoryRegion[i].MemorySize:=NewMemoryRegions[i].MemorySize;
PMemoryRegion[i].BaseAddress:=NewMemoryRegions[i].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结构的大小。
本文来自Delphi之窗,原文地址:http://www.52delphi.com
返回值:
函数写入lpBuffer的字节数,如果不等于sizeof(MEMORY_BASIC_INFORMATION)表示失败。
{=============================================}
{=============开始查找=========================}
{=============================================}
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[i].BaseAddress,PMemoryRegion[i].MemorySize);
end;
EndTime:=FloatToStr(CPUTimeCounterQPC);
SendMessage(APPHandle,
WM_READMEMORY,
RM_USETIME,
StrToInt(Copy(EndTime,1,Pos('.',EndTime)-1))-StrToInt(Copy(BeginTime,1,Pos('.',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[i].DataAddr);
end;
EndTime:=FloatToStr(CPUTimeCounterQPC);
SendMessage(APPHandle,
WM_READMEMORY,
RM_USETIME,
StrToInt(Copy(EndTime,1,Pos('.',EndTime)-1))-StrToInt(Copy(BeginTime,1,Pos('.',BeginTime)-1)));
SendMessage(APPHandle,WM_READMEMORY,RM_ADDRCOUNT,AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_FINISH,RM_FINISH);
end;
Suspend;
end;
end;
具体分配如下:
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 ,Now begin
{=============================================}
{=============的到进程的ID=====================}
{=============================================}
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;
本文来自Delphi之窗,原文地址:http://www.52delphi.com
这里用到
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[i].MemorySize>$FFFF then
begin
for K:=0 to PMemoryRegion[i].MemorySize div $FFFF do
begin
if K=PMemoryRegion[i].MemorySize div $FFFF+1 then
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion[i].BaseAddress+K*$FFFF;
NewMemoryRegions[j].MemorySize:=PMemoryRegion[i].MemorySize Mod $FFFF;
end else
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion[i].BaseAddress+K*$FFFF;
NewMemoryRegions[j].MemorySize:=$FFFF;
end;
Inc(J);
end;
end else
begin
NewMemoryRegions[j].BaseAddress:=PMemoryRegion[i].BaseAddress;
NewMemoryRegions[j].MemorySize:=PMemoryRegion[i].MemorySize;
Inc(J);
end;
end;
//---------------------------------------------------数据转换
MemoryRegionsIndex:=j;
for i:=0 to MemoryRegionsIndex-1 do
begin
PMemoryRegion[i].MemorySize:=NewMemoryRegions[i].MemorySize;
PMemoryRegion[i].BaseAddress:=NewMemoryRegions[i].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结构的大小。
本文来自Delphi之窗,原文地址:http://www.52delphi.com
返回值:
函数写入lpBuffer的字节数,如果不等于sizeof(MEMORY_BASIC_INFORMATION)表示失败。
{=============================================}
{=============开始查找=========================}
{=============================================}
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[i].BaseAddress,PMemoryRegion[i].MemorySize);
end;
EndTime:=FloatToStr(CPUTimeCounterQPC);
SendMessage(APPHandle,
WM_READMEMORY,
RM_USETIME,
StrToInt(Copy(EndTime,1,Pos('.',EndTime)-1))-StrToInt(Copy(BeginTime,1,Pos('.',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[i].DataAddr);
end;
EndTime:=FloatToStr(CPUTimeCounterQPC);
SendMessage(APPHandle,
WM_READMEMORY,
RM_USETIME,
StrToInt(Copy(EndTime,1,Pos('.',EndTime)-1))-StrToInt(Copy(BeginTime,1,Pos('.',BeginTime)-1)));
SendMessage(APPHandle,WM_READMEMORY,RM_ADDRCOUNT,AddrCount);
SendMessage(APPHandle,WM_READMEMORY,RM_FINISH,RM_FINISH);
end;
Suspend;
end;
end;