We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Abusing the NT Kernel Shim Engine

00:00

Formale Metadaten

Titel
Abusing the NT Kernel Shim Engine
Serientitel
Teil
18
Anzahl der Teile
20
Autor
Lizenz
CC-Namensnennung 4.0 International:
Sie dürfen das Werk bzw. den Inhalt zu jedem legalen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
Identifikatoren
Herausgeber
Erscheinungsjahr
Sprache

Inhaltliche Metadaten

Fachgebiet
Genre
Abstract
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.
PlotterMultiplikationsoperatorTemplateRechenschieberGruppenoperationJSONXMLUMLComputeranimation
Kernel <Informatik>BitCoxeter-GruppeDebuggingFunktionalEndliche ModelltheorieAdditionMaßerweiterungDemo <Programm>SymboltabelleSkriptspracheKette <Mathematik>KonfigurationsdatenbankAblaufverfolgungBetriebssystem
Hook <Programmierung>SprachsyntheseBimodulBinärcodeKategorie <Mathematik>Zusammenhängender GraphFächer <Mathematik>Proxy ServerArchitektur <Informatik>ATMBildschirmfensterVirtuelle MaschineObjekt <Kategorie>DefaultSpeicherabzugGraphische BenutzeroberflächeEin-AusgabeEnterprise-Resource-PlanningBitMailing-ListeMAPKernel <Informatik>Patch <Software>BenutzeroberflächeDemo <Programm>Service providerARM <Computerarchitektur>AusnahmebehandlungEinsDatenstrukturRechter WinkelVersionsverwaltungQuick-SortEndliche ModelltheorieReverse EngineeringProgrammierungPhysikalische TheorieFigurierte ZahlPartitionsfunktionComputeranimation
BitKernel <Informatik>ProgrammverifikationKartesische KoordinatenDateiformatBildschirmfensterKonfigurationsdatenbankBenutzeroberflächeVirtuelle MaschineRadiusPhysikalisches SystemEinfach zusammenhängender RaumRationale ZahlNP-hartes ProblemProzessfähigkeit <Qualitätsmanagement>Bus <Informatik>ZahlenbereichAbzählenFahne <Mathematik>UmwandlungsenthalpieElektronische PublikationHardwareBetrag <Mathematik>PunktTypentheorieLastInformationCachingVersionsverwaltungInformationsspeicherungHardy-RaumZustandsmaschineMaßerweiterungSoundverarbeitungKlasse <Mathematik>DifferenteCASE <Informatik>p-BlockHalbleiterspeicherQuick-SortAggregatzustandMatchingBinärcodeRechter WinkelAssoziativgesetzOffice-PaketMultiplikationsoperatorTabelleSpeicherabzugKategorie <Mathematik>DatenbankARM <Computerarchitektur>DatenverwaltungQuaderBefehlsprozessorKonditionszahlSchnittmengeFunktionalHilfesystemATMSystemaufrufWiederherstellung <Informatik>App <Programm>AbfrageHook <Programmierung>DezimalzahlDruckertreiberVerzeichnisdienstDienst <Informatik>Patch <Software>Bildgebendes VerfahrenComputerunterstützte ÜbersetzungTermCoxeter-GruppeMini-DiscDigital Rights ManagementMathematikE-MailZweiGamecontrollerSoftwareGenerizitätTeilmengeEindringerkennungBootenProgrammfehlerParametersystemDatentypAdressraumMultifunktionComputeranimation
AdressraumSpeicherverwaltungTypentheorieService providerLastKonfigurationsdatenbankDatensatzObjekt <Kategorie>AbfrageZahlenbereichFunktionalDatenbankBimodulExistenzaussagePunktHook <Programmierung>Elektronische PublikationElektronischer ProgrammführerSystemaufrufMAPHalbleiterspeicherEnterprise-Resource-PlanningLeistung <Physik>Kompakter RaumDienst <Informatik>BildschirmfensterPhysikalisches SystemBenutzeroberflächeEreignishorizontBildgebendes VerfahrenKernel <Informatik>DifferenzenrechnungVersionsverwaltungTabelleHyperbelverfahrenSchnittmengeLie-GruppePatch <Software>Fahne <Mathematik>AblaufverfolgungGrenzschichtablösungGarbentheorieMailing-ListeATMSoundverarbeitungCASE <Informatik>Geradesinc-FunktionEndliche ModelltheorieMechanismus-Design-TheorieRechter WinkelWort <Informatik>DefaultTropfenAdditionRationale ZahlSchaltwerkKartesische KoordinatenGruppenoperationQuick-SortSkriptsprachePeer-to-Peer-NetzUmsetzung <Informatik>ComputervirusDivergenz <Vektoranalysis>BitVirtuelle MaschineSkalenniveauQuaderHoaxEvoluteQuadratische GleichungIndexberechnungEuler-WinkelProgrammfehlerRegistrierung <Bildverarbeitung>DivisionDatenverwaltungQuelle <Physik>QuellcodeBootenAnpassung <Mathematik>Gebäude <Mathematik>TopologieComputeranimation
Quick-SortHook <Programmierung>TypentheorieFunktionalAdressraumKoroutineElektronische PublikationComputerspielProgrammfehlerLokales MinimumEin-AusgabeEnterprise-Resource-PlanningDatenstrukturMessage-PassingMatchingZeiger <Informatik>Kernel <Informatik>MehrrechnersystemSystemaufrufElektronischer ProgrammführerBetriebsmittelverwaltungSchnittmengeHalbleiterspeicherBildschirmfensterVisualisierungPhysikalisches SystemLastArithmetisches MittelLesen <Datenverarbeitung>Automatische IndexierungAbgeschlossene MengeRechter WinkelTouchscreenMultiplikationGrenzschichtablösungZusammenhängender GraphGüte der AnpassungCASE <Informatik>SoundverarbeitungEndliche ModelltheorieRechenschieberHoaxAdditionComputeranimation
DatenfeldFunktionalMessage-PassingService providerVirtuelle AdresseHook <Programmierung>GruppenoperationDatenstrukturBootenAdressraumHalbleiterspeicherAuflösung <Mathematik>VollständigkeitMultiplikationsoperatorKoroutineZeiger <Informatik>LastAuswahlaxiomSystemzusammenbruchObjekt <Kategorie>CASE <Informatik>ZahlenbereichPunktRippen <Informatik>Einfach zusammenhängender RaumEinsLesen <Datenverarbeitung>Enterprise-Resource-PlanningNichtlinearer OperatorProzess <Informatik>Abgeschlossene MengeIdentifizierbarkeitAusnahmebehandlungSystemaufrufZählenHoaxGarbentheorieInformationRegistrierung <Bildverarbeitung>ZeitstempelResultanteÄhnlichkeitsgeometrieArithmetisches MittelSchreiben <Datenverarbeitung>ATMApp <Programm>
Kernel <Informatik>E-MailDatenbankFahne <Mathematik>SystemaufrufZahlenbereichBildschirmfensterSpieltheorieMessage-PassingVersionsverwaltungMultiplikationsoperatorInformationKlasse <Mathematik>SpeicherabzugProdukt <Mathematik>HilfesystemStabilitätstheorie <Logik>App <Programm>MereologieElektronische PublikationEinsInformationsspeicherungService providerSoftwareProgrammbibliothekQuick-SortHardwareDefaultDifferenteSchlüsselverwaltungHypermediaKonfigurationsdatenbankARM <Computerarchitektur>DimensionsanalyseDemoszene <Programmierung>RechenschieberPhysikalisches SystemPartitionsfunktionp-BlockATMEndliche ModelltheorieGemeinsamer SpeicherDienst <Informatik>Prozess <Informatik>BenutzeroberflächeGebäude <Mathematik>AdditionRichtungInformationsüberlastungLokales MinimumErhaltungssatzGrundsätze ordnungsmäßiger DatenverarbeitungLastSchreib-Lese-KopfStellenringDivisionMinimumComputeranimation
DatenbankSet-Top-BoxRechter WinkelInformationsspeicherungAbfrageDatenstrukturHook <Programmierung>DatenfeldWort <Informatik>BildschirmfensterKategorie <Mathematik>UmwandlungsenthalpieVollständigkeitTypentheorieLie-GruppeEigentliche AbbildungVersionsverwaltungAuflösung <Mathematik>Einfach zusammenhängender RaumSymboltabelleAdressraumAdditionSCSIArithmetisches MittelFunktionalGamecontrollerRechenschieberGraphiktablettStandardabweichungVerkehrsinformationMereologieGruppenoperationDienst <Informatik>OrtsoperatorBenutzeroberflächeBetrag <Mathematik>Element <Gruppentheorie>SchnittmengeKinematikComputeranimation
E-MailRechter WinkelService providerEndliche ModelltheorieNP-hartes ProblemVirtuelle MaschineMailing-ListeInformationKernel <Informatik>SkriptspracheReverse EngineeringGüte der AnpassungFahne <Mathematik>PortscannerDatensichtgerätDatenstrukturAggregatzustandSymboltabelleARM <Computerarchitektur>LaufzeitfehlerHardwareCachingBimodulComputeranimation
Güte der AnpassungMailing-ListeSkriptspracheEindringerkennungCachingVersionsverwaltungHardwareKoroutineKonfigurationsdatenbankAggregatzustandAdressraumVorzeichen <Mathematik>BimodulLie-GruppeGruppenoperationLastPunktSymboltabelleInformationsspeicherungEndliche ModelltheorieNP-hartes ProblemGemeinsamer SpeicherGeradeGebäude <Mathematik>KurvenanpassungGrundsätze ordnungsmäßiger DatenverarbeitungFahne <Mathematik>RestklasseMobiles InternetOffice-PaketKonditionszahlRegistrierung <Bildverarbeitung>Virtuelle MaschineService providerVideokonferenzDemo <Programm>AdditionKonfiguration <Informatik>VollständigkeitPhysikalisches SystemDatenstrukturMomentenproblemErhaltungssatzDemoszene <Programmierung>Computeranimation
AblaufverfolgungFahne <Mathematik>GamecontrollerStichprobenumfangDatenbankFlächentheorieElektronischer ProgrammführerEreignishorizontQuellcodeFehlermeldungMereologieCodeGruppenoperationBimodulInteraktives FernsehenHochdruckBildschirmfensterElektronische PublikationKonfigurationsdatenbankKernel <Informatik>InformationArithmetisches MittelMessage-PassingDebuggingEnergiedichteVirtuelle MaschineKonditionszahlCASE <Informatik>FlächeninhaltRichtungDemo <Programm>SchnittmengeZusammenhängender GraphDoS-AttackeWort <Informatik>Endliche ModelltheorieIndexberechnungPhysikalisches SystemFolge <Mathematik>VerdeckungsrechnungLokales MinimumGemeinsamer SpeicherMathematische LogikWeg <Topologie>Arithmetische FolgeComputeranimation
Rechter WinkelNichtlinearer OperatorMultiplikationsoperatorFreewareTwitter <Softwareplattform>TypentheorieWrapper <Programmierung>Exogene VariableDemo <Programm>Puffer <Netzplantechnik>Vorzeichen <Mathematik>ARM <Computerarchitektur>BildschirmmaskeE-MailFunktionalProgrammiererBefehlsprozessorWort <Informatik>Automatische IndexierungWeb-SeiteHilfsprogrammMailing-ListeGrundsätze ordnungsmäßiger DatenverarbeitungBootenProzess <Informatik>CASE <Informatik>Computeranimation
Nichtlinearer OperatorDienst <Informatik>BitHalbleiterspeicherMotion CapturingBildschirmfensterGraphische BenutzeroberflächeBenutzeroberflächeMenütechnikQuick-SortComputeranimation
Graphische BenutzeroberflächeGüte der AnpassungBitHilfesystemDateiverwaltungThreadMultiplikationsoperatorPhysikalisches SystemMotion CapturingPunktProzess <Informatik>NormalvektorHook <Programmierung>Filter <Stochastik>Inklusion <Mathematik>LastHackerRechter WinkelCAN-BusComputerunterstützte ÜbersetzungArithmetische FolgeComputeranimationTabelle
Filter <Stochastik>MultiplikationsoperatorHackerProzess <Informatik>KonzentrizitätBitrateComputeranimationProgramm/Quellcode
Puffer <Netzplantechnik>Grundsätze ordnungsmäßiger DatenverarbeitungAutomatische HandlungsplanungDemo <Programm>Gesetz <Physik>Geschlecht <Mathematik>Hook <Programmierung>RechenschieberKreiszylinderKonfigurationsdatenbankPhysikalisches SystemElektronischer ProgrammführerComputervirusRechter WinkelEndliche ModelltheorieComputeranimation
BetriebsmittelverwaltungElektronische UnterschriftDatenbankComputerforensikLokales MinimumGamecontrollerPhysikalisches SystemZellularer AutomatQuick-SortElektronische PublikationVersionsverwaltungSchlüsselverwaltungBenutzeroberflächeElektronischer ProgrammführerSummierbarkeitHash-AlgorithmusBildschirmfensterStrömungsrichtungComputersicherheitKonfigurationsdatenbankVorzeichen <Mathematik>Computeranimation
Hook <Programmierung>ARM <Computerarchitektur>Stabilitätstheorie <Logik>HilfesystemSkriptspracheApp <Programm>KonfigurationsdatenbankElektronische PublikationMultiplikationsoperatorDebuggingPhysikalisches SystemPhysikalischer EffektKette <Mathematik>Einfache GenauigkeitComputeranimationVorlesung/Konferenz
Computeranimation
Transkript: English(automatisch erzeugt)
I'd like to welcome someone who's participating in recon for the very first time. Just kidding. All right, Alex, nice to have you back. Thank you. All right, thank you, everyone. I apologize for the transitions in the slides.
I just realized now that that company template has transitions, which I hate. So sorry for that. Anyway, so I'm going to be talking about the kernel shim engine in this talk. And I'm going to do a little bit of introduction about myself and the 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 winback 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. And then I'll be doing a demo of a tool called Drivermon, which is built on top of the shim engine and 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 CrowdStrike 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. And I've been doing reverse engineering for about 15, 16 years now of the anti-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 is in the same kind of realm as that. Someone who's not presenting with me today is Robin Keir.
He's a fellow co-worker at CrowdStrike. And he helped with the Drivermon tool immensely. He actually rode the whole GUI for it. So when we do talk about the 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 entry, so imports. It's going to let you hook ERPs.
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 is 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 in the list of default shims, well, then you have a third-party shim and you really shouldn't, except the tool I'll be 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 AppCompat. Whenever we say shims, we always talk about AppCompat 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 reinitialize 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 reinitializing the device. So this has been there since Windows XP under the guise of AppCompat. Then this, they had the errata manager, which kind of does the same thing. And then the register, 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 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 ERP handlers. So it does both driver shimming and device shimming.
Basically, during the IAM manager initialization, this thing initializes in kind of two phases. So there's a function called KSE initializer, which does that. And it parses the same SDB database that you might already have heard about in terms of AppCompat 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 safe 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 PE mode. So like in recovery mode, there won't be any shims either.
This shim database is called drivermain.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 AppCompat engine where you could have certain flags. And what changes in Windows 8 with the kernel shim engine
is the ability to have driver shims as well. So this is loaded very early on by winlow.exe, which is orb.efi, which is your Windows bootloader. It looks in system32c-windows-apppatch-drvmain.sdb. And it loads that. And then it also loads the errata-manager.inf file.
But we're not going to talk about the errata manager here. It then stores in a loader parameter block extension the base address of the shim database and the size. So at this point, it's already loaded in memory. And all KSE 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 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 a CPI 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 lookup in there as well. So device shims are basically exposed to three APIs, KSE
query device data, KSE query device data lists, 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 NT query system information, which is a well-known Windows undocumented API for getting all interesting things from the system, you can pass in those two information classes, and that's gonna 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 the registry. And in the registry, you basically have this reg key,
registry, machine, Windows, whoops, 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 bangs. 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 under registry, they're gonna do a lookup in the cache, because all this device information is cached. And if it's not in the cache, then they're gonna 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, a tag corresponds to a given data type. So there's a tag 7013, which is a flag, which is read by readkflag. And then there's another flag called kdata, which contains just arbitrary value pair of 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 having 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,
enumerator, the audio bus driver, the Bluetooth hit driver, the generic hit driver, NDIS, which is the network driver in Windows, UFX synopsis and URS-CX, 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 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 errata 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 any time a driver, any time a plug and play discovers a new device, it's gonna 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 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 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. Kinda weird because the plug and play manager already knows
and there's APIs for doing that, but 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 shimmings 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 IOCTOLs, it hooks create and close ERPs, it hooks power ERPs and it hooks plug and play ERPs. It then hooks IO create device, PO request power ERP, xallocate pool, xfree 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's internal tracing mechanism, anytime that happens. So it just kind of hooks those things and tells you that it happened. As the name suggests, you know, driver scope, kind of like a scope for drivers.
We're gonna see driver scope is never active on anything by default, but it basically means if you activate it and we're gonna 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 gonna hook RTL get version and PS get version
and each particular hook will return a different version. So just like in user mode, we 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. Well, basically that hooks your driver unload function and just doesn't call it anymore. Just prints out ETW. Yeah, I'm not gonna 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 gonna happen by IOP initialize built-in driver, MI compact service table or MI driver load succeeded, KC 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 gonna see how you can look at that in event log. There's a variable in the kernel that we're gonna 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 gonna look at introspection later with some kernel debugging scripts,
we're gonna 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 gonna 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 gonna search the registry to see if there's any applicable shims for your driver and we're gonna 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 FUBAR registered for this driver, we're gonna look in the SDB in the database, is there a shim called FUBAR? 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 gonna be doing that. Another possibility is there's nothing in the registry and if 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 them in 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 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 gonna be resolving the shims. So we're gonna see is that shim first of all registered?
Because for a shim to be registered that means a provider ran, the shim provider registered that shim and says I provide shim called FUBAR with the GUID 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. At that point we're gonna check,
is this shim a delayed load provider? If it's a delayed load provider, we're actually gonna go and load the provider name manually by basically seeing what's your name and calling zw load driver and loading that driver. Once the provider has been loaded, we're gonna 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 this module for whatever reason is not providing the shim that it's supposed to. If it is, the next thing that happens we're gonna dump all the load modules. Because one of the things that shims can do is hook IT entries of any driver. So we're gonna dump all the drivers that exist
and we're gonna see does your shim hook any of the drivers that this driver might import? So I have one driver that's basically foo.sys. It's importing from bar.sys and your shim driver is basically saying bar.sys's function has to be hooked. So we're gonna 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 gonna 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 does not export that API,
well then your shim can't hook anything. So we basically can bypass that. If not, your driver's now ready to be shimmed. In other words, we have found a shim that's valid. We have found all the things this shim wants to shim and all the exports exist. So we're ready to proceed to the next stage, which is gonna be applying the driver shims. So it happens with a separate function,
KSEP apply shims to driver. And this is gonna go in KSEP patch driver imports table, which calls KSEP patch import table entry, which then calls mmReplace import entry. So the memory manager has a whole bunch of functionality now to basically safely and correctly patch IAT entries, take care of the section objects and all that. At that point, your shim provider
gets a call-out notification, which we're gonna 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, IAT 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 initialized built-in driver, then we call KSE shim driver IO callbacks. This will now call KSEP get shim callbacks for driver,
and it's gonna hook your driver callbacks, driver init, driver unload, start IO, add device. And then it's gonna hook all your ERP 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 ERPs
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 this stuff for us. So the first thing we need to do is define a KSE shim. Again, a shim is a compatibility fix. And a compatibility fix is a set of functions
we have to hook and callbacks we have to hook and ERP 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 easy to reverse, so basically you have the size of KSE 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't 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 driver's shimming has been loaded, and another one when one of the driver's 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 zero, one, and two 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 what the name of those things are, so you don't have to bother with that. Otherwise, type three 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. 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, one for function or two 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 gonna see what the callback IDs match up to. You then pass in the address of your function that's gonna be hooking that thing. So the hook function there, that P void, 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 wanna 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 gonna have a problem. We're gonna 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 export's NTAUS kernel, you create a collection of type zero. If the export is HAL.dll, you create a collection of type one. And if this is a custom driver, you create a collection of type two and you put down your driver name. So I have a very simple example here. If you're trying to hook X allocate pool tag, you say zero,
because X allocate pool tag is an NTAUS kernel. You put in the name, X allocate pool tag, and then you give it a pointer to your hook of EX allocate pool tag. And then null, that's where you're gonna receive the original X allocate pool tag. So then your hook function, you do whatever you wanna do because you're hooking X allocate pool, and then you return hook's zero original function.
Basically then call the original function that's there. Or maybe you'll just decide, nope, I'm not gonna allocate any memory for you, which would probably be bad. Now one of the things you might wanna know inside of your hook is, if I'm hooking multiple drivers of the same shim, what driver's actually calling X allocate pool? So there's no kind of built-in way of knowing that,
but you know you've got an intrinsic and visual studio call underscore return address, and that'll give you the return address of whoever called you. So that way you can tell what driver actually is hooking EX allocate pool. So if you wanna 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 init, driver unload, driver start IO, and you can hook add device. Or you can hook every ERP, 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 ERPs. Interestingly, you can hook any of these things, except actually driver init. 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 init hook, but it won't actually ever be called, because your hooks only get applied after driver init runs. So kind of a design fallacy there. You can see I've got the pseudocode. We call driver init, then we apply the hooks.
And driver init never gets called again. So we're never gonna call your hooked driver init. Whoops. 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, KSCGetIOCallbacks, and KSCGetIOCallbacks 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 init, two, for driver start IO,
three, for driver on load, four, for driver add device, and for ERPs, every ERP has its own number. For example, IRPMJ create a zero, IRPMJ read is four or three. IRPMJ closes two. So 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 ERP identifier are the ERP handlers. Now how do you call KSCGetIOCallbacks? Because that's actually not an exported function. Well, let's go back for a second here in our definition of a KSC shim.
There's this field here called KSC callback routines. So the resolution's screwed up. Anyway, this thing here, KSC callback routines, that's where you actually get a pointer back to KSCGetIOCallback. 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 ERPs is that unlike function calls, which return immediately, ERPs can either be returned immediately, but by the time they've returned, the ERP has actually been completed, meaning that the other side has already received the answer, and the ERP 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 IO, so the ERP will be completed later, so if you do try to read from the ERP, there's no answer yet. So you kind of got two bad choices. Read from the ERP and you'll crash because the ERP is gone if the operation succeeded, or read from the ERP and get useless data
because the ERP hasn't actually completed. So what you actually have to do is register a hook for the completion of this ERP. And again, KAC gives you a function for that, KAC set completion hook, and you can say for this ERP, I would like to hook its result so I can actually know what happened with it. And again, KAC 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 address of KAC get IO completion callback so you know what to call when you're done, and KAC set completion hook if you'd like to request a hook for the ERP. Which is nice because that basically means you're gonna have pre-hooks before the ERP actually gets processed by the driver,
and you can have post hooks after the ERP has been processed by the driver. So for example, for IRPMJ write, in your pre you can see what the user mode app is trying to write, in your post you can see if 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's actually gonna be shimmed by you, you get a notification from KAC saying, you are now shimming this driver. And you get the name of the driver you're shimming,
it's load address, it's size, it's timestamp, and it's checksum. And when a driver's 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 a memory map of okay, from here to here, this driver's here, from here to here,
this other driver's there, from here to here, I've got another driver. And then in your function hooks, 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 start address of a driver. So again, you can match up the start address of the driver that's handling the ERP with one of the drivers you're targeting. And that way, you can know exactly what driver are you currently hooking in the middle of your ERP
or in the middle of your function hook. So once you've defined 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 gonna run through your driver unload,
but it's gonna keep you resident in memory. So you're not gonna 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 this means 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 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 kinda 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 SDB 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 SDB to XML, which lets you dump the shim database as an XML file. And then in the shim database, you're gonna see app help entries,
which basically say this driver is not something we wanna 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, when a driver tries to install itself, you get a little pop-up that says this driver's not compatible with Windows. Then you have K device entries, and we're gonna 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 SDB. You can't kind of make up your own provider
without any definition for it. So we 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 10B0, which looks like it's an AES media vendor, so some sort of USB 3 device made by AES 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, this device takes a longer time to initialize, so you should take longer as well. An example of a driver shim is at the bottom, and this is basically saying that TSSsafe.sys, 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 the product version associated with that. So that's an example of an app help shim that basically says, yeah, we're not gonna let you load this driver, it's bad.
And later on, if we have time, I'll show you some other examples. Again, these are just from the dump of the SDB database, dumped with SDB2XML, 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 autofail and autofail, which are meant to be registered by KM autofail.sys and autofail.sys, but those don't actually exist. Then storeport, device ID shim, and SRB shim are registered by storeport.sys, which is the Windows storage driver. USB shim is registered by USBD.sys,
which is kind of the generic library that all USB devices use. And NDIS get version 640 shim is registered by NDIS, which is the network driver. A lot of drivers try to check which version of NDIS they're on, so I'm guessing just like the version lie, this allows NDIS to lie to that driver and say, no, no, I'm not NDIS 6.6, I'm NDIS 6.4.
Then in the registries I mentioned, certain drivers can be targeted. So by default, on like a clean Windows 10 installation, if you go to the key there in the registry, the compatibility key, there's a subkey called driver, and under that subkey, there's different driver names.
And you might see in the screenshot, there's a few there that I've added, but the one that's there by default only is storeahci.sys, which is the AHCI or SATA storage driver. It has the SRB shim applied. So basically, whenever you load storeahci.sys, it's going to be shimmed by SRB shim,
which on the previous slide, we saw that SRB shim is registered by storeport. So storeport.sys will be shimming storeahci.sys. But that's only in the registry, because remember then the SDB can itself have other shim information. So just a few examples here, USB shim hooks wsrrci.sys,
edgersr64.sys, acfdcp64.sys. So those driver vendors are doing something wrong, and the USB has to come in and kind of fix them up. And there's a version 64 shim, there's some Realtek drivers in there, kmwin81 version line, something called the fragfs.sys in there. And there's other shims which are, again,
loaded by shim by other things. So if I open up here the database that I've got, stb.txt, oops, that's not the right thing, stb.txt. And anything that basically has kshim ref in there
is something that's gonna be hooked. So that's something from connect's USB, that's the one we've seen. But yeah, 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 U600 driver,
and it is being shimmed by kmwin7 version lie. So this driver needs to be told that we're on Windows 7. So again, just dump database, and you can see all these examples for your safe, basically. And Windows Update can obviously update its SDB database and can add additional devices in there as in additional shims as they're needed.
So let's look at one of those examples. SCSI port registers a shim, two 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 iOctos 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, which hooks iOctos for the device ID shim. And there's SRB shim hook device control, which hooks the iOctos that SRB shim is hooking.
So SRB shim, what is it then doing? It's basically for any iOcto, that's iOcto storage query property. And if you're querying a standard property, and the property ID is storage adapter property, and you're expecting 32 bytes or more, then it's gonna target this IRP. It's gonna say, all right, this IRP is interesting, so I wanna register a completion callback
or a completion hook. So when the IRP completes, then I wanna 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 gonna go in, and we're going to edit the actual, nevermind.
We're gonna edit the actual SRB type and address type field, and we're gonna set it to zero. So basically, we override this legitimate valid data that we received with zeros. So that's kind of interesting. Why are we doing this to poor storeAHCI.SYS? Why are we clearing out these bottom two fields
that were legitimately returned? And so if we actually read MSDN, 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? 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 if the driver's 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 the 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 expecting padding, or reading the previous field incorrectly, but for whatever reason, they're playing it safe,
and they're saying, no, no, 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 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 these 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 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 gonna show you a few shims here, hopefully they're gonna work. Shim.ws, which just kind of displays some information by the shim engine on my machine. Shimmod.wds, which is gonna dump any modules that are being shimmed. Shimreg, which is gonna dump any shims that have been registered. And shimcache, which can dump the shim cache.
So either the hardware ID cache, or the device data cache. So I'm just gonna demo the scripts for now. I'm gonna 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 KSE 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 KSE Engine. So let's try that, shim.wds. And this is basically saying the engine is ready, driver shims have not been disabled, device shims have not been disabled, these are the addresses 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, that's actually 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 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 shim reg.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 this shim not active. Then we have a little error,
module load complete, but symbols could not be loaded for, blah, blah, blah, blah, shimmer.sys. That's my stuff, which has two active shims. So shimmer is actually shimming two things, and then this is CS Shimmer as the driver name. So we're gonna see what that one's all about. And then USB D shim. So basically, you can clearly see with this script
that something's actually shimming the machine, and it's 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 dumped 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, MPSO, actually.
So there's a shim module here, that's a bug. There are not six billion active shims. But next one, MPFS is being shimmed, and there's one thing shimming it, and there's gonna be an array of all the things that are shimming it, and in that array, you're gonna find shimmer, and then a of these being shimmed. And again, that's because of the special thing I've loaded,
which I'm gonna 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 gonna dump the shim cache, but basically a bunch of hardware IDs at that point. So can you turn this thing off, by the way,
or what are ways 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 Windows components, device and driver 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 disable flags, and disable flags one means you're disabling driver shims, disable flags two 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 KSEP debug flag, and if you set KSEP 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 KSEP has debug prints everywhere. It even has an array called KSEP 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 has one shim was applied to driverafd.sys,
applied to the registry, and that's the shim that I'm actually going to demo, that's part of the drivermon. So in the event viewer, by default, you can actually see these operational messages that are gonna 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 line utility reminiscent of Pullmon,
if you're familiar with Pullmon, and basically just showed you the driver at the time, on which CPU, which PID, and which did something. And as a demo, I basically shimmed all the ERPs, and the allocate and free pull functions. So I won't show this tool, because instead, thanks to Robin,
he built a different tool called Drivermon. And Drivermon basically was meant to kind of, not replace, but be like Procmon. So if you're familiar with process monitor, the ability to search, filter, and highlight operations, to do non-destructive filtering and boot logging, to be able to export to a CSV, to be able to decode different iOCTLs,
and so started working on the tool in the spare time. And we basically have a 1.0 release that's almost ready. We basically have to wrap up the UI, the EULA, the build, the signing, and all of that. And it should be on the community tools page. So if you're familiar with Crowd Inspect or Crowd Response, it's gonna 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 gonna be set up to Drivermon or CrowdStrike, 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 gonna 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 that's obviously wanted. Then search indexer allocated from the pool, a buffer, and then it read from a pipe 1,300 bytes as well.
So because this is NPFS, these are implying that these are kind of pipe operations. But I'll show you some afd.sys, which would imply that these are metric operations. So let me actually run Drivermon. See how bad things fail.
Okay, so I'm just gonna hit capture. And it's starting to give us some stuff. So afd, which is the Windows windsock driver. So I can see that service host sent an octal, then afd allocated a free to 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 afd from service host. Click on start menu, a whole bunch of stuff happened when I clicked on start. Notice also, 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. Some of you 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. There we go. 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 gonna keep on going and going and going, receding, oh, we're done. 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. All right, so you know what? I wanna see the principle is up too, so right-click, thank you. Include spool SV. And now I see just what spool SV is doing with spooler. I'm gonna say include AFD only, thank you, and now I see AFD. 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, process hacker, for example, it loads a driver. So I can clear all this and say, let's go hook process hacker, which I think is kprocesshacker2.sys,
and say okay. Turn on capturing. And that's, let me get rid of AFD.sys. And get rid of NPFS.sys. Oop, oh, it looks like, ha ha. It brought the other one back. Okay, gonna have to work on that. So let's run process hacker.
Yes. Okay, and then if I autoscroll, and clear, and let's reset the filters. Is it doing anything?
Process hacker. It might have renamed itself to processhacker3.sys. This is actually what I'm afraid of. So I'm trying to double check that file. Oh yeah, it's kprocesshacker3. All right, so let me just write that one more time.
Kprocesshacker3.sys. And then actually let me unload. Nets sc.kprocesshacker3. Okay, edit. Run process hacker. And make a sacrifice to the demo gods. See if that actually works.
Nope, oh well. You can't demo everything. So it would normally work when we figure out whatever's wrong with this thing. So, well 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 of kind of what we're aiming for here. So I'm gonna 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 at 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's 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'm km-autofail. And one just now knows, okay, 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 AFD.sys, MPFS.sys in the system, current control set, control compatibility key that we talked about.
And it's basically just saying, oh, AFD.sys has a shim and its shim is called km-autofail. And now I'm km-autofail. I basically registered 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 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 it'd also be good to have 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. And 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 allow that. And make sure you use those driver debugger scripts
that I'm gonna release. Make sure you don't have weird shims. Look at your registry and 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? Okay, maybe one or two questions. One over there. Anything other than unfucking 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 progmon.sys, I'm not sure who makes that. Oh, right, Microsoft. A driver is installed that causes stability problems with your system.
So they use it on their own stuff, but not as an actual shim, but just kind of blocking it. 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 Recon.
Thank you.