unit hookedfunctions; {$mode delphi} interface uses sysutils, windows, messages, syncobjs; type TNtAllocateVirtualMemory=function(processHandle: THandle; BaseAddress: PPtrUint; ZeroBits: DWORD; RegionSize: PDWORD; AllocationType: DWORD; Protect: DWORD): DWORD; stdcall; type TNtFreeVirtualMemory=function(processHandle: THandle; BaseAddress: PPtrUint; RegionSize: PDWORD; FreeType: DWORD ): DWORD; stdcall; type TRtlAllocateHeap=function(HeapHandle: pointer; Flags: DWORD; size: integer): pointer; stdcall; type TRtlFreeHeap=function(HeapHandle: pointer; Flags: DWORD; HeapBase: pointer): BOOL; stdcall; type TRtlDestroyHeap=function(HeapHandle: pointer): pointer; stdcall; function CeAllocateVirtualMemory(processHandle: THandle; BaseAddress: PPtrUint; ZeroBits: DWORD; RegionSize: PDWORD; AllocationType: DWORD; Protect: DWORD): DWORD; stdcall; function CeFreeVirtualMemory(processHandle: THandle; BaseAddress: PPtrUint; RegionSize: PDWORD; FreeType: DWORD ): DWORD; stdcall; function CeRtlAllocateHeap(HeapHandle: pointer; Flags: DWORD; size: integer): pointer; stdcall; function CeRtlFreeHeap(HeapHandle: pointer; Flags: DWORD; HeapBase: pointer): BOOL; stdcall; function CeRtlDestroyHeap(HeapHandle: pointer): pointer; stdcall; function CeInitializeAllocHook: BOOL; stdcall; var NtAllocateVirtualMemoryOrig: TNtAllocateVirtualMemory; NtFreeVirtualMemoryOrig: TNtFreeVirtualMemory; RtlAllocateHeapOrig: TRtlAllocateHeap; RtlFreeHeapOrig: TRtlFreeHeap; RtlDestroyHeapOrig: TRtlDestroyHeap; 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; var HookEventData: THookEvent; var HasSetupDataEvent: qword; //set by this routine var CEHasHandledItEvent: qword; //set by ce var CEInitializationFinished: qword; //set by CeInitializeAllocHook, and reset by ce (or never) implementation var allocCS: TCriticalSection; function CeInitializeAllocHook: BOOL; stdcall; //this function will gather the start memory situation using a heapwalk and pass off that information to ce (ce's lookup is faster for the pointerscan) //call this after the hooks are in place and all configuration has been completed (handles) var heaphandles: array of thandle; size: integer; h: THandle; i: integer; phe: TProcessHeapEntry; begin ResetEvent(CEInitializationFinished); //in case ce forgot to reset it... h:=0; size:=GetProcessHeaps(0,h); if size>0 then begin setlength(heaphandles,size); size:=GetProcessHeaps(size,heaphandles[0]); if size>0 then begin for i:=0 to size-1 do begin heaplock(heaphandles[i]); try ZeroMemory(@phe,sizeof(phe)); while HeapWalk(heaphandles[i], phe) do begin if phe.wFlags=PROCESS_HEAP_ENTRY_BUSY then begin allocCS.Enter; try HookEventData.eventtype:=HOOKEVENT_HEAPALLOC; HookEventData.HeapAllocEvent.HeapHandle:=heaphandles[i]; HookEventData.HeapAllocEvent.flags:=0; HookEventData.HeapAllocEvent.size:=phe.cbData; HookEventData.HeapAllocEvent.esp:=0; HookEventData.HeapAllocEvent.address:=qword(phe.lpData); //signal ce that the event has been filled in SetEvent(HasSetupDataEvent); //and wait till ce is done with it if waitforsingleobject(CEHasHandledItEvent,5000)<>WAIT_OBJECT_0 then outputdebugstring('CeRtlAllocateHeap:timeout on CEHasHandledItEvent'); finally allocCS.Leave; end; end; end; finally heapunlock(heaphandles[i]); end; end; end; end; result:=true; setevent(CEInitializationFinished); end; function CeRtlAllocateHeap(HeapHandle: pointer; Flags: DWORD; size: integer): pointer; stdcall; var stack: dword; begin result:=RtlAllocateHeapOrig(heapHandle, flags,size); if result<>nil then begin allocCS.Enter; HookEventData.eventtype:=HOOKEVENT_HEAPALLOC; HookEventData.HeapAllocEvent.HeapHandle:=qword(HeapHandle); HookEventData.HeapAllocEvent.flags:=flags; HookEventData.HeapAllocEvent.size:=size; HookEventData.HeapAllocEvent.address:=qword(result); //signal ce that the event has been filled in SetEvent(HasSetupDataEvent); //and wait till ce is done with it if waitforsingleobject(CEHasHandledItEvent,5000)<>WAIT_OBJECT_0 then outputdebugstring('CeRtlAllocateHeap:timeout on CEHasHandledItEvent'); allocCS.Leave; end; end; function CeRtlFreeHeap(HeapHandle: pointer; Flags: DWORD; HeapBase: pointer): BOOL; stdcall; begin result:=RtlFreeHeapOrig(heapHandle, Flags, HeapBase); if result then begin allocCS.Enter; HookEventData.eventtype:=HOOKEVENT_HEAPFREE; HookEventData.HeapFreeEvent.HeapHandle:=qword(HeapHandle); HookEventData.HeapFreeEvent.Flags:=flags; HookEventData.HeapFreeEvent.HeapBase:=qword(HeapBase); //signal ce that the event has been filled in SetEvent(HasSetupDataEvent); //and wait till ce is done with it if waitforsingleobject(CEHasHandledItEvent,5000)<>WAIT_OBJECT_0 then outputdebugstring('CeRtlFreeHeap:timeout on CEHasHandledItEvent'); allocCS.Leave; end; end; function CeRtlDestroyHeap(HeapHandle: pointer): pointer; stdcall; //Hooked because destroying a heaphandle destroys ALL related heap allocs begin result:=RtlDestroyHeapOrig(heaphandle); if result=nil then begin allocCS.Enter; HookEventData.eventtype:=HOOKEVENT_HEAPDESTROY; HookEventData.HeapDestroyEvent.HeapHandle:=qword(HeapHandle); //signal ce that the event has been filled in SetEvent(HasSetupDataEvent); //and wait till ce is done with it if waitforsingleobject(CEHasHandledItEvent,5000)<>WAIT_OBJECT_0 then outputdebugstring('CeRtlDestroyHeap:timeout on CEHasHandledItEvent'); allocCS.Leave; end; end; function CeAllocateVirtualMemory(processHandle: THandle; BaseAddress: PPtrUint; ZeroBits: DWORD; RegionSize: PDWORD; AllocationType: DWORD; Protect: DWORD): DWORD; stdcall; var stack: dword; begin //note: don't call anything that allocs memory result:=NtAllocateVirtualMemoryOrig(processHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect); if result=0 then //successfully allocated begin allocCS.Enter; //fill in allocation field //post a message to the handlerthread with the address of CreateEvent and wait till it's done HookEventData.eventtype:=HOOKEVENT_ALLOC; HookEventData.AllocEvent.handle:=processHandle; if baseaddress<>nil then HookEventData.AllocEvent.baseaddress:=BaseAddress^ else HookEventData.AllocEvent.baseaddress:=0; HookEventData.AllocEvent.allocationType:=AllocationType; HookEventData.AllocEvent.protect:=protect; // asm // mov stack,ebp // end; // HookEventData.AllocEvent.esp:=stack; if regionsize<>nil then HookEventData.AllocEvent.size:=regionsize^ else HookEventData.AllocEvent.size:=0; //signal ce that the createEvent has been filled in SetEvent(HasSetupDataEvent); //and wait till ce is done with it if waitforsingleobject(CEHasHandledItEvent,5000)<>WAIT_OBJECT_0 then outputdebugstring('Alloc:timeout on CEHasHandledItEvent'); allocCS.Leave; end; end; function CeFreeVirtualMemory(processHandle: THandle; BaseAddress: PPtrUint; RegionSize: PDWORD; FreeType: DWORD ): DWORD; stdcall; begin result:=NtFreeVirtualMemoryOrig(processHandle, BaseAddress, RegionSize, FreeType); if result=0 then //success begin allocCS.Enter; HookEventData.eventtype:=HOOKEVENT_FREE; HookEventData.FreeEvent.handle:=processHandle; if baseaddress <> nil then HookEventData.FreeEvent.baseaddress:=baseaddress^ else HookEventData.FreeEvent.baseaddress:=0; if regionsize<>nil then HookEventData.FreeEvent.size:=regionSize^ else HookEventData.FreeEvent.size:=0; HookEventData.FreeEvent.FreeType:=FreeType; //signal ce that the createEvent has been filled in SetEvent(HasSetupDataEvent); //and wait till ce is done with it if waitforsingleobject(CEHasHandledItEvent,5000)<>WAIT_OBJECT_0 then outputdebugstring('Free:timeout on CEHasHandledItEvent'); allocCS.Leave; end; end; initialization allocCS:=TCriticalSection.Create; end.