cheat-engine/Cheat Engine/pointeraddresslist.pas

221 lines
5.1 KiB
ObjectPascal

unit pointeraddresslist;
{$mode delphi}
{
the pointeraddresslist will hold a map of all addresses that contain an pointer
and the value they hold.
It's similar to the reversepointerlist, with the exception that I expect this to
eat a TON more RAM since there are more addresses with a pointer then there are
unique pointer values (multiple addresses point to the same address)
Also, this first implementation will make use of the default available maps object
}
interface
uses
Classes, SysUtils, maps, ComCtrls, bigmemallochandler, CEFuncProc;
type
TPointerListHandler=class
private
bma: TBigMemoryAllocHandler;
pmap: TMap;
modulelist: tstringlist;
modulebases: array of ptruint;
is32bit: boolean;
public
procedure reorderModuleIdList(ml: tstrings); //changes the order of modules so they match the provided list (addresses stay unchanged of course)
function getAddressFromModuleIndexPlusOffset(moduleindex: integer; offset: integer): ptruint;
function getPointer(address: ptruint): ptruint; //return 0 if not found
constructor createFromStream(s: TStream; progressbar: tprogressbar=nil);
destructor destroy; override;
end;
implementation
function TPointerListHandler.getAddressFromModuleIndexPlusOffset(moduleindex: integer; offset: integer): ptruint;
begin
if moduleindex>=0 then
result:=modulebases[moduleindex]+offset
else
result:=offset; //if moduleindex=-1 it's an non module base
end;
function TPointerListHandler.getPointer(address: ptruint): ptruint;
var
base: ptruint;
pbase: PByteArray;
begin
base:=address and qword(not qword($ffff));
if pmap.GetData(base, pbase) then
begin
if is32bit then
result:=pdword(@pbase[address-base])^
else
result:=pqword(@pbase[address-base])^
end
else
result:=0;
end;
procedure TPointerListHandler.reorderModuleIdList(ml: tstrings);
//sorts the modulelist based on the given modulelist
var
oldindex: integer;
oldmodulename: string;
oldaddress :ptruint;
i: integer;
begin
for i:=0 to ml.count-1 do
begin
oldindex:=modulelist.IndexOf(ml[i]);
if oldindex=-1 then //it wasn'tin the list, add it with address 0
begin
oldindex:=modulelist.Add(ml[i]);
setlength(modulebases, length(modulebases)+1);
end;
if oldindex<>i then
begin
//swap
oldaddress:=modulebases[i];
oldmodulename:=modulelist[i];
modulebases[i]:=modulebases[oldindex];
modulelist[i]:=modulelist[oldindex];
modulebases[oldindex]:=oldaddress;
modulelist[oldindex]:=oldmodulename;
end;
end;
end;
constructor TPointerListHandler.createFromStream(s: TStream; progressbar: tprogressbar=nil);
var
i,x: integer;
mlistlength: integer;
mname: pchar;
count: qword;
totalcount: qword;
ml: dword;
value: ptruint;
nrofpointers: integer;
lastupdate: qword;
address: qword;
base: qword;
offset: dword;
pbase: pbytearray;
limit: integer;
begin
//create and fill in the pointerlist based on a reversepointerlist
bma:=TBigMemoryAllocHandler.create;
pmap:=TMap.Create(ituPtrSize, sizeof(ptruint));
modulelist:=TStringList.create;
modulelist.CaseSensitive:=false;
mlistlength:=s.ReadDWord;
setlength(modulebases, mlistlength);
for i:=0 to mlistlength-1 do
begin
x:=s.ReadDWord;
getmem(mname, x);
s.ReadBuffer(mname^, x);
mname[x]:=#0;
modulebases[i]:=s.ReadQWord; //seperate array for quicker lookup
modulelist.AddObject(mname, tobject(modulebases[i]));
freemem(mname);
end;
ml:=s.ReadDWord; //maxlevel (for determining if 32 or 64-bit)
if ml=7 then
begin
is32bit:=true;
limit:=65536-sizeof(dword);
end
else
begin
is32bit:=false;
limit:=65536-sizeof(qword);
end;
totalcount:=s.ReadQWord;
count:=0;
if progressbar<>nil then
begin
progressbar.position:=0;
progressbar.Max:=100;
end;
lastupdate:=GetTickCount64;
while count<totalcount do
begin
value:=ptruint(s.ReadQWord);
nrofpointers:=s.ReadDWord;
for i:=0 to nrofpointers-1 do
begin
address:=s.ReadQWord;
base:=address and qword(not qword($ffff));
if not pmap.GetData(base, pbase) then
begin
pbase:=bma.alloc(65536);
pmap.Add(base, pbase);
end;
if (address-base)<limit then
begin
if is32bit then
PDWord(@pbase[address-base])^:=value
else
PQWord(@pbase[address-base])^:=value
end;
//todo: else add some overlap support. But for now, only allow alligned pointers
if s.ReadByte=1 then //has static info
s.ReadQWord; //discard data
end;
inc(count, nrofpointers);
if (progressbar<>nil) and (gettickcount64>lastupdate+1000) then
begin
progressbar.position:=trunc(count/totalcount*100);
lastupdate:=GetTickCount64;
end;
end;
end;
destructor TPointerListHandler.destroy;
begin
if pmap<>nil then
pmap.free;
bma.free;
inherited destroy;
end;
end.