发新话题
打印

[SDK/API/系统] 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

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[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结构的大小。

返回值:
    函数写入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[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;


//------------------------------------------------------------------------------第一次查询
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[i]))^=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[i]))^=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[i]))^=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/function/viewfunc.asp?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[i]))^      AA
                  PWord(@(Buffer[i]))^      BBAA
                  PLongword (@(Buffer[i]))^  DDCCBBAA

{=============================================}
{=============修改内存=========================}
{=============================================}
procedure TReadMemoryFrm.ChangeMemoryClick(Sender: TObject);
var
  LPDW:DWord;
  NewData:Integer;
  PDataType:Integer;
begin
  if Not ElevPrivileges(False) Then
  begin
    DisMessage('提高程序权限失败');
    Exit;
  end;
  
  if (EdtAddr.Text='')  or (EdtDataType.Text='') or (EdtNewData.Text='') then
  begin
    DisMessage('请输入数据');
    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('$'+EdtAddr.Text)),
                          @NewData,
                          PDataType,
                          LPDW) then
    begin
      DisMessage('修改成功');
    end else
    begin
      DisMessage('修改失败');
    end;
  except
    DisMessage('修改失败');
  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.

完。
妖城欢迎您!

TOP

修改内存有什么用?

TOP

游戏外挂方面,当然还有其他方面
妖城欢迎您!

TOP

发新话题