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].BaseAddresswhile (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].BaseAddress 0) 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