10 ms·
Overriding C++ virtual functions at run time
- The_rationalist 6y agoI 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-to-override-a-method-at-runtime https://stackoverflow.com/questions/8273685/is-it-possible-t...
- MaxBarraclough 6y agoSo, is it possible? I get the impression you can create a new class using a bytecode-manipulation library, but that's not the same as modifying an existing class at runtime. I believe classes, once loaded by the JVM, cannot be changed. https://stackoverflow.com/a/43653466/ https://stackoverflow.com/a/43653466/
- CHY872 6y agoIt'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-classes 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 some security libraries attempt to add additional security related hooks.
- The_rationalist 6y agoWhen would you use ByteBuddy versus https://asm.ow2.io https://asm.ow2.io ?
- CHY872 6y agoASM 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-classes https://github.com/raphw/byte-buddy#changing-existing-classe... http://web.cs.ucla.edu/~msb/cs239-tutorial/ 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.
- danmg 6y agoIn 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.
- jcelerier 6y ago> 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 https://gcc.godbolt.org/z/qWEe9r
- topiolli 6y agoCool. Is this due to "final" and the fact that the compiler can figure out the target at compile time?
- MaulingMonkey 6y agoOne call site (the one that takes bar&) relies on the final to devirtualize. The other call sites merely rely on the compiler being able to determine the exact type involved at compile time to devirtualize.
- badsectoracula 6y agoNot 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 like having a vtable at the start of a class, then it should also make sure that this assumption holds by not trying to work around it (e.g. via final) and using compiler options that control that optimization (e.g. GCC has -fno-devirtualize). It doesn't make much sense to both try and take advantage of implementation details and work against taking advantage of implementation details at the same time.
- leni536 6y agoIn 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.
- jamesu 6y agoHad 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).
- greesil 6y agoAre 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?
- Google234 6y agoI would guess a normal project that involves this would be making a hack for a video game
- greesil 6y agoGames ship with symbols unstripped?
- diath 6y agoWouldn't that be useful for crash reporting?
- antiuniverse 6y agoThe 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.
- MaulingMonkey 6y ago
- rurban 6y agoAutoCad does this in their ObjectARX technology, with a fixed compiler version, to support user or vendor provided plugins to extend classes. At runtime. For decades.
- bitwize 6y agoAnd this is why despite trying real hard several times, they couldn't remove Autolisp completely...
- mehrdada 6y agoAs you might imagine, overwriting vtables in memory is a common technique to hijack control flow and making your program execute attacker's code in an exploit.
- saagarjha 6y agoPatching function pointers in general is very desirable thing to be able to do when writing these kinds of things. vtables are interesting because unlike normal C function pointers they can only be used in a standards-compliant manner in a few very limited ways, so if you’re implementing control flow verification you can really ratchet up the security for these. For normal C function pointers, sadly, the best you can do is usually very little, if anything at all. Especially because the use of non-compliant constructs like forging ordinary function pointers is extremely common in things like language runtimes.
- rootlocus 6y agoThis all fine and well for single public inheritance. Multiple inheritance and virtual inheritance don't generate layouts this simple.
- bregma 6y agoWe 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.
- saagarjha 6y agoPatching the GOT doesn't work for internal function calls, though.
- ppg677 6y agoFDO compilation will often de-virtualize and remove vtable indirection.
- Someone 6y agoIn Objective-C, that’s called “method swizzling”, and better supported by the runtime. See https://nshipster.com/method-swizzling/ https://nshipster.com/method-swizzling/ And of course, Common Lisp has “change-class” (https://www.snellman.net/blog/archive/2015-07-27-use-cases-for-change-class-in-common-lisp/ https://www.snellman.net/blog/archive/2015-07-27-use-cases-f..., discussed at https://news.ycombinator.com/item?id=734025 https://news.ycombinator.com/item?id=734025) and Smalltalk has “become:” (https://gbracha.blogspot.com/2009/07/miracle-of-become.html https://gbracha.blogspot.com/2009/07/miracle-of-become.html. Short discussion at https://news.ycombinator.com/item?id=734025 https://news.ycombinator.com/item?id=734025)