Live data from Hacker News

Overriding C++ virtual functions at run time

blog.visionappster.com

21–30 of 39 posts

Re: Overriding C++ virtual functions at run time

#21
post #17

Earlier quoted context omitted.

Are you willing to share any info on how you got stuck with this project, and what this "codebase" was? Can you call it a codebase is it doesn't have source code?

I would guess a normal project that involves this would be making a hack for a video game

Games ship with symbols unstripped?

Re: Overriding C++ virtual functions at run time

#22

> 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…

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 to do so, is worthwhile. I promise you there's C++ programmers out there who weren't aware of how aggressive optimizers can be.

Re: Overriding C++ virtual functions at run time

#23
post #17
post #4

Had to go a step further in a project and patch static functions in a codebase with no source. It’s certainly enlightening how much you can do with just a symbol map and type info. I don’t think the articles vtable layout is entirely accurate for gcc though - usually you’ll get 2 destructors at the start of the vtable (assuming the first virtual func declared is the destructor).

Are you willing to share any info on how you got stuck with this project, and what this "codebase" was? Can you call it a codebase is it doesn't have source code?

I really cannot recall which library it was exactly. I worked on a project that had many proprietary dependencies. It might have been a GenICam camera driver that caused us a lot of other headaches as well.

Re: Overriding C++ virtual functions at run time

#25
post #14

Earlier quoted context omitted.

It's generally possible to rewrite loaded classes. Some changes are possible (e.g. replacing a method's body), others are not (adding new methods). The state of the art library for doing this at the application layer is ByteBuddy https://github.com/raphw/byte-buddy#changing-existing-classe... but this functionality is used by plenty of tooling - profilers such as YourKit rewrite methods to add telemetry - I've seen s…

When would you use ByteBuddy versus https://asm.ow2.io ?

ASM is far lower level than ByteBuddy. To write some ASM code you probably want to have some proficiency with the bytecode format itself (e.g. you're typically outputting individual JVM bytecode instructions ;(invokespecial,athrow,etc). Personally I'd probably always use ByteBuddy unless I had some very specific reason why not. For comparison, these two examples https://github.com/raphw/byte-buddy#changing-existing-classe... http://web.cs.ucla.edu/~msb/cs239-tutorial/ explain how to do a System.out.println wrapper around a method.

In one case, the developer writes `System.out.println`. In the other, the developer must individually get the static field System.err and push it to the stack, reference PrintStream's method println, including the arguments (Ljava.lang.String;)V. That means it takes an array of strings and returns void.

Re: Overriding C++ virtual functions at run time

#26
post #24
post #21

Earlier quoted context omitted.

Games ship with symbols unstripped?

Wouldn't that be useful for crash reporting?

The standard approach to this, at least on Windows, is to build the debug symbols into a separate database (PDB file), and reconnect the addresses to the symbol names on the back end. Microsoft makes tons of symbols available for their own code via a symbol server which debuggers can query by the combination of a module hash and a relative virtual address.

Re: Overriding C++ virtual functions at run time

#28
post #11

We were overriding non-virtual functions at run time in the 8-bit days. Even in the feature article's case it would be easier and more reliable to patch the GOT (since he's using ELF on Linux). It's hardly news but I guess it makes this common cracking technique more accessible.

Patching the GOT doesn't work for internal function calls, though.

Re: Overriding C++ virtual functions at run time

#29
post #21

Earlier quoted context omitted.

I would guess a normal project that involves this would be making a hack for a video game

Games ship with symbols unstripped?

You'd be suprised what games accidentally ship. I've seen everything from pdbs to unoptimized debug builds accidentally included. If you don't make those mistakes, you might still have std::type_info (or custom equivalents) / RTTI info and __FILE__ / __LINE__ spam from macros, that can still sneak their way in.

Suppose you fix all that - the game still has a good chance of including 1 or more scripting languages. They may be included complete in their original unobufscated glory. Or the bytecode might include unstripped debug information. Or the C++ script binding layer might still include unobfuscated string identifiers.

If you're clever, you'll rebrand this lack of obfuscation as being "mod friendly" ;)

Re: Overriding C++ virtual functions at run time

#30
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…

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.

Post reply on HN