📄 pointerscannerfrm.pas.svn-base
字号:
if results.Size>25*1024*1024 then //bigger than 25mb
flushresults;
end;
procedure TReverseScanWorker.rscan(address:dword; level: integer);
{
scan through tht memory for a address that points in the region of level, if found, recursive call till level maxlevel
}
var p: ^byte;
pd: ^dword absolute p;
maxaddress: dword;
AddressMinusMaxStructSize: dword;
found: boolean;
i,j: integer;
createdworker: boolean;
mi: tmoduleinfo;
begin
if (level>=maxlevel) or
(symhandler.getmodulebyaddress(address,mi)) then //static address
begin
//reached max level, store this results entry
StorePath(level-1);
exit;
end;
if self.staticscanner.Terminated then
exit;
p:=vm.GetBuffer;
AddressMinusMaxStructSize:=address-structsize;
maxaddress:=dword(p)+vm.GetBufferSize;
while dword(p)<maxaddress do
begin
if (pd^<=address) and
(pd^>AddressMinusMaxStructSize) then
begin
//found one
found:=true;
tempresults[level]:=vm.PointerToAddress(p);
//check if I can offload it to another thread
if staticscanner.isdone and ((level+1)<maxlevel) then //best only do it when staticscanner is done
begin
createdworker:=false;
reverseScanCS.Enter;
//scan the worker thread array for a idle one, if found use it
for i:=0 to length(staticscanner.reversescanners)-1 do
begin
if staticscanner.reversescanners[i].isdone then
begin
staticscanner.reversescanners[i].isdone:=false;
staticscanner.reversescanners[i].maxlevel:=maxlevel;
staticscanner.reversescanners[i].addresstofind:=addresstofind; //in case it wasn't set yet...
staticscanner.reversescanners[i].startaddress:=vm.PointerToAddress(p);
for j:=0 to maxlevel-1 do
staticscanner.reversescanners[i].tempresults[j]:=tempresults[j]; //copy results
staticscanner.reversescanners[i].startlevel:=level;
staticscanner.reversescanners[i].structsize:=structsize;
staticscanner.reversescanners[i].startworking.SetEvent;
break;
end;
end;
reverseScanCS.Leave;
if createdworker then continue; //stop processing the rest of this routine and continue scanning
end;
rscan(tempresults[level],level+1);
//messagebox(0,pchar(inttohex(address,8)),'',0);
end;
if alligned then
inc(pd) //dword pointer+1
else
inc(p); //byte pointer+1
end;
if (not found) and (not staticonly) then
begin
//nothing was found, let's just say this is the final level and store it...
StorePath(level-1);
end;
end;
procedure TStaticScanner.reversescan;
{
Do a reverse pointer scan
The level0 seperately so it's easier to spawn of the child threads.
Of course, if there's only 1 top level entry it only spawns 1 thread... but someday
I may update it to spawn the threads inside a recursive function... (hmm, or not)
}
var p: ^byte;
pd: ^dword absolute p;
maxaddress: dword;
automaticAddressMinusMaxStructSize: dword;
results: array of dword;
i,j: integer;
alldone: boolean;
begin
//scan the buffer
fcount:=0; //debug counter to 0
scount:=0;
maxlevel:=maxlevel-1; //adjustment for this kind of scan
setlength(results,maxlevel);
p:=vm.GetBuffer;
automaticAddressMinusMaxStructSize:=automaticAddress-sz;
maxaddress:=dword(p)+vm.GetBufferSize;
lastaddress:=pointer(maxaddress); //variable for progressbar calculation
currentaddress:=p;
firstaddress:=p;
j:=0;
start:=gettickcount;
while dword(p)<maxaddress do
begin
if (pd^<=automaticaddress) and
(pd^>automaticAddressMinusMaxStructSize) then
begin
//found one
//activate a worker thread to do this path
reversescansemaphore.Aquire; //aquire here, the thread will release it
//quick check if we didn't wait to long and the user clicked terminate
if terminated then
begin
reversescansemaphore.release;
break;
end;
//find an inactive thread
for i:=0 to length(reversescanners)-1 do
begin
if reversescanners[i].isdone then
begin
reversescanners[i].isdone:=false;
reversescanners[i].maxlevel:=maxlevel;
reversescanners[i].startaddress:=vm.PointerToAddress(p);
reversescanners[i].addresstofind:=self.automaticaddress;
reversescanners[i].tempresults[0]:=reversescanners[i].startaddress;
reversescanners[i].startlevel:=0;
reversescanners[i].structsize:=sz;
reversescanners[i].startworking.SetEvent;
break;
end;
end;
//results[0]:=vm.PointerToAddress(p);
//rscan(results[0],1,results);
//messagebox(0,pchar(inttohex(address,8)),'',0);
end;
if unalligned then
inc(p) //byte pointer+1
else
inc(pd); //dword pointer+1
currentaddress:=p;
end;
isdone:=true;
alldone:=false;
//wait till all threads are in isdone state
while (not alldone) do
begin
sleep(500);
alldone:=true;
//no need for a CS here since it's only a read, and even when a new thread is being made, the creator also has the isdone boolean to false
for i:=0 to length(reversescanners)-1 do
begin
if not reversescanners[i].isdone then
begin
alldone:=false;
break;
end;
end;
end;
setlength(filenames,length(reversescanners));
for i:=0 to length(reversescanners)-1 do
begin
reversescanners[i].stop:=true;
reversescanners[i].startworking.SetEvent; //run it in case it was waiting
reversescanners[i].WaitFor; //wait till this thread has terminated because the main thread has terminated
reversescanners[i].flushresults; //write results to disk
filenames[i]:=reversescanners[i].filename;
reversescanners[i].Free;
end;
postmessage(frmpointerscanner.Handle,staticscanner_done,0,0);
terminate;
freeandnil(reversescansemaphore);
stop:=gettickcount;
messagebox(0,pchar('Delta Tickcount='+inttostr(stop-start)+' found='+inttostr(fcount)),'',mb_ok);
end;
procedure TStaticScanner.execute;
var
i,j,k: integer;
x,opcode:string;
t:dword;
hexcount,hexstart: integer;
isstruct: boolean;
isstatic: boolean;
found: boolean;
mbi: _MEMORY_BASIC_INFORMATION;
tn,tempnode: ttreenode;
th: TDissectData;
lastnode: ttreenode;
oldshowsymbols: boolean;
oldshowmodules: boolean;
bitcount: integer;
scanregions: tmemoryregions;
currentregion: integer;
maxpos: dword;
dw: byte;
begin
if terminated then exit;
if (vm<>nil) and (not reuse) then
freeandnil(vm); //free so the next piece of code will do a whole new scan
if vm=nil then
begin
phase:=1;
progressbar.Position:=0;
vm:=tvirtualmemory.Create(filterstart,filterstop,progressbar);
end;
phase:=2;
progressbar.Position:=0;
currentpos:=pointer(start);
i:=0;
if reverse then
begin
reverseScanCS:=tcriticalsection.Create;
try
reverseScanSemaphore:=tsemaphore.create(threadcount);
setlength(reversescanners,threadcount);
for i:=0 to threadcount-1 do
begin
reversescanners[i]:=TReverseScanWorker.Create(true);
reversescanners[i].Priority:=scannerpriority;
reversescanners[i].staticscanner:=self;
setlength(reversescanners[i].tempresults,maxlevel);
setlength(reversescanners[i].offsetlist,maxlevel);
reversescanners[i].staticonly:=staticonly;
reversescanners[i].alligned:=not self.unalligned;
reversescanners[i].Resume;
end;
reversescan;
finally
reverseScanCS.Free;
end;
end
else
begin
Method2semaphore:=tsemaphore.create(threadcount);
setlength(method2scanners,threadcount);
for i:=0 to threadcount-1 do
begin
method2scanners[i]:=tmethod2scanner.create(false);
method2scanners[i].Priority:=scannerpriority;
end;
try
//create some regions it should scan
setlength(scanregions,0);
if not unallignedbase then
begin
if (start mod 4)>0 then
start:=start+(4-(start mod 4));
end;
symhandler.fillMemoryRegionsWithModuleData(scanregions,start,stop-start);
if length(scanregions)=0 then
begin
//no memory found (e.g failed to open process)
setlength(scanregions,1);
scanregions[0].BaseAddress:=start;
scanregions[0].MemorySize:=stop-start;
scanregions[0].IsChild:=false;
scanregions[0].startaddress:=nil;
end;
currentregion:=0;
currentpos:=pointer(scanregions[currentregion].BaseAddress);
progressbar.Position:=0;
progressbar.Max:=stop-start;
maxpos:=scanregions[currentregion].BaseAddress+scanregions[currentregion].MemorySize-4;
while (not terminated) and (dword(currentpos)<=stop) do
begin
isstatic:=false;
try
if ((pdword(vm.AddressToPointer(dword(currentpos)))^ mod 4)=0) or (unalligned) then //unaligned check after the first one so it includes a readable check
isstatic:=true;
if (writableonly) and ((dword(currentpos) mod 4096)=0) then
begin
if vm.isbadwriteptr(currentpos,4) then
begin
inc(pbyte(currentpos),4096);
isstatic:=false;
if dword(currentpos)>=maxpos then
begin
inc(currentregion);
if currentregion=length(scanregions) then break; //no more regions
currentpos:=pointer(scanregions[currentregion].BaseAddress);
maxpos:=scanregions[currentregion].BaseAddress+scanregions[currentregion].MemorySize-4;
end;
inc(i);
i:=i mod 40;
if i=0 then progressbar.position:=(dword(currentpos)-start);
continue;
end;
end;
if isstatic and (pdword(vm.AddressToPointer(dword(currentpos)))^>=filterstart) and (pdword(vm.AddressToPointer(dword(currentpos)))^<=filterstop) then
begin
method2scan(dword(currentpos));
end;
inc(i);
i:=i mod 40;
if i=0 then progressbar.position:=(dword(currentpos)-start);
if unallignedbase then
inc(pbyte(currentpos))
else
inc(pbyte(currentpos),4);
if dword(currentpos)>=maxpos then
begin
inc(currentregion);
if currentregion=length(scanregions) then break; //no more regions
currentpos:=pointer(scanregions[currentregion].BaseAddress);
maxpos:=scanregions[currentregion].BaseAddress+scanregions[currentregion].MemorySize-4;
end;
except
inc(currentregion);
if currentregion=length(scanregions) then break; //no more regions
currentpos:=pointer(scanregions[currentregion].BaseAddress);
maxpos:=scanregions[currentregion].BaseAddress+scanregions[currentregion].MemorySize-4;
end;
end;
//done
finally
setlength(filenames,length(method2scanners));
for i:=0 to length(method2scanners)-1 do
begin
method2scanners[i].stop:=true;
method2scanners[i].startworking.SetEvent; //run it in case it was waiting
method2scanners[i].WaitFor; //wait till this thread has terminated because the main thread has terminated
method2scanners[i].flushresults;
filenames[i]:=method2scanners[i].filename; //save the filename
method2scanners[i].Free;
end;
postmessage(frmpointerscanner.Handle,staticscanner_done,0,0);
terminate;
freeandnil(Method2semaphore);
end;
end;
if (vm<>nil) and (not reuse) then
freeandnil(vm);
end;
destructor TStaticscanner.destroy;
begin
terminate;
waitfor;
inherited destroy;
end;
//---------------------------------main--------------------------
procedure Tfrmpointerscanner.Method3Fastspeedandaveragememoryusage1Click(
Sender: TObject);
var
i: integer;
begin
start:=now;
if frmpointerscannersettings=nil then
frmpointerscannersettings:=tfrmpointerscannersettings.create(nil);
if frmpointerscannersettings.Visible then exit; //already open, so no need to make again
if vm<>nil then
frmpointerscannersettings.cbreuse.Caption:='Reuse memory copy from previous scan';
if frmpointerscannersettings.Showmodal=mrok then
begin
treeview2.Visible:=false;
panel2.Visible:=false;
open1.Enabled:=false;
new1.enabled:=false;
save1.Enabled:=false;
rescanmemory1.Enabled:=false;
incorrectresult:=0;
continued:=0;
pointersfound:=0;
label1.Caption:='Matches found:';
label2.Left:=label1.Left+label1.Width+5;
timer2.Enabled:=true;
treenodeswithchildrenpos:=0;
matchednodespos:=0;
//free the old critical section's
for i:=0 to length(dissectedpointersLevelMREWS)-1 do
dissectedpointersLevelMREWS[i].Free;
setlength(dissectedpointersLevelpos,frmpointerscannersettings.maxlevel+1);
setlength(dissectedpointersLevel,frmpointerscannersettings.maxlevel+1);
setlength(dissectedpointersLevelMREWS,frmpointerscannersettings.maxlevel+1);
for i:=0 to length(dissectedpointersLevelpos)-1 do
dissectedpointersLevelpos[i]:=0;
for i:=0 to length(dissectedpointersLevelMREWS)-1 do
dissectedpointersLevelMREWS[i]:=TMultiReadExclusiveWriteSynchronizer.create;
for i:=0 to length(dissectedpointerslevel)-1 do
setlength(dissectedpointerslevel[i],1024*1024); //1mb default
//possible paths cleaning and reinitialize
for i:=0 to length(possiblepathslevelMREWS)-1 do
possiblepathslevelMREWS[i].Free;
setlength(possiblepathslevelpos,frmpointerscannersettings.maxlevel+1);
setlength(possiblepathslevel,frmpointerscannersettings.maxlevel+1);
setlength(possiblepathslevelMREWS,frmpointerscannersettings.maxlevel+1);
for i:=0 to length(possiblepathslevelpos)-1 do
possiblepathslevelpos[i]:=0;
for i:=0 to length(possiblepathslevelMREWS)-1 do
possiblepathslevelMREWS[i]:=TMultiReadExclusiveWriteSynchronizer.create;
for i:=0 to length(possiblepathslevel)-1 do
setlength(possiblepathslevel[i],1024*1024); //1mb default
if staticscanner<>nil then
begin
staticscanner.free;
staticscanner:=nil;
end;
//default scan
staticscanner:=TStaticscanner.Create(true);
try
staticscanner.reverse:=frmpointerscannersettings.rbreverse.checked;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -