So the course of this talk with most likely go into generating a totally dynamic address space and once again, end in another theoretical solution, to an overly complex problem. Defeating Rebasing ------------------------------------- Many operating systems with fault handling features and refined multitasking, reference address spaces with segments to permit these features and aid general performance. The majority of this behavior can be studied by following process creation and task switching. Start from the user API and step through until the entry point of the executable is reached. TEB: Thread Environment Block TIB: Thread Information Block PEB: Process Environment Block The TEB/TIB fs:[] segment references originated in the OS2 days and have since passed down into 9x client systems, and of course, Windows NT. During the process creation the PEB and TIB are initialized into the new virt and can be referenced by the fs segment. Modifying the address space referenced by fs and how fs is setup is possible... but by the time you're done you're designing a new operating system. As Ryan might say... It's all data ;) The data referenced in this delta can be referenced during a ret. You just need to find a set of bytes that forms the needed instruction. You may be able to modify this arena in a way that you can insert your own instructions. Maybe some of the TLS storage can be controlled by supplying malformed sizes in your exploit session... ;) Note: PEB locking pointers can be overwritten with format bugs and control structure based heap overflows. 7FFDF000 00010000 7FFDF004 FFFFFFFF 7FFDF008 01000000 <- Executable image base ;) 7FFDF00C 00071E90 7FFDF010 00020000 7FFDF014 00000000 7FFDF018 00070000 7FFDF01C 77FCF170 <- PEB fast Lock entry point 7FFDF020 77F8313C <- PEB lock entry point 7FFDF024 77F8316D <- PEB unlock entry point Brett Moore wrote me several months ago with a very interesting exploit concept using multiple writes. The first write you insert your needed instruction into writeable memory somewhere. The second write you overwrite some writeable entry point or hook, with the address of the inserted instruction. There's not much out there if you're interested in learning about the TIB and the PEB. If you really want to understand these structures and general loading behavior, learn Polish and Russian, then hit up some VX'er archives. If you end up talking to any of them, tell them that somebody is trying to stop exploits by rebasing dll's :) Rebasing... There's a reason why relocation sections exist. While doing your own relocations is possible, the design of such a system is extremely, and I'll say again, extremely complex. Just differentiating all the instructions from data is a fairly painful process. Maybe the ETCH guys did this at one point but as far as I know this has been a big hurdle in image modifcation for quite some time. Michal Zalewski provided some great examples of issue's you'll run into: MZ> Also, what if I wanted to pass a value 4325404 (0x42001c) to this MZ> function, and it is not a pointer, only looks this way? For example,some MZ> FOO_ASYNC flag is defined as 0x400000, FOO_LOCK as 0x020000, and voila,OR MZ> them and you have "a pointer". MZ> In other cases, say, with register calls, it is getting even nastier, MZ> because even if, one way or another, you managed to find out how every MZ> single function is going to use its parameters (not likely), register MZ> calls are still black magic. GetProcAddress ACL's... > > It is possible to intercept every call to GetProcAddress and determine > whether or not the call should be authorized based on a predetermined list > of known valid callers (runtime call stack analysis). Simply rewrite a micro GetProcAddress. GetProcAddress is basically an overstuffed RVA engine. This is defeated by "The payload brings the tools concept". Most userland hooking schemes can also easily be bypassed by using direct gates "Ex: Interupts Gates". You could also intercept a thread that has the neccesary privelege by snagging a hook in it's path. > This list of authorized callers must be constructed through the use of forensic profiling > tools in the case of other people's binaries, but can be constructed with > the help of additional API calls in the case of one's own code. Call a > profiling/tracing API before calling GetProcAddress. After compilation but > before deployment to production boxes you simply execute the code in profile > mode to generate a list of authorized callers. This list is then configured > as a static security setting adhered to by the security layer that sits > between GetProcAddress and the rest of the virtual world. Who's an authorized caller? Someone who has a "safe" caller address on the stack.... If a the attacker start's offering instructions to your CPU... kiss your ass goodbye. Research AV/VX trends from the late 80's and early 90's. -R Riley Hassell Security Research Associate eEye Digital Security [DOW]