unit RemoteMemoryManager; { this unit will contain a class that will be used to control remotely allocated memory blocks. Specifically designed for smaller allocations. allocate at least systeminfo.dwAllocationGranularity on each real alloc (64kb) Speed is not of essence here. Assumed it that only up to 8KB of memory will be used at MOST } {$mode delphi} interface uses windows, syncobjs, Classes, SysUtils, cefuncproc, newkernelhandler; type TAllocs=record //record describing each little allocated block of memory address: ptruint; size: dword; end; PAllocs=^TAllocs; type TAllocatedRegion=record remotebase: ptruint; //size is not stored, that is systeminfo.dwAllocationGranularity allocs: Tlist; //sorted list of allocations end; PAllocatedRegion=^TAllocatedRegion; type TRemoteMemoryManager=class(tobject) private cs: TCriticalsection; allocatedRegions: Tlist; bigAllocs: Tlist; function findFreeRegion(size: dword): ptruint; procedure addNewAlloc(address: ptruint; size: integer); public function alloc(size: dword):ptruint; procedure dealloc(address: ptruint); constructor create; destructor destroy; override; end; implementation uses ProcessHandlerUnit; procedure TRemoteMemoryManager.addNewAlloc(address: ptruint; size: integer); var i,j: integer; a,b: PAllocs; ar: PAllocatedRegion; begin getmem(a, sizeof(TAllocs)); a.address:=address; a.size:=size; for i:=0 to allocatedRegions.count-1 do begin ar:=PAllocatedRegion(allocatedRegions[i]); if InRangeQ(address, ar.remotebase, ar.remotebase+systeminfo.dwAllocationGranularity) then begin for j:=0 to ar.allocs.Count-1 do begin b:=PAllocs(ar.allocs[j]); if b.address>address then //insert the address before this one begin ar.allocs.Insert(j,a); exit; //inserted the alloc data. leave now end; end; //still here, add it to the end ar.allocs.Add(a); break; end; end; end; function TRemoteMemoryManager.findFreeRegion(size: dword): ptruint; var i,j: integer; currentTry: ptruint; a: PAllocs; ar: PAllocatedRegion; begin result:=0; //scan the regions for a gap of at least size bytes for i:=0 to allocatedRegions.count-1 do begin ar:=PAllocatedRegion(allocatedRegions[i]); currentTry:=ar.remotebase; for j:=0 to ar.allocs.count-1 do begin a:=PAllocs(ar.allocs[j]); //keep in mind: sorted list if ((currentTry+size)>=a.address) then //too big to be used here currentTry:=qword(a.address)+a.size //not usable, try the next block else //this block seems usable break; //this block seems usable end; //check if we're not outside of the allocated region if (currentTry+size)<(ar.remotebase+ systeminfo.dwAllocationGranularity) then //found a usable block that falls within a allocated region begin result:=currentTry; break; end; end; end; function TRemoteMemoryManager.alloc(size: dword):ptruint; var i: integer; ar: PAllocatedRegion; begin result:=0; if size=0 then exit; //make it so size is always at least dividable by 4 (means min size is 4) i:=size mod 4; if i>0 then size:=size + (4-i); if size>=systeminfo.dwAllocationGranularity then //can't be handled with the small handler begin result:=ptruint(VirtualAllocEx(processhandle,nil,size,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE)); if result<>0 then begin cs.enter; bigAllocs.Add(pointer(result)); cs.leave; end; end else begin //small enough cs.enter; try result:=findFreeRegion(size); if result=0 then begin //no free region found result:=ptruint(VirtualAllocEx(processhandle,nil,systeminfo.dwAllocationGranularity,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE)); if result<>0 then begin ar:=getmem(sizeof(TAllocatedRegion)); ar.remotebase:=result; ar.allocs:=tlist.create; allocatedRegions.Add(ar); end; end; addNewAlloc(result, size); finally cs.leave; end; end; end; procedure TRemoteMemoryManager.dealloc(address: ptruint); var i,j: integer; ar: PAllocatedRegion; b: PAllocs; begin cs.enter; try for i:=0 to allocatedRegions.count-1 do begin ar:=PAllocatedRegion(allocatedRegions[i]); if InRangeQ(address, ar.remotebase, ar.remotebase+systeminfo.dwAllocationGranularity) then begin for j:=0 to ar.allocs.Count-1 do begin b:=PAllocs(ar.allocs[j]); if address=b.address then //insert the address before this one begin //found it freemem(b); ar.allocs.Delete(j); if ar.allocs.Count=0 then //completely freed this region begin virtualfreeex(processhandle,pointer(ar.remotebase),0,MEM_RELEASE); ar.allocs.Free; freemem(ar); allocatedRegions.Delete(i); end; exit; end; end; end; end; //not found, check the big alloc region i:=bigallocs.IndexOf(pointer(address)); if i<>-1 then begin virtualfreeex(processhandle,pointer(address),0,MEM_RELEASE); bigallocs.Delete(i); end; finally cs.leave; end; end; constructor TRemoteMemoryManager.create; begin cs:=TCriticalsection.create; allocatedRegions:=tlist.create; bigallocs:=Tlist.create; end; destructor TRemoteMemoryManager.destroy; var i,j: integer; begin //don't dealloc the memory, but do free the structures allocated here for i:=0 to allocatedRegions.count-1 do begin for j:=0 to PAllocatedRegion(allocatedRegions[i]).allocs.Count-1 do freemem(PAllocatedRegion(allocatedRegions[i]).allocs[j]); PAllocatedRegion(allocatedRegions[i]).allocs.Free; freemem(allocatedRegions[i]); end; allocatedRegions.free; bigallocs.free; cs.free; end; end.