Abusing the NT Kernel Shim Engine
Ionescu, Alex
The Kernel Shim Engine is the kernel’s analogue to the user-mode shim engine (ShimEng). Although the latter now has had some pretty good research done on it, the KSE remains a mystery. First introduced in Windows XP as merely a Plug-and-Play compatibility layer for custom registry flags, it morphed into a nearly-full blown Shim Engine implementation, with the ability to misuse it for both persistence and stealth hooks in the kernel. In this talk, you’ll learn how to use the KSE for hooking drivers (dispatch tables, IRPs, and entrypoints) as well as kernel APIs both legitimatelly and illegitimately. You’ll also see some WinDBG scripts & techniques for detecting and enumerating installed kernel shims for forensic purposes. Finally, a tool called DriverMon is planned for release at the conference, which uses the KSE to provide ProcMon for Drivers.
 I'd like to welcome someone who's participating in recon for the very first time. I apologize for the transitions in the slides. I just realized now that the company template has transitions, which I hate, so sorry for that. I'm going to be talking about the kernel shim engine in this talk and I'm going to do a brief introduction about myself and presentation. Then we're going to look at what exactly the shim engine is, what it does, how does it shim. We're going to look at how you can write a shim driver or how existing shim drivers function. And we're going to take a look at a few examples of existing shims that exist on the operating system. Now because shims in the kernel are undocumented, there's not any tools, there's not any debugger extensions, there's no symbols for actually understanding what's being shimmed and who's shimming what. So I'm going to show you some WinVac scripts, some registry keys, some event log functionality that we can then use to figure out what shims are active. So if you're doing IR, if you're doing endpoint protection, if you're trying to understand what's going on, hopefully that'll be useful. Then I'll be doing a demo of a tool called DriverMon, which is built on top of the shim engine in which we plan to release in about a few weeks time. Then we'll conclude and do some Q&A. So a little bit about myself. I'm a chief architect at CrossStrike right now before I worked on the Apple Core iOS team. So I'm a big fan of operating some internals, both Windows and Apple. So I'm a co-author of the Windows Internals books. I've been doing a reverse engineering for about 15, 16 years now of the empty kernel. Far too long. I wish it would just die. But anyway, it's still around. So I do a lot of conference speaking about design issues in Windows or undocumented modules in Windows. Things that are fun to poke at, things that can give you interesting levels of access or interesting kinds of persistence or hiding or things like that. So this isn't the same kind of realm as that. Someone who's not presenting with me today is Robin Keir. He's a fellow coworker at CrossStrike and he helped with the DriverMon tool immensely. He actually rode the whole GUI for it. So when we do talk about a DriverMon tool, that's all really his work. So I took care of the driver and the internals, but big thanks to Robin for doing that. So basically, we're going to be looking in this talk at another component in the kernel that's not very well known called KSE, the kernel shim engine. And if you attended last year's recon, I gave a talk on binary instrumentation technologies and hooking. So how from user mode you can hook binaries using a shim engine and using other technologies. So in a way, this is kind of a follow-up because I figured, well, all that was user mode, can you do some of this stuff from kernel mode as well? So we're going to talk about a way that you can now hook any Windows driver using a legitimate interface. So without actually having to patch your own IAT entries or hook the driver object. So this is going to let you hook IAT entries, so imports. It's going to let you hook herbs. It's going to let you hook driver callbacks. And it's actually a really nice interface to program against. You just kind of tell it what you want to hook and it does it all for you. The trick, of course, it's undocumented, so you have to figure out those data structures. Then we're going to talk about how to, again, forensically look for shim providers. So what's already on the machine? What's it shimming? Are there things that should not be there by default? And we'll talk about something interesting, which is how you can actually hook the hook engine itself or hooking the shim engine, which has some interesting kind of bypass properties. And we're also going to look at some built-in shim providers, built so you can kind of know what's already on the machine. So if you have a shim that's not on your machine, that's interesting. Or if you have a shim that is on your machine, but that's not on the list of default shims, well, then you have a third-party shim and you really shouldn't accept the tool that we're releasing. And then I'll talk about this shimmer tool that I wrote and kind of how a driver can register with the shim engine and how to interact with it. And then I'll do a demo of the driver mount tool, which I think will be pretty cool. So let's talk a little bit about how the kernel shim engine actually does its work. So basically, the whole point of the kernel shim engine is to provide two types of shims, or app-compact. Whenever you say shims, we always talk about app-compact behavior, basically. And there's device shims and driver shims. Device shims are basically ways to apply flags or specific policies to certain devices, identify by their hardware ID. So you have some particular kind of USB device or some particular kind of PCI device. And different bus drivers, like the PCI bus driver, the USB bus driver, and also class drivers, are going to be checking what flags are active for those devices. And so, for example, if you have some sort of weird USB device that requires one millisecond instead of half a millisecond to initialize itself, there's going to be a hack flag that basically says, you know, required, but flag number four. And it's associated with this hardware ID. This way, the driver sees, oh, you've got a device that has flag number four active. Well, that means that I have to wait a little bit longer when re-initializing the device. So this has been there since Windows XP, under the guise of app-compact. Then, this thing had the Erota manager, which kind of does the same thing. And then in the registry, you have sometimes flags called PCI hack flags or things like that. So it's really yet another way for device drivers to be able to identify if there's some sort of weird device on the machine. The second kind of shim this provides is driver shims. And a driver shim is basically a file name, a path to a driver that you would like to hook. It's imports, it's callbacks, or it's IRB handlers. So it does both driver shimming and device shimming. Basically, during the IMAG initialization, this thing initializes in kind of two phases. So there's a function called KSE initialize, which does that. And it parses the same STB database that you might already have heard about in terms of app-compact shims and IE shims and other presentations that have been done. So the exact same format that's used for user mode shims, MSI shims, is also used for kernel shims as well. Now KSE will not initialize if you're in save boot. It won't initialize if driver verifier is enabled. It won't initialize if there's actually no database, like you deleted it off disk. And it won't initialize if you're booting in Windows BE mode. So like in recovery mode, there won't be any shims either. This shim database is called driver main.sdb, and it's located in the same app patch directory as everything else. And it appeared in XP. And in XP, again, there was no kernel shim engine, but there was this app-compact engine where you could have certain flags. And with changes in Windows 8 with the kernel shim engine, it's the ability to have driver shims as well. So this is loaded very early on by winload.exe, which is orb.efi, which is your Windows bootloader. It looks in system 32.cwindows.apppatch.drvmain.sdb, and it loads that. And then it also loads the irata-manager.inf file, but we're not going to talk about the irata-manager here. It then stores in a loader parameter block extension, the base address of the shim database, and the size. This point is already loaded in memory, and in all cases, it has to do is now just parse it from memory and look up all of those data structures. And when you have user mode shims, you can tag, you can associate a user mode shim with a particular binary. What's cool in the kernel shim engine is you can associate a shim with a particular type of device. So you can say, if you have this type of ACPI table, and you have this type of BIOS, and this type of CPU, then this shim applies to you. So it does some of that look up in there as well. So device shims are basically exposed to three APIs, KSE Query Device Data, KSE Query Device Data List, KSE Query Device Flags, and device flags are basically a subset of device data. They're the XP flags that always existed. The XP flags became a subtype of the device data. Now this device data can actually be queried from user mode. So those functions are kernel functions, but if you call anti-query system information, which is a well-known Windows undocumented API for getting all sorts of interesting things from the system, you can pass in those two information classes, and that's going to give you the device data for a particular device. And device data, again, it's flags, policies, things that make this device interesting or unusual compared to other devices so that its driver can basically react to those differences that the device might have. The other place device data can come from is the registry. So device data can either come from the SDB database when it's loaded off the disk, or it can actually come from registry. And in the registry, you basically have this Reggie registry machine Windows system, current control set, control compatibility device, and you take a hardware ID, which is like USB ampersand, some number, slash, bus ampersand, some number, you replace all the slashes with banks, and if there's anything in there, that means there's device data for that device path for the hardware ID. If it's not in the registry, they're going to look up in the cache because all this device information is cached, and if it's not in the cache, then they're going to look in the SDB. And in the SDB, basically if you're not familiar with the SDB format, which is now documented, and there's lots of tools to dump it, everything's identified by tag, attack or response to a given data type. So there's a tag 7013, which is a flag, which is read by read read Kflag, and there's another flag called Kdata, which contains just arbitrary value pair data. So Kflag, there's a few of those in the SDB file, and I'll show you some dumps. Kdata, I haven't found anything in my Windows 10 driver main, so it's implemented by, I haven't seen any data other than flags that is at least in the inbox SDB that I've got. So who actually reads device data or device flags? You've got a Bluetooth driver, port driver, and numerator, the audio driver, the audio bus driver, the Bluetooth hit driver, the generic hit driver, and this, which is the network driver in Windows, UFX synopsis and URSCX, which I'm not sure what those do. I think it's another type of Bluetooth type stuff. And then USB hub, which is the USB driver. So all those, basically what that means is that all those drivers recognize that some devices that they manage are strange, and the device flags, if they match particular hits on your machine, these drivers will act differently. So either fixing iradas or working around a hardware bug that might exist. Kc also implements a hardware ID cache. Not 100% sure what this is used for, but basically anytime a driver, anytime a plug and play discovers a new device, it's going to capture the whole hardware ID and then adds it into another cache database. And then there's an app help function, NT app help cache control that you can call from user mode, which is used by the application helper service. And then this basically lets you query the hardware ID. So it's a very simple way of knowing, is this hardware present on your machine? Because all the plug and play hardware is enumerated in a, in this cache, and then the application helper and user mode can just call it and say, dump me all the hardware IDs or tell me if this hardware ID is present. Kind of weird because the plug and play manager already knows and there's APIs for doing that, but you know, this is Windows. There's always like 10 different ways of doing something and 15 different things that store the same information. So that's another thing you can dump from user mode, basically all the hardware IDs on the machine. The other stuff this does then is driver shimming. And there's some built in driver shims that you have as soon as KAC initializes. One of them is called driver scope. So driver scope is a built in shim and it hooks all driver callbacks. It hooks IocTools. It hooks create and close herbs. It hooks power herbs and it hooks plug and play herbs. It then hooks Iocray device, PO request power herb, X allocate pool, X free pool, and basically when this shim is active, all it does is hook all those things and it just prints out over ETW, which is event tracing for Windows, which is kind of Windows' internal tracing mechanism. Anytime that happens. So just kind of hooks those things and tells you that it happened. As the name suggests, you have a driver scope, kind of like a scope for drivers. We're going to see driver scope is never active on anything by default, but it basically means if you activate it and we're going to see how you can activate a shim, you get some ETW events. Then there's another three set of shims, Windows 7 version lie, Windows 8 version lie, and Windows 8.1 version lie. And as you can probably imagine, these are going to hook RTL get version and PS get version. And each particular hook will return a different version. So just like in user mode, you can enable XP compatibility mode or Windows 7 compatibility mode. This basically lies to the driver and makes the driver think we're running on a different operating system. And there's another one called skip driver unload, which kind of worries me. Basically that hooks your driver unload function and just doesn't call it anymore. It just prints out ETW. Yeah, I'm not going to bother calling the unload for this driver. That is not active on anything by default, but you know, it's an interesting one. So how do loaded drivers get shimmed? Well, whenever a driver gets loaded, which either is going to happen by IOP initialize built-in driver, MI compact service table or MI driver load succeeded, KSC driver load image runs. This will then do two things. It's going to get the shims for a particular driver and then it's going to apply the shims for that driver. Once the driver has been shimmed, you get an event trace and we're going to see how you can look at that in event log. There's a variable in the kernel. We're going to see that basically points to the last driver that got shimmed and you get some flags as well that tell you a shim is active. So when we're going to look at introspection later with some currently bugging scripts, we're going to see side effects of basically that being enabled. At that point, whenever a module is now being shimmed, it gets added to the shimmed driver list and there's a function called KSEP is module shimmed. And this is basically going to record the load address of every driver that has been shimmed, the number of shims that this driver is currently that have been applied to this driver, and an array of all the shims that have been applied. So if you're not already shimmed, then we're going to search the registry to see if there's any applicable shims for your driver. And we're going to see how the registry basically allows you to shim a driver. So this happens with KSEP Engine gets shims from registry and KSEP registry query driver shims. Now, if the registry says that you have a shim called foobar registered for this driver, we're going to look in the SDB in the database, is there a shim called foobar? So the database actually has to define all possible shims. A shim then has a shim descriptor called a Kshim, which basically tells us the name of the shim, the GUID of the shim, and the module that should be providing the shim. So the driver, that's actually going to be doing that. Another possibility is there's nothing in the registry, and there's nothing in the registry, then the SDB file itself can have what are called Kshim references, and can basically identify this driver and that driver and this driver need to be shimmed by that shim, and then the shim is defined in the SDB as well. So I can either shim a driver by putting that in the registry, or I can shim a driver by putting that in the SDB. And then each shim is described, like I mentioned, by a GUID, a name, a command line, and also a source. So you can know, was this driver shimmed because of the registry, or was this driver shimmed because it was in the SDB file, which again is useful once we go and dump these things in memory. Now, once we've identified that a shim is active and correctly defined for a driver, we're going to be resolving the shims. So we're going to see, is that shim for smaller registered? Because for a shim to be registered, that means a provider ran the provider, the shim provider, registered that shim and says, I provide shim called foobar with the GUID, you know, so and so. Now, it's possible that a shim provider hasn't yet loaded. In other words, you're loading the driver before you're actually loading the shim provider. Now, that's what we're going to check is this shim, a delay load provider. If it's a delay load provider, we're actually going to go and load the provider name manually by basically seeing what's your name and calling the ZW load driver and loading that driver. Once the provider has been loaded, we're going to dump all the registered shims again, and at this point we should expect to find that shim in the driver list. Otherwise, something's wrong. Basically means that, you know, this module for whatever reason is not providing the shim that it's supposed to. If it is, the next thing that happens is we're going to dump all the loaded modules, because one of the things that shims can do is hook IET entries of any driver. So we're going to dump all the drivers that exist, and we're going to see, does your shim hook any of the drivers that this driver might import? Right, so I have one driver that's basically, you know, foo.sys. It's importing from bar.sys, and your shim driver is basically saying, bar.sys as function has to be hooked. So we're going to see, is there a bar.sys loaded? If there is a bar.sys loaded, does it have the function you're trying to hook? And if the function you're trying to hook exists and bar.sys is loaded, then we're going to go ahead and apply the shim a little bit later. We're not yet applying the shim, we're basically just checking, do the shims actually resolve to anything? Because if there's no bar.sys, or this version of bar.sys is not exported at API, well then your shim can't hook anything, so we basically can bypass that. If not, your driver is now ready to be shimmed. In other words, we have found a shim that's valid, we have found all the things shim wants to shim, and all the exports exist. So we're ready to proceed to the next stage, which is going to be applying the driver shims. So it happens with a separate function, ksep, apply, shims to driver, and this is going to go in ksep, patch, driver, imports table, which calls ksep, patch, import table entry, which then calls mmReplace, import entry. So the marry manager has a whole bunch of functionality now to basically safely and correctly patch IET entries, take care of the section objects, and all that. At that point, your shim provider gets a call-out notification, which we're going to talk about later, which basically tells you, okay, you are now shimming this thing. But the only thing we've shimmed so far are functions, IET entries. And there's two, or really three types of things shims can take care of. You can shim the exported functions of a driver, but you can also shim the callbacks that a driver receives. And right now we haven't done any callbacks, because all we've done is we've loaded your driver. We haven't yet initialized it. So once your driver actually initializes, which is done by IOP load driver, or IOP initialize built-in driver, then we call ksep shim driver IO callbacks. This will now call ksep get shim callbacks for driver, and it's going to hook your driver callbacks, driver in it, driver unload, start IO, add device, and then it's going to hook all your IRB handlers based on whatever my shim describes. So two stages here. First stage, hook the imports as soon as the driver loads. Second stage, hook the callbacks and the IRBs as soon as the driver is initialized. And then the shim is fully active. So let's see how we can write our own driver that basically makes a shim engine do all the stuff for us. So the first thing we need to do is define a ksep shim. Again, a shim is a compatibility fix. A compatibility fix is a set of functions we have to hook, and callbacks we have to hook, and IRB handlers we have to hook, and by hooking all those things, the idea is we're providing, we're fixing, we're working around some sort of bug in this driver. So the structure's not documented. It's basically my own definition of it. Fairly is the reverse. So basically you have the size of ksep shim, a GUID, and a name. Now the name of the shim that you're registering, and the GUID of the shim you're registering, must match one of the shims in the sdb file. And the sdb file has your shim name and your GUID. So you can register, I mean you can register an arbitrary shim, but nothing will use it because the sdb file won't actually match up to that. Then you get some callback routines, and we'll see what those are useful. And then you get two notifications. One when your driver has been targeted, so when you've actually loaded, not you, sorry, when one of your drivers is shimming has been loaded, and another one when one of the drivers is shimming has been unloaded. And then you pass in an array of hook collections. What's a hook collection? Well, a hook collection is basically a type of hooked entity, and there's two entities you can hook, functions or driver callbacks. And functions can either come from NT, they can come from the HAL, or they can come from an arbitrary driver. So 0, 1, and 2 are used for function hooks. If you said that they're coming from an arbitrary driver, then you have to pass in the name of the driver you're hooking. Otherwise, if it's an NT hook or HAL hook, well, we all know the name of those things are, so you don't have to bother with that. Otherwise, type 3 is a callback, and a callback means you're hooking either a driver callback or an ERP handler. And now you define the collection of hooks, and you now have to go and actually define the hooks that make up this collection. So that's now with another structure. And kind of repeatedly, that structure has its own type, 1 for function or 2 for callback. And if this is a function, you have to give it the function name that you're hooking. If this is a ERP callback, you give it a callback ID. I'm going to see what the callback IDs match up to. You then pass in the address of your function that's going to be hooking that thing. So the hook function there, that pvoid, is a pointer to your hook. And in original function, you get a pointer back to the original function that got hooked, the idea being that if you do want to hook the original function, you call original function and then life goes on. But that is only filled out if this is a function hook. If this is an ERP callback hook, that actually doesn't get filled out. So we're going to have a problem. We're going to see how to deal with that. So how do you hook a function? Well, again, fairly easy. You look at what you're trying to, what exports a thing. If the exports Entos kernel, you create a collection of type 0. If the export is hal.dll, you create a collection of type 1. And if this is a custom driver, you create a collection of type 2 and you put down your driver name. So I have a very simple example here. If you're trying to hook xallocate pool tag, you say 0 because xallocate pool tag is an Entos kernel. You put in the name xallocate pool tag and then you give it a pointer to your hook of exallocate pool tag. And then null, that's where you're going to receive the original xallocate pool tag. So then your hook function, you do whatever you want to do because you're hooking xallocate pool. And then you return hooks 0 original function. Basically then call the original function that's there. Or maybe you'll just decide, nope, I'm not going to allocate any memory for you, which would probably be bad. Now, one of the things you might want to know inside of your hook is if I'm hooking multiple drivers of the same shim, what driver is actually calling xallocate pool? So there's no kind of built in way of knowing that, but you know you've got an interesting visual studio called underscore return address, and they'll give you the return address of whoever called you. So that way you can tell what driver actually is hooking exallocate pool. So if you want to filter on certain drivers only, you can do that. Obviously if you're only shimming one driver, then you don't need to worry about that. So what about hooking callbacks? So there's four callbacks you can hook. You can hook driver in it, driver on load, driver start IO, and you can hook add device. Or you can hook every IRP, which are IO request packets, which is how Windows actually does IO. So there's IOs for create, for close, for read, for write. There's up to IRPMJ maximum function IRPs. Interestingly, you can hook in you these things, except actually driver in it. Because if you go back a few slides, we said that we hooked all the functions as soon as driver loads, and then we hook all the callbacks as soon as driver initializes. So you can specify a driver in it hook, but it won't actually ever be called, because your hooks only get applied after driver in it runs. So kind of a design fallacy there. You can see I've got the pseudocode. We call driver in it, then we apply the hooks, and driver in it never gets called again. So we're never going to call your hooked driver in it. Oops. So we said that if you have a function, you get the original address. Now when you hook a callback, you don't actually get the original address filled out. Instead, what you're supposed to do is you're supposed to call this other function, KSE getIO callbacks, and KSE getIO callbacks returns to you the original callback. So kind of weird for functions, you get the address. For callbacks, you have to ask it what the address is. And you can ask it one, for the original address of driver in it, two for driver startIO, three for driver unload, four for driver add device, and for herbs, every herb has its own number. For example, IRPMJ create is zero, IRPMJ read is four or three, IRPMJ closes two. What you do is you add 100 to that number. So if you ask for 102, then you get IRPMJ close. If you ask for 100, then you get IRPMJ create. So one through four are those hard coded ones, and then 100 plus the herb identifier are the herb handlers. Now how do you call KSE getIO callbacks? Because that's actually not an exported function. Well, let's go back for a second here in our definition of a KSE shim. So there's this field here called KSE callback routines. Well, let's see the resolution screwed up. Anyway, this thing here KSE callback routines, that's where you actually get a pointer back to KSE getIO callback. So it gives you the function that you need to call. So that's how you find it, basically. And then you can call the original function. Now the other thing with herbs is that unlike function calls, which return immediately, herbs can either be returned immediately. But by the time they've returned, the herb has actually been completed, meaning that the other side has already received the answer, and the herb structure which contains the answer may have already been deallocated or freed. The other possibility is that the function cannot return immediately. In other words, this is an asynchronous I.O. So the herb will be completed later. So if you do try to read from the herb, there's no answer yet. So you kind of got two bad choices. You read from the herb and you'll crash because the herb is gone, if the operation succeeded, or read from the herb and get useless data because the herb hasn't actually completed. So what you actually have to do is register a hook for the completion of this herb. And again KSE gives you a function for that, KSE set completion hook. And you can say for this herb, I would like to hook its result so I can actually know what happened with it. And again KSE set completion hook is not an exported function. It's another callback that you receive in your shim. So your shim structure basically gets back the addisive KSE get I.O. completion callback. So you know what to call when you're done. And KSE set completion hook if you'd like to request a hook for the herb. Which is nice because that basically means you're going to have pre-operate pre-hooks before the herb actually gets processed by the driver. And you can have post-hooks after the herb has been processed by the driver. So for example for IRPMG write, in your pre you can see what the user mode app is trying to write. In your post you can see the write actually worked and if so how many bytes have been written. For a read, well when you see the read in your pre all you get is someone wants to read something. In your post then you actually get to see what was actually read. The other thing I mentioned you get is two callbacks, the shim targeting callbacks. And so whenever a driver is actually going to be shimmed by you, you get a notification from KSE saying you are now shimming this driver. And you get the name of the driver you're shimming, its load address, its size, its time stamp and its checksum. And when a driver is unloaded you get the same information back telling you this driver that you were shimming before is now gone. And so what's interesting now is with this information you can basically build yourself like a memory map of okay from here to here I have this driver is here, from here to here this other driver is there, from here to here I've got another driver. And then in your function hook when you get the return address you can scan is the return address in one of these memory blobs that I know about. Okay then this is this driver trying to call me and you have its name and its checksum from your targeting callback. For an ERP, well an ERP gets a device object, a device object points to a driver object, the driver object points to the star data of the driver. So again you can match up the start address of the driver that sent the ERP with the, sorry that's handling the ERP with one of the drivers you're targeting. And that way you can know exactly what drivers are you currently hooking in the middle of your ERP or in the middle of your function hook. So once you define all these structures how do you then register for a shim provider? Well there's a nice little export API for you called KSC register shim EX and you basically pass in that KSC shim structure which identifies your shim, your GUID, your name, the collections of hooks and the actual hooks and you pass in your driver object. That means that KSC will now take a reference on your driver and if you actually try to unload your driver while you're still shimming things it won't actually let you unload. So it's going to run through your driver on load but it's going to keep you resident in memory. So you're not going to be handling any new kind of IOs but anything that's shimmed will still go through you unless you unregister your shim and that thing then goes away as well. So this allows you to basically reference counting and making sure that you don't end up with a shim driver unloading while there's active shims which obviously will now call a null pointer or something worse. So basically these are the two things. If you unload and unregister your shim but drivers are still active you remain resident in memory. Similarly though it also means if you load your provider after the driver is already loaded you can't shim an existing running driver. So you have to reboot the machine and shim it at boot or unload the driver and reload it because if the driver already ran you were never registered so there was nothing to hook to begin with. So let's look at a few examples or at least one example of a built in actually not a built in but an inbox shim. So basically a not a third party driver but an inbox driver that's not the kernel that registers its own shim. Because basically by looking at this that's how I kind of understood how shims work. So in the built in database there's a number of interesting things in there and you can dump the database with STB Explorer, great tool. TZWorks has something they call shims which also lets you dump the shim database and then Microsoft actually has something called shim to XML or STB to XML which lets you dump the shim database as an XML file. And then in the shim database you're going to see app help entries which basically say this driver is not something we want to load so just block it and that's done in user mode actually. So that's one part of the shim engine that's not done by the kernel. It's done in user mode and the driver tries to install itself, you get a little pop up that says these drivers not compatible with Windows. Then you have K device entries and we're going to look at a few of these which are used by the device compatibility stuff. So any flags that need to be applied or any device data that's K device and then K driver is used by actual driver shims. So the driver shims are in there and then K shim are what shim providers are actually registered. And again every provider has to be in the STB. You can't kind of make up your own provider without any definition for it. So you can look at a few examples. I've got both the XML dump from one of the tools and the XML dump from the other tool. So there's one here that basically says this is a K device shim. So this is a device shim and the name identifies some sort of hardware. So if I have something from vendor 1B21 product 1 0 B 0 which looks like it's an AS media vendor. So some sort of USB 3 device made by AS media. It's going to apply the flag 4096 with the name USB. And the implication here would be that the USB class driver would then call KSE get device flags passing in the device ID over here. And the shim database would say, yep, I know this device. It's got flag 4096. And then 4096 to the USB class driver means something like again, you know, this device takes a longer time to initialize. So you should take longer as well. So the example of a driver shim is at the bottom. And this is basically saying that T s s safe dot sis a QQ game from Tencent. I love it when games load kernel drivers makes me feel really safe. This pops up a message that says a driver is installed that causes stability problems with your system. No surprise. And then it basically has, you know, the product version associated with that. So that's an example of an app help shim that basically says, yeah, we're not going to let you load this driver. It's it's bad. And later on, if we have time, I'll share some other examples. Again, these are just from the dump of the SDB database dumped with SDB 2x ML, which is that Microsoft tool. So what are the built in Windows shims and providers? If you look at the database, well, there's driver scope, skip driver unload KM version line, which are built in. Then there's two interesting ones called KM auto fail and auto fail, which are meant to be registered by KM auto fail dot sis and auto fail dot sis. But those don't actually exist. Then store port device ID shim and SRB shim are registered by store port dot sis, which is the Windows storage driver. USB shim is registered by USB D dot sis, which is the kind of the generic library that all USB devices use. And end is get version 640 shim is registered by endis, which is that driver allow drivers try to check which version of end is the wrong. So I'm guessing just like the version line, this allows and is the light driver and say, no, no, I'm not and this 6.6. I'm in this, you know, 6.4. Then in the registry, so mentioned certain drivers can be targeted. So by default on like a clean Windows then installation. If you go to the key there in the registry, the compatibility key. So under that sub key called driver and under that sub key, there's different driver names and might see in the screenshot. There's a few there that I've added, but the one that's there by default only is store a HCI dot sis, which is the HCI or you know, SATA storage driver. It has the SRB shim applied. So basically whenever you load store a HCI dot sis, it's going to be shimmed by SRB shim, which on the previous slide we saw that SRB shim is registered by store port. So store port access will be shimming store HCI dot sis. But that's only in the registry. So remember then the SDB can itself have other shim information. So just a few examples here USB shim hooks WSR RCI dot sis, edgerser 64 dot sis, ACF DCP 64 dot sis. So those driver vendors are doing something wrong and USB has to come in and kind of fix them up and this get version six portion. There's some real tech drivers in there. KM win eight one version line something called the frag FS sis in there. And there's other shims which are again loaded by shim by other things. So, you know, if I open up here the database that I've got SDB dot text. That's not the right thing. And anything that basically has K shim ref in there is something that's going to be hooked. So that's coming from can that's USB. That's the one we've seen. But here's one I didn't have in the slide. So for example, there's where is it Franklin. The resolution doesn't let me zoom in properly. There's a Franklin use excited driver and it is being shim by KM win seven version lie. So this driver needs to be told that one window seven. So again, just dump the database and you can see all these examples for your safe. Basically, and Windows update can obviously update is as the database and can add additional devices in there as an additional shims as they're needed. So let's look at one of those examples. Scuzzy port registers a shim to shims actually SRB shim and device ID shim. Both of those only should have one hook collection. It's a callback collection. And there's a single hook for that callback collection, which is the hook for IRP MJ device control. So any I octals sent to store port or through sorry through store HCI, which store port is hooking will be hooked. And there's a function device ID shim hook device control to hook I octals for the device ID shim. And there's SRB shim hook device control, which hooks the octals that SRB shim is okay. So SRB shim. What is it then doing? It's basically for any I octal that's I octal storage query property. And if you're querying standard property and the property ID is storage adapter property and you're expecting 32 bytes or more, then it's going to target this service and say, all right, this is interesting. So I want to register a completion callback or completion hook. So in the IRP completes, then I want to be notified in the completion hook. What does it do? Well, it basically checks again, did we return 32 bytes or more and did we turn it successfully? And if so, we're going to go in and we're going to edit the actual. We're going to edit the actual SRB type and address type field. And we're going to set it to zero. So basically override this legitimate valid data that we received with zeros. So that's kind of interesting. Why are we doing this to poor store? HCI dot says, why are we clearing out these bottom two fields that, you know, we're legitimately returned. And so if we actually read them as the end, basically tells you that SRB type was added in Windows 8 and address type was added in Windows 8, meaning that an older driver that's interacting with store HCI wouldn't necessarily know about those fields. But then what's the problem? Like why would they have passed the size that is 32 bytes or more because the size of the structure without those two elements, if you count it should be 30 bytes. So the driver is asking for 30 bytes, it shouldn't get those fields. Why would a driver that doesn't know about those fields ask for 32 bytes? Well, if you actually look at the structure in Ida turns out that because of alignment, because you've got an existing word at the end of the structure and structures are four byte aligned, you have two bytes of alignment at the end. So the actual size of the Windows 7 structure is 32 bytes and the bottom two bytes are just padding. And so you might now instead of padding on Windows 8 get actually data that's there. So they zero out that data to basically pretend, no, no, that's still padding because you're a Windows 7 driver and you shouldn't know about those fields. So either that's because someone was, you know, expecting padding or hard, you know, reading the previous field incorrectly. For whatever reason, they're playing it safe and they're saying, you know, that driver will still see the Windows 7 structure. So that's an example of a shim, highly specific shim, but it's a really good example on, you know, how I could write my own shims after that. And all this was easy to analyze with basically all the symbols that are in Ida. So that's kind of how an inbox shim works. I want to show you how you can actually see the shims and introspect them. And there's different ways you can introspect the shim engine. Now, because there's actually no symbols, it's very hard to analyze at runtime what's actually going on. But if you have a kernel debugger and you have, you know, some scripts and the right knowledge and you've done reverse engineering, you can get a pretty good overview of everything that the shim engine has actually been doing. So I'm going to show you a few shims here. Hopefully they're going to work. Shim.ws, which is kind of, it's going to display some information about the shim engine on my machine. Shim.ma.wds, which is going to dump any modules that are being shimmed. Shimreg, which is going to dump any shims that have been registered. And shim cache, which can dump the shim cache. So either the hardware ID cache or the device data cache. So I'm just going to demo the scripts for now and clean them up, comment them a little bit, and I'll probably post them on GitHub later next week so you can actually use these scripts and learn from them and do your own introspection as well. So basically they all rely on this structure called KSC Engine, which is a global in the kernel. Again, not documented, but this is kind of what I've been able to reverse from it. So there's some flags, some state information. There's a list of all the shim providers. There's a list of all the drivers that have been shimmed. And then there's the cache, the device cache, and the hardware cache. And then there's the last driver that got shimmed. And so the little script that will display the state of the KSC Engine. So let's try that. Shim.ws. And this is basically saying the engine is ready. Driver shims have not been disabled. Device shims have not been disabled. These are the address of the two callback routines that drivers can call. This is where the device cache is. That's where the hardware cache is. Here's the list of registered shims. Here is the list of shimmed drivers. And the last driver that got shimmed is afd.sys. And this is basically saying that on my system, afd got shimmed. And then there's some state flags, which are indicating, for example, that no group policy was found. So shims have not been disabled or enabled by group policy. They're just not configured. And active driver shim, which is indicating that something is shimmed. And there's a good sign of that, which is that afd is shimmed. So that's just kind of a global state about what's going on. At this point, I can, for example, take the registered shims list. And I'm going to dump it with a bang list and run a little script that should hopefully show what those drivers are. So that's shimmedreg.wds. So KSCDS shim has been registered. That's driver scope, but there are no active shims. So driver scope isn't active. Win7 version lie shim has been registered, but it's not active. Win8 version lie registered, but no active shims. Win8.1 registered no active shims. Skip driver unload registered no active shims. Store port SRB shim also not active device ID shim not active and the shim not active. Let me have a little error module load complete, but symbols could not be loaded for blah, blah, blah, blah shimmer dot sis. That's my stuff, which has two active shims. So shimmer is actually shimming two things. And then this is CS shimmer as a driver name. So we're going to see what that one's all about. And then USB de shim. So basically you can clearly see with the script that something's actually shimming the machine and it's, you know, the strange shimmer driver. All the built in shims that we've seen, they're not shimming anything at all. And so if we go back to the KSC structure, that what we just dump was the list of registered drivers or shimmers. Now we can see what's actually being shimmed. So that's a different list there. So let's try that one. So this is shim mod. That's the address of that list. Cross fingers. Okay. And two things are being shimmed. MP. So actually, so there's a shim module here. That's a bug. There are no not six billion active shims. But next one MPFS is being shimmed and there's one thing shimming it. And there's going to be a ray of all the things that are shimming it and in that array, you're going to find shimmer and then a of these being shimmed. And again, that's because of the special thing I've loaded, which I'm going to demo. So I can see all the shim providers and how many things are shimming and I can see all the shim things and what's actually shimming them. So that should be pretty useful. And then I'm not going to dump the shim cash, but it basically a bunch of hardware IDs at that point. So can you turn this thing off by the way or what are ways again, you can kind of interact with it. So there's a registry key called compatibility where you can disable device shimming or you can disable driver shimming. And if you go to the group policy editor GP edit, you can actually go, you know, when it's components device and direct compatibility and you can turn off device compatibility, which means no device shims, no flags, or you can turn off driver compatibility settings, which means no driver shims. Then there's a secondary registry key, which is in current control set control compatibility, which for your system, you can use disabled flags and disable flags. One means you're disabling driver shims, disable flags to means you're disabling device shims and both of them together, aka three means you're disabling both kinds of shims. Now from the debugger, there's a variable called case of debug flag. And if you set case of debug flag to a mask, you can then see all errors, all warnings, any information from the debugger, the kernel debugger, the kernel shim engine, because KSC has debug prints everywhere. It even has an array called case of history errors, which contains an array of all the errors and you get the file name and the module ID and the status code where an error happened. Then in the event viewer, there actually is a kernel compatibility log, and you can see, for example, event log entries when a device shim has been applied and tells you the source. So for example, on my machine, there actually is a USB device which has a flag applied to it, and it says apply through compatibility database. So the SDB on my surface has actually applied a device shim. There's another event log sample here which says one shim was applied to driver afd.sys, applied to the registry. And that's the shim that I'm actually going to demo, and that's part of the driver mon. So in the event viewer, by default, you can actually see these operational messages that are going to indicate to you if any shims are active. So you don't actually necessarily have to use the debugger. You get some information in the event log as well. Obviously with the debugger, you can actually see the driver because here all he says is this GUID has shimmed AFD, but what is that GUID? So basically with this ability to then be able to shim any driver, I came up and created this tool called shimmer. And it was very ugly, command-lay utility reminiscent of like pullmon, if you're familiar with pullmon, and basically just showed you the driver at the time, on which CPU, which pit, and which pit did something. And as a demo, I basically shimmed all the IRPs and the allocate and free pull functions. So I want to show this tool because instead of thanks to Robin, he built a different tool called drivermon. And drivermon basically was meant to kind of not replace, but be like prokmon. So if you're familiar with processor monitor, the ability to search, filter, and highlight operations, to do non-instructive filtering and boot logging, to be able to export to a CSV, to be able to decode different octals. And so I started working on a tool on a spare time, and we basically have a 1.0 release that's almost ready. We basically have to wrap up the UI, the ULA, the build, the signing, and all of that. And it should be on the community tools page. So if you're familiar with like Crowd Inspect or Crowd Response, it's going to be on that same page. I managed to avoid not having it be called crowd something, thankfully. And we've got a mailing list that's going to be set up to drivermon across trike, or you can just reach out to me on Twitter once the tool comes out if you have any kind of questions or feature requests or things like that. So basically this is what it looks like today. I'm actually going to be demoing it. But this is the pretty picture in case demo fails, because demo gods and all. So this is kind of showing you NPFS. Inside of search indexer, did a write. It wrote 14 bytes. Now I won't show you yet what those 14 bytes were, but you know, that's obviously wanted. Then search indexer allocated from the pool, a buffer. And then it read from a pipe, 1300 bytes as well. So because this is NPFS, these are implying that these are kind of pipe operations. But I'll show you some AVD dots, which would imply that these are metric operations. So let me actually run drivermon. Feel bad things fail. Okay, so I'm just going to hit capture. And it's starting to give us some stuff. So AVD, which is the Windows Winsock driver. So I can see that service host sent an octal. Then AVD allocate a Fritsa memory. Then we got a create, and then we allocated some memory. You know, if I run like explorer. Well, we've got a little bit more AVD from service host. On start menu, a whole bunch of stuff happened when I click on start. Now I'm seeing NPFS kind of got very, very busy. Let's see what happens when we run Chrome, because that'll be fun. Somebody might know Chrome uses named pipes for its stuff. So that's just Chrome sitting around doing nothing. But good thing Microsoft spends a lot of time improving their named pipe file system. Of course, I can stop the capture, which will stop at some point. The UI only really has one thread or two, because this is just like starving the app, nonstop with stuff. And I could close Chrome, and hopefully that'll help things a little bit. So this will stop at some point. Now it's just basically going over everything Chrome did, and I can kill the auto-scrolling, which would help a little bit. And now it's just going to keep on going and going and going, receiving. So this is just like Progma, so I can right click on Chrome, for example, and say, all right, thank you for letting me know that I did that, exclude process Chrome.exe and just excluded Chrome. So now I can see everything else except Chrome. So you know what, I want to see the principle is up too. So right click, thank you, includes poolSV. So I can see just what poolSV is doing with Spooler. I'm going to say include A of the only, thank you, and an I just A of the. So just like the normal filters you're probably used to with Progma. And then I can, of course, clear all the custom filters so everything should be coming back. Now I can also say, you know, processHacker, for example, it loads the driver. So I can clear all this and say, let's go hook processHacker, and I'm going to say, I think it's K processHacker2.sys and say, okay, turn on capturing. Now let me get rid of A of the.sys and get rid of NPFS.sys. Oh, looks like it brought the other one back. Okay, I'm going to have to work on that. So let's run processHacker. Okay, and then by autoscroll and clear, and let's reset the filters. Is it doing anything? ProcessHacker file. It might have renamed itself to processHacker3.sys is actually what I'm afraid of. So I'm trying to double check that file. Oh yeah, it's K processHacker3. All right, so let me just write it one more time. K processHacker3.sys. And then actually let me unload nets.sys.k processHacker3. Okay, edit, run processHacker, and make a sacrifice to them of gods. See if that actually works. Nope, oh well. Can't demo everything. So it would normally work when we figure out whatever is wrong with this thing. So hopefully that's the idea, and obviously the plan is to make it a lot more, you know, less buggy, and to be able to actually see what those buffers are, and decode the octals, and so on and so forth. But it gives you an idea kind of what we're aiming for here. So I'm going to skip the bonuses. But you know, you'll see this on a slide, but basically you can hook the hook engine, which is what I found out kind of the last minute. So those are bonus slides that you'll have online. And so let me just conclude some concluding thoughts. So basically one of the questions you might have is how is the shimmer tool able to shim arbitrary drivers? Because we said that if a shim is applied to the registry, it has to match a shim in the SDB. And I haven't modified my SDB to say that there is now a new shim called shimmer. What's really cool though, the SDB pretty fine some non-extinct shims. So there's a shim called KM Autofail with a GUID. Now KM Autofail doesn't actually exist. So nothing on a system comes up and says, I am KM Autofail, and here's my GUID. So all we have to do is write our own driver, like the one I just did, which basically says, I am KM Autofail. And one of those now knows, OK, cool, I know who KM Autofail is. And according to the SDB, KM Autofail is a legitimate shimmer. So you're legitimate. And then I can just go in the registry and basically all the tool is doing is going to, you know, AFD.SIS, MPFS.SIS in the system, current control set, control compatibility key that we talked about. And it's basically just saying, oh, AFD.SIS has a shim and its shim is called KM Autofail. And now I'm KM Autofail. I basically register with this GUID and now I can shim that. So I'm not sure that's kind of desired behavior. Now, even if that wasn't the fact, though, even if you couldn't do that trick, remember, the SDB files aren't signed. So if you know how to build an SDB file, you can just edit drvmain.sdb and define a new shim in there. So this was a trick that allowed me to avoid having to do that. But even if the trick didn't work, you could always edit drvmain.sdb because there's no signature there. So if you're doing forensics, if you're doing security software, obviously you want to make sure that those registry keys don't contain weird entries, that you don't have drivers that shouldn't be shimmed being shimmed. And you also, you know, be good to have like a check or some sort of database of drvmain.sdb hashes. Because it's not signed, so it's very hard to know, do you have the original Microsoft drvmain.sdb or do you have a modified malicious drvmain.sdb? So you want to kind of get a check sum of it. In all Windows 10 versions should have the same drvmain.sdb unless someone kind of added stuff in there. So that's pretty much it. We have this ability to hook anything we want. We have an API that lets us do that and we can build tools to rely on that and make sure you use those driver debugger scripts that I'm going to release, make sure you don't have weird shims, look at your registry, make sure there's no weird shims in there, and then look at your sdb file and make sure that your sdb file matches what it should be. So thank you very much for listening. And I probably don't have time for questions I'm guessing, or are we doing that? Maybe one or two questions, one over there. Can you serve Microsoft since it's not an OEM for anything other than fucking up OEM drivers? Anything other than un-fucking-up OEM drivers? Well, I have seen the app help stuff being used on something quite surprising. So, whoops, I'm going the wrong way. So if you have this thing called Procmon.sys, I'm not sure who makes that. Oh, right, Microsoft. A driver's install that causes the build-in problem with your system. So they use that on their own stuff, but not as an actual shim, but just kind of blocking. So now I haven't seen any built-in shims that don't work around OEM issues. So, yeah. All right, well, I'll be around if you have any other questions. I'll let the next speaker come up, and thank you again, and enjoy the rest of the recon. Thank you. Thank you. Thank you.
 I'd like to welcome someone who's participating in recon for the very first time.  I apologize for the transitions in the slides.  I just realized now that the company template has transitions, which I hate, so sorry for that.  I'm going to be talking about the kernel shim engine in this talk and I'm going to do a brief introduction about myself and presentation.  Then we're going to look at what exactly the shim engine is, what it does, how does it shim.  We're going to look at how you can write a shim driver or how existing shim drivers function.  And we're going to take a look at a few examples of existing shims that exist on the operating system.  Now because shims in the kernel are undocumented, there's not any tools, there's not any debugger extensions,  there's no symbols for actually understanding what's being shimmed and who's shimming what.  So I'm going to show you some WinVac scripts, some registry keys, some event log functionality that we can then use to figure out what shims are active.  So if you're doing IR, if you're doing endpoint protection, if you're trying to understand what's going on, hopefully that'll be useful.  Then I'll be doing a demo of a tool called DriverMon, which is built on top of the shim engine in which we plan to release in about a few weeks time.  Then we'll conclude and do some Q&A.  So a little bit about myself. I'm a chief architect at CrossStrike right now before I worked on the Apple Core iOS team.  So I'm a big fan of operating some internals, both Windows and Apple.  So I'm a co-author of the Windows Internals books. I've been doing a reverse engineering for about 15, 16 years now of the empty kernel.  Far too long. I wish it would just die. But anyway, it's still around.  So I do a lot of conference speaking about design issues in Windows or undocumented modules in Windows.  Things that are fun to poke at, things that can give you interesting levels of access or interesting kinds of persistence or hiding or things like that.  So this isn't the same kind of realm as that.  Someone who's not presenting with me today is Robin Keir. He's a fellow coworker at CrossStrike and he helped with the DriverMon tool immensely.  He actually rode the whole GUI for it. So when we do talk about a DriverMon tool, that's all really his work.  So I took care of the driver and the internals, but big thanks to Robin for doing that.  So basically, we're going to be looking in this talk at another component in the kernel that's not very well known called KSE, the kernel shim engine.  And if you attended last year's recon, I gave a talk on binary instrumentation technologies and hooking.  So how from user mode you can hook binaries using a shim engine and using other technologies.  So in a way, this is kind of a follow-up because I figured, well, all that was user mode, can you do some of this stuff from kernel mode as well?  So we're going to talk about a way that you can now hook any Windows driver using a legitimate interface.  So without actually having to patch your own IAT entries or hook the driver object.  So this is going to let you hook IAT entries, so imports. It's going to let you hook herbs. It's going to let you hook driver callbacks.  And it's actually a really nice interface to program against. You just kind of tell it what you want to hook and it does it all for you.  The trick, of course, it's undocumented, so you have to figure out those data structures.  Then we're going to talk about how to, again, forensically look for shim providers.  So what's already on the machine? What's it shimming? Are there things that should not be there by default?  And we'll talk about something interesting, which is how you can actually hook the hook engine itself or hooking the shim engine,  which has some interesting kind of bypass properties.  And we're also going to look at some built-in shim providers, built so you can kind of know what's already on the machine.  So if you have a shim that's not on your machine, that's interesting. Or if you have a shim that is on your machine,  but that's not on the list of default shims, well, then you have a third-party shim and you really shouldn't accept the tool that we're releasing.  And then I'll talk about this shimmer tool that I wrote and kind of how a driver can register with the shim engine and how to interact with it.  And then I'll do a demo of the driver mount tool, which I think will be pretty cool.  So let's talk a little bit about how the kernel shim engine actually does its work.  So basically, the whole point of the kernel shim engine is to provide two types of shims, or app-compact.  Whenever you say shims, we always talk about app-compact behavior, basically.  And there's device shims and driver shims.  Device shims are basically ways to apply flags or specific policies to certain devices,  identify by their hardware ID. So you have some particular kind of USB device or some particular kind of PCI device.  And different bus drivers, like the PCI bus driver, the USB bus driver, and also class drivers,  are going to be checking what flags are active for those devices.  And so, for example, if you have some sort of weird USB device that requires one millisecond instead of half a millisecond to initialize itself,  there's going to be a hack flag that basically says, you know, required, but flag number four.  And it's associated with this hardware ID.  This way, the driver sees, oh, you've got a device that has flag number four active.  Well, that means that I have to wait a little bit longer when re-initializing the device.  So this has been there since Windows XP, under the guise of app-compact.  Then, this thing had the Erota manager, which kind of does the same thing.  And then in the registry, you have sometimes flags called PCI hack flags or things like that.  So it's really yet another way for device drivers to be able to identify if there's some sort of weird device on the machine.  The second kind of shim this provides is driver shims.  And a driver shim is basically a file name, a path to a driver that you would like to hook.  It's imports, it's callbacks, or it's IRB handlers.  So it does both driver shimming and device shimming.  Basically, during the IMAG initialization, this thing initializes in kind of two phases.  So there's a function called KSE initialize, which does that.  And it parses the same STB database that you might already have heard about in terms of app-compact shims and IE shims  and other presentations that have been done.  So the exact same format that's used for user mode shims, MSI shims, is also used for kernel shims as well.  Now KSE will not initialize if you're in save boot.  It won't initialize if driver verifier is enabled.  It won't initialize if there's actually no database, like you deleted it off disk.  And it won't initialize if you're booting in Windows BE mode.  So like in recovery mode, there won't be any shims either.  This shim database is called driver main.sdb, and it's located in the same app patch directory as everything else.  And it appeared in XP.  And in XP, again, there was no kernel shim engine, but there was this app-compact engine where you could have certain flags.  And with changes in Windows 8 with the kernel shim engine, it's the ability to have driver shims as well.  So this is loaded very early on by winload.exe, which is orb.efi, which is your Windows bootloader.  It looks in system 32.cwindows.apppatch.drvmain.sdb, and it loads that.  And then it also loads the irata-manager.inf file, but we're not going to talk about the irata-manager here.  It then stores in a loader parameter block extension, the base address of the shim database, and the size.  This point is already loaded in memory, and in all cases, it has to do is now just parse it from memory and look up all of those data structures.  And when you have user mode shims, you can tag, you can associate a user mode shim with a particular binary.  What's cool in the kernel shim engine is you can associate a shim with a particular type of device.  So you can say, if you have this type of ACPI table, and you have this type of BIOS, and this type of CPU, then this shim applies to you.  So it does some of that look up in there as well.  So device shims are basically exposed to three APIs, KSE Query Device Data, KSE Query Device Data List, KSE Query Device Flags,  and device flags are basically a subset of device data.  They're the XP flags that always existed. The XP flags became a subtype of the device data.  Now this device data can actually be queried from user mode.  So those functions are kernel functions, but if you call anti-query system information, which is a well-known Windows undocumented API  for getting all sorts of interesting things from the system, you can pass in those two information classes,  and that's going to give you the device data for a particular device.  And device data, again, it's flags, policies, things that make this device interesting or unusual compared to other devices  so that its driver can basically react to those differences that the device might have.  The other place device data can come from is the registry.  So device data can either come from the SDB database when it's loaded off the disk, or it can actually come from registry.  And in the registry, you basically have this Reggie registry machine Windows system, current control set, control compatibility device,  and you take a hardware ID, which is like USB ampersand, some number, slash, bus ampersand, some number, you replace all the slashes with banks,  and if there's anything in there, that means there's device data for that device path for the hardware ID.  If it's not in the registry, they're going to look up in the cache because all this device information is cached,  and if it's not in the cache, then they're going to look in the SDB.  And in the SDB, basically if you're not familiar with the SDB format, which is now documented, and there's lots of tools to dump it,  everything's identified by tag, attack or response to a given data type.  So there's a tag 7013, which is a flag, which is read by read read Kflag, and there's another flag called Kdata,  which contains just arbitrary value pair data.  So Kflag, there's a few of those in the SDB file, and I'll show you some dumps.  Kdata, I haven't found anything in my Windows 10 driver main, so it's implemented by, I haven't seen any data other than flags that is at least in the inbox SDB that I've got.  So who actually reads device data or device flags?  You've got a Bluetooth driver, port driver, and numerator, the audio driver, the audio bus driver, the Bluetooth hit driver, the generic hit driver,  and this, which is the network driver in Windows, UFX synopsis and URSCX, which I'm not sure what those do.  I think it's another type of Bluetooth type stuff.  And then USB hub, which is the USB driver.  So all those, basically what that means is that all those drivers recognize that some devices that they manage are strange,  and the device flags, if they match particular hits on your machine, these drivers will act differently.  So either fixing iradas or working around a hardware bug that might exist.  Kc also implements a hardware ID cache.  Not 100% sure what this is used for, but basically anytime a driver, anytime a plug and play discovers a new device, it's going to capture the whole hardware ID  and then adds it into another cache database.  And then there's an app help function, NT app help cache control that you can call from user mode, which is used by the application helper service.  And then this basically lets you query the hardware ID.  So it's a very simple way of knowing, is this hardware present on your machine?  Because all the plug and play hardware is enumerated in a, in this cache, and then the application helper and user mode can just call it and say,  dump me all the hardware IDs or tell me if this hardware ID is present.  Kind of weird because the plug and play manager already knows and there's APIs for doing that, but you know, this is Windows.  There's always like 10 different ways of doing something and 15 different things that store the same information.  So that's another thing you can dump from user mode, basically all the hardware IDs on the machine.  The other stuff this does then is driver shimming.  And there's some built in driver shims that you have as soon as KAC initializes.  One of them is called driver scope.  So driver scope is a built in shim and it hooks all driver callbacks.  It hooks IocTools.  It hooks create and close herbs.  It hooks power herbs and it hooks plug and play herbs.  It then hooks Iocray device, PO request power herb,  X allocate pool, X free pool, and basically when this shim is active,  all it does is hook all those things and it just prints out over ETW,  which is event tracing for Windows, which is kind of Windows' internal tracing mechanism.  Anytime that happens.  So just kind of hooks those things and tells you that it happened.  As the name suggests, you have a driver scope, kind of like a scope for drivers.  We're going to see driver scope is never active on anything by default, but it basically means if you activate it  and we're going to see how you can activate a shim, you get some ETW events.  Then there's another three set of shims, Windows 7 version lie,  Windows 8 version lie, and Windows 8.1 version lie.  And as you can probably imagine, these are going to hook RTL get version and PS get version.  And each particular hook will return a different version.  So just like in user mode, you can enable XP compatibility mode or Windows 7 compatibility mode.  This basically lies to the driver and makes the driver think we're running on a different operating system.  And there's another one called skip driver unload, which kind of worries me.  Basically that hooks your driver unload function and just doesn't call it anymore.  It just prints out ETW.  Yeah, I'm not going to bother calling the unload for this driver.  That is not active on anything by default, but you know, it's an interesting one.  So how do loaded drivers get shimmed?  Well, whenever a driver gets loaded, which either is going to happen by IOP initialize built-in driver,  MI compact service table or MI driver load succeeded, KSC driver load image runs.  This will then do two things.  It's going to get the shims for a particular driver and then it's going to apply the shims for that driver.  Once the driver has been shimmed, you get an event trace and we're going to see how you can look at that in event log.  There's a variable in the kernel.  We're going to see that basically points to the last driver that got shimmed and you get some flags as well that tell you a shim is active.  So when we're going to look at introspection later with some currently bugging scripts,  we're going to see side effects of basically that being enabled.  At that point, whenever a module is now being shimmed, it gets added to the shimmed driver list and there's a function called KSEP is module shimmed.  And this is basically going to record the load address of every driver that has been shimmed,  the number of shims that this driver is currently that have been applied to this driver,  and an array of all the shims that have been applied.  So if you're not already shimmed, then we're going to search the registry to see if there's any applicable shims for your driver.  And we're going to see how the registry basically allows you to shim a driver.  So this happens with KSEP Engine gets shims from registry and KSEP registry query driver shims.  Now, if the registry says that you have a shim called foobar registered for this driver,  we're going to look in the SDB in the database, is there a shim called foobar?  So the database actually has to define all possible shims.  A shim then has a shim descriptor called a Kshim, which basically tells us the name of the shim,  the GUID of the shim, and the module that should be providing the shim.  So the driver, that's actually going to be doing that.  Another possibility is there's nothing in the registry, and there's nothing in the registry,  then the SDB file itself can have what are called Kshim references,  and can basically identify this driver and that driver and this driver need to be shimmed by that shim,  and then the shim is defined in the SDB as well.  So I can either shim a driver by putting that in the registry, or I can shim a driver by putting that in the SDB.  And then each shim is described, like I mentioned, by a GUID, a name, a command line, and also a source.  So you can know, was this driver shimmed because of the registry,  or was this driver shimmed because it was in the SDB file,  which again is useful once we go and dump these things in memory.  Now, once we've identified that a shim is active and correctly defined for a driver,  we're going to be resolving the shims.  So we're going to see, is that shim for smaller registered?  Because for a shim to be registered, that means a provider ran the provider, the shim provider,  registered that shim and says, I provide shim called foobar with the GUID, you know, so and so.  Now, it's possible that a shim provider hasn't yet loaded.  In other words, you're loading the driver before you're actually loading the shim provider.  Now, that's what we're going to check is this shim, a delay load provider.  If it's a delay load provider, we're actually going to go and load the provider name manually  by basically seeing what's your name and calling the ZW load driver and loading that driver.  Once the provider has been loaded, we're going to dump all the registered shims again,  and at this point we should expect to find that shim in the driver list.  Otherwise, something's wrong.  Basically means that, you know, this module for whatever reason is not providing the shim that it's supposed to.  If it is, the next thing that happens is we're going to dump all the loaded modules,  because one of the things that shims can do is hook IET entries of any driver.  So we're going to dump all the drivers that exist, and we're going to see,  does your shim hook any of the drivers that this driver might import?  Right, so I have one driver that's basically, you know, foo.sys.  It's importing from bar.sys, and your shim driver is basically saying,  bar.sys as function has to be hooked.  So we're going to see, is there a bar.sys loaded?  If there is a bar.sys loaded, does it have the function you're trying to hook?  And if the function you're trying to hook exists and bar.sys is loaded,  then we're going to go ahead and apply the shim a little bit later.  We're not yet applying the shim, we're basically just checking,  do the shims actually resolve to anything?  Because if there's no bar.sys, or this version of bar.sys is not exported at API,  well then your shim can't hook anything, so we basically can bypass that.  If not, your driver is now ready to be shimmed.  In other words, we have found a shim that's valid, we have found all the things  shim wants to shim, and all the exports exist.  So we're ready to proceed to the next stage, which is going to be applying the driver shims.  So it happens with a separate function, ksep, apply, shims to driver,  and this is going to go in ksep, patch, driver, imports table,  which calls ksep, patch, import table entry, which then calls mmReplace, import entry.  So the marry manager has a whole bunch of functionality now to basically  safely and correctly patch IET entries, take care of the section objects, and all that.  At that point, your shim provider gets a call-out notification, which we're going to talk about later,  which basically tells you, okay, you are now shimming this thing.  But the only thing we've shimmed so far are functions, IET entries.  And there's two, or really three types of things shims can take care of.  You can shim the exported functions of a driver, but you can also shim the callbacks that a driver receives.  And right now we haven't done any callbacks, because all we've done is we've loaded your driver.  We haven't yet initialized it.  So once your driver actually initializes, which is done by IOP load driver,  or IOP initialize built-in driver, then we call ksep shim driver IO callbacks.  This will now call ksep get shim callbacks for driver,  and it's going to hook your driver callbacks, driver in it, driver unload, start IO, add device,  and then it's going to hook all your IRB handlers based on whatever my shim describes.  So two stages here.  First stage, hook the imports as soon as the driver loads.  Second stage, hook the callbacks and the IRBs as soon as the driver is initialized.  And then the shim is fully active.  So let's see how we can write our own driver that basically makes a shim engine do all the stuff for us.  So the first thing we need to do is define a ksep shim.  Again, a shim is a compatibility fix.  A compatibility fix is a set of functions we have to hook, and callbacks we have to hook,  and IRB handlers we have to hook, and by hooking all those things, the idea is we're providing,  we're fixing, we're working around some sort of bug in this driver.  So the structure's not documented.  It's basically my own definition of it.  Fairly is the reverse.  So basically you have the size of ksep shim, a GUID, and a name.  Now the name of the shim that you're registering, and the GUID of the shim you're registering,  must match one of the shims in the sdb file.  And the sdb file has your shim name and your GUID.  So you can register, I mean you can register an arbitrary shim, but nothing will use it  because the sdb file won't actually match up to that.  Then you get some callback routines, and we'll see what those are useful.  And then you get two notifications.  One when your driver has been targeted, so when you've actually loaded,  not you, sorry, when one of your drivers is shimming has been loaded,  and another one when one of the drivers is shimming has been unloaded.  And then you pass in an array of hook collections.  What's a hook collection?  Well, a hook collection is basically a type of hooked entity,  and there's two entities you can hook, functions or driver callbacks.  And functions can either come from NT, they can come from the HAL,  or they can come from an arbitrary driver.  So 0, 1, and 2 are used for function hooks.  If you said that they're coming from an arbitrary driver,  then you have to pass in the name of the driver you're hooking.  Otherwise, if it's an NT hook or HAL hook,  well, we all know the name of those things are, so you don't have to bother with that.  Otherwise, type 3 is a callback, and a callback means you're hooking either a driver callback  or an ERP handler.  And now you define the collection of hooks,  and you now have to go and actually define the hooks that make up this collection.  So that's now with another structure.  And kind of repeatedly, that structure has its own type,  1 for function or 2 for callback.  And if this is a function, you have to give it the function name that you're hooking.  If this is a ERP callback, you give it a callback ID.  I'm going to see what the callback IDs match up to.  You then pass in the address of your function that's going to be hooking that thing.  So the hook function there, that pvoid, is a pointer to your hook.  And in original function, you get a pointer back to the original function that got hooked,  the idea being that if you do want to hook the original function,  you call original function and then life goes on.  But that is only filled out if this is a function hook.  If this is an ERP callback hook, that actually doesn't get filled out.  So we're going to have a problem.  We're going to see how to deal with that.  So how do you hook a function?  Well, again, fairly easy.  You look at what you're trying to, what exports a thing.  If the exports Entos kernel, you create a collection of type 0.  If the export is hal.dll, you create a collection of type 1.  And if this is a custom driver, you create a collection of type 2 and you put down your driver name.  So I have a very simple example here.  If you're trying to hook xallocate pool tag, you say 0 because xallocate pool tag is an Entos kernel.  You put in the name xallocate pool tag and then you give it a pointer to your hook of exallocate pool tag.  And then null, that's where you're going to receive the original xallocate pool tag.  So then your hook function, you do whatever you want to do because you're hooking xallocate pool.  And then you return hooks 0 original function.  Basically then call the original function that's there.  Or maybe you'll just decide, nope, I'm not going to allocate any memory for you, which would probably be bad.  Now, one of the things you might want to know inside of your hook is if I'm hooking multiple drivers of the same shim,  what driver is actually calling xallocate pool?  So there's no kind of built in way of knowing that, but you know you've got an interesting visual studio called underscore return address,  and they'll give you the return address of whoever called you.  So that way you can tell what driver actually is hooking exallocate pool.  So if you want to filter on certain drivers only, you can do that.  Obviously if you're only shimming one driver, then you don't need to worry about that.  So what about hooking callbacks?  So there's four callbacks you can hook.  You can hook driver in it, driver on load, driver start IO, and you can hook add device.  Or you can hook every IRP, which are IO request packets, which is how Windows actually does IO.  So there's IOs for create, for close, for read, for write.  There's up to IRPMJ maximum function IRPs.  Interestingly, you can hook in you these things, except actually driver in it.  Because if you go back a few slides, we said that we hooked all the functions as soon as driver loads,  and then we hook all the callbacks as soon as driver initializes.  So you can specify a driver in it hook, but it won't actually ever be called,  because your hooks only get applied after driver in it runs.  So kind of a design fallacy there.  You can see I've got the pseudocode.  We call driver in it, then we apply the hooks, and driver in it never gets called again.  So we're never going to call your hooked driver in it.  Oops.  So we said that if you have a function, you get the original address.  Now when you hook a callback, you don't actually get the original address filled out.  Instead, what you're supposed to do is you're supposed to call this other function, KSE getIO callbacks,  and KSE getIO callbacks returns to you the original callback.  So kind of weird for functions, you get the address.  For callbacks, you have to ask it what the address is.  And you can ask it one, for the original address of driver in it, two for driver startIO,  three for driver unload, four for driver add device, and for herbs, every herb has its own number.  For example, IRPMJ create is zero, IRPMJ read is four or three, IRPMJ closes two.  What you do is you add 100 to that number.  So if you ask for 102, then you get IRPMJ close.  If you ask for 100, then you get IRPMJ create.  So one through four are those hard coded ones, and then 100 plus the herb identifier are the herb handlers.  Now how do you call KSE getIO callbacks?  Because that's actually not an exported function.  Well, let's go back for a second here in our definition of a KSE shim.  So there's this field here called KSE callback routines.  Well, let's see the resolution screwed up.  Anyway, this thing here KSE callback routines, that's where you actually get a pointer back to KSE getIO callback.  So it gives you the function that you need to call.  So that's how you find it, basically.  And then you can call the original function.  Now the other thing with herbs is that unlike function calls, which return immediately,  herbs can either be returned immediately.  But by the time they've returned, the herb has actually been completed,  meaning that the other side has already received the answer,  and the herb structure which contains the answer may have already been deallocated or freed.  The other possibility is that the function cannot return immediately.  In other words, this is an asynchronous I.O.  So the herb will be completed later.  So if you do try to read from the herb, there's no answer yet.  So you kind of got two bad choices.  You read from the herb and you'll crash because the herb is gone, if the operation succeeded,  or read from the herb and get useless data because the herb hasn't actually completed.  So what you actually have to do is register a hook for the completion of this herb.  And again KSE gives you a function for that, KSE set completion hook.  And you can say for this herb, I would like to hook its result so I can actually know what happened with it.  And again KSE set completion hook is not an exported function.  It's another callback that you receive in your shim.  So your shim structure basically gets back the addisive KSE get I.O. completion callback.  So you know what to call when you're done.  And KSE set completion hook if you'd like to request a hook for the herb.  Which is nice because that basically means you're going to have pre-operate pre-hooks  before the herb actually gets processed by the driver.  And you can have post-hooks after the herb has been processed by the driver.  So for example for IRPMG write, in your pre you can see what the user mode app is trying to write.  In your post you can see the write actually worked and if so how many bytes have been written.  For a read, well when you see the read in your pre all you get is someone wants to read something.  In your post then you actually get to see what was actually read.  The other thing I mentioned you get is two callbacks, the shim targeting callbacks.  And so whenever a driver is actually going to be shimmed by you, you get a notification from KSE saying you are now shimming this driver.  And you get the name of the driver you're shimming, its load address, its size, its time stamp and its checksum.  And when a driver is unloaded you get the same information back telling you this driver that you were shimming before is now gone.  And so what's interesting now is with this information you can basically build yourself like a memory map of  okay from here to here I have this driver is here, from here to here this other driver is there, from here to here I've got another driver.  And then in your function hook when you get the return address you can scan is the return address in one of these memory blobs that I know about.  Okay then this is this driver trying to call me and you have its name and its checksum from your targeting callback.  For an ERP, well an ERP gets a device object, a device object points to a driver object, the driver object points to the star data of the driver.  So again you can match up the start address of the driver that sent the ERP with the, sorry that's handling the ERP with one of the drivers you're targeting.  And that way you can know exactly what drivers are you currently hooking in the middle of your ERP or in the middle of your function hook.  So once you define all these structures how do you then register for a shim provider?  Well there's a nice little export API for you called KSC register shim EX and you basically pass in that KSC shim structure which identifies your shim,  your GUID, your name, the collections of hooks and the actual hooks and you pass in your driver object.  That means that KSC will now take a reference on your driver and if you actually try to unload your driver while you're still shimming things it won't actually let you unload.  So it's going to run through your driver on load but it's going to keep you resident in memory.  So you're not going to be handling any new kind of IOs but anything that's shimmed will still go through you unless you unregister your shim and that thing then goes away as well.  So this allows you to basically reference counting and making sure that you don't end up with a shim driver unloading while there's active shims which obviously will now call a null pointer or something worse.  So basically these are the two things. If you unload and unregister your shim but drivers are still active you remain resident in memory.  Similarly though it also means if you load your provider after the driver is already loaded you can't shim an existing running driver.  So you have to reboot the machine and shim it at boot or unload the driver and reload it because if the driver already ran you were never registered so there was nothing to hook to begin with.  So let's look at a few examples or at least one example of a built in actually not a built in but an inbox shim.  So basically a not a third party driver but an inbox driver that's not the kernel that registers its own shim.  Because basically by looking at this that's how I kind of understood how shims work.  So in the built in database there's a number of interesting things in there and you can dump the database with STB Explorer, great tool.  TZWorks has something they call shims which also lets you dump the shim database and then Microsoft actually has something called shim to XML or STB to XML  which lets you dump the shim database as an XML file.  And then in the shim database you're going to see app help entries which basically say this driver is not something we want to load so just block it and that's done in user mode actually.  So that's one part of the shim engine that's not done by the kernel.  It's done in user mode and the driver tries to install itself, you get a little pop up that says these drivers not compatible with Windows.  Then you have K device entries and we're going to look at a few of these which are used by the device compatibility stuff.  So any flags that need to be applied or any device data that's K device and then K driver is used by actual driver shims.  So the driver shims are in there and then K shim are what shim providers are actually registered.  And again every provider has to be in the STB. You can't kind of make up your own provider without any definition for it.  So you can look at a few examples.  I've got both the XML dump from one of the tools and the XML dump from the other tool.  So there's one here that basically says this is a K device shim.  So this is a device shim and the name identifies some sort of hardware.  So if I have something from vendor 1B21 product 1 0 B 0 which looks like it's an AS media vendor.  So some sort of USB 3 device made by AS media.  It's going to apply the flag 4096 with the name USB.  And the implication here would be that the USB class driver would then call KSE get device flags passing in the device ID over here.  And the shim database would say, yep, I know this device.  It's got flag 4096.  And then 4096 to the USB class driver means something like again, you know, this device takes a longer time to initialize.  So you should take longer as well.  So the example of a driver shim is at the bottom.  And this is basically saying that T s s safe dot sis a QQ game from Tencent.  I love it when games load kernel drivers makes me feel really safe.  This pops up a message that says a driver is installed that causes stability problems with your system.  No surprise.  And then it basically has, you know, the product version associated with that.  So that's an example of an app help shim that basically says, yeah, we're not going to let you load this driver.  It's it's bad.  And later on, if we have time, I'll share some other examples.  Again, these are just from the dump of the SDB database dumped with SDB 2x ML, which is that Microsoft tool.  So what are the built in Windows shims and providers?  If you look at the database, well, there's driver scope, skip driver unload KM version line, which are built in.  Then there's two interesting ones called KM auto fail and auto fail, which are meant to be registered by KM auto fail dot sis and auto fail dot sis.  But those don't actually exist.  Then store port device ID shim and SRB shim are registered by store port dot sis, which is the Windows storage driver.  USB shim is registered by USB D dot sis, which is the kind of the generic library that all USB devices use.  And end is get version 640 shim is registered by endis, which is that driver allow drivers try to check which version of end is the wrong.  So I'm guessing just like the version line, this allows and is the light driver and say, no, no, I'm not and this 6.6.  I'm in this, you know, 6.4.  Then in the registry, so mentioned certain drivers can be targeted.  So by default on like a clean Windows then installation.  If you go to the key there in the registry, the compatibility key.  So under that sub key called driver and under that sub key, there's different driver names and might see in the screenshot.  There's a few there that I've added, but the one that's there by default only is store a HCI dot sis, which is the HCI or you know,  SATA storage driver.  It has the SRB shim applied.  So basically whenever you load store a HCI dot sis, it's going to be shimmed by SRB shim, which on the previous slide we saw that SRB shim is registered by store port.  So store port access will be shimming store HCI dot sis.  But that's only in the registry.  So remember then the SDB can itself have other shim information.  So just a few examples here USB shim hooks WSR RCI dot sis, edgerser 64 dot sis, ACF DCP 64 dot sis.  So those driver vendors are doing something wrong and USB has to come in and kind of fix them up and this get version six portion.  There's some real tech drivers in there.  KM win eight one version line something called the frag FS sis in there.  And there's other shims which are again loaded by shim by other things.  So, you know, if I open up here the database that I've got SDB dot text.  That's not the right thing.  And anything that basically has K shim ref in there is something that's going to be hooked.  So that's coming from can that's USB.  That's the one we've seen.  But here's one I didn't have in the slide.  So for example, there's where is it Franklin.  The resolution doesn't let me zoom in properly.  There's a Franklin use excited driver and it is being shim by KM win seven version lie.  So this driver needs to be told that one window seven.  So again, just dump the database and you can see all these examples for your safe.  Basically, and Windows update can obviously update is as the database and can add additional devices in there as an additional shims as they're needed.  So let's look at one of those examples.  Scuzzy port registers a shim to shims actually SRB shim and device ID shim.  Both of those only should have one hook collection.  It's a callback collection.  And there's a single hook for that callback collection, which is the hook for IRP MJ device control.  So any I octals sent to store port or through sorry through store HCI, which store port is hooking will be hooked.  And there's a function device ID shim hook device control to hook I octals for the device ID shim.  And there's SRB shim hook device control, which hooks the octals that SRB shim is okay.  So SRB shim.  What is it then doing?  It's basically for any I octal that's I octal storage query property.  And if you're querying standard property and the property ID is storage adapter property and you're expecting 32 bytes or more,  then it's going to target this service and say, all right, this is interesting.  So I want to register a completion callback or completion hook.  So in the IRP completes, then I want to be notified in the completion hook.  What does it do?  Well, it basically checks again, did we return 32 bytes or more and did we turn it successfully?  And if so, we're going to go in and we're going to edit the actual.  We're going to edit the actual SRB type and address type field.  And we're going to set it to zero.  So basically override this legitimate valid data that we received with zeros.  So that's kind of interesting.  Why are we doing this to poor store?  HCI dot says, why are we clearing out these bottom two fields that, you know, we're legitimately returned.  And so if we actually read them as the end, basically tells you that SRB type was added in Windows 8 and address type was added in Windows 8,  meaning that an older driver that's interacting with store HCI wouldn't necessarily know about those fields.  But then what's the problem?  Like why would they have passed the size that is 32 bytes or more because the size of the structure without those two elements,  if you count it should be 30 bytes.  So the driver is asking for 30 bytes, it shouldn't get those fields.  Why would a driver that doesn't know about those fields ask for 32 bytes?  Well, if you actually look at the structure in Ida turns out that because of alignment, because you've got an existing word at the end of the structure and structures are four byte aligned,  you have two bytes of alignment at the end.  So the actual size of the Windows 7 structure is 32 bytes and the bottom two bytes are just padding.  And so you might now instead of padding on Windows 8 get actually data that's there.  So they zero out that data to basically pretend, no, no, that's still padding because you're a Windows 7 driver and you shouldn't know about those fields.  So either that's because someone was, you know, expecting padding or hard, you know, reading the previous field incorrectly.  For whatever reason, they're playing it safe and they're saying, you know, that driver will still see the Windows 7 structure.  So that's an example of a shim, highly specific shim, but it's a really good example on, you know, how I could write my own shims after that.  And all this was easy to analyze with basically all the symbols that are in Ida.  So that's kind of how an inbox shim works.  I want to show you how you can actually see the shims and introspect them.  And there's different ways you can introspect the shim engine.  Now, because there's actually no symbols, it's very hard to analyze at runtime what's actually going on.  But if you have a kernel debugger and you have, you know, some scripts and the right knowledge and you've done reverse engineering,  you can get a pretty good overview of everything that the shim engine has actually been doing.  So I'm going to show you a few shims here.  Hopefully they're going to work.  Shim.ws, which is kind of, it's going to display some information about the shim engine on my machine.  Shim.ma.wds, which is going to dump any modules that are being shimmed.  Shimreg, which is going to dump any shims that have been registered.  And shim cache, which can dump the shim cache. So either the hardware ID cache or the device data cache.  So I'm just going to demo the scripts for now and clean them up, comment them a little bit,  and I'll probably post them on GitHub later next week so you can actually use these scripts and learn from them and do your own introspection as well.  So basically they all rely on this structure called KSC Engine, which is a global in the kernel.  Again, not documented, but this is kind of what I've been able to reverse from it.  So there's some flags, some state information. There's a list of all the shim providers.  There's a list of all the drivers that have been shimmed.  And then there's the cache, the device cache, and the hardware cache.  And then there's the last driver that got shimmed.  And so the little script that will display the state of the KSC Engine.  So let's try that. Shim.ws.  And this is basically saying the engine is ready.  Driver shims have not been disabled. Device shims have not been disabled.  These are the address of the two callback routines that drivers can call.  This is where the device cache is. That's where the hardware cache is.  Here's the list of registered shims.  Here is the list of shimmed drivers.  And the last driver that got shimmed is afd.sys.  And this is basically saying that on my system, afd got shimmed.  And then there's some state flags, which are indicating, for example, that no group policy was found.  So shims have not been disabled or enabled by group policy.  They're just not configured. And active driver shim, which is indicating that something is shimmed.  And there's a good sign of that, which is that afd is shimmed.  So that's just kind of a global state about what's going on.  At this point, I can, for example, take the registered shims list.  And I'm going to dump it with a bang list and run a little script that should hopefully show what those drivers are.  So that's shimmedreg.wds.  So KSCDS shim has been registered. That's driver scope, but there are no active shims.  So driver scope isn't active.  Win7 version lie shim has been registered, but it's not active.  Win8 version lie registered, but no active shims.  Win8.1 registered no active shims.  Skip driver unload registered no active shims.  Store port SRB shim also not active device ID shim not active and the shim not active.  Let me have a little error module load complete, but symbols could not be loaded for blah, blah, blah, blah shimmer dot sis.  That's my stuff, which has two active shims.  So shimmer is actually shimming two things.  And then this is CS shimmer as a driver name.  So we're going to see what that one's all about.  And then USB de shim.  So basically you can clearly see with the script that something's actually shimming the machine and it's, you know, the strange shimmer driver.  All the built in shims that we've seen, they're not shimming anything at all.  And so if we go back to the KSC structure, that what we just dump was the list of registered drivers or shimmers.  Now we can see what's actually being shimmed.  So that's a different list there.  So let's try that one.  So this is shim mod.  That's the address of that list.  Cross fingers.  Okay.  And two things are being shimmed.  MP.  So actually, so there's a shim module here.  That's a bug.  There are no not six billion active shims.  But next one MPFS is being shimmed and there's one thing shimming it.  And there's going to be a ray of all the things that are shimming it and in that array, you're going to find shimmer and then a of these being shimmed.  And again, that's because of the special thing I've loaded, which I'm going to demo.  So I can see all the shim providers and how many things are shimming and I can see all the shim things and what's actually shimming them.  So that should be pretty useful.  And then I'm not going to dump the shim cash, but it basically a bunch of hardware IDs at that point.  So can you turn this thing off by the way or what are ways again, you can kind of interact with it.  So there's a registry key called compatibility where you can disable device shimming or you can disable driver shimming.  And if you go to the group policy editor GP edit, you can actually go, you know, when it's components device and direct compatibility and you can turn off device compatibility,  which means no device shims, no flags, or you can turn off driver compatibility settings, which means no driver shims.  Then there's a secondary registry key, which is in current control set control compatibility, which for your system, you can use disabled flags and disable flags.  One means you're disabling driver shims, disable flags to means you're disabling device shims and both of them together, aka three means you're disabling both kinds of shims.  Now from the debugger, there's a variable called case of debug flag.  And if you set case of debug flag to a mask, you can then see all errors, all warnings, any information from the debugger, the kernel debugger, the kernel shim engine,  because KSC has debug prints everywhere.  It even has an array called case of history errors, which contains an array of all the errors and you get the file name and the module ID and the status code where an error happened.  Then in the event viewer, there actually is a kernel compatibility log, and you can see, for example, event log entries when a device shim has been applied and tells you the source.  So for example, on my machine, there actually is a USB device which has a flag applied to it, and it says apply through compatibility database.  So the SDB on my surface has actually applied a device shim.  There's another event log sample here which says one shim was applied to driver afd.sys, applied to the registry.  And that's the shim that I'm actually going to demo, and that's part of the driver mon.  So in the event viewer, by default, you can actually see these operational messages that are going to indicate to you if any shims are active.  So you don't actually necessarily have to use the debugger.  You get some information in the event log as well.  Obviously with the debugger, you can actually see the driver because here all he says is this GUID has shimmed AFD, but what is that GUID?  So basically with this ability to then be able to shim any driver, I came up and created this tool called shimmer.  And it was very ugly, command-lay utility reminiscent of like pullmon, if you're familiar with pullmon, and basically just showed you the driver at the time, on which CPU, which pit, and which pit did something.  And as a demo, I basically shimmed all the IRPs and the allocate and free pull functions.  So I want to show this tool because instead of thanks to Robin, he built a different tool called drivermon.  And drivermon basically was meant to kind of not replace, but be like prokmon.  So if you're familiar with processor monitor, the ability to search, filter, and highlight operations, to do non-instructive filtering and boot logging,  to be able to export to a CSV, to be able to decode different octals.  And so I started working on a tool on a spare time, and we basically have a 1.0 release that's almost ready.  We basically have to wrap up the UI, the ULA, the build, the signing, and all of that.  And it should be on the community tools page.  So if you're familiar with like Crowd Inspect or Crowd Response, it's going to be on that same page.  I managed to avoid not having it be called crowd something, thankfully.  And we've got a mailing list that's going to be set up to drivermon across trike, or you can just reach out to me on Twitter  once the tool comes out if you have any kind of questions or feature requests or things like that.  So basically this is what it looks like today. I'm actually going to be demoing it.  But this is the pretty picture in case demo fails, because demo gods and all.  So this is kind of showing you NPFS.  Inside of search indexer, did a write.  It wrote 14 bytes. Now I won't show you yet what those 14 bytes were, but you know, that's obviously wanted.  Then search indexer allocated from the pool, a buffer.  And then it read from a pipe, 1300 bytes as well.  So because this is NPFS, these are implying that these are kind of pipe operations.  But I'll show you some AVD dots, which would imply that these are metric operations.  So let me actually run drivermon.  Feel bad things fail.  Okay, so I'm just going to hit capture.  And it's starting to give us some stuff. So AVD, which is the Windows Winsock driver.  So I can see that service host sent an octal.  Then AVD allocate a Fritsa memory. Then we got a create, and then we allocated some memory.  You know, if I run like explorer.  Well, we've got a little bit more AVD from service host.  On start menu, a whole bunch of stuff happened when I click on start.  Now I'm seeing NPFS kind of got very, very busy.  Let's see what happens when we run Chrome, because that'll be fun.  Somebody might know Chrome uses named pipes for its stuff.  So that's just Chrome sitting around doing nothing.  But good thing Microsoft spends a lot of time improving their named pipe file system.  Of course, I can stop the capture, which will stop at some point.  The UI only really has one thread or two, because this is just like starving the app, nonstop with stuff.  And I could close Chrome, and hopefully that'll help things a little bit.  So this will stop at some point.  Now it's just basically going over everything Chrome did,  and I can kill the auto-scrolling, which would help a little bit.  And now it's just going to keep on going and going and going, receiving.  So this is just like Progma, so I can right click on Chrome, for example, and say,  all right, thank you for letting me know that I did that,  exclude process Chrome.exe and just excluded Chrome.  So now I can see everything else except Chrome.  So you know what, I want to see the principle is up too.  So right click, thank you, includes poolSV.  So I can see just what poolSV is doing with Spooler.  I'm going to say include A of the only, thank you, and an I just A of the.  So just like the normal filters you're probably used to with Progma.  And then I can, of course, clear all the custom filters so everything should be coming back.  Now I can also say, you know, processHacker, for example, it loads the driver.  So I can clear all this and say, let's go hook processHacker,  and I'm going to say, I think it's K processHacker2.sys  and say, okay, turn on capturing.  Now let me get rid of A of the.sys and get rid of NPFS.sys.  Oh, looks like it brought the other one back.  Okay, I'm going to have to work on that.  So let's run processHacker.  Okay, and then by autoscroll and clear, and let's reset the filters.  Is it doing anything?  ProcessHacker file.  It might have renamed itself to processHacker3.sys is actually what I'm afraid of.  So I'm trying to double check that file.  Oh yeah, it's K processHacker3.  All right, so let me just write it one more time.  K processHacker3.sys.  And then actually let me unload nets.sys.k processHacker3.  Okay, edit, run processHacker, and make a sacrifice to them of gods.  See if that actually works.  Nope, oh well.  Can't demo everything.  So it would normally work when we figure out whatever is wrong with this thing.  So hopefully that's the idea, and obviously the plan is to make it a lot more, you know, less buggy,  and to be able to actually see what those buffers are, and decode the octals, and so on and so forth.  But it gives you an idea kind of what we're aiming for here.  So I'm going to skip the bonuses.  But you know, you'll see this on a slide, but basically you can hook the hook engine,  which is what I found out kind of the last minute.  So those are bonus slides that you'll have online.  And so let me just conclude some concluding thoughts.  So basically one of the questions you might have is how is the shimmer tool able to shim arbitrary drivers?  Because we said that if a shim is applied to the registry, it has to match a shim in the SDB.  And I haven't modified my SDB to say that there is now a new shim called shimmer.  What's really cool though, the SDB pretty fine some non-extinct shims.  So there's a shim called KM Autofail with a GUID.  Now KM Autofail doesn't actually exist.  So nothing on a system comes up and says, I am KM Autofail, and here's my GUID.  So all we have to do is write our own driver, like the one I just did, which basically says, I am KM Autofail.  And one of those now knows, OK, cool, I know who KM Autofail is.  And according to the SDB, KM Autofail is a legitimate shimmer. So you're legitimate.  And then I can just go in the registry and basically all the tool is doing is going to, you know,  AFD.SIS, MPFS.SIS in the system, current control set, control compatibility key that we talked about.  And it's basically just saying, oh, AFD.SIS has a shim and its shim is called KM Autofail.  And now I'm KM Autofail. I basically register with this GUID and now I can shim that.  So I'm not sure that's kind of desired behavior.  Now, even if that wasn't the fact, though, even if you couldn't do that trick,  remember, the SDB files aren't signed.  So if you know how to build an SDB file, you can just edit drvmain.sdb and define a new shim in there.  So this was a trick that allowed me to avoid having to do that.  But even if the trick didn't work, you could always edit drvmain.sdb because there's no signature there.  So if you're doing forensics, if you're doing security software, obviously you want to make sure that those registry keys  don't contain weird entries, that you don't have drivers that shouldn't be shimmed being shimmed.  And you also, you know, be good to have like a check or some sort of database of drvmain.sdb hashes.  Because it's not signed, so it's very hard to know, do you have the original Microsoft drvmain.sdb  or do you have a modified malicious drvmain.sdb?  So you want to kind of get a check sum of it.  In all Windows 10 versions should have the same drvmain.sdb unless someone kind of added stuff in there.  So that's pretty much it.  We have this ability to hook anything we want.  We have an API that lets us do that and we can build tools to rely on that  and make sure you use those driver debugger scripts that I'm going to release,  make sure you don't have weird shims, look at your registry,  make sure there's no weird shims in there, and then look at your sdb file  and make sure that your sdb file matches what it should be.  So thank you very much for listening.  And I probably don't have time for questions I'm guessing, or are we doing that?  Maybe one or two questions, one over there.  Can you serve Microsoft since it's not an OEM for anything other than fucking up OEM drivers?  Anything other than un-fucking-up OEM drivers?  Well, I have seen the app help stuff being used on something quite surprising.  So, whoops, I'm going the wrong way.  So if you have this thing called Procmon.sys, I'm not sure who makes that.  Oh, right, Microsoft.  A driver's install that causes the build-in problem with your system.  So they use that on their own stuff, but not as an actual shim, but just kind of blocking.  So now I haven't seen any built-in shims that don't work around OEM issues.  So, yeah.  All right, well, I'll be around if you have any other questions.  I'll let the next speaker come up, and thank you again, and enjoy the rest of the recon.  Thank you.  Thank you.  Thank you.
recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_0_2879.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_2880_4391.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_4392_30299.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_30300_40379.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_40380_45215.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_45216_47855.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_47856_50039.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_50040_51299.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_51300_56303.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_56304_56387.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_56388_57059.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_57060_58979.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_58980_59051.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_59052_59099.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_59100_65003.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_65004_66203.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_66204_66275.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_66276_66323.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_66324_66455.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_66456_66599.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_66600_67103.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_67104_67451.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_67452_67523.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_67524_68351.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_68352_68435.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_68436_68483.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_68484_68927.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_68928_70559.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_70560_72863.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_72864_75191.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_75192_75479.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_75480_75611.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_75612_76019.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_76020_76451.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_76452_77363.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_77364_77579.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_77580_78059.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_78060_79127.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_79128_81731.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_81732_82151.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_82152_82487.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_82488_85979.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_85980_88163.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_88164_88295.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_88296_88499.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_88500_88583.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_88584_88763.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_88764_88955.png recon2016-19-alex-ionescu-Abusing-the-NT-Kernel-Shim-Engine_88956_89719.png
I'd like to welcome someone who's participating in recon for the very first time. I apologize for the transitions in the slides. I just realized now that the company template has transitions, which I hate, so sorry for that. I'm going to be talking about the kernel shim engine in this talk and I'm going to do a brief introduction about myself and presentation. Then we're going to look at what exactly the shim engine is, what it does, how does it shim. We're going to look at how you can write a shim driver or how existing shim drivers function. And we're going to take a look at a few examples of existing shims that exist on the operating system. Now because shims in the kernel are undocumented, there's not any tools, there's not any debugger extensions, there's no symbols for actually understanding what's being shimmed and who's shimming what. So I'm going to show you some WinVac scripts, some registry keys, some event log functionality that we can then use to figure out what shims are active. So if you're doing IR, if you're doing endpoint protection, if you're trying to understand what's going on, hopefully that'll be useful. Then I'll be doing a demo of a tool called DriverMon, which is built on top of the shim engine in which we plan to release in about a few weeks time. Then we'll conclude and do some Q&A. So a little bit about myself. I'm a chief architect at CrossStrike right now before I worked on the Apple Core iOS team. So I'm a big fan of operating some internals, both Windows and Apple. So I'm a co-author of the Windows Internals books. I've been doing a reverse engineering for about 15, 16 years now of the empty kernel. Far too long. I wish it would just die. But anyway, it's still around. So I do a lot of conference speaking about design issues in Windows or undocumented modules in Windows. Things that are fun to poke at, things that can give you interesting levels of access or interesting kinds of persistence or hiding or things like that. So this isn't the same kind of realm as that. Someone who's not presenting with me today is Robin Keir. He's a fellow coworker at CrossStrike and he helped with the DriverMon tool immensely. He actually rode the whole GUI for it. So when we do talk about a DriverMon tool, that's all really his work. So I took care of the driver and the internals, but big thanks to Robin for doing that. So basically, we're going to be looking in this talk at another component in the kernel that's not very well known called KSE, the kernel shim engine. And if you attended last year's recon, I gave a talk on binary instrumentation technologies and hooking. So how from user mode you can hook binaries using a shim engine and using other technologies. So in a way, this is kind of a follow-up because I figured, well, all that was user mode, can you do some of this stuff from kernel mode as well? So we're going to talk about a way that you can now hook any Windows driver using a legitimate interface. So without actually having to patch your own IAT entries or hook the driver object. So this is going to let you hook IAT entries, so imports. It's going to let you hook herbs. It's going to let you hook driver callbacks. And it's actually a really nice interface to program against. You just kind of tell it what you want to hook and it does it all for you. The trick, of course, it's undocumented, so you have to figure out those data structures. Then we're going to talk about how to, again, forensically look for shim providers. So what's already on the machine? What's it shimming? Are there things that should not be there by default? And we'll talk about something interesting, which is how you can actually hook the hook engine itself or hooking the shim engine, which has some interesting kind of bypass properties. And we're also going to look at some built-in shim providers, built so you can kind of know what's already on the machine. So if you have a shim that's not on your machine, that's interesting. Or if you have a shim that is on your machine, but that's not on the list of default shims, well, then you have a third-party shim and you really shouldn't accept the tool that we're releasing. And then I'll talk about this shimmer tool that I wrote and kind of how a driver can register with the shim engine and how to interact with it. And then I'll do a demo of the driver mount tool, which I think will be pretty cool. So let's talk a little bit about how the kernel shim engine actually does its work. So basically, the whole point of the kernel shim engine is to provide two types of shims, or app-compact. Whenever you say shims, we always talk about app-compact behavior, basically. And there's device shims and driver shims. Device shims are basically ways to apply flags or specific policies to certain devices, identify by their hardware ID. So you have some particular kind of USB device or some particular kind of PCI device. And different bus drivers, like the PCI bus driver, the USB bus driver, and also class drivers, are going to be checking what flags are active for those devices. And so, for example, if you have some sort of weird USB device that requires one millisecond instead of half a millisecond to initialize itself, there's going to be a hack flag that basically says, you know, required, but flag number four. And it's associated with this hardware ID. This way, the driver sees, oh, you've got a device that has flag number four active. Well, that means that I have to wait a little bit longer when re-initializing the device. So this has been there since Windows XP, under the guise of app-compact. Then, this thing had the Erota manager, which kind of does the same thing. And then in the registry, you have sometimes flags called PCI hack flags or things like that. So it's really yet another way for device drivers to be able to identify if there's some sort of weird device on the machine. The second kind of shim this provides is driver shims. And a driver shim is basically a file name, a path to a driver that you would like to hook. It's imports, it's callbacks, or it's IRB handlers. So it does both driver shimming and device shimming. Basically, during the IMAG initialization, this thing initializes in kind of two phases. So there's a function called KSE initialize, which does that. And it parses the same STB database that you might already have heard about in terms of app-compact shims and IE shims and other presentations that have been done. So the exact same format that's used for user mode shims, MSI shims, is also used for kernel shims as well. Now KSE will not initialize if you're in save boot. It won't initialize if driver verifier is enabled. It won't initialize if there's actually no database, like you deleted it off disk. And it won't initialize if you're booting in Windows BE mode. So like in recovery mode, there won't be any shims either. This shim database is called driver main.sdb, and it's located in the same app patch directory as everything else. And it appeared in XP. And in XP, again, there was no kernel shim engine, but there was this app-compact engine where you could have certain flags. And with changes in Windows 8 with the kernel shim engine, it's the ability to have driver shims as well. So this is loaded very early on by winload.exe, which is orb.efi, which is your Windows bootloader. It looks in system 32.cwindows.apppatch.drvmain.sdb, and it loads that. And then it also loads the irata-manager.inf file, but we're not going to talk about the irata-manager here. It then stores in a loader parameter block extension, the base address of the shim database, and the size. This point is already loaded in memory, and in all cases, it has to do is now just parse it from memory and look up all of those data structures. And when you have user mode shims, you can tag, you can associate a user mode shim with a particular binary. What's cool in the kernel shim engine is you can associate a shim with a particular type of device. So you can say, if you have this type of ACPI table, and you have this type of BIOS, and this type of CPU, then this shim applies to you. So it does some of that look up in there as well. So device shims are basically exposed to three APIs, KSE Query Device Data, KSE Query Device Data List, KSE Query Device Flags, and device flags are basically a subset of device data. They're the XP flags that always existed. The XP flags became a subtype of the device data. Now this device data can actually be queried from user mode. So those functions are kernel functions, but if you call anti-query system information, which is a well-known Windows undocumented API for getting all sorts of interesting things from the system, you can pass in those two information classes, and that's going to give you the device data for a particular device. And device data, again, it's flags, policies, things that make this device interesting or unusual compared to other devices so that its driver can basically react to those differences that the device might have. The other place device data can come from is the registry. So device data can either come from the SDB database when it's loaded off the disk, or it can actually come from registry. And in the registry, you basically have this Reggie registry machine Windows system, current control set, control compatibility device, and you take a hardware ID, which is like USB ampersand, some number, slash, bus ampersand, some number, you replace all the slashes with banks, and if there's anything in there, that means there's device data for that device path for the hardware ID. If it's not in the registry, they're going to look up in the cache because all this device information is cached, and if it's not in the cache, then they're going to look in the SDB. And in the SDB, basically if you're not familiar with the SDB format, which is now documented, and there's lots of tools to dump it, everything's identified by tag, attack or response to a given data type. So there's a tag 7013, which is a flag, which is read by read read Kflag, and there's another flag called Kdata, which contains just arbitrary value pair data. So Kflag, there's a few of those in the SDB file, and I'll show you some dumps. Kdata, I haven't found anything in my Windows 10 driver main, so it's implemented by, I haven't seen any data other than flags that is at least in the inbox SDB that I've got. So who actually reads device data or device flags? You've got a Bluetooth driver, port driver, and numerator, the audio driver, the audio bus driver, the Bluetooth hit driver, the generic hit driver, and this, which is the network driver in Windows, UFX synopsis and URSCX, which I'm not sure what those do. I think it's another type of Bluetooth type stuff. And then USB hub, which is the USB driver. So all those, basically what that means is that all those drivers recognize that some devices that they manage are strange, and the device flags, if they match particular hits on your machine, these drivers will act differently. So either fixing iradas or working around a hardware bug that might exist. Kc also implements a hardware ID cache. Not 100% sure what this is used for, but basically anytime a driver, anytime a plug and play discovers a new device, it's going to capture the whole hardware ID and then adds it into another cache database. And then there's an app help function, NT app help cache control that you can call from user mode, which is used by the application helper service. And then this basically lets you query the hardware ID. So it's a very simple way of knowing, is this hardware present on your machine? Because all the plug and play hardware is enumerated in a, in this cache, and then the application helper and user mode can just call it and say, dump me all the hardware IDs or tell me if this hardware ID is present. Kind of weird because the plug and play manager already knows and there's APIs for doing that, but you know, this is Windows. There's always like 10 different ways of doing something and 15 different things that store the same information. So that's another thing you can dump from user mode, basically all the hardware IDs on the machine. The other stuff this does then is driver shimming. And there's some built in driver shims that you have as soon as KAC initializes. One of them is called driver scope. So driver scope is a built in shim and it hooks all driver callbacks. It hooks IocTools. It hooks create and close herbs. It hooks power herbs and it hooks plug and play herbs. It then hooks Iocray device, PO request power herb, X allocate pool, X free pool, and basically when this shim is active, all it does is hook all those things and it just prints out over ETW, which is event tracing for Windows, which is kind of Windows' internal tracing mechanism. Anytime that happens. So just kind of hooks those things and tells you that it happened. As the name suggests, you have a driver scope, kind of like a scope for drivers. We're going to see driver scope is never active on anything by default, but it basically means if you activate it and we're going to see how you can activate a shim, you get some ETW events. Then there's another three set of shims, Windows 7 version lie, Windows 8 version lie, and Windows 8.1 version lie. And as you can probably imagine, these are going to hook RTL get version and PS get version. And each particular hook will return a different version. So just like in user mode, you can enable XP compatibility mode or Windows 7 compatibility mode. This basically lies to the driver and makes the driver think we're running on a different operating system. And there's another one called skip driver unload, which kind of worries me. Basically that hooks your driver unload function and just doesn't call it anymore. It just prints out ETW. Yeah, I'm not going to bother calling the unload for this driver. That is not active on anything by default, but you know, it's an interesting one. So how do loaded drivers get shimmed? Well, whenever a driver gets loaded, which either is going to happen by IOP initialize built-in driver, MI compact service table or MI driver load succeeded, KSC driver load image runs. This will then do two things. It's going to get the shims for a particular driver and then it's going to apply the shims for that driver. Once the driver has been shimmed, you get an event trace and we're going to see how you can look at that in event log. There's a variable in the kernel. We're going to see that basically points to the last driver that got shimmed and you get some flags as well that tell you a shim is active. So when we're going to look at introspection later with some currently bugging scripts, we're going to see side effects of basically that being enabled. At that point, whenever a module is now being shimmed, it gets added to the shimmed driver list and there's a function called KSEP is module shimmed. And this is basically going to record the load address of every driver that has been shimmed, the number of shims that this driver is currently that have been applied to this driver, and an array of all the shims that have been applied. So if you're not already shimmed, then we're going to search the registry to see if there's any applicable shims for your driver. And we're going to see how the registry basically allows you to shim a driver. So this happens with KSEP Engine gets shims from registry and KSEP registry query driver shims. Now, if the registry says that you have a shim called foobar registered for this driver, we're going to look in the SDB in the database, is there a shim called foobar? So the database actually has to define all possible shims. A shim then has a shim descriptor called a Kshim, which basically tells us the name of the shim, the GUID of the shim, and the module that should be providing the shim. So the driver, that's actually going to be doing that. Another possibility is there's nothing in the registry, and there's nothing in the registry, then the SDB file itself can have what are called Kshim references, and can basically identify this driver and that driver and this driver need to be shimmed by that shim, and then the shim is defined in the SDB as well. So I can either shim a driver by putting that in the registry, or I can shim a driver by putting that in the SDB. And then each shim is described, like I mentioned, by a GUID, a name, a command line, and also a source. So you can know, was this driver shimmed because of the registry, or was this driver shimmed because it was in the SDB file, which again is useful once we go and dump these things in memory. Now, once we've identified that a shim is active and correctly defined for a driver, we're going to be resolving the shims. So we're going to see, is that shim for smaller registered? Because for a shim to be registered, that means a provider ran the provider, the shim provider, registered that shim and says, I provide shim called foobar with the GUID, you know, so and so. Now, it's possible that a shim provider hasn't yet loaded. In other words, you're loading the driver before you're actually loading the shim provider. Now, that's what we're going to check is this shim, a delay load provider. If it's a delay load provider, we're actually going to go and load the provider name manually by basically seeing what's your name and calling the ZW load driver and loading that driver. Once the provider has been loaded, we're going to dump all the registered shims again, and at this point we should expect to find that shim in the driver list. Otherwise, something's wrong. Basically means that, you know, this module for whatever reason is not providing the shim that it's supposed to. If it is, the next thing that happens is we're going to dump all the loaded modules, because one of the things that shims can do is hook IET entries of any driver. So we're going to dump all the drivers that exist, and we're going to see, does your shim hook any of the drivers that this driver might import? Right, so I have one driver that's basically, you know, foo.sys. It's importing from bar.sys, and your shim driver is basically saying, bar.sys as function has to be hooked. So we're going to see, is there a bar.sys loaded? If there is a bar.sys loaded, does it have the function you're trying to hook? And if the function you're trying to hook exists and bar.sys is loaded, then we're going to go ahead and apply the shim a little bit later. We're not yet applying the shim, we're basically just checking, do the shims actually resolve to anything? Because if there's no bar.sys, or this version of bar.sys is not exported at API, well then your shim can't hook anything, so we basically can bypass that. If not, your driver is now ready to be shimmed. In other words, we have found a shim that's valid, we have found all the things shim wants to shim, and all the exports exist. So we're ready to proceed to the next stage, which is going to be applying the driver shims. So it happens with a separate function, ksep, apply, shims to driver, and this is going to go in ksep, patch, driver, imports table, which calls ksep, patch, import table entry, which then calls mmReplace, import entry. So the marry manager has a whole bunch of functionality now to basically safely and correctly patch IET entries, take care of the section objects, and all that. At that point, your shim provider gets a call-out notification, which we're going to talk about later, which basically tells you, okay, you are now shimming this thing. But the only thing we've shimmed so far are functions, IET entries. And there's two, or really three types of things shims can take care of. You can shim the exported functions of a driver, but you can also shim the callbacks that a driver receives. And right now we haven't done any callbacks, because all we've done is we've loaded your driver. We haven't yet initialized it. So once your driver actually initializes, which is done by IOP load driver, or IOP initialize built-in driver, then we call ksep shim driver IO callbacks. This will now call ksep get shim callbacks for driver, and it's going to hook your driver callbacks, driver in it, driver unload, start IO, add device, and then it's going to hook all your IRB handlers based on whatever my shim describes. So two stages here. First stage, hook the imports as soon as the driver loads. Second stage, hook the callbacks and the IRBs as soon as the driver is initialized. And then the shim is fully active. So let's see how we can write our own driver that basically makes a shim engine do all the stuff for us. So the first thing we need to do is define a ksep shim. Again, a shim is a compatibility fix. A compatibility fix is a set of functions we have to hook, and callbacks we have to hook, and IRB handlers we have to hook, and by hooking all those things, the idea is we're providing, we're fixing, we're working around some sort of bug in this driver. So the structure's not documented. It's basically my own definition of it. Fairly is the reverse. So basically you have the size of ksep shim, a GUID, and a name. Now the name of the shim that you're registering, and the GUID of the shim you're registering, must match one of the shims in the sdb file. And the sdb file has your shim name and your GUID. So you can register, I mean you can register an arbitrary shim, but nothing will use it because the sdb file won't actually match up to that. Then you get some callback routines, and we'll see what those are useful. And then you get two notifications. One when your driver has been targeted, so when you've actually loaded, not you, sorry, when one of your drivers is shimming has been loaded, and another one when one of the drivers is shimming has been unloaded. And then you pass in an array of hook collections. What's a hook collection? Well, a hook collection is basically a type of hooked entity, and there's two entities you can hook, functions or driver callbacks. And functions can either come from NT, they can come from the HAL, or they can come from an arbitrary driver. So 0, 1, and 2 are used for function hooks. If you said that they're coming from an arbitrary driver, then you have to pass in the name of the driver you're hooking. Otherwise, if it's an NT hook or HAL hook, well, we all know the name of those things are, so you don't have to bother with that. Otherwise, type 3 is a callback, and a callback means you're hooking either a driver callback or an ERP handler. And now you define the collection of hooks, and you now have to go and actually define the hooks that make up this collection. So that's now with another structure. And kind of repeatedly, that structure has its own type, 1 for function or 2 for callback. And if this is a function, you have to give it the function name that you're hooking. If this is a ERP callback, you give it a callback ID. I'm going to see what the callback IDs match up to. You then pass in the address of your function that's going to be hooking that thing. So the hook function there, that pvoid, is a pointer to your hook. And in original function, you get a pointer back to the original function that got hooked, the idea being that if you do want to hook the original function, you call original function and then life goes on. But that is only filled out if this is a function hook. If this is an ERP callback hook, that actually doesn't get filled out. So we're going to have a problem. We're going to see how to deal with that. So how do you hook a function? Well, again, fairly easy. You look at what you're trying to, what exports a thing. If the exports Entos kernel, you create a collection of type 0. If the export is hal.dll, you create a collection of type 1. And if this is a custom driver, you create a collection of type 2 and you put down your driver name. So I have a very simple example here. If you're trying to hook xallocate pool tag, you say 0 because xallocate pool tag is an Entos kernel. You put in the name xallocate pool tag and then you give it a pointer to your hook of exallocate pool tag. And then null, that's where you're going to receive the original xallocate pool tag. So then your hook function, you do whatever you want to do because you're hooking xallocate pool. And then you return hooks 0 original function. Basically then call the original function that's there. Or maybe you'll just decide, nope, I'm not going to allocate any memory for you, which would probably be bad. Now, one of the things you might want to know inside of your hook is if I'm hooking multiple drivers of the same shim, what driver is actually calling xallocate pool? So there's no kind of built in way of knowing that, but you know you've got an interesting visual studio called underscore return address, and they'll give you the return address of whoever called you. So that way you can tell what driver actually is hooking exallocate pool. So if you want to filter on certain drivers only, you can do that. Obviously if you're only shimming one driver, then you don't need to worry about that. So what about hooking callbacks? So there's four callbacks you can hook. You can hook driver in it, driver on load, driver start IO, and you can hook add device. Or you can hook every IRP, which are IO request packets, which is how Windows actually does IO. So there's IOs for create, for close, for read, for write. There's up to IRPMJ maximum function IRPs. Interestingly, you can hook in you these things, except actually driver in it. Because if you go back a few slides, we said that we hooked all the functions as soon as driver loads, and then we hook all the callbacks as soon as driver initializes. So you can specify a driver in it hook, but it won't actually ever be called, because your hooks only get applied after driver in it runs. So kind of a design fallacy there. You can see I've got the pseudocode. We call driver in it, then we apply the hooks, and driver in it never gets called again. So we're never going to call your hooked driver in it. Oops. So we said that if you have a function, you get the original address. Now when you hook a callback, you don't actually get the original address filled out. Instead, what you're supposed to do is you're supposed to call this other function, KSE getIO callbacks, and KSE getIO callbacks returns to you the original callback. So kind of weird for functions, you get the address. For callbacks, you have to ask it what the address is. And you can ask it one, for the original address of driver in it, two for driver startIO, three for driver unload, four for driver add device, and for herbs, every herb has its own number. For example, IRPMJ create is zero, IRPMJ read is four or three, IRPMJ closes two. What you do is you add 100 to that number. So if you ask for 102, then you get IRPMJ close. If you ask for 100, then you get IRPMJ create. So one through four are those hard coded ones, and then 100 plus the herb identifier are the herb handlers. Now how do you call KSE getIO callbacks? Because that's actually not an exported function. Well, let's go back for a second here in our definition of a KSE shim. So there's this field here called KSE callback routines. Well, let's see the resolution screwed up. Anyway, this thing here KSE callback routines, that's where you actually get a pointer back to KSE getIO callback. So it gives you the function that you need to call. So that's how you find it, basically. And then you can call the original function. Now the other thing with herbs is that unlike function calls, which return immediately, herbs can either be returned immediately. But by the time they've returned, the herb has actually been completed, meaning that the other side has already received the answer, and the herb structure which contains the answer may have already been deallocated or freed. The other possibility is that the function cannot return immediately. In other words, this is an asynchronous I.O. So the herb will be completed later. So if you do try to read from the herb, there's no answer yet. So you kind of got two bad choices. You read from the herb and you'll crash because the herb is gone, if the operation succeeded, or read from the herb and get useless data because the herb hasn't actually completed. So what you actually have to do is register a hook for the completion of this herb. And again KSE gives you a function for that, KSE set completion hook. And you can say for this herb, I would like to hook its result so I can actually know what happened with it. And again KSE set completion hook is not an exported function. It's another callback that you receive in your shim. So your shim structure basically gets back the addisive KSE get I.O. completion callback. So you know what to call when you're done. And KSE set completion hook if you'd like to request a hook for the herb. Which is nice because that basically means you're going to have pre-operate pre-hooks before the herb actually gets processed by the driver. And you can have post-hooks after the herb has been processed by the driver. So for example for IRPMG write, in your pre you can see what the user mode app is trying to write. In your post you can see the write actually worked and if so how many bytes have been written. For a read, well when you see the read in your pre all you get is someone wants to read something. In your post then you actually get to see what was actually read. The other thing I mentioned you get is two callbacks, the shim targeting callbacks. And so whenever a driver is actually going to be shimmed by you, you get a notification from KSE saying you are now shimming this driver. And you get the name of the driver you're shimming, its load address, its size, its time stamp and its checksum. And when a driver is unloaded you get the same information back telling you this driver that you were shimming before is now gone. And so what's interesting now is with this information you can basically build yourself like a memory map of okay from here to here I have this driver is here, from here to here this other driver is there, from here to here I've got another driver. And then in your function hook when you get the return address you can scan is the return address in one of these memory blobs that I know about. Okay then this is this driver trying to call me and you have its name and its checksum from your targeting callback. For an ERP, well an ERP gets a device object, a device object points to a driver object, the driver object points to the star data of the driver. So again you can match up the start address of the driver that sent the ERP with the, sorry that's handling the ERP with one of the drivers you're targeting. And that way you can know exactly what drivers are you currently hooking in the middle of your ERP or in the middle of your function hook. So once you define all these structures how do you then register for a shim provider? Well there's a nice little export API for you called KSC register shim EX and you basically pass in that KSC shim structure which identifies your shim, your GUID, your name, the collections of hooks and the actual hooks and you pass in your driver object. That means that KSC will now take a reference on your driver and if you actually try to unload your driver while you're still shimming things it won't actually let you unload. So it's going to run through your driver on load but it's going to keep you resident in memory. So you're not going to be handling any new kind of IOs but anything that's shimmed will still go through you unless you unregister your shim and that thing then goes away as well. So this allows you to basically reference counting and making sure that you don't end up with a shim driver unloading while there's active shims which obviously will now call a null pointer or something worse. So basically these are the two things. If you unload and unregister your shim but drivers are still active you remain resident in memory. Similarly though it also means if you load your provider after the driver is already loaded you can't shim an existing running driver. So you have to reboot the machine and shim it at boot or unload the driver and reload it because if the driver already ran you were never registered so there was nothing to hook to begin with. So let's look at a few examples or at least one example of a built in actually not a built in but an inbox shim. So basically a not a third party driver but an inbox driver that's not the kernel that registers its own shim. Because basically by looking at this that's how I kind of understood how shims work. So in the built in database there's a number of interesting things in there and you can dump the database with STB Explorer, great tool. TZWorks has something they call shims which also lets you dump the shim database and then Microsoft actually has something called shim to XML or STB to XML which lets you dump the shim database as an XML file. And then in the shim database you're going to see app help entries which basically say this driver is not something we want to load so just block it and that's done in user mode actually. So that's one part of the shim engine that's not done by the kernel. It's done in user mode and the driver tries to install itself, you get a little pop up that says these drivers not compatible with Windows. Then you have K device entries and we're going to look at a few of these which are used by the device compatibility stuff. So any flags that need to be applied or any device data that's K device and then K driver is used by actual driver shims. So the driver shims are in there and then K shim are what shim providers are actually registered. And again every provider has to be in the STB. You can't kind of make up your own provider without any definition for it. So you can look at a few examples. I've got both the XML dump from one of the tools and the XML dump from the other tool. So there's one here that basically says this is a K device shim. So this is a device shim and the name identifies some sort of hardware. So if I have something from vendor 1B21 product 1 0 B 0 which looks like it's an AS media vendor. So some sort of USB 3 device made by AS media. It's going to apply the flag 4096 with the name USB. And the implication here would be that the USB class driver would then call KSE get device flags passing in the device ID over here. And the shim database would say, yep, I know this device. It's got flag 4096. And then 4096 to the USB class driver means something like again, you know, this device takes a longer time to initialize. So you should take longer as well. So the example of a driver shim is at the bottom. And this is basically saying that T s s safe dot sis a QQ game from Tencent. I love it when games load kernel drivers makes me feel really safe. This pops up a message that says a driver is installed that causes stability problems with your system. No surprise. And then it basically has, you know, the product version associated with that. So that's an example of an app help shim that basically says, yeah, we're not going to let you load this driver. It's it's bad. And later on, if we have time, I'll share some other examples. Again, these are just from the dump of the SDB database dumped with SDB 2x ML, which is that Microsoft tool. So what are the built in Windows shims and providers? If you look at the database, well, there's driver scope, skip driver unload KM version line, which are built in. Then there's two interesting ones called KM auto fail and auto fail, which are meant to be registered by KM auto fail dot sis and auto fail dot sis. But those don't actually exist. Then store port device ID shim and SRB shim are registered by store port dot sis, which is the Windows storage driver. USB shim is registered by USB D dot sis, which is the kind of the generic library that all USB devices use. And end is get version 640 shim is registered by endis, which is that driver allow drivers try to check which version of end is the wrong. So I'm guessing just like the version line, this allows and is the light driver and say, no, no, I'm not and this 6.6. I'm in this, you know, 6.4. Then in the registry, so mentioned certain drivers can be targeted. So by default on like a clean Windows then installation. If you go to the key there in the registry, the compatibility key. So under that sub key called driver and under that sub key, there's different driver names and might see in the screenshot. There's a few there that I've added, but the one that's there by default only is store a HCI dot sis, which is the HCI or you know, SATA storage driver. It has the SRB shim applied. So basically whenever you load store a HCI dot sis, it's going to be shimmed by SRB shim, which on the previous slide we saw that SRB shim is registered by store port. So store port access will be shimming store HCI dot sis. But that's only in the registry. So remember then the SDB can itself have other shim information. So just a few examples here USB shim hooks WSR RCI dot sis, edgerser 64 dot sis, ACF DCP 64 dot sis. So those driver vendors are doing something wrong and USB has to come in and kind of fix them up and this get version six portion. There's some real tech drivers in there. KM win eight one version line something called the frag FS sis in there. And there's other shims which are again loaded by shim by other things. So, you know, if I open up here the database that I've got SDB dot text. That's not the right thing. And anything that basically has K shim ref in there is something that's going to be hooked. So that's coming from can that's USB. That's the one we've seen. But here's one I didn't have in the slide. So for example, there's where is it Franklin. The resolution doesn't let me zoom in properly. There's a Franklin use excited driver and it is being shim by KM win seven version lie. So this driver needs to be told that one window seven. So again, just dump the database and you can see all these examples for your safe. Basically, and Windows update can obviously update is as the database and can add additional devices in there as an additional shims as they're needed. So let's look at one of those examples. Scuzzy port registers a shim to shims actually SRB shim and device ID shim. Both of those only should have one hook collection. It's a callback collection. And there's a single hook for that callback collection, which is the hook for IRP MJ device control. So any I octals sent to store port or through sorry through store HCI, which store port is hooking will be hooked. And there's a function device ID shim hook device control to hook I octals for the device ID shim. And there's SRB shim hook device control, which hooks the octals that SRB shim is okay. So SRB shim. What is it then doing? It's basically for any I octal that's I octal storage query property. And if you're querying standard property and the property ID is storage adapter property and you're expecting 32 bytes or more, then it's going to target this service and say, all right, this is interesting. So I want to register a completion callback or completion hook. So in the IRP completes, then I want to be notified in the completion hook. What does it do? Well, it basically checks again, did we return 32 bytes or more and did we turn it successfully? And if so, we're going to go in and we're going to edit the actual. We're going to edit the actual SRB type and address type field. And we're going to set it to zero. So basically override this legitimate valid data that we received with zeros. So that's kind of interesting. Why are we doing this to poor store? HCI dot says, why are we clearing out these bottom two fields that, you know, we're legitimately returned. And so if we actually read them as the end, basically tells you that SRB type was added in Windows 8 and address type was added in Windows 8, meaning that an older driver that's interacting with store HCI wouldn't necessarily know about those fields. But then what's the problem? Like why would they have passed the size that is 32 bytes or more because the size of the structure without those two elements, if you count it should be 30 bytes. So the driver is asking for 30 bytes, it shouldn't get those fields. Why would a driver that doesn't know about those fields ask for 32 bytes? Well, if you actually look at the structure in Ida turns out that because of alignment, because you've got an existing word at the end of the structure and structures are four byte aligned, you have two bytes of alignment at the end. So the actual size of the Windows 7 structure is 32 bytes and the bottom two bytes are just padding. And so you might now instead of padding on Windows 8 get actually data that's there. So they zero out that data to basically pretend, no, no, that's still padding because you're a Windows 7 driver and you shouldn't know about those fields. So either that's because someone was, you know, expecting padding or hard, you know, reading the previous field incorrectly. For whatever reason, they're playing it safe and they're saying, you know, that driver will still see the Windows 7 structure. So that's an example of a shim, highly specific shim, but it's a really good example on, you know, how I could write my own shims after that. And all this was easy to analyze with basically all the symbols that are in Ida. So that's kind of how an inbox shim works. I want to show you how you can actually see the shims and introspect them. And there's different ways you can introspect the shim engine. Now, because there's actually no symbols, it's very hard to analyze at runtime what's actually going on. But if you have a kernel debugger and you have, you know, some scripts and the right knowledge and you've done reverse engineering, you can get a pretty good overview of everything that the shim engine has actually been doing. So I'm going to show you a few shims here. Hopefully they're going to work. Shim.ws, which is kind of, it's going to display some information about the shim engine on my machine. Shim.ma.wds, which is going to dump any modules that are being shimmed. Shimreg, which is going to dump any shims that have been registered. And shim cache, which can dump the shim cache. So either the hardware ID cache or the device data cache. So I'm just going to demo the scripts for now and clean them up, comment them a little bit, and I'll probably post them on GitHub later next week so you can actually use these scripts and learn from them and do your own introspection as well. So basically they all rely on this structure called KSC Engine, which is a global in the kernel. Again, not documented, but this is kind of what I've been able to reverse from it. So there's some flags, some state information. There's a list of all the shim providers. There's a list of all the drivers that have been shimmed. And then there's the cache, the device cache, and the hardware cache. And then there's the last driver that got shimmed. And so the little script that will display the state of the KSC Engine. So let's try that. Shim.ws. And this is basically saying the engine is ready. Driver shims have not been disabled. Device shims have not been disabled. These are the address of the two callback routines that drivers can call. This is where the device cache is. That's where the hardware cache is. Here's the list of registered shims. Here is the list of shimmed drivers. And the last driver that got shimmed is afd.sys. And this is basically saying that on my system, afd got shimmed. And then there's some state flags, which are indicating, for example, that no group policy was found. So shims have not been disabled or enabled by group policy. They're just not configured. And active driver shim, which is indicating that something is shimmed. And there's a good sign of that, which is that afd is shimmed. So that's just kind of a global state about what's going on. At this point, I can, for example, take the registered shims list. And I'm going to dump it with a bang list and run a little script that should hopefully show what those drivers are. So that's shimmedreg.wds. So KSCDS shim has been registered. That's driver scope, but there are no active shims. So driver scope isn't active. Win7 version lie shim has been registered, but it's not active. Win8 version lie registered, but no active shims. Win8.1 registered no active shims. Skip driver unload registered no active shims. Store port SRB shim also not active device ID shim not active and the shim not active. Let me have a little error module load complete, but symbols could not be loaded for blah, blah, blah, blah shimmer dot sis. That's my stuff, which has two active shims. So shimmer is actually shimming two things. And then this is CS shimmer as a driver name. So we're going to see what that one's all about. And then USB de shim. So basically you can clearly see with the script that something's actually shimming the machine and it's, you know, the strange shimmer driver. All the built in shims that we've seen, they're not shimming anything at all. And so if we go back to the KSC structure, that what we just dump was the list of registered drivers or shimmers. Now we can see what's actually being shimmed. So that's a different list there. So let's try that one. So this is shim mod. That's the address of that list. Cross fingers. Okay. And two things are being shimmed. MP. So actually, so there's a shim module here. That's a bug. There are no not six billion active shims. But next one MPFS is being shimmed and there's one thing shimming it. And there's going to be a ray of all the things that are shimming it and in that array, you're going to find shimmer and then a of these being shimmed. And again, that's because of the special thing I've loaded, which I'm going to demo. So I can see all the shim providers and how many things are shimming and I can see all the shim things and what's actually shimming them. So that should be pretty useful. And then I'm not going to dump the shim cash, but it basically a bunch of hardware IDs at that point. So can you turn this thing off by the way or what are ways again, you can kind of interact with it. So there's a registry key called compatibility where you can disable device shimming or you can disable driver shimming. And if you go to the group policy editor GP edit, you can actually go, you know, when it's components device and direct compatibility and you can turn off device compatibility, which means no device shims, no flags, or you can turn off driver compatibility settings, which means no driver shims. Then there's a secondary registry key, which is in current control set control compatibility, which for your system, you can use disabled flags and disable flags. One means you're disabling driver shims, disable flags to means you're disabling device shims and both of them together, aka three means you're disabling both kinds of shims. Now from the debugger, there's a variable called case of debug flag. And if you set case of debug flag to a mask, you can then see all errors, all warnings, any information from the debugger, the kernel debugger, the kernel shim engine, because KSC has debug prints everywhere. It even has an array called case of history errors, which contains an array of all the errors and you get the file name and the module ID and the status code where an error happened. Then in the event viewer, there actually is a kernel compatibility log, and you can see, for example, event log entries when a device shim has been applied and tells you the source. So for example, on my machine, there actually is a USB device which has a flag applied to it, and it says apply through compatibility database. So the SDB on my surface has actually applied a device shim. There's another event log sample here which says one shim was applied to driver afd.sys, applied to the registry. And that's the shim that I'm actually going to demo, and that's part of the driver mon. So in the event viewer, by default, you can actually see these operational messages that are going to indicate to you if any shims are active. So you don't actually necessarily have to use the debugger. You get some information in the event log as well. Obviously with the debugger, you can actually see the driver because here all he says is this GUID has shimmed AFD, but what is that GUID? So basically with this ability to then be able to shim any driver, I came up and created this tool called shimmer. And it was very ugly, command-lay utility reminiscent of like pullmon, if you're familiar with pullmon, and basically just showed you the driver at the time, on which CPU, which pit, and which pit did something. And as a demo, I basically shimmed all the IRPs and the allocate and free pull functions. So I want to show this tool because instead of thanks to Robin, he built a different tool called drivermon. And drivermon basically was meant to kind of not replace, but be like prokmon. So if you're familiar with processor monitor, the ability to search, filter, and highlight operations, to do non-instructive filtering and boot logging, to be able to export to a CSV, to be able to decode different octals. And so I started working on a tool on a spare time, and we basically have a 1.0 release that's almost ready. We basically have to wrap up the UI, the ULA, the build, the signing, and all of that. And it should be on the community tools page. So if you're familiar with like Crowd Inspect or Crowd Response, it's going to be on that same page. I managed to avoid not having it be called crowd something, thankfully. And we've got a mailing list that's going to be set up to drivermon across trike, or you can just reach out to me on Twitter once the tool comes out if you have any kind of questions or feature requests or things like that. So basically this is what it looks like today. I'm actually going to be demoing it. But this is the pretty picture in case demo fails, because demo gods and all. So this is kind of showing you NPFS. Inside of search indexer, did a write. It wrote 14 bytes. Now I won't show you yet what those 14 bytes were, but you know, that's obviously wanted. Then search indexer allocated from the pool, a buffer. And then it read from a pipe, 1300 bytes as well. So because this is NPFS, these are implying that these are kind of pipe operations. But I'll show you some AVD dots, which would imply that these are metric operations. So let me actually run drivermon. Feel bad things fail. Okay, so I'm just going to hit capture. And it's starting to give us some stuff. So AVD, which is the Windows Winsock driver. So I can see that service host sent an octal. Then AVD allocate a Fritsa memory. Then we got a create, and then we allocated some memory. You know, if I run like explorer. Well, we've got a little bit more AVD from service host. On start menu, a whole bunch of stuff happened when I click on start. Now I'm seeing NPFS kind of got very, very busy. Let's see what happens when we run Chrome, because that'll be fun. Somebody might know Chrome uses named pipes for its stuff. So that's just Chrome sitting around doing nothing. But good thing Microsoft spends a lot of time improving their named pipe file system. Of course, I can stop the capture, which will stop at some point. The UI only really has one thread or two, because this is just like starving the app, nonstop with stuff. And I could close Chrome, and hopefully that'll help things a little bit. So this will stop at some point. Now it's just basically going over everything Chrome did, and I can kill the auto-scrolling, which would help a little bit. And now it's just going to keep on going and going and going, receiving. So this is just like Progma, so I can right click on Chrome, for example, and say, all right, thank you for letting me know that I did that, exclude process Chrome.exe and just excluded Chrome. So now I can see everything else except Chrome. So you know what, I want to see the principle is up too. So right click, thank you, includes poolSV. So I can see just what poolSV is doing with Spooler. I'm going to say include A of the only, thank you, and an I just A of the. So just like the normal filters you're probably used to with Progma. And then I can, of course, clear all the custom filters so everything should be coming back. Now I can also say, you know, processHacker, for example, it loads the driver. So I can clear all this and say, let's go hook processHacker, and I'm going to say, I think it's K processHacker2.sys and say, okay, turn on capturing. Now let me get rid of A of the.sys and get rid of NPFS.sys. Oh, looks like it brought the other one back. Okay, I'm going to have to work on that. So let's run processHacker. Okay, and then by autoscroll and clear, and let's reset the filters. Is it doing anything? ProcessHacker file. It might have renamed itself to processHacker3.sys is actually what I'm afraid of. So I'm trying to double check that file. Oh yeah, it's K processHacker3. All right, so let me just write it one more time. K processHacker3.sys. And then actually let me unload nets.sys.k processHacker3. Okay, edit, run processHacker, and make a sacrifice to them of gods. See if that actually works. Nope, oh well. Can't demo everything. So it would normally work when we figure out whatever is wrong with this thing. So hopefully that's the idea, and obviously the plan is to make it a lot more, you know, less buggy, and to be able to actually see what those buffers are, and decode the octals, and so on and so forth. But it gives you an idea kind of what we're aiming for here. So I'm going to skip the bonuses. But you know, you'll see this on a slide, but basically you can hook the hook engine, which is what I found out kind of the last minute. So those are bonus slides that you'll have online. And so let me just conclude some concluding thoughts. So basically one of the questions you might have is how is the shimmer tool able to shim arbitrary drivers? Because we said that if a shim is applied to the registry, it has to match a shim in the SDB. And I haven't modified my SDB to say that there is now a new shim called shimmer. What's really cool though, the SDB pretty fine some non-extinct shims. So there's a shim called KM Autofail with a GUID. Now KM Autofail doesn't actually exist. So nothing on a system comes up and says, I am KM Autofail, and here's my GUID. So all we have to do is write our own driver, like the one I just did, which basically says, I am KM Autofail. And one of those now knows, OK, cool, I know who KM Autofail is. And according to the SDB, KM Autofail is a legitimate shimmer. So you're legitimate. And then I can just go in the registry and basically all the tool is doing is going to, you know, AFD.SIS, MPFS.SIS in the system, current control set, control compatibility key that we talked about. And it's basically just saying, oh, AFD.SIS has a shim and its shim is called KM Autofail. And now I'm KM Autofail. I basically register with this GUID and now I can shim that. So I'm not sure that's kind of desired behavior. Now, even if that wasn't the fact, though, even if you couldn't do that trick, remember, the SDB files aren't signed. So if you know how to build an SDB file, you can just edit drvmain.sdb and define a new shim in there. So this was a trick that allowed me to avoid having to do that. But even if the trick didn't work, you could always edit drvmain.sdb because there's no signature there. So if you're doing forensics, if you're doing security software, obviously you want to make sure that those registry keys don't contain weird entries, that you don't have drivers that shouldn't be shimmed being shimmed. And you also, you know, be good to have like a check or some sort of database of drvmain.sdb hashes. Because it's not signed, so it's very hard to know, do you have the original Microsoft drvmain.sdb or do you have a modified malicious drvmain.sdb? So you want to kind of get a check sum of it. In all Windows 10 versions should have the same drvmain.sdb unless someone kind of added stuff in there. So that's pretty much it. We have this ability to hook anything we want. We have an API that lets us do that and we can build tools to rely on that and make sure you use those driver debugger scripts that I'm going to release, make sure you don't have weird shims, look at your registry, make sure there's no weird shims in there, and then look at your sdb file and make sure that your sdb file matches what it should be. So thank you very much for listening. And I probably don't have time for questions I'm guessing, or are we doing that? Maybe one or two questions, one over there. Can you serve Microsoft since it's not an OEM for anything other than fucking up OEM drivers? Anything other than un-fucking-up OEM drivers? Well, I have seen the app help stuff being used on something quite surprising. So, whoops, I'm going the wrong way. So if you have this thing called Procmon.sys, I'm not sure who makes that. Oh, right, Microsoft. A driver's install that causes the build-in problem with your system. So they use that on their own stuff, but not as an actual shim, but just kind of blocking. So now I haven't seen any built-in shims that don't work around OEM issues. So, yeah. All right, well, I'll be around if you have any other questions. I'll let the next speaker come up, and thank you again, and enjoy the rest of the recon. Thank you. Thank you. Thank you.
talking about the kernel shim engine in this talk demo of a tool called DriverMon, which is built the shim engine, which has some interesting kind shim engine is to provide two types of shims, or there since Windows XP, under the guise of shims, is also used for kernel shims as well. Now flags. And with changes in Windows 8 with the kernel shim engine, it's the ability to have basically exposed to three APIs, KSE Query Device you activate it and we're going to see how you shims for your driver. And we're going to see how hooks, and you now have to go and actually define to the key there in the registry, the pretty good overview of everything that the shim actually use these scripts and learn from them shims. Here is the list of shimmed drivers. And don't actually necessarily have to use the just showed you the driver at the time, on which as a demo, I basically shimmed all the IRPs and