cheat-engine/Cheat Engine/pointerscannerfrm.pas

3437 lines
103 KiB
ObjectPascal

unit pointerscannerfrm;
{$MODE Delphi}
//todo: Make a command prompt version of the distributed scanning pointerscan client, and make it functional in linux as well (real servers)
interface
uses
windows, LCLIntf, LResources, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, syncobjs, syncobjs2,
Menus, math, frmRescanPointerUnit, pointervaluelist, rescanhelper,
virtualmemory, symbolhandler, MainUnit, disassembler, CEFuncProc,
NewKernelHandler, valuefinder, PointerscanresultReader, maps, zstream,
WinSock2, Sockets, registry, PageMap, CELazySocket,
PointerscanNetworkCommands, resolve, pointeraddresslist, pointerscanworker,
PointerscanStructures, PointerscanController, sqlite3conn, sqldb, frmSelectionlistunit, commonTypeDefs;
const staticscanner_done=wm_user+1;
const rescan_done=wm_user+2;
const open_scanner=wm_user+3;
type
Tfrmpointerscanner=class;
{
TPointerscanListener=class(tthread)
private
serverip: string;
serverport:word;
pointerscannerform: Tfrmpointerscanner;
procedure DoPointerscan;
procedure DoRescan;
procedure DoSendResults;
procedure DoCommand(command: byte; srecv: sockaddr_in; recvsize: tsocklen; port:word);
public
executingCommand: boolean;
done: boolean;
procedure execute; override;
constructor create(owner: TfrmPointerscanner; suspended: boolean);
end; }
TRescanWorker=class(TThread) //todo: move to seperate unit
private
procedure flushresults;
function isMatchToValue(p: pointer): boolean;
public
filename: string;
tempfile: tfilestream;
tempbuffer: TMemoryStream;
novaluecheck: boolean;
PointerAddressToFind: ptrUint;
forvalue: boolean;
valuetype: TVariableType;
valuesize: integer;
valuescandword: dword;
valuescansingle: single;
valuescandouble: double;
valuescansinglemax: single;
valuescandoublemax: double;
mustbeinrange: boolean;
baseStart: ptruint;
baseEnd: ptruint;
startOffsetValues: array of dword;
endoffsetvalues: array of dword;
//---
Pointerscanresults: TPointerscanresultReader;
pointermap: TPointerListHandler;
startentry: qword;
EntriesToCheck: qword;
rescanhelper: TRescanhelper;
evaluated: qword;
useluafilter: boolean; //when set to true each pointer will be passed on to the luafilter function
luafilter: string; //function name of the luafilter
done: boolean;
procedure execute; override;
destructor destroy; override;
end;
Trescanpointers=class(tthread) //todo: move to seperate unit
private
rescanworkercount: integer;
rescanworkers: array of TRescanWorker;
rescanhelper: TRescanHelper;
Pointerscanresults: TPointerscanresultReader;
procedure closeOldFile;
public
ownerform: TFrmPointerScanner;
progressbar: tprogressbar;
filename: string;
originalptrfile: string;
pointermapfilename: string;
pointermapprogressbar: tprogressbar;
pointermapprogressbarlabel: tlabel;
pointermap: TPointerListHandler;
overwrite: boolean;
address: ptrUint;
forvalue: boolean;
delay: integer;
valuetype: TVariableType;
valuescandword: dword;
valuescansingle: single;
valuescandouble: double;
valuescansinglemax: single;
valuescandoublemax: double;
mustbeinrange: boolean;
baseStart: ptruint;
baseEnd: ptruint;
startOffsetValues: array of dword;
endoffsetvalues: array of dword;
novaluecheck: boolean; //when set to true the value and final address are not compared, just check that he final address is in fact readable
useluafilter: boolean; //when set to true each pointer will be passed on to the luafilter function
luafilter: string; //function name of the luafilter
waitforall: boolean;
procedure execute; override;
destructor destroy; override;
end;
{ Tfrmpointerscanner }
Tfrmpointerscanner = class(TForm)
btnConnect: TButton;
btnStopRescanLoop: TButton;
btnStopScan: TButton;
btnIncreaseThreadCount: TButton;
btnDecreaseThreadCount: TButton;
cbTrusted: TCheckBox;
cbPriority: TComboBox;
cbTestCrappyConnection: TCheckBox;
edtIP: TEdit;
edtPassword: TEdit;
edtPort: TEdit;
gbNetwork: TGroupBox;
lblIP: TLabel;
lblPort: TLabel;
lblPassword: TLabel;
lblThreadPriority: TLabel;
lblProgressbar1: TLabel;
miExportTosqlite: TMenuItem;
MenuItem2: TMenuItem;
miImportFromsqlite: TMenuItem;
miCreatePSNnode: TMenuItem;
miResume: TMenuItem;
odMerge: TOpenDialog;
odSqlite: TOpenDialog;
pnlData: TPanel;
pnlStop: TPanel;
pnlControl: TPanel;
pnlProgressName: TPanel;
pnlProgressBar: TPanel;
pnlProgress: TPanel;
Panel1: TPanel;
MainMenu1: TMainMenu;
File1: TMenuItem;
New1: TMenuItem;
N2: TMenuItem;
Open1: TMenuItem;
Pointerscanner1: TMenuItem;
Method3Fastspeedandaveragememoryusage1: TMenuItem; //I should probably rename this, it's not really, 'average memory usage' anymore...
N1: TMenuItem;
ProgressBar1: TProgressBar;
Rescanmemory1: TMenuItem;
SaveDialog1: TSaveDialog;
OpenDialog1: TOpenDialog;
SaveDialog2: TSaveDialog;
sdSqlite: TSaveDialog;
SQLite3: TSQLite3Connection;
SQLQuery: TSQLQuery;
SQLTransaction: TSQLTransaction;
Timer2: TTimer;
lvResults: TListView;
PopupMenu1: TPopupMenu;
Resyncmodulelist1: TMenuItem;
cbType: TComboBox;
tvInfo: TTreeView;
procedure btnStopRescanLoopClick(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure btnIncreaseThreadCountClick(Sender: TObject);
procedure btnDecreaseThreadCountClick(Sender: TObject);
procedure cbPriorityChange(Sender: TObject);
procedure cbTestCrappyConnectionChange(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure lvResultsColumnClick(Sender: TObject; Column: TListColumn);
procedure lvResultsResize(Sender: TObject);
procedure miExportTosqliteClick(Sender: TObject);
procedure miImportFromsqliteClick(Sender: TObject);
procedure miCreatePSNnodeClick(Sender: TObject);
procedure miMergePointerscanResultsClick(Sender: TObject);
procedure miResumeClick(Sender: TObject);
procedure miSetWorkFolderClick(Sender: TObject);
procedure miJoinDistributedRescanClick(Sender: TObject);
procedure miJoinDistributedScanClick(Sender: TObject);
procedure Method3Fastspeedandaveragememoryusage1Click(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
procedure Open1Click(Sender: TObject);
procedure Rescanmemory1Click(Sender: TObject);
procedure btnStopScanClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure New1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure lvResultsData(Sender: TObject; Item: TListItem);
procedure Resyncmodulelist1Click(Sender: TObject);
procedure lvResultsDblClick(Sender: TObject);
procedure cbTypeChange(Sender: TObject);
private
{ Private declarations }
start:tdatetime;
rescan: trescanpointers;
rescanpointerform: TFrmRescanPointer;
{
distributedworkfolder: string;
PointerscanListener: TPointerscanListener; }
infonodes: record
statistics: record
node: TTreenode; //+ statistics
stats: record
totalTimeScanning: TTreenode;
localPathsEvaluated: TTreenode;
localPathsPerSecond: TTreenode;
totalPathsEvaluated: TTreenode;
totalPathsPerSecond: TTreenode;
pointersInMap: TTreenode;
pathQueue: TTreenode;
resultsFound: TTreenode;
timeSpentWriting: TTreenode;
minpath: TTreenode;
maxpath: TTreenode;
end;
end;
localworkers: record
node: TTreenode; // + localworkers
workernodes: array of record
node: TTreenode; //threadnr (status)
end;
end;
network: record
node: TTreenode; // + network
parent: TTreenode; //ip+port or disconnected
parentnodes: record
lastUpdateSent: TTreenode;
end;
connectingto: TTreenode;
connectingToNodes: array of record
data: TTreenode; //ip, port, trusted
end;
connectedTo: TTreenode;
connectedToNodes: array of record
node: TTreenode; //ip:port (status)
data: record
disconnectreason: TTreenode;
trusted: TTreenode; //trusted: true/false
totalthreadcount: TTreenode; //Total threadcount: %d
resultsfound: TTreenode; //Total results found: %d
pathqueuesize: TTreenode; //Queuesize: %d
totalpathquesize: TTreenode; //Total queuesize: %d
totalpathsEvaluated: TTreenode; //Total paths evaluated: %d
pathspersecond: TTreenode; //Paths per second: %d
end;
end;
end;
end;
procedure m_staticscanner_done(var message: tmessage); message staticscanner_done;
procedure rescandone(var message: tmessage); message rescan_done;
procedure openscanner(var message: tmessage); message open_scanner;
procedure PointerscanStart(sender: TObject);
procedure doneui;
procedure resyncloadedmodulelist;
procedure OpenPointerfile(filename: string);
procedure stopscan(savestate: boolean);
procedure PointerscanDone(sender: TObject; hasError: boolean; errorstring: string); //called by the pointerscan controller thread when done
public
{ Public declarations }
Staticscanner: TPointerscanController;
Pointerscanresults: TPointerscanresultReader;
SkipNextScanSettings: boolean; //set to true if you wish to start the scan with the predefined settings in the pointerscan settings form
{
procedure JoinPointerscan(host: string='127.0.0.1'; port: word=52737; threadcount: integer=1; scannerpriority:TThreadPriority=tpHigher; UseLoadedPointermap: boolean=false; LoadedPointermapFilename: string='');
procedure JoinRescan(server: string; port: dword); }
end;
//var
// frmPointerScanner: TfrmPointerScanner;
implementation
uses PointerscannerSettingsFrm, frmMemoryAllocHandlerUnit, frmSortPointerlistUnit,
LuaHandler, lauxlib, lua, frmPointerscanConnectDialogUnit,
frmpointerrescanconnectdialogunit, frmMergePointerscanResultSettingsUnit,
ProcessHandlerUnit, frmResumePointerscanUnit, PointerscanConnector,
frmSetupPSNNodeUnit, PointerscanNetworkStructures;
resourcestring
rsErrorDuringScan = 'Error during scan';
rsGeneratingPointermap = 'Generating pointermap...';
rsIsNotAValid4ByteValue = '%s is not a valid 4 byte value';
rsIsNotAValidFloatingPointValue = '%s is not a valid floating point value';
rsIsNotAValidDoubleValue = '%s is not a valid double value';
rsAddressSpecifiersFoundInTheWholeProcess = 'Address specifiers found in '
+'the whole process';
rsPointerPathsFound = 'Pointer paths found';
rsThreads = 'Threads';
rsEvaluated = 'Evaluated';
rsTime = 'Time';
rsThread = 'Thread';
rsCurrentLevel = 'Current Level';
rsLookingFor = 'Looking for';
rsSleeping = 'Sleeping';
rsActive = 'Active';
rsWritingToDisk = 'Writing to disk';
rsBaseAddress = 'Base Address';
rsOffset = 'Offset';
rsPointsTo = 'Points to';
rsPointercount = 'pointercount';
rsOnlyTheFirst1000000EntriesWillBeDisplayed = 'Only the first 1000000 '
+'entries will be displayed. Rescan will still work with all results. ('
+'This is normal for a pointerscan, you MUST do a few rescans)';
rsPointerScan = 'Pointer scan';
rsPointerscanResult = 'pointerscan result';
rsTerminating = 'Terminating';
rsSavingAndTerminating = 'Saving...';
rsStop = 'Stop';
rsOUTOFDISKSPACECleanUpTheDiskOrStop = 'OUT OF DISKSPACE! Clean up the disk '
+'or stop';
//----------------------- scanner info --------------------------
//----------------------- staticscanner -------------------------
{$ifdef benchmarkps}
//totalpathsevaluated: qword;
{
var
starttime: dword;
startcount: qword; }
{$endif}
procedure TFrmpointerscanner.doneui;
begin
progressbar1.position:=0;
pnlprogress.visible:=false;
pnlData.Visible:=false;
open1.Enabled:=true;
new1.enabled:=true;
rescanmemory1.Enabled:=true;
if (staticscanner<>nil) and (staticscanner.generatePointermapOnly) then
new1.Click;
if (staticscanner<>nil) and (staticscanner.filename<>'') then
OpenPointerfile(staticscanner.filename);
if rescan<>nil then
begin
OpenPointerfile(rescan.filename);
freeandnil(rescan);
end;
{
if (PointerscanListener<>nil) then
PointerscanListener.executingCommand:=false; //start listening for new commands }
end;
procedure Tfrmpointerscanner.PointerscanDone(sender: TObject; hasError: boolean; errorstring: string);
begin
postmessage(Handle,staticscanner_done,0,0);
end;
procedure Tfrmpointerscanner.m_staticscanner_done(var message: tmessage);
begin
if staticscanner=nil then exit;
if staticscanner.useHeapData then
frmMemoryAllocHandler.memrecCS.leave; //continue adding new entries
//update the treeview
if staticscanner.haserror then
messagedlg(rsErrorDuringScan+': '+staticscanner.errorString, mtError, [mbok] , 0);
doneui;
end;
{
procedure TPointerscanListener.DoPointerscan;
var cpucount: integer;
begin
//join a pointerscan
cpucount:=GetCPUCount;
if HasHyperthreading then
cpucount:=(cpucount div 2)+1;
pointerscannerform.JoinPointerscan(serverip, serverport, cpucount);
end;
procedure TPointerscanListener.DoRescan;
begin
pointerscannerform.JoinRescan(serverip, serverport);
end;
procedure TPointerscanListener.DoSendResults;
begin
end;
procedure TPointerscanListener.DoCommand(command: byte; srecv: sockaddr_in; recvsize: tsocklen; port:word);
begin
if executingCommand then exit; //already doing something
executingCommand:=true;
serverip:=NetAddrToStr(srecv.sin_addr);
serverport:=port;
case command of
0: synchronize(DoPointerscan);
1: synchronize(DoRescan);
2: synchronize(DoSendResults);
end;
end;
procedure TPointerscanListener.execute;
var
s: TSocket;
srecv: sockaddr_in;
recvsize: tsocklen;
cecommand: packed record
id: byte; // 0xce
operation: byte;
port: word;
test: word;
end;
i: integer;
begin
i:=0;
s:=fpsocket(PF_INET, SOCK_DGRAM, 0);
if s>=0 then
begin
srecv.sin_family:=PF_INET;
srecv.sin_addr.s_addr:=htonl(INADDR_ANY);
srecv.sin_port:=htons(3297);
i:=fpbind(s, @srecv, sizeof(srecv));
while (i>=0) and (not terminated) do
begin
ZeroMemory(@srecv, sizeof(srecv));
recvsize:=sizeof(srecv);
i:=fprecvfrom(s, @cecommand, sizeof(cecommand), 0, @srecv, @recvsize);
if (i=sizeof(cecommand)) and (cecommand.id=$ce) and (cecommand.test=word((cecommand.id+cecommand.operation+cecommand.port)*599)) then
DoCommand(cecommand.operation, srecv, recvsize, cecommand.port);
end;
end;
CloseSocket(s);
done:=true; //todo: Perhaps relaunch ?
end;
constructor TPointerscanListener.create(owner: Tfrmpointerscanner; suspended: boolean);
begin
self.pointerscannerform:=owner;
inherited create(suspended);
end;
}
//---------------------------------main--------------------------
{
procedure Tfrmpointerscanner.JoinRescan(server: string; port: dword);
begin
if rescan<>nil then
freeandnil(rescan);
rescan:=trescanpointers.create(true);
rescan.ownerform:=self;
rescan.progressbar:=progressbar1;
rescan.distributedrescan:=true;
rescan.distributedrescanWorker:=true;
rescan.distributedserver:=server;
rescan.distributedport:=port;
rescan.distributedworkfolder:=distributedworkfolder;
pnlprogress.visible:=true;
rescan.start;
end;
}
{
procedure Tfrmpointerscanner.JoinPointerscan(host: string='127.0.0.1'; port: word=52737; threadcount: integer=1; scannerpriority:TThreadPriority=tpHigher; UseLoadedPointermap: boolean=false; LoadedPointermapFilename: string='');
begin
new1.click; //setup the gui
totalpathsevaluated:=0;
startcount:=0;
starttime:=0;
btnStopScan.enabled:=true;
btnStopScan.Caption:=rsStop;
pgcPScandata.Visible:=false;
open1.Enabled:=false;
new1.enabled:=false;
rescanmemory1.Enabled:=false;
cbType.Visible:=false;
lvResults.Visible:=false;
//launch the scanner
staticscanner:=TPointerscanController.Create(true);
label5.caption:=rsGeneratingPointermap;
pnlProgress.Visible:=true;
staticscanner.distributedScanning:=true;
staticscanner.distributedWorker:=true;
staticscanner.distributedServer:=host;
staticscanner.distributedport:=port;
staticscanner.progressbar:=progressbar1;
staticscanner.threadcount:=threadcount;
staticscanner.scannerpriority:=scannerpriority;
staticscanner.UseLoadedPointermap:=UseLoadedPointermap;
staticscanner.LoadedPointermapFilename:=LoadedPointermapFilename;
staticscanner.filename:=IncludeTrailingPathDelimiter(distributedworkfolder);
staticscanner.pointerlisthandler:=pointerlisthandler;
open1.Enabled:=false;
staticscanner.start;
pgcPScandata.Visible:=true;
end; }
procedure Tfrmpointerscanner.miJoinDistributedScanClick(Sender: TObject);
{var
f: tfrmPointerscanConnectDialog;}
begin
{
f:=tfrmPointerscanConnectDialog.create(self);
if f.showmodal=mrok then
begin
if distributedworkfolder='' then
miSetWorkFolder.Click;
if distributedworkfolder='' then exit;
JoinPointerscan(f.edthost.text, f.port, f.threadcount, f.scannerpriority, f.cbUseLoadedPointermap.checked, f.odLoadPointermap.FileName);
end;
f.free; }
end;
procedure Tfrmpointerscanner.miResumeClick(Sender: TObject);
var
f: tfrmresumePointerScan;
filename: string;
{
maxlevel: dword
structsize: dword; //sz
totalpathsevaluated: dword
compressedptr: byte; //boolean
unalligned: byte; //boolen
noloop: byte; //boolean
muststartwithbase; byte //boolean
LimitToMaxOffsetsPerNode: byte //boolean
onlyOneStaticInPath: byte; //boolean
instantrescan: byte //boolean (not really needed, but it's a nice padding)
mustEndWithSpecificOffset: byte; //boolean ( ^ ^ )
maxoffsetspernode: integer;
basestart: qword;
basestop: qword;
mustendwithoffsetlistlength: integer
mustendwithoffsetlist[]: dword*mustendwithoffsetlistlength
instantrescancount: integer;
instantrescanentry []: record[] [
filenamelength: integer
filename: char[filenamelength] //full path
address: qword
]
}
var
threadcount: integer;
config: Tfilestream;
maxlevel: integer;
structsize: integer;
compressedptr: boolean;
unalligned: boolean;
noloop: boolean;
muststartwithbase: boolean;
LimitToMaxOffsetsPerNode:boolean;
onlyOneStaticInPath:boolean;
instantrescan:boolean; //(not really needed, but it's a nice padding)
mustEndWithSpecificOffset:boolean;// ( ^ ^ )
maxoffsetspernode: integer;
basestart: qword;
basestop: qword;
mustendwithoffsetlist: array of dword;
instantrescanentries: array of record
filename: string;
address: qword;
end;
i: integer;
pb: TProgressbar;
lb: TLabel;
begin
//show a dialog where the user can pick the number of threads to scan
if (pointerscanresults<>nil) and Pointerscanresults.CanResume then
begin
filename:=Pointerscanresults.filename;
try
config:=TFileStream.Create(filename+'.resume.config', fmOpenRead or fmShareDenyNone);
except
exit;
end;
maxlevel:=config.ReadDWord;
structsize:=config.ReadDWord;
// totalpathsevaluated:=config.ReadQWord; //IGNORED
compressedptr:=config.ReadByte=1;
unalligned:=config.ReadByte=1;
noloop:=config.ReadByte=1;
muststartwithbase:=config.ReadByte=1;
LimitToMaxOffsetsPerNode:=config.ReadByte=1;
onlyOneStaticInPath:=config.ReadByte=1;
instantrescan:=config.ReadByte=1;
mustEndWithSpecificOffset:=config.ReadByte=1;
maxoffsetspernode:=config.ReadDWord;
basestart:=config.ReadQWord;
basestop:=config.ReadQWord;
setlength(mustendwithoffsetlist, config.ReadDWord);
config.ReadBuffer(mustendwithoffsetlist[0], sizeof(dword)*length(mustendwithoffsetlist));
setlength(instantrescanentries, config.readdword);
for i:=0 to length(instantrescanentries)-1 do
begin
instantrescanentries[i].filename:=config.ReadAnsiString;
instantrescanentries[i].address:=config.ReadQWord;
end;
config.free;
f:=tfrmresumePointerScan.create(self);
if f.instantrescanfiles<>nil then
for i:=0 to length(instantrescanentries)-1 do
f.instantrescanfiles.AddObject(instantrescanentries[i].filename, tobject(instantrescanentries[i].address));
if f.showmodal=mrOK then
begin
threadcount:=f.threadcount;
for i:=0 to f.instantrescanfiles.Count-1 do
instantrescanentries[i].filename:=f.instantrescanfiles[i];
new1.click;
//default scan
staticscanner:=TPointerscanController.Create(true);
btnStopScan.enabled:=true;
btnStopScan.Caption:=rsStop;
pnlData.Visible:=false;
open1.Enabled:=false;
new1.enabled:=false;
rescanmemory1.Enabled:=false;
cbType.Visible:=false;
lvResults.Visible:=false;
pnlProgress.Visible:=true;
try
staticscanner.OnStartScan:=PointerscanStart;
staticscanner.OnScanDone:=PointerscanDone;
staticscanner.threadcount:=threadcount;
staticscanner.resumescan:=true;
staticscanner.maxlevel:=maxlevel;
staticscanner.sz:=structsize;
staticscanner.compressedptr:=compressedptr;
staticscanner.unalligned:=unalligned;
staticscanner.noLoop:=noloop;
staticscanner.mustStartWithBase:=muststartwithbase;
staticscanner.LimitToMaxOffsetsPerNode:=LimitToMaxOffsetsPerNode;
staticscanner.onlyOneStaticInPath:=onlyOneStaticInPath;
staticscanner.instantrescan:=true;
staticscanner.mustEndWithSpecificOffset:=true;
staticscanner.MaxOffsetsPerNode:=maxoffsetspernode;
staticscanner.BaseStart:=basestart;
staticscanner.BaseStart:=basestop;
setlength(staticscanner.mustendwithoffsetlist, length(mustendwithoffsetlist));
for i:=0 to length(mustendwithoffsetlist)-1 do
staticscanner.mustendwithoffsetlist[i]:=mustendwithoffsetlist[i];
setlength(staticscanner.instantrescanfiles, length(instantrescanentries));
for i:=0 to length(staticscanner.instantrescanfiles)-1 do
begin
staticscanner.instantrescanfiles[i].address:=instantrescanentries[i].address;
staticscanner.instantrescanfiles[i].filename:=instantrescanentries[i].filename;
staticscanner.instantrescanfiles[i].plist:=nil;
//create a new progressbar to show how long it'll take
pb:=TProgressBar.Create(self);
pb.parent:=pnlProgressBar;
pb.position:=0;
pb.Max:=100;
if i=0 then
pb.top:=ProgressBar1.Top+progressbar1.height
else
pb.Top:=staticscanner.instantrescanfiles[i-1].progressbar.Top+staticscanner.instantrescanfiles[i-1].progressbar.Height;
pb.left:=ProgressBar1.left;
pb.width:=ProgressBar1.width;
pb.Anchors:=ProgressBar1.Anchors;
lb:=TLabel.create(self);
lb.caption:=extractfilename(instantrescanentries[i].filename);
lb.Parent:=pnlProgressName;
lb.top:=pb.Top+(pb.Height div 2)-(lb.height div 2);
lb.hint:=ansitoutf8(instantrescanentries[i].filename);
lb.showhint:=true;
staticscanner.instantrescanfiles[i].progressbar:=pb;
staticscanner.instantrescanfiles[i].progresslabel:=lb;
pnlProgress.ClientHeight:=pb.Top+pb.height+1;
end;
staticscanner.UseLoadedPointermap:=true;
staticscanner.LoadedPointermapFilename:=filename+'.resume.scandata';
staticscanner.progressbar:=ProgressBar1;
staticscanner.filename:=filename;
staticscanner.Start;
pnlData.Visible:=true;
Method3Fastspeedandaveragememoryusage1.Enabled:=false;
except
on e: exception do
begin
staticscanner.Free;
staticscanner:=nil;
MessageDlg(e.message, mtError, [mbok], 0);
end;
end;
end;
end
else
miResume.Visible:=false;
end;
procedure Tfrmpointerscanner.Method3Fastspeedandaveragememoryusage1Click(
Sender: TObject);
var
i: integer;
floataccuracy: integer;
floatsettings: TFormatSettings;
filename: string;
pb: TProgressBar;
lb: TLabel;
pfn: string;
al: TStringlist;
SkipNextScanSettingsWasTrue: boolean;
begin
SkipNextScanSettingsWasTrue:=SkipNextScanSettings;
SkipNextScanSettings:=false;
FloatSettings:=DefaultFormatSettings;
start:=now;
if frmpointerscannersettings=nil then
frmpointerscannersettings:=tfrmpointerscannersettings.create(application);
if frmpointerscannersettings.Visible then exit; //already open, so no need to make again
if SkipNextScanSettingsWasTrue or (frmpointerscannersettings.Showmodal=mrok) then
begin
new1.click;
if frmpointerscannersettings.rbGeneratePointermap.checked then //show a .scandata dialog instad of a .ptr
begin
if not savedialog2.execute then exit;
filename:=savedialog2.filename;
end
else
begin
if not savedialog1.Execute then exit;
filename:=savedialog1.filename;
end;
btnStopScan.enabled:=true;
btnStopScan.Caption:=rsStop;
pnlData.Visible:=false;
open1.Enabled:=false;
new1.enabled:=false;
rescanmemory1.Enabled:=false;
cbType.Visible:=false;
lvResults.Visible:=false;
//initialize array's
//default scan
staticscanner:=TPointerscanController.Create(true);
pnlProgress.Visible:=true;
try
staticscanner.OnStartScan:=PointerscanStart;
staticscanner.OnScanDone:=PointerscanDone;
staticscanner.allowIncomingChildren:=frmpointerscannersettings.cbAllowRuntimeWorkers.Checked;
staticscanner.listenport:=frmpointerscannersettings.distributedport;
staticscanner.childpassword:=frmpointerscannersettings.edtDistributedPassword.text;
staticscanner.initializer:=true;
staticscanner.filename:=utf8toansi(fileName);
staticscanner.generatePointermapOnly:=frmpointerscannersettings.rbGeneratePointermap.checked;
if staticscanner.generatePointermapOnly then
begin
al:=tstringlist.create;
MainForm.addresslist.getAddressList(al);
al.SaveToFile(filename+'.addresslist');
al.free;
end;
staticscanner.compressedptr:=frmpointerscannersettings.cbCompressedPointerscanFile.checked;
staticscanner.noReadOnly:=frmpointerscannersettings.cbNoReadOnly.checked;
staticscanner.mustBeClassPointers:=frmpointerscannersettings.cbClassPointersOnly.checked;
staticscanner.acceptNonModuleClasses:=frmpointerscannersettings.cbAcceptNonModuleVtable.checked;
staticscanner.useStacks:=frmpointerscannersettings.cbStaticStacks.checked;
staticscanner.stacksAsStaticOnly:=frmPointerscannersettings.cbStackOnly.checked;
staticscanner.threadstacks:=frmPointerscannersettings.threadstacks;
staticscanner.stacksize:=frmPointerscannersettings.stacksize;
staticscanner.UseLoadedPointermap:=frmpointerscannersettings.cbUseLoadedPointermap.Checked;
staticscanner.LoadedPointermapFilename:=frmpointerscannersettings.odLoadPointermap.FileName;
if staticscanner.UseLoadedPointermap then
lblProgressbar1.caption:=extractfilename(staticscanner.LoadedPointermapFilename)
else
lblProgressbar1.caption:='Generating pointermap';
staticscanner.startaddress:=frmpointerscannersettings.start;
staticscanner.stopaddress:=frmpointerscannersettings.Stop;
staticscanner.unalligned:=not frmpointerscannersettings.CbAlligned.checked;
staticscanner.staticonly:=frmpointerscannersettings.cbStaticOnly.checked;
staticscanner.noLoop:=frmpointerscannersettings.cbNoLoop.checked;
staticscanner.LimitToMaxOffsetsPerNode:=frmpointerscannersettings.cbMaxOffsetsPerNode.Checked;
staticscanner.maxOffsetsPerNode:=frmpointerscannersettings.maxOffsetsPerNode;
staticscanner.automatic:=true;
staticscanner.automaticaddress:=frmpointerscannersettings.automaticaddress;
staticscanner.sz:=frmpointerscannersettings.structsize;
staticscanner.maxlevel:=frmpointerscannersettings.maxlevel-1;
staticscanner.progressbar:=progressbar1;
staticscanner.threadcount:=frmpointerscannersettings.threadcount;
staticscanner.scannerpriority:=frmpointerscannersettings.scannerpriority;
{
staticscanner.distributedScanning:=frmpointerscannersettings.cbDistributedScanning.checked;
staticscanner.distributedport:=frmpointerscannersettings.distributedPort;
staticscanner.broadcastThisScanner:=frmpointerscannersettings.cbBroadcast.checked;
staticscanner.potentialWorkerList:=frmpointerscannersettings.resolvediplist; }
staticscanner.mustStartWithBase:=frmpointerscannersettings.cbMustStartWithBase.checked;
staticscanner.BaseStart:=frmpointerscannersettings.baseStart;
staticscanner.BaseStop:=frmpointerscannersettings.baseStop;
staticscanner.mustEndWithSpecificOffset:=frmpointerscannersettings.cbMustEndWithSpecificOffset.checked;
if staticscanner.mustEndWithSpecificOffset then
begin
setlength(staticscanner.mustendwithoffsetlist, frmpointerscannersettings.offsetlist.count);
for i:=0 to frmpointerscannersettings.offsetlist.count-1 do
staticscanner.mustendwithoffsetlist[i]:=TOffsetEntry(frmpointerscannersettings.offsetlist[i]).offset;
end;
staticscanner.instantrescan:=frmpointerscannersettings.cbCompareToOtherPointermaps.checked;
setlength(staticscanner.instantrescanfiles,0);
if staticscanner.instantrescan then
begin
for i:=0 to frmpointerscannersettings.pdatafilelist.count-1 do
begin
pfn:=Utf8ToAnsi(frmpointerscannersettings.pdatafilelist.filenames[i]);
if pfn<>'' then
begin
setlength(staticscanner.instantrescanfiles,length(staticscanner.instantrescanfiles)+1);
staticscanner.instantrescanfiles[length(staticscanner.instantrescanfiles)-1].filename:=pfn;
staticscanner.instantrescanfiles[length(staticscanner.instantrescanfiles)-1].address:=frmpointerscannersettings.pdatafilelist.addresses[i];
staticscanner.instantrescanfiles[length(staticscanner.instantrescanfiles)-1].plist:=nil;
//create a new progressbar to show how long it'll take
pb:=TProgressBar.Create(self);
pb.parent:=pnlProgressBar;
pb.position:=0;
pb.Max:=100;
if i=0 then
pb.top:=ProgressBar1.Top+progressbar1.height
else
pb.Top:=staticscanner.instantrescanfiles[length(staticscanner.instantrescanfiles)-2].progressbar.Top+staticscanner.instantrescanfiles[length(staticscanner.instantrescanfiles)-2].progressbar.Height;
pb.left:=ProgressBar1.left;
pb.width:=ProgressBar1.width;
pb.Anchors:=ProgressBar1.Anchors;
lb:=TLabel.create(self);
lb.caption:=extractfilename(pfn);
lb.Parent:=pnlProgressName;
lb.top:=pb.Top+(pb.Height div 2)-(lb.height div 2);
lb.hint:=pfn;
lb.showhint:=true;
staticscanner.instantrescanfiles[length(staticscanner.instantrescanfiles)-1].progressbar:=pb;
staticscanner.instantrescanfiles[length(staticscanner.instantrescanfiles)-1].progresslabel:=lb;
pnlProgress.ClientHeight:=pb.Top+pb.height+1;
end;
end;
if length(staticscanner.instantrescanfiles)=0 then
staticscanner.instantrescan:=false; //no rescan at all
end
else
pnlProgress.ClientHeight:=ProgressBar1.Top+progressbar1.height+1;
staticscanner.onlyOneStaticInPath:=frmpointerscannersettings.cbOnlyOneStatic.checked;
staticscanner.useHeapData:=frmpointerscannersettings.cbUseHeapData.Checked;
staticscanner.useOnlyHeapData:=frmpointerscannersettings.cbHeapOnly.checked;
if staticscanner.useHeapData then
frmMemoryAllocHandler.memrecCS.enter; //stop adding entries to the list
//check if the user choose to scan for addresses or for values
staticscanner.findValueInsteadOfAddress:=frmpointerscannersettings.rbFindValue.checked;
if staticscanner.findValueInsteadOfAddress then
begin
//if values, check what type of value
floataccuracy:=pos(FloatSettings.DecimalSeparator,frmpointerscannersettings.cbAddress.Text);
if floataccuracy>0 then
floataccuracy:=length(frmpointerscannersettings.cbAddress.Text)-floataccuracy;
case frmpointerscannersettings.cbValueType.ItemIndex of
0:
begin
staticscanner.valuetype:=vtDword;
val(frmpointerscannersettings.cbAddress.Text, staticscanner.valuescandword, i);
if i>0 then raise exception.Create(Format(rsIsNotAValid4ByteValue, [frmpointerscannersettings.cbAddress.Text]));
end;
1:
begin
staticscanner.valuetype:=vtSingle;
val(frmpointerscannersettings.cbAddress.Text, staticscanner.valuescansingle, i);
if i>0 then raise exception.Create(Format(rsIsNotAValidFloatingPointValue, [frmpointerscannersettings.cbAddress.Text]));
staticscanner.valuescansingleMax:=staticscanner.valuescansingle+(1/(power(10,floataccuracy)));
end;
2:
begin
staticscanner.valuetype:=vtDouble;
val(frmpointerscannersettings.cbAddress.Text, staticscanner.valuescandouble, i);
if i>0 then raise exception.Create(Format(rsIsNotAValidDoubleValue, [frmpointerscannersettings.cbAddress.Text]));
staticscanner.valuescandoubleMax:=staticscanner.valuescandouble+(1/(power(10,floataccuracy)));
end;
end;
end;
progressbar1.Max:=staticscanner.stopaddress-staticscanner.startaddress;
open1.Enabled:=false;
staticscanner.start;
pnlData.Visible:=true;
Method3Fastspeedandaveragememoryusage1.Enabled:=false;
if frmpointerscannersettings.cbConnectToNode.checked then
begin
for i:=0 to frmpointerscannersettings.iplist.count-1 do
begin
if frmpointerscannersettings.iplist[i].host<>'' then
staticscanner.BecomeParentOfNode(frmpointerscannersettings.iplist[i].host, strtoint(frmpointerscannersettings.iplist[i].port), frmpointerscannersettings.iplist[i].password, frmpointerscannersettings.iplist[i].stable);
end;
end;
except
on e: exception do
begin
staticscanner.Free;
staticscanner:=nil;
MessageDlg(e.message, mtError, [mbok], 0);
end;
end;
end;
end;
procedure Tfrmpointerscanner.lvResultsResize(Sender: TObject);
var i,l: integer;
begin
if lvResults.Columns.Count>0 then
begin
l:=0;
for i:=0 to lvResults.columns.count-2 do
inc(l,lvResults.Columns[i].Width);
l:=lvResults.ClientWidth-l;
l:=max(120,l);
lvResults.Columns[lvResults.columns.count-1].Width:=l;
end;
end;
procedure Tfrmpointerscanner.miExportTosqliteClick(Sender: TObject);
var
filename: string;
r: TModalResult;
name: string;
maxlevel: string;
compressedptr, unalligned, MaxBitCountModuleIndex, MaxBitCountModuleOffset, MaxBitCountLevel, MaxBitCountOffset: string;
tablenames: Tstringlist;
fieldnames: tstringlist;
offsetlist, offsetvalues: string;
ptrid: string;
i: integer;
j: qword;
p: PPointerscanResult;
s: string;
pb: TProgressbar;
pbl: TLabel;
oldpb: string;
begin
if (Pointerscanresults<>nil) and (sdSqlite.execute) then
begin
oldpb:=lblProgressbar1.Caption;
filename:=utf8toansi(sdsqlite.FileName);
name:=extractfilename(pointerscanresults.filename);
if InputQuery('Export to database','Give a name for these results', name)=false then exit;
SQLite3.DatabaseName:=filename;
sqlite3.Connected:=true;
SQLTransaction.active:=true;
try
tablenames:=tstringlist.create;
sqlite3.GetTableNames(tablenames, false);
//build the tables if necesary
if tablenames.IndexOf('pointerfiles')=-1 then
begin
sqlite3.ExecuteDirect('CREATE TABLE pointerfiles ('+
'`ptrid` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,'+
'`name` char(256) NOT NULL,'+
'`maxlevel` INTEGER,'+
'`compressedptr` INTEGER,'+
'`unalligned` INTEGER,'+
'`MaxBitCountModuleIndex` INTEGER,'+
'`MaxBitCountModuleOffset` INTEGER,'+
'`MaxBitCountLevel` INTEGER,'+
'`MaxBitCountOffset` INTEGER);');
sqlite3.ExecuteDirect('CREATE UNIQUE INDEX "id_idx" ON pointerfiles( "ptrid" );');
end;
if tablenames.IndexOf('pointerfiles_endwithoffsetlist')=-1 then
begin
sqlite3.ExecuteDirect('CREATE TABLE pointerfiles_endwithoffsetlist ('+
' `ptrid` INTEGER NOT NULL,'+
' `offsetnr` INTEGER NOT NULL,'+
' `offsetvalue` INTEGER NOT NULL,'+
' PRIMARY KEY(ptrid,offsetnr)'+
');');
sqlite3.ExecuteDirect('CREATE UNIQUE INDEX "ptrid_idx" ON pointerfiles( "ptrid" );');
end;
if tablenames.IndexOf('modules')=-1 then
begin
sqlite3.ExecuteDirect('create table modules(ptrid integer not null, moduleid integer not null, name char(256) not null, primary key (ptrid, moduleid) );');
sqlite3.ExecuteDirect('CREATE UNIQUE INDEX "ptr_mod_id_idx" ON "modules"( ptrid, moduleid );');
end;
if tablenames.IndexOf('results')=-1 then
begin
offsetlist:='';
for i:=1 to pointerscanresults.offsetCount do
offsetlist:=offsetlist+', offset'+inttostr(i)+' integer';
sqlite3.ExecuteDirect('create table results(ptrid integer not null, resultid integer not null, offsetcount integer, moduleid integer, moduleoffset integer '+offsetlist+', primary key (ptrid, resultid) );');
sqlite3.ExecuteDirect('CREATE UNIQUE INDEX "ptr_res_id_idx" ON "results"( ptrid, resultid );');
sqlite3.ExecuteDirect('CREATE INDEX "modid_modoff_idx" ON "results"( moduleid, moduleoffset );');
end
else
begin
//might need an update
fieldnames:=tstringlist.create;
sqlite3.GetFieldNames('results', fieldnames);
for i:=1 to pointerscanresults.offsetCount do
if fieldnames.indexof('offset'+inttostr(i))=0 then
sqlite3.ExecuteDirect('ALTER TABLE results ADD COLUMN offset'+inttostr(i)+' integer');
fieldnames.free;
end;
tablenames.free;
SQLQuery.SQL.Text:='Select ptrid from pointerfiles where name="'+name+'"';
SQLQuery.Active:=true;
if SQLQuery.RecordCount>0 then
begin
ptrid:=SQLQuery.FieldByName('ptrid').text;
if MessageDlg('Export to database', 'There is already a pointerfile with this name present in this database. Replace it''s content with this one ?', mtConfirmation, [mbyes, mbno], 0)<>mryes then
begin
showmessage('Export aborted');
exit;
end;
cursor:=crHourGlass;
sqlite3.ExecuteDirect('delete from results where ptrid='+ptrid);
sqlite3.ExecuteDirect('delete from modules where ptrid='+ptrid);
sqlite3.ExecuteDirect('delete from pointerfiles where ptrid='+ptrid);
sqlite3.ExecuteDirect('delete from pointerfiles_endwithoffsetlist where ptrid='+ptrid);
cursor:=crDefault;
end;
SQLQuery.Active:=false;
//and now fill it
cursor:=crHourGlass;
lblProgressbar1.Caption:='Exporting...';
progressbar1.position:=0;
progressbar1.max:=100;
pnlProgress.visible:=true;
Update;
maxlevel:=inttostr(pointerscanresults.offsetCount);
compressedptr:=inttostr(ifthen(Pointerscanresults.compressedptr, 1, 0));
if Pointerscanresults.compressedptr then
begin
unalligned:=inttostr(ifthen(Pointerscanresults.aligned,0,1));
MaxBitCountModuleIndex:=IntToStr(Pointerscanresults.MaxBitCountModuleIndex);
MaxBitCountModuleOffset:=IntToStr(Pointerscanresults.MaxBitCountModuleOffset);
MaxBitCountLevel:=IntToStr(Pointerscanresults.MaxBitCountLevel);
MaxBitCountOffset:=IntToStr(Pointerscanresults.MaxBitCountOffset);
end
else
begin
unalligned:='NULL';
MaxBitCountModuleIndex:='NULL';
MaxBitCountModuleOffset:='NULL';
MaxBitCountLevel:='NULL';
MaxBitCountOffset:='NULL';
end;
s:='INSERT INTO pointerfiles (name, maxlevel, compressedptr, unalligned, MaxBitCountModuleIndex, MaxBitCountModuleOffset, MaxBitCountLevel, MaxBitCountOffset) values ("'+name+'", '+maxlevel+','+compressedptr+','+unalligned+','+MaxBitCountModuleIndex+','+MaxBitCountModuleOffset+','+MaxBitCountLevel+','+MaxBitCountOffset+')';
sqlite3.ExecuteDirect(s);
for i:=0 to Pointerscanresults.EndsWithOffsetListCount-1 do
begin
s:='INSERT INTO pointerfiles_endwithoffsetlist (ptrid, offsetnr, offsetvalue) values ("'+ptrid+'", '+inttostr(i)+','+inttostr(Pointerscanresults.EndsWithOffsetList[i])+')';
sqlite3.ExecuteDirect(s);
end;
SQLQuery.SQL.Text:='Select max(ptrid) as max from pointerfiles';
SQLQuery.Active:=true;
ptrid:=SQLQuery.FieldByName('max').AsString;
SQLQuery.active:=false;
for i:=0 to Pointerscanresults.modulelistCount-1 do
sqlite3.ExecuteDirect('INSERT INTO modules(ptrid, moduleid, name) values ('+ptrid+','+inttostr(i)+',"'+Pointerscanresults.getModulename(i)+'")');
for j:=0 to Pointerscanresults.count-1 do
begin
offsetlist:='';
offsetvalues:='';
p:=Pointerscanresults.getPointer(j);
for i:=1 to p.offsetcount do
begin
offsetlist:=offsetlist+',offset'+inttostr(i);
offsetvalues:=offsetvalues+','+inttostr(p.offsets[i-1]);
end;
s:='INSERT INTO results(ptrid, resultid, offsetcount, moduleid, moduleoffset'+offsetlist+') values ('+ptrid+','+inttostr(j)+','+inttostr(p.offsetcount)+','+inttostr(p.modulenr)+','+inttostr(p.moduleoffset)+offsetvalues+')';
sqlite3.ExecuteDirect(s);
if j mod 50=0 then
begin
progressbar1.position:=ceil(j / Pointerscanresults.count * 100);
progressbar1.Update;
end;
end;
progressbar1.position:=100;
progressbar1.update;
SQLTransaction.Commit;
SQLTransaction.Active:=false;
finally
sqlite3.Connected:=false;
cursor:=crDefault;
lblProgressbar1.Caption:=oldpb;
pnlProgress.visible:=false;
beep;
end;
end;
end;
procedure Tfrmpointerscanner.miImportFromsqliteClick(Sender: TObject);
var
l: TStringList;
f: TfrmSelectionList;
name, filename: string;
query2: TSQLQuery;
ptrfile: tfilestream;
resultptrfile: Tfilestream;
ptrid: string;
i: integer;
compressed: boolean;
alligned: boolean;
MaxBitCountModuleIndex: dword;
MaxBitCountModuleOffset: dword;
MaxBitCountLevel: dword;
MaxBitCountOffset: dword;
MaskModuleIndex: dword;
MaskLevel: dword;
MaskOffset: dword;
maxlevel: integer;
mustendwithoffsetlistlength: integer;
compressedEntry: pbytearray;
compressedEntrySize: integer;
bit: integer;
bd8, bm8: dword;
totalcount: qword;
importedcount: qword;
oldpb: string;
begin
if (sdSqlite.execute) then
begin
filename:=utf8toansi(sdsqlite.FileName);
SQLite3.DatabaseName:=filename;
sqlite3.Connected:=true;
SQLQuery.SQL.Text:='select name from pointerfiles';
SQLQuery.Active:=true;
if SQLQuery.RecordCount>0 then
begin
l:=tstringlist.create;
while not SQLQuery.EOF do
begin
l.add(SQLQuery.FieldByName('Name').Text);
SQLQuery.Next;
end;
end;
SQLQuery.Active:=false;
if l.Count=0 then
begin
MessageDlg('This database does not contain any pointer files', mtError, [mbok],0);
exit;
end;
f:=TfrmSelectionList.create(self, l);
try
if f.showmodal=mrok then
name:=f.selected
else
exit;
finally
f.free;
end;
savedialog1.FileName:=name;
if savedialog1.Execute=false then exit;
filename:=utf8toansi(savedialog1.filename);
ptrfile:=nil;
query2:=nil;
SQLQuery.SQL.Text:='select * from pointerfiles where name="'+name+'"';
SQLQuery.Active:=true;
try
if (SQLQuery.RecordCount=0) or (SQLQuery.RecordCount>1) then
raise exception.create('Invalid database');
query2:=TSQLQuery.Create(self); //extra query
query2.DataBase:=SQLite3;
ptrfile:=TFileStream.Create(filename, fmCreate);
ptrfile.writeByte($ce);
ptrfile.writeByte(pointerscanfileversion);
ptrid:=SQLQuery.FieldByName('ptrid').text;
//save the modulelist
try
query2.sql.text:='Select count(*) as count from modules where ptrid='+ptrid;
query2.Active:=true;
ptrfile.WriteDWord(query2.FieldByName('count').AsInteger);
query2.active:=false;
query2.sql.text:='Select * from modules where ptrid='+ptrid+' order by moduleid asc';
query2.active:=true;
i:=0;
while not query2.EOF do
begin
if query2.FieldByName('moduleid').AsInteger=i then
begin
name:=query2.FieldByName('name').AsString;
//OutputDebugString(pchar(name));
ptrfile.WriteAnsiString(name);
ptrfile.WriteQWord(0);
query2.next;
end
else
begin
//this one seems to be missing
ptrfile.WriteAnsiString('Bogus');
ptrfile.WriteQword(0);
end;
inc(i);
end;
finally
query2.active:=false;
end;
maxlevel:=SQLQuery.FieldByName('maxlevel').AsInteger;
ptrfile.WriteDword(maxlevel);
if SQLQuery.FieldByName('compressedptr').AsInteger=1 then
begin
compressed:=true;
alligned:=SQLQuery.FieldByName('unalligned').AsInteger=0;
MaxBitCountModuleIndex:=SQLQuery.FieldByName('MaxBitCountModuleIndex').AsInteger;
MaxBitCountModuleOffset:=SQLQuery.FieldByName('MaxBitCountModuleOffset').AsInteger;
MaxBitCountLevel:=SQLQuery.FieldByName('MaxBitCountLevel').AsInteger;
MaxBitCountOffset:=SQLQuery.FieldByName('MaxBitCountOffset').AsInteger;
ptrfile.WriteByte(1);
ptrfile.writeByte(ifthen(alligned, 1,0));
ptrfile.writeByte(MaxBitCountModuleIndex);
ptrfile.writeByte(MaxBitCountModuleOffset);
ptrfile.writeByte(MaxBitCountLevel);
ptrfile.writeByte(MaxBitCountOffset);
query2.sql.text:='select count(*) as count from pointerfiles_endwithoffsetlist where ptrid='+ptrid;
query2.active:=true;
mustendwithoffsetlistlength:=query2.FieldByName('count').AsInteger;
ptrfile.writebyte(mustendwithoffsetlistlength);
query2.active:=false;
query2.sql.text:='select * from pointerfiles_endwithoffsetlist where ptrid='+ptrid;
query2.active:=true;
while not query2.eof do
begin
ptrfile.WriteDWord(query2.FieldByName('offsetvalue').AsInteger);
query2.next;
end;
query2.active:=false;
end
else
begin
compressed:=false;
ptrfile.WriteByte(0);
end;
finally
if ptrfile<>nil then
freeandnil(ptrfile);
SQLQuery.Active:=false;
if query2<>nil then
begin
query2.active:=false;
freeandnil(query2);
end;
end;
oldpb:=lblProgressbar1.Caption;
lblProgressbar1.Caption:='Importing...';
progressbar1.position:=0;
progressbar1.max:=100;
pnlProgress.visible:=true;
Update;
compressedEntry:=nil;
resultptrfile:=nil;
{ totalcount: qword;
importedcount: qword;
}
importedcount:=0;
sqlquery.sql.text:='select count(*) as count from results where ptrid='+ptrid;
SQLQuery.Active:=true;
totalcount:=SQLQuery.FieldByName('count').AsInteger;
sqlquery.Active:=false;
sqlquery.sql.text:='select * from results where ptrid='+ptrid;
SQLQuery.active:=true;
try
resultptrfile:=tfilestream.create(filename+'.results.0', fmcreate);
if compressed then
begin
compressedEntrySize:=MaxBitCountModuleOffset+MaxBitCountModuleIndex+MaxBitCountLevel+MaxBitCountOffset*(maxlevel-mustendwithoffsetlistlength);
compressedEntrySize:=(compressedEntrySize+7) div 8;
getmem(compressedEntry, compressedEntrySize+4); //+4 so there's some space for overhead (writing using a dword pointer to the last byte)
MaskModuleIndex:=0;
for i:=1 to MaxBitCountModuleIndex do
MaskModuleIndex:=(MaskModuleIndex shl 1) or 1;
MaskLevel:=0;
for i:=1 to MaxBitCountLevel do
MaskLevel:=(MaskLevel shl 1) or 1;
MaskOffset:=0;
for i:=1 to MaxBitCountOffset do
MaskOffset:=(MaskOffset shl 1) or 1;
end;
while not SQLQuery.eof do
begin
if compressed then
begin
;
//-------------------------------------------
bit:=0;
pqword(compressedEntry)^:=sqlquery.FieldByName('moduleoffset').AsLargeInt;
bit:=bit+MaxBitCountModuleOffset;
bd8:=bit shr 3; //bit div 8;
pdword(@compressedEntry[bd8])^:=sqlquery.FieldByName('moduleid').AsInteger;
bit:=bit+MaxBitCountModuleIndex;
bd8:=bit shr 3; //bit div 8;
bm8:=bit and $7; //bit mod 8;
pdword(@compressedEntry[bd8])^:=pdword(@compressedEntry[bd8])^ and (not (MaskLevel shl bm8)) or ((sqlquery.FieldByName('offsetcount').AsInteger-mustendwithoffsetlistlength) shl bm8);
bit:=bit+MaxBitCountLevel; //next section
//compress the offsets
for i:=1 to sqlquery.FieldByName('offsetcount').AsInteger-mustendwithoffsetlistlength do
begin
bd8:=bit shr 3; //bit div 8;
bm8:=bit and $7; //bit mod 8;
if alligned then
pdword(@compressedEntry[bd8])^:=pdword(@compressedEntry[bd8])^ and (not (MaskOffset shl bm8)) or ((sqlquery.FieldByName('offset'+inttostr(i)).AsInteger shr 2) shl bm8)
else
pdword(@compressedEntry[bd8])^:=pdword(@compressedEntry[bd8])^ and (not (MaskOffset shl bm8)) or ((sqlquery.FieldByName('offset'+inttostr(i)).AsInteger) shl bm8);
bit:=bit+MaxBitCountOffset;
end;
resultptrfile.WriteBuffer(compressedEntry^, compressedEntrySize);
//-------------------------------------------
end
else
begin
resultptrfile.WriteDWord(sqlquery.FieldByName('moduleid').AsInteger);
resultptrfile.WriteQWord(sqlquery.FieldByName('moduleoffset').AsLargeInt);
resultptrfile.WriteDWord(sqlquery.FieldByName('offsetcount').AsInteger);
for i:=1 to maxlevel do
resultptrfile.WriteDWord(sqlquery.FieldByName('offset'+inttostr(i)).AsInteger);
end;
//SQLQuery.FieldByName('');
SQLQuery.next;
inc(importedcount);
if importedcount mod 25=0 then
begin
progressbar1.Position:=ceil(importedcount/totalcount*100);
progressbar1.update;
end;
end;
finally
pnlProgress.visible:=false;
lblProgressbar1.caption:=oldpb;
SQLQuery.active:=false;
if resultptrfile<>nil then
freeandnil(resultptrfile);
if compressedEntry<>nil then
freemem(compressedEntry);
end;
OpenPointerfile(filename);
end;
end;
procedure Tfrmpointerscanner.miCreatePSNnodeClick(Sender: TObject);
var f: TfrmSetupPSNNode;
begin
f:=TfrmSetupPSNNode.Create(self);
if f.showmodal=mrok then
begin
if staticscanner<>nil then
freeandnil(staticscanner);
cbType.Visible:=false;
lvResults.Visible:=false;
//create a new pointerscanner that acts as a node
staticscanner:=TPointerscanController.create(true);
staticscanner.OnStartScan:=PointerscanStart;
staticscanner.OnScanDone:=PointerscanDone;
staticscanner.initializer:=false;
staticscanner.threadcount:=f.threadcount;
staticscanner.priority:=f.priority;
staticscanner.publicname:=f.edtPublicname.text;
staticscanner.listenport:=f.listenport;
staticscanner.allowIncomingParent:=f.cbAllowParents.checked;
staticscanner.allowIncomingChildren:=f.cbAllowChildren.checked;
staticscanner.parentpassword:=f.edtParentPassword.text;
staticscanner.childpassword:=f.edtChildPassword.text;
staticscanner.autoTrustIncomingChildren:=f.cbAutoTrustChildren.checked;
staticscanner.maxResultsToFind:=f.maxresultstofind;
staticscanner.maxTimeToScan:=f.maxtimetoscan;
if f.cbConnectToOtherNode.checked then
begin
if f.rbConnectAsParent.checked then
staticscanner.BecomeParentOfNode(f.edtConnectIP.text, f.connectport, f.edtConnectPassword.text)
else
staticscanner.BecomeChildOfNode(f.edtConnectIP.text, f.connectport, f.edtConnectPassword.text);
end;
staticscanner.allowTempFiles:=f.cbAllowTempFiles.checked;
staticscanner.Start;
pnlData.Visible:=true;
timer2.enabled:=true;
end;
f.free;
end;
procedure Tfrmpointerscanner.miMergePointerscanResultsClick(Sender: TObject);
begin
end;
procedure Tfrmpointerscanner.miSetWorkFolderClick(Sender: TObject);
begin
end;
procedure Tfrmpointerscanner.FormDestroy(Sender: TObject);
var x: array of integer;
begin
setlength(x,1);
x[0]:=cbtype.itemindex;
SaveFormPosition(self, x);
end;
procedure Tfrmpointerscanner.btnStopRescanLoopClick(Sender: TObject);
begin
btnStopRescanLoop.visible:=false;
rescanpointerform.cbRepeat.checked:=false;
end;
procedure Tfrmpointerscanner.btnConnectClick(Sender: TObject);
begin
if staticscanner<>nil then
staticscanner.BecomeParentOfNode(edtIP.text, strtoint(edtPort.text), edtPassword.text, cbTrusted.checked);
end;
procedure Tfrmpointerscanner.btnIncreaseThreadCountClick(Sender: TObject);
begin
if staticscanner<>nil then
begin
staticscanner.addWorkerThread;
inc(staticscanner.threadcount);
end;
end;
procedure Tfrmpointerscanner.btnDecreaseThreadCountClick(Sender: TObject);
begin
if staticscanner<>nil then
begin
staticscanner.RemoveWorkerThread;
if staticscanner.threadcount>0 then
dec(staticscanner.threadcount);
end;
end;
procedure Tfrmpointerscanner.cbPriorityChange(Sender: TObject);
var scannerpriority: TThreadPriority;
begin
if staticscanner<>nil then
begin
case cbPriority.itemindex of
0: scannerpriority:=tpIdle;
1: scannerpriority:=tpLowest;
2: scannerpriority:=tpLower;
3: scannerpriority:=tpNormal;
4: scannerpriority:=tpHigher;
5: scannerpriority:=tpHighest;
6: scannerpriority:=tpTimeCritical;
end;
staticscanner.changeWorkerPriority(scannerpriority);
end;
end;
procedure Tfrmpointerscanner.cbTestCrappyConnectionChange(Sender: TObject);
begin
debug_connectionfailure:=cbTestCrappyConnection.checked;
end;
procedure Tfrmpointerscanner.FormResize(Sender: TObject);
begin
btnStopRescanLoop.Left:=(clientwidth div 2) - (btnStopRescanLoop.Width div 2);
end;
procedure Tfrmpointerscanner.lvResultsColumnClick(Sender: TObject; Column: TListColumn);
//Using dark byte's super secret "Screw this, I'll just split it into chunks" algorithm
var
c: integer;
frmSortPointerlist: TfrmSortPointerlist;
tempname: string;
oldname: string;
oldlist: Tstringlist;
tempfilelist: tstringlist;
newname: string;
i: integer;
s: string;
begin
c:=column.index;
if c=lvResults.ColumnCount-1 then exit; //raise exception.create('The result/value list is unsortable');
if Pointerscanresults.count<=1 then exit; //don't even bother
frmSortPointerlist:=TfrmSortPointerlist.Create(self);
oldname:=Pointerscanresults.filename;
oldlist:=tstringlist.create;
tempfilelist:=tstringlist.create;
Pointerscanresults.getFileList(oldlist);
if frmSortPointerlist.dowork(column.index, oldname , tempname, tempfilelist) then
begin
//sorting done
new1.Click;
//delete the old pointerfiles
for i:=0 to oldlist.Count-1 do
begin
s:=oldlist[i];
DeleteFile(s);
end;
for i:=0 to tempfilelist.count-1 do
begin
newname:=StringReplace(tempfilelist[i], tempname, oldname+'.results',[]);
DeleteFile(newname);
RenameFile(tempfilelist[i], newname);
end;
OpenPointerfile(oldname);
end;
oldlist.free;
frmSortPointerlist.free;
end;
procedure Tfrmpointerscanner.Timer2Timer(Sender: TObject);
var i,j: integer;
s: string;
tn,tn2: TTreenode;
x: qword;
tpe: qword;
tpf: qword;
totalTimeWriting: qword;
totalTime: qword;
percentageSpentWriting: single;
connectinglist: TConnectEntryArray;
connectionlist: TConnectionEntryArray;
parentdata: TPublicParentData;
info: tstringlist;
statistics: record
totalTimeScanning: qword;
totalPathsEvaluated: QWord;
totalpathspersecond: double;
localPathsEvaluated: Qword;
localpathspersecond: double;
pointersinmap: qword;
pathqueuesize: integer;
pathqueueoverflow: dword;
resultsfound: qword;
timeSpentWriting: qword;
percentageTimeSpentWriting: single;
minpath, maxpath: TDynDwordArray;
minpaths, maxpaths: string;
shownetwork: boolean;
end;
scanners: array of record
status: string;
end;
sl: TStringList;
begin
if lvResults.Visible then
lvResults.repaint;
try
//collect data and then update the treeview
zeromemory(@statistics, sizeof(statistics));
statistics.totalTimeScanning:=0;
statistics.localPathsEvaluated:=0;
statistics.localpathspersecond:=0;
if staticscanner<>nil then
begin
statistics.shownetwork:=staticscanner.hasNetworkResponsibility;
if staticscanner.starttime>0 then
statistics.totalTimeScanning:=GetTickCount64-staticscanner.starttime;
statistics.totalPathsEvaluated:=staticscanner.totalpathsevaluated;
statistics.localPathsEvaluated:=staticscanner.localpathsevaluated;
if statistics.totalTimeScanning>0 then
begin
statistics.totalpathspersecond:=(statistics.totalPathsEvaluated / statistics.totalTimeScanning)*1000; //paths / second
statistics.localPathsPersecond:=(statistics.localPathsEvaluated / statistics.totalTimeScanning)*1000; //paths / second
end;
statistics.pointersinmap:=staticscanner.getPointerlistHandlerCount;
statistics.pathqueuesize:=staticscanner.pathqueuelength;
statistics.pathqueueoverflow:=length(staticscanner.overflowqueue);
statistics.resultsfound:=staticscanner.getTotalResultsFound;
statistics.timeSpentWriting:=ceil((staticscanner.getTotalTimeWriting / 1000) / staticscanner.threadcount); //time spend writing in seconds
statistics.percentageTimeSpentWriting:=(statistics.timeSpentWriting / (statistics.totalTimeScanning / 1000)) * 100; //time spend writing in seconds / total time div
staticscanner.getMinAndMaxPath(statistics.minpath, statistics.maxpath);
statistics.minpaths:='';
for i:=0 to length(statistics.minpath)-1 do
begin
statistics.minpaths:=statistics.minpaths+inttohex(statistics.minpath[i],1);
if i<length(statistics.minpath)-1 then
statistics.minpaths:=statistics.minpaths+' - ';
end;
statistics.maxpaths:='';
for i:=0 to length(statistics.maxpath)-1 do
begin
statistics.maxpaths:=statistics.maxpaths+inttohex(statistics.maxpath[i],1);
if i<length(statistics.maxpath)-1 then
statistics.maxpaths:=statistics.maxpaths+' - ';
end;
sl:=TStringList.create;
staticscanner.getThreadStatuses(sl);
setlength(scanners, sl.Count);
for i:=0 to sl.count-1 do
scanners[i].status:=sl[i];
sl.free;
end;
//setup the basics if it hasn't been setup yet
with infonodes.statistics.stats do
begin
if infonodes.statistics.node=nil then
begin
//create the statistics node and the childnodes
infonodes.statistics.node:=tvInfo.Items.Add(nil, 'Statistics');
pointersInMap:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
totalTimeScanning:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
localPathsEvaluated:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
localPathsPerSecond:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
totalPathsEvaluated:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
totalPathsPerSecond:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
pathQueue:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
resultsFound:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
timeSpentWriting:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
minpath:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
//maxpath:=tvInfo.Items.AddChild(infonodes.statistics.node,'');
infonodes.statistics.node.Expand(true);
end;
pointersInMap.Text:='Unique pointervalues in target:'+IntToStr(statistics.pointersinmap);
totalTimeScanning.Text:='Scan duration: '+TimeToStr(TimeStampToDateTime(MSecsToTimeStamp(statistics.totalTimeScanning)));
localPathsEvaluated.Text:='Paths evaluated: '+IntToStr(statistics.localPathsEvaluated);
localPathsPerSecond.Text:=format('Paths / seconds: (%.0n / s)', [statistics.localpathspersecond]);
totalPathsEvaluated.Text:='Total paths evaluated: '+IntToStr(statistics.totalPathsEvaluated);
totalPathsPerSecond.Text:=format('Total paths / seconds: (%.0n / s)', [statistics.totalpathspersecond]);
pathQueue.Text:='Static queue size: '+inttostr(statistics.pathqueuesize)+' Dynamic queue size:'+inttostr(statistics.pathqueueoverflow);
resultsFound.Text:='Results found: '+inttostr(statistics.resultsfound);
timeSpentWriting.Text:='Time spent writing: '+inttostr(statistics.timeSpentWriting)+format(' (%.2f %%)', [statistics.percentageTimeSpentWriting]) ;
minpath.text:='Lowest known path:'+statistics.minpaths;
// maxpath.text:='Highest known path:'+statistics.maxpaths;
totalPathsEvaluated.visible:=statistics.shownetwork;
totalPathsPerSecond.visible:=statistics.shownetwork;
end;
if infonodes.localworkers.node=nil then
infonodes.localworkers.node:=tvInfo.Items.Add(nil, 'Threads');
for i:=length(infonodes.localworkers.workernodes)-1 downto length(scanners) do //delete the nodes that are too many
if infonodes.localworkers.workernodes[i].node<>nil then
infonodes.localworkers.workernodes[i].node.free;
setlength(infonodes.localworkers.workernodes, length(scanners));
for i:=0 to length(infonodes.localworkers.workernodes)-1 do
begin
if infonodes.localworkers.workernodes[i].node=nil then
infonodes.localworkers.workernodes[i].node:=tvInfo.Items.AddChild(infonodes.localworkers.node, '');
infonodes.localworkers.workernodes[i].node.Text:=scanners[i].status;
end;
if staticscanner<>nil then
begin
if staticscanner.hasNetworkResponsibility then
begin
//display network info
if infonodes.network.node=nil then
infonodes.network.node:=tvInfo.Items.Add(nil,'Network');
staticscanner.getConnectingList(connectinglist);
for i:=length(infonodes.network.connectingToNodes)-1 downto length(connectinglist) do
infonodes.network.connectingToNodes[i].data.Free;
setlength(infonodes.network.connectingToNodes, length(connectinglist));
//connecting to:
if infonodes.network.connectingto=nil then
infonodes.network.connectingto:=tvInfo.Items.AddChild(infonodes.network.node,'Connecting to:');
for i:=0 to length(connectinglist)-1 do
begin
if infonodes.network.connectingToNodes[i].data=nil then //create a new one
infonodes.network.connectingToNodes[i].data:=tvinfo.Items.AddChild(infonodes.network.connectingto,'');
s:=connectinglist[i].ip+':'+inttostr(connectinglist[i].port);
if connectinglist[i].becomeparent=false then
s:=s+BoolToStr(connectinglist[i].trusted, ' (Trusted)','');
infonodes.network.connectingToNodes[i].data.Text:=s;
end;
staticscanner.getConnectionList(connectionlist);
for i:=length(infonodes.network.connectedToNodes)-1 downto length(connectionlist) do
infonodes.network.connectedToNodes[i].node.free;
setlength(infonodes.network.connectedToNodes, length(connectionlist));
//connected to:
if Staticscanner.initializer=false then
begin
staticscanner.getParentData(parentdata);
if infonodes.network.parent=nil then
infonodes.network.parent:=tvInfo.Items.AddChild(infonodes.network.node,'Parent: ');
if parentdata.connected then
begin
infonodes.network.parent.Text:='Parent: '+parentdata.name+'('+parentdata.ip+':'+inttostr(parentdata.port)+')';
if infonodes.network.parentnodes.lastUpdateSent=nil then
infonodes.network.parentnodes.lastUpdateSent:=tvInfo.Items.AddChild(infonodes.network.parent,'');
if staticscanner.downloadingscandata then
begin
infonodes.network.parentnodes.lastUpdateSent.Text:=format('Downloading scandata: %.1f%% (%dKB/%dKB : %d KB/sec)', [staticscanner.downloadingscandata_received/staticscanner.downloadingscandata_total*100, staticscanner.downloadingscandata_received div 1024, staticscanner.downloadingscandata_total div 1024, ceil(((staticscanner.downloadingscandata_received / 1024)/((GetTickCount64-staticscanner.downloadingscandata_starttime)/1000)) )]);
end
else
begin
infonodes.network.parentnodes.lastUpdateSent.Text:='Last update: '+inttostr((GetTickCount64-parentdata.lastupdatesent) div 1000)+' seconds ago';
end;
end
else
begin
//mark that it has no parent (yet/anymore)
if parentdata.waitingforreconnect then
infonodes.network.parent.Text:='Parent: <disconnected> (Waiting for reconnect)'
else
infonodes.network.parent.Text:='Parent: <none>';
//if there are nodes, delete them
if infonodes.network.parentnodes.lastUpdateSent<>nil then
freeandnil(infonodes.network.parentnodes.lastUpdateSent);
end;
end;
if infonodes.network.connectedTo=nil then
infonodes.network.connectedTo:=tvInfo.Items.AddChild(infonodes.network.node,'Children:');
for i:=0 to length(connectionlist)-1 do
begin
if infonodes.network.connectedToNodes[i].node=nil then //create it
begin
infonodes.network.connectedToNodes[i].node:=tvInfo.Items.AddChild(infonodes.network.connectedTo, s);
tn:=infonodes.network.connectedToNodes[i].node;
with infonodes.network.connectedToNodes[i].data do
begin
disconnectreason:=tvinfo.items.AddChild(tn, '');
trusted:=tvInfo.Items.AddChild(tn, '');
totalthreadcount:=tvInfo.Items.AddChild(tn, '');
resultsfound:=tvInfo.Items.AddChild(tn, '');
pathqueuesize:=tvInfo.Items.AddChild(tn, '');
totalpathquesize:=tvInfo.Items.AddChild(tn, '');
totalpathsEvaluated:=tvInfo.Items.AddChild(tn, '');
// pathspersecond:=tvInfo.Items.AddChild(tn, '');
end;
end;
s:=connectionlist[i].ip+':'+inttostr(connectionlist[i].port);
if connectionlist[i].disconnected then
s:=s+' (Disconnected)'
else
if connectionlist[i].queued then
s:=s+' (Queued: '+inttostr(connectionlist[i].queuepos)+'/'+inttostr(connectionlist[i].queuesize)+')'
else
begin
if connectionlist[i].isidle=false then
s:=s+' (Active)'
else
s:=s+' (Idle)';
if connectionlist[i].uploadingscandata then
s:=s+format(' (Uploading scandata: %.1f%% (%dKB/%dKB : %d KB/sec)', [connectionlist[i].ScanDataSent/connectionlist[i].ScanDataTotalSize*100, connectionlist[i].ScanDataSent div 1024, connectionlist[i].ScanDataTotalSize div 1024, ceil(((connectionlist[i].ScanDataSent / 1024)/((GetTickCount64-connectionlist[i].ScanDataStartTime)/1000)) )]);
if connectionlist[i].downloadingResuls then
s:=s+' (Downloading and handling results)';
end;
infonodes.network.connectedToNodes[i].node.Text:=s;
with infonodes.network.connectedToNodes[i].data do
begin
disconnectreason.visible:=connectionlist[i].disconnected;
disconnectreason.Text:=connectionlist[i].lasterror;
trusted.text:='Trusted: '+BoolToStr(connectionlist[i].trustedconnection, 'True', 'False');
totalthreadcount.text:='Threadcount: '+IntToStr(connectionlist[i].potentialthreadcount)+' ('+IntToStr(connectionlist[i].actualthreadcount)+')';
resultsfound.text:='Results found: '+IntToStr(connectionlist[i].resultsfound);
pathqueuesize.text:='Queuesize: '+inttostr(connectionlist[i].pathquesize);
totalpathquesize.text:='Total Queuesize: '+inttostr(connectionlist[i].totalpathqueuesize);
totalpathsEvaluated.text:='Paths evaluated: '+inttostr(connectionlist[i].pathsevaluated);
//pathspersecond.text:='Paths/second: '+inttostr(connectionlist[i].pathspersecond);
end;
end;
end;
end;
except
// showmessage('exception happened');
on e:exception do
begin
OutputDebugString('pscangui update timer error: '+e.message);
end;
end;
end;
procedure Tfrmpointerscanner.OpenPointerfile(filename: string);
var
i: integer;
col_baseaddress:TListColumn;
col_pointsto: TListColumn;
col_offsets: Array of TListColumn;
begin
new1.Click;
Pointerscanresults:=TPointerscanresultReader.create(filename);
lvResults.Items.BeginUpdate;
lvResults.Columns.BeginUpdate;
lvResults.Items.Count:=0;
lvResults.Columns.Clear;
col_baseaddress:=lvResults.Columns.Add;
col_baseaddress.Caption:=rsBaseAddress;
col_baseaddress.Width:=150;
col_baseaddress.MinWidth:=20;
setlength(col_offsets, Pointerscanresults.offsetCount);
for i:=0 to Pointerscanresults.offsetCount-1 do
begin
col_offsets[i]:=lvResults.Columns.Add;
col_offsets[i].Caption:=rsOffset+' '+inttostr(i);
col_offsets[i].Width:=80;
col_offsets[i].MinWidth:=10;
end;
col_pointsto:=lvResults.Columns.Add;
col_pointsto.Caption:=rsPointsTo+':';
col_pointsto.Width:=120;
col_pointsto.MinWidth:=10;
col_pointsto.AutoSize:=true;
panel1.Caption:=rsPointercount+':'+inttostr(Pointerscanresults.count);
if (Pointerscanresults.count>1000000) then
begin
lvResults.Items.Count:=1000000;
// showmessage(rsOnlyTheFirst1000000EntriesWillBeDisplayed);
end
else
lvResults.Items.Count:=Pointerscanresults.count;
lvResults.Align:=alClient;
lvResults.Visible:=true;
lvResults.Columns.EndUpdate;
lvResults.Items.EndUpdate;
cbtype.top:=0;
cbtype.height:=panel1.ClientHeight;
cbtype.Visible:=true;
Rescanmemory1.Enabled:=true;
new1.Enabled:=true;
caption:=rsPointerScan+' : '+extractfilename(filename);
miResume.visible:=Pointerscanresults.CanResume;
miResume.Enabled:=Pointerscanresults.CanResume;
end;
procedure Tfrmpointerscanner.Open1Click(Sender: TObject);
begin
if opendialog1.Execute then
OpenPointerfile(utf8toansi(Opendialog1.filename));
end;
function TRescanWorker.isMatchToValue(p:pointer): boolean;
begin
case valuetype of
vtDword: result:=pdword(p)^=valuescandword;
vtSingle: result:=(psingle(p)^>=valuescansingle) and (psingle(p)^<valuescansinglemax);
vtDouble: result:=(pdouble(p)^>=valuescandouble) and (pdouble(p)^<valuescandoublemax);
end;
end;
procedure TRescanWorker.flushresults;
begin
tempfile.WriteBuffer(tempbuffer.Memory^,tempbuffer.Position);
tempbuffer.Seek(0,sofrombeginning);
end;
destructor TRescanworker.destroy;
begin
if Pointerscanresults<>nil then
Pointerscanresults.Free;
end;
procedure TRescanWorker.execute;
var
currentEntry: qword;
i,j,k: integer;
baseaddress, address,address2, tempaddress: ptrUint;
pi: TPageInfo;
x: dword;
valid: boolean;
tempvalue: pointer;
value: pointer;
p: ppointerscanresult;
pointersize: integer;
L: Plua_State;
lref: integer;
lfun: integer;
ltable: integer;
mr: TMemoryRegion;
begin
l:=nil;
try
if useluafilter then
begin
//create a new lua thread
luacs.enter;
try
l:=lua_newthread(luavm); //pushes the thread on the luavm stack.
lref:=luaL_ref(luavm,LUA_REGISTRYINDEX); //add a reference so the garbage collector wont destroy the thread (pops the thread off the stack)
finally
luacs.leave;
end;
lua_getglobal(L, pchar(luafilter));
lfun:=lua_gettop(L);
//create a table for the offset
lua_createtable(L, Pointerscanresults.offsetCount+1,0); //+1 for a nil
ltable:=lua_gettop(L);
end;
tempfile:=nil;
tempbuffer:=nil;
address:=0;
address2:=0;
pointersize:=processhandler.pointersize;
getmem(tempvalue,valuesize);
try
tempfile:=tfilestream.Create(self.filename, fmCreate);
tempbuffer:=TMemoryStream.Create;
tempbuffer.SetSize(16*1024*1024);
evaluated:=0;
currentEntry:=self.startentry;
if currentEntry>Pointerscanresults.count then exit;
while evaluated < self.EntriesToCheck do
begin
p:=Pointerscanresults.getPointer(currentEntry);
if p<>nil then
begin
valid:=true;
if pointermap=nil then
begin
if p.modulenr=-1 then
address:=p.moduleoffset
else
address:=Pointerscanresults.getModuleBase(p.modulenr)+p.moduleoffset
end
else
address:=pointermap.getAddressFromModuleIndexPlusOffset(p.modulenr,p.moduleoffset);
baseaddress:=address;
if address>0 then
begin
//if the base must be in a range then check if the base address is in the given range
if (not mustbeinrange) or (inrangex(address, baseStart, baseEnd)) then
begin
//don't care or in range.
//check if start offet values are given
if length(startOffsetValues)>0 then
begin
//check the offsets
for i:=0 to length(startOffsetValues)-1 do
if p.offsets[p.offsetcount-1-i]<>startOffsetValues[i] then
begin
valid:=false;
break;
end;
end;
if valid and (length(endoffsetvalues)>0) then
begin
j:=0;
for i:=length(endoffsetvalues)-1 downto 0 do
begin
if p.offsets[j]<>endoffsetvalues[i] then
begin
valid:=false;
break;
end;
inc(j);
end;
end;
if valid then
begin
//evaluate the pointer to address
if pointermap=nil then
begin
for i:=p.offsetcount-1 downto 0 do
begin
pi:=rescanhelper.FindPage(address shr 12);
if (pi.data<>nil) then
begin
tempaddress:=0;
j:=address and $fff; //offset into the page
k:=min(pointersize, 4096-j); //bytes to read from this page
if (k<pointersize) then
begin
//more bytes are needed
copymemory(@tempaddress, @pi.data[j], k);
pi:=rescanhelper.FindPage((address shr 12)+1);
if pi.data<>nil then
copymemory(pointer(ptruint(@address)+k), @pi.data[0], pointersize-k)
else
begin
valid:=false;
break;
end;
end
else
tempaddress:=pptruint(@pi.data[j])^;
{$ifdef cpu64}
if pointersize=4 then
tempaddress:=tempaddress and $ffffffff;
{$endif}
address:=tempaddress+p.offsets[i];
end
else
begin
valid:=false;
break;
end;
end;
end
else
begin
//use pointermap
for i:=p.offsetcount-1 downto 0 do
begin
address:=pointermap.getPointer(address);
if address=0 then
begin
valid:=false;
break;
end;
address:=address+p.offsets[i];
end;
end;
end;
if valid then
begin
if novaluecheck or forvalue then
begin
//evaluate the address (address must be accessible)
if rescanhelper.ispointer(address) then
begin
if novaluecheck=false then //check if the value is correct
begin
value:=nil;
pi:=rescanhelper.FindPage(address shr 12);
if pi.data<>nil then
begin
i:=address and $fff;
j:=min(valuesize, 4096-i);
copymemory(tempvalue, @pi.data[i], j);
if j<valuesize then
begin
pi:=rescanhelper.FindPage((address shr 12)+1);
if pi.data<>nil then
copymemory(pointer(ptruint(tempvalue)+j), @pi.data[0], valuesize-j)
else
valid:=false;
end;
end
else
valid:=false;
value:=tempvalue;
if (not valid) or (value=nil) or (not isMatchToValue(value)) then
valid:=false; //invalid value
end;
end else valid:=false; //unreadable address
end
else
begin
//check if the address matches
if address<>PointerAddressToFind then
valid:=false;
end;
end;
if valid and useluafilter then
begin
//check the lua function
//first set the offsets
for i:=0 to p.offsetcount-1 do
begin
lua_pushinteger(L, p.offsets[i]);
lua_rawseti(L, ltable, i+1);
end;
//end the table with a nil marker
lua_pushnil(L);
lua_rawseti(L, ltable, p.offsetcount+1);
//setup the function call
lua_pushvalue(L, lfun); //function
lua_pushinteger(L, baseaddress); //base
lua_pushvalue(L, ltable); //offsets
lua_pushinteger(L, address); //address
lua_call(L, 3,1); //call and don't expect any errors
valid:=lua_toboolean(L, -1);
lua_pop(L, 1);
end;
if valid then
begin
//checks passed, it's valid
if pointerscanresults.compressedptr then
p:=pointerscanresults.LastRawPointer;
tempbuffer.Write(p^,Pointerscanresults.entrySize);
if tempbuffer.Position>16*1024*1024 then flushresults;
end;
end; //must be in range and it wasn't in the range
end;
end;
inc(evaluated);
inc(currentEntry);
end;
flushresults;
finally
freemem(tempvalue);
if tempfile<>nil then
freeandnil(tempfile);
if tempbuffer<>nil then
freeandnil(tempbuffer);
if l<>nil then
begin
lua_settop(L, 0);
//remove the reference to the thread
luacs.enter;
try
luaL_unref(LuaVM, LUA_REGISTRYINDEX, lref);
finally
luacs.leave;
end;
end;
done:=true;
end;
except
on e: exception do
begin
MessageBox(0, 'FUU', pchar(e.message), 0);
end;
end;
end;
//------RescanPointers-------
procedure TRescanpointers.closeOldFile;
begin
ownerform.New1Click(ownerform.new1);
end;
procedure TRescanpointers.execute;
var
tempstring: string;
i,j: integer;
TotalPointersToEvaluate: qword;
PointersEvaluated: qword;
blocksize: qword;
threadhandles: array of Thandle;
result: tfilestream;
//rpmcontainer: TReadProcessMemoryContainer;
temp: dword;
valuesize: integer;
f: tfilestream;
ds: Tdecompressionstream;
oldptr: Tmemorystream;
oldfiles: TStringList;
ml: Tstringlist;
begin
progressbar.Min:=0;
progressbar.Max:=100;
progressbar.Position:=0;
result:=nil;
sleep(delay*1000);
pointerscanresults:=ownerform.pointerscanresults;
pointerscanresults.resyncModulelist;
if forvalue and (valuetype=vtDouble) then valuesize:=8 else valuesize:=4;
rescanhelper:=TRescanHelper.create;
if pointermapfilename<>'' then
begin
ds:=nil;
f:=tfilestream.Create(pointermapfilename, fmOpenRead or fmShareDenyNone);
try
ds:=Tdecompressionstream.create(f);
pointermap:=TPointerListHandler.createFromStream(ds, pointermapprogressbar);
ml:=TStringList.create;
for i:=0 to pointerscanresults.modulelistCount-1 do
ml.AddObject(pointerscanresults.getModulename(i), tobject(pointerscanresults.getModuleBase(i)));
pointermap.reorderModuleIdList(ml);
ml.free;
finally
if ds<>nil then
freeandnil(ds);
f.free;
end;
end;
pointermapprogressbar.position:=100;
//fill the modulelist with baseaddresses
try
//the modulelist now holds the baseaddresses (0 if otherwise)
TotalPointersToEvaluate:=pointerscanresults.count;
//spawn all threads
rescanworkercount:=GetCPUCount;
if HasHyperthreading then rescanworkercount:=ceil((rescanworkercount / 2)+(rescanworkercount / 4));
blocksize:=TotalPointersToEvaluate div rescanworkercount;
if blocksize<8 then blocksize:=8;
setlength(rescanworkers, rescanworkercount);
setlength(threadhandles, rescanworkercount);
for i:=0 to rescanworkercount-1 do
begin
rescanworkers[i]:=TRescanWorker.Create(true);
rescanworkers[i].Pointerscanresults:=TPointerscanresultReader.create(originalptrfile, pointerscanresults);
rescanworkers[i].pointermap:=pointermap;
rescanworkers[i].PointerAddressToFind:=self.address;
rescanworkers[i].novaluecheck:=novaluecheck;
rescanworkers[i].forvalue:=forvalue;
rescanworkers[i].valuesize:=valuesize;
rescanworkers[i].valuetype:=valuetype;
rescanworkers[i].valuescandword:=valuescandword;
rescanworkers[i].valuescansingle:=valuescansingle;
rescanworkers[i].valuescandouble:=valuescandouble;
rescanworkers[i].valuescansinglemax:=valuescansinglemax;
rescanworkers[i].valuescandoublemax:=valuescandoublemax;
rescanworkers[i].rescanhelper:=rescanhelper;
rescanworkers[i].filename:=self.filename+'.newresults.'+inttostr(i);
rescanworkers[i].startEntry:=blocksize*i;
rescanworkers[i].entriestocheck:=blocksize;
if i=rescanworkercount-1 then
rescanworkers[i].entriestocheck:=TotalPointersToEvaluate-rescanworkers[i].startEntry; //to the end
rescanworkers[i].mustbeinrange:=mustbeinrange;
rescanworkers[i].baseStart:=baseStart;
rescanworkers[i].baseEnd:=baseEnd;
setlength(rescanworkers[i].startOffsetValues, length(startoffsetvalues));
for j:=0 to length(startOffsetValues)-1 do
rescanworkers[i].startOffsetValues[j]:=startOffsetValues[j];
setlength(rescanworkers[i].endoffsetvalues, length(endoffsetvalues));
for j:=0 to length(EndOffsetValues)-1 do
rescanworkers[i].EndOffsetValues[j]:=EndOffsetValues[j];
rescanworkers[i].useluafilter:=useluafilter;
rescanworkers[i].luafilter:=luafilter;
threadhandles[i]:=rescanworkers[i].Handle;
rescanworkers[i].start;
end;
while WaitForMultipleObjects(rescanworkercount, @threadhandles[0], true, 250) = WAIT_TIMEOUT do //wait
begin
//query all threads the number of pointers they have evaluated
PointersEvaluated:=0;
for i:=0 to rescanworkercount-1 do
inc(PointersEvaluated,rescanworkers[i].evaluated);
progressbar.Position:=PointersEvaluated div (TotalPointersToEvaluate div 100);
end;
//no timeout, so finished or crashed
//destroy workers
for i:=0 to rescanworkercount-1 do
begin
rescanworkers[i].WaitFor; //just to be sure
if rescanworkers[i].Pointerscanresults<>nil then
freeandnil(rescanworkers[i].Pointerscanresults);
rescanworkers[i].Free;
rescanworkers[i]:=nil;
end;
synchronize(closeoldfile);
oldptr:=tmemorystream.create;
try
oldptr.LoadFromFile(originalptrfile);
oldptr.SaveToFile(filename);
finally
oldptr.free;
end;
//delete the old files of the destination filename that could conflict
oldfiles:=tstringlist.create;
try
findAllResultFilesForThisPtr(filename, oldfiles);
for i:=0 to oldfiles.count-1 do
DeleteFile(oldfiles[i]);
finally
oldfiles.free;
end;
//rename the newresults to results
for i:=0 to rescanworkercount-1 do
begin
DeleteFile(filename+'.results.'+inttostr(i)); //just to be sure (oldfiles should have cleaned this up)
RenameFile(filename+'.newresults.'+inttostr(i), filename+'.results.'+inttostr(i));
end;
rescanworkercount:=0;
setlength(rescanworkers,0);
finally
if rescanhelper<>nil then
freeandnil(rescanhelper);
progressbar.Position:=0;
postmessage(ownerform.Handle,rescan_done,0,0);
end;
end;
destructor TRescanpointers.destroy;
begin
if pointermapprogressbar<>nil then
freeandnil(pointermapprogressbar);
if pointermapprogressbarlabel<>nil then
freeandnil(pointermapprogressbarlabel);
if pointermap<>nil then
freeandnil(pointermap);
inherited destroy;
end;
procedure Tfrmpointerscanner.miJoinDistributedRescanClick(Sender: TObject);
//var f: tfrmPointerrescanConnectDialog;
begin
{ f:=tfrmPointerrescanConnectDialog.create(self);
if f.showmodal=mrok then
begin
//create a rescanpointers object
if distributedworkfolder='' then
miSetWorkFolder.Click;
if distributedworkfolder='' then exit;
JoinRescan(f.edtHost.text, f.port);
end; }
end;
procedure Tfrmpointerscanner.Rescanmemory1Click(Sender: TObject);
var address: ptrUint;
FloatSettings: TFormatSettings;
floataccuracy: integer;
i: integer;
begin
floatsettings:=DefaultFormatSettings;
if rescan<>nil then
freeandnil(rescan);
rescan:=trescanpointers.create(true);
rescan.ownerform:=self;
rescan.progressbar:=progressbar1;
lblProgressbar1.caption:='Rescanning';
pnlProgress.visible:=true;
try
if rescanpointerform=nil then
rescanpointerform:=TFrmRescanPointer.Create(self);
with rescanpointerform do
begin
if (rescanpointerform.cbRepeat.checked) or (showmodal=mrok) then
begin
if (rescanpointerform.cbRepeat.checked) or savedialog1.Execute then
begin
rescan.novaluecheck:=cbNoValueCheck.checked;
if cbUseSavedPointermap.checked then
begin
rescan.pointermapfilename:=odLoadPointermap.filename;
rescan.pointermapprogressbar:=TProgressBar.Create(self);
rescan.pointermapprogressbar.parent:=pnlProgressBar;
rescan.pointermapprogressbar.position:=0;
rescan.pointermapprogressbar.max:=100;
rescan.pointermapprogressbar.top:=progressbar1.top+progressbar1.height;
rescan.pointermapprogressbar.left:=ProgressBar1.Left;
rescan.pointermapprogressbar.width:=Progressbar1.width;
rescan.pointermapprogressbar.anchors:=ProgressBar1.anchors;
rescan.pointermapprogressbarlabel:=TLabel.create(self);
rescan.pointermapprogressbarlabel.caption:=extractfilename(rescan.pointermapfilename);
rescan.pointermapprogressbarlabel.parent:=pnlProgressName;
rescan.pointermapprogressbarlabel.top:=rescan.pointermapprogressbar.top+(rescan.pointermapprogressbar.height div 2)-(rescan.pointermapprogressbarlabel.height div 2);
rescan.pointermapprogressbarlabel.hint:=rescan.pointermapfilename;
rescan.pointermapprogressbarlabel.showhint:=true;
pnlProgress.ClientHeight:=rescan.pointermapprogressbar.Top+rescan.pointermapprogressbar.height+1;
end;
if cbRepeat.Checked then
begin
//show the stop rescan repeat button
btnStopRescanLoop.Visible:=true;
btnStopRescanLoop.BringToFront;
end;
rescan.filename:=utf8toansi(savedialog1.filename);
if cbDelay.checked then
rescan.delay:=delay
else
rescan.delay:=0;
rescan.mustbeinrange:=cbBasePointerMustBeInRange.checked;
if rescan.mustbeinrange then
begin
rescan.BaseStart:=baseStart;
rescan.BaseEnd:=baseEnd;
end;
if cbMustStartWithSpecificOffsets.checked then
begin
setlength(rescan.startOffsetValues, length(startOffsetValues));
for i:=0 to length(startOffsetValues)-1 do
rescan.startOffsetValues[i]:=startOffsetValues[i];
end
else
setlength(rescan.startOffsetValues,0); //shouldn't be necessary, but just in case
if cbMustEndWithSpecificOffsets.checked then
begin
setlength(rescan.endOffsetValues, length(endOffsetValues));
for i:=0 to length(endOffsetValues)-1 do
rescan.endOffsetValues[i]:=endOffsetValues[i];
end
else
setlength(rescan.endoffsetvalues,0);
if uppercase(rescan.filename)=uppercase(pointerscanresults.filename) then
rescan.overwrite:=true;
Rescanmemory1.Enabled:=false;
new1.Enabled:=false;
if cbNoValueCheck.checked=false then
begin
if rbFindAddress.Checked then
begin
try
address:=StrToQWordEx('$'+edtAddress.Text);
//rescan the pointerlist
except
raise exception.create('Find by address requires an address. "'+edtaddress.text+'" is not a valid address');
end;
rescan.address:=address;
rescan.forvalue:=false;
end
else
begin
//if values, check what type of value
floataccuracy:=pos(FloatSettings.DecimalSeparator,edtAddress.Text);
if floataccuracy>0 then
floataccuracy:=length(edtAddress.Text)-floataccuracy;
case cbValueType.ItemIndex of
0:
begin
rescan.valuetype:=vtDword;
val(edtAddress.Text, rescan.valuescandword, i);
if i>0 then raise exception.Create(Format(rsIsNotAValid4ByteValue, [edtAddress.Text]));
end;
1:
begin
rescan.valuetype:=vtSingle;
val(edtAddress.Text, rescan.valuescansingle, i);
if i>0 then raise exception.Create(Format(rsIsNotAValidFloatingPointValue, [edtAddress.Text]));
rescan.valuescansingleMax:=rescan.valuescansingle+(1/(power(10,floataccuracy)));
end;
2:
begin
rescan.valuetype:=vtDouble;
val(edtAddress.Text, rescan.valuescandouble, i);
if i>0 then raise exception.Create(Format(
rsIsNotAValidDoubleValue, [edtAddress.Text]));
rescan.valuescandoubleMax:=rescan.valuescandouble+(1/(power(10,floataccuracy)));
end;
end;
rescan.forvalue:=true;
end;
end;
rescan.useLuaFilter:=cbLuaFilter.checked;
rescan.LuaFilter:=edtRescanFunction.text;
{
if (Pointerscanresults.externalScanners>0) and (cbDistributedRescan.checked) then
begin
rescan.distributedport:=distributedport;
rescan.distributedrescan:=true;
rescan.distributedrescanWorker:=false;
rescan.broadcastThisScanner:=cbDistributedRescan.Checked;
rescan.potentialWorkerList:=resolvediplist;
rescan.waitforall:=cbWaitForAll.checked;
end; }
rescan.originalptrfile:=Pointerscanresults.filename;
rescan.start;
end;
end;
end;
except
on e: exception do
begin
Rescanmemory1.Enabled:=true;
new1.Enabled:=true;
freeandnil(rescan);
raise exception.create(e.message);
end;
end;
end;
procedure tfrmpointerscanner.rescandone(var message: tmessage);
{
The rescan is done. rescan.oldpointerlist (the current pointerlist) can be deleted
and the new pointerlist becomes the current pointerlist
}
begin
doneui;
if rescan<>nil then
freeandnil(rescan);
if (rescanpointerform<>nil) and rescanpointerform.cbRepeat.checked then
begin
//repeat
Rescanmemory1.Click;
end
else
begin
Rescanmemory1.Enabled:=true;
new1.Enabled:=true;
end;
end;
procedure Tfrmpointerscanner.stopscan(savestate: boolean);
var
i: integer;
f: tfilestream;
begin
if staticscanner<>nil then
begin
if savestate then
begin
btnStopScan.Caption:=rsSavingAndTerminating;
for i:=0 to pnlProgress.ControlCount-1 do
begin
if pnlProgress.Controls[i]<>lblProgressbar1 then
pnlProgress.Controls[i].Visible:=false;
end;
for i:=0 to pnlProgressBar.ControlCount-1 do
begin
if pnlProgressBar.Controls[i]<>Progressbar1 then
pnlProgressBar.Controls[i].Visible:=false;
end;
pnlProgress.height:=ProgressBar1.height+1;
ProgressBar1.visible:=true;
Progressbar1.Position:=0;
progressbar1.Max:=100;
progressbar1.top:=0;
pnlProgressName.visible:=true;
pnlProgressBar.visible:=true;
lblProgressbar1.Visible:=true;
pnlProgress.Visible:=true;
staticscanner.TerminateAndSaveState;
end
else
begin
btnStopScan.Caption:=rsTerminating;
staticscanner.Terminate;
end;
btnStopScan.enabled:=false;
end;
end;
procedure Tfrmpointerscanner.btnStopScanClick(Sender: TObject);
var c: TModalResult;
begin
if staticscanner<>nil then
begin
if staticscanner.initializer=false then
c:=mryes
else
begin
if not (staticscanner.useheapdata or staticscanner.findValueInsteadOfAddress) then
c:=MessageDlg('Do you wish to resume the current pointerscan at a later time?', mtInformation,[mbyes, mbno, mbCancel], 0)
else
c:=mrno; //you can't resume scans that do a valuescan or use heapdata
end;
case c of
mryes: stopscan(true);
mrno: stopscan(false);
else exit;
end;
end;
end;
procedure Tfrmpointerscanner.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if Staticscanner<>nil then
begin
Staticscanner.Terminate;
Staticscanner.WaitFor;
freeandnil(Staticscanner);
end;
new1.Click;
action:=cafree; //on close free itself
end;
procedure Tfrmpointerscanner.openscanner(var message: tmessage);
begin
if frmpointerscannersettings=nil then
frmpointerscannersettings:=tfrmpointerscannersettings.create(application);
frmpointerscannersettings.cbAddress.text:=inttohex(message.WParam,8);
Method3Fastspeedandaveragememoryusage1.Click;
end;
procedure Tfrmpointerscanner.PointerscanStart(sender: TObject);
begin
pnlProgress.Visible:=false;
timer2.enabled:=true;
end;
procedure Tfrmpointerscanner.New1Click(Sender: TObject);
begin
if staticscanner<>nil then
freeandnil(staticscanner);
pnlData.Visible:=false;
panel1.Caption:='';
open1.Enabled:=true;
new1.enabled:=true;
rescanmemory1.Enabled:=false;
lvResults.Items.BeginUpdate;
lvResults.columns.BeginUpdate;
lvResults.Columns.Clear;
lvResults.Items.Count:=0;
lvResults.Items.EndUpdate;
lvResults.Columns.EndUpdate;
Method3Fastspeedandaveragememoryusage1.Enabled:=true;
timer2.Enabled:=false;
if Pointerscanresults<>nil then
freeandnil(Pointerscanresults);
end;
procedure Tfrmpointerscanner.FormCreate(Sender: TObject);
var
x: array of integer;
reg: tregistry;
begin
{$ifdef cpu64}
SQLiteLibraryName:='.\win64\sqlite3.dll';
{$else}
SQLiteLibraryName:='.\win32\sqlite3.dll';
{$endif}
{$ifdef injectedpscan}
caption:='CE Injected Pointerscan';
{$endif}
lvResults.DoubleBuffered:=true;
lvResults.Align:=alClient;
lvResults.Visible:=true;
setlength(x,1);
if loadformposition(self,x) then
cbtype.itemindex:=x[0];
reg:=TRegistry.Create;
reg.free;
end;
procedure Tfrmpointerscanner.lvResultsData(Sender: TObject;
Item: TListItem);
var
p: PPointerscanResult;
i: integer;
s: string;
check: boolean;
doublevalue: double;
dwordvalue: dword absolute doublevalue; //make sure of the same memory
floatvalue: single absolute doublevalue;
x: ptruint;
address: ptrUint;
begin
if Pointerscanresults<>nil then
begin
p:=Pointerscanresults.getPointer(item.index, address);
if p<>nil then //just to be safe
begin
if p.modulenr=-1 then
item.Caption:=inttohex(p.moduleoffset,8)
else
begin
if p.moduleoffset>=0 then
item.Caption:=ansitoutf8('"'+pointerscanresults.getModulename(p.modulenr)+'"+'+inttohex(p.moduleoffset,8))
else
item.Caption:=ansitoutf8('"'+pointerscanresults.getModulename(p.modulenr)+'"-'+inttohex(-p.moduleoffset,8));
end;
for i:=p.offsetcount-1 downto 0 do
item.SubItems.Add(inttohex(p.offsets[i],1));
for i:=p.offsetcount to Pointerscanresults.offsetCount-1 do
item.SubItems.Add('');
if address=0 then
item.SubItems.Add('-') else
begin
s:=inttohex(address,8);
if cbType.ItemIndex<>-1 then
begin
s:=s+' = ';
if cbType.ItemIndex=2 then
check:=readprocessmemory(processhandle, pointer(address),@doublevalue,8,x) else
check:=readprocessmemory(processhandle, pointer(address),@doublevalue,4,x);
if check then
begin
case cbType.ItemIndex of
0: s:=s+inttostr(dwordvalue);
1: s:=s+floattostr(floatvalue);
2: s:=s+floattostr(doublevalue);
end;
end else s:=s+'??';
end;
item.SubItems.Add(s);
end;
end;
end;
end;
procedure Tfrmpointerscanner.resyncloadedmodulelist;
begin
if pointerscanresults<>nil then
pointerscanresults.resyncModulelist;
end;
procedure Tfrmpointerscanner.Resyncmodulelist1Click(Sender: TObject);
begin
resyncloadedmodulelist;
lvResults.Refresh;
end;
procedure Tfrmpointerscanner.lvResultsDblClick(Sender: TObject);
var
li: tlistitem;
i: integer;
offsets: array of integer;
t: string;
c: integer;
vtype: TVariableType;
begin
if lvResults.ItemIndex<>-1 then
begin
li:=lvResults.Items.Item[lvResults.ItemIndex];
t:=utf8toansi(li.caption);
try
setlength(offsets,li.SubItems.Count);
c:=0;
for i:=li.SubItems.Count-2 downto 0 do
begin
if li.SubItems[i]='' then continue;
offsets[c]:=strtoint('$'+li.SubItems[i]);
inc(c);
end;
case cbType.ItemIndex of
1: vtype:=vtSingle;
2: vtype:=vtDouble;
else vtype:=vtDword;
end;
mainform.addresslist.addaddress(rsPointerscanResult, t, offsets, c, vtype);
except
end;
end;
end;
procedure Tfrmpointerscanner.cbTypeChange(Sender: TObject);
begin
lvResults.Refresh;
end;
initialization
{$i pointerscannerfrm.lrs}
end.