cheat-engine/Cheat Engine/frmMemoryAllocHandlerUnit.pas

1032 lines
27 KiB
ObjectPascal
Executable file

unit frmMemoryAllocHandlerUnit;
{$MODE Delphi}
{
ZwVirtualAllocEx
}
interface
uses
{$ifdef darwin}
macport,
{$endif}
{$ifdef windows}
windows,
{$endif}
LCLIntf, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, symbolhandler, symbolhandlerstructs, CEFuncProc,NewKernelHandler,
autoassembler, ExtCtrls, ComCtrls, stacktrace2, math, Menus, syncobjs, Contnrs, circularbuffer,
LResources, commonTypeDefs, betterControls;
const
HOOKEVENT_ALLOC=0;
HOOKEVENT_FREE=1;
HOOKEVENT_HEAPALLOC=2;
HOOKEVENT_HEAPFREE=3;
HOOKEVENT_HEAPDESTROY=4;
type
TAllocData=record
handle: qword;
baseaddress: qword;
allocationType: dword;
protect: dword;
size: dword;
esp: qword;
end;
TFreeData=record
handle: qword;
baseaddress: qword;
size: dword;
FreeType: dword;
end;
THeapAllocData=record
HeapHandle: qword;
Flags: DWORD;
Size: dword;
esp:qword;
address: qword;
end;
THeapFreeData=record
HeapHandle: qword;
Flags: dword;
HeapBase: qword;
end;
THeapDestroyData=record
HeapHandle: qword;
end;
THookEvent = record
eventtype: integer;
case integer of
HOOKEVENT_ALLOC: (AllocEvent: TAllocData);
HOOKEVENT_FREE: (FreeEvent: TFreeData);
HOOKEVENT_HEAPALLOC: (HeapAllocEvent: THeapAllocData);
HOOKEVENT_HEAPFREE: (HeapFreeEvent: THeapFreeData);
HOOKEVENT_HEAPDESTROY: (HeapDestroyEvent: THeapDestroyData);
end;
type TmemoryAllocevent=class
private
public
HookEvent: THookEvent;
BaseAddress: ptrUint;
//stack: array [0..4095] of byte;
//stacksize: dword;
procedure assign(o: TMemoryAllocEvent);
end;
type
PMemRecTable=^TMemRecTable;
PMemRecTableArray=^TMemRecTableArray;
TMemRecTable=record
case integer of
1: (memallocevent: TmemoryAllocevent); //if this is the last level (7) this is a memallocevent pointer
2: (MemrecArray: PMemRecTableArray); //else it's a PMemrectablearray
end;
TMemRecTableArray=array [0..15] of TMemRecTable;
type TDisplayThread=class(tthread)
private
maxlevel: integer;
procedure AddAddress(addresslist: PMemrecTableArray; memallocevent: TmemoryAllocevent );
procedure removeaddress(addresslist: PMemrecTableArray; memallocevent: TmemoryAllocevent );
public
csObjectList: TCriticalSection;
ObjectQueue: TCircularObjectBuffer;
ListContainsEntries: TEvent;
errorcount: dword; //debug variable
heapcount: integer;
//-----
procedure AddObject_Free(o: TMemoryAllocEvent);
procedure AddObject_Alloc(o: TMemoryAllocEvent);
procedure AddObject_HeapAlloc(o: TMemoryAllocEvent);
procedure AddObject_HeapFree(o: TMemoryAllocEvent);
procedure AddObject_HeapDestroy(o: TMemoryAllocEvent);
procedure AddObject_HeapDestroy2(a: PMemrectableArray; level: integer; heaphandle: qword);
procedure addobject(objecttoadd: TMemoryAllocEvent);
procedure execute; override;
constructor create(suspended: boolean);
destructor destroy; override;
end;
type TAllocWatcher=class(TThread)
private
HasSetupDataEvent: THandle;
CEHasHandledItEvent: THandle;
HookEventDataAddress: ptrUint;
errorcount: dword; //debug variable
HookEvent: THookEvent;
maxlevel: integer;
procedure allocevent;
procedure freeEvent;
procedure heapAllocEvent;
procedure heapFreeEvent;
procedure headpDestroyEvent;
// procedure addObject;
procedure addObjectToList(o: TmemoryAllocevent);
public
procedure execute; override;
constructor create(suspended: boolean; HasSetupDataEvent: THandle; CEHasHandledItEvent: THandle; HookEventDataAddress: ptrUint);
end;
type
{ TfrmMemoryAllocHandler }
TfrmMemoryAllocHandler = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
lblBaseAddress: TLabel;
lblFlags: TLabel;
lblHeapHandle: TLabel;
lblSize: TLabel;
Panel2: TPanel;
StatusBar1: TStatusBar;
Timer1: TTimer;
GroupBox1: TGroupBox;
Panel1: TPanel;
Edit1: TEdit;
Button1: TButton;
lblErr: TLabel;
btnReload: TButton;
cbHookAllocs: TCheckBox;
procedure cbHookAllocsChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure GroupBox1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure btnReloadClick(Sender: TObject);
procedure cbHookAllocsClick(Sender: TObject);
private
{ Private declarations }
HasSetupDataEvent: THandle;
CEHasHandledItEvent: THandle;
CEInitializationFinished: THandle;
watcher: TAllocWatcher;
HookEventDataAddress: ptrUint;
hookscript: tstringlist;
disableinfo: TDisableInfo;
maxlevel: integer;
pointermask: integer;
public
{ Public declarations }
//level0 (0000000-10000000-20000000-30000000-40000000-50000000-60000000-70000000-80000000-90000000-a0000000-b0000000-c0000000-d0000000-e0000000-f0000000
//level1.0 (01000000-02000000-03000000-04000000-....
//level1.1 (11000000-12000000-13000000-14000000-....
//max level (7/15) is the actual record
memrecCS: TCriticalSection;
HeapBaselevel: TMemRecTableArray;
AllocBaseLevel: TMemRecTableArray;
hookedprocessid: dword;
displaythread: TDisplayThread;
function FindAddress(addresslist: PMemrecTableArray; address: ptrUint): TMemoryAllocEvent;
function WaitForInitializationToFinish: boolean;
end;
var
frmMemoryAllocHandler: TfrmMemoryAllocHandler;
implementation
uses frmautoinjectunit, MemoryBrowserFormUnit, processhandlerunit, Globals;
resourcestring
rsQueuedMemoryEventsWaiting = 'Queued memory events waiting: %s';
rsHeapcount = 'Heapcount=%s';
rsFailureToInitialize = 'Failure to initialize';
rsFailureToHook = 'Failure to hook';
rsEvent1Failure = 'Event1 failure:';
rsEvent2Failure = 'Event2 failure:';
rsEvent3Failure = 'Event3 failure:';
procedure TDisplayThread.removeaddress(addresslist: PMemrecTableArray; memallocevent: TmemoryAllocevent );
var
level: integer;
entrynr: integer;
currentarray: PMemrectablearray;
i: integer;
temp: TmemoryAllocevent;
begin
level:=0;
currentarray:=addresslist;
while level<maxlevel do
begin
entrynr:=memallocevent.baseaddress shr ((maxlevel-level)*4) and $f;
if currentarray[entrynr].MemrecArray=nil then
exit; //not found
currentarray:=currentarray[entrynr].MemrecArray;
inc(level);
end;
entrynr:=memallocevent.baseaddress shr ((maxlevel-level)*4) and $f;
if currentarray[entrynr].memallocevent<>nil then
begin
//remove it
temp:=currentarray[entrynr].memallocevent;
currentarray[entrynr].memallocevent:=nil;
if addresslist=@frmMemoryAllocHandler.HeapBaselevel then
dec(heapcount);
temp.Free;
end;
end;
procedure TDisplayThread.AddAddress(addresslist: PMemrecTableArray; memallocevent: TmemoryAllocevent );
var
level: integer;
entrynr: integer;
temp,currentarray: PMemrectablearray;
temp2: TmemoryAllocevent;
i: integer;
begin
level:=0;
currentarray:=addresslist;
while level<maxlevel do
begin
entrynr:=memallocevent.baseaddress shr ((maxlevel-level)*4) and $f;
if currentarray[entrynr].MemrecArray=nil then //allocate the array
begin
GetMem(temp, sizeof(TMemRecTableArray));
ZeroMemory(temp, sizeof(TMemRecTableArray));
currentarray[entrynr].MemrecArray:=temp;
end;
currentarray:=currentarray[entrynr].MemrecArray;
inc(level);
end;
entrynr:=memallocevent.baseaddress shr ((maxlevel-level)*4) and $f;
if currentarray[entrynr].memallocevent<>nil then
begin
temp2:=currentarray[entrynr].memallocevent;
currentarray[entrynr].memallocevent:=nil;
temp2.free;
end;
currentarray[entrynr].memallocevent:=memallocevent;
if addresslist=@frmMemoryAllocHandler.HeapBaselevel then
inc(heapcount);
end;
procedure TDisplayThread.AddObject_HeapAlloc(o: TMemoryAllocEvent);
begin
addaddress(@frmMemoryAllocHandler.HeapBaseLevel, o);
end;
procedure TDisplayThread.AddObject_HeapFree(o: TMemoryAllocEvent);
var
first,last: integer;
j,k: integer;
x: integer;
temp: dword;
begin
removeaddress(@frmMemoryAllocHandler.HeapBaseLevel, o);
o.Free;
end;
procedure TDisplayThread.AddObject_HeapDestroy2(a: PMemrectableArray; level: integer; heaphandle: qword);
var i: integer;
temp: TMemoryAllocEvent;
begin
if level=maxlevel then
begin
for i:=0 to 15 do
if (a[i].memallocevent<>nil) and (a[i].memallocevent.HookEvent.HeapAllocEvent.HeapHandle=heaphandle) then
begin
//delete this one
temp:=a[i].memallocevent;
a[i].memallocevent:=nil;
dec(heapcount);
temp.free;
end;
end
else
for i:=0 to 15 do
begin
if a[i].MemrecArray<>nil then
AddObject_HeapDestroy2(a[i].MemrecArray,level+1,heaphandle);
end;
end;
procedure TDisplayThread.AddObject_HeapDestroy(o: TMemoryAllocEvent);
var
i: integer;
level: integer;
destroyedHandle: pointer;
begin
AddObject_HeapDestroy2(@frmMemoryAllocHandler.HeapBaseLevel,0,o.HookEvent.HeapDestroyEvent.HeapHandle);
end;
procedure TDisplayThread.AddObject_Alloc(o: TMemoryAllocEvent);
var
s: string;
first,last: integer;
x,i,j,k,l: integer;
temp: dword;
insert: boolean;
begin
addaddress(@frmMemoryAllocHandler.AllocBaseLevel, o);
end;
procedure TDisplayThread.AddObject_Free(o: TMemoryAllocEvent);
var
first,last: integer;
x,j,k: integer;
temp: dword;
begin
removeaddress(@frmMemoryAllocHandler.AllocBaseLevel, o);
o.Free;
end;
procedure TDisplayThread.addobject(objecttoadd: TMemoryAllocEvent);
//Handles the current object with the gui (add, delete, etc...)
begin
try
case objecttoadd.HookEvent.eventtype of
HOOKEVENT_FREE: AddObject_Free(objecttoadd);
HOOKEVENT_ALLOC: AddObject_Alloc(objecttoadd);
HOOKEVENT_HEAPALLOC: AddObject_HeapAlloc(objecttoadd);
HOOKEVENT_HEAPFREE: AddObject_HeapFree(objecttoadd);
HOOKEVENT_HEAPDESTROY:AddObject_HeapDestroy(objecttoadd);
end;
except
inc(errorcount);
OutputDebugString('Exception in TDisplayThread.addobject2. objecttoadd='+inttohex(ptrUint(objecttoadd),8));
end;
end;
procedure TDisplayThread.execute;
var o: TMemoryAllocEvent;
begin
while not terminated do
begin
try
o:=nil;
csObjectList.Enter;
try
if ObjectQueue.Count>0 then
o:=TMemoryAllocEvent(ObjectQueue.Read);
finally
csObjectList.Leave;
end;
if o<>nil then
begin
frmMemoryAllocHandler.memrecCS.enter;
try
addobject(o)
finally
frmMemoryAllocHandler.memrecCS.leave;
end;
end
else
ListContainsEntries.WaitFor(1000); //nothing to add to the list, wait a second and check again
except
inc(errorcount);
OutputDebugString('Error in TDisplayThread.execute');
end;
end;
end;
constructor TDisplayThread.create(suspended: boolean);
begin
csObjectList:=TCriticalSection.Create;
ObjectQueue:=TCircularObjectBuffer.Create(5000000, 1000); //arround 20MB of of pointe storage
ListContainsEntries:=TEvent.Create(nil,false,false,'');
if processhandler.is64Bit then
maxlevel:=15
else
maxlevel:=7;
inherited create(suspended);
end;
destructor TDisplayThread.destroy;
begin
if csObjectList<>nil then
freeandnil(csObjectList);
if ListContainsEntries<>nil then
freeandnil(ListContainsEntries);
if ObjectQueue<>nil then
freeandnil(ObjectQueue);
inherited destroy;
end;
procedure TAllocWatcher.addObjectToList(o: TmemoryAllocevent);
//Will add this object to a list that will later on be read out by the display thread
begin
frmMemoryAllocHandler.displaythread.csObjectList.Enter;
try
frmMemoryAllocHandler.displaythread.ObjectQueue.Write(o)
finally
frmMemoryAllocHandler.displaythread.csObjectList.Leave;
end;
frmMemoryAllocHandler.displaythread.ListContainsEntries.SetEvent;
end;
procedure TmemoryAllocevent.assign(o: TMemoryAllocEvent);
var i: integer;
begin
self.HookEvent:=o.HookEvent;
{ for i:=0 to o.stacksize-1 do
self.stack[i]:=o.stack[i];
self.stacksize:=o.stacksize; }
end;
{
procedure TAllocWatcher.addObject;
end; }
procedure TAllocWatcher.allocEvent;
var s: integer;
o: TMemoryAllocEvent;
begin
{$IFDEF windows}
o:=TmemoryAllocevent.create;
o.HookEvent:=hookevent;
o.BaseAddress:=hookevent.AllocEvent.baseaddress;
{
if not ReadProcessMemory(processhandle,pointer(o.HookEvent.AllocEvent.esp),@o.stack[0],4096,o.stacksize) then
begin
//probably couldn't read because of pageerror
//read the remaining of the page
s:=4096-(o.HookEvent.AllocEvent.esp mod 4096);
ReadProcessMemory(processhandle,pointer(o.HookEvent.AllocEvent.esp),@o.stack[0],s,o.stacksize);
end; }
setevent(CEHasHandledItEvent); //tell the hooked app to continue
addObjectToList(o);
{$ENDIF}
end;
procedure TAllocWatcher.freeEvent;
var o: TMemoryAllocEvent;
begin
{$IFDEF windows}
o:=TmemoryAllocevent.create;
o.HookEvent:=hookevent;
o.BaseAddress:=hookevent.FreeEvent.baseaddress;
setevent(CEHasHandledItEvent);
addObjectToList(o);
{$ENDIF}
end;
procedure TAllocWatcher.heapAllocEvent;
var o: TMemoryAllocEvent;
var s: integer;
begin
{$IFDEF windows}
o:=TmemoryAllocevent.create;
o.HookEvent:=hookevent;
o.BaseAddress:=ptrUint(hookevent.HeapAllocEvent.address);
{
if not ReadProcessMemory(processhandle,pointer(o.HookEvent.HeapAllocEvent.esp),@o.stack[0],4096,o.stacksize) then
begin
//probably couldn't read because of pageerror
//read the remaining of the page
s:=4096-(o.HookEvent.AllocEvent.esp mod 4096);
ReadProcessMemory(processhandle,pointer(o.HookEvent.HeapAllocEvent.esp),@o.stack[0],s,o.stacksize);
end; }
setevent(CEHasHandledItEvent);
addObjectToList(o);
{$ENDIF}
end;
procedure TAllocWatcher.heapFreeEvent;
var o: TMemoryAllocEvent;
begin
{$IFDEF windows}
o:=TmemoryAllocevent.create;
o.HookEvent:=hookevent;
o.BaseAddress:=ptrUint(hookevent.HeapFreeEvent.HeapBase);
setevent(CEHasHandledItEvent);
addObjectToList(o);
{$ENDIF}
end;
procedure TAllocWatcher.headpDestroyEvent;
var o: TMemoryAllocEvent;
begin
{$IFDEF windows}
o:=TmemoryAllocevent.create;
o.HookEvent:=hookevent;
o.BaseAddress:=$0;
setevent(CEHasHandledItEvent);
addObjectToList(o);
{$ENDIF}
end;
procedure TAllocWatcher.execute;
var x: PtrUInt;
begin
{$IFDEF windows}
while not terminated do
begin
try
if waitforsingleobject(HasSetupDataEvent,500)=WAIT_OBJECT_0 then
begin
if readprocessmemory(processhandle, pointer(HookEventDataAddress),@HookEvent,sizeof(HookEvent),x) then
begin
case HookEvent.eventtype of
HOOKEVENT_ALLOC : allocEvent;
HOOKEVENT_FREE : freeEvent;
HOOKEVENT_HEAPALLOC : heapAllocEvent;
HOOKEVENT_HEAPFREE : heapFreeEvent;
HOOKEVENT_HEAPDESTROY : headpDestroyEvent;
end;
end;
end;
except
inc(errorcount);
OutputDebugString('Error in TAllocWatcher.execute');
end;
end;
{$ENDIF}
end;
constructor TAllocWatcher.create(suspended: boolean; HasSetupDataEvent: THandle; CEHasHandledItEvent: THandle; HookEventDataAddress: ptrUint);
begin
self.HasSetupDataEvent:=HasSetupDataEvent;
self.CeHasHandledItEvent:=CeHasHandledItEvent;
self.HookEventDataAddress:=HookEventDataAddress;
if processhandler.is64Bit then
maxlevel:=15
else
maxlevel:=7;
inherited create(suspended);
end;
procedure TfrmMemoryAllocHandler.FormCreate(Sender: TObject);
var
injectionscript: TStringlist;
x,y,z: THandle;
mi: tmoduleinfo;
mname: string;
begin
{$ifdef windows}
if processhandler.is64Bit then
begin
maxlevel:=15;
pointermask:=7; //AND the value/address with this value. If the result=0 it's aligned
end
else
begin
maxlevel:=7;
pointermask:=3;
end;
memrecCS:=TCriticalSection.Create;
displaythread:=TDisplayThread.create(false);
injectionscript:=tstringlist.Create;
try
//inject allochook.dll
if processhandler.is64bit then
mname:='allochook-x86_64.dll'
else
mname:='allochook-i386.dll';
if not symhandler.getmodulebyname(mname,mi) then
begin
injectdll(CheatEngineDir+mname);
symhandler.reinitialize(True);
end;
HasSetupDataEvent:=CreateEvent(nil, false, false, nil);
CEHasHandledItEvent:=CreateEvent(nil,false,false,nil);
CEInitializationFinished:=CreateEvent(nil,true,false,nil);
x:=0;
if not DuplicateHandle(GetCurrentProcess, HasSetupDataEvent, processhandle, @x, 0, false, DUPLICATE_SAME_ACCESS ) then
raise exception.Create(rsEvent1Failure+inttostr(getlasterror));
y:=0;
if not DuplicateHandle(GetCurrentProcess, CEHasHandledItEvent, processhandle, @y, 0, false, DUPLICATE_SAME_ACCESS ) then
raise exception.Create(rsEvent2Failure+inttostr(getlasterror));
z:=0;
if not DuplicateHandle(GetCurrentProcess, CEInitializationFinished, processhandle, @z, 0, false, DUPLICATE_SAME_ACCESS ) then
raise exception.Create(rsEvent3Failure+inttostr(getlasterror));
//set event handles
injectionscript.Add('HasSetupDataEvent:');
injectionscript.Add('DQ '+inttohex(x,8));
injectionscript.Add('CEHasHandledItEvent:');
injectionscript.Add('DQ '+inttohex(y,8));
injectionscript.Add('CEInitializationFinished:');
injectionscript.Add('DQ '+inttohex(z,8));
if not autoassemble(injectionscript,false) then raise exception.Create(rsFailureToHook);
HookEventDataAddress:=symhandler.getAddressFromName('HookEventData');
//everything configured successful, start thread that watches for HasSetupDataEvent events
watcher:=TAllocWatcher.create(false, HasSetupDataEvent, CEHasHandledItEvent, HookEventDataAddress);
hookedprocessid:=processid;
injectionscript.Clear;
injectionscript.Add('CreateThread(CeInitializeAllocHook)');
if not autoassemble(injectionscript,false) then raise exception.Create(rsFailureToInitialize);
finally
injectionscript.Free;
end;
{$endif}
end;
procedure TfrmMemoryAllocHandler.cbHookAllocsChange(Sender: TObject);
begin
end;
procedure TfrmMemoryAllocHandler.FormDestroy(Sender: TObject);
begin
if watcher<>nil then
freeandnil(watcher);
if HasSetupDataEvent>0 then
closehandle(HasSetupDataEvent);
if CEHasHandledItEvent>0 then
closehandle(CEHasHandledItEvent);
//cleanup memory allocs
end;
procedure TfrmMemoryAllocHandler.FormShow(Sender: TObject);
begin
if processhandler.is64Bit then
edit1.ClientWidth:=canvas.TextWidth(' DDDDDDDD ')
else
edit1.ClientWidth:=canvas.TextWidth(' DDDDDDDDDDDDD ')
end;
procedure TfrmMemoryAllocHandler.GroupBox1Click(Sender: TObject);
begin
end;
procedure TfrmMemoryAllocHandler.Timer1Timer(Sender: TObject);
begin
StatusBar1.Panels[0].Text:=Format(rsQueuedMemoryEventsWaiting, [inttostr(displaythread.ObjectQueue.Count)]);
Statusbar1.Panels[1].Text:=Format(rsHeapcount, [inttostr(displaythread.heapcount)]);
end;
procedure TfrmMemoryAllocHandler.Button1Click(Sender: TObject);
var result: TMemoryAllocEvent;
begin
result:=FindAddress(@HeapBaselevel, strToInt('$'+edit1.Text));
if result<>nil then
begin
lblHeapHandle.caption:=inttohex(ptrUint(result.HookEvent.HeapAllocEvent.HeapHandle),8);
lblflags.Caption:=heapflagstostring(result.HookEvent.HeapAllocEvent.Flags);
lblbaseaddress.caption:=inttohex(ptrUint(result.HookEvent.HeapAllocEvent.address),8);
lblsize.Caption:=inttostr(result.HookEvent.HeapAllocEvent.Size);
if lblErr.Visible then
lblErr.Visible:=false;
end else
begin
lblHeapHandle.caption:='-';
lblflags.Caption:='-';
if FindAddress(@AllocBaseLevel,strtoint('$'+edit1.Text))<>nil then
begin
lblbaseaddress.caption:=inttohex(ptrUint(result.HookEvent.HeapAllocEvent.address),8);
lblsize.Caption:=inttostr(result.HookEvent.HeapAllocEvent.Size);
lblErr.Visible:=true;
end
else
begin
lblbaseaddress.caption:='-';
lblsize.Caption:='-';
if lblErr.Visible then
lblErr.Visible:=false;
end;
end;
end;
type TMemrectablearraylist = array [0..15] of record
arr:PMemrectablearray;
entrynr: integer;
end;
function findMaxOfPath(a: PMemrectablearray; level: integer; maxlevel: integer):TMemoryAllocEvent;
var
i: integer;
begin
result:=nil;
if level=maxlevel then
begin
for i:=15 downto 0 do
begin
if a[i].memallocevent<>nil then
begin
result:=a[i].memallocevent;
exit;
end;
end;
end
else
begin
for i:=15 downto 0 do
begin
if a[i].MemrecArray<>nil then
begin
result:=findMaxOfPath(a[i].MemrecArray,level+1, maxlevel);
if result<>nil then exit;
end;
end;
end;
end;
function findprevious(lvl: TMemrectablearraylist; level: integer; maxlevel: integer):TMemoryAllocEvent;
var
i: integer;
currentarray: PMemrectablearray;
begin
result:=nil;
if level=maxlevel then
begin
currentarray:=lvl[level].arr;
for i:=lvl[level].entrynr-1 downto 0 do
begin
if currentarray[i].memallocevent<>nil then
begin
result:=currentarray[i].memallocevent;
exit;
end;
end;
end
else
begin
currentarray:=lvl[level].arr;
for i:=lvl[level].entrynr-1 downto 0 do
begin
if currentarray[i].MemrecArray<>nil then
begin
result:=findMaxOfPath(currentarray[i].MemrecArray,level+1, maxlevel);
if result<>nil then exit;
end;
end;
end;
//still here
if level>0 then
begin
lvl[level].entrynr:=$f;
result:=findprevious(lvl,level-1, maxlevel);
end;
end;
function TfrmMemoryAllocHandler.WaitForInitializationToFinish: boolean;
begin
{$IFDEF windows}
result:=WaitForSingleObject(CEInitializationFinished,5000)=WAIT_OBJECT_0;
{$ENDIF}
end;
function TfrmMemoryAllocHandler.FindAddress(addresslist: PMemrecTableArray; address: ptrUint): TMemoryAllocEvent;
//only call this when displaythread is suspended
var
level: integer;
entrynr: integer;
currentarray: PMemrectablearray;
lvl: TMemrectablearraylist;
i: integer;
begin
zeromemory(@lvl,sizeof(TMemrectablearraylist));
result:=nil;
//memrecCS.Enter;
// try
level:=0;
currentarray:=addresslist;
while level<maxlevel do
begin
entrynr:=address shr ((7-level)*4) and $f;
lvl[level].arr:=currentarray;
lvl[level].entrynr:=entrynr;
if currentarray[entrynr].MemrecArray=nil then
begin
//not a direct match (this will happen almost every time)
//try to find a previous entry
result:=findprevious(lvl, level, maxlevel);
if (result<>nil) and (not InRangeX(address,result.BaseAddress,result.BaseAddress+result.HookEvent.HeapAllocEvent.Size)) then
result:=nil;
exit;
end;
currentarray:=currentarray[entrynr].MemrecArray;
inc(level);
end;
entrynr:=address shr ((maxlevel-level)*4) and $f;
lvl[level].arr:=currentarray;
lvl[level].entrynr:=entrynr;
if currentarray[entrynr].memallocevent<>nil then
result:=currentarray[entrynr].memallocevent
else
begin
//not a direct match
//try to find a previous entry
result:=findprevious(lvl,level, maxlevel);
end;
if (result<>nil) and (not InRangeX(address,result.BaseAddress,result.BaseAddress+result.HookEvent.HeapAllocEvent.Size)) then
result:=nil;
{
finally
//memrecCS.Leave;
end;}
end;
procedure DeletePath(addresslist: PMemrecTableArray; level: integer; maxlevel: integer);
var
i: integer;
begin
if level=maxlevel then
begin
for i:=0 to 15 do
begin
if addresslist[i].memallocevent<>nil then
freeandnil(addresslist[i].memallocevent);
end;
end
else
begin
for i:=0 to 15 do
begin
if addresslist[i].MemrecArray<>nil then
begin
deletepath(addresslist[i].MemrecArray,level+1, maxlevel);
freememandnil(addresslist[i].MemrecArray);
end;
end;
end;
end;
procedure TfrmMemoryAllocHandler.btnReloadClick(Sender: TObject);
var
injectionscript: TStringlist;
i: integer;
begin
{$IFDEF windows}
WaitForInitializationToFinish;
injectionscript:=TStringList.Create;
memrecCS.Enter;
displaythread.csObjectList.Enter;
try
//whipe the old list
DeletePath(@HeapBaselevel, 0, maxlevel);
displaythread.heapcount:=0;
injectionscript.Add('CreateThread(CeInitializeAllocHook)');
ResetEvent(CEInitializationFinished);
if not autoassemble(injectionscript, false) then raise exception.Create(rsFailureToInitialize);
finally
displaythread.csObjectList.Leave;
memrecCS.Leave;
injectionscript.Free;
end;
{$ENDIF}
end;
procedure TfrmMemoryAllocHandler.cbHookAllocsClick(Sender: TObject);
begin
{$ifdef windows}
if cbHookAllocs.Checked then
begin
if hookscript=nil then
hookscript:=tstringlist.Create;
hookscript.Clear;
hookscript.Add('[Enable]');
hookscript.Add('');
hookscript.Add('[Disable]');
hookscript.Add('');
//hook apis
generateAPIHookScript(hookscript,'NtAllocateVirtualMemory','CeAllocateVirtualMemory', 'NtAllocateVirtualMemoryOrig','0');
generateAPIHookScript(hookscript,'NtFreeVirtualMemory','CeFreeVirtualMemory', 'NtFreeVirtualMemoryOrig','1');
generateAPIHookScript(hookscript,'RtlAllocateHeap','CeRtlAllocateHeap', 'RtlAllocateHeapOrig','2');
generateAPIHookScript(hookscript,'RtlFreeHeap','CeRtlFreeHeap', 'RtlFreeHeapOrig','3');
generateAPIHookScript(hookscript,'RtlDestroyHeap','CeRtlDestroyHeap', 'RtlDestroyHeapOrig','4');
if not autoassemble(hookscript,false,true,false,false,disableinfo) then raise exception.Create(rsFailureToHook);
end
else
begin
//unload
if hookscript=nil then exit; //should never happen
if not autoassemble(hookscript,false,false,false,false,disableinfo) then raise exception.Create(rsFailureToHook);
freeandnil(hookscript);
end;
{$endif}
end;
initialization
{$i frmMemoryAllocHandlerUnit.lrs}
end.