Scanning process/module's data/heap region

On sábado, 22 de enero de 2011 0 comentarios

cheat engine is open source, so it might be worth looking at the technique he uses to search the memory

im guessing walking the page table is out of the question lol

Edit:
Just had a look at the source for cheatengine and VirtualMemory.pas looked interesting (copy/pasted below)

Code:
unit VirtualMemory;

interface

uses SysUtils,windows,newkernelhandler,cefuncproc,ComCtrls;

type TMemoryRegion2 = record
  Address: dword;
  Size: dword;
  Protect: dword;
end;

type TVirtualMemory = class(tobject)
  private
    buffer: pointer; //base address of all the memory
    buffersize: dword;
    memoryregion: array of TMemoryRegion;
    memoryregion2: array of TMemoryRegion2;
    procedure quicksortmemoryregions(lo,hi: integer);
  public
    function AddressToPointer(address: dword): pointer;
    function PointerToAddress(p: pointer): dword;
    function isvalid(address: dword): boolean;
    function IsBadReadPtr(x: pointer;size: integer):boolean;
    function IsBadWritePtr(x: pointer;size: integer):boolean;
    function GetBuffer: pointer;
    function GetBufferSize: dword;
    constructor Create(Start,Stop: dword; progressbar: tprogressbar); //will load the current process in memory (say goodbye to memory....)
    destructor destroy; override;
end;


implementation



function TVirtualMemory.GetBuffer:pointer;
begin
  result:=buffer;
end;

function TVirtualMemory.GetBufferSize: dword;
begin
  result:=buffersize;
end;

function TVirtualMemory.isvalid(address: dword): boolean;
begin
  result:=AddressToPointer(address)<>nil;
end;

function TVirtualMemory.IsBadReadPtr(x: pointer;size: integer):boolean;
begin
  result:=AddressToPointer(dword(x))=nil;
end;

function TVirtualMemory.IsBadWritePtr(x: pointer;size: integer):boolean;
var i: integer;
    address: dword;
begin
  result:=true;
  address:=dword(x);

  for i:=0 to length(memoryregion2)-1 do
  begin
    if memoryregion2[i].Address>address then exit;
    if (memoryregion2[i].Address+memoryregion2[i].Size)>address then
    begin
      if ((memoryregion2[i].Protect and PAGE_READWRITE)=PAGE_READWRITE) or ((memoryregion2[i].Protect and PAGE_EXECUTE_READWRITE)=PAGE_EXECUTE_READWRITE) then result:=false;
      exit;
    end;
  end;
end;

function TVirtualMemory.PointerToAddress(p: pointer): dword;
{
returns the address the pointer points to
}
var offset: dword;
    i: integer;
begin
  result:=0;
  offset:=dword(p)-dword(buffer); //difference from start of the buffer till p
  for i:=0 to length(memoryregion)-1 do
  begin
    if dword(memoryregion[i].startaddress) > (dword(memoryregion[0].startaddress)+offset) then exit;

    if (
         (dword(p) >= dword(memoryregion[i].startaddress) ) and
         (dword(p) < (dword(memoryregion[i].startaddress)+memoryregion[i].MemorySize)  )
       )
    then
    begin
      result:=memoryregion[i].BaseAddress+(dword(p)-dword(memoryregion[i].startaddress));
      exit;
    end;

  end;
end;

function TVirtualMemory.AddressToPointer(address: dword): pointer;
var i: integer;
begin
try
  result:=nil;

  for i:=0 to length(memoryregion)-1 do
  begin
    if memoryregion[i].BaseAddress>address then exit; //sorted so higher will never be found
    if (memoryregion[i].BaseAddress+memoryregion[i].MemorySize)>address then
    begin
      result:=pointer(dword(memoryregion[i].startaddress)+(address-memoryregion[i].BaseAddress));
      exit;
    end;
  end;

except
  //messagebox(0,pchar(format('address=%.8x i=%d length(memoryregion)=%d',[address,i,length(memoryregion)])),'error',mb_ok);
  //raise exception.create('unnhandled error');
end;

  //still here

end;

procedure TVirtualMemory.quicksortmemoryregions(lo,hi: integer);
var i,j: integer;
    x,h: TMemoryRegion;
begin
  i:=lo;
  j:=hi;

  x:=memoryregion[(lo+hi) div 2];

  repeat
    while (memoryregion[i].BaseAddress
    while (memoryregion[j].BaseAddress>x.BaseAddress) do dec(j);

    if i<=j then
    begin
      h:=memoryregion[i];
      memoryregion[i]:=memoryregion[j];
      memoryregion[j]:=h;
      inc(i);
      dec(j);
    end;

  until i>j;

  if (lo
  if (i
end;

constructor TVirtualMemory.Create(Start,Stop: dword; progressbar: tprogressbar);
var RMPointer: ^Byte;

    mbi : _MEMORY_BASIC_INFORMATION;
    address: Dword;
    size:       dword;

    i: Integer;
    j: Integer;

    actualread: dword;
    TotalToRead: Dword;
    Total: dword;

    NO: boolean;
begin
  address:=start;

  while (Virtualqueryex(processhandle,pointer(address),mbi,sizeof(mbi))<>0) and (addressaddress) do
  begin
    if (not (not scan_mem_private and (mbi.type_9=mem_private))) and (not (not scan_mem_image and (mbi.type_9=mem_image))) and (not (not scan_mem_mapped and (mbi.type_9=mem_mapped))) and (mbi.State=mem_commit) and ((mbi.Protect and page_guard)=0) and ((mbi.protect and page_noaccess)=0) then  //look if it is commited
    begin
      if Skip_PAGE_NOCACHE then
        if (mbi.AllocationProtect and PAGE_NOCACHE)=PAGE_NOCACHE then
        begin
          address:=dword(mbi.BaseAddress)+mbi.RegionSize;
          continue;
        end;

      setlength(memoryregion,length(memoryregion)+1);

      memoryregion[length(memoryregion)-1].BaseAddress:=dword(mbi.baseaddress);  //just remember this location
      memoryregion[length(memoryregion)-1].MemorySize:=mbi.RegionSize;
    end;


    address:=dword(mbi.baseaddress)+mbi.RegionSize;
  end;

  setlength(memoryregion2,length(memoryregion));
  for i:=0 to length(memoryregion2)-1 do
  begin
    memoryregion2[i].Address:=memoryregion[i].BaseAddress;
    memoryregion2[i].Size:=memoryregion[i].MemorySize;


    if Virtualqueryex(processhandle,pointer(memoryregion2[i].Address),mbi,sizeof(mbi))<>0 then
      memoryregion2[i].Protect:=mbi.Protect
    else
      memoryregion2[i].Protect:=page_readonly;
  end;


  if length(memoryregion)=0 then raise exception.create('No memory found in the specified region');

  //lets search really at the start of the location the user specified
  if (memoryregion[0].BaseAddress0) then
  begin
    memoryregion[0].MemorySize:=memoryregion[0].MemorySize-(start-memoryregion[0].BaseAddress);
    memoryregion[0].BaseAddress:=start;
  end;

  //also the right end
  if (memoryregion[length(memoryregion)-1].BaseAddress+memoryregion[length(memoryregion)-1].MemorySize)>stop then
    dec(memoryregion[length(memoryregion)-1].MemorySize,(memoryregion[length(memoryregion)-1].BaseAddress+memoryregion[length(memoryregion)-1].MemorySize)-stop-1);

  //if anything went ok memoryregions should now contain all the addresses and sizes
  //to speed it up combine the regions that are attached to eachother.

  j:=0;
  address:=memoryregion[0].BaseAddress;
  size:=memoryregion[0].MemorySize;

  for i:=1 to length(memoryregion) do
  begin
    if memoryregion[i].BaseAddress=address+size then
      inc(size,memoryregion[i].MemorySize)
    else
    begin
      memoryregion[j].BaseAddress:=address;
      memoryregion[j].MemorySize:=size;

      address:=memoryregion[i].BaseAddress;
      size:=memoryregion[i].MemorySize;
      inc(j);
    end;
  end;

  memoryregion[j].BaseAddress:=address;
  memoryregion[j].MemorySize:=size;
  setlength(memoryregion,j+1);

  //sort memoryregions from small to high
  quicksortmemoryregions(0,length(memoryregion)-1);

  TotalToRead:=0;
  For i:=0 to length(memoryregion)-1 do
    inc(TotalToRead,Memoryregion[i].MemorySize);

  progressbar.Min:=0;
  progressbar.Step:=1;
  progressbar.Position:=0;
  progressbar.max:=length(memoryregion)+1;

  try
    getmem(buffer,TotalToRead);
  except
    raise exception.Create('Not enough memory free to scan');
  end;

  buffersize:=totaltoread;

  RMPointer:=pointer(buffer);

  total:=0;
  for i:=0 to length(memoryregion)-1 do
  begin
    actualread:=0;
    readprocessmemory(processhandle,pointer(Memoryregion[i].BaseAddress),RMPointer,Memoryregion[i].MemorySize,actualread);

    inc(total,actualread);
    Memoryregion[i].MemorySize:=actualread;
    Memoryregion[i].startaddress:=RMPointer;
    inc(RMPointer,actualread);

    progressbar.StepIt;
  end;
end;

destructor TVirtualMemory.destroy;
begin
  if buffer<>nil then freemem(buffer);
  setlength(memoryregion,0);
  setlength(memoryregion2,0);
  inherited destroy;
end;

end.

0 comentarios:

Publicar un comentario