2011-07-04 19:52:53 +00:00
{
todo:
This has shown a usefull method to dissect structures
wat can be done is add every dword offset in a structure as an offset and compare against the 4 bytes there
}
unit frmStringPointerScanUnit;
{$mode delphi}
interface
uses
2019-12-18 12:07:17 +01:00
{$ifdef darwin}
macport,
{$endif}
{$ifdef windows}
windows,
{$endif}
2022-11-15 11:25:18 +01:00
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, ExtCtrls, ComCtrls, CEFuncProc, NewKernelHandler, frmStringMapUnit,
MemFuncs, AvgLvlTree, Menus, bigmemallochandler, math, maps, oldRegExpr,
symbolhandler, commonTypeDefs, lmessages, LCLIntf, betterControls, DPIHelper;
2011-07-04 19:52:53 +00:00
const
wm_sps_done= wm_user+ 1 ;
type
{ TfrmStringPointerScan }
TPointerpath= array of dword;
TDiffkind= ( dkDontCare, dkMustBeDifferent, dkMustBeSame) ;
type
PMappedRegion= ^ TMappedRegion;
TMappedRegion= record
baseaddress: ptruint; //if a new section overlaps, append to this
size: ptruint; //if a new section ovrlaps increase this
previous: PMappedRegion;
next: PMappedRegion;
end ;
PPointerListEntry= ^ TPointerListEntry;
TPointerListEntry= record
address: ptruint;
pointsto: ptruint;
previous: PPointerListEntry;
next: PPointerListEntry;
end ;
type TPointerRecord= packed record
level: integer ;
stringsize: integer ;
2021-05-12 11:46:10 +02:00
unicode: longbool ;
2011-07-04 19:52:53 +00:00
offset: TDwordArray;
end ;
PPointerRecord= ^ TPointerRecord;
TPointerfileReader= class
private
pointerfile: TFilestream;
entrysize: integer ;
fcount: qword;
pointerfileLevelwidth: integer ;
bufferindex: integer ;
buffersize: integer ;
pointerrecords: PPointerRecord; //actually an array...
stringbuf: pchar ;
widestringbuf: pwidechar ;
pointermap: TMap;
ffilename: string ;
function getByteFromAddress( address: ptruint; var error: boolean ) : byte ;
function getWordFromAddress( address: ptruint; var error: boolean ) : word ;
function getDWordFromAddress( address: ptruint; var error: boolean ) : dword;
function getQWordFromAddress( address: ptruint; var error: boolean ) : qword;
function getSingleFromAddress( address: ptruint; var error: boolean ) : single ;
function getDoubleFromAddress( address: ptruint; var error: boolean ) : double ;
function getPointerFromAddress( address: ptruint; var error: boolean ) : ptruint;
public
vartype: TVariableType;
procedure clearPointerCache;
2012-05-17 01:15:07 +00:00
function getPointerRec( index : qword) : PPointerRecord;
2013-04-09 23:08:58 +00:00
function getAddressFromPointerRecord( p: ppointerrecord; baseaddress: ptruint; shadow: ptruint; shadowsize: integer ) : ptruint;
function getStringFromPointerRecord( p: ppointerrecord; address: ptruint; shadow: ptruint; shadowsize: integer ) : string ;
function getStringAndAddress( index : qword; var address: ptruint; out p: PPointerRecord; shadow: ptruint; shadowsize: integer ) : string ;
2011-07-04 19:52:53 +00:00
constructor create( filename: string ) ;
destructor destroy; override ;
property levelWidth: integer read pointerfileLevelwidth;
property count: qword read fcount;
property filename: string read ffilename;
end ;
Trescan= class( tthread)
private
outputfile: tfilestream;
isstringscan: boolean ;
mustbestart: boolean ;
regEx: TRegExprEngine;
diffkind: TDiffkind;
pointerfilereader: TPointerfileReader;
address, address2: ptruint;
2013-04-09 23:08:58 +00:00
shadow, shadow2: ptruint;
shadowsize, shadowsize2: integer ;
2011-07-04 19:52:53 +00:00
mustbeinregion: boolean ;
pointerstart, pointerend: ptruint;
outputfilename: string ;
oldpointerfilename: string ;
results: TMemorystream;
fcount: qword;
fCurrentPosition: qword;
vartype: TVariableType;
lastwrite: dword;
ownerFrmStringPointerScan: TCustomForm;
procedure addPointer( p: PPointerRecord) ;
procedure flushresults;
function checkByte( p: PPointerRecord) : boolean ;
function checkWord( p: PPointerRecord) : boolean ;
function checkDWord( p: PPointerRecord) : boolean ;
function checkQWord( p: PPointerRecord) : boolean ;
function checkSingle( p: PPointerRecord) : boolean ;
function checkDouble( p: PPointerRecord) : boolean ;
function checkPointer( p: PPointerRecord) : boolean ;
public
procedure execute; override ;
constructor create( suspended: boolean ; address, address2: ptruint; mustbeinregion: boolean ; pointerstart, pointerend: ptruint; isstringscan, caseSensitive, mustbestart: boolean ; regExstr: string ; diffkind: TDiffkind; vartype: TVariableType; oldpointerfilename: string ; outputfilename: string ; ownerFrmStringPointerScan: TCustomForm ) ;
destructor destroy; override ;
property count: qword read fcount;
property currentPosition: qword read fCurrentPosition;
end ;
TScanner= class( tthread)
private
baseaddress: ptruint;
2013-04-09 23:08:58 +00:00
shadow: ptruint;
shadowsize: ptruint;
2011-07-04 19:52:53 +00:00
baseaddress2: ptruint;
2013-04-09 23:08:58 +00:00
shadow2: ptruint;
shadowsize2: ptruint;
2011-07-04 19:52:53 +00:00
diffkind: Tdiffkind;
vartype: TVariableType;
structsize: ptruint;
maxlevel: ptruint;
mappedregions: TAvgLvlTree;
pointerlist: TAvgLvlTree;
tempvariablebuffer, tempvariablebuffer2: pbytearray ; //storage for the value compare. Preallocate so no need to call getmem/freemem each time
variablesize: integer ;
valuemap: tmap;
bma: TBigMemoryAllocHandler;
count: integer ;
2013-06-08 00:58:29 +00:00
//levelblock: array of Puint64Array; //I think this is obsolete
fillpointerblock: pointer ; //memory block allocated for the fuillpointers function
2011-07-04 19:52:53 +00:00
// block64: array of Pint64Array;
results: TMemorystream;
resultfile: tfilestream;
lastwrite: dword;
//datascan variables
isDataScan: boolean ;
alignment: integer ;
mustbeinregion: boolean ;
pointerstart: ptruint;
pointerstop: ptruint;
ownerFrmStringPointerScan: TCustomForm;
2013-06-08 00:58:29 +00:00
is64bittarget: boolean ;
2011-07-04 19:52:53 +00:00
procedure handleBlock( blockaddress: ptruint; level: integer ; path: TPointerpath) ;
2021-05-12 11:46:10 +02:00
function addStringPath( level: integer ; path: tpointerpath; stringsize: integer ; unicode: longbool ) : boolean ;
2011-07-04 19:52:53 +00:00
function comparePath( level: integer ; path: tpointerpath; stringsize: integer ) : boolean ;
2013-04-09 23:08:58 +00:00
function getAddressFromPath( base : ptruint; column: integer ; level: integer ; const path: TPointerPath) : ptruint;
2011-07-04 19:52:53 +00:00
procedure mapRegionIfNeeded( blockaddress: ptruint; size: integer ) ;
procedure fillPointers( base: ptruint; size: integer ) ;
function getFirstPointerEntry( base: ptruint) : PPointerListEntry;
2013-04-09 23:08:58 +00:00
function getPointerValue( address: ptruint; column: integer ) : ptruint;
2011-07-04 19:52:53 +00:00
procedure flushResults;
public
progress: TPointerpath;
procedure execute; override ;
2013-04-09 23:08:58 +00:00
constructor create( isDataScan, mustbeinregion: boolean ; alignment: integer ; pointerstart, pointerstop: ptruint; baseaddress: ptruint; shadow: ptruint; shadowsize: ptruint; baseaddress2: ptruint; shadow2: ptruint; shadowsize2: integer ; diffkind: TDiffkind; vartype: TVariableType; mapvalues: boolean ; structsize: integer ; maxlevel: integer ; mappedregions, pointerlist: TAvgLvlTree; bma: TBigMemoryAllocHandler; filename: string ; ownerFrmStringPointerScan: TCustomForm) ;
2011-07-04 19:52:53 +00:00
destructor destroy; override ;
end ;
TfrmStringPointerScan = class( TForm)
2013-04-11 18:31:08 +00:00
btnNewScan: TButton;
2016-08-18 18:28:45 +02:00
btnScan: TButton;
2011-07-04 19:52:53 +00:00
cbCaseSensitive: TCheckBox;
2016-08-18 18:28:45 +02:00
cbHasShadow: TCheckBox;
2013-04-09 23:08:58 +00:00
cbHasShadow2: TCheckBox;
2011-07-04 19:52:53 +00:00
cbMustBeStart: TCheckBox;
cbRegExp: TCheckBox;
cbPointerInRange: TCheckBox;
cbMapPointerValues: TCheckBox;
2016-12-13 14:26:18 +01:00
cbReuseStringmap: TCheckBox;
2011-07-04 19:52:53 +00:00
comboCompareType: TComboBox;
2016-08-18 18:28:45 +02:00
comboType: TComboBox;
edtBase: TEdit;
edtMaxLevel: TEdit;
2013-04-09 23:08:58 +00:00
edtShadowAddress: TEdit;
edtShadowAddress2: TEdit;
2011-07-04 19:52:53 +00:00
edtPointerStart: TEdit;
edtPointerStop: TEdit;
edtAlignsize: TEdit;
edtExtra: TEdit;
edtRegExp: TEdit;
2016-08-18 18:28:45 +02:00
edtShadowSize: TEdit;
2013-04-09 23:08:58 +00:00
edtShadowSize2: TEdit;
2011-07-04 19:52:53 +00:00
edtStructsize: TEdit;
2016-12-13 23:34:10 +01:00
FindDialog1: TFindDialog;
2019-05-12 01:13:44 +02:00
spImageList: TImageList;
2016-08-18 18:28:45 +02:00
lblBaseRegion: TLabel;
lblInfo: TLabel;
lblMaxLevel: TLabel;
2013-04-11 18:31:08 +00:00
lblSize: TLabel;
lblsize2: TLabel;
2011-07-04 19:52:53 +00:00
lblStructsize: TLabel;
lblCompare: TLabel;
lblAlign: TLabel;
lblAnd: TLabel;
lblString: TLabel;
lblExtra: TLabel;
2016-08-18 18:28:45 +02:00
lblvds: TLabel;
2011-07-04 19:52:53 +00:00
ListView1: TListView;
MainMenu1: TMainMenu;
MenuItem1: TMenuItem;
2016-12-13 23:34:10 +01:00
miFind: TMenuItem;
miFindNext: TMenuItem;
2013-04-11 18:31:08 +00:00
miNewScan: TMenuItem;
2016-09-16 12:06:24 +02:00
miOpen: TMenuItem;
2011-07-04 19:52:53 +00:00
MenuItem4: TMenuItem;
MenuItem7: TMenuItem;
miClearCache: TMenuItem;
MenuItem5: TMenuItem;
MenuItem6: TMenuItem;
OpenDialog1: TOpenDialog;
Panel1: TPanel;
Panel2: TPanel;
Panel3: TPanel;
Panel4: TPanel;
2016-08-18 18:28:45 +02:00
Panel5: TPanel;
Panel6: TPanel;
Panel7: TPanel;
Panel8: TPanel;
Panel9: TPanel;
2011-07-04 19:52:53 +00:00
pmPointerfile: TPopupMenu;
ProgressBar1: TProgressBar;
rbDiffDontCare: TRadioButton;
rbMustBeDifferent: TRadioButton;
rbMustBeSame: TRadioButton;
rbStringscan: TRadioButton;
rbDatascan: TRadioButton;
SaveDialog1: TSaveDialog;
statusupdater: TTimer;
procedure btnScanClick( Sender: TObject) ;
2013-04-11 18:31:08 +00:00
procedure cbHasShadowChange( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
procedure cbRegExpChange( Sender: TObject) ;
procedure cbPointerInRangeChange( Sender: TObject) ;
2018-06-03 10:00:23 +02:00
procedure cbReuseStringmapChange( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
procedure comboTypeChange( Sender: TObject) ;
procedure edtBaseChange( Sender: TObject) ;
procedure edtExtraChange( Sender: TObject) ;
2016-12-13 23:34:10 +01:00
procedure FindDialog1Find( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
procedure FormClose( Sender: TObject; var CloseAction: TCloseAction) ;
2022-11-15 11:25:18 +01:00
procedure FormCreate( Sender: TObject) ;
procedure FormDestroy( Sender: TObject) ;
2013-04-11 18:31:08 +00:00
procedure FormShow( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
procedure ListView1CustomDrawItem( Sender: TCustomListView; Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean ) ;
procedure ListView1Data( Sender: TObject; Item: TListItem) ;
procedure ListView1DblClick( Sender: TObject) ;
2016-12-13 23:34:10 +01:00
procedure miFindClick( Sender: TObject) ;
2013-04-11 18:31:08 +00:00
procedure miNewScanClick( Sender: TObject) ;
2016-09-16 12:06:24 +02:00
procedure miOpenClick( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
procedure MenuItem7Click( Sender: TObject) ;
procedure miClearCacheClick( Sender: TObject) ;
procedure MenuItem6Click( Sender: TObject) ;
2016-12-13 23:34:10 +01:00
procedure Panel3Click( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
procedure rbDatascanChange( Sender: TObject) ;
procedure rbDiffDontCareChange( Sender: TObject) ;
procedure statusupdaterTimer( Sender: TObject) ;
private
{ private declarations }
2022-11-15 11:25:18 +01:00
loadedFormPosition: boolean ;
2011-07-04 19:52:53 +00:00
mappedRegions: TAvgLvlTree; //holds the map of the regions that have been mapped
pointerlist: TAvgLvlTree; //holds the pointers in the app of the mapped regions
2012-06-05 13:14:43 +00:00
2011-07-04 19:52:53 +00:00
bma: TBigMemoryAllocHandler;
scanner: TScanner;
rescanner: TRescan;
pointerfilereader: TPointerfilereader;
address, address2: ptruint;
2013-04-09 23:08:58 +00:00
shadow, shadow2: ptruint;
shadowsize, shadowsize2: integer ;
2011-07-04 19:52:53 +00:00
hasAddress2: boolean ;
2022-11-15 11:25:18 +01:00
scanning: boolean ;
2011-07-04 19:52:53 +00:00
function mapCompare( Tree: TAvgLvlTree; Data1, Data2: Pointer ) : integer ;
function pointerCompare( Tree: TAvgLvlTree; Data1, Data2: Pointer ) : integer ;
procedure cleanup;
procedure OpenPointerfile( filename: string ) ;
2016-12-13 14:26:18 +01:00
procedure scanDone;
2011-07-04 19:52:53 +00:00
function getStringFromPointer( address: ptruint; offsets: TDwordArray; level, bytesize: integer ; unicode: boolean ; var a: ptruint) : string ;
2016-09-16 12:06:24 +02:00
procedure setGUIStateEnabled( state: boolean ) ;
2011-07-04 19:52:53 +00:00
public
{ public declarations }
2016-09-16 12:06:24 +02:00
procedure disableGui;
2011-07-04 19:52:53 +00:00
procedure enablegui;
end ;
var
frmStringPointerScan: TfrmStringPointerScan;
implementation
{ TfrmStringPointerScan }
2014-11-07 02:09:23 +00:00
uses frmStructPointerRescanUnit, MemoryBrowserFormUnit, ProcessHandlerUnit, Parsers;
2011-07-04 19:52:53 +00:00
resourcestring
rsGeneratingStringmap = 'Generating stringmap' ;
rsGeneratedScanning = 'Generated. Scanning...' ;
rsThisAddressIsNotAccessible = 'This address is not accessible' ;
2014-02-13 22:40:50 +00:00
rsStop = 'Stop' ;
rsTerminating = 'Terminating...' ;
rsAreYouSureYo = 'Are you sure you wish to start a new scan?' ;
rsScan = 'Scan' ;
rsScanningFoun = 'Scanning... Found %s' ;
2015-09-19 23:20:34 +02:00
rsSPSUNotYetImplemented = 'Not yet implemented' ;
rsSPSUFUUUU = 'FUUUU' ;
rsSPSUFUUUUU = 'FUUUUU' ;
rsSPSUException = 'Exception:' ;
rsSPSUOffset = 'Offset ' ;
rsSPSUAddress = 'Address' ;
rsSPSUAddress2 = 'Address 2' ;
rsSPSURescan = 'Rescan' ;
rsSPSUFound = 'Found:' ;
rsSPSUScanDoneFound = 'Scan done! Found ' ;
rsSPSUErrorduringScanNoScanresults = 'Error during scan. No scanresults available' ;
2011-07-04 19:52:53 +00:00
//----------TPointerfileReader---------
function TPointerfilereader. getByteFromAddress( address: ptruint; var error: boolean ) : byte ;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
begin
error: = not readprocessmemory( processhandle, pointer( address) , @ result , 1 , x) ;
error: = error or ( x< > 1 ) ;
end ;
function TPointerfilereader. getWordFromAddress( address: ptruint; var error: boolean ) : word ;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
begin
error: = not readprocessmemory( processhandle, pointer( address) , @ result , 2 , x) ;
error: = error or ( x< > 2 ) ;
end ;
function TPointerfilereader. getDWordFromAddress( address: ptruint; var error: boolean ) : dword;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
begin
error: = not readprocessmemory( processhandle, pointer( address) , @ result , 4 , x) ;
error: = error or ( x< > 4 ) ;
end ;
function TPointerfilereader. getQWordFromAddress( address: ptruint; var error: boolean ) : qword;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
begin
error: = not readprocessmemory( processhandle, pointer( address) , @ result , 8 , x) ;
error: = error or ( x< > 8 ) ;
end ;
function TPointerfilereader. getSingleFromAddress( address: ptruint; var error: boolean ) : single ;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
begin
error: = not readprocessmemory( processhandle, pointer( address) , @ result , 4 , x) ;
error: = error or ( x< > 4 ) ;
end ;
function TPointerfilereader. getDoubleFromAddress( address: ptruint; var error: boolean ) : double ;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
begin
error: = not readprocessmemory( processhandle, pointer( address) , @ result , 8 , x) ;
error: = error or ( x< > 8 ) ;
end ;
function TPointerfilereader. getPointerFromAddress( address: ptruint; var error: boolean ) : ptruint;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
begin
result : = 0 ;
error: = not readprocessmemory( processhandle, pointer( address) , @ result , processhandler. pointersize, x) ;
error: = error or ( x< > processhandler. pointersize) ;
end ;
procedure TPointerfilereader. clearPointerCache;
begin
pointermap. Clear;
end ;
2012-05-17 01:15:07 +00:00
function TPointerfileReader. getPointerRec( index : qword) : PPointerRecord;
2021-05-12 11:46:10 +02:00
var
blocksize: integer ;
newpos: int64 ;
2011-07-04 19:52:53 +00:00
begin
2021-05-12 11:46:10 +02:00
2011-07-04 19:52:53 +00:00
result : = nil ;
if ( buffersize= 0 ) or ( not InRangeQ( index , bufferindex, bufferindex+ buffersize- 1 ) ) then
begin
2021-05-12 11:46:10 +02:00
2013-06-06 17:50:54 +00:00
blocksize: = count- index ;
2011-07-04 19:52:53 +00:00
blocksize: = min( blocksize, 4 0 9 6 ) ;
2021-05-12 11:46:10 +02:00
newpos: = sizeof( pointerfileLevelwidth) + index * entrysize;
pointerfile. Position: = newpos;
2011-07-04 19:52:53 +00:00
if pointerfile. Read( pointerrecords^ , entrysize* blocksize) = entrysize* blocksize then
begin
bufferindex: = index ;
buffersize: = blocksize;
2021-05-12 11:46:10 +02:00
end
else
exit( nil ) ;
2011-07-04 19:52:53 +00:00
end ;
2021-05-12 11:46:10 +02:00
result : = PPointerRecord( ptruint( pointerrecords) + ( index - bufferindex) * entrysize) ;
2011-07-04 19:52:53 +00:00
end ;
2013-04-09 23:08:58 +00:00
function TPointerfilereader. getAddressFromPointerRecord( p: ppointerrecord; baseaddress: ptruint; shadow: ptruint; shadowsize: integer ) : ptruint;
2011-07-04 19:52:53 +00:00
var address: ptruint;
a: ptruint;
i: integer ;
2014-05-11 03:08:36 +00:00
x: ptruint;
2011-07-04 19:52:53 +00:00
dp: pptruint;
begin
result : = 0 ;
address: = baseaddress+ p. offset[ 0 ] ;
2013-04-09 23:08:58 +00:00
2013-04-11 18:31:08 +00:00
if shadow< > 0 then
begin
if inrangeq( address, baseaddress, baseaddress+ shadowsize) then
address: = address+ ( shadow- baseaddress) ;
end ;
2013-04-09 23:08:58 +00:00
2011-07-04 19:52:53 +00:00
for i: = 1 to p. level do
begin
dp: = pointermap. GetDataPtr( address) ;
if dp< > nil then
begin
address: = dp^ ;
if address= 0 then
exit; //unreadable
end
else
begin
a: = 0 ;
if not readprocessmemory( processhandle, pointer( address) , @ a, processhandler. pointersize, x) then
a: = 0 ;
2013-04-11 18:31:08 +00:00
if ( shadow< > 0 ) and ( inrangeq( a, baseaddress, baseaddress+ shadowsize) ) then
2013-04-09 23:08:58 +00:00
a: = a+ ( shadow- baseaddress) ;
2011-07-04 19:52:53 +00:00
pointermap. Add( address, a) ;
address: = a;
if a= 0 then
exit; //unreadable
end ;
address: = address+ p. offset[ i]
end ;
result : = address;
end ;
2013-04-09 23:08:58 +00:00
function TPointerfileReader. getStringFromPointerRecord( p: ppointerrecord; address: ptruint; shadow: ptruint; shadowsize: integer ) : string ;
2011-07-04 19:52:53 +00:00
var i, j: integer ;
2014-05-11 03:08:36 +00:00
x: ptruint;
2011-07-04 19:52:53 +00:00
e: boolean ;
begin
result : = '' ;
2013-04-09 23:08:58 +00:00
address: = getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if address> 0 then
begin
case vartype of
vtByte, vtWord, vtDword, vtQword, vtSingle, vtDouble, vtPointer:
begin
e: = false ;
case vartype of
vtByte: result : = inttostr( getByteFromAddress( address, e) ) ;
vtWord: result : = inttostr( getWordFromAddress( address, e) ) ;
vtDword: result : = inttostr( getDwordFromAddress( address, e) ) ;
vtQword: result : = inttostr( getQwordFromAddress( address, e) ) ;
vtSingle: result : = format( '%.3f' , [ getSingleFromAddress( address, e) ] ) ;
vtDouble: result : = format( '%.3f' , [ getDoubleFromAddress( address, e) ] ) ;
vtPointer: result : = IntToHex( getPointerFromAddress( address, e) , processhandler. pointersize* 2 ) ;
end ;
end ;
vtString:
begin
//string
if p. stringsize> 0 then
i: = min( p. stringsize, 5 1 0 )
else
i: = 1 6 ; //it was a data type
if readprocessmemory( processhandle, pointer( address) , stringbuf, i, x) then
begin
stringbuf[ i] : = #0 ;
stringbuf[ i+ 1 ] : = #0 ;
if p. stringsize< = 0 then
begin
//guess the stringtype (if it is one to begin with)
if stringbuf[ 1 ] = #0 then
p. unicode: = true ;
end ;
if p. unicode then
result : = widestringbuf
else
result : = stringbuf;
end ;
end
else
2015-09-19 23:20:34 +02:00
result : = rsSPSUNotYetImplemented;
2011-07-04 19:52:53 +00:00
end ;
end ;
end ;
2013-04-09 23:08:58 +00:00
function TPointerfileReader. getStringAndAddress( index : qword; var address: ptruint; out p: PPointerRecord; shadow: ptruint; shadowsize: integer ) : string ;
2011-07-04 19:52:53 +00:00
begin
2018-06-01 12:50:03 +02:00
result : = '' ;
2012-05-17 01:15:07 +00:00
p: = getPointerRec( index ) ;
2011-07-04 19:52:53 +00:00
if p< > nil then
2018-06-05 20:45:45 +02:00
begin
2013-04-09 23:08:58 +00:00
result : = getStringFromPointerRecord( p, address, shadow, shadowsize) ;
2018-06-05 20:45:45 +02:00
address: = getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
end ;
2011-07-04 19:52:53 +00:00
end ;
constructor TPointerfileReader. create( filename: string ) ;
begin
ffilename: = filename;
pointerfile: = TFileStream. Create( filename, fmOpenRead or fmShareDenyNone) ;
pointerfile. ReadBuffer( pointerfileLevelwidth, sizeof( pointerfileLevelwidth) ) ;
entrysize: = ( pointerfileLevelwidth+ 4 ) * sizeof( dword) ; //+4 for : Levelsize of pointer, stringsize and the isunicode boolean and levelwidth is based on 0 (0=1 offset, 1=2 offsets, etc..)
fcount: = ( pointerfile. size- sizeof( pointerfileLevelwidth) ) div ( entrysize) ;
2021-05-12 11:46:10 +02:00
2011-07-04 19:52:53 +00:00
getmem( pointerrecords, entrysize* 4 0 9 6 ) ;
getmem( stringbuf, 5 1 2 ) ;
widestringbuf: = pwidechar( stringbuf) ;
pointermap: = TMap. Create( ituPtrSize, sizeof( pointer ) )
end ;
destructor TPointerfileReader. destroy;
begin
if pointerfile< > nil then
freeandnil( pointerfile) ;
if pointerrecords< > nil then
2018-06-12 20:23:45 +02:00
FreeMemAndNil( pointerrecords) ;
2011-07-04 19:52:53 +00:00
if stringbuf< > nil then
2018-06-12 20:23:45 +02:00
FreeMemAndNil( stringbuf) ;
2011-07-04 19:52:53 +00:00
if pointermap< > nil then
freeandnil( pointermap) ;
//cleanup the maps
inherited destroy;
end ;
//--------------TRescan----------------
procedure TRescan. flushResults;
begin
lastwrite: = GetTickCount;
outputfile. WriteBuffer( results. Memory^ , results. position) ;
results. position: = 0 ;
end ;
procedure TRescan. addPointer( p: PPointerRecord) ;
begin
inc( fcount) ;
results. WriteBuffer( p^ , pointerfilereader. entrysize) ;
if ( ( gettickcount- lastwrite) > 5 * 6 0 * 1 0 0 0 ) or ( results. Position> = ( 1 5 * 1 0 2 4 * 1 0 2 4 ) ) then
flushResults;
end ;
function TRescan. checkByte( p: PPointerRecord) : boolean ;
var error: boolean ;
a: ptruint;
v, v2: byte ;
begin
result : = false ;
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( a< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( a, pointerstart, pointerend) ) ) then
begin
v: = pointerfilereader. getByteFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a< > 0 then
begin
v2: = pointerfilereader. getByteFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( diffkind< > dkDontcare) then
2011-07-04 19:52:53 +00:00
begin
if diffkind= dkMustBeDifferent then
result : = v< > v2
else
result : = v= v2; //must be equal
end ;
end
else
result : = false ;
end ;
end ;
end ;
function TRescan. checkWord( p: PPointerRecord) : boolean ;
var error: boolean ;
a: ptruint;
v, v2: word ;
begin
result : = false ;
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( a< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( a, pointerstart, pointerend) ) ) then
begin
v: = pointerfilereader. getWordFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a< > 0 then
begin
v2: = pointerfilereader. getWordFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( diffkind< > dkDontCare) then
2011-07-04 19:52:53 +00:00
begin
if diffkind= dkMustBeDifferent then
result : = v< > v2
else
result : = v= v2; //must be equal
end ;
end
else
result : = false ;
end ;
end ;
end ;
function TRescan. checkDWord( p: PPointerRecord) : boolean ;
var error: boolean ;
a: ptruint;
v, v2: Dword;
begin
result : = false ;
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( a< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( a, pointerstart, pointerend) ) ) then
begin
v: = pointerfilereader. getDwordFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a< > 0 then
begin
v2: = pointerfilereader. getDwordFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( diffkind< > dkDontCare) then
2011-07-04 19:52:53 +00:00
begin
if diffkind= dkMustBeDifferent then
result : = v< > v2
else
result : = v= v2; //must be equal
end ;
end
else
result : = false ;
end ;
end ;
end ;
function TRescan. checkQWord( p: PPointerRecord) : boolean ;
var error: boolean ;
a: ptruint;
v, v2: Qword;
begin
result : = false ;
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( a< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( a, pointerstart, pointerend) ) ) then
begin
v: = pointerfilereader. getQwordFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a< > 0 then
begin
v2: = pointerfilereader. getQwordFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( diffkind< > dkDontCare) then
2011-07-04 19:52:53 +00:00
begin
if diffkind= dkMustBeDifferent then
result : = v< > v2
else
result : = v= v2; //must be equal
end ;
end
else
result : = false ;
end ;
end ;
end ;
function TRescan. checkSingle( p: PPointerRecord) : boolean ;
var error: boolean ;
a: ptruint;
v, v2: Single ;
begin
result : = false ;
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( a< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( a, pointerstart, pointerend) ) ) then
begin
v: = pointerfilereader. getSingleFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a< > 0 then
begin
v2: = pointerfilereader. getSingleFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( diffkind< > dkDontCare) then
2011-07-04 19:52:53 +00:00
begin
if diffkind= dkMustBeDifferent then
result : = v< > v2
else
result : = v= v2; //must be equal
end ;
end
else
result : = false ;
end ;
end ;
end ;
function TRescan. checkDouble( p: PPointerRecord) : boolean ;
var error: boolean ;
a: ptruint;
v, v2: Double ;
begin
result : = false ;
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( a< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( a, pointerstart, pointerend) ) ) then
begin
v: = pointerfilereader. getDoubleFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a< > 0 then
begin
v2: = pointerfilereader. getDoubleFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( diffkind< > dkDontCare) then
2011-07-04 19:52:53 +00:00
begin
if diffkind= dkMustBeDifferent then
result : = v< > v2
else
result : = v= v2; //must be equal
end ;
end
else
result : = false ;
end ;
end ;
end ;
function TRescan. checkPointer( p: PPointerRecord) : boolean ;
var error: boolean ;
a: ptruint;
v, v2: PtrUint;
begin
result : = false ;
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( a< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( a, pointerstart, pointerend) ) ) then
begin
v: = pointerfilereader. getPointerFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
a: = pointerfilereader. getAddressFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a< > 0 then
begin
v2: = pointerfilereader. getPointerFromAddress( a, error) ;
result : = not error;
2016-12-13 14:26:18 +01:00
if result and ( diffkind< > dkDontCare) then
2011-07-04 19:52:53 +00:00
begin
if diffkind= dkMustBeDifferent then
result : = v< > v2
else
result : = v= v2; //must be equal
end ;
end
else
result : = false ;
end ;
end ;
end ;
procedure TRescan. execute;
var i, j: integer ;
p: PPointerRecord;
s, s2: string ;
passed: boolean ;
index , len: integer ;
begin
try
for i: = 0 to pointerfilereader. count- 1 do
begin
2012-05-17 01:15:07 +00:00
p: = pointerfilereader. getPointerRec( i) ;
2011-07-04 19:52:53 +00:00
case vartype of
vtByte: passed: = checkByte( p) ;
vtWord: passed: = checkWord( p) ;
vtDword: passed: = checkDword( p) ;
vtQword: passed: = checkQword( p) ;
vtSingle: passed: = checkSingle( p) ;
vtDouble: passed: = checkDouble( p) ;
vtPointer: passed: = checkPointer( p) ;
vtString: //todo, move to checkString
begin
2013-04-09 23:08:58 +00:00
s: = pointerfilereader. getStringFromPointerRecord( p, address, shadow, shadowsize) ;
2011-07-04 19:52:53 +00:00
if ( address< > 0 ) and ( ( not mustbeinregion) or ( InRangeX( address, pointerstart, pointerend) ) ) then
begin
if s< > '' then
begin
if regex< > nil then
begin
//use the regex engine to test this string
index : = 0 ;
len: = 0 ;
passed: = RegExprPos( regex, pchar( s) , index , len) ;
if passed and mustbestart then
passed: = index = 0 ;
end
else
begin
passed: = true ;
if isstringscan then
begin //check if the first 4 characters are valid
for j: = 1 to min( length( s) , 4 ) do
if not ( s[ j] in [ # $20 .. # $7f ] ) then
begin
passed: = false ;
break;
end ;
end ;
end ;
end
else
passed: = false ;
2016-12-13 14:26:18 +01:00
if passed and ( address2< > 0 ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
s2: = pointerfilereader. getStringFromPointerRecord( p, address2, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
2016-12-13 14:26:18 +01:00
if ( s2< > '' ) then
begin
if ( diffkind< > dkDontCare) then
begin
if diffkind= dkMustBeDifferent then
passed: = s< > s2
else
passed: = s= s2;
end ;
end
2011-07-04 19:52:53 +00:00
else
2016-12-13 14:26:18 +01:00
passed: = false ;
2011-07-04 19:52:53 +00:00
if ( passed) and ( regex< > nil ) then
begin
index : = 0 ;
len: = 0 ;
2016-12-13 14:26:18 +01:00
passed: = RegExprPos( regex, pchar( s2) , index , len) ;
2011-07-04 19:52:53 +00:00
if passed and mustbestart then
passed: = index = 0 ;
end ;
end ;
end //else the address is not in the region
end ;
end ;
if passed then //add it
addPointer( p) ;
//check for forced exit
if terminated then exit;
fCurrentPosition: = i;
end ;
flushresults;
finally
if outputfile< > nil then
freeandnil( outputfile) ;
if results< > nil then
freeandnil( results) ;
if pointerfilereader< > nil then
freeandnil( pointerfilereader) ;
2016-12-13 14:26:18 +01:00
if deletefile( outputfilename) = false then
OutputDebugString( 'Failure deleting ' + outputfilename) ;
2011-07-04 19:52:53 +00:00
2016-12-13 14:26:18 +01:00
RenameFile( outputfilename+ '.temp' , outputfilename) ;
Queue( TfrmStringPointerScan( ownerFrmStringPointerScan) . scandone) ;
2011-07-04 19:52:53 +00:00
end ;
end ;
constructor TRescan. create( suspended: boolean ; address, address2: ptruint; mustbeinregion: boolean ; pointerstart, pointerend: ptruint; isstringscan, caseSensitive, mustbestart: boolean ; regExstr: string ; diffkind: TDiffkind; vartype: TVariableType; oldpointerfilename: string ; outputfilename: string ; ownerFrmStringPointerScan: TCustomForm) ;
var regflags: tregexprflags;
lw: integer ;
begin
self. vartype: = vartype;
self. isstringscan: = isstringscan;
self. mustbestart: = mustbestart;
self. diffkind: = diffkind;
self. oldpointerfilename: = oldpointerfilename;
pointerfilereader: = TPointerfileReader. create( oldpointerfilename) ;
pointerfilereader. vartype: = vartype;
self. address: = address;
self. address2: = address2;
self. mustbeinregion: = mustbeinregion;
self. pointerstart: = pointerstart;
self. pointerend: = pointerend;
self. outputfilename: = outputfilename;
self. ownerFrmStringPointerScan: = ownerFrmStringPointerScan;
pointerfilereader. clearPointercache;
if isstringscan then
begin
if regexstr< > '' then
begin
if CaseSensitive then
regflags: = [ ]
else
regflags: = [ ref_caseinsensitive] ;
self. regex: = GenerateRegExprEngine( pchar( regexstr) , regflags) ;
end ;
end ;
2012-05-17 01:15:07 +00:00
2016-12-13 14:26:18 +01:00
2012-05-17 01:15:07 +00:00
2011-07-04 19:52:53 +00:00
outputfile: = TFileStream. Create( outputfilename+ '.temp' , fmCreate or fmShareDenyNone) ;
outputfile. Free; //so it can be reopened by other processes
2012-05-17 01:15:07 +00:00
outputfile: = TFileStream. create( Outputfilename+ '.temp' , fmOpenWrite or fmShareDenyNone) ;
2011-07-04 19:52:53 +00:00
lastwrite: = GetTickCount;
lw: = pointerfilereader. levelWidth;
outputfile. WriteBuffer( lw, sizeof( lw) ) ;
results: = TMemoryStream. Create;
results. size: = 1 6 * 1 0 2 4 * 1 0 2 4 ;
inherited create( suspended) ;
end ;
destructor TRescan. destroy;
begin
if pointerfilereader< > nil then
freeandnil( pointerfilereader) ;
if outputfile< > nil then
freeandnil( outputfile) ;
if results< > nil then
freeandnil( results) ;
inherited destroy;
end ;
//--------------TScanner---------------
2013-04-09 23:08:58 +00:00
function TScanner. getPointerValue( address: ptruint; column: integer ) : ptruint;
2011-07-04 19:52:53 +00:00
{
returns 0 if not found
}
var
search: TPointerListEntry;
pe: TAvgLvlTreeNode;
r: PPointerListEntry;
begin
2013-04-09 23:08:58 +00:00
if column= 1 then
begin
2013-04-11 18:31:08 +00:00
if ( shadow< > 0 ) and ( InRangeQ( address, baseaddress, baseaddress+ shadowsize) ) then
address: = address+ ( shadow- baseaddress) ;
2013-04-09 23:08:58 +00:00
end
else
begin
2016-12-14 00:12:26 +01:00
if ( shadow2< > 0 ) and ( InRangeQ( address, baseaddress2, baseaddress2+ shadowsize2) ) then
2013-04-11 18:31:08 +00:00
address: = address+ ( shadow2- baseaddress2) ;
2013-04-09 23:08:58 +00:00
end ;
2011-07-04 19:52:53 +00:00
result : = 0 ;
2013-06-08 00:58:29 +00:00
mapRegionIfNeeded( address, structsize) ;
2011-07-04 19:52:53 +00:00
search. address: = address;
pe: = pointerlist. Find( @ search) ;
if pe< > nil then
begin
r: = pe. data;
result : = r. pointsto;
end ;
end ;
function TScanner. getFirstPointerEntry( base: ptruint) : PPointerListEntry;
var pe: TAvgLvlTreeNode;
search: TPointerListEntry;
r: PPointerListEntry;
begin
r: = nil ;
zeromemory( @ search, sizeof( search) ) ;
search. address: = base;
pe: = pointerlist. FindNearest( @ search) ;
if pe< > nil then
begin
r: = pe. data;
2013-06-08 00:58:29 +00:00
2011-07-04 19:52:53 +00:00
while ( r< > nil ) and ( r. address< base) do
r: = r. next;
end ;
result : = r;
end ;
procedure TScanner. fillPointers( base: ptruint; size: integer ) ;
2014-05-11 03:08:36 +00:00
var x: ptruint;
2011-07-04 19:52:53 +00:00
i: integer ;
p: PPointerListEntry;
pe, prev, next: TAvgLvlTreeNode;
2013-04-09 23:08:58 +00:00
a: ptruint;
2011-07-04 19:52:53 +00:00
begin
if readprocessmemory( processhandle, pointer( base) , fillpointerblock, size, x) then
begin
//walk through the array of dwords
2013-06-08 00:58:29 +00:00
if is64bittarget then
2011-07-04 19:52:53 +00:00
begin
2013-06-08 00:58:29 +00:00
for i: = 0 to ( x div 8 ) - 1 do
2013-04-09 23:08:58 +00:00
begin
2013-06-08 00:58:29 +00:00
a: = PPtrUintArray( fillpointerblock) [ i] ;
2013-04-09 23:08:58 +00:00
2013-06-08 00:58:29 +00:00
if shadow< > 0 then
begin
if InRangeQ( a, baseaddress, baseaddress+ shadowsize) then
a: = a+ ( shadow- baseaddress) ;
2011-07-04 19:52:53 +00:00
2013-06-08 00:58:29 +00:00
PPtrUintArray( fillpointerblock) [ i] : = a;
end ;
2011-07-04 19:52:53 +00:00
2013-06-08 00:58:29 +00:00
if ( a> $10000 ) and ( ( a mod 8 ) = 0 ) and ( isreadable( a) ) then //<-- isReadable can be sped up by caching in a tree
2011-07-04 19:52:53 +00:00
begin
2013-06-08 00:58:29 +00:00
p: = bma. alloc( sizeof( TPointerListEntry) ) ;
p. address: = base+ ( i* 8 ) ;
p. pointsto: = PPtrUintArray( fillpointerblock) [ i] ;
pe: = pointerlist. Add( p) ;
prev: = pointerlist. FindPrecessor( pe) ;
next: = pointerlist. FindSuccessor( pe) ;
if prev= nil then
p. previous: = nil
else
begin
p. previous: = prev. Data;
PPointerListEntry( prev. data) . next: = p;
end ;
if next= nil then
p. next: = nil
else
begin
p. next: = next. Data;
PPointerListEntry( next. data) . previous: = p;
end ;
2011-07-04 19:52:53 +00:00
end ;
2013-06-08 00:58:29 +00:00
end ;
end
else
begin
for i: = 0 to ( x div 4 ) - 1 do
begin
a: = PDwordArray( fillpointerblock) [ i] ;
2011-07-04 19:52:53 +00:00
2013-06-08 00:58:29 +00:00
if shadow< > 0 then
2011-07-04 19:52:53 +00:00
begin
2013-06-08 00:58:29 +00:00
if InRangeQ( a, baseaddress, baseaddress+ shadowsize) then
a: = a+ ( shadow- baseaddress) ;
PDwordArray( fillpointerblock) [ i] : = a;
2011-07-04 19:52:53 +00:00
end ;
2013-06-08 00:58:29 +00:00
if ( a> $10000 ) and ( ( a mod 4 ) = 0 ) and ( isreadable( a) ) then
begin
p: = bma. alloc( sizeof( TPointerListEntry) ) ;
p. address: = base+ ( i* 4 ) ;
p. pointsto: = PDwordArray( fillpointerblock) [ i] ;
// debug code
{ if pointerlist. Find( p) < > nil then
begin
// freemem(p);
2015-09-19 23:20:34 +02:00
messagebox( 0 , rsSPSUFUUUU, rsSPSUFUUUUU, 0 ) ;
2013-06-08 00:58:29 +00:00
continue;
end ; }
pe: = pointerlist. Add( p) ;
prev: = pointerlist. FindPrecessor( pe) ;
next: = pointerlist. FindSuccessor( pe) ;
2011-07-04 19:52:53 +00:00
2013-06-08 00:58:29 +00:00
if prev= nil then
p. previous: = nil
else
begin
p. previous: = prev. Data;
PPointerListEntry( prev. data) . next: = p;
end ;
if next= nil then
p. next: = nil
else
begin
p. next: = next. Data;
PPointerListEntry( next. data) . previous: = p;
end ;
end ;
2011-07-04 19:52:53 +00:00
end ;
end ;
2013-06-08 00:58:29 +00:00
2011-07-04 19:52:53 +00:00
end ;
end ;
procedure TScanner. mapRegionIfNeeded( blockaddress: ptruint; size: integer ) ;
var search: TMappedRegion;
result : TAvgLvlTreeNode;
map, oldmap: PMappedRegion;
prev, next: TAvgLvlTreeNode;
size2: integer ;
begin
search. baseaddress: = blockaddress;
result : = mappedregions. FindNearest( @ search) ;
if result< > nil then
map: = result . data
else
map: = nil ;
if ( map< > nil ) and ( not ( ( map. baseaddress< = blockaddress) and ( map. baseaddress+ map. size> = blockaddress) ) ) then
begin
//if the found map isn't a good enough match then check the next and previous one
if ( map. next< > nil ) and ( ( map. next. baseaddress< = blockaddress) and ( map. next. baseaddress+ map. next. size> = blockaddress) ) then
map: = map. next
else
if ( map. previous< > nil ) and ( ( map. previous. baseaddress< = blockaddress) and ( map. previous. baseaddress+ map. previous. size> = blockaddress) ) then
map: = map. previous
else
map: = nil ;
end ;
if ( map< > nil ) then
begin
//this map can contain or add the extra bytes needed
size2: = ( ( blockaddress+ size) - ( map. baseaddress+ map. size) ) ; //size now contains the total bytes that need to appended to this map
if size2> 0 then
begin
inc( blockaddress, size- size2) ;
size: = size2;
if ( map. next< > nil ) and ( map. next. baseaddress< blockaddress+ size) then
begin
//adjust the size so it won't overlap with the next map
size2: = map. next. baseaddress- ( map. baseaddress+ map. size) ;
end ;
if size2> 0 then
begin
fillPointers( map. baseaddress+ map. size, size2) ;
map. size: = map. size+ size2;
dec( size, size2) ;
end ;
if ( size> 0 ) then //this map has been filled as much as it can, try the next one
mapRegionIfNeeded( blockaddress, size) ;
end ; //else it's already fully mapped
end
else
begin
//create a new one
// map:=bma.alloc(sizeof(TMappedRegion));
//no bma, a map can be freed
map: = getmem( sizeof( TMappedRegion) ) ;
//ZeroMemory(map, sizeof(TMappedRegion));
map. baseaddress: = blockaddress;
result : = mappedregions. Add( map) ;
prev: = mappedregions. FindPrecessor( result ) ;
next: = mappedregions. FindSuccessor( result ) ;
if prev= nil then
map. previous: = nil
else
begin
map. previous: = prev. Data;
PMappedRegion( prev. data) . next: = map;
end ;
if next= nil then
map. next: = nil
else
begin
map. next: = next. Data;
PMappedRegion( next. data) . previous: = map;
end ;
map. size: = structsize;
//adjust the size so it won't overlap with the next block
if ( map. next< > nil ) and ( map. next. baseaddress< map. baseaddress+ map. size) then
map. size: = map. next. baseaddress- map. baseaddress;
fillPointers( map. baseaddress, map. size) ;
if ( map. next< > nil ) and ( map. next. baseaddress= map. baseaddress+ map. size) then
begin
//merge (delte old one)
result : = mappedregions. Find( map. next) ;
if result< > nil then
begin
oldmap: = result . data; //adjust the linked list
map. next: = oldmap. next;
if map. next< > nil then
map. next. previous: = map;
map. size: = map. size+ oldmap. size;
mappedregions. Remove( oldmap) ;
2018-06-12 20:23:45 +02:00
FreeMemAndNil( oldmap) ;
2011-07-04 19:52:53 +00:00
end ;
end ;
end ;
end ;
procedure TScanner. flushResults;
begin
lastwrite: = GetTickCount;
resultfile. WriteBuffer( results. Memory^ , results. position) ;
results. position: = 0 ;
end ;
2013-04-09 23:08:58 +00:00
function TScanner. getAddressFromPath( base : ptruint; column: integer ; level: integer ; const path: TPointerPath) : ptruint;
2011-07-04 19:52:53 +00:00
var x: ptruint;
i: integer ;
begin
result : = base+ path[ 0 ] ;
2016-12-14 00:12:26 +01:00
if column= 1 then
begin
if ( shadow< > 0 ) and ( InRangeQ( result , baseaddress, baseaddress+ shadowsize) ) then
result : = result + ( shadow- baseaddress) ;
end
else
begin
if ( shadow2< > 0 ) and ( InRangeQ( result , baseaddress2, baseaddress2+ shadowsize2) ) then
result : = result + ( shadow2- baseaddress2) ;
end ;
2011-07-04 19:52:53 +00:00
for i: = 1 to level do
begin
2013-04-09 23:08:58 +00:00
result : = getPointerValue( result , column) ;
2011-07-04 19:52:53 +00:00
if result = 0 then exit;
result : = result + path[ i] ;
end ;
end ;
function TScanner. comparePath( level: integer ; path: tpointerpath; stringsize: integer ) : boolean ;
var i: integer ;
x: ptruint;
address, address2: ptruint;
e: boolean ;
value, value2: pbytearray ;
2014-05-11 03:08:36 +00:00
br: ptruint;
2011-07-04 19:52:53 +00:00
begin
result : = false ;
2013-04-09 23:08:58 +00:00
address2: = getAddressFromPath( baseaddress2, 2 , level, path) ;
2011-07-04 19:52:53 +00:00
if address2= 0 then exit;
2013-04-09 23:08:58 +00:00
address: = getAddressFromPath( baseaddress, 1 , level, path) ;
2011-07-04 19:52:53 +00:00
if address= 0 then exit; //weird
//still here so both addresses are readable and not the same address
//
if valuemap< > nil then
begin
value: = valuemap. GetDataPtr( address) ;
if address2= address then //if they both have the same address assign th same map pointer
value2: = value
else
value2: = valuemap. GetDataPtr( address2) ;
end
else
begin
value: = nil ;
value2: = nil ;
end ;
//check address1
if value= nil then //not found, so read it manually
begin
if readprocessmemory( processhandle, pointer( address) , @ tempvariablebuffer[ 1 ] , variablesize, br) then
begin
tempvariablebuffer[ 0 ] : = 1 ; //mark as readable
value: = tempvariablebuffer;
if address2= address then
value2: = value;
end
else
tempvariablebuffer[ 0 ] : = 0 ; //mark as unreadable
if valuemap< > nil then //add it
valuemap. Add( address, tempvariablebuffer^ ) ;
end ;
if value= nil then exit; //unreadable
//check address2
if value2= nil then //not found, so read it manually
begin
if readprocessmemory( processhandle, pointer( address2) , @ tempvariablebuffer2[ 1 ] , variablesize, br) then
begin
tempvariablebuffer2[ 0 ] : = 1 ; //mark as readable
value2: = tempvariablebuffer2;
end
else
tempvariablebuffer2[ 0 ] : = 0 ; //mark as unreadable
if valuemap< > nil then //add it
valuemap. Add( address2, tempvariablebuffer2^ ) ;
end ;
if value2= nil then exit; //unreadable
if value[ 0 ] = 0 then exit; //marked as unreadable
if value2[ 0 ] = 0 then exit; // " " "
2016-12-13 14:26:18 +01:00
if diffkind= dkDontCare then exit( true ) ;
2011-07-04 19:52:53 +00:00
value: = @ value[ 1 ] ;
value2: = @ value2[ 1 ] ;
2016-12-13 14:26:18 +01:00
2011-07-04 19:52:53 +00:00
if address= address2 then
begin
result : = diffkind= dkMustBeSame;
exit;
end ;
//still here so not the same address
if isDataScan then
begin
result : = CompareMem( value, value2, variablesize) ;
if diffkind= dkMustBeDifferent then result : = not result ; //invert the result if it's a mustbedifferent type
end
else
begin
result : = CompareMem( value, value2, min( stringsize, variablesize) ) ;
if diffkind= dkMustBeDifferent then result : = not result ; //invert the result if it's a mustbedifferent type
end ;
end ;
2021-05-12 11:46:10 +02:00
function TScanner. addStringPath( level: integer ; path: tpointerpath; stringsize: integer ; unicode: longbool ) : boolean ;
2011-07-04 19:52:53 +00:00
begin
result : = false ;
2016-12-13 14:26:18 +01:00
if ( baseaddress2< > 0 ) and ( not comparePath( level, path, stringsize) ) then exit;
2011-07-04 19:52:53 +00:00
results. WriteBuffer( level, sizeof( level) ) ;
results. WriteBuffer( stringsize, sizeof( stringsize) ) ;
results. WriteBuffer( unicode, sizeof( unicode) ) ;
results. WriteBuffer( path[ 0 ] , sizeof( path[ 0 ] ) * ( maxlevel+ 1 ) ) ;
if ( getTickCount- lastwrite> 5 * 6 0 * 1 0 0 0 ) or ( results. Position> = ( 1 5 * 1 0 2 4 * 1 0 2 4 ) ) then
flushResults;
inc( count) ;
result : = true ;
end ;
procedure TScanner. handleBlock( blockaddress: ptruint; level: integer ; path: TPointerpath) ;
var
x: dword;
i: integer ;
newaddress: ptruint;
p: Pstringdata;
2013-06-08 00:58:29 +00:00
// block: pdwordarray;
2011-07-04 19:52:53 +00:00
pe: PPointerListEntry;
begin
if terminated then exit;
2013-04-11 18:31:08 +00:00
if shadow< > 0 then
begin
if inrangeq( blockaddress, baseaddress, baseaddress+ shadowsize) then
2016-12-14 00:12:26 +01:00
blockaddress: = blockaddress+ ( shadow- baseaddress) ;
2013-04-11 18:31:08 +00:00
end ;
2013-04-09 23:08:58 +00:00
2016-12-14 00:12:26 +01:00
2011-07-04 19:52:53 +00:00
if level> 0 then
begin
progress[ level- 1 ] : = path[ level- 1 ] ;
2013-04-09 23:08:58 +00:00
if ( diffkind< > dkDontCare) and ( getAddressFromPath( baseaddress2, 2 , level- 1 , path) = 0 ) then exit; //nothing to be found in this block
2011-07-04 19:52:53 +00:00
end ;
if isDataScan then
begin
i: = 0 ;
while i< structsize do
begin
path[ level] : = i;
if ( not mustbeinregion) or ( InRangeX( blockaddress+ i, pointerstart, pointerstop) ) then
addStringPath( level, path, - 1 , false ) ;
inc( i, alignment) ;
end ;
end
else
begin
//check which strings can be found in this block
p: = frmStringMap. findNearestString( blockaddress) ;
if p< > nil then
begin
while ( p< > nil ) and ( p. address< blockaddress+ structsize) do //found a string, add it
begin
if p. address> = blockaddress then
begin
path[ level] : = p. address- blockaddress;
if ( not mustbeinregion) or ( InRangeX( p. address, pointerstart, pointerstop) ) then
addStringPath( level, path, p. stringsize, p. unicode) ;
end
else
begin
path[ level] : = 0 ;
if ( not mustbeinregion) or ( InRangeX( blockaddress, pointerstart, pointerstop) ) then
addStringPath( level, path, p. stringsize- ( blockaddress- p. address) , p. unicode) ;
end ;
p: = p. next;
end ;
end ;
end ;
if level> = maxlevel then exit; //max level reached, no need to scan for pointers in this block
//still here, so go through this block looking for pointers
//see if this block already has it's pointers mapped, if not, map them
mapRegionIfNeeded( blockaddress, structsize) ;
pe: = getFirstPointerEntry( blockaddress) ;
while ( pe< > nil ) and ( pe. address< blockaddress+ structsize) do
begin
path[ level] : = pe. address- blockaddress;
handleBlock( pe. pointsto, level+ 1 , path) ;
pe: = pe. next;
end ;
end ;
procedure TScanner. execute;
var pointerpath: TPointerpath;
i: integer ;
begin
try
try
setlength( pointerpath, maxlevel+ 1 ) ; //maxlevel=0 means 1 offset
2013-06-08 00:58:29 +00:00
{ setlength( levelblock, maxlevel+ 1 ) ;
2011-07-04 19:52:53 +00:00
for i: = 0 to length( levelblock) - 1 do
getmem( levelblock[ i] , structsize) ; //one time alloc for each level so it can be reused without having to reallocate each recursion
2013-06-08 00:58:29 +00:00
}
2011-07-04 19:52:53 +00:00
2013-06-08 00:58:29 +00:00
getmem( fillpointerblock, max( 4 0 9 6 , structsize) ) ;
2011-07-04 19:52:53 +00:00
results: = TMemoryStream. Create;
results. Size: = 1 6 * 1 0 2 4 * 1 0 2 4 ;
results. Position: = 0 ;
handleBlock( baseaddress, 0 , pointerpath) ;
flushResults;
except
on e: exception do
2015-09-19 23:20:34 +02:00
messagebox( 0 , pchar( rsSPSUException+ e. Message ) , 'ps' , 0 ) ;
2011-07-04 19:52:53 +00:00
end ;
finally
//reached the end, tell the main thread that the scan is done
2016-12-13 14:26:18 +01:00
Queue( TfrmStringPointerScan( ownerFrmStringPointerScan) . scandone) ;
2011-07-04 19:52:53 +00:00
end ;
end ;
2013-04-09 23:08:58 +00:00
constructor TScanner. create( isDataScan, mustbeinregion: boolean ; alignment: integer ; pointerstart, pointerstop: ptruint; baseaddress: ptruint; shadow: ptruint; shadowsize: ptruint; baseaddress2: ptruint; shadow2: ptruint; shadowsize2: integer ; diffkind: TDiffkind; vartype: TVariableType; mapvalues: boolean ; structsize: integer ; maxlevel: integer ; mappedregions, pointerlist: TAvgLvlTree; bma: TBigMemoryAllocHandler; filename: string ; ownerFrmStringPointerScan: TCustomForm) ;
2011-07-04 19:52:53 +00:00
begin
2013-06-08 00:58:29 +00:00
self. is64bittarget: = processhandler. is64Bit;
2011-07-04 19:52:53 +00:00
self. baseaddress: = baseaddress;
2013-04-09 23:08:58 +00:00
self. shadow: = shadow;
self. shadowsize: = shadowsize;
2011-07-04 19:52:53 +00:00
self. baseaddress2: = baseaddress2;
2013-04-09 23:08:58 +00:00
self. shadow2: = shadow2;
self. shadowsize2: = shadowsize2;
2011-07-04 19:52:53 +00:00
self. diffkind: = diffkind;
self. vartype: = vartype;
self. structsize: = structsize;
self. maxlevel: = maxlevel;
self. mappedregions: = mappedregions;
self. pointerlist: = pointerlist;
self. bma: = bma;
self. isDataScan: = isDataScan;
self. alignment: = alignment;
self. pointerstart: = pointerstart;
self. pointerstop: = pointerstop;
self. mustbeinregion: = mustbeinregion;
self. ownerFrmStringPointerScan: = ownerFrmStringPointerScan;
2016-12-13 14:26:18 +01:00
//if diffkind<>dkDontCare then
2011-07-04 19:52:53 +00:00
begin
case vartype of
vtString: variablesize: = 8 ; //string
vtByte: variablesize: = 1 ; //byte
vtWord: variablesize: = 2 ; //word
vtDword: variablesize: = 4 ; //dword
vtQword: variablesize: = 8 ; //qword
vtSingle: variablesize: = 4 ; //single
vtDouble: variablesize: = 8 ; //double
vtPointer: variablesize: = processhandler. pointersize; //pointer
end ;
if mapvalues then
valuemap: = TMap. create( ituPtrSize, variablesize+ 1 ) ;
getmem( tempvariablebuffer, variablesize+ 1 ) ;
getmem( tempvariablebuffer2, variablesize+ 1 ) ;
end ;
resultfile: = TFileStream. Create( filename, fmCreate or fmShareDenyNone) ;
resultfile. Free;
resultfile: = TFileStream. Create( filename, fmOpenWrite or fmShareDenyNone) ; //make it accessible by other files
resultfile. Write( maxlevel, sizeof( maxlevel) ) ;
count: = 0 ;
setlength( progress, maxlevel+ 1 ) ;
inherited create( false ) ; //let's get started...
end ;
destructor TScanner. destroy;
var i: integer ;
begin
2013-06-08 00:58:29 +00:00
{ for i: = 0 to length( levelblock) - 1 do
freemem( levelblock[ i] ) ; }
2011-07-04 19:52:53 +00:00
if fillpointerblock< > nil then
2018-06-12 20:23:45 +02:00
FreeMemAndNil( fillpointerblock) ;
2011-07-04 19:52:53 +00:00
if resultfile< > nil then
freeandnil( resultfile) ;
if tempvariablebuffer< > nil then
2018-06-12 20:23:45 +02:00
FreeMemAndNil( tempvariablebuffer) ;
2011-07-04 19:52:53 +00:00
if tempvariablebuffer2< > nil then
2018-06-12 20:23:45 +02:00
FreeMemAndNil( tempvariablebuffer2) ;
2011-07-04 19:52:53 +00:00
if valuemap< > nil then
freeandnil( valuemap) ;
end ;
//----------------------------
function TfrmStringPointerScan. getStringFromPointer( address: ptruint; offsets: TDwordArray; level, bytesize: integer ; unicode: boolean ; var a: ptruint) : string ;
var i: integer ;
2014-05-11 03:08:36 +00:00
x: ptruint;
2011-07-04 19:52:53 +00:00
b: pchar ;
wb: pwidechar absolute b;
begin
2018-06-01 12:50:03 +02:00
result : = '' ;
2011-07-04 19:52:53 +00:00
a: = address+ offsets[ 0 ] ;
for i: = 1 to level do
begin
if readprocessmemory( processhandle, pointer( a) , @ a, processhandler. pointersize, x) then
begin
a: = a+ offsets[ i] ;
end
else
begin
result : = '???' ;
exit;
end ;
end ;
getmem( b, bytesize+ 2 ) ;
if ReadProcessMemory( processhandle, pointer( a) , b, bytesize, x) then
begin
b[ bytesize] : = #0 ;
b[ bytesize+ 1 ] : = #0 ;
if unicode then
result : = wb
else
result : = b;
end ;
2018-06-12 20:23:45 +02:00
FreeMemAndNil( b) ;
2011-07-04 19:52:53 +00:00
end ;
procedure TfrmStringPointerScan. ListView1CustomDrawItem( Sender: TCustomListView; Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean ) ;
begin
defaultdraw: = true ;
if item. data< > nil then
sender. Canvas. Font. Color: = clblue;
end ;
procedure TfrmStringPointerScan. ListView1Data( Sender: TObject; Item: TListItem) ;
var
i: integer ;
s, s2: string ;
a: ptruint;
2013-04-09 23:08:58 +00:00
a2: ptruint;
2011-07-04 19:52:53 +00:00
p: PPointerRecord;
begin
if pointerfilereader< > nil then
begin
item. data: = nil ;
a: = address;
2013-04-09 23:08:58 +00:00
s: = pointerfilereader. getStringAndAddress( item. index , a, p, shadow, shadowsize) ;
2013-06-06 17:50:54 +00:00
2013-04-11 18:31:08 +00:00
if ( shadow< > 0 ) and ( inrangeq( a, address, address+ shadowsize) ) then
2013-04-09 23:08:58 +00:00
a: = a+ ( shadow- address) ;
2011-07-04 19:52:53 +00:00
if p< > nil then
begin
item. caption: = inttohex( p. offset[ 0 ] , 1 ) ;
2021-05-12 11:46:10 +02:00
if length( p. offset) < p. level then
begin
item. subitems. add( 'bug' ) ;
//raise exception.create('Assertion error. p.offset is '+inttostr(length(p.offset))+' entries long and p.level is '+inttostr(p.level))
end
else
begin
for i: = 1 to p. level do
item. SubItems. add( inttohex( p. offset[ i] , 1 ) ) ;
for i: = p. level+ 1 to pointerfilereader. levelWidth do
item. SubItems. Add( '' ) ;
end ;
2011-07-04 19:52:53 +00:00
end ;
if a> 0 then
item. SubItems. Add( inttohex( a, 8 ) + ' : ' + s)
else
item. subitems. add( '??? : ???' ) ;
if hasAddress2 then
begin
a: = address2;
2013-04-09 23:08:58 +00:00
s2: = pointerfilereader. getStringAndAddress( item. index , a, p, shadow2, shadowsize2) ;
2011-07-04 19:52:53 +00:00
if a> 0 then
item. SubItems. Add( inttohex( a, 8 ) + ' : ' + s2)
else
item. subitems. add( '??? : ???' ) ;
if s< > s2 then
item. data: = pointer( 1 ) ;
end ;
end ;
end ;
procedure TfrmStringPointerScan. ListView1DblClick( Sender: TObject) ;
begin
if listview1. Selected< > nil then
2013-04-09 23:08:58 +00:00
MemoryBrowser. hexview. address: = pointerfilereader. getAddressFromPointerRecord( pointerfilereader. getPointerRec( listview1. Selected. Index ) , address, shadow, shadowsize2) ;
2011-07-04 19:52:53 +00:00
end ;
2016-12-13 23:34:10 +01:00
procedure TfrmStringPointerScan. miFindClick( Sender: TObject) ;
begin
finddialog1. execute;
end ;
2011-07-04 19:52:53 +00:00
procedure TfrmStringPointerScan. OpenPointerfile( filename: string ) ;
var lc: TListColumn;
i: integer ;
begin
cleanup;
pointerfilereader: = TPointerfileReader. Create( filename) ;
comboType. OnChange( comboType) ;
for i: = 0 to pointerfilereader. levelWidth do
begin
lc: = listview1. Columns. Add;
lc. MinWidth: = 2 ;
lc. Width: = 7 0 ;
2015-09-19 23:20:34 +02:00
lc. Caption: = rsSPSUOffset+ inttostr( i) ;
2011-07-04 19:52:53 +00:00
end ;
lc: = listview1. Columns. Add;
lc. MinWidth: = 2 ;
lc. Width: = 1 2 0 ;
2015-09-19 23:20:34 +02:00
lc. Caption: = rsSPSUAddress;
2011-07-04 19:52:53 +00:00
lc: = listview1. Columns. Add;
lc. MinWidth: = 2 ;
lc. Width: = 1 2 0 ;
2015-09-19 23:20:34 +02:00
lc. Caption: = rsSPSUAddress2;
2011-07-04 19:52:53 +00:00
lblExtra. enabled: = true ;
edtExtra. Enabled: = true ;
edtExtraChange( edtExtra) ;
2019-07-19 18:35:40 +02:00
listview1. items. count: = dword( min( dword( 1 0 0 0 0 0 0 ) , dword( pointerfilereader. count) ) ) ;
2011-07-04 19:52:53 +00:00
//setup rescan mode
2015-09-19 23:20:34 +02:00
btnScan. caption: = rsSPSURescan;
2012-05-12 13:41:36 +00:00
btnScan. tag: = 1 ;
2011-07-04 19:52:53 +00:00
end ;
2016-12-13 14:26:18 +01:00
procedure TfrmStringPointerScan. scanDone;
2011-07-04 19:52:53 +00:00
begin
2022-11-15 11:25:18 +01:00
scanning: = false ;
2011-07-04 19:52:53 +00:00
if scanner< > nil then
2015-09-19 23:20:34 +02:00
lblInfo. caption: = rsSPSUFound+ inttostr( scanner. count) ;
2011-07-04 19:52:53 +00:00
if rescanner< > nil then
2015-09-19 23:20:34 +02:00
lblInfo. caption: = rsSPSUFound+ inttostr( rescanner. count) ;
2011-07-04 19:52:53 +00:00
cleanup;
OpenPointerfile( SaveDialog1. FileName) ;
2015-09-19 23:20:34 +02:00
btnScan. caption: = rsSPSURescan;
2012-05-12 13:41:36 +00:00
btnScan. tag: = 1 ;
2013-04-11 18:31:08 +00:00
btnScan. Left: = panel1. clientwidth- btnScan. width- btnNewScan. left;
btnNewScan. visible: = true ;
btnNewScan. enabled: = true ;
2011-07-04 19:52:53 +00:00
if not rbDiffDontCare. checked then
comboType. itemindex: = comboCompareType. itemindex;
if pointerfilereader< > nil then
2015-09-19 23:20:34 +02:00
showmessage( rsSPSUScanDoneFound+ inttostr( pointerfilereader. count) )
2011-07-04 19:52:53 +00:00
else
2015-09-19 23:20:34 +02:00
raise exception. create( rsSPSUErrorduringScanNoScanresults) ;
2011-07-04 19:52:53 +00:00
//restore the gui
EnableGui;
end ;
function TfrmStringPointerScan. mapCompare( Tree: TAvgLvlTree; Data1, Data2: Pointer ) : integer ;
begin
result : = CompareValue( PMappedRegion( Data1) . baseaddress, PMappedRegion( Data2) . baseaddress) ;
end ;
function TfrmStringPointerScan. pointerCompare( Tree: TAvgLvlTree; Data1, Data2: Pointer ) : integer ;
begin
result : = CompareValue( PPointerListEntry( Data1) . address, PPointerListEntry( Data2) . address) ;
end ;
procedure tfrmStringPointerScan. cleanup;
var r: TAvgLvlTreeNode;
p, m: PMappedRegion;
begin
statusupdater. enabled: = false ;
progressbar1. Visible: = false ;
progressbar1. Position: = 0 ;
if rescanner< > nil then
begin
rescanner. terminate;
rescanner. waitfor;
freeandnil( rescanner) ;
end ;
if scanner< > nil then
begin
scanner. terminate;
scanner. WaitFor;
freeandnil( scanner) ;
end ;
listview1. items. count: = 0 ;
while listview1. ColumnCount> 0 do
listview1. Columns. Delete( 0 ) ;
if bma< > nil then
freeAndNil( bma) ;
if pointerlist< > nil then
freeandnil( pointerlist) ;
2012-06-05 13:14:43 +00:00
{
2011-07-04 19:52:53 +00:00
if pointerlistMemManager< > nil then
2012-06-05 13:14:43 +00:00
freeandnil( pointerlistMemManager) ; }
2011-07-04 19:52:53 +00:00
if pointerlist< > nil then
freeandnil( pointerlist) ;
if mappedRegions< > nil then
begin
r: = mappedRegions. FindLowest;
if r< > nil then
begin
m: = PMappedRegion( r. data) ;
while m< > nil do
begin
p: = m;
m: = m. next;
2018-06-12 20:23:45 +02:00
FreeMemAndNil( p) ;
2011-07-04 19:52:53 +00:00
end ;
end ;
freeandnil( mappedRegions) ;
end ;
if pointerfilereader< > nil then
freeandnil( pointerfilereader) ;
end ;
procedure TfrmStringPointerScan. btnScanClick( Sender: TObject) ;
var baseaddress: ptruint;
baseaddress2: ptruint;
structsize: integer ;
maxlevel: integer ;
alignsize: integer ;
pointerstart: ptruint;
pointerstop: ptruint;
diffkind: TDiffkind;
vartype: TVariableType;
2013-04-09 23:08:58 +00:00
shadow, shadow2: ptruint;
shadowsize, shadowsize2: ptruint;
2011-07-04 19:52:53 +00:00
oldpointerfile: string ;
begin
2016-12-13 14:26:18 +01:00
2012-05-17 01:15:07 +00:00
vartype: = vtPointer;
2022-11-15 11:25:18 +01:00
if ( scanner= nil ) and ( rescanner= nil ) and ( scanning= false ) then
2011-07-04 19:52:53 +00:00
begin
2013-04-09 23:08:58 +00:00
baseaddress: = symhandler. getAddressFromName( edtBase. text ) ;
2016-06-01 18:15:19 +02:00
baseaddress2: = 0 ;
2013-04-09 23:08:58 +00:00
2016-06-01 18:15:19 +02:00
shadow: = 0 ;
shadowsize: = 0 ;
shadow2: = 0 ;
shadowsize2: = 0 ;
pointerstart: = 0 ;
pointerstop: = 0 ;
alignsize: = 4 ;
2013-04-09 23:08:58 +00:00
if cbHasShadow. checked then
begin
shadow: = symhandler. getAddressFromName( edtShadowAddress. text ) ;
shadowsize: = strtoint( edtShadowSize. text ) ;
end ;
if ( ( shadow< > 0 ) and ( not isreadable( shadow) ) ) or
( ( shadow= 0 ) and ( not isreadable( baseaddress) ) ) then
2011-07-04 19:52:53 +00:00
raise exception. create( rsThisAddressIsNotAccessible) ;
structsize: = strtoint( edtStructsize. text ) ;
maxlevel: = strtoint( edtMaxLevel. text ) ;
if edtExtra. text = '' then
rbDiffDontCare. Checked: = true
else
2013-04-09 23:08:58 +00:00
begin
baseaddress2: = symhandler. getAddressFromName( edtExtra. text ) ;
if cbHasShadow2. checked then
begin
2016-06-01 18:15:19 +02:00
shadow2: = symhandler. getAddressFromName( edtShadowAddress2. text ) ;
shadowsize2: = strtoint( edtShadowSize2. text ) ;
2013-04-09 23:08:58 +00:00
end ;
end ;
2011-07-04 19:52:53 +00:00
if rbDatascan. checked then
begin
alignsize: = strtoint( edtAlignsize. text ) ;
if cbPointerInRange. checked then
begin
2016-03-29 23:06:02 +02:00
pointerstart: = symhandler. getAddressFromName( edtPointerStart. text ) ;
pointerstop: = symhandler. getAddressFromName( edtPointerStop. text ) ;
2011-07-04 19:52:53 +00:00
end ;
end ;
if savedialog1. execute then
begin
2016-12-13 14:26:18 +01:00
if pointerfilereader< > nil then
oldpointerfile: = pointerfilereader. filename
else
oldpointerfile: = '' ;
cleanup;
2011-07-04 19:52:53 +00:00
//we got till this point so everything is fine, disable the gui
2016-09-16 12:06:24 +02:00
disableGui;
2011-07-04 19:52:53 +00:00
if rbMustBeSame. checked then
diffkind: = dkMustBeSame
else
if rbMustBeDifferent. checked then
diffkind: = dkMustBeDifferent
else
diffkind: = dkDontCare;
2016-12-13 14:26:18 +01:00
if diffkind= dkDontCare then
vartype: = vtByte
else
case comboCompareType. itemindex of
0 : vartype: = vtString;
1 : vartype: = vtByte;
2 : vartype: = vtWord;
3 : vartype: = vtDword;
4 : vartype: = vtQword;
5 : vartype: = vtSingle;
6 : vartype: = vtDouble;
7 : vartype: = vtPointer;
2011-07-04 19:52:53 +00:00
end ;
2016-12-13 14:26:18 +01:00
if rbStringscan. checked then
vartype: = vtString;
2022-11-15 11:25:18 +01:00
btnScan. caption: = rsStop;
btnScan. enabled: = true ;
progressbar1. visible: = true ;
statusupdater. enabled: = true ;
scanning: = true ;
2012-06-05 13:14:43 +00:00
2022-11-15 11:25:18 +01:00
try
if btnScan. tag= 0 then //first scan
begin
2011-07-04 19:52:53 +00:00
2022-11-15 11:25:18 +01:00
mappedRegions: = TAvgLvlTree. CreateObjectCompare( mapCompare) ;
pointerlist: = TAvgLvlTree. CreateObjectCompare( pointerCompare) ;
2016-12-13 14:26:18 +01:00
2022-11-15 11:25:18 +01:00
bma: = TBigMemoryAllocHandler. create;
2016-12-13 14:26:18 +01:00
2022-11-15 11:25:18 +01:00
if rbStringscan. checked then
2016-12-13 14:26:18 +01:00
begin
2022-11-15 11:25:18 +01:00
vartype: = vtString;
2011-07-04 19:52:53 +00:00
2022-11-15 11:25:18 +01:00
if ( frmStringMap< > nil ) and ( cbReuseStringmap. checked= false ) then
freeandnil( frmStringMap) ;
2013-04-11 18:31:08 +00:00
2022-11-15 11:25:18 +01:00
if frmStringMap= nil then
begin
frmStringMap: = tfrmStringMap. Create( application) ;
2011-07-04 19:52:53 +00:00
2022-11-15 11:25:18 +01:00
//fill the stringmap
frmstringmap. cbRegExp. checked: = cbRegExp. checked;
frmstringmap. cbCaseSensitive. checked: = cbCaseSensitive. checked;
frmstringmap. cbMustBeStart. checked: = cbMustBeStart. checked;
frmstringmap. edtRegExp. text : = edtRegExp. text ;
2011-07-04 19:52:53 +00:00
2022-11-15 11:25:18 +01:00
frmstringmap. btnScan. click;
lblInfo. caption: = rsGeneratingStringmap;
lblInfo. Repaint;
end ;
2011-07-04 19:52:53 +00:00
2022-11-15 11:25:18 +01:00
while not frmstringmap. scanner. Finished do
begin
if scanning then
application. processmessages
else
begin
cleanup;
lblInfo. Caption: = '' ;
progressbar1. Visible: = false ;
btnScan. Caption: = rsScan;
enablegui;
exit;
end ;
end ;
end ;
lblInfo. caption: = rsGeneratedScanning;
2011-07-04 19:52:53 +00:00
2022-11-15 11:25:18 +01:00
//everything has been configured
2011-07-04 19:52:53 +00:00
2022-11-15 11:25:18 +01:00
scanner: = Tscanner. create( rbDatascan. checked, cbPointerInRange. checked, alignsize, pointerstart, pointerstop, baseAddress, shadow, shadowsize, baseaddress2, shadow2, shadowsize2, diffkind, vartype, cbMapPointerValues. checked, structsize, maxlevel, mappedRegions, pointerlist, bma, savedialog1. filename, self) ;
end
else
begin
//next scan aka Rescan
listview1. items. count: = 0 ;
rescanner: = trescan. create( false , address, address2, cbpointerinrange. checked, pointerstart, pointerstop, rbStringscan. checked, cbCaseSensitive. checked, cbMustBeStart. checked, edtRegExp. text , diffkind, vartype, oldpointerfile, savedialog1. filename , self) ;
end ;
except
scanning: = false ;
raise ;
2011-07-04 19:52:53 +00:00
end ;
end ;
end
else
begin
2022-11-15 11:25:18 +01:00
scanning: = false ;
2011-07-04 19:52:53 +00:00
btnScan. enabled: = false ;
2014-02-13 22:40:50 +00:00
btnScan. caption: = rsTerminating;
2011-07-04 19:52:53 +00:00
if scanner< > nil then
scanner. terminate;
if rescanner< > nil then
rescanner. terminate;
end ;
2013-04-11 18:31:08 +00:00
end ;
procedure TfrmStringPointerScan. cbHasShadowChange( Sender: TObject) ;
begin
2013-04-12 19:25:59 +00:00
2016-09-16 12:06:24 +02:00
edtShadowAddress. visible: = cbHasShadow. checked or cbHasShadow2. checked;
edtShadowAddress2. Visible: = edtShadowAddress. visible;
lblSize. visible: = edtShadowAddress. visible;
lblSize2. visible: = edtShadowAddress. visible;
edtShadowSize. visible: = edtShadowAddress. visible;
edtShadowSize2. visible: = edtShadowAddress. visible;
edtBaseChange( edtBase) ;
2013-04-12 19:25:59 +00:00
2016-09-16 12:06:24 +02:00
shadow: = 0 ;
2011-07-04 19:52:53 +00:00
end ;
procedure TfrmStringPointerScan. cbRegExpChange( Sender: TObject) ;
begin
2018-06-03 10:00:23 +02:00
cbCaseSensitive. enabled: = rbstringscan. checked and cbRegExp. enabled and cbRegExp. checked;
2016-09-16 12:06:24 +02:00
cbMustBeStart. enabled: = cbCaseSensitive. enabled;
edtRegExp. enabled: = cbCaseSensitive. enabled;
lblString. enabled: = cbCaseSensitive. enabled;
2011-07-04 19:52:53 +00:00
end ;
procedure TfrmStringPointerScan. cbPointerInRangeChange( Sender: TObject) ;
begin
edtPointerStart. enabled: = cbPointerInRange. checked;
edtPointerStop. enabled: = cbPointerInRange. checked;
lbland. enabled: = cbPointerInRange. checked;
end ;
2018-06-03 10:00:23 +02:00
procedure TfrmStringPointerScan. cbReuseStringmapChange( Sender: TObject) ;
begin
end ;
2011-07-04 19:52:53 +00:00
procedure TfrmStringPointerScan. comboTypeChange( Sender: TObject) ;
begin
if pointerfilereader< > nil then
begin
case comboType. itemindex of
0 : pointerfilereader. vartype: = vtString;
1 : pointerfilereader. vartype: = vtByte;
2 : pointerfilereader. vartype: = vtWord;
3 : pointerfilereader. vartype: = vtDword;
4 : pointerfilereader. vartype: = vtQword;
5 : pointerfilereader. vartype: = vtSingle;
6 : pointerfilereader. vartype: = vtDouble;
7 : pointerfilereader. vartype: = vtPointer;
end ;
listview1. Refresh;
end ;
end ;
procedure TfrmStringPointerScan. edtBaseChange( Sender: TObject) ;
2013-04-09 23:08:58 +00:00
var
err: boolean ;
2011-07-04 19:52:53 +00:00
begin
try
2013-04-09 23:08:58 +00:00
address: = symhandler. getAddressFromName( edtBase. text ) ;
shadow: = symhandler. getAddressFromName( edtShadowAddress. text , false , err) ;
if err then
shadow: = 0 ;
try
shadowsize: = strtoint( edtShadowSize. text ) ;
except
end ;
2013-04-12 19:25:59 +00:00
address2: = symhandler. getAddressFromName( edtBase. text , false , err) ;
if err then
address2: = 0 ;
shadow2: = symhandler. getAddressFromName( edtShadowAddress2. text , false , err) ;
if err then
shadow2: = 0 ;
try
shadowsize2: = strtoint( edtShadowSize. text ) ;
except
end ;
2011-07-04 19:52:53 +00:00
listview1. Refresh;
except
end ;
end ;
procedure TfrmStringPointerScan. edtExtraChange( Sender: TObject) ;
begin
hasAddress2: = edtExtra. Text< > '' ;
rbMustBeDifferent. enabled: = hasAddress2;
rbMustBeSame. enabled: = hasAddress2;
rbDiffDontCare. enabled: = hasAddress2;
try
2016-03-29 23:06:02 +02:00
address2: = symhandler. getAddressFromName( edtExtra. text ) ;
2011-07-04 19:52:53 +00:00
listview1. Refresh;
except
end ;
rbDiffDontCareChange( nil ) ;
end ;
2016-12-13 23:34:10 +01:00
procedure TfrmStringPointerScan. FindDialog1Find( Sender: TObject) ;
var
i, start: integer ;
s: string ;
FindText: string ;
cs: boolean ;
begin
FindText: = finddialog1. FindText;
if FindText= '' then exit;
miFindNext. enabled: = true ;
cs: = frMatchCase in finddialog1. Options;
if not cs then findtext: = uppercase( findtext) ;
for i: = listview1. ItemIndex+ 1 to listview1. Items. Count- 1 do
begin
s: = listview1. items[ i] . SubItems. Text ;
if not cs then s: = uppercase( s) ;
if pos( FindText, s) > 0 then
begin
listview1. ItemIndex: = i;
listview1. Items[ i] . MakeVisible( false ) ;
exit;
end ;
end ;
beep;
end ;
2011-07-04 19:52:53 +00:00
procedure TfrmStringPointerScan. FormClose( Sender: TObject; var CloseAction: TCloseAction) ;
begin
2022-11-15 11:25:18 +01:00
scanning: = false ;
2011-07-04 19:52:53 +00:00
cleanup;
end ;
2022-11-15 11:25:18 +01:00
procedure TfrmStringPointerScan. FormCreate( Sender: TObject) ;
begin
loadedFormPosition: = LoadFormPosition( self) ;
end ;
procedure TfrmStringPointerScan. FormDestroy( Sender: TObject) ;
begin
SaveFormPosition( self) ;
end ;
2013-04-11 18:31:08 +00:00
procedure TfrmStringPointerScan. FormShow( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
begin
2016-08-18 18:28:45 +02:00
//panel1.Constraints.MinHeight:=btnNewScan.Top+btnNewScan.Height+lblInfo.Height+4;
2013-04-11 18:31:08 +00:00
cbHasShadowChange( nil ) ;
2022-11-15 11:25:18 +01:00
AdjustEditBoxSize( edtPointerStart, canvas. GetTextWidth( ' XXXXXXXXXXXXXXXX ' ) ) ;
AdjustEditBoxSize( edtPointerStop, canvas. GetTextWidth( ' XXXXXXXXXXXXXXXX ' ) ) ;
AdjustEditBoxSize( edtBase, canvas. GetTextWidth( 'XXXXXXXXXXXXXXXX' ) ) ;
AdjustEditBoxSize( edtExtra, canvas. GetTextWidth( 'XXXXXXXXXXXXXXXX' ) ) ;
AdjustEditBoxSize( edtShadowAddress, canvas. GetTextWidth( 'XXXXXXXXXXXXXXXX' ) ) ;
AdjustEditBoxSize( edtShadowAddress2, canvas. GetTextWidth( 'XXXXXXXXXXXXXXXX' ) ) ;
AdjustEditBoxSize( edtShadowSize, canvas. GetTextWidth( '999999' ) ) ;
AdjustEditBoxSize( edtShadowSize2, canvas. GetTextWidth( '999999' ) ) ;
AdjustEditBoxSize( edtMaxLevel, canvas. GetTextWidth( ' 999 ' ) ) ;
AdjustEditBoxSize( edtStructsize, canvas. GetTextWidth( ' 999999 ' ) ) ;
AdjustComboboxSize( comboType, canvas) ;
if not loadedFormPosition then
begin
autosize: = false ;
clientheight: = panel9. top+ panel9. height+ lblInfo. height+ progressbar1. Height;
clientwidth: = panel1. width+ panel6. width* 2 + 1 6 + max( lblvds. width, comboType. Width) ;
end ;
2013-04-11 18:31:08 +00:00
end ;
2011-07-04 19:52:53 +00:00
2013-04-11 18:31:08 +00:00
procedure TfrmStringPointerScan. miNewScanClick( Sender: TObject) ;
begin
2014-02-13 22:40:50 +00:00
if MessageDlg( rsAreYouSureYo, mtConfirmation, mbYesNo, 0 ) = mryes then
2013-04-11 18:31:08 +00:00
begin
cleanup;
btnScan. tag: = 0 ;
2014-02-13 22:40:50 +00:00
btnScan. caption: = rsScan;
2013-04-11 18:31:08 +00:00
btnScan. Left: = ( panel1. ClientWidth div 2 ) - ( btnscan. Width div 2 ) ;
EnableGui;
edtMaxLevel. Enabled: = true ;
edtStructsize. enabled: = true ;
lblMaxLevel. enabled: = true ;
lblStructsize. enabled: = true ;
lblBaseRegion. enabled: = true ;
lblExtra. enabled: = true ;
edtBase. enabled: = true ;
edtExtra. enabled: = true ;
cbHasShadow. enabled: = true ;
cbHasShadow2. enabled: = true ;
edtShadowAddress. Enabled: = true ;
edtShadowAddress2. enabled: = true ;
edtShadowSize. enabled: = true ;
edtShadowSize2. enabled: = true ;
lblSize. enabled: = true ;
lblSize2. enabled: = true ;
btnNewScan. Visible: = false ;
end ;
2011-07-04 19:52:53 +00:00
end ;
2016-09-16 12:06:24 +02:00
procedure TfrmStringPointerScan. miOpenClick( Sender: TObject) ;
2011-07-04 19:52:53 +00:00
begin
if ( scanner= nil ) and ( rescanner= nil ) and OpenDialog1. Execute then
begin
OpenPointerfile( opendialog1. filename) ;
enablegui;
end ;
end ;
procedure TfrmStringPointerScan. MenuItem7Click( Sender: TObject) ;
begin
with Tfrmstringpointerscan. create( Application) do show;
end ;
procedure TfrmStringPointerScan. miClearCacheClick( Sender: TObject) ;
begin
if pointerfilereader< > nil then
pointerfilereader. clearPointerCache;
listview1. Refresh;
end ;
procedure TfrmStringPointerScan. MenuItem6Click( Sender: TObject) ;
begin
end ;
2016-12-13 23:34:10 +01:00
procedure TfrmStringPointerScan. Panel3Click( Sender: TObject) ;
begin
end ;
2011-07-04 19:52:53 +00:00
procedure TfrmStringPointerScan. rbDatascanChange( Sender: TObject) ;
begin
2016-09-16 12:06:24 +02:00
cbRegExp. enabled: = rbStringscan. enabled and rbStringscan. checked;
cbCaseSensitive. enabled: = cbRegExp. enabled and rbStringscan. checked and cbRegExp. checked;
cbMustBeStart. enabled: = cbCaseSensitive. enabled;
lblString. enabled: = cbCaseSensitive. enabled;
edtRegExp. enabled: = cbCaseSensitive. enabled;
2018-06-03 10:00:23 +02:00
cbReuseStringmap. enabled: = cbCaseSensitive. enabled;
2011-07-04 19:52:53 +00:00
2016-09-16 12:06:24 +02:00
lblAlign. enabled: = rbDatascan. enabled and rbDatascan. checked;
edtAlignsize. enabled: = lblAlign. enabled;
edtPointerStart. enabled: = cbPointerInRange. enabled and cbPointerInRange. checked;
lblAnd. enabled: = edtPointerStart. enabled;
edtPointerStop. enabled: = edtPointerStart. enabled;
2011-07-04 19:52:53 +00:00
end ;
procedure TfrmStringPointerScan. rbDiffDontCareChange( Sender: TObject) ;
begin
2016-09-16 12:06:24 +02:00
lblCompare. enabled: = rbDiffDontCare. enabled and ( rbDiffDontCare. checked = false ) ;
comboCompareType. enabled: = lblCompare. enabled;
cbMapPointerValues. Enabled: = comboCompareType. enabled;
2011-07-04 19:52:53 +00:00
end ;
procedure TfrmStringPointerScan. statusupdaterTimer( Sender: TObject) ;
var
scannerprogress: double ;
scannerTotal: double ;
i: integer ;
x: integer ;
begin
if ( rescanner< > nil ) and ( pointerfilereader< > nil ) then
progressbar1. position: = trunc( ( rescanner. currentPosition / pointerfilereader. count) * 1 0 0 0 ) ;
if scanner< > nil then
begin
2014-02-13 22:40:50 +00:00
lblInfo. caption: = Format( rsScanningFoun, [ inttostr( scanner. count) ] ) ;
2011-07-04 19:52:53 +00:00
scannerTotal: = power( scanner. structsize, scanner. maxlevel+ 1 ) ;
scannerprogress: = 0 ;
for i: = 0 to scanner. maxlevel- 1 do
begin
x: = scanner. progress[ i] ;
scannerprogress: = scannerprogress+ x* power( scanner. structsize, ( scanner. maxlevel+ 1 ) - i- 1 ) ;
end ;
progressbar1. position: = trunc( ( scannerprogress / scannertotal) * 1 0 0 0 ) ;
end
else
if rescanner< > nil then
2014-02-13 22:40:50 +00:00
lblinfo. caption: = Format( rsScanningFoun, [ inttostr( rescanner. count) ] )
2011-07-04 19:52:53 +00:00
end ;
2016-09-16 12:06:24 +02:00
procedure TfrmStringPointerScan. setGUIStateEnabled( state: boolean ) ;
2011-07-04 19:52:53 +00:00
begin
2016-09-16 12:06:24 +02:00
lblBaseRegion. enabled: = state;
lblExtra. enabled: = state;
2011-07-04 19:52:53 +00:00
2016-09-16 12:06:24 +02:00
cbPointerInRange. enabled: = state;
2011-07-04 19:52:53 +00:00
cbPointerInRange. OnChange( cbPointerInRange) ;
2016-09-16 12:06:24 +02:00
lblBaseRegion. enabled: = state;
lblExtra. enabled: = state;
lblvds. enabled: = state;
2011-07-04 19:52:53 +00:00
2016-09-16 12:06:24 +02:00
edtBase. enabled: = state;
edtExtra. enabled: = state;
2011-07-04 19:52:53 +00:00
edtExtra. OnChange( edtExtra) ; //makes the difftypes enabled or not
2016-09-16 12:06:24 +02:00
rbDatascan. enabled: = state;
rbStringscan. enabled: = state;
2011-07-04 19:52:53 +00:00
cbRegExpChange( rbStringscan) ;
2016-09-16 12:06:24 +02:00
comboType. enabled: = state;
2011-07-04 19:52:53 +00:00
rbDatascanChange( Nil ) ;
2016-09-16 12:06:24 +02:00
cbHasShadow. enabled: = state;
cbHasShadow2. enabled: = state;
2013-04-11 18:31:08 +00:00
2016-09-16 12:06:24 +02:00
edtShadowAddress. Enabled: = state;
edtShadowAddress2. enabled: = state;
2013-04-11 18:31:08 +00:00
2016-09-16 12:06:24 +02:00
edtShadowSize. enabled: = state;
edtShadowSize2. enabled: = state;
2013-04-11 18:31:08 +00:00
2016-09-16 12:06:24 +02:00
lblSize. enabled: = state;
lblSize2. enabled: = state;
2013-04-11 18:31:08 +00:00
2016-09-16 12:06:24 +02:00
btnScan. enabled: = state;
end ;
procedure TfrmStringPointerScan. disableGui;
begin
setGUIStateEnabled( false ) ;
end ;
procedure TfrmStringPointerScan. enableGui;
begin
setGUIStateEnabled( true ) ;
2011-07-04 19:52:53 +00:00
end ;
initialization
{$I frmStringPointerScanUnit.lrs}
end .