Recent Posts

Tags

News

  • A blog about Microsoft Windows development, focused on kernel-mode driver development, the Windows DDK, WDK, and related tools.

    To elaborate on the copyright notice at the bottom: all content produced by me on this site is copyright and licensed as follows:

    <!-- Creative Commons License --> Creative Commons License
    This work is licensed under a Creative Commons License. <!-- /Creative Commons License --> <!-- <rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <Work rdf:about=""> <dc:type rdf:resource="http://purl.org/dc/dcmitype/Text" /> <license rdf:resource="http://creativecommons.org/licenses/by-nc/2.0/" /> </Work> <License rdf:about="http://creativecommons.org/licenses/by-nc/2.0/"> <permits rdf:resource="http://web.resource.org/cc/Reproduction" /> <permits rdf:resource="http://web.resource.org/cc/Distribution" /> <requires rdf:resource="http://web.resource.org/cc/Notice" /> <requires rdf:resource="http://web.resource.org/cc/Attribution" /> <prohibits rdf:resource="http://web.resource.org/cc/CommercialUse" /> <permits rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> </License> </rdf:RDF> -->

    Although I work for Positive Networks, this work is my own and is not connected with my employer in any way.

    <!-- technorati again --> <script type="text/javascript" src="http://embed.technorati.com/embed/8xz8dihr.js"> </script>

Community

Email Notifications

Other Blogs

General

Technical Resources

About Me

Archives

Kernel Mustard

Reflections on Windows System Programming
Steve Dispensa, MVP - Windows DDK

Hot Patching

Well, how frustrating is this... as far as I can tell, .Text completely ate my last post, except for a couple of sentences at the top. I've switched to writing these posts off-line (like a real blogger!), so hopefully that's the last time this will happen to me.

Some co-workers and I were discussing a change you may have noticed in recent Windows kernel binaries. Disassembling into a kernel function shows an odd-looking instruction at the top:

   lkd> u NtCreateFile
   nt!NtCreateFile:
   80570d48 8bff             mov     edi,edi
   80570d4a 55               push    ebp
   80570d4b 8bec             mov     ebp,esp
   ...

Notice the 'mov edi,edi' at the top - that would seem to be a creative no-op, and in fact, it is. This seemingly useless instruction is designed to enable a new capability for modern kernels: hot patching. Hot patching is designed to address the availablility requirements of modern servers (and workstations, for that matter), by enabling certain hotfixes to patch the live kernel and redirect function calls from the existing function into a replacement (or potentially a filter function, etc). Administrators need something like this to enable them to apply hotfixes in a timely manner, rather than having to wait for a maintenance window. The world is a better place when servers are patched!

Technically, this works by replacing those two extra MOV bytes at the top of a function with a jump instruction. Now, some of you may have noticed that, on x86, two bytes will only get you a short jump, good for 127 bytes in either direction. Clearly this isn't going to do it - you'd have to write the new function into memory that is probably occupied by another function, which is no good. However, a little extra searching reveals this:

   lkd> u NtCreateFile-0x10
   nt!NtOpenFile+0x55:
   80570d38 0f841afdffff     je      nt!FsRtlCurrentBatchOplock+0xf7 (80570a58)
   80570d3e e9cd440600       jmp    nt!FsRtlRegisterUncProvider+0x18b (805d5210)
   80570d43 90               nop
   80570d44 90               nop
   80570d45 90               nop
   80570d46 90               nop
   80570d47 90               nop
   nt!NtCreateFile:
   80570d48 8bff             mov     edi,edi
   ...

Well, just what we needed - five extra bytes in which to place a long jump (relative to the current selector). Those five bytes can get patched on-the-fly with the pointer to the real function. Because they're immediately before the MOV, they're in range for our short jump. The hotfix can then write a relative long jump into those NOP bytes that points to the replacement function.

This design is interestng for several reasons. First, Microsoft chose to use the "creative no-op", rather than two real NOP instructions, even though they then used five real NOPs for the long jump. The reason is easy - the MOV is called every time the function is called, whether it is hooked or not (or, more precisely, when it its not hooked). Because you could be talking about a measurable performance impact on high-traffic code paths, those two bytes should get executed as fast as possible, and with minimal side-effects. The mov is just what the doctor ordered - as a single instruction, it should execute faster than two consecutive NOP instructions.

Why didn't Microsoft just put the five NOPs in as the first bytes of the function (rather than using the short jump)? Again, the question is performance - they have optimized for the common case (the unhooked function), rather than the uncommon case. This costs two extra bytes per function statically, but they save you 2/3 of the instructions (assuming you reserved your five bytes with MOV / MOV / NOP).

One other question that came up was why Microsoft didn't just use Detours, or something much like it. Detours relies on disassembly to perform runtime hooks like these, and it winds up overwriting a number of bytes at the begining of the function to make this work. This is difficult, at best - the implemented solution is much more robust. The cost is an extra seven bytes per function, but it's worth it, IMO.

This is an interesting, and instructive, bit of low-level software engineering, where space, performance, and robustness must be balanced.

Comments

Steve Dispensa said:

To try out this functionality yourself, simply call NtSetSystemInformation with the Information Class 69 (SystemApplyHotPatch).
You'll need a large undocumented structure, and a handle to a file contaninga a special hot patch PE section with special hot patch data. Once you have that, not only can you patch the data, but you can also install Rtl Debug Hooks which will hook everything you need and notify you.

Best regards,
Alex Ionescu
# April 27, 2005 7:29 AM

Steve Dispensa said:

>>The reason is easy - the MOV is called every time the
>>function is called, whether it is hooked or not (or,
>>more precisely, when it its not hooked).

Actually it's about applying patches safely - if there were two NOPs the EIP in some thread at the moment when patch is being applied could point to second NOP which would result in execution of second byte of jmps as an instruction. But when there's a 2-byte instruction, you can always replace it with another 2-byte instruction, cause EIP points either at it or at next instruction (it's also SMP-safe, cause CPU will re-read instruction when it detects a write to any of the instruction bytes while)
# May 12, 2005 6:53 AM

Khurram Aziz said:

Over the last few years; rebooting Windows frequency is decreased. People have started making good installers....
# February 19, 2006 10:31 PM

Usermode Troubleshooooo..ting paper said:

反馈收集和回复===请您在这里通过添加评论留下您对这篇文章的反馈信息,我会及时整理并且回复。如果您的反馈不想让别人看到,可以点击右边的Email链接给我发邮件:
http://blogs.msdn.com/lixiong/contact.aspx...
# August 3, 2006 9:55 AM

Kernel Mustard » Blog Archive » Whence came function hooking? said:

Pingback from  Kernel Mustard  &raquo; Blog Archive   &raquo; Whence came function hooking?

# June 14, 2007 12:46 AM

» Hot Patching said:

Pingback from  &raquo; Hot Patching

# June 14, 2007 9:02 AM

» Hot Patching said:

Pingback from  &raquo; Hot Patching

# June 14, 2007 9:02 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)