How to boost PatchGuard : it’s all about gong fu!

In this post i will take a look at PatchGuard, at classic scenario of bypassing this protection and also at little bit diferent one. I will also examine new way (bust most probably not new, just reinvented cause it is too obvious and quite efective) how to locate & abuse page guard context and its behaviour.

PoC and some explanation of code, of its weaknes and points to research are included

Everyone who started playing with PatchGuard should read previous research, which gives good background and explanation how it works.

  1. Clasicall trilogy : PatchGuard1 & PatchGuard2 & PatchGuard3
  2. Mcafee whitepaper
  3. Early PoC
  4. other research

With this background, i started looking for PageGuard Context, and way how it is invoked in win8. (how easy is to find it, i will describe in next blog post). Here is some snapshots of context assembly code (whole dump is located on github along the PoC sources) :

decryptorinvokepatchguardpatchguarddrxidpatchguardsyscallcheck

Classic approach how to defeat PatchGuard is terminate it as soon as you can, but i think it is waste of its potential . Inspiration of idea, what to do with PatchGuard, come from writers of malware known as Goblin / Xpaj (btw. very well written piece of metamorphic file infector – in new era also bootkit functionality). They not terminate PatchGuard during boot, but instead of this they abuse its behaviour for protecting its own hooks! Which is quite briliant, because no-one is more suitable to protect your piece of code than windows protection mechanism – PatchGuard itself

So lets do it with minimal touch of system, with fine gain => lets hook SYSCALL! As you already know patchguard read MSR (intel – IA64_SYSENTER_EIP – 0xC0000082) and check it for consistency. But before that you need to handle some issues :

  1. locate PageGuard Context
  2. locate Syscall pointer saved in PatchGuard Context
  3. exchange it whithout pay attention of KeBugCheck ;)

It seems it is no such big deal, and really it is not ! First of all, take a look at 3exit points which invoke PatchGuard routine :

In my PoC I focused just at the first method hooking (nt!KiProcessExpiredTimerList+0x1fc) – and ofc there can be (and probably are) more such exit points which is necessary to hook for proper implementation of abusing PatchGuard -. Ok so lets go observe some behaviour :

and little windbg-output for observing:

As you can see, it is no huge number of different routines except PageGuard DereferedRoutine with bogus pointer… And this is the goal, when you are able to detect that now is turn for PatchGuard routine, with little research is very high probability that you are able to own it! And even detect PatchGuard routine will be in the future problem (a large amount of routine with bogus pointer, or more stealthy way for PatchGuard routine), i guess there will be always way how to detect it – generic or trough pattern …

  • LOCATION of PageGuard Context

Ok so main point is that, when you look deeper at final DPC routines which are suposed to resolve original pointer to PageGuard Context and its code, you can see interesting things calculated here :


As i said, this is probably not new ‘discovery’ – i did not find it anywhere, but it probably just means i did not search deep enough …; So from the code you have straight way how to locate PatchGuard context :

And also when you look at the third mentioned exit point, and keep eye on values from which are formed PatchGuard context address, you will trace smth like this :

So as you can see, when you are able to filter all exit points, then it should not be problem, in current state of PatchGuard, recognize if DerferredRoutine is related to PatchGuard and locate its context.

  • Position of Syscall pointer inside PatchGuard context

nt!KiDispatchCallout method snapshot, i post here mainly because it clearly describe how to pwn PatchGuard. First DWORD would be always patched at the same value – probably because try to handle one of bypass technique ? – and cause of nature of decryptor you know how to looks like also first QWORD (0x085131481131482e), and it means disclosure of XOR_KEY! And when you take a deeper look at PatchGuard decryption mechanism, you can play with it in your own :

(even without xoring it would be possible to gather this xor_key -xoring is just pretty shortcut –> just keep in mind you are at the same level as PatchGuard, in your hook you have the same data available, and you can debug – disasemble – just play with code which calc this xor_key)

Position of Syscall ptr is relative to main function of PatchGuard, and position of this main function is stored in structure describing its context :

  • Pwn PageGuard context

Two problems can raise when you try to patch :

  1. Code is encrypted
  2. Context is checksumed

But you known encryption mechanism, so you need just to implement encrypt / decrypt mechanism, and also Just Code and PAGEGUARD_STRUCT is encrypted, data are plain Second problem can be solved by disasembling checksum mechanism, and re-calc checksum on current data .. crc snapshot :

Problems & points to research:

  • PageGuard is not one-threaded so it is necessary to handle with all threads
  • Find out all exit points

Conclusions : PatchGuard is very nice piece of code, really challenging :) In my opinion there should be always way how to ‘defeat’ it (when you are at the same privilage level it is all just about gongfu ), but i guess thats not a point. Main reason in patchguard i see to force software vendors to avoid intercept kernel with hooks and altering key structures in undocumented way. But in this way of looking at problem, i did not come with idea why so much hardering. But i believe that it is interesting part of job for m$ developers, hide code, implement obfuscation, respond to new bypass techniques etc. – but it sounds familiar does not it ?

On the other side, when m$ do it also with anti-malware reasons, i am not sure that they do it effectively. Malware writers does not come to them with this kind of findings, instead of this they will implement and sales it. And when new bypass technique invented by malware writers would be uncovered what would m$ do next ?

… when they just update its patchguard it cause BSOD on infected machines =>users dont like bsod. With legitimate software vendors it is fault by 3rd party and user will blame crappy software. But in case of malware m$ will need to handle desinfection of system at first, otherwise they are screwed up by malware writers …

So i think PatchGuard is perfect for rule over software vendors, that they can not patch kernel, but not as malware protection. I think when m$ would to improve this code more efficiently they should to create some kind of competition like pwnium, but related to breaking the PatchGuard, it will gave reason for hardering PageGuard and it will be more fun

Leave a comment

4 Comments.

  1. Great job dude!
    I really enjoyed it. I am starting an analysis of new Windows 8.1 Patchguard and I found the work you have published very usefull.

    Thanks for sharing.
    Andrea

  2. In your reference itself, http://www.mcafee.com/us/resources/reports/rp-defeating-patchguard.pdf, it is mentioned how to use XOR magic to find PatchGuard Contexts.
    Nice work.

    • hi, thanks.

      in mcafee whitepaper is mentioned :

      * Initialize NTOS Timer Construct (allocated in PatchGuard context) with KeInitializeTimer. Select a
      random time value, select a random kernel’s Deferred Procedure Call (DPC) function from a list of the
      kernel’s DPC functions, call KeSetTimer, and time the execution of this DPC with a DeferredContext
      value as a completely invalid pointer value (by XORing the Context Pointer value with a random key)

      .. just found where is random key stored, nothing so inovative, but it helps with processing

  3. how does it work under win7 sp1 x64?is that “delay_execution” is a magic address?

    waitting for your reply ,thanks

Leave a Reply


[ Ctrl + Enter ]


Go To Top
Follow

Get every new post delivered to your Inbox

Join other followers: