Patching a running process code
The first feature we have to do is to allow on-the-fly change of the assembler code of a process.
When an executable is mapped in RAM, the memory page corresponding to the process code is marked as Read Only, in order to avoid any security attack from the outside. Only the current process can patch its own code.
We'll need to override a
pointer value in the code memory. The
following function, defined in
SynCommons.pas will handle it:
procedure PatchCodePtrUInt(Code: PPtrUInt; Value: PtrUInt); var RestoreProtection, Ignore: DWORD; begin if VirtualProtect(Code, SizeOf(Code^), PAGE_EXECUTE_READWRITE, RestoreProtection) then begin Code^ := Value; VirtualProtect(Code, SizeOf(Code^), RestoreProtection, Ignore); FlushInstructionCache(GetCurrentProcess, Code, SizeOf(Code^)); end; end;
VirtualProtect low-level Windows API is called to force the
corresponding memory to be written (via the
flag), then modify the corresponding
pointer value, then the
original memory page protection setting (should be
PAGE_EXECUTE_READ) is restored.
According to the MSDN documentation, we'd need to flush the CPU operation cache in order to force the modified code to be read on next access.
Per-class variable in the VMT
The VMT is the Virtual-Method Table, i.e. a Table which defines
class. In fact, every Delphi
defined internally by its VMT, contains a list of pointers to the
virtual methods. This VMT also contains
non-method values, which are class-specific information at negative
||–76||points back to the beginning of the table|
||–68||class’s automation table (deprecated)|
||–64||reference-counted fields type information|
||–60||the associated RTTI type information|
||–40||bytes needed by one class Instance|
We'll use the trick as detailed in
in order to use the
vmtAutoTable deprecated entry in the
This slot entry was used in Delphi 2 only for implementing Automation. Later version of Delphi (our goal) won't use it any more.
But the slot is still here, ready for being used by the framework.
We'll therefore be able to store a pointer to the
TSQLRecordProperties instance corresponding to a
TSQLRecord class, which will be retrieved as such:
class function TSQLRecord.RecordProps: TSQLRecordProperties; begin if Self<>nil then begin result := PPointer(PtrInt(Self)+vmtAutoTable)^; if result=nil then result := PropsCreate(self); end else result := nil; end;
Since this method is called a lot of time by our ORM, there is an asm-optimized version of the pascal code above:
class function TSQLRecord.RecordProps: TSQLRecordProperties; asm or eax,eax jz @null mov edx,[eax+vmtAutoTable] or edx,edx jz PropsCreate mov eax,edx @null: end;
Most of the time, this method will be executed very quickly. In fact, the
PropsCreate global function is called only once, i.e. the first
RecordProps method is called.
TSQLRecordProperties instance is therefore created within
function PropsCreate(aTable: TSQLRecordClass): TSQLRecordProperties; begin // private sub function makes the code faster in most case if not aTable.InheritsFrom(TSQLRecord) then // invalid call result := nil else begin // create the properties information from RTTI result := TSQLRecordProperties.Create(aTable); // store the TSQLRecordProperties instance into AutoTable unused VMT entry PatchCodePtrUInt(pointer(PtrInt(aTable)+vmtAutoTable),PtrUInt(result)); // register to the internal garbage collection (avoid memory leak) GarbageCollector.Add(result); end; end;
GarbageCollector is a global
which is used to store some global instances, living the whole process time,
just like our
TSQLRecordProperties was made therefore available
for each kind of
Feedback and comments are welcome on our forum.