On Tuesday 06 May 2003 06:50 pm, Ove Kaaven wrote:
Maybe this particular implementation, but C++ has other mechanisms that can be exploited. It might even be possible to bolt it on C++ native exceptions.
good point. For example, if we create a local object with a destructor that can call finally, we just implemented magical return-notification, since the language is guaranteed to call our destructor during unwinds due to an exception or a return... of course, the devil is most assuredly in the details ;)
Apart from the ugliness, what was wrong with hijacking the return address? It might be possible to put into the TEB any data you need that you expect will go out of scope by the time the hijacker-function gets invoked, I think.
Well, we could just memorize the stack between the frame pointer and the stack pointer, for example, and just put things back the way they were at some prior time,... this "remembering" trick would have to go at the beginning of the try block, however, which puts us in pretty dicey territory, a lot could change between the beginning of the try block and the exception, so now our frame is out-of-date, and the expected results are not achieved, i.e., local integers time-warp back to what they were at the beginning of the try block before the finally executes.
The only solution along this path that occurs to me is a frightening one: we assume (actually, we know, since this will only happen due to a return in the try block), upon invocation of our "interceptor" code, what happened: we were exeucting the try block, and the bastard returned. So we just act on the assumption that the stack frame is still sitting there, intact; we immediately restore frame-pointer, stack-pointer, registers, etc., say, from a setjmp() (not sure longjmp would do quite the right thing here, but maybe...), and branch to the finally clause or some perversion thereof. Then, when finally's done, we need to tear down everything back to what it was before we intercepted. (setjmp/longjmp should be fine for this second branch, into a secondary(?) JMP_BUF in the TEB), and continue on our merry way by magically returning the correct value to the caller... easy ;)
Seriously, I dunno, sounds pretty darn sketchy... we would need to be able to rest assured that the act of returning will not somehow mangle the stack on the way out, and that doesn't seem so clear to me...
Worth a shot, I guess....