Live data from Hacker News

Overriding C++ virtual functions at run time

blog.visionappster.com

31–39 of 39 posts

Re: Overriding C++ virtual functions at run time

#31

I was wondering whether such a thing is possible for JVM based languages and it turns out it is: https://stackoverflow.com/questions/8273685/is-it-possible-t...

In Java, you can write an agent and intercept when the bytecode for a class is loaded by the JVM by the Class Loader.

ASM is just a bytecode reader/writer/visitor library that can then modify it. You could also just do it statically by having the bytecode you want injected ready to go in an array or resource.

   if (className.equals("a/b/c/d$e"))
       return fixedClassBytecode;
   else
       return bytecode;
It's possible to create custom loaders (e.g., loading a class from an encrypted zip-file, or one that creates custom bytecode on the fly) and things which are trying to obfuscate what they're doing will have custom loaders, but this is a choke point that every class that's read in and instantiated must pass through.

Re: Overriding C++ virtual functions at run time

#32
In Objective-C, that’s called “method swizzling”, and better supported by the runtime. See https://nshipster.com/method-swizzling/

And of course, Common Lisp has “change-class” (https://www.snellman.net/blog/archive/2015-07-27-use-cases-f..., discussed at https://news.ycombinator.com/item?id=734025) and Smalltalk has “become:” (https://gbracha.blogspot.com/2009/07/miracle-of-become.html. Short discussion at https://news.ycombinator.com/item?id=734025)

Re: Overriding C++ virtual functions at run time

#34

> The C++ standard does not specify how virtual functions should be implemented. In practice, however, compilers generate a virtual function table and place a pointer to it as the first member of a class. wishful thinking: https://gcc.godbolt.org/z/qWEe9r

Not sure what you are trying to show, the object still has a vtable and is placed as the first member (and in your example, only) of the class, so that quote is correct. Obviously if you enable optimizations and one of those optimizations is avoiding the virtual call when the compiler thinks it isn't necessary, then sure you wont get a virtual call everywhere. But if your code is relying on implementation assumptions…

> Not sure what you are trying to show, the object still has a vtable and is placed as the first member (and in your example, only) of the class, so that quote is correct.

I would not say that it is correct - the "object"'s actual existence is only through the interpretation that is made of it by the functions that work on your bytes. There's no struct definition in compiled code, only functions that do something with memory at a given offset. I won't go as far as to say that "objects" don't exist once your code leaves C++'s abstract machine to enter the compiled code world... but quite close.

With that said, 4 out of these 5 functions completely (and rightfully) disregard the vtable so if you're relying on that behaviour to be in place consistently to, say, fix a security issue in a given binary... you're in for some surprises.

Re: Overriding C++ virtual functions at run time

#35
post #30

Earlier quoted context omitted.

The C++ standard is written in such a way that a vtable as the first member of a polymorphic class instance is the obvious way to satisfy the standard's demands. I don't think there is any mainstream C++ implementation that doesn't use vtables, although some older C++ compilers used a slightly different layout. The fact that inside a single CU an optimizing compiler can determine the targets of polymorphic dispatch s…

People might bring up that the only ABI that is "stable" is Itanium, while MSVC has historically broken ABI stability quite regularly until fairly recently (2017, iirc?). That said, so much software on Windows relies on vtable layout that breaking their particular implementation in the ABI would be a massive breaking change, so it's unlikely that it will happen.

I'm not a Windows programmer,but IIRC vtable layout is very thightly tied to COM so I doubt that MS has broken or will break this specific bit of the ABI anytime soon.

Re: Overriding C++ virtual functions at run time

#36

Earlier quoted context omitted.

Not sure what you are trying to show, the object still has a vtable and is placed as the first member (and in your example, only) of the class, so that quote is correct. Obviously if you enable optimizations and one of those optimizations is avoiding the virtual call when the compiler thinks it isn't necessary, then sure you wont get a virtual call everywhere. But if your code is relying on implementation assumptions…

> Not sure what you are trying to show, the object still has a vtable and is placed as the first member (and in your example, only) of the class, so that quote is correct. I would not say that it is correct - the "object"'s actual existence is only through the interpretation that is made of it by the functions that work on your bytes. There's no struct definition in compiled code, only functions that do something wit…

With "the object" i meant the bytes in memory that make up an object without taking optimizations into account which can ignore parts of it (since, as i wrote, those can interfere with what you are trying to do).

And yes, the compiler made 4 out of these 5 functions to disregard the vtable, but this is again something the compiler did that you have control over - if you are trying to take advantage of such implementation specific assumptions, you wont realistically use optimizations that break these assumptions nor write code that do not follow them.

The only place where this can break is if a library uses its own functions, those functions are inlined in some places and you want to hotpatch them. But that is an issue with hotpatching 3rd party code you have no control over in general regardless of language (it can happen in C too, for example), not just with vtable hotpatching.

Re: Overriding C++ virtual functions at run time

#37

Earlier quoted context omitted.

Not sure what you are trying to show, the object still has a vtable and is placed as the first member (and in your example, only) of the class, so that quote is correct. Obviously if you enable optimizations and one of those optimizations is avoiding the virtual call when the compiler thinks it isn't necessary, then sure you wont get a virtual call everywhere. But if your code is relying on implementation assumptions…

The article talks about vtable patching in scenarios where you might not be able to recompile the original target, which limits your ability to add unusual flags like -fno-devirtualize, or remove common optimization flags like -O3. Which doesn't make the technique completely useless, but raising this "obvious" important caveat - that it's likely to be an imperfect patch on it's own - when the article completely fails…

The scenario is just an example of where it could be useful, but what you describe isn't something that is unique to patching the vtable - it is something that can happen with any form of function hotpatching, e.g. a library might use its own functions and some of those might be inlined by the compiler, so if you try to hotpatch one of those functions not all uses of that function will be replaced with your own.

This is something that you should have in mind when hotpatching in general, but that doesn't make hotpatching any less useful.

Re: Overriding C++ virtual functions at run time

#38

Earlier quoted context omitted.

> Not sure what you are trying to show, the object still has a vtable and is placed as the first member (and in your example, only) of the class, so that quote is correct. I would not say that it is correct - the "object"'s actual existence is only through the interpretation that is made of it by the functions that work on your bytes. There's no struct definition in compiled code, only functions that do something wit…

With "the object" i meant the bytes in memory that make up an object without taking optimizations into account which can ignore parts of it (since, as i wrote, those can interfere with what you are trying to do). And yes, the compiler made 4 out of these 5 functions to disregard the vtable, but this is again something the compiler did that you have control over - if you are trying to take advantage of such implementa…

> this is again something the compiler did that you have control over

I've rarely if ever heard of patching vtables in cases where you have access to the code - it's always been about fixing a binary you cannot recompile with some LD_PRELOAD trick or similar

Re: Overriding C++ virtual functions at run time

#39
post #12

Earlier quoted context omitted.

In other words if your program relies on undefined behavior then make sure you look at your compiler's documentation and then you might be able to make it implementation defined.

The C++ standard is written in such a way that a vtable as the first member of a polymorphic class instance is the obvious way to satisfy the standard's demands. I don't think there is any mainstream C++ implementation that doesn't use vtables, although some older C++ compilers used a slightly different layout. The fact that inside a single CU an optimizing compiler can determine the targets of polymorphic dispatch s…

The layout of objects, including dynamic objects, is implementation defined.

Accessing them through reinterpret_cast is however undefined. Don't expect that compilers won't screw you over this.

Post reply on HN