pyscripter 689 Posted November 4, 2019 (edited) In case this of use to anyone: Quite often you find a bug in Delphi RTL and you come up with a fix. Patching involves replacing the RTL procedure with a new patched one. To do that you can use your favorite patching routine or library (I use Detours), but you need the address of the original function/method. a) Patching a non-virtual public method This is quite straight-forward: type TMethodType = procedure ... of object function GetAddress: Pointer; var MethodPtr : TMethodType; begin MethodPtr := TRTLClass(nil).PublicMethod; Result := TMethod(MethodPtr).Code; end; Note the type cast TRTLClass(nil). b) Patching a virtual public method If for example PublicMethod is virtual the above type cast TRTLClass(nil) with result in access violation, since to resolve the virtual method you need to access Self which is nil. You could create a class instance and use that instead of TRTLClass(nil), but apart from not being elegant, in some cases this has side-effects (for example it may require a valid windows handle). The trick is described in this Stackoverflow question. function GetAddress: Pointer; var VMT : NativeInt; MethodPtr: TMethodType; begin VMT := NativeInt(TRTLClass); MethodPtr := TRTLClass(@VMT).PublicMethod; Result := TMethod(MethodPtr).Code; end; This is based on two facts. A class is a pointer to the Virtual Method table (VMT) and an Object structure has as the first field a pointer to the VMT of its class. c) Patching a private virtual method The trick this time involves using a class helper to access the private method of the TRTLClass type TPrivateMethodType = procedure ... of object; TRTLClassHookFix = class helper for TRTLCLass function GetPriveMethodAddr: Pointer; end; function TRTLClassHookFix.GetPriveMethodAddr: Pointer; var VMT : NativeInt; MethodPtr: TPrivateMethodType; begin // Adjust Self to point to the VMT VMT := NativeInt(TRTLCLass); Self := TRTLCLass(@VMT); with Self do MethodPtr := PrivateMethod; Result := TMethod(MethodPtr).Code; end; That's it. Edited November 4, 2019 by pyscripter 6 1 Share this post Link to post
Stefan Glienke 2002 Posted November 4, 2019 When you patch a virtual method you don't need to patch it using the technique to place a jmp into the original code you can directly patch the address in the vmt slot. For that you just need to have the index of the virtual method. Share this post Link to post
A.M. Hoornweg 144 Posted November 5, 2019 21 hours ago, Stefan Glienke said: When you patch a virtual method you don't need to patch it using the technique to place a jmp into the original code you can directly patch the address in the vmt slot. For that you just need to have the index of the virtual method. That's very interesting, could you show a small example? Share this post Link to post
Stefan Glienke 2002 Posted November 5, 2019 (edited) {$APPTYPE CONSOLE} uses Windows; type TFoo = class procedure Bar; virtual; end; procedure TFoo.Bar; begin Writeln('broken'); end; procedure FixedBar(Self: TFoo); begin Writeln('fixed'); end; var f: TFoo; p: Pointer; n: UINT_PTR; begin {$POINTERMATH ON} p := @FixedBar; WriteProcessMemory(GetCurrentProcess, @PPointer(TFoo)[0], @p, SizeOf(Pointer), n); // 0 is the virtual index of the method to be replaced f := TFoo.Create; f.Bar; end. The virtual method index can also be found out programmatically. Edited November 5, 2019 by Stefan Glienke 1 1 Share this post Link to post
David Heffernan 2345 Posted November 5, 2019 @Stefan Glienke Your code above (and in spring4d) uses WriteProcessMemory to modify executable pages. This relies on an undocumented implementation detail of WriteProcessMemory. Namely that it will handle the protection flags on your behalf. Personally I would prefer to use VirtualProtect with this sort of pattern: procedure PatchCode(Address: Pointer; const NewCode; Size: Integer); var OldProtect: DWORD; begin if not VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin Fail; end; Move(NewCode, Address^, Size); FlushInstructionCache(GetCurrentProcess, nil, 0); if not VirtualProtect(Address, Size, OldProtect, @OldProtect) then begin Fail; end; end; 1 Share this post Link to post
A.M. Hoornweg 144 Posted November 5, 2019 2 hours ago, Stefan Glienke said: {$APPTYPE CONSOLE} uses Windows; type TFoo = class procedure Bar; virtual; end; procedure TFoo.Bar; begin Writeln('broken'); end; procedure FixedBar(Self: TFoo); begin Writeln('fixed'); end; var f: TFoo; p: Pointer; n: UINT_PTR; begin {$POINTERMATH ON} p := @FixedBar; WriteProcessMemory(GetCurrentProcess, @PPointer(TFoo)[0], @p, SizeOf(Pointer), n); // 0 is the virtual index of the method to be replaced f := TFoo.Create; f.Bar; end. The virtual method index can also be found out programmatically. What I meant specifically is, how do I find out the index of a method in the VMT? Share this post Link to post
Stefan Glienke 2002 Posted November 5, 2019 Just now, A.M. Hoornweg said: What I meant specifically is, how do I find out the index of a method in the VMT? Either you know it by looking into the assembly for its call or look for the method pointer in the VMT. Share this post Link to post
pyscripter 689 Posted November 5, 2019 (edited) @Stefan GlienkeWould this approach work with classes derived from TFoo? Wouldn't you have to patch the VMT of derived classes? Edited November 5, 2019 by pyscripter Share this post Link to post
Stefan Glienke 2002 Posted November 5, 2019 (edited) Yes, and I never stated otherwise - I just pointed out that you can patch virtual methods selectively by replacing them in the VMT. inherited calls would also still call into the old method with that approach. FWIW the approach you wrote for private virtual method works as well for a non virtual method. In fact the technique of hooking methods by placing a jmp has nothing to do with how the methods are being called. Especially for patching known code (i.e. RTL and alike) I rather write byte scanning code for finding the place I want to patch - yes such code has to be changed when you migrate to another version. But with that you can patch any code even if it's hidden deep within the private section of some classes or in the implementation part of a unit. Edited November 5, 2019 by Stefan Glienke 1 Share this post Link to post
Remy Lebeau 1396 Posted November 5, 2019 6 hours ago, A.M. Hoornweg said: What I meant specifically is, how do I find out the index of a method in the VMT? You can use Extended RTTI for that. TRttiMethod has a VirtualIndex property. 1 Share this post Link to post
Stefan Glienke 2002 Posted November 6, 2019 18 hours ago, Remy Lebeau said: You can use Extended RTTI for that. TRttiMethod has a VirtualIndex property. Well, not if the method is private or protected Share this post Link to post
Remy Lebeau 1396 Posted November 6, 2019 3 hours ago, Stefan Glienke said: Well, not if the method is private or protected I can see that being true for Standard RTTI (TypInfo.pas), which is only generated for published members. But that should not be true for Extended RTTI (Rtti.pas), which sees everything, even private/protected stuff. That is why TRttiMember has a Visibility property. Share this post Link to post
Stefan Glienke 2002 Posted November 6, 2019 (edited) Check the $RTTI directive in System.pas ... - also there is no this or that RTTI. Stuff from Rtti.pas just puts an easier to use layer ontop of the pointer stuff from typInfo.pas Edited November 6, 2019 by Stefan Glienke Share this post Link to post
Remy Lebeau 1396 Posted November 6, 2019 1 hour ago, Stefan Glienke said: Check the $RTTI directive in System.pas OK, so the default is to expose only Public and Protected properties and methods, and all available data fields. That is still way more RTTI available than TypInfo.pas provides (only Published properties/methods). 1 hour ago, Stefan Glienke said: there is no this or that RTTI. Stuff from Rtti.pas just puts an easier to use layer ontop of the pointer stuff from typInfo.pas Rtti.pas uses TypInfo.pas internally for some of its RTTI, but there is a lot more RTTI made accessible by Rtti.pas than TypInfo.pas ever provided. Much of the RTTI in Rtti.pas does not go through TypInfo.pas at all. Share this post Link to post
kokoslolos 1 Posted December 6, 2022 Hi, I recently started learning and experimenting with method patching due to a crazy idea I had and wanted to implement in my framework, but I'm not sure I fully got how it works. I thought that by patching a class method, then any new instances of that class created would have a copy of the new patched method, but that's not the case, right? All new instances point to one single pointer and the information of the 'self' pointer is simply not accessible, correct? And that is why it doesn't matter whether the new method is a unit method or a class method. What I was trying to achieve, is to have a wrapper object around a third party class object and patch the wrapped object's method pointing to a wrapper's method. What I'm also wondering, is this even possible? And if yes, any of the ways discussed here us the solution or do I need the DDetour library, and if this library is able of such task? Just a simple example of what I would like to achieve, if it is possible though : TFoo = class protected procedure DoSomething;virtual; public procedure Something; end; TFooOpener = class(TFoo) end; TWrapper = class private FFoo : TFoo; public constructor Create(pFoo : TFoo); procedure HackedDoSomething; end; implementation constructor TWrapper.Create(pFoo : TFoo); begin FFoo := pFoo; end; procedure TWrapper.HackedDoSomething; begin TFooOpener(FFoo).DoSomething(); end; initialization Patch(@TFoo.DoSomething, @TWrapper.HackedDoSomething) ------------------------------------------------------------------ ... ... fFoo : TFoo; fWrapper : TWrapper; fFoo := TFoo.Create; fWrapper := TWrapper.Create(fFoo); ... // And when fFoo.Something then the HackedDoSomething would be called. fFoo.Something(); Thank you! Share this post Link to post
Remy Lebeau 1396 Posted December 8, 2022 On 12/6/2022 at 1:06 AM, kokoslolos said: I thought that by patching a class method, then any new instances of that class created would have a copy of the new patched method, but that's not the case, right? Not a copy, but the original. All object instances of a class have their own copies of data members, but they all share a single set of code, vtables, etc in memory. So, patching a method of a class will affect all object instances of that class. On 12/6/2022 at 1:06 AM, kokoslolos said: All new instances point to one single pointer and the information of the 'self' pointer is simply not accessible, correct? Not sure I understand what you are asking. Share this post Link to post
kokoslolos 1 Posted December 14, 2022 On 12/9/2022 at 1:42 AM, Remy Lebeau said: Not a copy, but the original. All object instances of a class have their own copies of data members, but they all share a single set of code, vtables, etc in memory. So, patching a method of a class will affect all object instances of that class. I always wanted to know how all these work in memory, if you have any readings or links to articles on the subject that you can suggest I would very much appreciate it, I'm very eager to dive in these topics and learn more. i.e. The instantiation of a class to an object, you say they share the same code but different data members, so when multiple threads are using different objects of the same class how does the OS handles it? Does it load a copy of the methods/instructions of the class in the CPU with the data members of an object? Or how are unit methods are thread safe when only accessing local variables, or how dll methods are loaded and also thread safe as long are accessing local variable. I don't know if it makes sense what I'm asking :)! On 12/9/2022 at 1:42 AM, Remy Lebeau said: Not sure I understand what you are asking. I'll try to explain what I was asking at the end of the day, it's what the pseudo code is trying to achieve, having an A instance of TFoo method hooked and patched by another B instance's of TWrapper method, and when I call A.Method() it would actually call B.HackedMethod, but during my tests I realized that it isn't that simple and that's why I wrote my previous post asking for confirmation if what I realized was correct :). During my tests I did a patching this way, Patch(@TFoo.DoSomething, @TWrapper.HackedDoSomething) and during the call of A.Method(), it would execute without access violation even if I hadn't created an instance of TWrapper, and there is when I realized I was going the right direction and that I couldn't access the data members of the instances, for example the self pointer or FFoo of TWrapper. I finally managed to achieve this using the DDetours library, it's pretty amazing of what it can do :)! Hope what I wrote makes more sense now :). Share this post Link to post
Remy Lebeau 1396 Posted December 14, 2022 5 hours ago, kokoslolos said: i.e. The instantiation of a class to an object, you say they share the same code but different data members, so when multiple threads are using different objects of the same class how does the OS handles it? The OS is not involved in this process. 5 hours ago, kokoslolos said: Does it load a copy of the methods/instructions of the class in the CPU with the data members of an object? Instantiating an object is simply a matter of allocating a memory block to hold the data members, and then calling the class constructor on that memory block to initialize the data members. Any methods called on an object (including the constructor and destructor) is simply a matter of making a normal function call with a pointer to the object as a (hidden) parameter so the code knows which object is being act on. There are no copies of the method instructions being made. There is only 1 copy in memory that all objects share. Calling the same method on multiple objects will execute the same code instructions just with a different object parameter. 5 hours ago, kokoslolos said: During my tests I did a patching this way, Patch(@TFoo.DoSomething, @TWrapper.HackedDoSomething) and during the call of A.Method(), it would execute without access violation even if I hadn't created an instance of TWrapper It will fail if the patched method tries to access any data members that don't actually belong to the actual object that the method is being called on. Share this post Link to post
CoMPi74 3 Posted February 20, 2023 On 11/5/2019 at 11:14 AM, Stefan Glienke said: {$APPTYPE CONSOLE} uses Windows; type TFoo = class procedure Bar; virtual; end; procedure TFoo.Bar; begin Writeln('broken'); end; procedure FixedBar(Self: TFoo); begin Writeln('fixed'); end; var f: TFoo; p: Pointer; n: UINT_PTR; begin {$POINTERMATH ON} p := @FixedBar; WriteProcessMemory(GetCurrentProcess, @PPointer(TFoo)[0], @p, SizeOf(Pointer), n); // 0 is the virtual index of the method to be replaced f := TFoo.Create; f.Bar; end. The virtual method index can also be found out programmatically. @Stefan Glienke Should this also work for 'AfterConstruction'? Share this post Link to post
Stefan Glienke 2002 Posted February 21, 2023 Yes instead of 0 it will be vmtAfterConstruction div SizeOf(Pointer) Share this post Link to post