procedure TScanController.firstScan;
{
first scan will gather the memory regions, open the files, and spawn scanners
}
var
currentBaseAddress: dword;
mbi : TMemoryBasicInformation;
i,j: integer;
Blocksize: dword;
currentblocksize: dword;
totalProcessMemorySize: dword;
leftfromprevious: dword;
datatype: string[6];
begin
threadcount:=GetCPUCount;
totalProcessMemorySize:=0;
{
ScanController plan:
spawn idle scanner threads , ammount=maxthreadcount in settings
enumerate all regions and split up into jobs for the threads
if scanoption=soUnknownValue make a buffer big enough to hold all the memory, and give the threads the startbase where in the buffer their first region will start
start scanner threads
}
//determine the size in bytes for this variable. If one is provided.
//also fill in the fastscan alignment as well
//else it's ignored and never used
setlength(memRegion,16);
memRegionPos:=0;
if (startaddress mod 8)>0 then //align on a 8 byte base
startaddress:=startaddress-(startaddress mod 8);
currentBaseAddress:=startaddress;
while (Virtualqueryex(processhandle,pointer(currentBaseAddress),mbi,sizeof(mbi))<>0) and (currentBaseAddress<stopaddress) and ((currentBaseAddress+mbi.RegionSize)>currentBaseAddress) do //last check is done to see if it wasn't a 64-bit overflow.
begin
if (not (not scan_mem_private and (mbi.type_9=mem_private))) and (not (not scan_mem_image and (mbi.type_9=mem_image))) and (not (not scan_mem_mapped and (mbi.type_9=mem_mapped))) and (mbi.State=mem_commit) and ((mbi.Protect and page_guard)=0) and ((mbi.protect and page_noaccess)=0) then //look if it is commited
begin
if //no cache check
(Skip_PAGE_NOCACHE and ((mbi.AllocationProtect and PAGE_NOCACHE)=PAGE_NOCACHE))
or
//no readonly check
((not readonly) and (not ((((mbi.AllocationProtect) and (page_readonly or page_execute_read))=0) and
(((mbi.Protect) and (page_readonly or PAGE_EXECUTE_READ))=0))))
then
begin
//skip it
currentBaseAddress:=dword(mbi.BaseAddress)+mbi.RegionSize;
continue;
end;
//still here, so valid
try
if memRegionPos>0 then
begin
//check if it can be appended to the previous region
if memRegion[memRegionPos-1].BaseAddress+memRegion[memRegionPos].MemorySize=dword(mbi.baseaddress) then //yes, append
begin
//yes, so append
memRegion[memRegionPos-1].MemorySize:=memRegion[memRegionPos-1].MemorySize+mbi.RegionSize;
continue;
end;
end;
//still here, so a new region
memRegion[memRegionPos].BaseAddress:=dword(mbi.baseaddress); //just remember this location
memRegion[memRegionPos].MemorySize:=mbi.RegionSize;
memRegion[memRegionPos].startaddress:=pointer(totalProcessMemorySize); //starts from 0, for unknown scans
inc(memRegionPos);
if (memRegionPos mod 16)=0 then //add another 16 to it
setlength(memRegion,length(memRegion)+16);
finally
inc(totalProcessMemorySize,mbi.RegionSize); //add this size to the total
end;
end;
currentBaseAddress:=dword(mbi.baseaddress)+mbi.RegionSize;
end;
totalAddresses:=totalProcessMemorySize;
if memRegionPos=0 then raise exception.Create('No readable memory found');
//if soUnknown, make a buffer where it can store all the 'previous' memory
if scanOption=soUnknownValue then
begin
//extra check to make sure the previous scan was cleared
if OwningMemScan.previousMemoryBuffer<>nil then virtualfree(OwningMemScan.previousMemoryBuffer,0,MEM_RELEASE);
OwningMemScan.previousMemoryBuffer:=VirtualAlloc(nil,totalProcessMemorySize, MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); //top down to try to prevent memory fragmentation
end;
//split up into seperate workloads
Blocksize:=totalProcessMemorySize div threadcount;
Blocksize:=blocksize-(blocksize mod 4096); //lastblock gets the missing bytes
scannersCS.Enter; //block access by the mainthread on the scanners object, could scanner[14] has not yet been created when doing a progress request
try
setlength(scanners,threadcount);
j:=0; //start at memregion 0
leftfromprevious:=0;
for i:=0 to threadcount-1 do
begin
scanners:=tscanner.Create(true);
scanners.scannernr:=i;
scanners.OwningScanController:=self;
scanners._startregion:=j;
scanners.startaddress:=memRegion[j].BaseAddress+leftfromprevious;
scanners.maxregionsize:=0;
if i=(threadcount-1) then
begin
scanners.stopaddress:=stopaddress;
scanners._stopregion:=memregionpos-1;
if scanOption<>soUnknownValue then
begin
//define maxregionsize
while j<memregionpos do
begin
if scanners.maxregionsize<memregion[j].MemorySize then
scanners.maxregionsize:=memregion[j].MemorySize;
inc(j);
end;
end;
end
else
begin
currentblocksize:=0;
inc(currentblocksize,memregion[j].MemorySize+leftfromprevious);
inc(j);
while (currentblocksize<blocksize) and (j<memregionpos) do
begin
if scanOption<>soUnknownValue then //not a unknown initial value scan, so it doesn't need overlap
begin
if scanners.maxregionsize<memregion[j].MemorySize+variablesize then
scanners.maxregionsize:=memregion[j].MemorySize+variablesize;
end;
inc(currentblocksize,memregion[j].MemorySize);
inc(j);
end;
dec(j);
scanners._stopregion:=j;
scanners.stopaddress:=memregion[j].BaseAddress+memregion[j].MemorySize;
leftfromprevious:=currentblocksize-blocksize;
dec(scanners.stopaddress,leftfromprevious);
if leftfromprevious<=0 then inc(j); //nothing left in this region
end;
if scanners.maxregionsize>buffersize then
scanners.maxregionsize:=buffersize;
//now configure the scanner thread with the same info this thread got, with some extra info
scanners.scanType:=scanType; //stFirstScan obviously
scanners.scanoption:=scanoption;
scanners.variableType:=VariableType;
scanners.roundingtype:=roundingtype;
scanners.fastscan:=fastscan;
scanners.scanValue1:=scanvalue1; //usual scanvalue
scanners.scanValue2:=scanValue2; //2nd value for between scan
scanners.readonly:=readonly;
scanners.unicode:=unicode;
scanners.caseSensitive:=caseSensitive;
scanners.hexadecimal:=hexadecimal;
scanners.binaryStringAsDecimal:=binaryStringAsDecimal;
scanners.fastscanalignsize:=fastscanalignsize;
scanners.variablesize:=variablesize;
scanners.customscanscript:=customscanscript;
scanners.customscantype:=customscantype;
if i=0 then //first thread gets the header part
begin
if scanoption=soUnknownValue then
datatype:='REGION'
else
datatype:='NORMAL';
scanners.AddressFile.WriteBuffer(datatype,sizeof(datatype));
end;
end;
finally
scannersCS.Leave;
end;
//all threads are created, so start them
for i:=0 to length(scanners)-1 do
scanners.Resume;
//prepare the result files
try
OwningMemScan.found:=0;
//and now we wait
for i:=0 to threadcount-1 do
begin
repeat
WaitForSingleObject(scanners.Handle,25); //25ms, an eternity for a cpu
synchronize(updategui);
until scanners.isdone;
if scanners.haserror then
begin
OwningMemScan.found:=0;
haserror:=true;
errorstring:=scanners.errorstring;
break;
end;
inc(OwningMemScan.found,scanners.totalfound);
end;
synchronize(updategui);
if haserror then
begin
OwningMemScan.found:=0;
//synchronize(errorpopup);
exit;
end;
//all threads are done
//combine all results and write them too the AddressFile and MemoryFile
if scanOption=soUnknownValue then
begin
//read the scanner memregions and adapt this memregion to it
//first find out how many regions it got
memRegionPos:=0;
for i:=0 to threadcount-1 do
inc(memRegionPos,scanners.memRegionPos);
setlength(OwningMemScan.memRegion,memRegionPos); //setting the size accordingly (max, can end up smaller due to appending)
OwningMemScan.memRegionPos:=0;
for i:=0 to threadcount-1 do
begin
for j:=0 to scanners.memRegionPos-1 do
begin
inc(OwningMemScan.found,scanners.memregions[j].MemorySize);
if OwningMemScan.memregionpos>0 then
begin
if OwningMemScan.memregion[OwningMemScan.memregionpos-1].BaseAddress+OwningMemScan.memregion[OwningMemScan.memregionpos-1].MemorySize=scanners.memregions[j].BaseAddress then
begin
//append
inc(OwningMemScan.memregion[OwningMemScan.memregionpos-1].MemorySize,scanners.memregions[j].MemorySize);
continue;
end;
end;
//new one
OwningMemScan.memregion[OwningMemScan.memregionpos]:=scanners.memregions[j];
inc(OwningMemScan.memregionpos);
end;
end;
if fastscan then //divide by alignsize of fastscan
OwningMemScan.found:=OwningMemScan.found div fastscanalignsize;
savescannerresults:=true;
end
else
begin
savescannerresults:=true;
end;
finally
end;
end;