├── .gitignore ├── LICENSE ├── MManager ├── MManager.sln ├── MManager │ ├── MManager.vcxproj │ ├── MManager.vcxproj.filters │ ├── main.c │ ├── mm │ │ ├── mmtypes.h │ │ ├── vad.c │ │ └── vad.h │ ├── mmanager-dispatch.c │ ├── mmanager-dispatch.h │ ├── mmanager-globals.h │ ├── mmanager-routines.c │ ├── mmanager-routines.h │ └── rtl │ │ └── osversion.h └── vadlist │ ├── main.cpp │ ├── mmanager.cpp │ ├── mmanager.h │ ├── vadlist.vcxproj │ └── vadlist.vcxproj.filters ├── README.md ├── WKI ├── WKI.sln ├── WKIKM │ ├── WKIKM.vcxproj │ ├── WKIKM.vcxproj.filters │ ├── ki-globals.h │ ├── main.c │ └── wki │ │ ├── wki.c │ │ └── wki.h └── WKIUM │ ├── WKIUM.vcxproj │ ├── WKIUM.vcxproj.filters │ ├── callback.c │ ├── dirutil.c │ ├── inc │ ├── callback.h │ ├── dirutil.h │ ├── interface.h │ ├── msdia │ │ └── inlcude │ │ │ ├── cvconst.h │ │ │ ├── dia2.h │ │ │ └── diacreate.h │ └── registry.h │ ├── interface.c │ ├── main.c │ ├── registry.c │ └── tools │ ├── msdia140.dll │ └── symsrv.dll └── mpp ├── mpp-client ├── device.hpp ├── main.cpp ├── mpp-client.vcxproj ├── mpp-client.vcxproj.filters ├── sym.cpp └── sym.hpp ├── mpp.sln └── mpp ├── main.cpp ├── mpp.cpp ├── mpp.hpp ├── mpp.vcxproj ├── mpp.vcxproj.filters ├── worker.cpp └── worker.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml -------------------------------------------------------------------------------- /MManager/MManager.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32505.426 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MManager", "MManager\MManager.vcxproj", "{0B1A382E-0DD8-4822-B4DF-E206B62E52BE}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vadlist", "vadlist\vadlist.vcxproj", "{17475489-56C9-4202-BA6F-79C75805E497}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM64 = Debug|ARM64 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|ARM64.ActiveCfg = Debug|ARM64 21 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|ARM64.Build.0 = Debug|ARM64 22 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|ARM64.Deploy.0 = Debug|ARM64 23 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|x64.ActiveCfg = Debug|x64 24 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|x64.Build.0 = Debug|x64 25 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|x64.Deploy.0 = Debug|x64 26 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|x86.ActiveCfg = Debug|x64 27 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|x86.Build.0 = Debug|x64 28 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Debug|x86.Deploy.0 = Debug|x64 29 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|ARM64.ActiveCfg = Release|ARM64 30 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|ARM64.Build.0 = Release|ARM64 31 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|ARM64.Deploy.0 = Release|ARM64 32 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|x64.ActiveCfg = Release|x64 33 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|x64.Build.0 = Release|x64 34 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|x64.Deploy.0 = Release|x64 35 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|x86.ActiveCfg = Release|x64 36 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|x86.Build.0 = Release|x64 37 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE}.Release|x86.Deploy.0 = Release|x64 38 | {17475489-56C9-4202-BA6F-79C75805E497}.Debug|ARM64.ActiveCfg = Debug|x64 39 | {17475489-56C9-4202-BA6F-79C75805E497}.Debug|ARM64.Build.0 = Debug|x64 40 | {17475489-56C9-4202-BA6F-79C75805E497}.Debug|x64.ActiveCfg = Debug|x64 41 | {17475489-56C9-4202-BA6F-79C75805E497}.Debug|x64.Build.0 = Debug|x64 42 | {17475489-56C9-4202-BA6F-79C75805E497}.Debug|x64.Deploy.0 = Debug|x64 43 | {17475489-56C9-4202-BA6F-79C75805E497}.Debug|x86.ActiveCfg = Debug|Win32 44 | {17475489-56C9-4202-BA6F-79C75805E497}.Debug|x86.Build.0 = Debug|Win32 45 | {17475489-56C9-4202-BA6F-79C75805E497}.Release|ARM64.ActiveCfg = Release|x64 46 | {17475489-56C9-4202-BA6F-79C75805E497}.Release|ARM64.Build.0 = Release|x64 47 | {17475489-56C9-4202-BA6F-79C75805E497}.Release|x64.ActiveCfg = Release|x64 48 | {17475489-56C9-4202-BA6F-79C75805E497}.Release|x64.Build.0 = Release|x64 49 | {17475489-56C9-4202-BA6F-79C75805E497}.Release|x86.ActiveCfg = Release|Win32 50 | {17475489-56C9-4202-BA6F-79C75805E497}.Release|x86.Build.0 = Release|Win32 51 | EndGlobalSection 52 | GlobalSection(SolutionProperties) = preSolution 53 | HideSolutionNode = FALSE 54 | EndGlobalSection 55 | GlobalSection(ExtensibilityGlobals) = postSolution 56 | SolutionGuid = {6CC78C36-84C3-4A75-AD4D-0D6DFBCF2187} 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /MManager/MManager/MManager.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | {0B1A382E-0DD8-4822-B4DF-E206B62E52BE} 23 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 24 | v4.5 25 | 12.0 26 | Debug 27 | x64 28 | MManager 29 | 30 | 31 | 32 | Windows10 33 | true 34 | WindowsKernelModeDriver10.0 35 | Driver 36 | WDM 37 | false 38 | 39 | 40 | Windows10 41 | false 42 | WindowsKernelModeDriver10.0 43 | Driver 44 | WDM 45 | 46 | 47 | Windows10 48 | true 49 | WindowsKernelModeDriver10.0 50 | Driver 51 | WDM 52 | 53 | 54 | Windows10 55 | false 56 | WindowsKernelModeDriver10.0 57 | Driver 58 | WDM 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | DbgengKernelDebugger 70 | 71 | 72 | DbgengKernelDebugger 73 | 74 | 75 | DbgengKernelDebugger 76 | 77 | 78 | DbgengKernelDebugger 79 | 80 | 81 | 82 | sha256 83 | 84 | 85 | $(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies) 86 | 87 | 88 | 89 | 90 | sha256 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /MManager/MManager/MManager.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /MManager/MManager/main.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: main.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | Device driver entry point. 10 | 11 | ================================================================================================+*/ 12 | 13 | #include "mmanager-globals.h" 14 | #include "mmanager-dispatch.h" 15 | 16 | #include "rtl/osversion.h" 17 | 18 | /// 19 | /// Device driver entry point. 20 | /// 21 | /// Pointer to the driver object. 22 | /// Pointer to the registry path, if any. 23 | /// Functions status code. 24 | EXTERN_C NTSTATUS DriverEntry( 25 | _In_ PDRIVER_OBJECT DriverObject, 26 | _In_ PUNICODE_STRING RegistryPath 27 | ); 28 | 29 | #ifdef ALLOC_PRAGMA 30 | #pragma alloc_text(PAGE, DriverEntry) 31 | #endif // ALLOC_PRAGMA 32 | 33 | _Use_decl_annotations_ 34 | EXTERN_C NTSTATUS DriverEntry( 35 | _In_ PDRIVER_OBJECT DriverObject, 36 | _In_ PUNICODE_STRING RegistryPath 37 | ) { 38 | UNREFERENCED_PARAMETER(RegistryPath); 39 | 40 | MMDebug(("----------------------------------------------------------------\r\n")); 41 | MMDebug(("Kernel Memory MAnager Utility (MManager) \r\n")); 42 | MMDebug(("Version: 1.0 \r\n")); 43 | MMDebug((" \r\n")); 44 | MMDebug(("Tested on: Windows 10 Kernel Version 19041 MP (1 procs) Free x64\r\n")); 45 | MMDebug(("Edition build lab: 19041.1.amd64fre.vb_release.191206-1406 \r\n")); 46 | MMDebug(("----------------------------------------------------------------\r\n")); 47 | 48 | // 1. Check current Windows version 49 | OSVERSIONINFOW SystemInfo = { 0x00 }; 50 | ASSERT(NT_SUCCESS(RtlGetVersion(&SystemInfo))); 51 | ASSERT(SystemInfo.dwMajorVersion == WINDOWS_10); 52 | ASSERT(SystemInfo.dwBuildNumber == WINDOWS_10_19044); 53 | 54 | // Initialise stack variables 55 | NTSTATUS Status = STATUS_SUCCESS; 56 | UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(MMANAGER_DEVICE_NAME); 57 | UNICODE_STRING SymbolicName = RTL_CONSTANT_STRING(MMANAGER_SYMBOLIC_LINK_NAME); 58 | 59 | PDEVICE_OBJECT DeviceObject = NULL; 60 | BOOLEAN SymbolicLink = FALSE; 61 | 62 | // Set all the routines 63 | DriverObject->DriverUnload = MmanDriverUnload; 64 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = MmanDriverCreateClose; 65 | DriverObject->MajorFunction[IRP_MJ_CREATE] = MmanDriverCreateClose; 66 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MmanDriverDispatch; 67 | 68 | // Register the device driver and symbolic link 69 | do { 70 | // Exclusive - Prevent multiple handles to be open for the device driver. 71 | // SDDLString - Prevent non-admin and non-SYSTEM from interacting with the device driver. 72 | Status = WdmlibIoCreateDeviceSecure( 73 | DriverObject, 74 | 0x00, 75 | &DeviceName, 76 | FILE_DEVICE_UNKNOWN, 77 | 0x00, 78 | TRUE, 79 | &SDDL_DEVOBJ_SYS_ALL_ADM_ALL, 80 | &MMANAGER_CLASS_GUID, 81 | &DeviceObject 82 | ); 83 | if (!NT_SUCCESS(Status)) { 84 | MMDebug(("Failed to create device object (0x%08X).\r\n", Status)); 85 | break; 86 | } 87 | DeviceObject->Flags |= DO_DIRECT_IO; 88 | 89 | Status = IoCreateSymbolicLink(&SymbolicName, &DeviceName); 90 | if (!NT_SUCCESS(Status)) { 91 | MMDebug(("Failed to symbolic link (0x%08X).\r\n", Status)); 92 | break; 93 | } 94 | SymbolicLink = TRUE; 95 | } while (FALSE); 96 | 97 | // Check for errors 98 | if (!NT_SUCCESS(Status)) { 99 | MMDebug(("Roll-back operations.\r\n")); 100 | if (SymbolicLink) 101 | IoDeleteSymbolicLink(&SymbolicName); 102 | if (DeviceObject != NULL) 103 | IoDeleteDevice(DeviceObject); 104 | MMDebug(("----------------------------------------------------------------\r\n")); 105 | return Status; 106 | } 107 | 108 | // Display final information and exit 109 | MMDebug(("Device name : %wZ\r\n", DeviceName)); 110 | MMDebug(("Symbolic link name: %wZ\r\n", SymbolicName)); 111 | MMDebug(("----------------------------------------------------------------\r\n")); 112 | return Status; 113 | } -------------------------------------------------------------------------------- /MManager/MManager/mm/vad.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: vad.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | All the routines used to deal with Virtual Address Descriptors (VADs). 10 | APC must be disabled. 11 | 12 | ================================================================================================+*/ 13 | 14 | #include "vad.h" 15 | 16 | #ifdef ALLOC_PRAGMA 17 | #pragma alloc_text(PAGE, XMiInitializeVadTable) 18 | #pragma alloc_text(PAGE, XMiUninitializeVadTable) 19 | #pragma alloc_text(PAGE, XMiBuildVadTable) 20 | #pragma alloc_text(PAGE, XMiGetVadNodeAbstractInfo) 21 | #endif // ALLOC_PRAGMA 22 | 23 | _Use_decl_annotations_ 24 | EXTERN_C NTSTATUS XMiInitializeVadTable( 25 | _In_ CONST PEPROCESS Process, 26 | _Out_ PXVAD_TABLE XVadTable 27 | ) { 28 | if (Process == NULL) 29 | return STATUS_INVALID_PARAMETER_1; 30 | if (XVadTable == NULL) 31 | return STATUS_INVALID_PARAMETER_2; 32 | 33 | // Ensure current IRQL allow paging. 34 | PAGED_CODE(); 35 | 36 | // Allocate required data 37 | XVadTable->Process = (PEPROCESS)Process; 38 | InitializeListHead(&XVadTable->InsertOrderList); 39 | 40 | return STATUS_SUCCESS; 41 | } 42 | 43 | _Use_decl_annotations_ 44 | EXTERN_C NTSTATUS XMiUninitializeVadTable( 45 | _In_ PXVAD_TABLE XVadTable 46 | ) { 47 | if (XVadTable == NULL) 48 | return STATUS_INVALID_PARAMETER_1; 49 | 50 | // Ensure current IRQL allow paging. 51 | PAGED_CODE(); 52 | 53 | // Check if there is any nodes 54 | if (XVadTable->NumberOfNodes == 0x00) 55 | return STATUS_SUCCESS; 56 | 57 | // Release all entries 58 | while (!IsListEmpty(&XVadTable->InsertOrderList)) { 59 | PLIST_ENTRY Entry = RemoveTailList(&XVadTable->InsertOrderList); 60 | PXVAD_TABLE_ENTRY Vad = CONTAINING_RECORD(Entry, XVAD_TABLE_ENTRY, List); 61 | if (Vad != NULL) { 62 | ExFreePoolWithTag(Vad, XVAD_MM_TAG); 63 | } 64 | } 65 | 66 | RtlZeroMemory(XVadTable, sizeof(XVAD_TABLE)); 67 | return STATUS_SUCCESS; 68 | } 69 | 70 | _Use_decl_annotations_ 71 | EXTERN_C PXVAD_TABLE_ENTRY XMiBuildVadTable( 72 | _In_ PXVAD_TABLE XVadTree, 73 | _In_opt_ PMMVAD VadNode, 74 | _In_opt_ PXVAD_TABLE_ENTRY Parent, 75 | _In_ ULONG Level 76 | ) { 77 | // Increase max level 78 | if (Level > XVadTree->MaximumLevel) 79 | XVadTree->MaximumLevel = Level; 80 | 81 | // Allocate memory to store the new node 82 | PXVAD_TABLE_ENTRY NewVadEntry = ExAllocatePool2(POOL_FLAG_PAGED, sizeof(XVAD_TABLE_ENTRY), XVAD_MM_TAG); 83 | if (NewVadEntry == NULL) 84 | return NULL; 85 | NewVadEntry->Level = Level; 86 | XVadTree->NumberOfNodes++; 87 | 88 | // Get VadRoot if VadNode is NULL 89 | if (VadNode == NULL) 90 | VadNode = XMM_GET_PROCESS_VAD_ROOT(XVadTree->Process); 91 | 92 | // Get the information and insert into the list 93 | XMiGetVadNodeAbstractInfo(VadNode, NewVadEntry); 94 | InsertTailList(&XVadTree->InsertOrderList, &NewVadEntry->List); 95 | 96 | // Handle the root node 97 | if (Parent == NULL) { 98 | NewVadEntry->Parent = (struct XVAD_TABLE_ENTRY*)NewVadEntry; 99 | XVadTree->Root = NewVadEntry; 100 | } 101 | else 102 | NewVadEntry->Parent = (struct XVAD_TABLE_ENTRY*)Parent; 103 | 104 | // Get left and right nodes 105 | PMMVAD Left = (PMMVAD)VadNode->Core.VadNode.Left; 106 | PMMVAD Right = (PMMVAD)VadNode->Core.VadNode.Right; 107 | 108 | // Parse left and right nodes 109 | if (Left != NULL) { 110 | NewVadEntry->Left = (struct XVAD_TABLE_ENTRY*)XMiBuildVadTable( 111 | XVadTree, 112 | Left, 113 | NewVadEntry, 114 | Level + 1 115 | ); 116 | } 117 | if (Right != NULL) { 118 | NewVadEntry->Right = (struct XVAD_TABLE_ENTRY*)XMiBuildVadTable( 119 | XVadTree, 120 | Right, 121 | NewVadEntry, 122 | Level + 1 123 | ); 124 | } 125 | return NewVadEntry; 126 | } 127 | 128 | _Use_decl_annotations_ 129 | EXTERN_C VOID XMiGetVadNodeAbstractInfo( 130 | _In_ PMMVAD VadNode, 131 | _In_ PXVAD_TABLE_ENTRY TableEntry 132 | ) { 133 | if (VadNode == NULL) 134 | return; 135 | if (TableEntry == NULL) 136 | return; 137 | 138 | // Ensure current IRQL allow paging. 139 | PAGED_CODE(); 140 | 141 | // Easy store of the VAD Node 142 | TableEntry->VadNode = VadNode; 143 | 144 | // Calculate Virtual Page Number (VPN) 145 | TableEntry->StartingVpn = VadNode->Core.StartingVpn; 146 | TableEntry->EndingVpn = VadNode->Core.EndingVpn; 147 | if (VadNode->Core.StartingVpnHigh) 148 | TableEntry->StartingVpn |= ((ULONG64)VadNode->Core.StartingVpnHigh) << 32; 149 | if (VadNode->Core.EndingVpnHigh) 150 | TableEntry->EndingVpn |= ((ULONG64)VadNode->Core.EndingVpnHigh) << 32; 151 | 152 | // Get all flags 153 | TableEntry->VadFlags = VadNode->Core.u.VadFlags; 154 | TableEntry->VadFlags1 = VadNode->Core.u1.VadFlags1; 155 | TableEntry->VadFlags2 = VadNode->u2.VadFlags2; 156 | 157 | // Check for a control area. Applicable only in case this is mapped memory. 158 | if (!TableEntry->VadFlags.PrivateMemory) { 159 | if (VadNode->Subsection != NULL) { 160 | TableEntry->ControlArea = VadNode->Subsection->ControlArea; 161 | 162 | // Now check for the FileObject if any 163 | if (TableEntry->ControlArea->FilePointer.Value != 0x00) { 164 | TableEntry->FileObject = (PFILE_OBJECT)(TableEntry->ControlArea->FilePointer.Value & 0xFFFFFFFFFFFFFFF0); 165 | TableEntry->Name = &TableEntry->FileObject->FileName; 166 | } 167 | } 168 | } 169 | 170 | // Get commit charge 171 | TableEntry->CommitCharge = TableEntry->VadFlags1.CommitCharge; 172 | if (VadNode->Core.CommitChargeHigh) 173 | TableEntry->CommitCharge |= ((ULONG64)VadNode->Core.CommitChargeHigh) << 31; 174 | } 175 | -------------------------------------------------------------------------------- /MManager/MManager/mm/vad.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: vad.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | All the routines used to deal with Virtual Address Descriptors (VADs). 10 | APC must be disabled. 11 | 12 | ================================================================================================+*/ 13 | 14 | #ifndef __X_VAD_H_GUARD__ 15 | #define __X_VAD_H_GUARD__ 16 | 17 | #include "mmtypes.h" 18 | 19 | // XVAD Memory Pool Tag -- XVad 20 | #define XVAD_MM_TAG (ULONG)0x64615658 21 | 22 | // This is not a reliable way to get the VadRoot but could not find any better for the moment. 23 | #define XMM_GET_PROCESS_VAD_ROOT(ps) (PMMVAD) *(PULONG64)((PUCHAR)ps + 0x7d8) 24 | 25 | /// 26 | /// Virtual Address Descriptor (VAD) abstraction structure. 27 | /// 28 | typedef struct _XVAD_TABLE_ENTRY { 29 | LIST_ENTRY List; 30 | struct XVAD_TABLE_ENTRY* Parent; 31 | struct XVAD_TABLE_ENTRY* Left; 32 | struct XVAD_TABLE_ENTRY* Right; 33 | 34 | // Address of the VAD Node in kernel pool. 35 | union { 36 | PMMVAD VadNode; 37 | PVOID Address; 38 | }; 39 | 40 | PCONTROL_AREA ControlArea; // Pointer to the CONTROL_AREA if mapped memory 41 | PFILE_OBJECT FileObject; // Pointer to the FILE_OBJECT if mapped memory. 42 | ULONG64 StartingVpn; // Start of Virtual Page Number(VPN). 43 | ULONG64 EndingVpn; // Start of Virtual Page Number (VPN). 44 | ULONG64 CommitCharge; 45 | ULONG Level; // Depth level in the AFL tree. 46 | 47 | // First set of flags. 48 | union { 49 | ULONG LongVadFlags; 50 | MMVAD_FLAGS VadFlags; 51 | MM_PRIVATE_VAD_FLAGS PrivateVadFlags; 52 | MM_GRAPHICS_VAD_FLAGS GraphicsVadFlags; 53 | MM_SHARED_VAD_FLAGS SharedVadFlags; 54 | }; 55 | 56 | // Second set of flags. 57 | union { 58 | MMVAD_FLAGS1 VadFlags1; 59 | ULONG LongVadFlags1; 60 | }; 61 | 62 | // Third set of flags. 63 | union { 64 | MMVAD_FLAGS2 VadFlags2; 65 | ULONG LongVadFlags2; 66 | }; 67 | 68 | // Name of the mapped file, if any. 69 | PUNICODE_STRING Name; 70 | } XVAD_TABLE_ENTRY, * PXVAD_TABLE_ENTRY; 71 | 72 | /// 73 | /// Global structure used to collect additional information about Virtual Address Descriptors (VADs). 74 | /// 75 | typedef struct _XVAD_TABLE { 76 | ULONG MaximumLevel; // Deepest level 77 | ULONG NumberOfNodes; // Total number of nodes 78 | ULONG64 TotalPrivateCommit; // Total private memory 79 | ULONG64 TotalSharedCommit; // Total shared memory 80 | 81 | PEPROCESS Process; // Process linked to the VAD 82 | 83 | LIST_ENTRY InsertOrderList; // Order in which all nodes have been loaded 84 | PXVAD_TABLE_ENTRY Root; // First entry of the table 85 | } XVAD_TABLE, * PXVAD_TABLE; 86 | 87 | 88 | _IRQL_requires_max_(APC_LEVEL) 89 | EXTERN_C NTSTATUS XMiInitializeVadTable( 90 | _In_ CONST PEPROCESS Process, 91 | _Out_ PXVAD_TABLE XVadTable 92 | ); 93 | 94 | 95 | _IRQL_requires_max_(APC_LEVEL) 96 | EXTERN_C NTSTATUS XMiUninitializeVadTable( 97 | _In_ PXVAD_TABLE XVadTree 98 | ); 99 | 100 | 101 | _IRQL_requires_max_(APC_LEVEL) 102 | EXTERN_C PXVAD_TABLE_ENTRY XMiBuildVadTable( 103 | _In_ PXVAD_TABLE XVadTree, 104 | _In_opt_ PMMVAD VadNode, 105 | _In_opt_ PXVAD_TABLE_ENTRY Parent, 106 | _In_ ULONG Level 107 | ); 108 | 109 | /// 110 | /// Extract all the information from a Virtual Address Descriptor (VAD) node. 111 | /// 112 | /// Most of the logic taken from C:\Program Files\WindowsApps\Microsoft.WinDbg_\amd64\winxp\kdexts.dll 113 | /// Interesting functions to RE from this module are: 114 | /// - vad 115 | /// - PrintVad 116 | /// 117 | /// Pointer to an internal VAD structure. 118 | /// Pointer to global VAD table. 119 | EXTERN_C VOID XMiGetVadNodeAbstractInfo( 120 | _In_ PMMVAD VadNode, 121 | _In_ PXVAD_TABLE_ENTRY TableEntry 122 | ); 123 | 124 | #endif // !__X_VAD_H_GUARD__ 125 | -------------------------------------------------------------------------------- /MManager/MManager/mmanager-dispatch.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mmanager-dispatch.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | This file contains all global definition and information used by the kernel driver. 10 | 11 | ================================================================================================+*/ 12 | 13 | #include "mmanager-dispatch.h" 14 | #include "mmanager-routines.h" 15 | 16 | #ifdef ALLOC_PRAGMA 17 | #pragma alloc_text(PAGE, MmanDriverUnload) 18 | #pragma alloc_text(PAGE, MmanDriverCreateClose) 19 | #pragma alloc_text(PAGE, MmanDriverDispatch) 20 | #endif // ALLOC_PRAGMA 21 | 22 | _Use_decl_annotations_ 23 | EXTERN_C VOID MmanDriverUnload( 24 | _In_ PDRIVER_OBJECT DriverObject 25 | ) { 26 | MMDebug(("----------------------------------------------------------------\r\n\r\n")); 27 | 28 | // Delete the symbolic link and the device object 29 | UNICODE_STRING SymbolicName = RTL_CONSTANT_STRING(MMANAGER_SYMBOLIC_LINK_NAME); 30 | IoDeleteSymbolicLink(&SymbolicName); 31 | IoDeleteDevice(DriverObject->DeviceObject); 32 | } 33 | 34 | _Use_decl_annotations_ 35 | EXTERN_C NTSTATUS MmanDriverCreateClose( 36 | _Inout_ PDEVICE_OBJECT DeviceObject, 37 | _Inout_ PIRP Irp 38 | ) { 39 | UNREFERENCED_PARAMETER(DeviceObject); 40 | MMDebug(("MmanDriverCreateClose: 0x%0x8\r\n", HandleToUlong(PsGetCurrentProcessId()))); 41 | 42 | NTSTATUS Status = STATUS_SUCCESS; 43 | Irp->IoStatus.Status = Status; 44 | Irp->IoStatus.Information = 0x00; 45 | 46 | IofCompleteRequest(Irp, IO_NO_INCREMENT); 47 | return STATUS_SUCCESS; 48 | } 49 | 50 | _Use_decl_annotations_ 51 | EXTERN_C NTSTATUS MmanDriverDispatch( 52 | _Inout_ PDEVICE_OBJECT DeviceObject, 53 | _Inout_ PIRP Irp 54 | ) { 55 | UNREFERENCED_PARAMETER(DeviceObject); 56 | 57 | // Get the IRP Stack 58 | PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); 59 | 60 | ULONG_PTR Information = 0x00; 61 | NTSTATUS Status = STATUS_SUCCESS; 62 | 63 | switch (Stack->Parameters.DeviceIoControl.IoControlCode) { 64 | case IOCTL_MMANAGER_FIND_PROCESS_VADS: 65 | Status = MmanIoctlFindProcessVads(Irp, Stack); 66 | if (NT_SUCCESS(Status)) 67 | Information = sizeof(ULONG64); 68 | break; 69 | case IOCTL_MMANAGER_GET_PROCESS_VADS: 70 | Status = MmanIoctlGetProcessVads(Irp, Stack, &Information); 71 | if (!NT_SUCCESS(Status)) 72 | Information = 0x00; 73 | break; 74 | default: 75 | MMDebug(("Invalid IOCTL: 0x%08x\r\n", Stack->Parameters.DeviceIoControl.IoControlCode)); 76 | Status = STATUS_INVALID_DEVICE_REQUEST; 77 | break; 78 | } 79 | 80 | // Complete request 81 | Irp->IoStatus.Status = Status; 82 | Irp->IoStatus.Information = Information; 83 | IofCompleteRequest(Irp, IO_NO_INCREMENT); 84 | return Status; 85 | } -------------------------------------------------------------------------------- /MManager/MManager/mmanager-dispatch.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mmanager-dispatch.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | This file contains all global definition and information used by the kernel driver. 10 | 11 | ================================================================================================+*/ 12 | 13 | #ifndef __MMANAGER_DISPATCH_H_GUARD__ 14 | #define __MMANAGER_DISPATCH_H_GUARD__ 15 | 16 | #include "mmanager-globals.h" 17 | 18 | /// 19 | /// The Unload routine performs any operations that are necessary before the system unloads the driver. 20 | /// 21 | /// Caller-supplied pointer to a DRIVER_OBJECT structure. This is the driver's driver object. 22 | _IRQL_requires_max_(PASSIVE_LEVEL) 23 | EXTERN_C VOID 24 | MmanDriverUnload( 25 | _In_ PDRIVER_OBJECT DriverObject 26 | ); 27 | 28 | /// 29 | /// The callback routine for IRP_MJ_CREATE and IRP_MJ_CLOSE. 30 | /// 31 | /// Caller-supplied pointer to a DEVICE_OBJECT structure.This is the device object for the target device, previously created by the driver's AddDevice routine. 32 | /// Caller-supplied pointer to an IRP structure that describes the requested I/O operation. 33 | /// If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in Ntstatus.h. 34 | __drv_dispatchType(IRP_MJ_CREATE) 35 | __drv_dispatchType(IRP_MJ_CLOSE) 36 | _IRQL_requires_max_(PASSIVE_LEVEL) 37 | EXTERN_C NTSTATUS 38 | MmanDriverCreateClose( 39 | _Inout_ PDEVICE_OBJECT DeviceObject, 40 | _Inout_ PIRP Irp 41 | ); 42 | 43 | /// 44 | /// The callback routine services various IRPs. In this case handle user-mode IOCTL. For a list of function codes, see mmanager-globals.h. 45 | /// 46 | /// Caller-supplied pointer to a DEVICE_OBJECT structure.This is the device object for the target device, previously created by the driver's AddDevice routine. 47 | /// Caller-supplied pointer to an IRP structure that describes the requested I/O operation. 48 | /// If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values defined in Ntstatus.h. 49 | __drv_dispatchType(IRP_MJ_DEVICE_CONTROL) 50 | _IRQL_requires_max_(DISPATCH_LEVEL) 51 | EXTERN_C NTSTATUS 52 | MmanDriverDispatch( 53 | _Inout_ PDEVICE_OBJECT DeviceObject, 54 | _Inout_ PIRP Irp 55 | ); 56 | 57 | #endif // !__MMANAGER_DISPATCH_H_GUARD__ 58 | -------------------------------------------------------------------------------- /MManager/MManager/mmanager-globals.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mmanager-globals.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | This file contains all global definition and information used by the kernel driver. 10 | 11 | ================================================================================================+*/ 12 | 13 | #ifndef __MMANAGER_GLOBALS_H_GUARD__ 14 | #define __MMANAGER_GLOBALS_H_GUARD__ 15 | 16 | #include 17 | #include 18 | 19 | // Include security routines for driver 20 | #include 21 | #pragma comment(lib, "wdmsec.lib") 22 | 23 | // MManager Device driver Memory Pool Tag - "MMan" 24 | #define MMANAGER_MM_TAG (ULONG)0x6e614d4d 25 | 26 | // MManager Device driver name 27 | #define MMANAGER_DEVICE_NAME L"\\Device\\MManager" 28 | 29 | // MManager Device driver symbolic name 30 | #define MMANAGER_SYMBOLIC_LINK_NAME L"\\??\\MManager" 31 | 32 | // MManager Debug tag 33 | #define MMANAGER_DEBUG_TAG "[MManager] " 34 | 35 | // MManager wrapper around KdPrint for less bloated code. 36 | #define MMDebug(_x_) KdPrint((MMANAGER_DEBUG_TAG)); KdPrint(_x_) 37 | 38 | // MManager class GUID - {F7BD4AF3-BA07-4EB4-BD62-4BBF596D5C23} 39 | // {5C368CE1-3DB6-43EE-8EA8-9338B4803FAE} 40 | static CONST GUID MMANAGER_CLASS_GUID = { 41 | 0x5c368ce1, 42 | 0x3db6, 43 | 0x43ee, 44 | { 0x8e, 0xa8, 0x93, 0x38, 0xb4, 0x80, 0x3f, 0xae } 45 | }; 46 | 47 | // Query the VAD tree of a process 48 | #define IOCTL_MMANAGER_FIND_PROCESS_VADS CTL_CODE( \ 49 | 0x8000, /* DeviceType */\ 50 | 0x800, /* Function */\ 51 | METHOD_OUT_DIRECT, /* Method */\ 52 | FILE_ANY_ACCESS /* Access */\ 53 | ) 54 | 55 | // Query the VAD tree of a process 56 | #define IOCTL_MMANAGER_GET_PROCESS_VADS CTL_CODE( \ 57 | 0x8000, /* DeviceType */\ 58 | 0x801, /* Function */\ 59 | METHOD_OUT_DIRECT, /* Method */\ 60 | FILE_ANY_ACCESS /* Access */\ 61 | ) 62 | 63 | #endif // !__MMANAGER_GLOBALS_H_GUARD__ 64 | -------------------------------------------------------------------------------- /MManager/MManager/mmanager-routines.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mmanager-routines.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | Handle User-Mode IOCTL requests. 10 | 11 | ================================================================================================+*/ 12 | 13 | #include "mmanager-routines.h" 14 | 15 | #ifdef ALLOC_PRAGMA 16 | #pragma alloc_text(PAGE, MmanIoctlFindProcessVads) 17 | #pragma alloc_text(PAGE, MmanIoctlGetProcessVads) 18 | 19 | #pragma alloc_text(PAGE, MmanpCalculateStructureSize) 20 | #endif // ALLOC_PRAGMA 21 | 22 | // Global variable to store the size of the UM structure. 23 | ULONG64 VadTableSize = 0x00; 24 | 25 | // Global variable to build the UM structure. 26 | XVAD_TABLE VadTable = {0x00 }; 27 | 28 | 29 | _Use_decl_annotations_ 30 | EXTERN_C NTSTATUS MmanIoctlFindProcessVads( 31 | _In_ PIRP Irp, 32 | _In_ PIO_STACK_LOCATION Stack 33 | ) { 34 | // Ensure current IRQL allow paging. 35 | PAGED_CODE(); 36 | 37 | // Check for the input length 38 | if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) 39 | return STATUS_BUFFER_TOO_SMALL; 40 | 41 | // Check for output length 42 | if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(ULONG64)) { 43 | MMDebug(("MDL too small.\r\n")); 44 | return STATUS_INSUFFICIENT_RESOURCES; 45 | } 46 | PVOID UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 47 | if (UserBuffer == NULL) { 48 | MMDebug(("Unable to get MDL.\r\n")); 49 | return STATUS_INSUFFICIENT_RESOURCES; 50 | } 51 | 52 | // Filter out the system "process" 53 | ULONG ProcessId = 0x00; 54 | __try { 55 | RtlCopyMemory(&ProcessId, Irp->AssociatedIrp.SystemBuffer, sizeof(ULONG)); 56 | } 57 | __except (EXCEPTION_EXECUTE_HANDLER) { 58 | MMDebug(("Unreadable user-mode buffer.\r\n")); 59 | return STATUS_ACCESS_VIOLATION; 60 | } 61 | if (ProcessId <= 0x04 || (ProcessId % 0x04) != 0x00) { 62 | MMDebug(("Invalid process ID supplied.\r\n")); 63 | return STATUS_INVALID_PARAMETER; 64 | } 65 | MMDebug(("Process ID : 0x%x\r\n", ProcessId)); 66 | 67 | // Forward declaration of stack variables 68 | NTSTATUS Status = STATUS_SUCCESS; 69 | BOOLEAN ProcessAttached = FALSE; 70 | KAPC_STATE ProcessApcState = { 0x00 }; 71 | 72 | // Get the EPROCESS structure based on the requested ID 73 | PEPROCESS Process = NULL; 74 | Status = PsLookupProcessByProcessId(ULongToHandle(ProcessId), &Process); 75 | if (!NT_SUCCESS(Status)) { 76 | MMDebug(("Unable to get the _EPROCESS structure for the given PID (0x%08x).\r\n", Status)); 77 | goto exit; 78 | } 79 | 80 | // Increase reference counter to prevent process from terminating while 81 | // parsing the VAD tree 82 | ObReferenceObject(Process); 83 | KeStackAttachProcess(Process, &ProcessApcState); 84 | ProcessAttached = TRUE; 85 | MMDebug(("_EPROCESS address: 0x%p\r\n", Process)); 86 | 87 | // Initialize internal VAD table 88 | Status = XMiInitializeVadTable(Process, &VadTable); 89 | if (!NT_SUCCESS(Status)) { 90 | MMDebug(("Failed to initialize the VAD table (0x%08x).\r\n", Status)); 91 | goto exit; 92 | } 93 | 94 | // Get the whole table 95 | VadTable.Process = Process; 96 | XMiBuildVadTable(&VadTable, NULL, NULL, 0x00); 97 | 98 | // Release the proces object 99 | KeUnstackDetachProcess(&ProcessApcState); 100 | ObDereferenceObject(Process); 101 | ProcessAttached = FALSE; 102 | 103 | // Calculate the user-mode size of the data 104 | VadTableSize = MmanpCalculateStructureSize(); 105 | 106 | // Return the data to the user-mode caller 107 | __try { 108 | RtlCopyMemory(UserBuffer, &VadTableSize, sizeof(ULONG64)); 109 | return STATUS_SUCCESS; 110 | } 111 | __except (EXCEPTION_EXECUTE_HANDLER) { 112 | MMDebug(("Unable to return buffer size to caller.\r\n")); 113 | Status = STATUS_INVALID_PARAMETER; 114 | } 115 | 116 | // Cleanup and dereference the object 117 | exit: 118 | if (ProcessAttached) 119 | KeUnstackDetachProcess(&ProcessApcState); 120 | if (Process != NULL) 121 | ObDereferenceObject(Process); 122 | if (VadTable.Process == NULL) { 123 | VadTableSize = 0x00; 124 | XMiUninitializeVadTable(&VadTable); 125 | } 126 | return Status; 127 | } 128 | 129 | 130 | _Use_decl_annotations_ 131 | EXTERN_C NTSTATUS MmanIoctlGetProcessVads( 132 | _In_ PIRP Irp, 133 | _In_ PIO_STACK_LOCATION Stack, 134 | _Out_ ULONG_PTR* BufferOutSize 135 | ) { 136 | UNREFERENCED_PARAMETER(Stack); 137 | 138 | // Ensure current IRQL allow paging. 139 | PAGED_CODE(); 140 | 141 | NTSTATUS Status = STATUS_SUCCESS; 142 | PVOID UserBuffer = NULL; 143 | ULONG64 UmAddress = 0x00; 144 | 145 | // Check the input buffer 146 | if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG64)) { 147 | MMDebug(("Buffer too small.\r\n")); 148 | Status = STATUS_BUFFER_TOO_SMALL; 149 | goto exit; 150 | } 151 | __try { 152 | RtlCopyMemory(&UmAddress, Irp->AssociatedIrp.SystemBuffer, sizeof(ULONG64)); 153 | } 154 | __except (EXCEPTION_EXECUTE_HANDLER) { 155 | MMDebug(("Unreadable user-mode buffer.\r\n")); 156 | Status = STATUS_ACCESS_VIOLATION; 157 | goto exit; 158 | } 159 | 160 | // Check the size of the output buffer 161 | if (MmGetMdlByteCount(Irp->MdlAddress) < VadTableSize) { 162 | MMDebug(("MDL too small.\r\n")); 163 | Status = STATUS_INSUFFICIENT_RESOURCES; 164 | goto exit; 165 | } 166 | UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 167 | if (UserBuffer == NULL) { 168 | MMDebug(("Unable to get MDL.\r\n")); 169 | Status = STATUS_INSUFFICIENT_RESOURCES; 170 | goto exit; 171 | } 172 | 173 | // Get the header 174 | PMMANAGER_VADLIST_HEADER Header = UserBuffer; 175 | Header->Size = sizeof(MMANAGER_VADLIST_HEADER); 176 | Header->MaximumLevel = VadTable.MaximumLevel; 177 | Header->NumberOfNodes = VadTable.NumberOfNodes; 178 | Header->TotalPrivateCommit = VadTable.TotalPrivateCommit; 179 | Header->TotalSharedCommit = VadTable.TotalSharedCommit; 180 | Header->Eprocess = VadTable.Process; 181 | 182 | // Get address of first entry 183 | PVOID EntryPoint = (PUCHAR)Header + Header->Size; 184 | Header->First = XLATE_TO_UM_ADDRESS(UmAddress, Header, EntryPoint); 185 | 186 | PMMANAGER_VADLIST_ENTRY Blink = NULL; 187 | 188 | // Parse all entries 189 | PLIST_ENTRY ListEntry = VadTable.InsertOrderList.Flink; 190 | do { 191 | PXVAD_TABLE_ENTRY TableEntry = CONTAINING_RECORD(ListEntry, XVAD_TABLE_ENTRY, List); 192 | if (TableEntry == NULL) 193 | break; 194 | 195 | // New entry in output memory 196 | PMMANAGER_VADLIST_ENTRY OutEntry = EntryPoint; 197 | OutEntry->List.Blink = XLATE_TO_UM_ADDRESS(UmAddress, Header, Blink); 198 | 199 | if (OutEntry == Header->First) 200 | OutEntry->List.Blink = NULL; 201 | 202 | OutEntry->VadAddress = TableEntry->Address; 203 | OutEntry->Level = TableEntry->Level; 204 | OutEntry->VpnStarting = TableEntry->StartingVpn; 205 | OutEntry->VpnEnding = TableEntry->EndingVpn; 206 | OutEntry->CommitCharge = TableEntry->CommitCharge; 207 | OutEntry->LongVadFlags = TableEntry->LongVadFlags; 208 | OutEntry->LongVadFlags1 = TableEntry->LongVadFlags1; 209 | OutEntry->LongVadFlags2 = TableEntry->LongVadFlags2; 210 | 211 | if (TableEntry->Name != NULL) { 212 | OutEntry->FileNameSize = TableEntry->Name->Length; 213 | RtlCopyMemory(OutEntry->FileName, TableEntry->Name->Buffer, OutEntry->FileNameSize); 214 | } 215 | else if (TableEntry->ControlArea != NULL) { 216 | OutEntry->CommitPageCount = TableEntry->ControlArea->u3.CommittedPageCount; 217 | } 218 | 219 | OutEntry->Size = sizeof(MMANAGER_VADLIST_ENTRY) + OutEntry->FileNameSize; 220 | Header->Size += OutEntry->Size; 221 | 222 | // Check for end of the parsing 223 | if (ListEntry->Flink == &VadTable.InsertOrderList) { 224 | OutEntry->List.Flink = NULL; 225 | break; 226 | } 227 | 228 | // Move to next entry 229 | EntryPoint = (PUCHAR)EntryPoint + OutEntry->Size; 230 | OutEntry->List.Flink = XLATE_TO_UM_ADDRESS(UmAddress, Header, EntryPoint); 231 | 232 | Blink = OutEntry; 233 | ListEntry = ListEntry->Flink; 234 | } while (TRUE); 235 | 236 | // Set last data 237 | Header->Last = XLATE_TO_UM_ADDRESS(UmAddress, Header, EntryPoint);; 238 | *BufferOutSize = Header->Size; 239 | exit: 240 | // Release memory 241 | if (VadTableSize != 0x00) { 242 | XMiUninitializeVadTable(&VadTable); 243 | VadTableSize = 0x00; 244 | } 245 | return Status; 246 | } 247 | 248 | 249 | _Use_decl_annotations_ 250 | EXTERN_C ULONG64 MmanpCalculateStructureSize( 251 | VOID 252 | ) { 253 | if (VadTable.Process == NULL) 254 | return 0x00; 255 | 256 | // Ensure current IRQL allow paging. 257 | PAGED_CODE(); 258 | 259 | ULONG64 TotalSize = sizeof(MMANAGER_VADLIST_HEADER); 260 | 261 | // Parse all entries 262 | PLIST_ENTRY Entry = VadTable.InsertOrderList.Flink; 263 | do { 264 | PXVAD_TABLE_ENTRY TableEntry = CONTAINING_RECORD(Entry, XVAD_TABLE_ENTRY, List); 265 | if (TableEntry == NULL) 266 | break; 267 | 268 | TotalSize += sizeof(MMANAGER_VADLIST_ENTRY); 269 | if (TableEntry->Name != NULL) 270 | TotalSize += TableEntry->Name->Length + sizeof(WCHAR); 271 | 272 | // Next entry 273 | if (Entry->Flink == &VadTable.InsertOrderList) 274 | break; 275 | Entry = Entry->Flink; 276 | } while (TRUE); 277 | 278 | // Return the aligned memory. 279 | while ((TotalSize % PAGE_SIZE) != 0x00) 280 | TotalSize++; 281 | return TotalSize; 282 | } -------------------------------------------------------------------------------- /MManager/MManager/mmanager-routines.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mmanager-routines.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | Handle User-Mode IOCTL requests. 10 | 11 | ================================================================================================+*/ 12 | 13 | #ifndef __MMANAGER_H_GUARD__ 14 | #define __MMANAGER_H_GUARD__ 15 | 16 | #include "mmanager-globals.h" 17 | #include "mm/vad.h" 18 | 19 | #define XLATE_TO_UM_ADDRESS(UM, KM, Address) \ 20 | (PVOID)(((PUCHAR)UM) + ((PUCHAR)Address - ((PUCHAR)KM))) 21 | 22 | typedef struct _MMANAGER_VADLIST_ENTRY { 23 | struct { 24 | struct _MMANAGER_VADLIST_ENTRY* Flink; 25 | struct _MMANAGER_VADLIST_ENTRY* Blink; 26 | } List; 27 | 28 | ULONG64 Size; // Size of the entry (structure + PWCHAR if filename) 29 | 30 | PVOID VadAddress; // Address of the VAD node 31 | ULONG Level; // Node depth level 32 | ULONG64 VpnStarting; // Start of Virtual Page Number(VPN). 33 | ULONG64 VpnEnding; // Start of Virtual Page Number (VPN). 34 | ULONG64 CommitCharge; // Number of bytes commit 35 | ULONG64 CommitPageCount; // Number of pages commit 36 | 37 | // First set of flags. 38 | union { 39 | ULONG LongVadFlags; 40 | MMVAD_FLAGS VadFlags; 41 | MM_PRIVATE_VAD_FLAGS PrivateVadFlags; 42 | MM_GRAPHICS_VAD_FLAGS GraphicsVadFlags; 43 | MM_SHARED_VAD_FLAGS SharedVadFlags; 44 | }; 45 | // Second set of flags. 46 | union { 47 | ULONG LongVadFlags1; 48 | MMVAD_FLAGS1 VadFlags1; 49 | }; 50 | // Third set of flags. 51 | union { 52 | ULONG LongVadFlags2; 53 | MMVAD_FLAGS2 VadFlags2; 54 | }; 55 | 56 | ULONG FileNameSize; // Size of the filename 57 | WCHAR FileName[ANYSIZE_ARRAY]; // Pointer to the filename 58 | } MMANAGER_VADLIST_ENTRY, * PMMANAGER_VADLIST_ENTRY; 59 | 60 | 61 | typedef struct _MMANAGER_VADLIST_HEADER { 62 | ULONG64 Size; // Size of the data (header + all entries) 63 | ULONG MaximumLevel; // Deepest level 64 | ULONG NumberOfNodes; // Total number of nodes 65 | ULONG64 TotalPrivateCommit; // Total private memory 66 | ULONG64 TotalSharedCommit; // Total shared memory 67 | PVOID Eprocess; // 68 | 69 | PMMANAGER_VADLIST_ENTRY First; 70 | PMMANAGER_VADLIST_ENTRY Last; 71 | } MMANAGER_VADLIST_HEADER, * PMMANAGER_VADLIST_HEADER; 72 | 73 | 74 | // Global variable to store the size of the UM structure. 75 | extern ULONG64 VadTableSize; 76 | 77 | // Global variable to build the UM structure. 78 | extern XVAD_TABLE VadTable; 79 | 80 | 81 | _IRQL_requires_max_(DISPATCH_LEVEL) 82 | EXTERN_C NTSTATUS MmanIoctlFindProcessVads( 83 | _In_ PIRP Irp, 84 | _In_ PIO_STACK_LOCATION Stack 85 | ); 86 | 87 | 88 | _IRQL_requires_max_(DISPATCH_LEVEL) 89 | EXTERN_C NTSTATUS MmanIoctlGetProcessVads( 90 | _In_ PIRP Irp, 91 | _In_ PIO_STACK_LOCATION Stack, 92 | _Out_ ULONG_PTR* BufferOutSize 93 | ); 94 | 95 | 96 | _IRQL_requires_max_(DISPATCH_LEVEL) 97 | EXTERN_C ULONG64 MmanpCalculateStructureSize( 98 | VOID 99 | ); 100 | 101 | #endif // !__MMANAGER_H_GUARD__ 102 | 103 | -------------------------------------------------------------------------------- /MManager/MManager/rtl/osversion.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: osversion.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | Windows operating system versions runtime library. 10 | 11 | ================================================================================================+*/ 12 | 13 | #ifndef __X_RTL_OSVERSION_H_GUARD__ 14 | #define __X_RTL_OSVERSION_H_GUARD__ 15 | 16 | // OS Versions 17 | #define WINDOWS_10 (ULONG)0x0000000A 18 | 19 | // Build versions 20 | #define WINDOWS_10_19044 (ULONG)0x00004A64 21 | #define WINDOWS_10_22000 (ULONG)0x000055F0 22 | 23 | #endif // !__X_RTL_OSVERSION_H_GUARD__ 24 | -------------------------------------------------------------------------------- /MManager/vadlist/main.cpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: main.cpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | Console application entry point. 10 | 11 | ================================================================================================+*/ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "mmanager.h" 18 | 19 | INT32 main( 20 | _In_ int argc, 21 | _In_ const char* argv[] 22 | ) { 23 | // Banner 24 | wprintf(L"================================================================================================\r\n"); 25 | wprintf(L"Module Name: Virtual Address Descriptor List (vadlist) \r\n"); 26 | wprintf(L"Author : Paul L. (@am0nsec) \r\n"); 27 | wprintf(L"Origin : https://github.com/am0nsec/wkpe/ \r\n\r\n"); 28 | wprintf(L"Tested OS : Windows 10 (20h2) - 19044.1706 \r\n"); 29 | wprintf(L"================================================================================================\r\n\r\n"); 30 | 31 | // Check for parameters 32 | if (argc < 0x02) { 33 | printf("Usage: vadlist.exe \r\n\r\n"); 34 | return EXIT_FAILURE; 35 | } 36 | 37 | // Check for the PID provided 38 | ULONG ProcessId = atoi(argv[0x01]);; 39 | if (ProcessId <= 0x04 || (ProcessId % 4) != 0x00) { 40 | printf("Invalid process ID supplied. \r\n\r\n"); 41 | return EXIT_FAILURE; 42 | } 43 | 44 | // Open handle to the device driver 45 | std::unique_ptr MManager = std::make_unique(); 46 | if (!MManager->IsDeviceReady()) { 47 | printf("Failed to open handle to device driver.\r\n\r\n"); 48 | return EXIT_FAILURE; 49 | } 50 | 51 | // Get the list of VADs 52 | if (!MManager->FindProcessVads(ProcessId)) { 53 | printf("Failed to retrieve VAD list.\r\n\r\n"); 54 | return EXIT_FAILURE; 55 | } 56 | MManager->PrintProcessVads(); 57 | 58 | return EXIT_SUCCESS; 59 | } 60 | -------------------------------------------------------------------------------- /MManager/vadlist/mmanager.cpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mmanager.cpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | User mode interface to query VAD list of a process. 10 | 11 | ================================================================================================+*/ 12 | 13 | #include 14 | #include "mmanager.h" 15 | 16 | 17 | CMManager::CMManager() { 18 | // Open handle to the device driver 19 | this->m_DeviceHandle = ::CreateFileW( 20 | MMANAGER_DEVICE_NAME_UM, 21 | (GENERIC_READ | GENERIC_WRITE), 22 | 0x00, 23 | NULL, 24 | OPEN_EXISTING, 25 | 0x00, 26 | NULL 27 | ); 28 | 29 | } 30 | 31 | 32 | CMManager::~CMManager() { 33 | if (this->m_DeviceHandle != INVALID_HANDLE_VALUE) { 34 | CloseHandle(this->m_DeviceHandle); 35 | } 36 | if (this->m_ListHeader != NULL) { 37 | HeapFree(GetProcessHeap(), 0x00, this->m_ListHeader); 38 | } 39 | } 40 | 41 | 42 | _Use_decl_annotations_ 43 | BOOLEAN CMManager::IsDeviceReady() { 44 | return this->m_DeviceHandle != INVALID_HANDLE_VALUE; 45 | } 46 | 47 | 48 | _Use_decl_annotations_ 49 | BOOLEAN CMManager::FindProcessVads( 50 | _In_ CONST ULONG ProcessId 51 | ) { 52 | if (ProcessId == 0x00) 53 | return FALSE; 54 | if (!this->IsDeviceReady()) 55 | return FALSE; 56 | 57 | // Make sure we do not allocate too much memory 58 | if (this->m_ListHeader != NULL) 59 | HeapFree(GetProcessHeap(), 0x00, this->m_ListHeader); 60 | 61 | // Send first IOCTL to get the amount of memory to allocate. 62 | ULONG64 BufferSize = 0x00; 63 | DWORD ReturnedBytes = 0x00; 64 | 65 | BOOL Success = ::DeviceIoControl( 66 | this->m_DeviceHandle, 67 | IOCTL_MMANAGER_FIND_PROCESS_VADS, 68 | (LPVOID)&ProcessId, 69 | sizeof(ULONG), 70 | &BufferSize, 71 | sizeof(ULONG64), 72 | &ReturnedBytes, 73 | NULL 74 | ); 75 | if (!Success) { 76 | wprintf(L"IOCTL_MMANAGER_FIND_PROCESS_VADS failed (%d).\r\n", GetLastError()); 77 | return Success; 78 | } 79 | 80 | // Allocate memory 81 | this->m_ListHeader = (MMANAGER_VADLIST_HEADER*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize); 82 | if (this->m_ListHeader == NULL) { 83 | wprintf(L"Not enough memory (%d).\r\n", GetLastError()); 84 | return FALSE; 85 | } 86 | 87 | // Call to get the data back 88 | ULONG64 UmAddress = (ULONG64)this->m_ListHeader; 89 | Success = ::DeviceIoControl( 90 | this->m_DeviceHandle, 91 | IOCTL_MMANAGER_GET_PROCESS_VADS, 92 | (PVOID)&UmAddress, 93 | sizeof(PVOID), 94 | this->m_ListHeader, 95 | (DWORD)BufferSize, 96 | &ReturnedBytes, 97 | NULL 98 | ); 99 | if (!Success) { 100 | wprintf(L"IOCTL_MMANAGER_GET_PROCESS_VADS failed (%d).\r\n", GetLastError()); 101 | HeapFree(GetProcessHeap(), 0x00, this->m_ListHeader); 102 | } 103 | return Success; 104 | } 105 | 106 | 107 | VOID CMManager::PrintProcessVads() { 108 | if (this->m_ListHeader == NULL) 109 | return; 110 | 111 | // Header of the table 112 | wprintf(L"VAD Level VPN Start VPN End Commit Type Protection Pagefile/Image\r\n"); 113 | wprintf(L"--- ----- --------- ------- ------ ---- ---------- --------------\r\n"); 114 | PMMANAGER_VADLIST_ENTRY Entry = this->m_ListHeader->First; 115 | do { 116 | // VAD node generic information 117 | wprintf(L"%p %5d %9llx %9llx %-8I64d %s", 118 | Entry->VadAddress, 119 | Entry->Level, 120 | 121 | Entry->VpnStarting, 122 | Entry->VpnEnding, 123 | Entry->CommitCharge, 124 | Entry->VadFlags.PrivateMemory != 0x00 ? L"Private " : L"Mapped " 125 | ); 126 | 127 | // VAD node type information 128 | switch ((MI_VAD_TYPE)Entry->VadFlags.VadType) { 129 | case VadDevicePhysicalMemory: 130 | wprintf(L"Phys "); 131 | break; 132 | case VadImageMap: 133 | wprintf(L"Exe "); 134 | break; 135 | case VadAwe: 136 | wprintf(L"AWE "); 137 | break; 138 | case VadWriteWatch: 139 | wprintf(L"WrtWatch "); 140 | break; 141 | case VadLargePages: 142 | wprintf(L"LargePag "); 143 | break; 144 | case VadRotatePhysical: 145 | wprintf(L"Rotate "); 146 | break; 147 | case VadLargePageSection: 148 | wprintf(L"LargePagSec "); 149 | break; 150 | case VadNone: 151 | default: 152 | wprintf(L" "); 153 | break; 154 | } 155 | 156 | // VAD node permissions 157 | switch (Entry->VadFlags.Protection & MM_PROTECTION_OPERATION_MASK) { 158 | case MM_READONLY: 159 | wprintf(L"READONLY "); 160 | break; 161 | case MM_EXECUTE: 162 | wprintf(L"EXECUTE "); 163 | break; 164 | case MM_EXECUTE_READ: 165 | wprintf(L"EXECUTE_READ "); 166 | break; 167 | case MM_READWRITE: 168 | wprintf(L"READWRITE "); 169 | break; 170 | case MM_WRITECOPY: 171 | wprintf(L"WRITECOPY "); 172 | break; 173 | case MM_EXECUTE_READWRITE: 174 | wprintf(L"EXECUTE_READWRITE "); 175 | break; 176 | case MM_EXECUTE_WRITECOPY: 177 | wprintf(L"EXECUTE_WRITECOPY "); 178 | break; 179 | } 180 | if ((Entry->VadFlags.Protection & ~MM_PROTECTION_OPERATION_MASK) != 0x00) { 181 | switch (Entry->VadFlags.Protection >> 0x03) { 182 | case (MM_NOCACHE >> 0x03): 183 | wprintf(L"NOCACHE "); 184 | break; 185 | case (MM_GUARD_PAGE >> 0x03): 186 | wprintf(L"GUARD_PAGE "); 187 | break; 188 | case (MM_NOACCESS >> 0x03): 189 | wprintf(L"NO_ACCESS "); 190 | break; 191 | } 192 | } 193 | 194 | // Display file name if mapped 195 | if (Entry->FileName[0x00] != 0x00) { 196 | wprintf(L"%s", (PWCHAR)Entry->FileName); 197 | } 198 | else if (Entry->CommitPageCount != 0x00) { 199 | wprintf(L"Pagefile section, shared commit %#I64x", Entry->CommitPageCount); 200 | } 201 | wprintf(L"\r\n"); 202 | } while (Entry = Entry->List.Flink); 203 | 204 | wprintf(L"\r\n"); 205 | wprintf(L"EPROCESS : 0x%p\r\n", this->m_ListHeader->Eprocess); 206 | wprintf(L"Total VADs : %d\r\n", this->m_ListHeader->NumberOfNodes); 207 | wprintf(L"Maximum depth: %d\r\n", this->m_ListHeader->MaximumLevel); 208 | wprintf(L"\r\n"); 209 | } -------------------------------------------------------------------------------- /MManager/vadlist/mmanager.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mmanager.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | 8 | Abstract: 9 | User mode interface to query VAD list of a process. 10 | 11 | ================================================================================================+*/ 12 | 13 | #ifndef __MMANAGER_H_GUARD__ 14 | #define __MMANAGER_H_GUARD__ 15 | 16 | #include 17 | #include 18 | 19 | // Query the VAD tree of a process 20 | #define IOCTL_MMANAGER_FIND_PROCESS_VADS CTL_CODE( \ 21 | 0x8000, /* DeviceType */\ 22 | 0x800, /* Function */\ 23 | METHOD_OUT_DIRECT, /* Method */\ 24 | FILE_ANY_ACCESS /* Access */\ 25 | ) 26 | 27 | // Query the VAD tree of a process 28 | #define IOCTL_MMANAGER_GET_PROCESS_VADS CTL_CODE( \ 29 | 0x8000, /* DeviceType */\ 30 | 0x801, /* Function */\ 31 | METHOD_OUT_DIRECT, /* Method */\ 32 | FILE_ANY_ACCESS /* Access */\ 33 | ) 34 | 35 | // User-mode name of the device driver 36 | #define MMANAGER_DEVICE_NAME_UM L"\\\\.\\MManager" 37 | 38 | #define MM_ZERO_ACCESS 0 // this value is not used. 39 | #define MM_READONLY 1 40 | #define MM_EXECUTE 2 41 | #define MM_EXECUTE_READ 3 42 | #define MM_READWRITE 4 // bit 2 is set if this is writable. 43 | #define MM_WRITECOPY 5 44 | #define MM_EXECUTE_READWRITE 6 45 | #define MM_EXECUTE_WRITECOPY 7 46 | 47 | #define MM_NOCACHE 0x8 48 | #define MM_GUARD_PAGE 0x10 49 | #define MM_DECOMMIT 0x10 // NO_ACCESS, Guard page 50 | #define MM_NOACCESS 0x18 // NO_ACCESS, Guard_page, nocache. 51 | #define MM_UNKNOWN_PROTECTION 0x100 // bigger than 5 bits! 52 | 53 | #define MM_INVALID_PROTECTION ((ULONG)-1) // bigger than 5 bits! 54 | 55 | #define MM_PROTECTION_WRITE_MASK 4 56 | #define MM_PROTECTION_COPY_MASK 1 57 | #define MM_PROTECTION_OPERATION_MASK 7 // mask off guard page and nocache. 58 | #define MM_PROTECTION_EXECUTE_MASK 2 59 | 60 | typedef enum _MI_VAD_TYPE { 61 | VadNone, 62 | VadDevicePhysicalMemory, 63 | VadImageMap, 64 | VadAwe, 65 | VadWriteWatch, 66 | VadLargePages, 67 | VadRotatePhysical, 68 | VadLargePageSection 69 | } MI_VAD_TYPE, * PMI_VAD_TYPE; 70 | 71 | typedef struct _MMVAD_FLAGS { 72 | ULONG Lock : 1; 73 | ULONG LockContended : 1; 74 | ULONG DeleteInProgress : 1; 75 | ULONG NoChange : 1; 76 | ULONG VadType : 3; 77 | ULONG Protection : 5; 78 | ULONG PreferredNode : 6; 79 | ULONG PageSize : 2; 80 | ULONG PrivateMemory : 1; 81 | } MMVAD_FLAGS, * PMMVAD_FLAGS; 82 | 83 | typedef struct _MMVAD_FLAGS1 { 84 | ULONG CommitCharge : 31; 85 | ULONG MemCommit : 1; 86 | } MMVAD_FLAGS1, * PMMVAD_FLAGS1; 87 | 88 | typedef struct _MMVAD_FLAGS2 { 89 | ULONG FileOffset : 24; 90 | ULONG Large : 1; 91 | ULONG TrimBehind : 1; 92 | ULONG Inherit : 1; 93 | ULONG NoValidationNeeded : 1; 94 | ULONG PrivateDemandZero : 1; 95 | ULONG Spare : 3; 96 | } MMVAD_FLAGS2, * PMMVAD_FLAGS2; 97 | 98 | typedef struct _MM_PRIVATE_VAD_FLAGS { 99 | union { 100 | ULONG Lock : 1; 101 | ULONG LockContended : 1; 102 | ULONG DeleteInProgress : 1; 103 | ULONG NoChange : 1; 104 | ULONG VadType : 3; 105 | ULONG Protection : 5; 106 | ULONG PreferredNode : 6; 107 | ULONG PageSize : 2; 108 | ULONG PrivateMemoryAlwaysSet : 1; 109 | ULONG WriteWatch : 1; 110 | ULONG FixedLargePageSize : 1; 111 | ULONG ZeroFillPagesOptional : 1; 112 | ULONG Graphics : 1; 113 | ULONG Enclave : 1; 114 | ULONG ShadowStack : 1; 115 | ULONG PhysicalMemoryPfnsReferenced : 1; 116 | }; 117 | } MM_PRIVATE_VAD_FLAGS, * PMM_PRIVATE_VAD_FLAGS; 118 | 119 | typedef struct _MM_GRAPHICS_VAD_FLAGS { 120 | union { 121 | ULONG Lock : 1; 122 | ULONG LockContended : 1; 123 | ULONG DeleteInProgress : 1; 124 | ULONG NoChange : 1; 125 | ULONG VadType : 3; 126 | ULONG Protection : 5; 127 | ULONG PreferredNode : 6; 128 | ULONG PageSize : 2; 129 | ULONG PrivateMemoryAlwaysSet : 1; 130 | ULONG WriteWatch : 1; 131 | ULONG FixedLargePageSize : 1; 132 | ULONG ZeroFillPagesOptional : 1; 133 | ULONG GraphicsAlwaysSet : 1; 134 | ULONG GraphicsUseCoherentBus : 1; 135 | ULONG GraphicsNoCache : 1; 136 | ULONG GraphicsPageProtection : 3; 137 | }; 138 | } MM_GRAPHICS_VAD_FLAGS, * PMM_GRAPHICS_VAD_FLAGS; 139 | 140 | typedef struct _MM_SHARED_VAD_FLAGS { 141 | union { 142 | ULONG Lock : 1; 143 | ULONG LockContended : 1; 144 | ULONG DeleteInProgress : 1; 145 | ULONG NoChange : 1; 146 | ULONG VadType : 3; 147 | ULONG Protection : 5; 148 | ULONG PreferredNode : 6; 149 | ULONG PageSize : 2; 150 | ULONG PrivateMemoryAlwaysClear : 1; 151 | ULONG PrivateFixup : 1; 152 | ULONG HotPatchAllowed : 1; 153 | }; 154 | } MM_SHARED_VAD_FLAGS, * PMM_SHARED_VAD_FLAGS; 155 | 156 | typedef struct _MMANAGER_VADLIST_ENTRY { 157 | struct { 158 | struct _MMANAGER_VADLIST_ENTRY* Flink; 159 | struct _MMANAGER_VADLIST_ENTRY* Blink; 160 | } List; 161 | 162 | ULONG64 Size; // Size of the entry (structure + PWCHAR if filename) 163 | 164 | PVOID VadAddress; // Address of the VAD node 165 | ULONG Level; // Node depth level 166 | ULONG64 VpnStarting; // Start of Virtual Page Number(VPN). 167 | ULONG64 VpnEnding; // Start of Virtual Page Number (VPN). 168 | ULONG64 CommitCharge; // Number of bytes commit 169 | ULONG64 CommitPageCount; // Number of pages commited 170 | 171 | // First set of flags. 172 | union { 173 | ULONG LongVadFlags; 174 | MMVAD_FLAGS VadFlags; 175 | MM_PRIVATE_VAD_FLAGS PrivateVadFlags; 176 | MM_GRAPHICS_VAD_FLAGS GraphicsVadFlags; 177 | MM_SHARED_VAD_FLAGS SharedVadFlags; 178 | }; 179 | // Second set of flags. 180 | union { 181 | ULONG LongVadFlags1; 182 | MMVAD_FLAGS1 VadFlags1; 183 | }; 184 | // Third set of flags. 185 | union { 186 | ULONG LongVadFlags2; 187 | MMVAD_FLAGS2 VadFlags2; 188 | }; 189 | 190 | ULONG FileNameSize; // Size of the filename 191 | WCHAR FileName[ANYSIZE_ARRAY]; // Pointer to the filename 192 | } MMANAGER_VADLIST_ENTRY, *PMMANAGER_VADLIST_ENTRY; 193 | 194 | typedef struct _MMANAGER_VADLIST_HEADER { 195 | ULONG64 Size; // Size of the data (header + all entries) 196 | ULONG MaximumLevel; // Deepest level 197 | ULONG NumberOfNodes; // Total number of nodes 198 | ULONG64 TotalPrivateCommit; // Total private memory 199 | ULONG64 TotalSharedCommit; // Total shared memory 200 | PVOID Eprocess; // 201 | 202 | PMMANAGER_VADLIST_ENTRY First; 203 | PMMANAGER_VADLIST_ENTRY Last; 204 | } MMANAGER_VADLIST_HEADER, *PMMANAGER_VADLIST_HEADER; 205 | 206 | class CMManager { 207 | 208 | public: 209 | CMManager(); 210 | ~CMManager(); 211 | 212 | _Must_inspect_result_ 213 | BOOLEAN IsDeviceReady(); 214 | 215 | _Must_inspect_result_ 216 | BOOLEAN FindProcessVads( 217 | _In_ CONST ULONG ProcessId 218 | ); 219 | 220 | VOID PrintProcessVads(); 221 | 222 | private: 223 | /// 224 | /// Handle to the device driver. 225 | /// 226 | HANDLE m_DeviceHandle{ INVALID_HANDLE_VALUE }; 227 | 228 | /// 229 | /// Pointer to the header of the list. 230 | /// 231 | PMMANAGER_VADLIST_HEADER m_ListHeader{ NULL }; 232 | }; 233 | 234 | #endif // !__MMANAGER_H_GUARD__ 235 | -------------------------------------------------------------------------------- /MManager/vadlist/vadlist.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {17475489-56c9-4202-ba6f-79c75805e497} 25 | vadlist 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | MultiThreadedDebug 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /MManager/vadlist/vadlist.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Windows Kernel Programming Experiments 2 | -------------------------------------- 3 | All projects and the code within this repository are solely proof of concepts and have not been thoroughly tested on different versions of Microsoft Windows. 4 | 5 | The `DriverEntry` routines of each driver checks for the version of the operating system and will make sure it is `Windows 10 (20h2) - 19044.1706`, as it the Windows 10 version I used to test the drivers. 6 | 7 | All structures and other `typedef` have been defined via available PDBs, WinDBG and [resym tool](https://github.com/ergrelet/resym). Structures and data may differ from one version to another - use with caution. 8 | 9 | ### MManager 10 | Experiments with the Windows Memory Manager (Mm/Mi). Currently listing Virtual Address Descriptors (VADs) of a process. 11 | 12 | Kernel Device Name: `\\Device\\MManager`
13 | 14 | List of User-Mode applications: 15 | - vadlist.exe -------------------------------------------------------------------------------- /WKI/WKI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32505.426 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WKIKM", "WKIKM\WKIKM.vcxproj", "{75E14ADD-808F-491C-A221-B29E5AA667D8}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WKIUM", "WKIUM\WKIUM.vcxproj", "{5E103710-74AD-495F-9A72-C69573DF2D2A}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|ARM64 = Debug|ARM64 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|ARM64 = Release|ARM64 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|Any CPU.ActiveCfg = Debug|x64 23 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|Any CPU.Build.0 = Debug|x64 24 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|Any CPU.Deploy.0 = Debug|x64 25 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|ARM64.ActiveCfg = Debug|ARM64 26 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|ARM64.Build.0 = Debug|ARM64 27 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|ARM64.Deploy.0 = Debug|ARM64 28 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|x64.ActiveCfg = Debug|x64 29 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|x64.Build.0 = Debug|x64 30 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|x64.Deploy.0 = Debug|x64 31 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|x86.ActiveCfg = Debug|x64 32 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|x86.Build.0 = Debug|x64 33 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Debug|x86.Deploy.0 = Debug|x64 34 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|Any CPU.ActiveCfg = Release|x64 35 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|Any CPU.Build.0 = Release|x64 36 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|Any CPU.Deploy.0 = Release|x64 37 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|ARM64.ActiveCfg = Release|ARM64 38 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|ARM64.Build.0 = Release|ARM64 39 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|ARM64.Deploy.0 = Release|ARM64 40 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|x64.ActiveCfg = Release|x64 41 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|x64.Build.0 = Release|x64 42 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|x64.Deploy.0 = Release|x64 43 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|x86.ActiveCfg = Release|x64 44 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|x86.Build.0 = Release|x64 45 | {75E14ADD-808F-491C-A221-B29E5AA667D8}.Release|x86.Deploy.0 = Release|x64 46 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|Any CPU.ActiveCfg = Debug|x64 47 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|Any CPU.Build.0 = Debug|x64 48 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|ARM64.ActiveCfg = Debug|x64 49 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|ARM64.Build.0 = Debug|x64 50 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|x64.ActiveCfg = Debug|x64 51 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|x64.Build.0 = Debug|x64 52 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|x86.ActiveCfg = Debug|Win32 53 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Debug|x86.Build.0 = Debug|Win32 54 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|Any CPU.ActiveCfg = Release|x64 55 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|Any CPU.Build.0 = Release|x64 56 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|ARM64.ActiveCfg = Release|x64 57 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|ARM64.Build.0 = Release|x64 58 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|x64.ActiveCfg = Release|x64 59 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|x64.Build.0 = Release|x64 60 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|x86.ActiveCfg = Release|Win32 61 | {5E103710-74AD-495F-9A72-C69573DF2D2A}.Release|x86.Build.0 = Release|Win32 62 | EndGlobalSection 63 | GlobalSection(SolutionProperties) = preSolution 64 | HideSolutionNode = FALSE 65 | EndGlobalSection 66 | GlobalSection(ExtensibilityGlobals) = postSolution 67 | SolutionGuid = {ED1B074C-3945-47E8-B42C-3F70C01E4BAC} 68 | EndGlobalSection 69 | EndGlobal 70 | -------------------------------------------------------------------------------- /WKI/WKIKM/WKIKM.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | {75E14ADD-808F-491C-A221-B29E5AA667D8} 23 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 24 | v4.5 25 | 12.0 26 | Debug 27 | x64 28 | KernelIntrospection 29 | WKIKM 30 | $(LatestTargetPlatformVersion) 31 | 32 | 33 | 34 | Windows10 35 | true 36 | WindowsKernelModeDriver10.0 37 | Driver 38 | WDM 39 | false 40 | 41 | 42 | Windows10 43 | false 44 | WindowsKernelModeDriver10.0 45 | Driver 46 | WDM 47 | 48 | 49 | Windows10 50 | true 51 | WindowsKernelModeDriver10.0 52 | Driver 53 | WDM 54 | 55 | 56 | Windows10 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | WDM 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | DbgengKernelDebugger 72 | wkikm 73 | 74 | 75 | DbgengKernelDebugger 76 | 77 | 78 | DbgengKernelDebugger 79 | 80 | 81 | DbgengKernelDebugger 82 | 83 | 84 | 85 | sha256 86 | 87 | 88 | wdmsec.lib;Aux_Klib.lib;%(AdditionalDependencies) 89 | 90 | 91 | 92 | 93 | sha256 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /WKI/WKIKM/WKIKM.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /WKI/WKIKM/ki-globals.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: ki-globals.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | This file contains all global definition and information used by the kernel driver. 9 | ================================================================================================+*/ 10 | 11 | #ifndef __KI_H_GUARD__ 12 | #define __KI_H_GUARD__ 13 | 14 | #include 15 | #include 16 | 17 | // Include security routines for driver 18 | #include 19 | 20 | // Windows Kernel Introspection Device driver name 21 | #define KI_DEVICE_NAME L"\\Device\\WKI" 22 | 23 | // Windows Kernel Introspection Device driver symbolic name 24 | #define KI_SYMBOLIC_LINK_NAME L"\\??\\WKI" 25 | 26 | // Windows Kernel Introspection Debug tag 27 | #define KI_DEBUG_TAG "[WKI] " 28 | 29 | // Windows Kernel Introspection wrapper around KdPrint for less bloated code. 30 | #define KiDebug(_x_) KdPrint((KI_DEBUG_TAG)); KdPrint(_x_) 31 | 32 | // Windows Kernel Introspection class GUID - {3E07100B-E36E-4F2E-8345-1399B9947497} 33 | static CONST GUID KI_CLASS_GUID = { 34 | 0x3e07100b, 35 | 0xe36e, 36 | 0x4f2e, 37 | { 0x83, 0x45, 0x13, 0x99, 0xb9, 0x94, 0x74, 0x97 } 38 | }; 39 | 40 | #endif // !__KI_H_GUARD__ 41 | -------------------------------------------------------------------------------- /WKI/WKIKM/main.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: main.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Device driver entry point. 9 | ================================================================================================+*/ 10 | 11 | #include "ki-globals.h" 12 | #include "wki/wki.h" 13 | 14 | /// 15 | /// Device driver entry point. 16 | /// 17 | /// Pointer to the driver object. 18 | /// Pointer to the registry path, if any. 19 | EXTERN_C NTSTATUS DriverEntry( 20 | _In_ PDRIVER_OBJECT DriverObject, 21 | _In_ PUNICODE_STRING RegistryPath 22 | ); 23 | 24 | /// 25 | /// The Unload routine performs any operations that are necessary before the system unloads the driver. 26 | /// 27 | _IRQL_requires_max_(PASSIVE_LEVEL) 28 | EXTERN_C VOID DriverUnload( 29 | _In_ PDRIVER_OBJECT DriverObject 30 | ); 31 | 32 | /// 33 | /// Test Windows Kernel Introspection initialisation and the successful retreival of required 34 | /// symbols for the list of memory pool tags. 35 | /// 36 | _IRQL_requires_max_(PASSIVE_LEVEL) 37 | EXTERN_C VOID TestWKI( 38 | VOID 39 | ); 40 | 41 | /// 42 | /// List kernel memory ppol tags. 43 | /// 44 | _IRQL_requires_max_(PASSIVE_LEVEL) 45 | EXTERN_C VOID ListPoolTags( 46 | VOID 47 | ); 48 | 49 | #ifdef ALLOC_PRAGMA 50 | #pragma alloc_text(INIT, DriverEntry) 51 | 52 | #pragma alloc_text(PAGE, DriverUnload) 53 | #pragma alloc_text(PAGE, TestWKI) 54 | #pragma alloc_text(PAGE, ListPoolTags) 55 | #endif // ALLOC_PRAGMA 56 | 57 | 58 | _Use_decl_annotations_ 59 | EXTERN_C NTSTATUS DriverEntry( 60 | _In_ PDRIVER_OBJECT DriverObject, 61 | _In_ PUNICODE_STRING RegistryPath 62 | ) { 63 | UNREFERENCED_PARAMETER(RegistryPath); 64 | 65 | KiDebug(("=================================================================\r\n")); 66 | KiDebug(("Module Name: Windows Kernel Introspection -- KM \r\n")); 67 | KiDebug(("Author : Paul L. (@am0nsec) \r\n")); 68 | KiDebug(("Origin : https://github.com/am0nsec/wkpe/ \r\n")); 69 | KiDebug(("Tested OS : Windows 10 (20h2) - 19044.1889 \r\n")); 70 | KiDebug((" Windows 10 (20h2) - 19044.1766 \r\n")); 71 | KiDebug((" Windows 10 (20h2) - 19044.1706 \r\n")); 72 | KiDebug(("=================================================================\r\n")); 73 | 74 | // Initialise stack variables 75 | NTSTATUS Status = STATUS_SUCCESS; 76 | UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(KI_DEVICE_NAME); 77 | UNICODE_STRING SymbolicName = RTL_CONSTANT_STRING(KI_SYMBOLIC_LINK_NAME); 78 | 79 | PDEVICE_OBJECT DeviceObject = NULL; 80 | BOOLEAN SymbolicLink = FALSE; 81 | 82 | // Set unload routine 83 | DriverObject->DriverUnload = DriverUnload; 84 | 85 | // Register the device driver and symbolic link 86 | do { 87 | // Exclusive - Prevent multiple handles to be open for the device driver. 88 | // SDDLString - Prevent non-admin and non-SYSTEM from interacting with the device driver. 89 | Status = WdmlibIoCreateDeviceSecure( 90 | DriverObject, 91 | 0x00, 92 | &DeviceName, 93 | FILE_DEVICE_UNKNOWN, 94 | 0x00, 95 | TRUE, 96 | &SDDL_DEVOBJ_SYS_ALL_ADM_ALL, 97 | &KI_CLASS_GUID, 98 | &DeviceObject 99 | ); 100 | if (!NT_SUCCESS(Status)) { 101 | KiDebug(("Failed to create device object (0x%08X).\r\n", Status)); 102 | break; 103 | } 104 | 105 | Status = IoCreateSymbolicLink(&SymbolicName, &DeviceName); 106 | if (!NT_SUCCESS(Status)) { 107 | KiDebug(("Failed to symbolic link (0x%08X).\r\n", Status)); 108 | break; 109 | } 110 | SymbolicLink = TRUE; 111 | } while (FALSE); 112 | 113 | // Check for errors 114 | if (!NT_SUCCESS(Status)) { 115 | KiDebug(("Roll-back operations.\r\n")); 116 | if (SymbolicLink) 117 | IoDeleteSymbolicLink(&SymbolicName); 118 | if (DeviceObject != NULL) 119 | IoDeleteDevice(DeviceObject); 120 | KiDebug(("----------------------------------------------------------------\r\n")); 121 | return Status; 122 | } 123 | 124 | // Display final information and exit 125 | KiDebug(("Device name : %wZ\r\n", DeviceName)); 126 | KiDebug(("Symbolic link name: %wZ\r\n", SymbolicName)); 127 | KiDebug(("-----------------------------------------------\r\n")); 128 | 129 | TestWKI(); 130 | ListPoolTags(); 131 | return Status; 132 | } 133 | 134 | 135 | _Use_decl_annotations_ 136 | EXTERN_C VOID DriverUnload( 137 | _In_ PDRIVER_OBJECT DriverObject 138 | ) { 139 | KiDebug(("-----------------------------------------------\r\n")); 140 | 141 | // Uninitialise WKI 142 | WkiUninitialise(); 143 | 144 | // Delete the symbolic link and the device object 145 | UNICODE_STRING SymbolicName = RTL_CONSTANT_STRING(KI_SYMBOLIC_LINK_NAME); 146 | IoDeleteSymbolicLink(&SymbolicName); 147 | IoDeleteDevice(DriverObject->DeviceObject); 148 | } 149 | 150 | 151 | _Use_decl_annotations_ 152 | EXTERN_C VOID TestWKI( 153 | VOID 154 | ) { 155 | KiDebug(("Start testing wki ...\r\n")); 156 | 157 | NTSTATUS Status = WkiInitialise(); 158 | if (NT_ERROR(Status)) { 159 | KiDebug(("WkiInitialise failed \r\n")); 160 | WkiUninitialise(); 161 | return; 162 | } 163 | 164 | // Make sure everything is available when required 165 | ASSERT(WkiGetSymbol("KeNumberProcessors")); 166 | ASSERT(WkiGetSymbol("ExPoolTagTables")); 167 | ASSERT(WkiGetSymbol("PoolTrackTableSize")); 168 | 169 | KiDebug(("Start testing wki ... ok\r\n")); 170 | KiDebug(("-----------------------------------------------\r\n")); 171 | } 172 | 173 | typedef struct _POOL_TRACKER_TABLE { 174 | INT32 Key; 175 | UINT64 NonPagedBytes; 176 | UINT64 NonPagedAllocs; 177 | UINT64 NonPagedFrees; 178 | UINT64 PagedBytes; 179 | UINT64 PagedAllocs; 180 | UINT64 PagedFrees; 181 | } POOL_TRACKER_TABLE, *PPOOL_TRACKER_TABLE; 182 | 183 | 184 | EXTERN_C VOID MakePrintableString( 185 | _In_ UINT32 Key, 186 | _Out_ PUCHAR String 187 | ) { 188 | 189 | for (UINT16 cx = 0x04; cx > 0x00; cx--) { 190 | 191 | INT Shift = (0x08 * (cx - 1)); 192 | INT Char = (Key & (UINT32)((UINT32)0xFF << Shift)) >> Shift; 193 | 194 | if (isprint(Char)) 195 | String[cx - 1] = (UCHAR)Char; 196 | else 197 | String[cx - 1] = (UCHAR)0x2E; 198 | } 199 | } 200 | 201 | 202 | _Use_decl_annotations_ 203 | /// 204 | /// List Windows Kernel Memory Pool Tags. 205 | /// 206 | EXTERN_C VOID ListPoolTags( 207 | VOID 208 | ) { 209 | KiDebug(("List kernel memory pool tags ...\r\n")); 210 | 211 | // Get the number of processors on the system. 212 | PVOID XxKeNumberProcessors = WkiGetSymbol("KeNumberProcessors"); 213 | if (XxKeNumberProcessors == NULL) { 214 | KiDebug(("Error \"KeNumberProcessors\" symbol not found.\r\n")); 215 | return; 216 | } 217 | 218 | // Get the list of Pool tables 219 | PVOID PoolTagTables = WkiGetSymbol("ExPoolTagTables"); 220 | if (PoolTagTables == NULL) { 221 | KiDebug(("Error \"ExPoolTagTables\" symbol not found.\r\n")); 222 | return; 223 | } 224 | 225 | // Get the pointer to the size of the kernel pool table. 226 | PVOID XxPoolTrackTableSize = WkiGetSymbol("PoolTrackTableSize"); 227 | if (XxPoolTrackTableSize == NULL) { 228 | KiDebug(("Error \"PoolTrackTableSize\" symbol not found.\r\n")); 229 | return; 230 | } 231 | 232 | // Get the pool block shift if any 233 | PVOID XxExpPoolBlockShift = WkiGetSymbol("ExpPoolBlockShift"); 234 | 235 | // Get pool table expansion 236 | PVOID XxPoolTrackTableExpansion = WkiGetSymbol("PoolTrackTableExpansion"); 237 | PVOID XxPoolTrackTableExpansionSize = WkiGetSymbol("PoolTrackTableExpansionSize"); 238 | 239 | // Prepare all local stack variables required 240 | UINT64 PoolTableEntries = 0x01; 241 | if (XxKeNumberProcessors != NULL) 242 | PoolTableEntries = WkiReadValue(XxKeNumberProcessors, sizeof(UINT32)); 243 | 244 | UINT64 PoolBlockShift = 0x00; 245 | if (XxExpPoolBlockShift != NULL) 246 | PoolBlockShift = WkiReadValue(XxExpPoolBlockShift, sizeof(UINT64)); 247 | 248 | UINT64 TrackTableExpansionEntries = 0x00; 249 | if (XxPoolTrackTableExpansionSize != NULL) 250 | TrackTableExpansionEntries = WkiReadValue(XxPoolTrackTableExpansionSize, sizeof(UINT64)); 251 | 252 | PPOOL_TRACKER_TABLE TrackTableExpansion = NULL; 253 | if (XxPoolTrackTableExpansion != NULL) 254 | TrackTableExpansion = (PVOID)WkiReadValue(XxPoolTrackTableExpansion, sizeof(UINT64)); 255 | 256 | UINT64 TrackTableEntries = WkiReadValue(XxPoolTrackTableSize, sizeof(UINT64)); 257 | 258 | // Allocate memory to store all the data in order to filter the result. 259 | PPOOL_TRACKER_TABLE PoolTags = ExAllocatePool2( 260 | POOL_FLAG_NON_PAGED, 261 | ((TrackTableEntries + TrackTableExpansionEntries) * sizeof(POOL_TRACKER_TABLE)), 262 | WKI_MM_TAG 263 | ); 264 | if (PoolTags == NULL) 265 | return; 266 | 267 | // Parse all tracker entries 268 | UINT64 ValidEntries = 0x00; 269 | for (UINT64 cx = 0x00; cx < TrackTableEntries; cx++) { 270 | 271 | BOOLEAN Valid = TRUE; 272 | for (UINT64 dx = 0x00; dx < PoolTableEntries; dx++) { 273 | 274 | // Get proper tracker table 275 | PPOOL_TRACKER_TABLE TrackerTable = (PVOID)WkiReadValue(((PUCHAR)PoolTagTables + (0x8 * dx)), sizeof(PPOOL_TRACKER_TABLE)); 276 | if (TrackerTable == NULL) 277 | continue; 278 | 279 | if (TrackerTable[cx].Key == 0x00) 280 | continue; 281 | 282 | PoolTags[cx].NonPagedAllocs += TrackerTable[cx].NonPagedAllocs; 283 | PoolTags[cx].NonPagedFrees += TrackerTable[cx].NonPagedFrees; 284 | PoolTags[cx].NonPagedBytes += TrackerTable[cx].NonPagedBytes; 285 | PoolTags[cx].PagedAllocs += TrackerTable[cx].PagedAllocs; 286 | PoolTags[cx].PagedFrees += TrackerTable[cx].PagedFrees; 287 | PoolTags[cx].PagedBytes += TrackerTable[cx].PagedBytes; 288 | PoolTags[cx].Key = TrackerTable[cx].Key; 289 | 290 | if (PoolTags[cx].Key != 0x00 && Valid) { 291 | ValidEntries++; 292 | Valid = FALSE; 293 | } 294 | } 295 | } 296 | if (TrackTableExpansion != NULL) { 297 | for (UINT64 cx = 0x00; cx < TrackTableExpansionEntries; cx++) { 298 | PoolTags[ValidEntries + cx].NonPagedAllocs += TrackTableExpansion[cx].NonPagedAllocs; 299 | PoolTags[ValidEntries + cx].NonPagedFrees += TrackTableExpansion[cx].NonPagedFrees; 300 | PoolTags[ValidEntries + cx].NonPagedBytes += TrackTableExpansion[cx].NonPagedBytes; 301 | PoolTags[ValidEntries + cx].PagedAllocs += TrackTableExpansion[cx].PagedAllocs; 302 | PoolTags[ValidEntries + cx].PagedFrees += TrackTableExpansion[cx].PagedFrees; 303 | PoolTags[ValidEntries + cx].PagedBytes += TrackTableExpansion[cx].PagedBytes; 304 | PoolTags[ValidEntries + cx].Key = TrackTableExpansion[cx].Key; 305 | } 306 | } 307 | 308 | // Display all information 309 | KdPrint((" NonPaged Paged\r\n")); 310 | KdPrint((" Tag Allocs Frees Diff Used Allocs Frees Diff Used\r\n\r\n")); 311 | 312 | for (UINT64 cx = 0x00; cx < TrackTableEntries; cx++) { 313 | POOL_TRACKER_TABLE Entry = PoolTags[cx]; 314 | if (Entry.Key == 0x00) 315 | continue; 316 | 317 | UCHAR KeyString[sizeof(UINT64)] = { 0x00 }; 318 | MakePrintableString(Entry.Key, KeyString); 319 | 320 | KdPrint((" %s %11I64u %11I64u %9I64u %12I64d %11I64u %11I64u %9I64u %12I64d\r\n", 321 | KeyString, 322 | Entry.NonPagedAllocs, 323 | Entry.NonPagedFrees, 324 | (Entry.NonPagedAllocs - Entry.NonPagedFrees), 325 | Entry.NonPagedBytes, 326 | Entry.PagedAllocs, 327 | Entry.PagedFrees, 328 | (Entry.PagedAllocs - Entry.PagedFrees), 329 | Entry.PagedBytes 330 | )); 331 | } 332 | 333 | // Cleanup 334 | ExFreePoolWithTag(PoolTags, WKI_MM_TAG); 335 | KiDebug(("List kernel memory pool tags ... ok\r\n")); 336 | KiDebug(("-----------------------------------------------\r\n")); 337 | } -------------------------------------------------------------------------------- /WKI/WKIKM/wki/wki.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: wki.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wspe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Windows Kernel Introspection (WKI). 9 | 10 | ================================================================================================+*/ 11 | 12 | #ifndef __WKI_H_GUARD__ 13 | #define __WKI_H_GUARD__ 14 | 15 | #ifndef _NTIFS_ 16 | #include 17 | #endif // !_NTIFS_ 18 | #ifndef _NTSTRSAFE_H_INCLUDED_ 19 | #include 20 | #endif // !_NTSTRSAFE_H_INCLUDED_ 21 | #ifndef _AUX_KLIB_H 22 | #include 23 | #endif // !_AUX_KLIB_H 24 | 25 | 26 | // Windows Kernel Introspection (WKI) Memory Pool Tag - "Wki ". 27 | #define WKI_MM_TAG (ULONG)0x20696b57 28 | 29 | // Name of the Windows Registry key that store the current OS version. 30 | #define WKI_CURRENTVERSION_KEY_NAME L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" 31 | 32 | // Name of the Windows Registry key that store all the WKI information. 33 | #define WKI_KINTROSPECTION_KEY_NAME L"\\Registry\\Machine\\SOFTWARE\\WKI" 34 | 35 | 36 | /// 37 | /// Structure representing a symbol. 38 | /// 39 | typedef struct _WKI_SYMBOL_ENTRY { 40 | LIST_ENTRY List; 41 | 42 | struct { 43 | UINT32 DJB; 44 | UINT32 OFF; 45 | UINT32 RVA; 46 | UINT32 SEG; 47 | } Body; 48 | } WKI_SYMBOL_ENTRY, *PWKI_SYMBOL_ENTRY; 49 | 50 | 51 | /// 52 | /// Global data used internally by WKI. 53 | /// 54 | typedef struct _WKI_GLOBALS { 55 | UINT32 NumberOfSymbols; 56 | UINT32 NumberOfRoutines; 57 | UINT32 NumberOfStructures; 58 | 59 | UINT64 KernelBase; 60 | 61 | LIST_ENTRY SymbolHead; 62 | LIST_ENTRY StructureHead; 63 | } WKI_GLOBALS, *PWKI_GLOBALS; 64 | 65 | 66 | /// 67 | /// 68 | /// 69 | EXTERN_C NTSTATUS 70 | _IRQL_requires_max_(APC_LEVEL) 71 | _Must_inspect_result_ 72 | _Success_(return == STATUS_SUCCESS) 73 | WkiInitialise(); 74 | 75 | 76 | /// 77 | /// 78 | /// 79 | EXTERN_C VOID 80 | _IRQL_requires_max_(APC_LEVEL) 81 | WkiUninitialise(); 82 | 83 | 84 | /// 85 | /// 86 | /// 87 | /// 88 | /// 89 | EXTERN_C PVOID 90 | _IRQL_requires_max_(APC_LEVEL) 91 | _Must_inspect_result_ 92 | _Success_(return != NULL) 93 | WkiGetSymbol( 94 | _In_ LPCSTR SymbolName 95 | ); 96 | 97 | 98 | EXTERN_C UINT64 99 | _IRQL_requires_max_(APC_LEVEL) 100 | _Must_inspect_result_ 101 | _Success_(return != 0x00) 102 | WkiReadValue( 103 | _In_ PVOID Address, 104 | _In_ UINT16 Size 105 | ); 106 | 107 | // Global Windows Kernel Introspection (WKI) Data. 108 | extern WKI_GLOBALS WkiGlobal; 109 | 110 | #endif // !__WKI_H_GUARD__ 111 | -------------------------------------------------------------------------------- /WKI/WKIUM/WKIUM.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {5e103710-74ad-495f-9a72-c69573df2d2a} 25 | KernelIntrospectionUM 26 | 10.0 27 | WKIUM 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | wkium 76 | 77 | 78 | 79 | Level3 80 | true 81 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 82 | true 83 | 84 | 85 | Console 86 | true 87 | 88 | 89 | 90 | 91 | Level3 92 | true 93 | true 94 | true 95 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 96 | true 97 | 98 | 99 | Console 100 | true 101 | true 102 | true 103 | 104 | 105 | 106 | 107 | Level3 108 | true 109 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | true 111 | MultiThreadedDebug 112 | 113 | 114 | Console 115 | true 116 | %(AdditionalDependencies) 117 | 118 | 119 | false 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Level3 129 | true 130 | true 131 | true 132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | 135 | 136 | Console 137 | true 138 | true 139 | true 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /WKI/WKIUM/WKIUM.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /WKI/WKIUM/callback.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: callback.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Abstraction of the Microsoft Debug Interface Access (DIA) SDK. 9 | 10 | In this case this module contains the code for the CCallback COM interface implementation when loading PDB from 11 | a PE EXE file. 12 | 13 | Documentation available at: https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/debug-interface-access-sdk 14 | Most of the code is based on the Dia2Dump code sample shipped with the MS DIA SDK. 15 | ================================================================================================+*/ 16 | 17 | #include 18 | #include 19 | 20 | #include "inc/callback.h" 21 | 22 | // 4688a074-5a4d-4486-aea8-7b90711d9f7c 23 | CONST IID IID_IDiaLoadCallback2 = { 24 | 0x4688a074, 0x5a4d, 0x4486, { 0xae, 0xa8, 0x7b, 0x90, 0x71, 0x1d, 0x9f, 0x7c } 25 | }; 26 | 27 | // C32ADB82-73F4-421b-95D5-A4706EDF5DBE 28 | CONST IID IID_IDiaLoadCallback = { 29 | 0xC32ADB82, 0x73F4, 0x421b, { 0x95, 0xD5, 0xA4, 0x70, 0x6E, 0xDF, 0x5D, 0xBE } 30 | }; 31 | 32 | // Global handle variable used to allocate/free executable heap memory. 33 | HANDLE g_HeapHandle = INVALID_HANDLE_VALUE; 34 | 35 | 36 | HRESULT STDMETHODCALLTYPE QueryInterface( 37 | IDiaLoadCallback2* This, 38 | REFIID rid, 39 | PVOID* ppUnk 40 | ) { 41 | if (ppUnk == NULL) { 42 | return E_INVALIDARG; 43 | } 44 | 45 | if (IsEqualIID(rid, &IID_IDiaLoadCallback2)) 46 | *ppUnk = (IDiaLoadCallback2*)This; 47 | else if (IsEqualIID(rid, &IID_IDiaLoadCallback)) 48 | *ppUnk = (IDiaLoadCallback*)This; 49 | else if (IsEqualIID(rid, &IID_IUnknown)) 50 | *ppUnk = (IUnknown*)This; 51 | else 52 | *ppUnk = NULL; 53 | if (*ppUnk != NULL) { 54 | This->lpVtbl->AddRef(This); 55 | return S_OK; 56 | } 57 | return E_NOINTERFACE; 58 | } 59 | 60 | ULONG STDMETHODCALLTYPE AddRef( 61 | IDiaLoadCallback2* This 62 | ) { 63 | DiaCallback* Callback = (DiaCallback*)This; 64 | return ++Callback->m_nRefCount; 65 | } 66 | 67 | ULONG STDMETHODCALLTYPE Release( 68 | IDiaLoadCallback2* This 69 | ) { 70 | DiaCallback* Callback = (DiaCallback*)This; 71 | 72 | if ((--Callback->m_nRefCount) == 0) { 73 | DiaCallbackHelper(FALSE, (PVOID)&This); 74 | return 0x00; 75 | } 76 | return Callback->m_nRefCount; 77 | } 78 | 79 | HRESULT STDMETHODCALLTYPE NotifyDebugDir( 80 | IDiaLoadCallback2* This, 81 | BOOL fExecutable, 82 | DWORD cbData, 83 | BYTE data[] 84 | ) { 85 | return S_OK; 86 | } 87 | 88 | HRESULT STDMETHODCALLTYPE NotifyOpenDBG( 89 | IDiaLoadCallback2* This, 90 | LPCOLESTR dbgPath, 91 | HRESULT resultCode 92 | ) { 93 | return S_OK; 94 | } 95 | 96 | HRESULT STDMETHODCALLTYPE NotifyOpenPDB( 97 | IDiaLoadCallback2* This, 98 | LPCOLESTR pdbPath, 99 | HRESULT resultCode 100 | ) { 101 | if (SUCCEEDED(resultCode)) { 102 | wprintf(L"[*] Open: %s\r\n", pdbPath); 103 | } 104 | return S_OK; 105 | } 106 | 107 | HRESULT STDMETHODCALLTYPE RestrictRegistryAccess( 108 | IDiaLoadCallback2* This 109 | ) { 110 | // return hr != S_OK to prevent querying the registry for symbol search paths 111 | return S_OK; 112 | } 113 | 114 | HRESULT STDMETHODCALLTYPE RestrictSymbolServerAccess( 115 | IDiaLoadCallback2* This 116 | ) { 117 | // return hr != S_OK to prevent accessing a symbol server 118 | return S_OK; 119 | } 120 | 121 | HRESULT STDMETHODCALLTYPE RestrictOriginalPathAccess( 122 | IDiaLoadCallback2* This 123 | ) { 124 | // return hr != S_OK to prevent querying the registry for symbol search paths 125 | return S_OK; 126 | } 127 | 128 | HRESULT STDMETHODCALLTYPE RestrictReferencePathAccess( 129 | IDiaLoadCallback2* This 130 | ) { 131 | // return hr != S_OK to prevent accessing a symbol server 132 | return S_OK; 133 | } 134 | 135 | HRESULT STDMETHODCALLTYPE RestrictDBGAccess( 136 | IDiaLoadCallback2* This 137 | ) { 138 | return S_OK; 139 | } 140 | 141 | HRESULT STDMETHODCALLTYPE RestrictSystemRootAccess( 142 | IDiaLoadCallback2* This 143 | ) { 144 | return S_OK; 145 | } 146 | 147 | 148 | /// 149 | /// Callback virtual table. 150 | /// 151 | static CONST IDiaLoadCallback2Vtbl CallbackVirtualTable = { 152 | // IUnknown 153 | QueryInterface, 154 | AddRef, 155 | Release, 156 | 157 | // IDiaLoadCallback 158 | NotifyDebugDir, 159 | NotifyOpenDBG, 160 | NotifyOpenPDB, 161 | RestrictRegistryAccess, 162 | RestrictSymbolServerAccess, 163 | 164 | // IDiaLoadCallback2 165 | RestrictOriginalPathAccess, 166 | RestrictReferencePathAccess, 167 | RestrictDBGAccess, 168 | RestrictSystemRootAccess 169 | }; 170 | 171 | 172 | _Use_decl_annotations_ 173 | HRESULT STDMETHODCALLTYPE DiaCallbackHelper( 174 | _In_ BOOLEAN Initialise, 175 | _Inout_ PVOID** Callback 176 | ) { 177 | if (Callback == NULL) 178 | return E_FAIL; 179 | 180 | // Create the structure for the callback 181 | if (Initialise) { 182 | if (g_HeapHandle != INVALID_HANDLE_VALUE) 183 | return E_FAIL; 184 | 185 | // Create executable heap 186 | g_HeapHandle = HeapCreate( 187 | HEAP_CREATE_ENABLE_EXECUTE, 188 | sizeof(IDiaLoadCallback2Vtbl) + sizeof(DiaCallback), 189 | 0x1000 190 | ); 191 | if (g_HeapHandle == INVALID_HANDLE_VALUE) 192 | return E_FAIL; 193 | 194 | // Allocate memory in the new heap 195 | DiaCallback* Buffer = HeapAlloc(g_HeapHandle, HEAP_ZERO_MEMORY, sizeof(DiaCallback) + sizeof(IDiaLoadCallback2Vtbl)); 196 | if (Buffer == NULL) { 197 | HeapDestroy(g_HeapHandle); 198 | return E_FAIL; 199 | } 200 | 201 | PVOID cstruct = HeapAlloc(g_HeapHandle, HEAP_ZERO_MEMORY, sizeof(DiaCallback));; 202 | PVOID vtable = NULL; 203 | 204 | 205 | // Assemble everything 206 | Buffer->m_nRefCount = 0x00; 207 | Buffer->lpVtbl = (IDiaLoadCallback2*)&CallbackVirtualTable; 208 | 209 | *Callback = (PVOID)Buffer; 210 | return S_OK; 211 | } 212 | // Delete the structure for the callback 213 | else { 214 | if (g_HeapHandle == INVALID_HANDLE_VALUE || Callback == NULL) 215 | return E_FAIL; 216 | 217 | // Check that the reference count is zero 218 | DiaCallback* src = (DiaCallback*)*Callback; 219 | if (src->m_nRefCount != 0x00) 220 | return E_FAIL; 221 | 222 | // Free the memory and destroy the executable heap 223 | HeapFree(g_HeapHandle, 0x00, src); 224 | HeapDestroy(g_HeapHandle); 225 | g_HeapHandle = INVALID_HANDLE_VALUE; 226 | } 227 | 228 | return E_FAIL; 229 | } -------------------------------------------------------------------------------- /WKI/WKIUM/dirutil.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: dirutil.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Windows Directory utility code. 9 | Used to change directory to the "PDB" folder and get the correct symbol server search path. 10 | 11 | ================================================================================================+*/ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "inc/dirutil.h" 18 | 19 | 20 | _Use_decl_annotations_ 21 | NTSTATUS GetSymSrvSearchPath( 22 | _Out_ PWCHAR* SymSearchPath 23 | ) { 24 | // Get the current path 25 | PWSTR DefaultDirectory[MAX_PATH] = { 0x00 }; 26 | DWORD dwCurrentDirectory = GetCurrentDirectoryW(MAX_PATH, (LPWSTR)DefaultDirectory); 27 | if (dwCurrentDirectory == 0x00) 28 | return E_FAIL; 29 | 30 | // Other local Stack Variables 31 | CONST PWCHAR Pdb = L"pdb"; 32 | CONST PWCHAR Sym = L"symsrv"; 33 | CONST PWCHAR Dll = L"symsrv.dll"; 34 | CONST PWCHAR Web = L"https://msdl.microsoft.com/download/symbols"; 35 | 36 | // Calculate the size of the buffer to allocate 37 | DWORD dwBuffer = 0x100; 38 | DWORD dwSize = lstrlenW(Pdb) + lstrlenW(Sym) + lstrlenW(Dll) + lstrlenW(Web) + (sizeof(WCHAR) * 4) + lstrlenW((LPWSTR)DefaultDirectory); 39 | while (dwBuffer < dwSize) 40 | dwBuffer += 0x100; 41 | 42 | PWCHAR Out = calloc(1, dwBuffer); 43 | if (Out == NULL) { 44 | *SymSearchPath = NULL; 45 | return E_OUTOFMEMORY; 46 | } 47 | 48 | // Assemble the whole string now 49 | HRESULT Result = StringCbPrintfW( 50 | Out, 51 | dwBuffer, 52 | L"%s*%s*%s\\%s*%s\0", 53 | Sym, 54 | Dll, 55 | (LPWSTR)DefaultDirectory, 56 | Pdb, 57 | Web 58 | ); 59 | if (FAILED(Result)) { 60 | free(Out); 61 | *SymSearchPath = NULL; 62 | return E_FAIL; 63 | } 64 | 65 | *SymSearchPath = Out; 66 | return S_OK; 67 | } 68 | -------------------------------------------------------------------------------- /WKI/WKIUM/inc/callback.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: callback.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Abstraction of the Microsoft Debug Interface Access (DIA) SDK. 9 | 10 | In this case this module contains the code for the CCallback COM interface implementation when loading PDB from 11 | a PE EXE file. 12 | 13 | Documentation available at: https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/debug-interface-access-sdk 14 | Most of the code is based on the Dia2Dump code sample shipped with the MS DIA SDK. 15 | ================================================================================================+*/ 16 | 17 | #ifndef __DIA_CALLBACK_H_GUARD__ 18 | #define __DIA_CALLBACK_H_GUARD__ 19 | 20 | #include 21 | 22 | #include "msdia/inlcude/dia2.h" 23 | 24 | typedef struct DiaCallback { 25 | 26 | // Virtual Table for the callback 27 | CONST_VTBL struct IDiaLoadCallback2* lpVtbl; 28 | 29 | // Reference counter for the AddRef/Release methods 30 | int m_nRefCount; 31 | } DiaCallback; 32 | 33 | /// 34 | /// Dynamically create the callback COM object used by DIA. 35 | /// 36 | HRESULT STDMETHODCALLTYPE 37 | _Must_inspect_result_ 38 | _Success_(return == S_OK) 39 | DiaCallbackHelper( 40 | _In_ BOOLEAN Initialise, 41 | _Inout_ PVOID * *Callback 42 | ); 43 | 44 | #endif // !__DIA_CALLBACK_H_GUARD__ -------------------------------------------------------------------------------- /WKI/WKIUM/inc/dirutil.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: dirutil.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Windows Directory utility code. 9 | Used to change directory to the "PDB" folder and get the correct symbol server search path. 10 | ================================================================================================+*/ 11 | 12 | #ifndef __DIA_DIRUTIL_H_GUARD__ 13 | #define __DIA_DIRUTIL_H_GUARD__ 14 | 15 | #include 16 | 17 | /// 18 | /// Utility function to get the proper symbol server address to download PDB. 19 | /// 20 | NTSTATUS STDMETHODCALLTYPE 21 | _Must_inspect_result_ 22 | GetSymSrvSearchPath( 23 | _Out_ PWCHAR* SymSearchPath 24 | ); 25 | 26 | #endif // !__DIA_DIRUTIL_H_GUARD__ 27 | -------------------------------------------------------------------------------- /WKI/WKIUM/inc/interface.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: interface.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Abstraction of the Microsoft Debug Interface Access (DIA) SDK. 9 | 10 | Documentation available at: https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/debug-interface-access-sdk 11 | Most of the code is based on the Dia2Dump code sample shipped with the MS DIA SDK. 12 | ================================================================================================+*/ 13 | 14 | #ifndef __DIA_INTERFACE_H_GUARD__ 15 | #define __DIA_INTERFACE_H_GUARD__ 16 | 17 | #include 18 | 19 | #include "msdia/inlcude/dia2.h" 20 | #include "msdia/inlcude/cvconst.h" 21 | 22 | #include "callback.h" 23 | #include "dirutil.h" 24 | 25 | // Type definition of the "DllGetClassObject" routine from the msdiaXXX.dll module. 26 | typedef HRESULT(STDMETHODCALLTYPE* TDllGetClassObject)( 27 | _In_ REFCLSID rclsid, 28 | _In_ REFIID riid, 29 | _Out_ LPVOID* ppv 30 | ); 31 | 32 | /// 33 | /// Simple structure to store all the information 34 | /// 35 | typedef struct _PUBLIC_SYMBOL { 36 | DWORD dwTag; 37 | DWORD dwRVA; 38 | DWORD dwOff; 39 | DWORD dwSeg; 40 | BSTR Name; 41 | } PUBLIC_SYMBOL, * PPUBLIC_SYMBOL; 42 | 43 | 44 | /// 45 | /// Initialise the COM runtime and IDiaDataSource interface. 46 | /// 47 | HRESULT STDMETHODCALLTYPE 48 | _Must_inspect_result_ 49 | _Success_(return == S_OK) 50 | DiaInitialise( 51 | _In_ PWCHAR DllName 52 | ); 53 | 54 | 55 | /// 56 | /// Uninitialise the COM runtime and general cleanup. 57 | /// 58 | VOID STDMETHODCALLTYPE DiaUninitialise(); 59 | 60 | 61 | /// 62 | /// Load the data from the PDB file provided. 63 | /// 64 | HRESULT STDMETHODCALLTYPE 65 | _Must_inspect_result_ 66 | _Success_(return == S_OK) 67 | DiaLoadDataFromPdb( 68 | _In_ PWCHAR FilePath 69 | ); 70 | 71 | 72 | /// 73 | /// Parse the PDB file to find all symbols requested. 74 | /// 75 | HRESULT STDMETHODCALLTYPE 76 | _Must_inspect_result_ 77 | _Success_(return == S_OK) 78 | DiaFindPublicSymbols( 79 | _In_ PUBLIC_SYMBOL PublicSymbols[], 80 | _In_ DWORD Elements 81 | ); 82 | 83 | #endif // !__DIA_INTERFACE_H_GUARD__ -------------------------------------------------------------------------------- /WKI/WKIUM/inc/msdia/inlcude/diacreate.h: -------------------------------------------------------------------------------- 1 | // diacreate.h - creation helper functions for DIA initialization 2 | //----------------------------------------------------------------- 3 | // 4 | // Copyright Microsoft Corporation. All Rights Reserved. 5 | // 6 | //--------------------------------------------------------------- 7 | #ifndef _DIACREATE_H_ 8 | #define _DIACREATE_H_ 9 | 10 | // 11 | // Create a dia data source object from the dia dll (by dll name - does not access the registry). 12 | // 13 | 14 | HRESULT STDMETHODCALLTYPE NoRegCoCreate(const __wchar_t* dllName, 15 | REFCLSID rclsid, 16 | REFIID riid, 17 | void** ppv); 18 | 19 | #ifndef _NATIVE_WCHAR_T_DEFINED 20 | #ifdef __cplusplus 21 | 22 | HRESULT STDMETHODCALLTYPE NoRegCoCreate(const wchar_t* dllName, 23 | REFCLSID rclsid, 24 | REFIID riid, 25 | void** ppv) 26 | { 27 | return NoRegCoCreate((const __wchar_t*)dllName, rclsid, riid, ppv); 28 | } 29 | 30 | #endif 31 | #endif 32 | 33 | 34 | 35 | // 36 | // Create a dia data source object from the dia dll (looks up the class id in the registry). 37 | // 38 | HRESULT STDMETHODCALLTYPE NoOleCoCreate(REFCLSID rclsid, 39 | REFIID riid, 40 | void** ppv); 41 | 42 | #endif -------------------------------------------------------------------------------- /WKI/WKIUM/inc/registry.h: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: registry.h 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Windows Registry related routines. Used to create and store symbols for access from the kernel driver. 9 | ================================================================================================+*/ 10 | 11 | #ifndef __KI_REGISTRY_H_GUARD__ 12 | #define __KI_REGISTRY_H_GUARD__ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "interface.h" 19 | 20 | // Base registry key 21 | #define REGISTRY_BASE_KEY L"SOFTWARE\\WKI" 22 | 23 | #define REGISTRY_ROUTINES_KEY L"Routines" 24 | #define REGISTRY_SYMBOLS_KEY L"Symbols" 25 | #define REGISTRY_STRUCTS_KEY L"Structs" 26 | 27 | // Dodgy macro to make the code less bloated 28 | #define RtlCreateOrOpenKey(Status, hKey, SubKey, hResult) \ 29 | Status = RegCreateKeyExW(hKey, SubKey, 0x00, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, hResult, NULL); \ 30 | if (Status != ERROR_SUCCESS) { RtlGetErrorMessageW((DWORD)Status); RegistryUninitialise(); return E_FAIL; } 31 | 32 | /// 33 | /// Get OS Build number and initialise Windows Registry keys. 34 | /// 35 | HRESULT STDMETHODCALLTYPE 36 | _Must_inspect_result_ 37 | _Success_(return == S_OK) RegistryInitialise( 38 | VOID 39 | ); 40 | 41 | 42 | /// 43 | /// Internal cleanup of all handles and memory. 44 | /// 45 | VOID STDMETHODCALLTYPE RegistryUninitialise( 46 | VOID 47 | ); 48 | 49 | 50 | /// 51 | /// Add symbols to the windows registry. 52 | /// 53 | HRESULT STDMETHODCALLTYPE RegistryAddSymbols( 54 | _In_ PUBLIC_SYMBOL Symbols[], 55 | _In_ DWORD Entries 56 | ); 57 | 58 | #endif // !__KI_REGISTRY_H_GUARD__ 59 | -------------------------------------------------------------------------------- /WKI/WKIUM/interface.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: interface.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Abstraction of the Microsoft Debug Interface Access (DIA) SDK. 9 | 10 | Documentation available at: https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/debug-interface-access-sdk 11 | Most of the code is based on the Dia2Dump code sample shipped with the MS DIA SDK. 12 | ================================================================================================+*/ 13 | 14 | #include 15 | #include 16 | 17 | #include "inc/interface.h" 18 | 19 | // e6756135-1e65-4d17-8576-610761398c3c 20 | CONST CLSID CLSID_DiaSource = { 21 | 0xe6756135, 0x1e65, 0x4d17, { 0x85, 0x76, 0x61, 0x07, 0x61, 0x39, 0x8c, 0x3c } 22 | }; 23 | 24 | // 79F1BB5F-B66E-48e5-B6A9-1545C323CA3D 25 | CONST IID IID_IDiaDataSource = { 26 | 0x79F1BB5F, 0xB66E, 0x48e5, { 0xB6, 0xA9, 0x15, 0x45, 0xC3, 0x23, 0xCA, 0x3D } 27 | }; 28 | 29 | // Global Data Source COM interface 30 | IDiaDataSource* g_DataSource = NULL; 31 | 32 | // Global Session COM interface 33 | IDiaSession* g_Session = NULL; 34 | 35 | // Global Symbol COM interface 36 | IDiaSymbol* g_GlobalSymbol = NULL; 37 | 38 | // Global Callback COM interface 39 | IDiaLoadCallback2* g_Callback = NULL; 40 | 41 | 42 | // Tags returned by Dia 43 | const wchar_t* const rgTags[] = { 44 | L"(SymTagNull)", // SymTagNull 45 | L"Executable (Global)", // SymTagExe 46 | L"Compiland", // SymTagCompiland 47 | L"CompilandDetails", // SymTagCompilandDetails 48 | L"CompilandEnv", // SymTagCompilandEnv 49 | L"Function", // SymTagFunction 50 | L"Block", // SymTagBlock 51 | L"Data", // SymTagData 52 | L"Annotation", // SymTagAnnotation 53 | L"Label", // SymTagLabel 54 | L"PublicSymbol", // SymTagPublicSymbol 55 | L"UserDefinedType", // SymTagUDT 56 | L"Enum", // SymTagEnum 57 | L"FunctionType", // SymTagFunctionType 58 | L"PointerType", // SymTagPointerType 59 | L"ArrayType", // SymTagArrayType 60 | L"BaseType", // SymTagBaseType 61 | L"Typedef", // SymTagTypedef 62 | L"BaseClass", // SymTagBaseClass 63 | L"Friend", // SymTagFriend 64 | L"FunctionArgType", // SymTagFunctionArgType 65 | L"FuncDebugStart", // SymTagFuncDebugStart 66 | L"FuncDebugEnd", // SymTagFuncDebugEnd 67 | L"UsingNamespace", // SymTagUsingNamespace 68 | L"VTableShape", // SymTagVTableShape 69 | L"VTable", // SymTagVTable 70 | L"Custom", // SymTagCustom 71 | L"Thunk", // SymTagThunk 72 | L"CustomType", // SymTagCustomType 73 | L"ManagedType", // SymTagManagedType 74 | L"Dimension", // SymTagDimension 75 | L"CallSite", // SymTagCallSite 76 | L"InlineSite", // SymTagInlineSite 77 | L"BaseInterface", // SymTagBaseInterface 78 | L"VectorType", // SymTagVectorType 79 | L"MatrixType", // SymTagMatrixType 80 | L"HLSLType", // SymTagHLSLType 81 | L"Caller", // SymTagCaller, 82 | L"Callee", // SymTagCallee, 83 | L"Export", // SymTagExport, 84 | L"HeapAllocationSite", // SymTagHeapAllocationSite 85 | L"CoffGroup", // SymTagCoffGroup 86 | L"Inlinee", // SymTagInlinee 87 | }; 88 | 89 | 90 | _Use_decl_annotations_ 91 | HRESULT STDMETHODCALLTYPE DiaInitialise( 92 | _In_ PWCHAR DllName 93 | ) { 94 | // Check if already initialised 95 | HRESULT Result = S_OK; 96 | if (g_DataSource != NULL) 97 | return Result; 98 | 99 | // Initialise COM runtime 100 | if (!SUCCEEDED(CoInitialize(NULL))) 101 | return E_FAIL; 102 | 103 | // Load the module 104 | HMODULE hModule = LoadLibraryExW(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 105 | if (hModule == NULL) 106 | return E_FAIL; 107 | 108 | // Get exported routine 109 | TDllGetClassObject DllGetClassObject = (TDllGetClassObject)GetProcAddress(hModule, "DllGetClassObject"); 110 | if (DllGetClassObject == NULL) 111 | return GetLastError(); 112 | 113 | // Create Instance of the IDiaDataSource COM interface 114 | IClassFactory* ClassFactory = NULL; 115 | if (SUCCEEDED(DllGetClassObject(&CLSID_DiaSource, &IID_IClassFactory, (LPVOID*)&ClassFactory))) { 116 | Result = ClassFactory->lpVtbl->CreateInstance(ClassFactory, NULL, &IID_IDiaDataSource, &g_DataSource); 117 | if (SUCCEEDED(Result)) 118 | ClassFactory->lpVtbl->AddRef(ClassFactory); 119 | return Result; 120 | } 121 | else { 122 | HRESULT Result = GetLastError(); 123 | if (Result > 0x00) 124 | Result |= REASON_LEGACY_API; 125 | return Result; 126 | } 127 | } 128 | 129 | 130 | _Use_decl_annotations_ 131 | VOID STDMETHODCALLTYPE DiaUninitialise() { 132 | if (g_GlobalSymbol != NULL) { 133 | g_GlobalSymbol->lpVtbl->Release(g_GlobalSymbol); 134 | g_GlobalSymbol = NULL; 135 | } 136 | 137 | if (g_Session != NULL) { 138 | g_Session->lpVtbl->Release(g_Session); 139 | g_Session = NULL; 140 | } 141 | 142 | if (g_DataSource != NULL) { 143 | g_DataSource->lpVtbl->Release(g_DataSource); 144 | g_DataSource = NULL; 145 | } 146 | 147 | if (g_Callback != NULL) { 148 | g_Callback->lpVtbl->Release(g_Callback); 149 | g_Callback = NULL; 150 | } 151 | 152 | CoUninitialize(); 153 | } 154 | 155 | 156 | _Use_decl_annotations_ 157 | HRESULT STDMETHODCALLTYPE DiaLoadDataFromPdb( 158 | _In_ PWCHAR FilePath 159 | ) { 160 | // Check if already initialised 161 | if (g_DataSource == NULL) 162 | return E_FAIL; 163 | HRESULT Result = S_OK; 164 | 165 | // Extract the file extension from the path 166 | PWCHAR FileExtension = calloc(1, MAX_PATH * sizeof(WCHAR)); 167 | if (FileExtension == NULL) 168 | return E_OUTOFMEMORY; 169 | _wsplitpath_s(FilePath, NULL, 0, NULL, 0, NULL, 0, FileExtension, MAX_PATH); 170 | 171 | // File is a ".PDB" 172 | if (!_wcsicmp(FileExtension, L".pdb")) { 173 | free(FileExtension); 174 | 175 | Result = g_DataSource->lpVtbl->loadDataFromPdb(g_DataSource, FilePath); 176 | if (FAILED(Result)) { 177 | wprintf(L"[-] Failed to load data from the PDB file (%08X).\r\n", Result); 178 | return Result; 179 | } 180 | } 181 | // File is a ".EXE" 182 | else if (!_wcsicmp(FileExtension, L".exe")) { 183 | free(FileExtension); 184 | 185 | // Create the callback COM implementation 186 | if (FAILED(DiaCallbackHelper(TRUE, (PVOID)&g_Callback))) { 187 | wprintf(L"[-] Failed to create the DIA Callback.\r\n"); 188 | return E_FAIL; 189 | } 190 | g_Callback->lpVtbl->AddRef(g_Callback); 191 | 192 | // Forge the Symbol search path 193 | PWCHAR SymSearchPath = NULL; 194 | if (FAILED(GetSymSrvSearchPath(&SymSearchPath))) { 195 | g_Callback->lpVtbl->Release(g_Callback); 196 | return E_FAIL; 197 | } 198 | 199 | // Load the PDB from Microsoft symbol server 200 | Result = g_DataSource->lpVtbl->loadDataForExe( 201 | g_DataSource, 202 | FilePath, 203 | SymSearchPath, 204 | (PVOID)g_Callback 205 | ); 206 | 207 | free(SymSearchPath); 208 | if (FAILED(Result)) { 209 | wprintf(L"[-] Failed to load PDB file (%08X).\r\n", Result); 210 | g_Callback->lpVtbl->Release(g_Callback); 211 | return Result; 212 | } 213 | } 214 | 215 | // Open session to access symbols 216 | Result = g_DataSource->lpVtbl->openSession(g_DataSource, &g_Session); 217 | if (FAILED(Result)) { 218 | wprintf(L"[-] Failed to open session (%08X).\r\n", Result); 219 | return Result; 220 | } 221 | 222 | // Get the global scope 223 | Result = g_Session->lpVtbl->get_globalScope(g_Session, &g_GlobalSymbol); 224 | if (FAILED(Result)) { 225 | wprintf(L"[-] Failed to get global scope (%08X).\r\n", Result); 226 | return Result; 227 | } 228 | 229 | return Result; 230 | } 231 | 232 | 233 | _Use_decl_annotations_ 234 | HRESULT STDMETHODCALLTYPE DiaFindPublicSymbols( 235 | _In_ PUBLIC_SYMBOL PublicSymbols[], 236 | _In_ DWORD Elements 237 | ) { 238 | // Check if everything has been properly initialised. 239 | if (g_DataSource == NULL || g_Session == NULL || g_GlobalSymbol == NULL) 240 | return E_FAIL; 241 | 242 | // Enumerates the various symbols contained in the data source. 243 | IDiaEnumSymbols* EnumSymbols = NULL; 244 | HRESULT Result = g_GlobalSymbol->lpVtbl->findChildren( 245 | g_GlobalSymbol, 246 | SymTagPublicSymbol, 247 | NULL, 248 | nsNone, 249 | &EnumSymbols 250 | ); 251 | if (FAILED(Result)) { 252 | wprintf(L"[-] Failed to load symbol enumerator (%08X).\r\n", Result); 253 | return Result; 254 | } 255 | 256 | // Parse all symbols 257 | IDiaSymbol* Symbol = NULL; 258 | ULONG celt = 0x00; 259 | while (SUCCEEDED(EnumSymbols->lpVtbl->Next(EnumSymbols, 0x01, &Symbol, &celt)) && (celt == 1)) { 260 | 261 | DWORD dwTag = 0x00; 262 | DWORD dwRVA = 0x00; 263 | DWORD dwOff = 0x00; 264 | DWORD dwSeg = 0x00; 265 | BSTR Name = NULL; 266 | 267 | // Make sure we have a tag for the symbol 268 | if (FAILED(Symbol->lpVtbl->get_symTag(Symbol, &dwTag))) 269 | goto next_symbol; 270 | 271 | // Get the name of the global variable 272 | if (SUCCEEDED(Symbol->lpVtbl->get_name(Symbol, &Name))) { 273 | 274 | // Find the symbol 275 | BOOLEAN Found = FALSE; 276 | DWORD Index = 0x00; 277 | for (DWORD cx = 0x00; cx < Elements; cx++) { 278 | if (wcscmp(PublicSymbols[cx].Name, Name) == 0x00) { 279 | Index = cx; 280 | Found = TRUE; 281 | break; 282 | } 283 | } 284 | if (!Found) 285 | goto next_symbol; 286 | 287 | // Get the Relative Virtual Address (RVA), the offset and section 288 | if (FAILED(Symbol->lpVtbl->get_relativeVirtualAddress(Symbol, &dwRVA))) 289 | dwRVA = 0xFFFFFFFF; 290 | Symbol->lpVtbl->get_addressSection(Symbol, &dwSeg); 291 | Symbol->lpVtbl->get_addressOffset(Symbol, &dwOff); 292 | 293 | PublicSymbols[Index].dwTag = dwTag; 294 | PublicSymbols[Index].dwRVA = dwRVA; 295 | PublicSymbols[Index].dwOff = dwOff; 296 | PublicSymbols[Index].dwSeg = dwSeg; 297 | 298 | // Release current interface 299 | next_symbol: 300 | Symbol->lpVtbl->Release(Symbol); 301 | } 302 | } 303 | EnumSymbols->lpVtbl->Release(EnumSymbols); 304 | return S_OK; 305 | } 306 | -------------------------------------------------------------------------------- /WKI/WKIUM/main.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: main.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Application entry point. 9 | ================================================================================================+*/ 10 | 11 | #include 12 | #include 13 | 14 | #include "inc/interface.h" 15 | #include "inc/registry.h" 16 | 17 | // Macro to make the code less bloated 18 | #define EXIT_ON_FAILURE(ex) if (!SUCCEEDED(ex)) { return EXIT_FAILURE; } 19 | 20 | // Macro to add an entry in the intenral symbol table. 21 | #define ADD_TABLE_ENTRY(str) { 0x00, 0x00, 0x00, 0x00, str } 22 | 23 | 24 | /// 25 | /// Sort the symbol table. 26 | /// 27 | VOID SortTable( 28 | _In_ PUBLIC_SYMBOL PublicSymbols[], 29 | _In_ DWORD Elements 30 | ) { 31 | // Sort with segment 32 | for (DWORD cx = 0x00; cx < (Elements - 1); cx++) { 33 | for (DWORD dx = 0x00; dx < (Elements - cx - 1); dx++) { 34 | if (PublicSymbols[dx].dwSeg > PublicSymbols[dx + 1].dwSeg) { 35 | 36 | PUBLIC_SYMBOL Temp = PublicSymbols[dx]; 37 | RtlCopyMemory(&Temp, &PublicSymbols[dx], sizeof(PUBLIC_SYMBOL)); 38 | RtlCopyMemory(&PublicSymbols[dx], &PublicSymbols[dx + 1], sizeof(PUBLIC_SYMBOL)); 39 | RtlCopyMemory(&PublicSymbols[dx + 1], &Temp, sizeof(PUBLIC_SYMBOL)); 40 | } 41 | } 42 | } 43 | 44 | // Sort with RVA 45 | for (DWORD cx = 0x00; cx < (Elements - 1); cx++) { 46 | for (DWORD dx = 0x00; dx < (Elements - cx - 1); dx++) { 47 | if (PublicSymbols[dx].dwRVA > PublicSymbols[dx + 1].dwRVA) { 48 | 49 | PUBLIC_SYMBOL Temp = PublicSymbols[dx]; 50 | RtlCopyMemory(&Temp, &PublicSymbols[dx], sizeof(PUBLIC_SYMBOL)); 51 | RtlCopyMemory(&PublicSymbols[dx], &PublicSymbols[dx + 1], sizeof(PUBLIC_SYMBOL)); 52 | RtlCopyMemory(&PublicSymbols[dx + 1], &Temp, sizeof(PUBLIC_SYMBOL)); 53 | } 54 | } 55 | } 56 | } 57 | 58 | 59 | /// 60 | /// Application Entry Point. 61 | /// 62 | INT main(VOID) { 63 | // Banner 64 | wprintf(L"=================================================================\r\n"); 65 | wprintf(L"Module Name: Windows Kernel Introspection -- UM \r\n"); 66 | wprintf(L"Author : Paul L. (@am0nsec) \r\n"); 67 | wprintf(L"Origin : https://github.com/am0nsec/wkpe/ \r\n\r\n"); 68 | wprintf(L"Tested OS : Windows 10 (20h2) - 19044.1889 \r\n"); 69 | wprintf(L"=================================================================\r\n\r\n"); 70 | 71 | // Initialise COM runtime and get IDiaDataSource interface. 72 | wprintf(L"[*] Initialise MSDIA \r\n"); 73 | EXIT_ON_FAILURE(DiaInitialise(L"msdia140.dll")); 74 | 75 | // Load the data from the PDB 76 | wprintf(L"[*] Open PDB from EXE: C:\\WINDOWS\\System32\\ntoskrnl.exe\r\n"); 77 | EXIT_ON_FAILURE(DiaLoadDataFromPdb(L"C:\\WINDOWS\\System32\\ntoskrnl.exe")); 78 | 79 | // Parse all public symbols 80 | PUBLIC_SYMBOL Symbols[] = { 81 | // Memory Manager variables 82 | ADD_TABLE_ENTRY(L"ExPoolTagTables"), 83 | ADD_TABLE_ENTRY(L"PoolTrackTableSize"), 84 | ADD_TABLE_ENTRY(L"ExpPoolBlockShift"), 85 | ADD_TABLE_ENTRY(L"PoolTrackTableExpansion"), 86 | ADD_TABLE_ENTRY(L"PoolTrackTableExpansionSize"), 87 | 88 | // General kernel info 89 | ADD_TABLE_ENTRY(L"KeNumberProcessors") 90 | }; 91 | EXIT_ON_FAILURE(DiaFindPublicSymbols(Symbols, _ARRAYSIZE(Symbols))); 92 | 93 | // Display everything to console 94 | SortTable(Symbols, _ARRAYSIZE(Symbols)); 95 | 96 | wprintf(L"\r\n"); 97 | wprintf(L"Found Segment RVA Offset Name\r\n"); 98 | wprintf(L"----- ------- --- ------ ----\r\n"); 99 | 100 | DWORD Found = 0x00; 101 | for (DWORD cx = 0x00; cx < _ARRAYSIZE(Symbols); cx++) { 102 | wprintf(L"%s %04X %08X %08X %s\r\n", 103 | Symbols[cx].dwRVA != 0x00 ? L"\033[0;32mY\033[0;37m" : L"\033[0;31mN\033[0;37m", 104 | Symbols[cx].dwSeg, 105 | Symbols[cx].dwRVA, 106 | Symbols[cx].dwOff, 107 | Symbols[cx].Name 108 | ); 109 | Found += Symbols[cx].dwRVA != 0x00 ? 1 : 0; 110 | } 111 | 112 | wprintf(L"\r\n"); 113 | wprintf(L"[*] Found: %i/%i\r\n", Found, (int)_ARRAYSIZE(Symbols)); 114 | wprintf(L"=================================================================\r\n\r\n"); 115 | 116 | // Initialise registry module 117 | RegistryInitialise(); 118 | RegistryAddSymbols(Symbols, _ARRAYSIZE(Symbols)); 119 | RegistryUninitialise(); 120 | 121 | // Uninitialise COM runtime and general cleanup 122 | DiaUninitialise(); 123 | return EXIT_SUCCESS; 124 | } -------------------------------------------------------------------------------- /WKI/WKIUM/registry.c: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: registry.c 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Windows Registry related routines. Used to create and store symbols for access from the kernel driver. 9 | ================================================================================================+*/ 10 | #include "inc/registry.h" 11 | 12 | // Handle to the base registry key 13 | HKEY g_BaseKey = INVALID_HANDLE_VALUE; 14 | 15 | // Handle to the key for the current build number 16 | HKEY g_BuilKey = INVALID_HANDLE_VALUE; 17 | 18 | // Handle to the key for the public symbols 19 | HKEY g_Symbols = INVALID_HANDLE_VALUE; 20 | 21 | // Handle to the key for the structures 22 | HKEY g_Structs = INVALID_HANDLE_VALUE; 23 | 24 | // Handle to the key for the routines 25 | HKEY g_Routines = INVALID_HANDLE_VALUE; 26 | 27 | // The OS version string 28 | WCHAR g_VersionString[0x20] = { 0x00 }; 29 | 30 | 31 | /// 32 | /// Display message related to an error message. 33 | /// 34 | /// Error id returned by GetLastError. 35 | VOID RtlGetErrorMessageW( 36 | _In_ DWORD dwError 37 | ) { 38 | WCHAR ErrorW[1024] = { 0x00 }; 39 | if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0x00, ErrorW, 1024, NULL) != 0x0) { 40 | wprintf(L"Message is \"%s\"\n", ErrorW); 41 | } 42 | else { 43 | wprintf(L"Failed! Error code %d\n", GetLastError()); 44 | } 45 | } 46 | 47 | 48 | /// 49 | /// Get the OS build number. 50 | /// 51 | HRESULT RtlGetOSVersion() { 52 | LSTATUS Status = ERROR_SUCCESS; 53 | 54 | // Get the major build version 55 | DWORD CurrentMajorVersionNumber = 0x00; 56 | DWORD CurrentMajorVersionNumberSize = sizeof(DWORD); 57 | Status = RegGetValueA( 58 | HKEY_LOCAL_MACHINE, 59 | "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 60 | "CurrentMajorVersionNumber", 61 | RRF_RT_REG_DWORD, 62 | NULL, 63 | &CurrentMajorVersionNumber, 64 | &CurrentMajorVersionNumberSize 65 | ); 66 | if (Status != ERROR_SUCCESS) { 67 | RtlGetErrorMessageW((DWORD)GetLastError()); 68 | return E_FAIL; 69 | } 70 | 71 | // Get the current build number 72 | char CurrentBuildNumber[0x10] = { 0x00 }; 73 | DWORD CurrentBuildNumberSize = ARRAYSIZE(CurrentBuildNumber); 74 | Status = RegGetValueA( 75 | HKEY_LOCAL_MACHINE, 76 | "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 77 | "CurrentBuildNumber", 78 | RRF_RT_REG_SZ, 79 | NULL, 80 | CurrentBuildNumber, 81 | &CurrentBuildNumberSize 82 | ); 83 | if (Status != ERROR_SUCCESS) { 84 | RtlGetErrorMessageW((DWORD)GetLastError()); 85 | return E_FAIL; 86 | } 87 | 88 | // Get the update build revision 89 | DWORD UpdateBuildRevision = 0x00; 90 | DWORD UpdateBuildRevisionSize = sizeof(DWORD); 91 | Status = RegGetValueA( 92 | HKEY_LOCAL_MACHINE, 93 | "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 94 | "UBR", 95 | RRF_RT_REG_DWORD, 96 | NULL, 97 | &UpdateBuildRevision, 98 | &UpdateBuildRevisionSize 99 | ); 100 | if (Status != ERROR_SUCCESS) { 101 | RtlGetErrorMessageW((DWORD)GetLastError()); 102 | return E_FAIL; 103 | } 104 | 105 | // Build the version string 106 | HRESULT Result = StringCbPrintfW( 107 | g_VersionString, 108 | sizeof(WCHAR) * 0x20, 109 | L"%u.%c%c%c%c%c.%u\0", 110 | CurrentMajorVersionNumber, 111 | CurrentBuildNumber[0], 112 | CurrentBuildNumber[1], 113 | CurrentBuildNumber[2], 114 | CurrentBuildNumber[3], 115 | CurrentBuildNumber[4], 116 | UpdateBuildRevision 117 | ); 118 | return Result; 119 | } 120 | 121 | 122 | /// 123 | /// Get the DJBT hash of a string. 124 | /// 125 | DWORD RtlGetHash(BSTR String) { 126 | // Allocate memory 127 | LPSTR MultiByte = calloc(0x01, 0x100); 128 | if (MultiByte == NULL) 129 | return 0x00; 130 | 131 | // Convert from wide-character to multibyte-character 132 | SIZE_T Count = 0x00; 133 | wcstombs_s(&Count, MultiByte, 0x100, String, lstrlenW(String)); 134 | if (Count == 0x00) { 135 | free(MultiByte); 136 | return 0x00; 137 | } 138 | 139 | // Calculate the djb2 hash 140 | DWORD Hash = 0x1505; 141 | INT c = 0x0000; 142 | LPSTR d = MultiByte; 143 | 144 | while (c = *d++) 145 | Hash = ((Hash << 5) + Hash) + c; 146 | 147 | free(MultiByte); 148 | return Hash; 149 | } 150 | 151 | 152 | _Use_decl_annotations_ 153 | HRESULT STDMETHODCALLTYPE RegistryInitialise( 154 | VOID 155 | ) { 156 | // Check if already initialised 157 | if (g_BaseKey != INVALID_HANDLE_VALUE) 158 | return S_OK; 159 | 160 | // Check if key exist 161 | LSTATUS Status = ERROR_SUCCESS; 162 | RtlCreateOrOpenKey(Status, HKEY_LOCAL_MACHINE, REGISTRY_BASE_KEY, &g_BaseKey); 163 | 164 | // Get OS Version 165 | if (FAILED(RtlGetOSVersion())) { 166 | RtlGetErrorMessageW((DWORD)GetLastError()); 167 | return E_FAIL; 168 | } 169 | wprintf(L"[*] OS Build: %s\r\n", g_VersionString); 170 | 171 | // Open or create the key with the version string 172 | RtlCreateOrOpenKey(Status, g_BaseKey, g_VersionString, &g_BuilKey); 173 | 174 | // Open or create the keys for: 175 | // - Public Symbols 176 | // - Structures 177 | // - Routines 178 | RtlCreateOrOpenKey(Status, g_BuilKey, REGISTRY_SYMBOLS_KEY, &g_Symbols); 179 | RtlCreateOrOpenKey(Status, g_BuilKey, REGISTRY_STRUCTS_KEY, &g_Structs); 180 | RtlCreateOrOpenKey(Status, g_BuilKey, REGISTRY_ROUTINES_KEY, &g_Routines); 181 | 182 | return S_OK; 183 | } 184 | 185 | 186 | _Use_decl_annotations_ 187 | VOID STDMETHODCALLTYPE RegistryUninitialise( 188 | VOID 189 | ) { 190 | if (g_BaseKey != INVALID_HANDLE_VALUE) 191 | RegCloseKey(g_BaseKey); 192 | if (g_BuilKey != INVALID_HANDLE_VALUE) 193 | RegCloseKey(g_BuilKey); 194 | if (g_Symbols != INVALID_HANDLE_VALUE) 195 | RegCloseKey(g_Symbols); 196 | if (g_Structs != INVALID_HANDLE_VALUE) 197 | RegCloseKey(g_Structs); 198 | if (g_Routines != INVALID_HANDLE_VALUE) 199 | RegCloseKey(g_Routines); 200 | 201 | memset(g_VersionString, 0x00, 0x20); 202 | } 203 | 204 | 205 | _Use_decl_annotations_ 206 | HRESULT STDMETHODCALLTYPE RegistryAddSymbols( 207 | _In_ PUBLIC_SYMBOL Symbols[], 208 | _In_ DWORD Entries 209 | ) { 210 | if (g_Symbols == INVALID_HANDLE_VALUE || Entries == 0x00 || Symbols == NULL) 211 | return E_FAIL; 212 | 213 | // Parse all the entries 214 | DWORD ValidEntries = 0x00; 215 | for (DWORD cx = 0x00; cx < Entries; cx++) { 216 | 217 | // If symbol has not been resolved, go to next entry 218 | if (Symbols[cx].dwRVA == 0x00) 219 | continue; 220 | ValidEntries++; 221 | 222 | // Create new key 223 | HKEY CurrentKey = INVALID_HANDLE_VALUE; 224 | LSTATUS Status = ERROR_SUCCESS; 225 | RtlCreateOrOpenKey(Status, g_Symbols, Symbols[cx].Name, &CurrentKey); 226 | wprintf(L"\\HKLM\\%s\\%s\\%s\\%s\r\n", REGISTRY_BASE_KEY, g_VersionString, REGISTRY_SYMBOLS_KEY, Symbols[cx].Name); 227 | 228 | // Add information 229 | RegSetKeyValueW(CurrentKey, NULL, L"RVA", REG_DWORD, &Symbols[cx].dwRVA, sizeof(DWORD)); 230 | RegSetKeyValueW(CurrentKey, NULL, L"OFF", REG_DWORD, &Symbols[cx].dwOff, sizeof(DWORD)); 231 | RegSetKeyValueW(CurrentKey, NULL, L"SEG", REG_DWORD, &Symbols[cx].dwSeg, sizeof(DWORD)); 232 | 233 | // Get the hash of the name 234 | DWORD Hash = RtlGetHash(Symbols[cx].Name); 235 | RegSetKeyValueW(CurrentKey, NULL, L"DJB", REG_DWORD, &Hash, sizeof(DWORD)); 236 | 237 | RegCloseKey(CurrentKey); 238 | } 239 | 240 | // Set the total number of entries 241 | RegSetKeyValueW(g_BuilKey, NULL, L"NumberOfSymbols", REG_DWORD, &ValidEntries, sizeof(DWORD)); 242 | return S_OK; 243 | } -------------------------------------------------------------------------------- /WKI/WKIUM/tools/msdia140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am0nsec/wkpe/708844b6bf7d2893b1a023f13ae4906e19868ef2/WKI/WKIUM/tools/msdia140.dll -------------------------------------------------------------------------------- /WKI/WKIUM/tools/symsrv.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am0nsec/wkpe/708844b6bf7d2893b1a023f13ae4906e19868ef2/WKI/WKIUM/tools/symsrv.dll -------------------------------------------------------------------------------- /mpp/mpp-client/device.hpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: device.hpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Wrapper for MMP kernel device access. 9 | ================================================================================================+*/ 10 | 11 | #ifndef __MPPCLIENT_DEVICE_H_GUARD__ 12 | #define __MPPCLIENT_DEVICE_H_GUARD__ 13 | 14 | #include 15 | 16 | constexpr ULONG MppAddImageName() { 17 | return (ULONG)CTL_CODE(\ 18 | 0x8000, /* DeviceType */\ 19 | 0x800, /* Function */\ 20 | METHOD_IN_DIRECT, /* Method */\ 21 | FILE_ANY_ACCESS /* Access */\ 22 | ); 23 | } 24 | 25 | constexpr ULONG MppRemoveImageName() { 26 | return (ULONG)CTL_CODE(\ 27 | 0x8000, /* DeviceType */\ 28 | 0x801, /* Function */\ 29 | METHOD_IN_DIRECT, /* Method */\ 30 | FILE_ANY_ACCESS /* Access */\ 31 | ); 32 | } 33 | 34 | constexpr ULONG MppInitialiseKernelRoutines() { 35 | return (ULONG)CTL_CODE(\ 36 | 0x8000, /* DeviceType */\ 37 | 0x802, /* Function */\ 38 | METHOD_IN_DIRECT, /* Method */\ 39 | FILE_ANY_ACCESS /* Access */\ 40 | ); 41 | } 42 | 43 | constexpr WCHAR AmsiImageName[] = L"amsi.dll\0"; 44 | 45 | /// @brief Data structure for `MppInitialiseKernelRoutines` input buffer IOCTL. 46 | typedef struct _MPP_KERNEL_ROUTINES_OFFSETS { 47 | DWORD MiAddSecureEntry; 48 | DWORD MiObtainReferencedVadEx; 49 | DWORD MiUnlockAndDereferenceVad; 50 | } MPP_KERNEL_ROUTINES_OFFSETS, *PMPP_KERNEL_ROUTINES_OFFSETS; 51 | 52 | /// @brief Data structure for `MppRemoveImageName` input buffer IOCTL. 53 | typedef struct _MPP_REMOVE_IMAGE_NAME { 54 | SIZE_T Size; 55 | WCHAR Name[MAX_PATH]; 56 | } MPP_REMOVE_IMAGE_NAME, *PMPP_REMOVE_IMAGE_NAME; 57 | 58 | /// @brief Data structure for `MppAddImageName` input buffer IOCTL. 59 | typedef struct _MPP_ADD_IMAGE_NAME { 60 | SIZE_T Size; 61 | WCHAR Name[MAX_PATH]; 62 | } MPP_ADD_IMAGE_NAME, *PMPP_ADD_IMAGE_NAME; 63 | 64 | /// @brief Class wrapper to manage kernel device driver. 65 | class CDeviceManager { 66 | public: 67 | CDeviceManager() { 68 | // Open handle to the device driver 69 | this->hDevice = ::CreateFileA( 70 | "\\\\.\\MppDrv", 71 | (GENERIC_READ | GENERIC_WRITE), 72 | 0x00, 73 | NULL, 74 | OPEN_EXISTING, 75 | 0x00, 76 | NULL 77 | ); 78 | } 79 | 80 | /// @brief Check if handle to kernel device driver is valid. 81 | _inline BOOLEAN 82 | _Must_inspect_result_ 83 | IsDeviceReady() { 84 | return this->hDevice != INVALID_HANDLE_VALUE; 85 | } 86 | 87 | /// @brief IOCTL to send offset of kernel routines. 88 | /// @param KernelRoutines List of offsets of kernel routines. 89 | BOOLEAN 90 | _Must_inspect_result_ 91 | SendKernelRoutinesOffsets( 92 | _In_ MPP_KERNEL_ROUTINES_OFFSETS KernelRoutines 93 | ) { 94 | DWORD ReturnedBytes = 0x00; 95 | BOOL Success = ::DeviceIoControl( 96 | this->hDevice, 97 | MppInitialiseKernelRoutines(), 98 | &KernelRoutines, 99 | sizeof(MPP_KERNEL_ROUTINES_OFFSETS), 100 | nullptr, 101 | 0x00, 102 | &ReturnedBytes, 103 | nullptr 104 | ); 105 | if (!Success) { 106 | ::printf("Failed to initialise kernel routines (%d).\r\n", ::GetLastError()); 107 | return Success; 108 | } 109 | } 110 | 111 | /// @brief IOCTL to add a new image name. 112 | /// @param ImageName Structure used to add a new image name. 113 | BOOLEAN 114 | _Must_inspect_result_ 115 | SendAddImageName( 116 | _In_ MPP_ADD_IMAGE_NAME ImageName 117 | ) { 118 | DWORD ReturnedBytes = 0x00; 119 | BOOL Success = ::DeviceIoControl( 120 | this->hDevice, 121 | MppAddImageName(), 122 | &ImageName, 123 | sizeof(MPP_ADD_IMAGE_NAME), 124 | nullptr, 125 | 0x00, 126 | &ReturnedBytes, 127 | nullptr 128 | ); 129 | if (!Success) { 130 | ::printf("Failed to add new image name (%d).\r\n", ::GetLastError()); 131 | return Success; 132 | } 133 | } 134 | 135 | private: 136 | /// @brief Handle to kernel device driver. 137 | HANDLE hDevice{ INVALID_HANDLE_VALUE }; 138 | 139 | }; 140 | 141 | #endif // !__MPPCLIENT_DEVICE_H_GUARD__ 142 | 143 | 144 | -------------------------------------------------------------------------------- /mpp/mpp-client/main.cpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: main.cpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Memory Patching Protection (MPP) Kernel Device Driver User-Mode Client. 9 | ================================================================================================+*/ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "sym.hpp" 18 | #include "device.hpp" 19 | 20 | 21 | INT32 main( 22 | _In_ int argc, 23 | _In_ const char* argv[] 24 | ) { 25 | // Banner 26 | wprintf(L"=================================================================\r\n"); 27 | wprintf(L"Module Name: Memory Patching Protection (MPP) User-Mode Client \r\n"); 28 | wprintf(L"Author : Paul L. (@am0nsec) \r\n"); 29 | wprintf(L"Origin : https://github.com/am0nsec/wkpe/ \r\n"); 30 | wprintf(L"Tested OS : Windows 10 (20h2) - 19044.2006 \r\n"); 31 | wprintf(L"=================================================================\r\n"); 32 | 33 | // Download PDB file of ntoskrnl 34 | auto SymDatabase = std::make_unique("C:\\Windows\\System32\\ntoskrnl.exe"); 35 | 36 | if (FAILED(SymDatabase->DownloadFromServer())) 37 | return EXIT_FAILURE; 38 | 39 | // Add symbols to find 40 | SymDatabase->Symbols.insert(std::make_pair("MiAddSecureEntry", 0x00)); 41 | SymDatabase->Symbols.insert(std::make_pair("MiObtainReferencedVadEx", 0x00)); 42 | SymDatabase->Symbols.insert(std::make_pair("MiUnlockAndDereferenceVad", 0x00)); 43 | 44 | // Find symbols 45 | ::printf("\r\n[+] Searching symbols ...\r\n"); 46 | if (FAILED(SymDatabase->LoadAndCheckSym())) 47 | return EXIT_FAILURE; 48 | ::printf("[+] Searching symbols ... OK\r\n"); 49 | 50 | // Send information to the kernel driver 51 | auto DeviceManager = std::make_unique(); 52 | if (!DeviceManager->IsDeviceReady()) { 53 | ::printf("[-] Failed to open handle to kernel device.\r\n"); 54 | return EXIT_FAILURE; 55 | } 56 | 57 | MPP_KERNEL_ROUTINES_OFFSETS KernelRoutines = { 58 | .MiAddSecureEntry = SymDatabase->Symbols["MiAddSecureEntry"], 59 | .MiObtainReferencedVadEx = SymDatabase->Symbols["MiObtainReferencedVadEx"], 60 | .MiUnlockAndDereferenceVad = SymDatabase->Symbols["MiUnlockAndDereferenceVad"] 61 | }; 62 | DeviceManager->SendKernelRoutinesOffsets(KernelRoutines); 63 | 64 | // Add AMSI DLL 65 | MPP_ADD_IMAGE_NAME ImageName = { 66 | .Size = ARRAYSIZE(AmsiImageName) * sizeof(WCHAR) 67 | }; 68 | RtlCopyMemory(ImageName.Name, AmsiImageName, ImageName.Size); 69 | DeviceManager->SendAddImageName(ImageName); 70 | 71 | return EXIT_SUCCESS; 72 | } -------------------------------------------------------------------------------- /mpp/mpp-client/mpp-client.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {76a08b15-abf0-48d7-9ae7-5c5a16a6dbee} 25 | mppclient 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | stdcpp20 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /mpp/mpp-client/mpp-client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mpp/mpp-client/sym.cpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: sym.cpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Windows PDB symbols Extractor. 9 | Based on: https://github.com/Coldzer0/TinyPDBParser 10 | ================================================================================================+*/ 11 | 12 | #include "sym.hpp" 13 | 14 | 15 | _Use_decl_annotations_ 16 | HRESULT CSymDatabase::DownloadFromServer( 17 | VOID 18 | ) { 19 | 20 | // Make sure path exists 21 | if (!std::filesystem::exists(this->FilePath)) { 22 | ::printf("File does not exist: %s\r\n", this->FilePath.c_str()); 23 | return E_UNEXPECTED; 24 | } 25 | 26 | // Get the content of the EXE file 27 | std::ifstream Executable( 28 | this->FilePath, 29 | std::ios::binary | std::ios::ate 30 | ); 31 | SIZE_T ExecutableSize = Executable.tellg(); 32 | 33 | // Set pointer to beginning of file 34 | Executable.seekg(0x00, std::ios::beg); 35 | 36 | // Allocate memory 37 | PVOID ModuleBase = ::malloc(ExecutableSize); 38 | if (ModuleBase == nullptr) { 39 | ::printf("Unable to allocate memory for executable: %d\r\n", ::GetLastError()); 40 | return E_OUTOFMEMORY; 41 | } 42 | 43 | // Start reading the file 44 | if (!Executable.read((char*)ModuleBase, ExecutableSize)) { 45 | ::free(ModuleBase); 46 | ::printf("Unable to read content of the file\r\n"); 47 | return E_UNEXPECTED; 48 | } 49 | 50 | // Get debug directory 51 | PIMAGE_DATA_DIRECTORY DataDirectory = this->GetImageDataDirectory(ModuleBase); 52 | if (DataDirectory == nullptr) { 53 | ::free(ModuleBase); 54 | ::printf("Failed to get debug directory for executable\r\n"); 55 | return E_UNEXPECTED; 56 | } 57 | 58 | // Get offset to the data within the executable 59 | DWORD Offset = this->GetVirtualAddress( 60 | ModuleBase, 61 | DataDirectory->VirtualAddress 62 | ); 63 | if (Offset == 0x00) { 64 | ::free(ModuleBase); 65 | ::printf("Failed to get debug directory for executable\r\n"); 66 | return E_UNEXPECTED; 67 | } 68 | 69 | // Parse all debug entries 70 | PIMAGE_DEBUG_DIRECTORY DebugEntry = reinterpret_cast( 71 | reinterpret_cast(ModuleBase) 72 | + Offset 73 | ); 74 | for (DWORD cx = 0x00; cx < (DataDirectory->Size / sizeof(IMAGE_DEBUG_DIRECTORY)); cx++) { 75 | 76 | // Check if the type of debug is contains what is required 77 | if (DebugEntry->Type != IMAGE_DEBUG_TYPE_CODEVIEW) { 78 | DebugEntry++; 79 | continue; 80 | } 81 | 82 | // Get the CodeView Header 83 | PCV_HEADER CvHeader = reinterpret_cast( 84 | reinterpret_cast(ModuleBase) 85 | + DebugEntry->PointerToRawData 86 | ); 87 | 88 | // Check if PDB 2.00 or PDB 7.00 89 | switch (CvHeader->CvSignature) { 90 | case PDB70: { 91 | PCV_INFO_PDB70 Info = reinterpret_cast(CvHeader); 92 | 93 | // Get basic information 94 | this->PdbName = reinterpret_cast(Info->PdbFileName); 95 | 96 | // Build the server URL to the PDB 97 | this->ServerPath = 98 | std::string("http://msdl.microsoft.com/download/symbols/") 99 | + this->PdbName 100 | + "/" 101 | + this->GuidToString(&Info->Signature) 102 | + std::to_string(Info->Age) 103 | + "/" 104 | + this->PdbName; 105 | break; 106 | } 107 | case PDB20: { 108 | PCV_INFO_PDB20 Info = reinterpret_cast(CvHeader); 109 | 110 | // Get basic information 111 | this->PdbName = reinterpret_cast(Info->PdbFileName); 112 | 113 | // Build the server URL to the PDB 114 | char AgeString[10]; 115 | ::snprintf(AgeString, sizeof(AgeString), "%08X%x", Info->Signature, Info->Age); 116 | 117 | this->ServerPath = 118 | std::string("http://msdl.microsoft.com/download/symbols/") 119 | + this->PdbName 120 | + "/" 121 | + std::string(AgeString) 122 | + "/" 123 | + this->PdbName; 124 | 125 | break; 126 | } 127 | default: { 128 | ::free(ModuleBase); 129 | ::printf("Unsupported CodeView signature %d.\n\r", CvHeader->CvSignature); 130 | return E_UNEXPECTED; 131 | } 132 | } 133 | 134 | // Display Information 135 | ::printf("[+] PDB Information\r\n"); 136 | ::printf(" %s\r\n", this->ServerPath.c_str()); 137 | ::free(ModuleBase); 138 | 139 | // Update the 140 | this->OutputPath = 141 | this->CurrentDirectory + "\\" + this->PdbName; 142 | 143 | // Download file 144 | HRESULT hr = URLDownloadToFileA( 145 | nullptr, 146 | this->ServerPath.c_str(), 147 | this->OutputPath.c_str(), 148 | BINDF_GETNEWESTVERSION, 149 | nullptr 150 | ); 151 | if (FAILED(hr)) 152 | ::printf("[-] Failed to download PDB from symbol server: %d\r\n", ::GetLastError()); 153 | else 154 | ::printf("[+] PDB successfully downloaded from symbol server.\r\n"); 155 | 156 | return hr; 157 | } 158 | 159 | // Cleanup and exit 160 | if (ModuleBase != nullptr) 161 | ::free(ModuleBase); 162 | return E_UNEXPECTED; 163 | } 164 | 165 | 166 | _Use_decl_annotations_ 167 | HRESULT CSymDatabase::LoadAndCheckSym( 168 | VOID 169 | ) { 170 | 171 | // Open handle to current process 172 | HANDLE hProcess = INVALID_HANDLE_VALUE; 173 | hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessId()); 174 | if (hProcess == INVALID_HANDLE_VALUE) { 175 | ::printf("Unable to open handle to current process: %d\r\n", ::GetLastError()); 176 | return E_UNEXPECTED; 177 | } 178 | 179 | // Initialise symbol library 180 | bool SymbolsPathInit = ::SymInitialize( 181 | hProcess, 182 | this->OutputPath.c_str(), 183 | false 184 | ); 185 | if (!SymbolsPathInit) { 186 | ::printf("Unable to initialise symbol library: %d\r\n", ::GetLastError()); 187 | 188 | ::CloseHandle(hProcess); 189 | return E_UNEXPECTED; 190 | } 191 | 192 | // Load PDB file 193 | ::SymSetOptions(SymGetOptions() | SYMOPT_CASE_INSENSITIVE | SYMOPT_LOAD_ANYTHING); 194 | ::SymSetSearchPath(hProcess, this->OutputPath.c_str()); 195 | 196 | SIZE_T SymBase = ::SymLoadModule( 197 | hProcess, 198 | nullptr, 199 | "C:\\Windows\\System32\\ntoskrnl.exe", 200 | nullptr, 201 | 0x00, 202 | 0x00 203 | ); 204 | if (SymBase == 0x00) { 205 | ::printf("Failed to load module: %d\r\n", ::GetLastError()); 206 | 207 | ::CloseHandle(hProcess); 208 | return E_UNEXPECTED; 209 | } 210 | 211 | // Set symbol enumeration callback 212 | HRESULT hr = S_OK; 213 | BOOL Success = SymEnumSymbols( 214 | hProcess, 215 | SymBase, 216 | nullptr, 217 | (PSYM_ENUMERATESYMBOLS_CALLBACK)CSymDatabase::EnumSymCallback, 218 | this 219 | ); 220 | if (!Success) { 221 | ::printf("Failed to set symbol enumeration callback: %d\r\n", ::GetLastError()); 222 | 223 | ::CloseHandle(hProcess); 224 | return E_UNEXPECTED; 225 | } 226 | 227 | // Cleanup and return 228 | ::CloseHandle(hProcess); 229 | return S_OK; 230 | } 231 | 232 | 233 | _Use_decl_annotations_ 234 | PIMAGE_DATA_DIRECTORY CSymDatabase::GetImageDataDirectory( 235 | _In_ LPVOID ModuleBase 236 | ) { 237 | if (ModuleBase == nullptr) 238 | return nullptr; 239 | 240 | // DOS Header 241 | PIMAGE_DOS_HEADER DosHeader = reinterpret_cast(ModuleBase); 242 | if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) 243 | return nullptr; 244 | 245 | // NT Header 246 | PIMAGE_NT_HEADERS NtHeaders = reinterpret_cast( 247 | reinterpret_cast(ModuleBase) 248 | + DosHeader->e_lfanew 249 | ); 250 | if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) 251 | return nullptr; 252 | 253 | // Get data directory 254 | if (!NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 255 | || !NtHeaders->FileHeader.Machine == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { 256 | ::printf("Unsupported executable machine type: %d\r\n", NtHeaders->FileHeader.Machine); 257 | return nullptr; 258 | } 259 | 260 | return &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]; 261 | } 262 | 263 | 264 | _Use_decl_annotations_ 265 | DWORD CSymDatabase::GetVirtualAddress( 266 | _In_ LPVOID ModuleBase, 267 | _In_ DWORD RelativeAddress 268 | ) { 269 | // DOS Header 270 | PIMAGE_DOS_HEADER DosHeader = reinterpret_cast(ModuleBase); 271 | if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) 272 | return 0x00; 273 | 274 | // NT Header 275 | PIMAGE_NT_HEADERS NtHeaders = reinterpret_cast( 276 | reinterpret_cast(ModuleBase) 277 | + DosHeader->e_lfanew 278 | ); 279 | if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) 280 | return 0x00; 281 | 282 | PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHeaders); 283 | for (int i = 0; i < NtHeaders->FileHeader.NumberOfSections; ++i) { 284 | if (RelativeAddress >= Section->VirtualAddress 285 | && RelativeAddress < (Section->VirtualAddress + Section->SizeOfRawData)) { 286 | return (Section->PointerToRawData + (RelativeAddress - Section->VirtualAddress)); 287 | } 288 | 289 | Section++; 290 | } 291 | return 0x00; 292 | } 293 | 294 | 295 | _Use_decl_annotations_ 296 | _inline std::string CSymDatabase::GuidToString( 297 | _In_ GUID* Guid 298 | ) { 299 | char Str[37]; // 32 hex chars + 4 hyphens + null terminator 300 | snprintf(Str, sizeof(Str), 301 | "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", 302 | Guid->Data1, 303 | Guid->Data2, 304 | Guid->Data3, 305 | Guid->Data4[0], 306 | Guid->Data4[1], 307 | Guid->Data4[2], 308 | Guid->Data4[3], 309 | Guid->Data4[4], 310 | Guid->Data4[5], 311 | Guid->Data4[6], 312 | Guid->Data4[7] 313 | ); 314 | return Str; 315 | } 316 | 317 | 318 | _Use_decl_annotations_ 319 | BOOLEAN CSymDatabase::EnumSymCallback( 320 | _In_ PSYMBOL_INFO pSymInfo, 321 | _In_ ULONG SymbolSize, 322 | _In_ PVOID UserContext 323 | ) { 324 | if (pSymInfo->NameLen == 0) 325 | return true; 326 | auto This = reinterpret_cast(UserContext); 327 | 328 | for (auto& kvp : This->Symbols) { 329 | if (std::string(pSymInfo->Name).find(kvp.first) == 0 330 | && ::strlen(pSymInfo->Name) == kvp.first.length() 331 | ) { 332 | kvp.second = pSymInfo->Address - pSymInfo->ModBase; 333 | printf(" - 0x%x : %s\r\n", 334 | (DWORD)(pSymInfo->Address - pSymInfo->ModBase), 335 | (LPSTR)pSymInfo->Name 336 | ); 337 | } 338 | } 339 | 340 | return true; 341 | } -------------------------------------------------------------------------------- /mpp/mpp-client/sym.hpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: sym.hpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Windows PDB symbols Extractor. 9 | Based on: https://github.com/Coldzer0/TinyPDBParser 10 | ================================================================================================+*/ 11 | 12 | #ifndef __MPPCLIENT_SYM_H_GUARD__ 13 | #define __MPPCLIENT_SYM_H_GUARD__ 14 | 15 | #pragma comment(lib, "urlmon") 16 | #pragma comment(lib, "imagehlp") 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | /// @brief CodeView header 27 | typedef struct _CV_HEADER { 28 | DWORD CvSignature;// NBxx 29 | LONG Offset; // Always 0 for NB10 30 | } CV_HEADER, * PCV_HEADER; 31 | 32 | /// @brief CodeView NB10 debug information. 33 | /// (used when debug information is stored in a PDB 2.00 file) 34 | typedef struct _CV_INFO_PDB20 { 35 | CV_HEADER Header; 36 | DWORD Signature; // seconds since 01.01.1970 37 | DWORD Age; // an always-incrementing value 38 | BYTE PdbFileName[1];// zero terminated string with the name of the PDB file 39 | } CV_INFO_PDB20, * PCV_INFO_PDB20; 40 | 41 | 42 | /// @brief CodeView RSDS debug information. 43 | /// (used when debug information is stored in a PDB 7.00 file) 44 | typedef struct _CV_INFO_PDB70 { 45 | DWORD CvSignature; 46 | GUID Signature; // unique identifier 47 | DWORD Age; // an always-incrementing value 48 | BYTE PdbFileName[1];// zero terminated string with the name of the PDB file 49 | } CV_INFO_PDB70, * PCV_INFO_PDB70; 50 | 51 | /// @brief PDB 7.00 CodeView Signature - 'SDSR' 52 | constexpr DWORD PDB70 = 0x53445352; 53 | 54 | /// @brief PDB 2.00 CodeView Signature - '01BN' 55 | constexpr DWORD PDB20 = 0x3031424e; 56 | 57 | /// @brief 58 | class CSymDatabase { 59 | public: 60 | CSymDatabase( 61 | _In_ LPCSTR FilePath 62 | ) { 63 | this->FilePath = std::string(FilePath); 64 | 65 | // Get current directory 66 | char Buffer[MAX_PATH] = { 0x00 }; 67 | ::GetCurrentDirectoryA(MAX_PATH, Buffer); 68 | this->CurrentDirectory = Buffer; 69 | } 70 | 71 | /// @brief Download the PDB from Microsoft symbol server for ntoskrnl.exe executable file. 72 | HRESULT 73 | _Must_inspect_result_ 74 | DownloadFromServer( 75 | VOID 76 | ); 77 | 78 | /// @brief Initialise, load and set callback to enumerate symbols from PDB file. 79 | HRESULT 80 | _Must_inspect_result_ 81 | LoadAndCheckSym( 82 | VOID 83 | ); 84 | 85 | public: 86 | /// @brief Key value pair of symbols and their offsets. 87 | std::map Symbols; 88 | 89 | private: 90 | 91 | /// @brief Get the data directory from ntoskrnl.exe executable file. 92 | /// @param ModuleBase Base address in memory of the ntoskrnl.exe executable file. 93 | PIMAGE_DATA_DIRECTORY 94 | _Must_inspect_result_ 95 | GetImageDataDirectory( 96 | _In_ LPVOID ModuleBase 97 | ); 98 | 99 | /// @brief Calculate virtual address for an offset and base address in memory of the ntoskrnl.exe executable file. 100 | /// @param ModuleBase Base address in memory of the ntoskrnl.exe executable file. 101 | /// @param RelativeAddress Offset of the data to get. 102 | DWORD 103 | _Must_inspect_result_ 104 | GetVirtualAddress( 105 | _In_ LPVOID ModuleBase, 106 | _In_ DWORD RelativeAddress 107 | ); 108 | 109 | /// @brief Convert a GUID to a string. 110 | /// @param Guid GUID to convert to string. 111 | _inline std::string 112 | _Must_inspect_result_ 113 | GuidToString( 114 | _In_ GUID* Guid 115 | ); 116 | 117 | /// @brief Callback to go through all symbols from the PDB file. 118 | /// @param pSymInfo Pointer to symbol information structure. 119 | /// @param SymbolSize Size of symbol. 120 | /// @param UserContext Arbitrary user context. 121 | /// @return 122 | static BOOLEAN 123 | _Must_inspect_result_ 124 | EnumSymCallback( 125 | _In_ PSYMBOL_INFO pSymInfo, 126 | _In_ ULONG SymbolSize, 127 | _In_ PVOID UserContext 128 | ); 129 | 130 | 131 | private: 132 | /// @brief Path to rhe ntoskrnl.exe executable file on disk. 133 | std::string FilePath; 134 | 135 | /// @brief Path to the PDB file on disk post-download. 136 | std::string OutputPath; 137 | 138 | /// @brief Path to the current working directory. 139 | std::string CurrentDirectory; 140 | 141 | /// @brief Web URL of the PDB file from the Microsoft symbol server. 142 | std::string ServerPath; 143 | 144 | /// @brief Name of the PDB file. 145 | std::string PdbName; 146 | }; 147 | 148 | 149 | #endif // !__MPPCLIENT_SYM_H_GUARD__ 150 | -------------------------------------------------------------------------------- /mpp/mpp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32630.192 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpp", "mpp\mpp.vcxproj", "{E163155D-8D27-47E9-AD64-E4E13C6004D6}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpp-client", "mpp-client\mpp-client.vcxproj", "{76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM64 = Debug|ARM64 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|ARM64.ActiveCfg = Debug|ARM64 21 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|ARM64.Build.0 = Debug|ARM64 22 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|ARM64.Deploy.0 = Debug|ARM64 23 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|x64.ActiveCfg = Debug|x64 24 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|x64.Build.0 = Debug|x64 25 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|x64.Deploy.0 = Debug|x64 26 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|x86.ActiveCfg = Debug|x64 27 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|x86.Build.0 = Debug|x64 28 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Debug|x86.Deploy.0 = Debug|x64 29 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|ARM64.ActiveCfg = Release|ARM64 30 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|ARM64.Build.0 = Release|ARM64 31 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|ARM64.Deploy.0 = Release|ARM64 32 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|x64.ActiveCfg = Release|x64 33 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|x64.Build.0 = Release|x64 34 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|x64.Deploy.0 = Release|x64 35 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|x86.ActiveCfg = Release|x64 36 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|x86.Build.0 = Release|x64 37 | {E163155D-8D27-47E9-AD64-E4E13C6004D6}.Release|x86.Deploy.0 = Release|x64 38 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Debug|ARM64.ActiveCfg = Debug|x64 39 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Debug|ARM64.Build.0 = Debug|x64 40 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Debug|x64.ActiveCfg = Debug|x64 41 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Debug|x64.Build.0 = Debug|x64 42 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Debug|x86.ActiveCfg = Debug|Win32 43 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Debug|x86.Build.0 = Debug|Win32 44 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Release|ARM64.ActiveCfg = Release|x64 45 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Release|ARM64.Build.0 = Release|x64 46 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Release|x64.ActiveCfg = Release|x64 47 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Release|x64.Build.0 = Release|x64 48 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Release|x86.ActiveCfg = Release|Win32 49 | {76A08B15-ABF0-48D7-9AE7-5C5A16A6DBEE}.Release|x86.Build.0 = Release|Win32 50 | EndGlobalSection 51 | GlobalSection(SolutionProperties) = preSolution 52 | HideSolutionNode = FALSE 53 | EndGlobalSection 54 | GlobalSection(ExtensibilityGlobals) = postSolution 55 | SolutionGuid = {85F6AD36-4300-436C-B671-EA3E3F356951} 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /mpp/mpp/mpp.cpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mpp.cpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Memory Patching Protection (MPP) Global Kernel Data. 9 | ================================================================================================+*/ 10 | 11 | #include "mpp.hpp" 12 | #include "worker.hpp" 13 | 14 | 15 | /// @brief MPP Global variables 16 | namespace MppGlobals { 17 | /// @brief Kernel memory pool tag. 18 | ULONG PoolTag = (ULONG)' ppM'; 19 | 20 | /// @brief Name of the kernel device driver. 21 | UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\MppDrv"); 22 | 23 | /// @brief Symbolic link name pointing to kernel device driver. 24 | UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\MppDrv"); 25 | 26 | /// @brief Unique Identifier for the kernel device driver - {F394F785-1D05-4C02-A3C5-6E3DC8F0BAD9}. 27 | CONST GUID DeviceId = { 28 | 0xf394f785, 29 | 0x1d05, 30 | 0x4c02, 31 | { 0xa3, 0xc5, 0x6e, 0x3d, 0xc8, 0xf0, 0xba, 0xd9 } 32 | }; 33 | 34 | /// @brief Work item to protect .text section of a module. 35 | PIO_WORKITEM ProtectWorker = nullptr; 36 | } 37 | 38 | 39 | /// @brief Routines and data related to callbacks. 40 | namespace MppCallbacks { 41 | 42 | /// @brief Weather the LoadImageNotify callbacks has been set. 43 | BOOLEAN LoadImage = FALSE; 44 | } 45 | 46 | 47 | /// @brief Data used by the various callbacks 48 | namespace MppCallbackData { 49 | /// @brief Double-linked list of image names to protect .text section. 50 | LIST_ENTRY HeadImageNames{}; 51 | 52 | /// @brief Number of image names to check for each modules being loaded. 53 | ULONG NumberOfImageNames = 0x00; 54 | 55 | /// @brief Spin lock for double-linked list of image names. 56 | KSPIN_LOCK ImageNamesLock = 0x00; 57 | } 58 | 59 | 60 | /// @brief List of non-exported kernel routines required to secure .text section of a module. 61 | namespace MppKernelRoutines { 62 | PVOID(STDMETHODCALLTYPE* MiObtainReferencedVadEx)( 63 | _In_ PVOID Address, 64 | _In_ UCHAR Flags, 65 | _Out_ NTSTATUS* Status 66 | ) = nullptr; 67 | 68 | VOID(STDMETHODCALLTYPE* MiUnlockAndDereferenceVad)( 69 | _In_ PVOID VadObject 70 | ) = nullptr; 71 | 72 | PVOID(STDMETHODCALLTYPE* MiAddSecureEntry) ( 73 | _In_ PVOID VadObject, 74 | _In_ PVOID AddressStart, 75 | _In_ PVOID AddressEnd, 76 | _In_ ULONG ProbMode, 77 | _In_ ULONG Flags 78 | ) = nullptr; 79 | 80 | /// @brief Base address of NT kernel image. 81 | UINT64 KernelBase = 0x00; 82 | 83 | /// @brief Whether the kernel routines have been initialised. 84 | BOOLEAN RoutinesInitialised = FALSE; 85 | } 86 | 87 | 88 | _Use_decl_annotations_ 89 | VOID __declspec(code_seg("PAGE")) 90 | MppCallbacks::LoadImageNotify( 91 | _In_opt_ PUNICODE_STRING FullImageName, 92 | _In_ HANDLE ProcessId, 93 | _In_ PIMAGE_INFO ImageInfo 94 | ) { 95 | UNREFERENCED_PARAMETER(ImageInfo); 96 | 97 | // Cannot check if there is no name 98 | if (FullImageName == nullptr) 99 | return; 100 | 101 | // Acquire spin-lock 102 | KLOCK_QUEUE_HANDLE LockHandle = { 0x00 }; 103 | ::KeAcquireInStackQueuedSpinLock( 104 | &MppCallbackData::ImageNamesLock, 105 | &LockHandle 106 | ); 107 | 108 | // Check if name is of our interest 109 | BOOLEAN Found = FALSE; 110 | PLIST_ENTRY Head = MppCallbackData::HeadImageNames.Flink; 111 | 112 | for (ULONG cx = 0x00; cx < MppCallbackData::NumberOfImageNames; cx++) { 113 | auto Entry = CONTAINING_RECORD(Head, MppCallbackData::ImageNameEntry, List); 114 | if (Entry == nullptr) 115 | break; 116 | 117 | // Check if name matches 118 | if (::wcsstr(FullImageName->Buffer, Entry->Name) != NULL) { 119 | Found = TRUE; 120 | break; 121 | } 122 | 123 | if (Head->Flink == &MppCallbackData::HeadImageNames) 124 | break; 125 | Head = Head->Flink; 126 | } 127 | 128 | // Release spin-lock 129 | ::KeReleaseInStackQueuedSpinLock(&LockHandle); 130 | 131 | // Check if found 132 | if (!Found) 133 | return; 134 | 135 | // Get information required 136 | MppLogger::Info("Image : %wZ\r\n", FullImageName); 137 | 138 | // Allocate memory for worker context data 139 | auto WorkerData = MppMemory::MemAlloc( 140 | sizeof(MppWorker::MPP_WORKER_PROTECT_DATA) 141 | ); 142 | if (WorkerData == nullptr) { 143 | MppLogger::Error("Unable to allocate memory for protect worker data\r\n"); 144 | return; 145 | } 146 | 147 | // Add information 148 | WorkerData->ThreadId = ::PsGetCurrentThreadId(); 149 | WorkerData->ProcessId = ProcessId; 150 | WorkerData->ImageBaseAddress = ImageInfo->ImageBase; 151 | 152 | // Fire the work item from kernel thread pool 153 | ::IoQueueWorkItem( 154 | MppWorker::ProtectWorker, 155 | (PIO_WORKITEM_ROUTINE)MppWorker::ProtectWorkerCallback, 156 | DelayedWorkQueue, 157 | WorkerData 158 | ); 159 | } 160 | 161 | 162 | _Use_decl_annotations_ 163 | HRESULT __declspec(code_seg("PAGE")) 164 | MppCallbackData::AddImageName( 165 | _In_ LPWSTR ImageName, 166 | _In_ SIZE_T ImageNameSize 167 | ) { 168 | // Ensure current IRQL allow paging. 169 | PAGED_CODE(); 170 | 171 | // Check for parameters 172 | if (ImageName == nullptr) 173 | return STATUS_INVALID_PARAMETER_1; 174 | if (ImageNameSize == 0x00) 175 | return STATUS_INVALID_PARAMETER_2; 176 | 177 | // Allocate memory 178 | auto Entry = MppMemory::MemAlloc(sizeof(ImageNameEntry)); 179 | if (Entry == nullptr) 180 | return STATUS_NO_MEMORY; 181 | 182 | // Move data to 183 | Entry->Size = ImageNameSize; 184 | RtlCopyMemory(Entry->Name, ImageName, ImageNameSize); 185 | 186 | // Acquire spin-lock 187 | KLOCK_QUEUE_HANDLE LockHandle = { 0x00 }; 188 | ::KeAcquireInStackQueuedSpinLock( 189 | &ImageNamesLock, 190 | &LockHandle 191 | ); 192 | 193 | // Add entry to the end of the list 194 | ::InsertTailList( 195 | &HeadImageNames, 196 | reinterpret_cast(Entry) 197 | ); 198 | NumberOfImageNames++; 199 | 200 | // Release spin-lock 201 | ::KeReleaseInStackQueuedSpinLock(&LockHandle); 202 | 203 | // Return success 204 | return STATUS_SUCCESS; 205 | } 206 | 207 | 208 | _Use_decl_annotations_ 209 | HRESULT __declspec(code_seg("PAGE")) 210 | MppCallbackData::RemoveImageName( 211 | _In_ LPWSTR ImageName 212 | ) { 213 | // Ensure current IRQL allow paging. 214 | PAGED_CODE(); 215 | 216 | // Check for parameter 217 | if (ImageName == nullptr) 218 | return STATUS_INVALID_PARAMETER_1; 219 | 220 | // Acquire spin-lock 221 | KLOCK_QUEUE_HANDLE LockHandle = { 0x00 }; 222 | ::KeAcquireInStackQueuedSpinLock( 223 | &ImageNamesLock, 224 | &LockHandle 225 | ); 226 | 227 | // Parse all entries 228 | ImageNameEntry* Entry = nullptr; 229 | PLIST_ENTRY Head = HeadImageNames.Flink; 230 | BOOLEAN Found = FALSE; 231 | for (UINT32 cx = 0x00; cx < NumberOfImageNames; cx++) { 232 | 233 | // Structure from memory 234 | Entry = CONTAINING_RECORD(Head, ImageNameEntry, List); 235 | if (Entry == nullptr) 236 | break; 237 | 238 | // Check if name matches 239 | if (::wcsstr(ImageName, Entry->Name) != NULL) { 240 | Found = TRUE; 241 | break; 242 | } 243 | 244 | // Move to next entry 245 | if (Head->Flink == &HeadImageNames) 246 | break; 247 | Head = Head->Flink; 248 | } 249 | 250 | // Remove if entry was found 251 | if (Found) { 252 | ::RemoveEntryList(reinterpret_cast(Entry)); 253 | MppMemory::MemFree(Entry); 254 | } 255 | 256 | // Release spin-lock 257 | ::KeReleaseInStackQueuedSpinLock(&LockHandle); 258 | 259 | // Return success 260 | return STATUS_SUCCESS; 261 | } 262 | 263 | 264 | _Use_decl_annotations_ 265 | HRESULT __declspec(code_seg("PAGE")) 266 | MppKernelRoutines::GetNtKernelBase() { 267 | // Ensure current IRQL allow paging. 268 | PAGED_CODE(); 269 | 270 | // Initialise auxiliary kernel library 271 | ::AuxKlibInitialize(); 272 | 273 | ULONG BufferSize = 0x00; 274 | NTSTATUS Status = ::AuxKlibQueryModuleInformation(&BufferSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL); 275 | if (NT_ERROR(Status) || BufferSize == 0x00) 276 | return STATUS_UNSUCCESSFUL; 277 | 278 | auto ExtendedInfo = MppMemory::MemAlloc(BufferSize); 279 | if (ExtendedInfo == NULL) 280 | return STATUS_NO_MEMORY; 281 | Status = ::AuxKlibQueryModuleInformation(&BufferSize, sizeof(AUX_MODULE_EXTENDED_INFO), (PVOID)ExtendedInfo); 282 | 283 | // Parse all modules 284 | for (UINT32 cx = 0x00; cx < (BufferSize / sizeof(AUX_MODULE_EXTENDED_INFO)); cx++) { 285 | if (::strcmp("\\SystemRoot\\system32\\ntoskrnl.exe", (CONST PCHAR)ExtendedInfo[cx].FullPathName) == 0x00) { 286 | MppKernelRoutines::KernelBase = (UINT64)ExtendedInfo[cx].BasicInfo.ImageBase; 287 | break; 288 | } 289 | } 290 | ASSERT(MppKernelRoutines::KernelBase != 0x00); 291 | 292 | // Cleanup and return 293 | MppMemory::MemFree(ExtendedInfo); 294 | return STATUS_SUCCESS; 295 | } -------------------------------------------------------------------------------- /mpp/mpp/mpp.hpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: mpp.hpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Memory Patching Protection (MPP) Global Kernel Data. 9 | ================================================================================================+*/ 10 | 11 | #ifndef __MPP_MPP_H_GUARD__ 12 | #define __MPP_MPP_H_GUARD__ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #ifndef _AUX_KLIB_H 19 | #include 20 | #endif // !_AUX_KLIB_H 21 | 22 | 23 | /// @brief MPP Global variables 24 | namespace MppGlobals { 25 | /// @brief Kernel memory pool tag. 26 | extern ULONG PoolTag; 27 | 28 | /// @brief Name of the kernel device driver. 29 | extern UNICODE_STRING DeviceName; 30 | 31 | /// @brief Symbolic link name pointing to kernel device driver. 32 | extern UNICODE_STRING SymlinkName; 33 | 34 | /// @brief Unique Identifier for the kernel device driver - {F394F785-1D05-4C02-A3C5-6E3DC8F0BAD9}. 35 | extern CONST GUID DeviceId; 36 | } 37 | 38 | 39 | /// @brief List of IOCTLs for the dispatcher. 40 | namespace MppIoctl { 41 | constexpr ULONG MppAddImageName() { 42 | return (ULONG)CTL_CODE(\ 43 | 0x8000, /* DeviceType */\ 44 | 0x800, /* Function */\ 45 | METHOD_IN_DIRECT, /* Method */\ 46 | FILE_ANY_ACCESS /* Access */\ 47 | ); 48 | } 49 | 50 | constexpr ULONG MppRemoveImageName() { 51 | return (ULONG)CTL_CODE(\ 52 | 0x8000, /* DeviceType */\ 53 | 0x801, /* Function */\ 54 | METHOD_IN_DIRECT, /* Method */\ 55 | FILE_ANY_ACCESS /* Access */\ 56 | ); 57 | } 58 | 59 | constexpr ULONG MppInitialiseKernelRoutines() { 60 | return (ULONG)CTL_CODE(\ 61 | 0x8000, /* DeviceType */\ 62 | 0x802, /* Function */\ 63 | METHOD_IN_DIRECT, /* Method */\ 64 | FILE_ANY_ACCESS /* Access */\ 65 | ); 66 | } 67 | 68 | /// @brief Data structure for `MppInitialiseKernelRoutines` input buffer IOCTL. 69 | typedef struct _MPP_KERNEL_ROUTINES_OFFSETS { 70 | ULONG MiAddSecureEntry; 71 | ULONG MiObtainReferencedVadEx; 72 | ULONG MiUnlockAndDereferenceVad; 73 | } MPP_KERNEL_ROUTINES_OFFSETS, * PMPP_KERNEL_ROUTINES_OFFSETS; 74 | 75 | /// @brief Data structure for `MppRemoveImageName` input buffer IOCTL. 76 | typedef struct _MPP_REMOVE_IMAGE_NAME { 77 | SIZE_T Size; 78 | WCHAR Name[260]; 79 | } MPP_REMOVE_IMAGE_NAME, * PMPP_REMOVE_IMAGE_NAME; 80 | 81 | /// @brief Data structure for `MppAddImageName` input buffer IOCTL. 82 | typedef struct _MPP_ADD_IMAGE_NAME { 83 | SIZE_T Size; 84 | WCHAR Name[260]; 85 | } MPP_ADD_IMAGE_NAME, * PMPP_ADD_IMAGE_NAME; 86 | } 87 | 88 | 89 | /// @brief Kernel logger routines. 90 | namespace MppLogger { 91 | 92 | /// @brief Default info logger. 93 | template 94 | _inline void Info(Arguments... Args) { 95 | ::KdPrint((Args...)); 96 | } 97 | 98 | /// @brief Default error logger. 99 | template 100 | _inline void Error(Arguments... Args) { 101 | #if DBG 102 | ::DbgPrint("[-::%ws::%d]\n\r", __FUNCTIONW__, __LINE__); 103 | ::KdPrint((Args...)); 104 | #endif 105 | } 106 | } 107 | 108 | 109 | /// @brief Kernel memory alloc/free wrapper. 110 | namespace MppMemory { 111 | 112 | /// @brief Wrapper to allocate memory within the kernel memory pool. 113 | template 114 | _inline T MemAlloc(SIZE_T Size) { 115 | return (T)::ExAllocatePool2( 116 | POOL_FLAG_PAGED, 117 | Size, 118 | MppGlobals::PoolTag 119 | ); 120 | } 121 | 122 | /// @brief Wrapper to free memory within the kernel memory pool. 123 | template 124 | _inline VOID MemFree(T Data) { 125 | ::ExFreePoolWithTag((PVOID)Data, MppGlobals::PoolTag); 126 | } 127 | 128 | /// @brief Check whether user input is large enough. 129 | /// @param IoStack IO Stack. 130 | /// @param Size Minimum size to check. 131 | _inline BOOLEAN CheckInputBuffer( 132 | _In_ PIO_STACK_LOCATION IoStack, 133 | _In_ ULONG Size 134 | ) { 135 | return (IoStack->Parameters.DeviceIoControl.InputBufferLength <= Size); 136 | } 137 | } 138 | 139 | 140 | /// @brief Routines and data related to callbacks. 141 | namespace MppCallbacks { 142 | 143 | /// @brief Callback for `PsRemoveLoadImageNotifyRoutine`. 144 | /// @param FullImageName Full name of the image being loaded. 145 | /// @param ProcessId Process Id of the process loading the image. 146 | /// @param ImageInfo Additional of the image being loaded. 147 | VOID __declspec(code_seg("PAGE")) 148 | _IRQL_requires_min_(PASSIVE_LEVEL) 149 | _IRQL_requires_max_(PASSIVE_LEVEL) 150 | LoadImageNotify( 151 | _In_opt_ PUNICODE_STRING FullImageName, 152 | _In_ HANDLE ProcessId, 153 | _In_ PIMAGE_INFO ImageInfo 154 | ); 155 | 156 | /// @brief Weather the LoadImageNotify callbacks has been set. 157 | extern BOOLEAN LoadImage; 158 | } 159 | 160 | 161 | /// @brief Callback specific data. 162 | namespace MppCallbackData { 163 | 164 | /// @brief Double-linked list of image names to protect .text section. 165 | extern LIST_ENTRY HeadImageNames; 166 | 167 | /// @brief Number of image names to check for each modules being loaded. 168 | extern ULONG NumberOfImageNames; 169 | 170 | /// @brief Spin lock for double-linked list of image names. 171 | extern KSPIN_LOCK ImageNamesLock; 172 | 173 | /// @brief Add new image name in the `HeadImageNames` double-linked list.. 174 | /// @param ImageName Name of the image to add. 175 | /// @param ImageNameSize Size of the image name to add. 176 | NTSTATUS __declspec(code_seg("PAGE")) 177 | _IRQL_requires_min_(APC_LEVEL) 178 | _IRQL_requires_max_(APC_LEVEL) 179 | AddImageName( 180 | _In_ LPWSTR ImageName, 181 | _In_ SIZE_T ImageNameSize 182 | ); 183 | 184 | /// @brief Remove image name from `HeadImageNames` double-linked list. 185 | /// @param ImageName Name of the entry to remove from the list. 186 | NTSTATUS __declspec(code_seg("PAGE")) 187 | _IRQL_requires_min_(APC_LEVEL) 188 | _IRQL_requires_max_(APC_LEVEL) 189 | RemoveImageName( 190 | _In_ LPWSTR ImageName 191 | ); 192 | 193 | /// @brief Structure used to store each image names to protect. 194 | typedef struct ImageNameEntry { 195 | LIST_ENTRY List; 196 | 197 | SIZE_T Size; 198 | WCHAR Name[260]; 199 | } ImageNameEntry; 200 | } 201 | 202 | 203 | /// @brief List of non-exported kernel routines required to secure .text section of a module. 204 | namespace MppKernelRoutines { 205 | extern PVOID(STDMETHODCALLTYPE* MiObtainReferencedVadEx)( 206 | _In_ PVOID Address, 207 | _In_ UCHAR Flags, 208 | _Out_ NTSTATUS* Status 209 | ); 210 | 211 | extern VOID(STDMETHODCALLTYPE* MiUnlockAndDereferenceVad)( 212 | _In_ PVOID VadObject 213 | ); 214 | 215 | extern PVOID(STDMETHODCALLTYPE* MiAddSecureEntry) ( 216 | _In_ PVOID VadObject, 217 | _In_ PVOID AddressStart, 218 | _In_ PVOID AddressEnd, 219 | _In_ ULONG ProbMode, 220 | _In_ ULONG Flags 221 | ); 222 | 223 | /// @brief Base address of NT kernel image. 224 | extern UINT64 KernelBase; 225 | 226 | /// @brief Whether the kernel routines have been initialised. 227 | extern BOOLEAN RoutinesInitialised; 228 | 229 | /// @brief Get base address of the NT kernel image. 230 | /// @return 231 | HRESULT __declspec(code_seg("PAGE")) 232 | _IRQL_requires_min_(APC_LEVEL) 233 | _IRQL_requires_max_(APC_LEVEL) 234 | GetNtKernelBase(); 235 | 236 | /// @brief Wrapper to update kernel routines function pointers. 237 | /// @param Function Function pointer to update. 238 | /// @param Offset Offset of the function from NT kernel base address. 239 | template 240 | _inline VOID UpdateFunctionPointer( 241 | _In_ T& Function, 242 | _In_ ULONG Offset 243 | ) { 244 | Function = reinterpret_cast( 245 | MppKernelRoutines::KernelBase 246 | + Offset 247 | ); 248 | } 249 | } 250 | 251 | 252 | #endif // !__MPP_MPP_H_GUARD__ 253 | -------------------------------------------------------------------------------- /mpp/mpp/mpp.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | {E163155D-8D27-47E9-AD64-E4E13C6004D6} 23 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 24 | v4.5 25 | 12.0 26 | Debug 27 | x64 28 | mpp 29 | 30 | 31 | 32 | Windows10 33 | true 34 | WindowsKernelModeDriver10.0 35 | Driver 36 | WDM 37 | false 38 | 39 | 40 | Windows10 41 | false 42 | WindowsKernelModeDriver10.0 43 | Driver 44 | WDM 45 | 46 | 47 | Windows10 48 | true 49 | WindowsKernelModeDriver10.0 50 | Driver 51 | WDM 52 | 53 | 54 | Windows10 55 | false 56 | WindowsKernelModeDriver10.0 57 | Driver 58 | WDM 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | DbgengKernelDebugger 70 | 71 | 72 | DbgengKernelDebugger 73 | 74 | 75 | DbgengKernelDebugger 76 | 77 | 78 | DbgengKernelDebugger 79 | 80 | 81 | 82 | sha256 83 | 84 | 85 | $(DDK_LIB_PATH)wdmsec.lib;$(DDK_LIB_PATH)Aux_Klib.lib;%(AdditionalDependencies) 86 | 87 | 88 | 89 | 90 | sha256 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /mpp/mpp/mpp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /mpp/mpp/worker.cpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: worker.cpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Memory Patching Protection (MPP) Worker for Image .text section protection. 9 | ================================================================================================+*/ 10 | 11 | #include "mpp.hpp" 12 | #include "worker.hpp" 13 | 14 | 15 | namespace MppWorker { 16 | 17 | /// @brief Work item to protect .text section of a module. 18 | PIO_WORKITEM ProtectWorker = nullptr; 19 | } 20 | 21 | 22 | _Use_decl_annotations_ 23 | VOID __declspec(code_seg("PAGE")) 24 | MppWorker::ProtectWorkerCallback( 25 | _In_ PDEVICE_OBJECT DeviceObject, 26 | _In_opt_ PVOID WorkerData 27 | ) { 28 | UNREFERENCED_PARAMETER(DeviceObject); 29 | if (WorkerData == nullptr) 30 | return; 31 | 32 | // Get local stack copy of the worker data 33 | MppWorker::MPP_WORKER_PROTECT_DATA LocalWorkerData = { 0x00 }; 34 | RtlCopyMemory( 35 | &LocalWorkerData, 36 | WorkerData, 37 | sizeof(MppWorker::MPP_WORKER_PROTECT_DATA) 38 | ); 39 | MppMemory::MemFree(WorkerData); 40 | 41 | // Log the information sent via from the callback 42 | MppLogger::Info("Process ID : 0x%08x\r\n", ::HandleToULong(LocalWorkerData.ProcessId)); 43 | MppLogger::Info("Thread ID : 0x%08x\r\n", ::HandleToULong(LocalWorkerData.ThreadId)); 44 | MppLogger::Info("Image : 0x%p\r\n", LocalWorkerData.ImageBaseAddress); 45 | 46 | // Attack to process 47 | PEPROCESS TargetProcess = NULL; 48 | KAPC_STATE ApcState = { 0x00 }; 49 | 50 | NTSTATUS Status = ::PsLookupProcessByProcessId(LocalWorkerData.ProcessId, &TargetProcess); 51 | if (!NT_SUCCESS(Status)) { 52 | MppLogger::Error("Unable to get PEPROCESS from PID (0x%08X).\r\n", Status); 53 | return; 54 | } 55 | ::KeStackAttachProcess(TargetProcess, &ApcState); 56 | 57 | // Get the start and end address of the .text section of the image 58 | PVOID AddressStart = nullptr; 59 | PVOID AddressEnd = nullptr; 60 | 61 | MppWorker::GetImageTextSectionAddresses( 62 | LocalWorkerData.ImageBaseAddress, 63 | &AddressStart, 64 | &AddressEnd 65 | ); 66 | if (AddressStart == nullptr || AddressEnd == nullptr) { 67 | ::KeUnstackDetachProcess(&ApcState); 68 | 69 | MppLogger::Error("Unable get the start and end address of the .text section.\r\n"); 70 | return; 71 | } 72 | MppLogger::Info(".text start: 0x%p\r\n", AddressStart); 73 | MppLogger::Info(".text end : 0x%p\r\n", AddressEnd); 74 | 75 | // Raise IRQL to APC_LEVEL (1) 76 | KIRQL OldIRQL = ::KfRaiseIrql(APC_LEVEL); 77 | 78 | // Get a reference to the Virtual Address Descriptor (VAD) 79 | PVOID VadObject = MppKernelRoutines::MiObtainReferencedVadEx( 80 | AddressStart, 81 | 0x00, 82 | &Status 83 | ); 84 | if (!NT_SUCCESS(Status)) { 85 | MppLogger::Error("Unable to get VAD for address (0x%08X).\r\n", Status); 86 | 87 | ::KeLowerIrql(OldIRQL); 88 | ::KeUnstackDetachProcess(&ApcState); 89 | return; 90 | } 91 | 92 | // Enforce non-writable and non-modifiable memory pages 93 | PVOID PoolMm = MppKernelRoutines::MiAddSecureEntry( 94 | VadObject, 95 | AddressStart, 96 | AddressEnd, 97 | (PAGE_REVERT_TO_FILE_MAP | PAGE_TARGETS_NO_UPDATE | PAGE_NOACCESS), 98 | (MM_SECURE_USER_MODE_ONLY | MM_SECURE_NO_CHANGE) 99 | ); 100 | if (!(PoolMm >= 0x00)) { 101 | MppLogger::Error("Unable to secure image (0x%08X).\r\n", Status); 102 | } 103 | 104 | // Cleanup 105 | MppKernelRoutines::MiUnlockAndDereferenceVad(VadObject); 106 | 107 | ::KeLowerIrql(OldIRQL); 108 | ::KeUnstackDetachProcess(&ApcState); 109 | return; 110 | } 111 | 112 | 113 | _Use_decl_annotations_ 114 | VOID __declspec(code_seg("PAGE")) 115 | MppWorker::GetImageTextSectionAddresses( 116 | _In_ PVOID ImageBaseAddress, 117 | _Out_ PVOID* AddressStart, 118 | _Out_ PVOID* AddressEnd 119 | ) { 120 | if (ImageBaseAddress == NULL) 121 | return; 122 | *AddressStart = 0x00; 123 | *AddressEnd = 0x00; 124 | 125 | PIMAGE_DOS_HEADER ImageDOSHeader = (PIMAGE_DOS_HEADER)ImageBaseAddress; 126 | if (ImageDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) { 127 | MppLogger::Error("Invalid DOS signature.\r\n"); 128 | return; 129 | } 130 | 131 | PIMAGE_NT_HEADERS ImageNTHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)ImageBaseAddress + ImageDOSHeader->e_lfanew); 132 | if (ImageNTHeaders->Signature != IMAGE_NT_SIGNATURE) { 133 | MppLogger::Error("Invalid NT Headers signature.\r\n"); 134 | return; 135 | } 136 | 137 | PIMAGE_SECTION_HEADER SectionHeader = IMAGE_FIRST_SECTION(ImageNTHeaders); 138 | while (TRUE) { 139 | if (MppWorker::IsTextSection(SectionHeader->Name)) 140 | break; 141 | SectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)SectionHeader + IMAGE_SIZEOF_SECTION_HEADER); 142 | } 143 | 144 | *AddressStart = (PVOID)(((ULONG_PTR)ImageBaseAddress + SectionHeader->VirtualAddress) & 0xFFFFFFFFFFFFF000); 145 | *AddressEnd = (PVOID)((ULONG_PTR)*AddressStart + SectionHeader->SizeOfRawData); 146 | return; 147 | } 148 | -------------------------------------------------------------------------------- /mpp/mpp/worker.hpp: -------------------------------------------------------------------------------- 1 | /*+================================================================================================ 2 | Module Name: worker.hpp 3 | Author : Paul L. (@am0nsec) 4 | Origin : https://github.com/am0nsec/wkpe/ 5 | Copyright : This project has been released under the GNU Public License v3 license. 6 | 7 | Abstract: 8 | Memory Patching Protection (MPP) Worker for Image .text section protection. 9 | ================================================================================================+*/ 10 | 11 | #ifndef __MPP_WORKER_H_GUARD__ 12 | #define __MPP_WORKER_H_GUARD__ 13 | 14 | #include "mpp.hpp" 15 | #include "worker.hpp" 16 | 17 | /// @brief System worker information 18 | namespace MppWorker { 19 | 20 | /// @brief Work item to protect .text section of a module. 21 | extern PIO_WORKITEM ProtectWorker; 22 | 23 | /// @brief Image Loading callback registered via PsSetLoadImageNotifyRoutine. 24 | /// @param FullImageName Name of the image loaded from the system. 25 | /// @param ProcessId Current process unique ID. 26 | /// @param ImageInfo Further information about the image being loaded. 27 | VOID __declspec(code_seg("PAGE")) 28 | _IRQL_requires_min_(PASSIVE_LEVEL) 29 | _IRQL_requires_max_(PASSIVE_LEVEL) 30 | ProtectWorkerCallback( 31 | _In_ PDEVICE_OBJECT DeviceObject, 32 | _In_opt_ PVOID WorkerData 33 | ); 34 | 35 | 36 | /// @brief Get the start and end address of the .text section of an image 37 | /// @param ImageBaseAddress Base address of the image being loaded. 38 | /// @param AddressStart Start address. 39 | /// @param AddressEnd End address. 40 | VOID __declspec(code_seg("PAGE")) 41 | _IRQL_requires_min_(PASSIVE_LEVEL) 42 | _IRQL_requires_max_(PASSIVE_LEVEL) 43 | GetImageTextSectionAddresses( 44 | _In_ PVOID ImageBaseAddress, 45 | _Out_ PVOID* AddressStart, 46 | _Out_ PVOID* AddressEnd 47 | ); 48 | 49 | /// @brief Check if section name is ".text" 50 | /// @param x Section name array. 51 | constexpr bool IsTextSection(UCHAR x[0x08]) { 52 | return ( 53 | x[0x00] == '.' 54 | && x[0x01] == 't' 55 | && x[0x02] == 'e' 56 | && x[0x03] == 'x' 57 | && x[0x04] == 't' 58 | ); 59 | } 60 | 61 | /// @brief Data Context for the protect worker. 62 | typedef struct _MPP_WORKER_PROTECT_DATA { 63 | HANDLE ThreadId; 64 | HANDLE ProcessId; 65 | PVOID ImageBaseAddress; 66 | } MPP_WORKER_PROTECT_DATA, *PMPP_WORKER_PROTECT_DATA; 67 | } 68 | 69 | #endif // !__MPP_WORKER_H_GUARD__ 70 | --------------------------------------------------------------------------------