1 Star 0 Fork 0

JonK/cheat-engine

Create your Gitee Account
Explore and code with more than 14 million developers,Free private repositories !:)
Sign up
文件
This repository doesn't specify license. Please pay attention to the specific project description and its upstream code dependency when using it.
Clone or Download
PointerscanresultReader.pas 20.93 KB
Copy Edit Raw Blame History
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
unit PointerscanresultReader;
{$MODE Delphi}
{
The TPointerscanresultReader will read the results from the pointerfile and present them to the pointerscanner as if it is just one file
}
interface
{$ifdef darwin}
uses macport, MacTypes, LCLIntf, sysutils, classes, CEFuncProc, NewKernelHandler,
symbolhandler, math, dialogs, LazUTF8,macportdefines;
{$endif}
{$ifdef windows}
uses windows, LCLIntf, sysutils, classes, CEFuncProc, NewKernelHandler,
symbolhandler, math, dialogs, LazUTF8;
{$endif}
resourcestring
rsPSRCorruptedPointerscanFile = 'Corrupted pointerscan file';
rsPSRInvalidPointerscanFileVersion = 'Invalid pointerscan file version';
rsBuggedList = 'BuggedList';
{$ifdef windows}
function GetFileSizeEx(hFile:HANDLE; FileSize:PQWord):BOOL; stdcall; external 'kernel32.dll' name 'GetFileSizeEx';
{$endif}
type TPointerscanResult=packed record
modulenr: integer;
moduleoffset: int64;
offsetcount: integer;
offsets: array [0..1000] of integer;
end;
type PPointerscanResult= ^TPointerscanResult;
type
TPointerscanresultReader=class;
TPointerscanresultReader=class
private
Fcount: qword;
sizeOfEntry: integer;
maxlevel: integer;
modulelist: tstringlist;
FFileName: widestring;
files: array of record
startindex: qword;
lastindex: qword;
filename: widestring;
filesize: qword;
f,fm: Thandle;
end;
cacheStart: integer;
cacheSize: size_t;
cache: pointer;
cacheStart2: integer;
cacheSize2: integer;
cache2: pointer;
fExternalScanners: integer;
fGeneratedByWorkerID: integer;
fCompressedPtr: boolean;
fAligned: boolean;
MaskModuleIndex: dword;
MaskLevel: dword;
MaskOffset: dword;
fMaxBitCountModuleIndex: dword;
fMaxBitCountModuleOffset: dword;
fMaxBitCountLevel: dword;
fMaxBitCountOffset: dword;
fEndsWithOffsetList: array of dword;
fCanResume: boolean;
fdidBaseRangeScan: boolean;
foriginalBaseScanRange: qword;
CompressedPointerScanResult: PPointerscanResult;
compressedTempBuffer: PByteArray;
fLastRawPointer: pointer;
fmergedresults: array of integer;
function InitializeCache(i: qword): boolean;
function getModuleListCount: integer;
function getMergedResultCount: integer;
function getMergedResult(index: integer): integer;
function getEndsWithOffsetListCount: integer;
function getEndsWithOffsetListEntry(index: integer): dword;
public
procedure resyncModulelist;
procedure saveModulelistToResults(s: Tstream);
function getModulename(modulenr: integer): string;
function getModuleBase(modulenr: integer): ptrUint;
procedure setModuleBase(modulenr: integer; newModuleBase: ptruint);
function getPointer(i: qword): PPointerscanResult; overload;
function getPointer(i: qword; var pointsto: ptrUint): PPointerscanResult; overload;
procedure getFileList(list: TStrings);
procedure ReleaseFiles;
constructor create(filename: widestring; original: TPointerscanresultReader=nil);
destructor destroy; override;
property count: qword read FCount;
property offsetCount: integer read maxlevel;
property filename: widestring read FFilename;
property entrySize: integer read sizeOfEntry;
property modulelistCount: integer read getModuleListcount;
property modulename[index: integer]: string read getModuleName;
property modulebase[index: integer]: ptruint read getModuleBase write setModuleBase;
property mergedresultcount: integer read getMergedResultCount;
property mergedresults[index: integer]: integer read getMergedResult;
property EndsWithOffsetListCount: integer read getEndsWithOffsetListCount;
property EndsWithOffsetList[index: integer]: dword read getEndsWithOffsetListEntry;
property compressedptr: boolean read fCompressedPtr;
property aligned: boolean read fAligned;
property MaxBitCountModuleIndex: dword read fMaxBitCountModuleIndex;
property MaxBitCountModuleOffset: dword read fMaxBitCountModuleOffset;
property MaxBitCountLevel: dword read fMaxBitCountLevel;
property MaxBitCountOffset: dword read fMaxBitCountOffset;
property LastRawPointer: pointer read fLastRawPointer;
property CanResume: boolean read fCanResume;
property DidBaseRangeScan: boolean read fdidBaseRangeScan;
property BaseScanRange: qword read foriginalBaseScanRange;
end;
procedure findAllResultFilesForThisPtr(filename: string; rs: TStrings; lookupmode: integer=0);
implementation
uses ProcessHandlerUnit, PointerscanStructures, Maps, AvgLvlTree;
procedure findAllResultFilesForThisPtr(filename: string; rs: TStrings; lookupmode: integer=0);
var
fr: TRawbyteSearchRec;
i,j: integer;
ext1, ext2: string;
basesort: boolean;
v1, v2: int64;
sepindex: integer;
temp: string;
swap: boolean;
filemap: TMap;
f: string;
fn: pchar;
path: string;
it: TMapIterator;
begin
//search the folder this ptr file is in for .result.* files
//extract1
rs.clear;
filemap:=TMap.Create(its8, sizeof(pointer));
if lookupmode=1 then
filename:=UTF8ToWinCP(filename);
path:=ExtractFilePath(filename);
if FindFirst(filename+'.results.*', 0, fr)=0 then
begin
repeat
ext1:=ExtractFileExt(fr.name);
ext1:=copy(ext1, 2, length(ext1)-1);
if copy(ext1,1,5)='child' then
begin
rs.add(path+fr.name); //no need to sort
end
else if TryStrToInt64('$'+ext1, v1) then
begin
f:=path+fr.name;
getmem(fn, length(f)+1);
strcopy(fn, @f[1]);
filemap.Add(v1, fn);
end;
until FindNext(fr)<>0;
FindClose(fr);
end
else
begin
if lookupmode<1 then
begin
findAllResultFilesForThisPtr(filename, rs, lookupmode+1);
exit;
end;
end;
it:=TMapIterator.Create(filemap);
it.First;
while not it.EOM do
begin
it.GetData(fn);
rs.add(fn);
freememandnil(fn);
it.Next;
end;
it.free;
filemap.Clear;
freeandnil(filemap);
end;
function TPointerscanresultreader.getMergedResultCount: integer;
begin
result:=length(fmergedresults);
end;
function TPointerscanresultreader.getMergedResult(index: integer): integer;
begin
if index<mergedresultcount then
result:=fmergedresults[index]
else
result:=-1;
end;
function TPointerscanresultreader.getEndsWithOffsetListCount: integer;
begin
result:=length(fEndsWithOffsetList);
end;
function TPointerscanresultreader.getEndsWithOffsetListEntry(index: integer): dword;
begin
result:=fEndsWithOffsetList[index]
end;
procedure TPointerscanresultreader.resyncModulelist;
var
tempmodulelist: TStringList;
i,j: integer;
begin
tempmodulelist:=tstringlist.Create;
try
symhandler.getModuleList(tempmodulelist);
//sift through the list filling in the modulelist of the opened pointerfile
for i:=0 to modulelist.Count-1 do
begin
j:=tempmodulelist.IndexOf(modulelist[i]);
if j<>-1 then
modulelist.Objects[i]:=tempmodulelist.Objects[j]
else
begin
try
modulelist.Objects[i]:=pointer(symhandler.getAddressFromName(modulelist[i]));
except
modulelist.Objects[i]:=nil;
end;
end;
end;
finally
tempmodulelist.free;
end;
end;
procedure TPointerscanresultReader.saveModuleListToResults(s: TStream);
var i: integer;
x: dword;
begin
//save the number of modules
x:=modulelist.Count;
s.Write(x,sizeof(x));
for i:=0 to modulelist.Count-1 do
begin
//for each module
//save the length
x:=length(modulelist[i]);
s.Write(x,sizeof(x));
//and the name
s.Write(modulelist[i][1],x);
//and the base (for debugging info)
s.WriteQWord(qword(modulelist.Objects[i]));
end;
end;
function TPointerscanresultReader.InitializeCache(i: qword): boolean;
var j: integer;
actualread: dword;
wantedoffset: qword;
offset: qword;
begin
result:=false;
// OutputDebugString('InitializeCache');
if i>=fcount then exit;
//find which file to use
for j:=0 to length(files)-1 do
begin
if InRangeQ(i, files[j].startindex, files[j].lastindex) then
begin
wantedoffset:=int64(sizeOfEntry*(i-files[j].startindex));
if (wantedoffset mod systeminfo.dwAllocationGranularity)<>0 then
begin
//bring offset down to a location matching systeminfo.dwAllocationGranularity
offset:=wantedoffset-(wantedoffset mod systeminfo.dwAllocationGranularity);
end
else
offset:=wantedoffset;
{$if FPC_FULLVERSION<30200}
cachesize:=min(files[j].filesize-offset, systeminfo.dwAllocationGranularity*32); //normally 2MBZ
{$else}
cachesize:=min(files[j].filesize-offset, qword(systeminfo.dwAllocationGranularity*32)); //normally 2MBZ
{$endif}
if cache2<>nil then
unmapviewoffile(cache2);
cache2:=MapViewOfFile(files[j].fm, FILE_MAP_READ, offset shr 32, offset and $ffffffff, cachesize );
// if cache2=nil then
// OutputDebugString('Failure to map view of file');
//point cache to the start of the wanted offset
cache:=pointer(ptruint(cache2)+(wantedoffset-offset));
cachesize:=(cachesize-(wantedoffset-offset)) div sizeofentry;
result:=cache2<>nil;
// OutputDebugString('InitializeCache success');
exit;
end;
end;
//nothing found...
// OutputDebugString('InitializeCache nothing found');
end;
function TPointerscanresultReader.getModuleListCount: integer;
begin
result:=modulelist.count;
end;
function TPointerscanresultReader.getModuleBase(modulenr: integer): ptrUint;
{pre: modulenr must be valid, so not -1 }
begin
if (modulenr>=0) and (modulenr<modulelist.Count) then
result:=ptrUint(modulelist.Objects[modulenr])
else
result:=0;
end;
procedure TPointerscanresultReader.setModuleBase(modulenr: integer; newModuleBase: ptruint);
begin
if (modulenr>=0) and (modulenr<modulelist.Count) then
modulelist.objects[modulenr]:=pointer(newModulebase);
end;
function TPointerscanresultReader.getModulename(modulenr: integer): string;
begin
if (modulenr>=0) and (modulenr<modulelist.Count) then
result:=modulelist[modulenr]
else
result:=rsBuggedList;
end;
function TPointerscanresultReader.getPointer(i: uint64): PPointerscanResult;
{
for those that know what they want
}
var
cachepos: integer;
p: PByteArray;
bit: integer;
j: integer;
begin
result:=nil;
if i>=count then exit;
//check if i is in the cache
if not InRange(i, cachestart,cachestart+cachesize-1) then
begin
//if not, reload the cache starting from i
if not InitializeCache(i) then exit;
cachestart:=i;
end;
//find out at which position in the cache this index is
cachepos:=i-cachestart;
if fCompressedPtr then
begin
p:=PByteArray(ptrUint(cache)+(cachepos*sizeofentry));
CopyMemory(compressedTempBuffer, p, sizeofentry);
if MaxBitCountModuleOffset=32 then //only 2 possibilities
compressedPointerScanResult.moduleoffset:=PInteger(compressedTempBuffer)^
else
compressedPointerScanResult.moduleoffset:=PInt64(compressedTempBuffer)^;
bit:=MaxBitCountModuleOffset;
compressedPointerScanResult.modulenr:=pdword(@compressedTempBuffer[bit shr 3])^;
compressedPointerScanResult.modulenr:=compressedPointerScanResult.modulenr and MaskModuleIndex;
if compressedPointerScanResult.modulenr shr (fMaxBitCountModuleIndex-1) = 1 then //most significant bit is set, sign extent this value
begin
//should be -1 as that is the only one possible
dword(compressedPointerScanResult.modulenr):=dword(compressedPointerScanResult.modulenr) or (not MaskModuleIndex);
if compressedPointerScanResult.modulenr<>-1 then
begin
//my assumption was wrong
compressedPointerScanResult.modulenr:=-1;
end;
end;
inc(bit, fMaxBitCountModuleIndex);
{
compressedPointerScanResult.offsetcount:=pdword(@compressedTempBuffer[bit div 8])^;
compressedPointerScanResult.offsetcount:=compressedPointerScanResult.offsetcount shr (bit mod 8);
compressedPointerScanResult.offsetcount:=compressedPointerScanResult.offsetcount and MaskLevel;
}
compressedPointerScanResult.offsetcount:=(pdword(@compressedTempBuffer[bit shr 3])^ shr (bit and $7)) and MaskLevel;
inc(compressedPointerScanResult.offsetcount, length(fEndsWithOffsetList));
inc(bit, fMaxBitCountLevel);
for j:=0 to length(fEndsWithOffsetList)-1 do
compressedPointerScanResult.offsets[j]:=fEndsWithOffsetList[j];
for j:=length(fEndsWithOffsetList) to compressedPointerScanResult.offsetcount-1 do
begin
{
compressedPointerScanResult.offsets[j]:=pdword(@compressedTempBuffer[bit div 8])^;
compressedPointerScanResult.offsets[j]:=compressedPointerScanResult.offsets[j] shr (bit mod 8);
compressedPointerScanResult.offsets[j]:=compressedPointerScanResult.offsets[j] and MaskOffset;
if aligned then
compressedPointerScanResult.offsets[j]:=compressedPointerScanResult.offsets[j] shl 2;
}
if aligned then
compressedPointerScanResult.offsets[j]:=((pdword(@compressedTempBuffer[bit shr 3])^ shr (bit and $7) ) and MaskOffset) shl 2
else
compressedPointerScanResult.offsets[j]:=(pdword(@compressedTempBuffer[bit shr 3])^ shr (bit and $7) ) and MaskOffset;
inc(bit, fMaxBitCountOffset);
end;
result:=compressedPointerScanResult;
fLastRawPointer:=compressedTempBuffer;
end
else
begin
result:=PPointerscanResult(ptrUint(cache)+(cachepos*sizeofentry));
fLastRawPointer:=result;
end;
end;
function TPointerscanresultReader.getPointer(i: qword; var pointsto: ptrUint): PPointerscanResult;
{
For use for simple display
}
var
x: ptruint;
address,address2: ptrUint;
j: integer;
begin
result:=getpointer(i);
address:=0;
address2:=0;
//resolve the pointer
pointsto:=0;
if result.modulenr=-1 then
address:=result.moduleoffset
else
begin
if result.modulenr<modulelist.count then
begin
address:=ptruint(modulelist.objects[result.modulenr]);
address:=address+result.moduleoffset;
end
else
begin
//error. Should never happen
address:=$12345678;
end;
end;
for j:=result.offsetcount-1 downto 0 do
begin
if readprocessmemory(processhandle, pointer(address), @address2, processhandler.pointersize, x) then
address:=address2+result.offsets[j]
else
exit; //can't fully resolve
end;
pointsto:=address;
end;
procedure TPointerscanresultReader.getFileList(list: TStrings);
var i: integer;
begin
for i:=0 to length(files)-1 do
list.add(files[i].FileName);
end;
constructor TPointerscanresultReader.create(filename: widestring; original: TPointerscanresultReader=nil);
var
configfile: TFileStream;
modulelistLength: integer;
tempmodulelist: Tstringlist;
x: dword;
i,j: integer;
temppchar: pchar;
temppcharmaxlength: dword;
filenamecount: integer;
error: boolean;
a: ptruint;
fn: widestring;
filenames: array of widestring;
fnames: tstringlist;
pscanversion: byte;
begin
FFilename:=filename;
configfile:=TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite);
if configfile.ReadByte<>$ce then
raise exception.create(rsPSRCorruptedPointerscanFile);
pscanversion:=configfile.ReadByte;
if pscanversion>pointerscanfileversion then
raise exception.create(rsPSRInvalidPointerscanFileVersion);
configfile.ReadBuffer(modulelistlength,sizeof(modulelistlength));
modulelist:=tstringlist.create;
tempmodulelist:=tstringlist.create;
temppcharmaxlength:=256;
getmem(temppchar, temppcharmaxlength);
//get the module list myself
if original=nil then
symhandler.getModuleList(tempmodulelist)
else
modulelist.Assign(original.modulelist);
//sift through the list filling in the modulelist of the opened pointerfile
for i:=0 to modulelistlength-1 do
begin
configfile.Read(x,sizeof(x));
while x>=temppcharmaxlength do
begin
temppcharmaxlength:=temppcharmaxlength*2;
ReallocMem(temppchar, temppcharmaxlength);
end;
configfile.Read(temppchar[0], x);
temppchar[x]:=#0;
a:=configfile.ReadQWord; //discard this info (only used for scandata)
if original=nil then
begin
j:=tempmodulelist.IndexOf(temppchar);
if j<>-1 then
modulelist.Addobject(temppchar, tempmodulelist.Objects[j]) //add it and store the base address
else
begin
a:=symhandler.getAddressFromName(temppchar,false,error,nil);
if not error then
modulelist.Addobject(temppchar, pointer(a))
else
modulelist.Add(temppchar);
end;
end;
end;
//read maxlevel
configfile.Read(maxlevel,sizeof(maxlevel));
//read compressedptr info
fCompressedPtr:=configfile.ReadByte=1;
if fCompressedPtr then
begin
fAligned:=configFile.ReadByte=1;
fMaxBitCountModuleIndex:=configfile.ReadByte;
fMaxBitCountModuleOffset:=configfile.ReadByte;
fMaxBitCountLevel:=configfile.ReadByte;
fMaxBitCountOffset:=configfile.ReadByte;
setlength(fEndsWithOffsetList, configfile.ReadByte);
for i:=0 to length(fEndsWithOffsetList)-1 do
fEndsWithOffsetList[i]:=configfile.ReadDWord;
sizeofentry:=MaxBitCountModuleOffset+MaxBitCountModuleIndex+MaxBitCountLevel+MaxBitCountOffset*(maxlevel-length(fEndsWithOffsetList));
sizeofentry:=(sizeofentry+7) div 8;
MaskModuleIndex:=0;
for i:=1 to MaxBitCountModuleIndex do
MaskModuleIndex:=(MaskModuleIndex shl 1) or 1;
for i:=1 to MaxBitCountLevel do
MaskLevel:=(MaskLevel shl 1) or 1;
for i:=1 to MaxBitCountOffset do
MaskOffset:=(MaskOffset shl 1) or 1;
getmem(CompressedPointerScanResult, 16+4*maxlevel);
getmem(CompressedTempBuffer, sizeofentry+4);
end
else
begin
sizeofentry:=16+(4*maxlevel)
end;
if pscanversion>=2 then
begin
fdidBaseRangeScan:=configFile.readByte=1;
if fdidBaseRangeScan then
foriginalBaseScanRange:=configfile.ReadQWord;
end;
//get the filenames
fnames:=tstringlist.create;
findAllResultFilesForThisPtr(filename, fnames);
setlength(filenames, fnames.count);
for i:=0 to fnames.count-1 do
filenames[i]:=fnames[i];
fnames.free;
setlength(files, length(filenames));
j:=0;
for i:=0 to length(filenames)-1 do
begin
try
if pos(PathDelim, filenames[i])=0 then
fn:=ExtractFilePath(filename)+filenames[i]
else
fn:=filenames[i];
files[j].filename:=fn;
files[j].f:=CreateFileW(pwchar(fn), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (files[j].f<>0) and (files[j].f<>INVALID_HANDLE_VALUE) then
begin
files[j].startindex:=fcount;
if GetFileSizeEx(files[j].f, @files[j].filesize)=false then
begin
OutputDebugString('GetFileSizeEx failed with error: '+inttostr(GetLastError));
end;
if files[j].filesize>0 then
begin
fcount:=fcount+uint64(files[j].filesize div uint64(sizeofentry));
files[j].lastindex:=fcount-1;
files[j].fm:=CreateFileMapping(files[j].f, nil,PAGE_READONLY, 0,0,nil);
end
else
files[j].fm:=0;
if (files[j].fm=0) then
closehandle(files[j].f)
else
inc(j);
end;
except
end;
end;
setlength(files,j);
// getmem(cache, sizeofEntry*maxcachecount);
// getmem(cache2, sizeofEntry*maxcachecount);
InitializeCache(0);
freememandnil(temppchar);
configfile.Free;
fCanResume:=fileexists(filename+'.resume.config') and fileexists(filename+'.resume.scandata') and fileexists(filename+'.resume.queue');
if length(filenames)=0 then
MessageDlg('There was an error loading the results. Check that the path is readable', mtError, [mbok],0);
end;
procedure TPointerscanresultReader.ReleaseFiles;
//if only the config file is needed. This releases the results
var i: integer;
begin
for i:=0 to length(files)-1 do
if files[i].f<>0 then
begin
if files[i].fm<>0 then
closehandle(files[i].fm);
closehandle(files[i].f);
end;
end;
destructor TPointerscanresultReader.destroy;
var i: integer;
begin
if modulelist<>nil then
modulelist.free;
if cache2<>nil then
UnmapViewOfFile(cache2);
ReleaseFiles;
if compressedTempBuffer<>nil then
freememandnil(compressedTempBuffer);
if compressedPointerScanResult<>nil then
freememandnil(compressedPointerScanResult);
end;
end.
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/JonDO/cheat-engine.git
git@gitee.com:JonDO/cheat-engine.git
JonDO
cheat-engine
cheat-engine
master

Search