3437 lines
103 KiB
ObjectPascal
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.
|
|
|
|
|