├── .github └── workflows │ └── build.yml ├── .gitignore ├── DurangoInteropDotnet.code-workspace ├── DurangoInteropDotnet.sln ├── LICENSE ├── README.md ├── msbuild_tasks ├── disable_firewall.xml ├── get_tempxvd_owners.xml ├── load_pe_shellcode.xml ├── mount_connectedstorage.xml ├── prepare_gamedump.xml ├── registry_dump.xml └── xbfs_backup.xml └── src ├── 00_GlobalUsings.cs ├── 01_Interop.cs ├── AppPackageMountManager.cs ├── DurangoInteropDotnet.csproj ├── FirewallManager.cs ├── LicenseManager.cs ├── Shellcode.cs ├── UserManager.cs ├── WinUserManager.cs ├── XCrd.cs └── modules ├── xcrdutil.psd1 └── xcrdutil.psm1 /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - main 6 | tags: 7 | - "v*" 8 | pull_request: 9 | workflow_call: 10 | 11 | permissions: 12 | contents: write 13 | 14 | jobs: 15 | build: 16 | runs-on: windows-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | - name: Setup .NET SDK 8.0 21 | uses: actions/setup-dotnet@v2 22 | with: 23 | dotnet-version: 8.0.x 24 | - name: Build 25 | run: dotnet build src\DurangoInteropDotnet.csproj -property:Configuration=Release 26 | - name: Copy README and LICENSE 27 | run: | 28 | copy README.md src\bin\Release\net8.0-windows\ 29 | copy LICENSE src\bin\Release\net8.0-windows\ 30 | - name: Upload artifacts 31 | id: upload-artifact 32 | uses: actions/upload-artifact@v4 33 | with: 34 | name: win-release-artifacts 35 | path: src/bin/Release/net8.0-windows/** 36 | 37 | release: 38 | needs: build 39 | if: success() && startsWith(github.ref, 'refs/tags/') 40 | runs-on: windows-latest 41 | steps: 42 | - uses: actions/download-artifact@v4 43 | with: 44 | name: win-release-artifacts 45 | - name: List files 46 | run: ls -R . 47 | - name: Package 48 | shell: bash 49 | run: | 50 | 7z a -tzip "DurangoInterop_${{ github.ref_name }}.zip" "*" 51 | - name: Create Release 52 | uses: softprops/action-gh-release@v2 53 | with: 54 | token: ${{ secrets.GITHUB_TOKEN }} 55 | files: "DurangoInterop_${{ github.ref_name }}.zip" 56 | make_latest: true 57 | generate_release_notes: true 58 | fail_on_unmatched_files: true -------------------------------------------------------------------------------- /.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 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | x64/ 20 | x86/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | [Ll]og/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # .NET Core 45 | project.lock.json 46 | project.fragment.lock.json 47 | artifacts/ 48 | **/Properties/launchSettings.json 49 | 50 | # VS Code 51 | .vscode/ 52 | 53 | *_i.c 54 | *_p.c 55 | *_i.h 56 | *.ilk 57 | *.meta 58 | *.obj 59 | *.pch 60 | *.pdb 61 | *.pgc 62 | *.pgd 63 | *.rsp 64 | *.sbr 65 | *.tlb 66 | *.tli 67 | *.tlh 68 | *.tmp 69 | *.tmp_proj 70 | *.log 71 | *.vspscc 72 | *.vssscc 73 | .builds 74 | *.pidb 75 | *.svclog 76 | *.scc 77 | 78 | # Chutzpah Test files 79 | _Chutzpah* 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opendb 86 | *.opensdf 87 | *.sdf 88 | *.cachefile 89 | *.VC.db 90 | *.VC.VC.opendb 91 | 92 | # Visual Studio profiler 93 | *.psess 94 | *.vsp 95 | *.vspx 96 | *.sap 97 | 98 | # TFS 2012 Local Workspace 99 | $tf/ 100 | 101 | # Guidance Automation Toolkit 102 | *.gpState 103 | 104 | # ReSharper is a .NET coding add-in 105 | _ReSharper*/ 106 | *.[Rr]e[Ss]harper 107 | *.DotSettings.user 108 | 109 | # JustCode is a .NET coding add-in 110 | .JustCode 111 | 112 | # TeamCity is a build add-in 113 | _TeamCity* 114 | 115 | # DotCover is a Code Coverage Tool 116 | *.dotCover 117 | 118 | # Visual Studio code coverage results 119 | *.coverage 120 | *.coveragexml 121 | 122 | # NCrunch 123 | _NCrunch_* 124 | .*crunch*.local.xml 125 | nCrunchTemp_* 126 | 127 | # MightyMoose 128 | *.mm.* 129 | AutoTest.Net/ 130 | 131 | # Web workbench (sass) 132 | .sass-cache/ 133 | 134 | # Installshield output folder 135 | [Ee]xpress/ 136 | 137 | # DocProject is a documentation generator add-in 138 | DocProject/buildhelp/ 139 | DocProject/Help/*.HxT 140 | DocProject/Help/*.HxC 141 | DocProject/Help/*.hhc 142 | DocProject/Help/*.hhk 143 | DocProject/Help/*.hhp 144 | DocProject/Help/Html2 145 | DocProject/Help/html 146 | 147 | # Click-Once directory 148 | publish/ 149 | 150 | # Publish Web Output 151 | *.[Pp]ublish.xml 152 | *.azurePubxml 153 | # TODO: Comment the next line if you want to checkin your web deploy settings 154 | # but database connection strings (with potential passwords) will be unencrypted 155 | *.pubxml 156 | *.publishproj 157 | 158 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 159 | # checkin your Azure Web App publish settings, but sensitive information contained 160 | # in these scripts will be unencrypted 161 | PublishScripts/ 162 | 163 | # NuGet Packages 164 | *.nupkg 165 | # The packages folder can be ignored because of Package Restore 166 | **/packages/* 167 | # except build/, which is used as an MSBuild target. 168 | !**/packages/build/ 169 | # Uncomment if necessary however generally it will be regenerated when needed 170 | #!**/packages/repositories.config 171 | # NuGet v3's project.json files produces more ignorable files 172 | *.nuget.props 173 | *.nuget.targets 174 | 175 | # Microsoft Azure Build Output 176 | csx/ 177 | *.build.csdef 178 | 179 | # Microsoft Azure Emulator 180 | ecf/ 181 | rcf/ 182 | 183 | # Windows Store app package directories and files 184 | AppPackages/ 185 | BundleArtifacts/ 186 | Package.StoreAssociation.xml 187 | _pkginfo.txt 188 | 189 | # Visual Studio cache files 190 | # files ending in .cache can be ignored 191 | *.[Cc]ache 192 | # but keep track of directories ending in .cache 193 | !*.[Cc]ache/ 194 | 195 | # Others 196 | ClientBin/ 197 | ~$* 198 | *~ 199 | *.dbmdl 200 | *.dbproj.schemaview 201 | *.jfm 202 | *.pfx 203 | *.publishsettings 204 | orleans.codegen.cs 205 | 206 | # Since there are multiple workflows, uncomment next line to ignore bower_components 207 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 208 | #bower_components/ 209 | 210 | # RIA/Silverlight projects 211 | Generated_Code/ 212 | 213 | # Backup & report files from converting an old project file 214 | # to a newer Visual Studio version. Backup files are not needed, 215 | # because we have git ;-) 216 | _UpgradeReport_Files/ 217 | Backup*/ 218 | UpgradeLog*.XML 219 | UpgradeLog*.htm 220 | 221 | # SQL Server files 222 | *.mdf 223 | *.ldf 224 | 225 | # Business Intelligence projects 226 | *.rdl.data 227 | *.bim.layout 228 | *.bim_*.settings 229 | 230 | # Microsoft Fakes 231 | FakesAssemblies/ 232 | 233 | # GhostDoc plugin setting file 234 | *.GhostDoc.xml 235 | 236 | # Node.js Tools for Visual Studio 237 | .ntvs_analysis.dat 238 | node_modules/ 239 | 240 | # Typescript v1 declaration files 241 | typings/ 242 | 243 | # Visual Studio 6 build log 244 | *.plg 245 | 246 | # Visual Studio 6 workspace options file 247 | *.opt 248 | 249 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 250 | *.vbw 251 | 252 | # Visual Studio LightSwitch build output 253 | **/*.HTMLClient/GeneratedArtifacts 254 | **/*.DesktopClient/GeneratedArtifacts 255 | **/*.DesktopClient/ModelManifest.xml 256 | **/*.Server/GeneratedArtifacts 257 | **/*.Server/ModelManifest.xml 258 | _Pvt_Extensions 259 | 260 | # Paket dependency manager 261 | .paket/paket.exe 262 | paket-files/ 263 | 264 | # FAKE - F# Make 265 | .fake/ 266 | 267 | # JetBrains Rider 268 | .idea/ 269 | *.sln.iml 270 | 271 | # CodeRush 272 | .cr/ 273 | 274 | # Python Tools for Visual Studio (PTVS) 275 | __pycache__/ 276 | *.pyc 277 | 278 | # Cake - Uncomment if you are using it 279 | # tools/** 280 | # !tools/packages.config 281 | 282 | # Telerik's JustMock configuration file 283 | *.jmconfig 284 | 285 | # BizTalk build output 286 | *.btp.cs 287 | *.btm.cs 288 | *.odx.cs 289 | *.xsd.cs 290 | -------------------------------------------------------------------------------- /DurangoInteropDotnet.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "editor.formatOnSave": true 9 | }, 10 | "extensions": { 11 | "recommendations": [ 12 | "EditorConfig.EditorConfig", 13 | "ms-dotnettools.csharp", 14 | "esbenp.prettier-vscode" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DurangoInteropDotnet.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurangoInteropDotnet", "src\DurangoInteropDotnet.csproj", "{38F46262-5C51-4D81-B3E3-716FDD6B0A65}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(SolutionProperties) = preSolution 14 | HideSolutionNode = FALSE 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {38F46262-5C51-4D81-B3E3-716FDD6B0A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {38F46262-5C51-4D81-B3E3-716FDD6B0A65}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {38F46262-5C51-4D81-B3E3-716FDD6B0A65}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {38F46262-5C51-4D81-B3E3-716FDD6B0A65}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Xbox One Research Project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/xboxoneresearch/Interop/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/xboxoneresearch/Interop/actions/workflows/build.yml) 2 | ![GitHub Downloads (all assets, latest release)](https://img.shields.io/github/downloads/xboxoneresearch/Interop/latest/total) 3 | [![GitHub latest Tag](https://img.shields.io/github/v/tag/xboxoneresearch/Interop)](https://github.com/xboxoneresearch/Interop/releases/latest) 4 | 5 | # Durango Interop Dotnet 6 | 7 | This repo serves two purposes 8 | 9 | - Full C# classes to interop 10 | - MSBuild tasks that can be ran via dotnet 11 | 12 | [Download latest binaries](https://github.com/xboxoneresearch/Interop/releases/latest) 13 | 14 | ### Dotnet MSBuild tasks 15 | 16 | #### Requirements 17 | 18 | - [Dotnet SDK, x64, Windows, zip](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) 19 | 20 | #### Usage 21 | 22 | - Extract dotnet sdk zip to flash drive 23 | - Copy the tasks to a flash drive 24 | - Execute them via `dotnet.exe msbuild taskname.xml` 25 | 26 | **NOTE**: Some scripts require modifications before being used, f.e. to adjust paths or addresses. 27 | 28 | #### Running in background / as another user 29 | 30 | As SYSTEM 31 | 32 | ``` 33 | schtasks /create /f /tn "MySYSTEMBackgroundTask" /ru SYSTEM /sc ONSTART /tr "D:\dotnet\dotnet.exe msbuild D:\msbuild_tasks\taskname.xml" 34 | schtasks /run /tn "MySYSTEMBackgroundTask" 35 | ``` 36 | 37 | As DefaultAccount 38 | 39 | ``` 40 | schtasks /create /f /tn "MyDABackgroundTask" /ru DefaultAccount /sc ONSTART /tr "D:\dotnet\dotnet.exe msbuild D:\msbuild_tasks\taskname.xml" 41 | schtasks /run /tn "MyDABackgroundTask" 42 | ``` 43 | 44 | ### C# Interop 45 | 46 | #### Requirement 47 | 48 | - Powershell Core (x64 binaries) 49 | 50 | OR 51 | 52 | - [SharpShell](https://github.com/xboxoneresearch/SharpShell) 53 | 54 | #### General 55 | 56 | Build this package (via msbuild) to generate self-contained C# code snippets in the build outputs `pwsh` directory + compiled .NET assembly. 57 | 58 | There are two ways to utilize it, by source code or by loading the .NET assembly (from bytes!). 59 | 60 | ~~NOTE: This currently does not work on 2024 Retail OS exploited consoles.~~ 61 | 62 | For OS ~2024 use SharpShell, linked above! 63 | 64 | #### Example usage by loading the compiled .NET Assembly 65 | 66 | The following snippet is executed via Powershell. 67 | Given `DurangoInteropDotnet.dll` is located in the root of Volume `D:\`. 68 | 69 | ```powershell 70 | $bytes = [System.IO.File]::ReadAllBytes("D:\\DurangoInteropDotnet.dll") 71 | $assembly = [System.Reflection.Assembly]::Load($bytes) 72 | 73 | [LicenseManager]::LoadLicenseFile("O:\\Licenses\\License0.xml") 74 | ``` 75 | 76 | #### Example usage with powershell by loading CSharp source files 77 | 78 | Important: Do the "compiling" genAio step first, to yield the standalone/ready to use *.cs files! 79 | 80 | XCrdAPi 81 | 82 | ```powershell 83 | Add-Type -Path xcrd.cs 84 | $xcrd = [XCrdManager]::new() 85 | 86 | # Mount savegame 87 | $xcrd.Unmount("[XTE:]\ConnectedStorage-retail") 88 | $xcrd.Mount("[XTE:]\ConnectedStorage-retail") 89 | # [+] Opened adapter... 90 | # [+] Successfully mounted XVD! 91 | # [+] Mount Path: \\?\GLOBALROOT\Device\Harddisk15\Partition1 92 | cmd /c mklink /j T:\connectedStorage "\\?\GLOBALROOT\Device\Harddisk15\Partition1\" 93 | 94 | # Read VBI 95 | $xcrd.ReadVbi("R:\A\system.xvd", "T:\system.vbi") 96 | # Alternatively, try these paths: 97 | # $xcrd.ReadVbi("R:\B\system.xvd", "T:\system.vbi") 98 | # $xcrd.ReadVbi("F:\system.xvd", "T:\system.vbi") 99 | ``` 100 | 101 | XcrdUtil 102 | ``` 103 | #Powershell 104 | import-module xcrdutil.psm1 105 | xcrdutil -m [XUC:]\connectedStorage-retail 106 | ``` 107 | 108 | License 109 | 110 | ```powershell 111 | Add-Type -Path license.cs 112 | [LicenseManager]::LoadLicenseFile("S:\Clip\g-u-i-d") 113 | ``` 114 | 115 | -------------------------------------------------------------------------------- /msbuild_tasks/disable_firewall.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /msbuild_tasks/get_tempxvd_owners.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /msbuild_tasks/load_pe_shellcode.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /msbuild_tasks/mount_connectedstorage.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /msbuild_tasks/prepare_gamedump.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | (Guid clsid) 32 | { 33 | var iid = typeof(T).GUID; 34 | var t = COM.CoCreateInstance(ref clsid, null, 4, ref iid, out object factory); 35 | if (t != 0) 36 | { 37 | throw new Exception($"Failed to activate class {typeof(T)}"); 38 | } 39 | 40 | return (T)factory; 41 | } 42 | } 43 | 44 | public static class WinRT 45 | { 46 | public enum RO_INIT_TYPE 47 | { 48 | RO_INIT_SINGLETHREADED = 0, 49 | RO_INIT_MULTITHREADED = 1, 50 | } 51 | 52 | [DllImport("api-ms-win-core-winrt-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 53 | public static extern IntPtr RoInitialize(RO_INIT_TYPE initType); 54 | 55 | [DllImport("api-ms-win-core-winrt-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 56 | public static extern IntPtr RoUninitialize(); 57 | 58 | [DllImport("api-ms-win-core-winrt-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 59 | public static extern IntPtr RoGetActivationFactory(IntPtr activatableClassId, byte[] iid, out IntPtr factory); 60 | 61 | [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 62 | public static extern IntPtr WindowsCreateString([MarshalAs(UnmanagedType.LPWStr)] string sourceString, int length, out IntPtr hstring); 63 | 64 | [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 65 | public static extern IntPtr WindowsDeleteString(IntPtr hstring); 66 | 67 | // A helper to read the virtual function pointer from virtual table of the instance. 68 | public static T GetVirtualMethodPointer(IntPtr instance, int index) 69 | { 70 | var table = Marshal.ReadIntPtr(instance); 71 | var pointer = Marshal.ReadIntPtr(table, index * IntPtr.Size); 72 | return Marshal.GetDelegateForFunctionPointer(pointer); 73 | } 74 | } 75 | 76 | public static class Win32 77 | { 78 | const string KERNELBASE_DLL = "kernelbase.dll"; 79 | const string KERNEL32_DLL = "kernel32.dll"; 80 | 81 | [Flags] 82 | public enum FileAccess : uint 83 | { 84 | GENERIC_READ = 0x80000000, 85 | GENERIC_WRITE = 0x40000000, 86 | GENERIC_EXECUTE = 0x20000000, 87 | GENERIC_ALL = 0x10000000 88 | } 89 | 90 | [Flags] 91 | public enum FileShare : uint 92 | { 93 | FILE_SHARE_READ = 0x00000001, 94 | FILE_SHARE_WRITE = 0x00000002, 95 | FILE_SHARE_DELETE = 0x00000004, 96 | } 97 | 98 | [Flags] 99 | public enum FileMode : uint 100 | { 101 | CREATE_NEW = 1, 102 | CREATE_ALWAYS = 2, 103 | OPEN_EXISTING = 3, 104 | OPEN_ALWAYS = 4, 105 | TRUNCATE_EXISTING = 5 106 | } 107 | 108 | [Flags] 109 | public enum FileAttributes : uint 110 | { 111 | NORMAL = 0x00000080, 112 | HIDDEN = 0x00000002, 113 | READONLY = 0x00000001, 114 | ARCHIVE = 0x00000020, 115 | SYSTEM = 0x00000004 116 | } 117 | 118 | 119 | [DllImport(KERNEL32_DLL, CharSet = CharSet.Ansi, SetLastError = true)] 120 | public static extern IntPtr CreateFileA( 121 | [MarshalAs(UnmanagedType.LPStr)] string filename, 122 | [MarshalAs(UnmanagedType.U4)] FileAccess access, 123 | [MarshalAs(UnmanagedType.U4)] FileShare share, 124 | IntPtr securityAttributes, 125 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 126 | [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, 127 | IntPtr templateFile); 128 | 129 | [DllImport(KERNEL32_DLL, SetLastError = true)] 130 | public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); 131 | 132 | public static void RawRead(string path) 133 | { 134 | IntPtr hFile = CreateFileA(path, Win32.FileAccess.GENERIC_READ, Win32.FileShare.FILE_SHARE_READ | Win32.FileShare.FILE_SHARE_WRITE, IntPtr.Zero, Win32.FileMode.OPEN_EXISTING, 0, IntPtr.Zero); 135 | if (hFile != IntPtr.Zero) 136 | { 137 | if (hFile == INVALID_HANDLE_VALUE) 138 | { 139 | int error = Marshal.GetLastWin32Error(); 140 | Console.WriteLine("GetLastError: " + error); 141 | } 142 | Console.WriteLine("[+] Opened handle to: " + path); 143 | Console.WriteLine("[+] Opened handle to: " + hFile.ToString()); 144 | 145 | uint numBytesRead = 0; 146 | byte[] tmpReadBuffer = new byte[256]; 147 | 148 | bool hasRead = ReadFile(hFile, tmpReadBuffer, 256, out numBytesRead, IntPtr.Zero); 149 | if (!hasRead) 150 | { 151 | Console.WriteLine("[x] Failed to read target :("); 152 | int error = Marshal.GetLastWin32Error(); 153 | Console.WriteLine("GetLastError: " + error); 154 | return; 155 | } 156 | Console.WriteLine("[+] Succesfully read target! Bytes read: " + numBytesRead); 157 | } 158 | } 159 | } 160 | 161 | public static class XCrd 162 | { 163 | [DllImport("xcrdapi.dll", PreserveSig = false)] 164 | public static extern uint XCrdOpenAdapter(out IntPtr hAdapter); 165 | 166 | [DllImport("xcrdapi.dll", PreserveSig = false)] 167 | public static extern uint XCrdCloseAdapter(IntPtr hAdapter); 168 | 169 | [DllImport("xcrdapi.dll", PreserveSig = false)] 170 | public static extern uint XCrdMount(out IntPtr hDevice, IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string crdPath, uint mountFlags); 171 | 172 | [DllImport("xcrdapi.dll", PreserveSig = false)] 173 | public static extern uint XCrdUnmount(IntPtr hAdapter, IntPtr hDevice); 174 | 175 | [DllImport("xcrdapi.dll", PreserveSig = false)] 176 | public static extern uint XCrdDeleteXVD(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string crdPath, uint flags); 177 | 178 | [DllImport("xcrdapi.dll", PreserveSig = false)] 179 | public static extern uint XCrdUnmountByPath(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string crdPath); 180 | 181 | [DllImport("xcrdapi.dll", PreserveSig = false)] 182 | public static extern uint XCrdQueryDevicePath([MarshalAs(UnmanagedType.LPWStr)] out string devicePath, IntPtr hDeviceHandle); 183 | 184 | [DllImport("xcrdapi.dll", PreserveSig = false)] 185 | public static extern uint XCrdStreamingStart( 186 | out IntPtr hStreamAdapter, 187 | IntPtr hAdapter, 188 | [MarshalAs(UnmanagedType.LPWStr)] string xcrdSourcePath, 189 | [MarshalAs(UnmanagedType.LPWStr)] string unkPath, 190 | [MarshalAs(UnmanagedType.LPWStr)] string xcrdDestPath, 191 | [MarshalAs(UnmanagedType.LPWStr)] string unkPath2, 192 | [MarshalAs(UnmanagedType.LPWStr)] string unkPath3, 193 | uint SpecifierCount, 194 | IntPtr Specifiers, 195 | uint Flags, 196 | out ulong DstSize, 197 | out IntPtr ErrorSource 198 | ); 199 | [DllImport("xcrdapi.dll", PreserveSig = false)] 200 | public static extern uint XCrdStreamingStop(IntPtr hAdapter, IntPtr hInstance, uint flags); 201 | [DllImport("xcrdapi.dll", PreserveSig = false)] 202 | public static extern uint XCrdStreamingQueryActiveInstanceId(IntPtr hAdapter, out IntPtr hInstanceId); 203 | [DllImport("xcrdapi.dll", PreserveSig = false)] 204 | // QueryInformation untested 205 | public static extern uint XCrdStreamingQueryInformation(IntPtr info, IntPtr hAdapter, IntPtr hInstance); 206 | 207 | 208 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 209 | public struct XvdStreamingInfo 210 | { 211 | public ulong StreamId; // 0x00 212 | 213 | ulong Unknown08; // 0x08 - UNKNOWN 214 | 215 | public ulong StreamedBytes; // 0x10 216 | public ulong SourceStreamedBytes; // 0x18 217 | public ulong CacheStreamedBytes; // 0x20 218 | public ulong UpdateStreamedBytes; // 0x28 219 | public ulong FallbackStreamedBytes; // 0x30 220 | 221 | ulong Unknown38; // 0x38 - UNKNOWN 222 | 223 | public ulong DownloadSize; // 0x40 224 | public ulong StagingSize; // 0x48 225 | public ulong BlobSize; // 0x50 226 | public ulong ActiveRegion; // 0x58 227 | public ulong ActiveRegionStreamedBytes; // 0x60 228 | public ulong RegionCount; // 0x68 229 | public ulong StreamedRegionCount; // 0x70 230 | public uint InitialPlayRegionId; // 0x78 231 | public uint CacheLastIoStatus; // 0x7C 232 | public ulong InitialPlayRegionOffset; // 0x80 233 | public ulong PaddingBytes; // 0x88 234 | public uint SourceLastIoStatus; // 0x90 235 | public uint DestinationLastIoStatus; // 0x94 236 | public uint SourceStreaming; // 0x98 237 | public uint RegionSpecifierCount; // 0x9C 238 | public uint StreamingDisc; // 0xA0 239 | public uint NeededDisc; // 0xA4 240 | public ulong SegmentCount; // 0xA8 241 | 242 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] 243 | byte[] UnknownB0; // 0xB0 - MISSING 244 | 245 | public ulong XipMissBytes; // 0xC0 246 | public uint XipMissCount; // 0xC8 247 | public uint XipReadAhead; // 0xCC 248 | public Guid StreamingPlanId; // 0xD0 249 | public ulong FsDefragmentedBytes; // 0xE0 250 | public ulong FsDefragmentedRequiredBytes; // 0xE8 251 | public ulong NandDefragmentedBytes; // 0xF0 252 | public ulong NandDefragmentRequiredBytes; // 0xF8 253 | 254 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 255 | public byte[] Reserved; // 0x100 256 | /* END 0x110 */ 257 | } 258 | } 259 | 260 | public class XCrdManager : IDisposable 261 | { 262 | const int CHUNK_SIZE = 16 * 1024 * 1024; // 16MB 263 | readonly IntPtr _adapterHandle; 264 | 265 | public XCrdManager() 266 | { 267 | uint result = XCrd.XCrdOpenAdapter(out IntPtr hAdapter); 268 | if (hAdapter == IntPtr.Zero) 269 | { 270 | throw new Exception($"Failed to open XCRD adapter, code: {result:08x}"); 271 | } 272 | _adapterHandle = hAdapter; 273 | } 274 | 275 | public string Mount(string xvdPath) 276 | { 277 | uint result = XCrd.XCrdMount(out IntPtr hDevice, _adapterHandle, xvdPath, 0); 278 | if (result != 0 || hDevice == IntPtr.Zero) 279 | { 280 | Console.WriteLine("Failed to mount target! Result: " + result); 281 | return null; 282 | } 283 | 284 | result = XCrd.XCrdQueryDevicePath(out string devicePath, hDevice); 285 | if (result != 0) 286 | { 287 | Console.WriteLine("Failed to read device path! Result: " + result); 288 | return null; 289 | } 290 | 291 | return devicePath; 292 | } 293 | 294 | /// 295 | /// Unmount an XVD based on XCRD path (host-relevant path) 296 | /// 297 | /// 298 | /// 0 on success 299 | public uint Unmount(string xcrdPath) 300 | { 301 | uint result = XCrd.XCrdUnmountByPath(_adapterHandle, xcrdPath); 302 | if (result != 0) 303 | { 304 | Console.WriteLine("[x] Failed to unmount target xvd!"); 305 | Console.WriteLine("[x] Result: " + result); 306 | return result; 307 | } 308 | Console.WriteLine("Unmounted successfully"); 309 | return 0; 310 | } 311 | 312 | public uint DeleteXVD(string xvdPath) 313 | { 314 | uint result = XCrd.XCrdDeleteXVD(_adapterHandle, xvdPath, 0); 315 | if (result != 0) 316 | { 317 | Console.WriteLine("[x] Failed to delete xvd! Result:" + result.ToString()); 318 | } 319 | return result; 320 | } 321 | 322 | string StreamingInfoToString(XCrd.XvdStreamingInfo info) 323 | { 324 | StringBuilder sb = new(); 325 | sb.AppendFormat("Active Region = 0x{0:X16}\n", info.ActiveRegion); 326 | sb.AppendFormat("Active Region Streamed Bytes = 0x{0:X16}\n", info.ActiveRegionStreamedBytes); 327 | sb.AppendFormat("Blob Size = 0x{0:X16}\n", info.BlobSize); 328 | sb.AppendFormat("Staging Size = 0x{0:X16}\n", info.StagingSize); 329 | sb.AppendFormat("Initial Play Region Id = 0x{0:X}\n", info.InitialPlayRegionId); 330 | sb.AppendFormat("Initial Play Region Offset = 0x{0:X16}\n", info.InitialPlayRegionOffset); 331 | sb.AppendFormat("Region Count = 0x{0:X16}\n", info.RegionCount); 332 | sb.AppendFormat("Segment Count = 0x{0:X16}\n", info.SegmentCount); 333 | sb.AppendFormat("Region Specifier Count = 0x{0:X}\n", info.RegionSpecifierCount); 334 | sb.AppendFormat("Streamed Region Count = 0x{0:X16}\n", info.StreamedRegionCount); 335 | sb.AppendFormat("Streamed Bytes = 0x{0:X16}\n", info.StreamedBytes); 336 | sb.AppendFormat("Source Streamed Bytes = 0x{0:X16}\n", info.SourceStreamedBytes); 337 | sb.AppendFormat("Cache Streamed Bytes = 0x{0:X16}\n", info.CacheStreamedBytes); 338 | sb.AppendFormat("Update Streamed Bytes = 0x{0:X16}\n", info.UpdateStreamedBytes); 339 | sb.AppendFormat("Fallback Streamed Bytes = 0x{0:X16}\n", info.FallbackStreamedBytes); 340 | sb.AppendFormat("Padding Bytes = 0x{0:X16}\n", info.PaddingBytes); 341 | sb.AppendFormat("Stream ID = 0x{0:X16}\n", info.StreamId); 342 | sb.AppendFormat("Download Size = 0x{0:X16}\n", info.DownloadSize); 343 | sb.AppendFormat("Source Last Io Status = 0x{0:X}\n", info.SourceLastIoStatus); 344 | sb.AppendFormat("Cache Last Io Status = 0x{0:X}\n", info.CacheLastIoStatus); 345 | sb.AppendFormat("Destination Last Io Status = 0x{0:X}\n", info.DestinationLastIoStatus); 346 | sb.AppendFormat("Source Streaming = {0:X}\n", info.SourceStreaming); 347 | // sb.AppendFormat("Cache Streaming = {0:X}"); 348 | // sb.AppendFormat("Update Streaming = {0:X}"); 349 | // sb.AppendFormat("FS Defragmenting = {0:X}"); 350 | // sb.AppendFormat("NAND Defragmenting = {0:X}"); 351 | sb.AppendFormat("Streaming Disc = {0:X}\n", info.StreamingDisc); 352 | sb.AppendFormat("Needed Disc = {0:X}\n", info.NeededDisc); 353 | sb.AppendFormat("XIP Miss Bytes = {0:X}\n", info.XipMissBytes); 354 | sb.AppendFormat("XIP Miss Count = {0:X}\n", info.XipMissCount); 355 | sb.AppendFormat("XIP Read Ahead (s) = {0:X}\n", info.XipReadAhead); 356 | // sb.AppendFormat("XIP Plan Type = {0}"); 357 | sb.AppendFormat("Streaming Plan Id = {0}\n", info.StreamingPlanId); 358 | sb.AppendFormat("FS Defragmented Bytes = {0:X}\n", info.FsDefragmentedBytes); 359 | sb.AppendFormat("FS Defragment Required Bytes = {0:X}\n", info.FsDefragmentedRequiredBytes); 360 | sb.AppendFormat("NAND Defragmented Bytes = {0:X}\n", info.NandDefragmentedBytes); 361 | sb.AppendFormat("NAND Defragment Required Bytes= {0:X}\n", info.NandDefragmentRequiredBytes); 362 | 363 | return sb.ToString(); 364 | } 365 | 366 | public uint Stream(string srcPath, string dstPath) 367 | { 368 | uint result = XCrd.XCrdStreamingStart( 369 | out IntPtr hInstanceId, 370 | _adapterHandle, 371 | srcPath, 372 | null, 373 | dstPath, 374 | null, 375 | null, 376 | 0, 377 | IntPtr.Zero, 378 | 0, 379 | out ulong dstSize, 380 | out IntPtr errorSource 381 | ); 382 | 383 | if (result != 0) 384 | { 385 | Console.WriteLine("Starting streaming failed: " + result.ToString()); 386 | return result; 387 | } 388 | Console.WriteLine("Streaming handle: 0x{0:X}", hInstanceId); 389 | 390 | IntPtr ptrInfoBuf = Marshal.AllocHGlobal(Marshal.SizeOf()); 391 | if (ptrInfoBuf == IntPtr.Zero) 392 | { 393 | Console.WriteLine("Failed to allocate XvdStreamingInfo buffer"); 394 | return 1; 395 | } 396 | 397 | while (true) 398 | { 399 | result = XCrd.XCrdStreamingQueryInformation(ptrInfoBuf, _adapterHandle, hInstanceId); 400 | if (result != 0) 401 | { 402 | Console.WriteLine("Failed to query streaming infos: " + result.ToString()); 403 | Marshal.FreeHGlobal(ptrInfoBuf); 404 | return result; 405 | } 406 | 407 | var streamingInfo = Marshal.PtrToStructure(ptrInfoBuf); 408 | Console.WriteLine(":: Streaming Info ::\n{0}", StreamingInfoToString(streamingInfo)); 409 | 410 | if (streamingInfo.BlobSize == streamingInfo.StreamedBytes) 411 | { 412 | Console.WriteLine("Streaming of {0:X16} bytes finished!", streamingInfo.StreamedBytes); 413 | break; 414 | } 415 | 416 | // Wait 5 seconds between queries 417 | Thread.Sleep(1000 * 5); 418 | } 419 | 420 | Marshal.FreeHGlobal(ptrInfoBuf); 421 | 422 | Console.WriteLine("Stopping streaming"); 423 | result = XCrd.XCrdStreamingStop(_adapterHandle, hInstanceId, 0); 424 | if (result != 0) 425 | { 426 | Console.WriteLine("Failed to stop streaming: " + result.ToString()); 427 | } 428 | 429 | return result; 430 | } 431 | 432 | public void Dispose() 433 | { 434 | if (_adapterHandle != IntPtr.Zero) 435 | { 436 | XCrd.XCrdCloseAdapter(_adapterHandle); 437 | } 438 | } 439 | } 440 | 441 | [Guid("2769c3a8-d8e3-41ba-b38b-01d05dd2374e")] 442 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 443 | public interface IClipLicenseManager 444 | { 445 | void StoreLicense(string licenseBuffer, uint flags, out IntPtr clipLicense); 446 | } 447 | 448 | public class LicenseManager 449 | { 450 | static readonly Guid CLSID = new Guid("7e480b22-b679-4542-9b30-d5a52da92ce5"); 451 | static readonly IClipLicenseManager _manager; 452 | 453 | static LicenseManager() 454 | { 455 | COM.CoInitializeEx(IntPtr.Zero, 0); 456 | 457 | _manager = COM.ActivateClass(CLSID); 458 | } 459 | 460 | /// 461 | /// Loads a full license (base64 representation of the license.xml) 462 | /// 463 | /// 464 | /// true on success, false otherwise 465 | public static bool LoadLicenseBase64(string licenseBuffer) 466 | { 467 | _manager.StoreLicense(licenseBuffer, 0x1, out IntPtr license); 468 | return license != IntPtr.Zero; 469 | } 470 | 471 | public static bool LoadLicenseFile(string filePath) 472 | { 473 | // 474 | // Read and convert license contents to base64 475 | // Just assume the license is valid, it'll fail anyway if it's not 476 | // 477 | string content = File.ReadAllText(filePath); 478 | if (string.IsNullOrEmpty(content)) 479 | { 480 | throw new InvalidDataException("Provided file is empty"); 481 | } 482 | 483 | var licenseBlob = Encoding.UTF8.GetBytes(content); 484 | var base64Blob = Convert.ToBase64String(licenseBlob); 485 | return LoadLicenseBase64(base64Blob); 486 | } 487 | } 488 | 489 | /* EDIT ME */ 490 | 491 | const string TEMP_XVD_PATH = @"[XTE:]\temp00"; // Replace with temp of exploited game 492 | const string SRC_XVC_PATH = @"[XUC:]\PUT-CONTENT-ID-OF-GAME-HERE"; 493 | const string LICENSE_FILE = @"S:\Clip\PUT-LICENSE-FILE-NAME-HERE"; 494 | 495 | /* EDIT END */ 496 | 497 | public override bool Execute() 498 | { 499 | Console.WriteLine("Start!"); 500 | 501 | var xcrd = new XCrdManager(); 502 | uint result = 0; 503 | 504 | try { 505 | result = xcrd.DeleteXVD(TEMP_XVD_PATH); 506 | if (result != 0) 507 | Console.WriteLine($"[-] DeleteXVD failed, result: {result}"); 508 | } catch (System.IO.FileNotFoundException) { 509 | Console.WriteLine($"[-] DeleteXVD failed, File was probably already deleted (no worries!)"); 510 | } 511 | 512 | result = xcrd.Stream(SRC_XVC_PATH, TEMP_XVD_PATH); 513 | if (result != 0) 514 | return false; 515 | 516 | if (!LicenseManager.LoadLicenseFile(LICENSE_FILE)) 517 | { 518 | Console.WriteLine("[-] Failed to load license file!"); 519 | return false; 520 | } 521 | Console.WriteLine("[+] License file loaded"); 522 | return true; 523 | } 524 | ]]> 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | -------------------------------------------------------------------------------- /msbuild_tasks/registry_dump.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {dumpPath}"); 156 | } 157 | 158 | return true; 159 | } 160 | ]]> 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /msbuild_tasks/xbfs_backup.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 48 | /// Read raw flash image. 49 | /// 50 | /// Filepath to save the flashdump. 51 | /// Zero on success, Non-Zero on failure 52 | public static int ReadFlashImage(string outputFile) 53 | { 54 | return ReadInternal(RawFlashDeviceName, outputFile); 55 | } 56 | 57 | /// 58 | /// Read single file from flash filesystem. 59 | /// 60 | /// Filename of file to read. 61 | /// Filepath to save the file. 62 | /// Zero on success, Non-Zero on failure 63 | public static int ReadFlashFsFile(string targetFile, string outputFile) 64 | { 65 | string fullpath = FlashDeviceName + "\\" + targetFile; 66 | return ReadInternal(fullpath, outputFile); 67 | } 68 | 69 | /// 70 | /// Reads from opened DeviceHandle until EOF is signalled. 71 | /// 72 | /// Full device path (e.g. \\.\Xvuc\FlashFs\filename.bin) 73 | /// Filepath to save the file. 74 | /// Zero on success, Non-Zero on failure 75 | public static int ReadInternal(string devicePath, string outputFile) 76 | { 77 | IntPtr pHandle = KernelBase.CreateFile( 78 | devicePath, 79 | System.IO.FileAccess.Read, 80 | System.IO.FileShare.ReadWrite, 81 | IntPtr.Zero, 82 | System.IO.FileMode.Open, 83 | System.IO.FileAttributes.Normal, 84 | IntPtr.Zero 85 | ); 86 | 87 | if (pHandle == IntPtr.Zero) 88 | { 89 | Console.WriteLine("Failed to get handle to {0}", devicePath); 90 | return -3; 91 | } 92 | 93 | bool success = false; 94 | uint numBytesRead = 0; 95 | ulong bytesReadTotal = 0; 96 | byte[] buf = new byte[1024 * 1024]; // 1 MB 97 | 98 | using (FileStream fsOutputFile = new FileStream(outputFile, FileMode.Create, FileAccess.Write)) 99 | { 100 | do 101 | { 102 | success = KernelBase.ReadFile(pHandle, buf, (uint)buf.Length, out numBytesRead, IntPtr.Zero); 103 | if (!success && bytesReadTotal == 0 && numBytesRead == 0) 104 | { 105 | Console.WriteLine("Failed to ReadFile {0}, error: 0x{1:X}", devicePath, KernelBase.GetLastError()); 106 | KernelBase.CloseHandle(pHandle); 107 | return -4; 108 | } 109 | fsOutputFile.Write(buf, 0, (int)numBytesRead); 110 | bytesReadTotal += numBytesRead; 111 | } 112 | while (numBytesRead > 0); 113 | } 114 | Console.WriteLine("Read {0} bytes", bytesReadTotal); 115 | KernelBase.CloseHandle(pHandle); 116 | return 0; 117 | } 118 | 119 | public override bool Execute() 120 | { 121 | Console.WriteLine("[+] Reading XBFS flash"); 122 | ReadFlashImage(FLASH_DUMP_PATH); 123 | Console.WriteLine("[*] Flashdump finished!"); 124 | return true; 125 | } 126 | ]]> 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /src/00_GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using System; 2 | global using System.IO; 3 | global using System.Text; 4 | global using System.Threading; 5 | global using System.Collections.Generic; 6 | global using System.Security.Principal; 7 | global using System.Runtime.CompilerServices; 8 | global using System.Runtime.InteropServices; 9 | -------------------------------------------------------------------------------- /src/01_Interop.cs: -------------------------------------------------------------------------------- 1 | public static class COM 2 | { 3 | [DllImport("ole32.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] 4 | public static extern int CoInitializeEx([In, Optional] IntPtr pvReserved, [In] uint dwCoInit); 5 | 6 | [DllImport("combase.dll")] 7 | public static extern uint CoCreateInstance(ref Guid clsid, [MarshalAs(UnmanagedType.IUnknown)] object inner, uint context, ref Guid uuid, [MarshalAs(UnmanagedType.IUnknown)] out object rReturnedComObject); 8 | 9 | 10 | public static T ActivateClass(Guid clsid) 11 | { 12 | var iid = typeof(T).GUID; 13 | var t = COM.CoCreateInstance(ref clsid, null, 4, ref iid, out object factory); 14 | if (t != 0) 15 | { 16 | throw new Exception($"Failed to activate class {typeof(T)}"); 17 | } 18 | 19 | return (T)factory; 20 | } 21 | } 22 | 23 | public static class WinRT 24 | { 25 | public enum RO_INIT_TYPE 26 | { 27 | RO_INIT_SINGLETHREADED = 0, 28 | RO_INIT_MULTITHREADED = 1, 29 | } 30 | 31 | [DllImport("api-ms-win-core-winrt-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 32 | public static extern IntPtr RoInitialize(RO_INIT_TYPE initType); 33 | 34 | [DllImport("api-ms-win-core-winrt-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 35 | public static extern IntPtr RoUninitialize(); 36 | 37 | [DllImport("api-ms-win-core-winrt-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 38 | public static extern IntPtr RoGetActivationFactory(IntPtr activatableClassId, byte[] iid, out IntPtr factory); 39 | 40 | [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 41 | public static extern IntPtr WindowsCreateString([MarshalAs(UnmanagedType.LPWStr)] string sourceString, int length, out IntPtr hstring); 42 | 43 | [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] 44 | public static extern IntPtr WindowsDeleteString(IntPtr hstring); 45 | 46 | // A helper to read the virtual function pointer from virtual table of the instance. 47 | public static T GetVirtualMethodPointer(IntPtr instance, int index) 48 | { 49 | var table = Marshal.ReadIntPtr(instance); 50 | var pointer = Marshal.ReadIntPtr(table, index * IntPtr.Size); 51 | return Marshal.GetDelegateForFunctionPointer(pointer); 52 | } 53 | } 54 | 55 | public static class Win32 56 | { 57 | const string KERNELBASE_DLL = "kernelbase.dll"; 58 | const string KERNEL32_DLL = "kernel32.dll"; 59 | 60 | [Flags] 61 | public enum FileAccess : uint 62 | { 63 | GENERIC_READ = 0x80000000, 64 | GENERIC_WRITE = 0x40000000, 65 | GENERIC_EXECUTE = 0x20000000, 66 | GENERIC_ALL = 0x10000000 67 | } 68 | 69 | [Flags] 70 | public enum FileShare : uint 71 | { 72 | FILE_SHARE_READ = 0x00000001, 73 | FILE_SHARE_WRITE = 0x00000002, 74 | FILE_SHARE_DELETE = 0x00000004, 75 | } 76 | 77 | [Flags] 78 | public enum FileMode : uint 79 | { 80 | CREATE_NEW = 1, 81 | CREATE_ALWAYS = 2, 82 | OPEN_EXISTING = 3, 83 | OPEN_ALWAYS = 4, 84 | TRUNCATE_EXISTING = 5 85 | } 86 | 87 | [Flags] 88 | public enum FileAttributes : uint 89 | { 90 | NORMAL = 0x00000080, 91 | HIDDEN = 0x00000002, 92 | READONLY = 0x00000001, 93 | ARCHIVE = 0x00000020, 94 | SYSTEM = 0x00000004 95 | } 96 | 97 | 98 | [DllImport(KERNEL32_DLL, CharSet = CharSet.Ansi, SetLastError = true)] 99 | public static extern IntPtr CreateFileA( 100 | [MarshalAs(UnmanagedType.LPStr)] string filename, 101 | [MarshalAs(UnmanagedType.U4)] FileAccess access, 102 | [MarshalAs(UnmanagedType.U4)] FileShare share, 103 | IntPtr securityAttributes, 104 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 105 | [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, 106 | IntPtr templateFile); 107 | 108 | [DllImport(KERNEL32_DLL, SetLastError = true)] 109 | public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); 110 | 111 | public static void RawRead(string path) 112 | { 113 | IntPtr hFile = CreateFileA(path, Win32.FileAccess.GENERIC_READ, Win32.FileShare.FILE_SHARE_READ | Win32.FileShare.FILE_SHARE_WRITE, IntPtr.Zero, Win32.FileMode.OPEN_EXISTING, 0, IntPtr.Zero); 114 | if (hFile != IntPtr.Zero) 115 | { 116 | if (hFile == (IntPtr.Zero - 1)) 117 | { 118 | int error = Marshal.GetLastWin32Error(); 119 | Console.WriteLine("GetLastError: " + error); 120 | } 121 | Console.WriteLine("[+] Opened handle to: " + path); 122 | Console.WriteLine("[+] Opened handle to: " + hFile.ToString()); 123 | 124 | uint numBytesRead = 0; 125 | byte[] tmpReadBuffer = new byte[256]; 126 | 127 | bool hasRead = ReadFile(hFile, tmpReadBuffer, 256, out numBytesRead, IntPtr.Zero); 128 | if (!hasRead) 129 | { 130 | Console.WriteLine("[x] Failed to read target :("); 131 | int error = Marshal.GetLastWin32Error(); 132 | Console.WriteLine("GetLastError: " + error); 133 | return; 134 | } 135 | Console.WriteLine("[+] Succesfully read target! Bytes read: " + numBytesRead); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/AppPackageMountManager.cs: -------------------------------------------------------------------------------- 1 | [Guid("CC31D32A-A46C-4EB0-A395-66B6D8AB1CC4")] 2 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 3 | public interface IAppPackageMountManager 4 | { 5 | void MountForFileIO(string packageFullName, uint target, int type); 6 | void UnmountForFileIO(string packageFullName, uint target); 7 | string MountTitleDeveloperScratch(); 8 | void UnmountTitleDeveloperScratch(); 9 | void PrepareForActivation(string packageFullName, string psmKey, int packageType); 10 | void CleanupAfterDeactivation(string packageFullName, string psmKey); 11 | void CleanupAfterUninstall(string packageFullName); 12 | void GetPathForTarget(string packageFullName, uint target, [MarshalAs(UnmanagedType.LPWStr)] out string path); 13 | } 14 | 15 | [Guid("b54e912f-c1f4-470d-b841-c59db24be3b7")] 16 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 17 | public interface IAppPackageMountManagerInternal 18 | { 19 | bool IsXCrdMountable(string xcrd); 20 | void UnmountForUninstall(string packageFullName); 21 | void AttachMount(string packageFullName, string crdPath, int type); 22 | } 23 | 24 | public class AppPackageMountManager 25 | { 26 | static readonly Guid CLSID = new Guid("8D2C2449-D1F1-4EB5-835A-D0DD0E5CAD36"); 27 | static readonly IAppPackageMountManager _manager; 28 | static readonly IAppPackageMountManagerInternal _managerInternal; 29 | 30 | static AppPackageMountManager() 31 | { 32 | COM.CoInitializeEx(IntPtr.Zero, 0); 33 | 34 | _manager = COM.ActivateClass(CLSID); 35 | _managerInternal = COM.ActivateClass(CLSID); 36 | } 37 | 38 | public string GetMountPath(string packageFullName) 39 | { 40 | _manager.GetPathForTarget(packageFullName, 0x00000001, out string mountPath); 41 | if (string.IsNullOrEmpty(mountPath)) 42 | { 43 | throw new InvalidDataException("Invalid mount path!"); 44 | } 45 | return mountPath; 46 | } 47 | 48 | public static void AttachMount(string packageFullName, string crdPath) 49 | { 50 | _managerInternal.AttachMount(packageFullName, crdPath, 1); 51 | } 52 | 53 | public static void MountPackage(string packageFullName) 54 | { 55 | _manager.MountForFileIO(packageFullName, 0x00000001, 1); 56 | } 57 | 58 | public static void UnmountPackage(string packageFullName) 59 | { 60 | _manager.UnmountForFileIO(packageFullName, 0x00000001); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/DurangoInteropDotnet.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0-windows 5 | enable 6 | disable 7 | true 8 | 9 | 10 | 11 | 12 | 13 | aio.cs 14 | 15 | 16 | xcrd.cs 17 | 18 | 19 | license.cs 20 | 21 | 22 | usermanager.cs 23 | 24 | 25 | packagemount.cs 26 | 27 | 28 | winuser.cs 29 | 30 | 31 | sc.cs 32 | 33 | 34 | xcrdutil.psm1 35 | 36 | 37 | 38 | 39 | 43 | 44 | 45 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/FirewallManager.cs: -------------------------------------------------------------------------------- 1 |  2 | /* 3 | Supports disabling of default firewalls and opening up ports that can be accessed remotely. 4 | 5 | .NET port of landaire's hard work: https://github.com/exploits-forsale/solstice/blob/main/crates/solstice_daemon/src/firewall.rs 6 | 7 | Example API usage: 8 | ``` 9 | FirewallManager.DisableFirewalls(); 10 | FirewallManager.AllowPortThroughFirewall("Debugger", 23946); 11 | FirewallManager.AllowPortThroughFirewall("SSH", 22); 12 | ``` 13 | 14 | Example E2E usage: 15 | 1. Copy .NET to `D:\XBOX\dotnet\` 16 | 2. Copy this DLL (`DurangoInteropDotnet.dll`) to `D:\XBOX\payloads\` 17 | 3. Copy `msbuild_tasks/disable_firewall.xml` to `D:\XBOX\payloads\disable_firewall.xml` 18 | 4. Execute the following commands: 19 | ``` 20 | set DOTNET_CLI_TELEMETRY_OPTOUT=1 21 | set DOTNET_EnableWriteXorExecute=0 22 | D:\XBOX\dotnet\dotnet.exe msbuild "D:\XBOX\payloads\disable_firewall.xml" 23 | ``` 24 | */ 25 | using System.Runtime.InteropServices.ComTypes; 26 | 27 | namespace DurangoInteropDotnet { 28 | 29 | public static class FirewallManager { 30 | 31 | private static readonly string FWPM_DISPLAY_NAME = "XOR"; 32 | private static readonly string FWPM_DISPLAY_DESCRIPTION = "XOR FWPM Provider"; 33 | private static readonly Guid FWPM_PROVIDER_GUID = new Guid(0xabad1dea, 0x4141, 0x4141, 0x0, 0x0, 0x0c, 0x0f, 0xfe, 0xe0, 0x00, 0x00); 34 | private static readonly Guid CLSID_HNETCFGFWPOLICY2 = new Guid("e2b3c97f-6ae1-41ac-817a-f6f92166d7dd"); 35 | private static readonly Guid CLSID_INETFWPOLICY2 = new Guid("98325047-C671-4174-8D81-DEFCD3F03186"); 36 | 37 | public static void DisableFirewalls() { 38 | 39 | uint result = NativeBridge.CoInitializeEx(IntPtr.Zero, NativeBridge.COINIT.COINIT_MULTITHREADED); 40 | if (result != 0 && result != 1) { // 0 = S_OK, 1 = S_FALSE 41 | throw new Exception($"CoInitializeEx returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 42 | } 43 | 44 | IntPtr pINetFwPolicy2 = IntPtr.Zero; 45 | result = NativeBridge.CoCreateInstance(CLSID_HNETCFGFWPOLICY2, IntPtr.Zero, NativeBridge.CLSCTX.ALL, CLSID_INETFWPOLICY2, out pINetFwPolicy2); 46 | if (result != 0) { 47 | // 0x80040110 = CLASS_E_NOAGGREGATION 48 | // 0x80040154 = REGDB_E_CLASSNOTREG 49 | throw new Exception($"CoCreateInstance returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 50 | } 51 | if (pINetFwPolicy2 == IntPtr.Zero) { 52 | throw new Exception($"pINetFwPolicy2 is null (Error: 0x{Marshal.GetLastWin32Error():X})"); 53 | } 54 | NativeBridge.INetFwPolicy2 iNetFwPolicy2 = (NativeBridge.INetFwPolicy2)Marshal.GetObjectForIUnknown(pINetFwPolicy2); 55 | 56 | /* 57 | foreach (NetFwProfileType2 profileType in new NetFwProfileType2[] { NetFwProfileType2.Public, NetFwProfileType2.Private, NetFwProfileType2.Domain }) { 58 | Console.WriteLine($"Profile Type: {profileType}"); 59 | try { 60 | Console.WriteLine($"\tFirewallEnabled: {iNetFwPolicy2.get_FirewallEnabled(profileType)}"); 61 | Console.WriteLine($"\tBlockAllInboundTraffic: {iNetFwPolicy2.get_BlockAllInboundTraffic(profileType)}"); 62 | Console.WriteLine($"\tDefaultInboundAction: {iNetFwPolicy2.get_DefaultInboundAction(profileType)}"); 63 | Console.WriteLine($"\tNotificationsDisabled: {iNetFwPolicy2.get_NotificationsDisabled(profileType)}"); 64 | } 65 | catch (Exception e) { 66 | Console.WriteLine($"{e.Message}"); 67 | } 68 | } 69 | */ 70 | 71 | //Console.WriteLine($"Updating profiles"); 72 | foreach (NativeBridge.NetFwProfileType2 profileType in new NativeBridge.NetFwProfileType2[] { NativeBridge.NetFwProfileType2.Public, NativeBridge.NetFwProfileType2.Private, NativeBridge.NetFwProfileType2.Domain }) { 73 | // Console.WriteLine($"Modifying profile Type: {profileType}"); 74 | 75 | try { 76 | iNetFwPolicy2.set_BlockAllInboundTraffic(profileType, false); 77 | } catch (Exception e) { 78 | throw new Exception("Unable to set BlockAllInboundTraffic", e); 79 | } 80 | 81 | try { 82 | iNetFwPolicy2.set_FirewallEnabled(profileType, false); 83 | } catch (Exception e) { 84 | throw new Exception("Unable to set FirewallEnabled", e); 85 | } 86 | 87 | try { 88 | iNetFwPolicy2.set_DefaultInboundAction(profileType, NativeBridge.NetFwAction.Allow); 89 | } catch (Exception e) { 90 | throw new Exception("Unable to set DefaultInboundAction", e); 91 | } 92 | 93 | try { 94 | iNetFwPolicy2.set_NotificationsDisabled(profileType, true); 95 | } catch (Exception e) { 96 | throw new Exception("Unable to set NotificationsDisabled", e); 97 | } 98 | } 99 | 100 | /* 101 | Console.WriteLine($"#### Verifying profiles"); 102 | foreach (NetFwProfileType2 profileType in new NetFwProfileType2[] { NetFwProfileType2.Public, NetFwProfileType2.Private, NetFwProfileType2.Domain }) { 103 | Console.WriteLine($"Profile Type: {profileType}"); 104 | try { 105 | Console.WriteLine($"\tFirewallEnabled: {iNetFwPolicy2.get_FirewallEnabled(profileType)}"); 106 | Console.WriteLine($"\tBlockAllInboundTraffic: {iNetFwPolicy2.get_BlockAllInboundTraffic(profileType)}"); 107 | Console.WriteLine($"\tDefaultInboundAction: {iNetFwPolicy2.get_DefaultInboundAction(profileType)}"); 108 | Console.WriteLine($"\tNotificationsDisabled: {iNetFwPolicy2.get_NotificationsDisabled(profileType)}"); 109 | } 110 | catch (Exception e) { 111 | Console.WriteLine($"{e.Message}"); 112 | } 113 | } 114 | */ 115 | 116 | // Console.WriteLine($"Disabled the firewall"); 117 | } 118 | 119 | public static void AllowPortThroughFirewall(string name, ushort port) { 120 | 121 | var engine = OpenFWPSession(); 122 | try { 123 | InstallFWPMProvider(engine); 124 | BuildAndAddFWPPortFilter(name, port, NativeBridge.FirewallLayerGuids.FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, engine); 125 | } 126 | finally { 127 | CloseFWPSession(engine); 128 | } 129 | 130 | // Console.WriteLine($"Opened up port {port} ({name}) in the firewall"); 131 | } 132 | 133 | private static IntPtr OpenFWPSession() { 134 | IntPtr IntPtr = IntPtr.Zero; 135 | var result = NativeBridge.FwpmEngineOpen0(IntPtr.Zero, (uint)NativeBridge.RPC_C_AUTHN_DEFAULT, IntPtr.Zero, IntPtr.Zero, ref IntPtr); 136 | if (result != 0) { 137 | throw new Exception($"FwpmEngineOpen0 returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 138 | } 139 | // Console.WriteLine($"Opened FWPM Engine: 0x{IntPtr:X}"); 140 | 141 | return IntPtr; 142 | } 143 | 144 | private static void CloseFWPSession(IntPtr IntPtr) { 145 | var result = NativeBridge.FwpmEngineClose0(IntPtr); 146 | if (result != 0) { 147 | throw new Exception($"FwpmEngineClose0 returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 148 | } 149 | // Console.WriteLine($"Closed FWPM Engine: 0x{IntPtr:X}"); 150 | } 151 | 152 | private static void InstallFWPMProvider(IntPtr IntPtr) { 153 | 154 | var provider = new NativeBridge.FWPM_PROVIDER0 { 155 | providerKey = FWPM_PROVIDER_GUID, 156 | displayData = new NativeBridge.FWPM_DISPLAY_DATA0 { 157 | name = FWPM_DISPLAY_NAME, 158 | description = FWPM_DISPLAY_DESCRIPTION, 159 | }, 160 | flags = NativeBridge.FirewallProviderFlags.Persistent, 161 | }; 162 | 163 | uint result = NativeBridge.FwpmTransactionBegin0(IntPtr, 0); 164 | if (result != 0) { 165 | throw new Exception($"FwpmTransactionBegin0 returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 166 | } 167 | 168 | result = NativeBridge.FwpmProviderAdd0(IntPtr, ref provider, IntPtr.Zero); 169 | if (result == NativeBridge.FWP_E_ALREADY_EXISTS) { 170 | // Console.WriteLine($"FwpmProviderAdd0 already exists: FWP_E_ALREADY_EXISTS"); 171 | } else if (result != 0) { 172 | throw new Exception($"FwpmProviderAdd0 returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 173 | } 174 | 175 | result = NativeBridge.FwpmTransactionCommit0(IntPtr); // 0x8032000D = FWP_E_NO_TXN_IN_PROGRESS 176 | if (result != 0) { 177 | throw new Exception($"FwpmTransactionCommit0 returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 178 | } 179 | 180 | // Console.WriteLine($"Added FWPM Provider"); 181 | } 182 | 183 | private static void BuildAndAddFWPPortFilter(string name, ushort port, Guid layer, IntPtr IntPtr) 184 | { 185 | IntPtr pProviderKey = IntPtr.Zero; 186 | IntPtr pConditionArray = IntPtr.Zero; 187 | 188 | try 189 | { 190 | pProviderKey = Marshal.AllocHGlobal(Marshal.SizeOf()); 191 | Marshal.StructureToPtr(FWPM_PROVIDER_GUID, pProviderKey, false); 192 | 193 | NativeBridge.FWPM_FILTER0 filter = new NativeBridge.FWPM_FILTER0 194 | { 195 | providerKey = pProviderKey, 196 | displayData = new NativeBridge.FWPM_DISPLAY_DATA0 197 | { 198 | name = $"{FWPM_DISPLAY_NAME}: {name}", 199 | description = $"Open port {port} for '{name}'", 200 | }, 201 | layerKey = layer, 202 | //flags = FirewallFilterFlags.Persistent, 203 | }; 204 | filter.action.type = NativeBridge.FirewallActionType.Permit; 205 | 206 | var conditions = new[] 207 | { 208 | new NativeBridge.FWPM_FILTER_CONDITION0 209 | { 210 | fieldKey = NativeBridge.FirewallLayerGuids.FWPM_CONDITION_IP_LOCAL_PORT, 211 | matchType = NativeBridge.FWP_MATCH_TYPE.FWP_MATCH_EQUAL, 212 | conditionValue = new NativeBridge.FWP_CONDITION_VALUE0 213 | { 214 | type = NativeBridge.FWP_DATA_TYPE.FWP_UINT16, 215 | anonymous = new NativeBridge.FWP_CONDITION_VALUE0_UNION { uint16 = port }, 216 | }, 217 | }, 218 | }; 219 | 220 | pConditionArray = Marshal.AllocHGlobal(conditions.Length * Marshal.SizeOf()); 221 | for (int i = 0; i < conditions.Length; i++) 222 | { 223 | Marshal.StructureToPtr(conditions[i], 224 | pConditionArray + (i * Marshal.SizeOf()), false); 225 | } 226 | 227 | filter.filterCondition = pConditionArray; 228 | filter.numFilterConditions = conditions.Length; 229 | 230 | IntPtr FilterId = IntPtr.Zero; 231 | uint result = NativeBridge.FwpmFilterAdd0(IntPtr, ref filter, IntPtr.Zero, ref FilterId); 232 | if (result != 0) 233 | { 234 | throw new Exception($"FwpmFilterAdd0 returned a non-zero result: 0x{result:X} (Error: 0x{Marshal.GetLastWin32Error():X})"); 235 | } 236 | } 237 | finally { 238 | if (pProviderKey != IntPtr.Zero) { 239 | Marshal.FreeHGlobal(pProviderKey); 240 | } 241 | if (pConditionArray != IntPtr.Zero) { 242 | Marshal.FreeHGlobal(pConditionArray); 243 | } 244 | } 245 | 246 | // Console.WriteLine($"Created Filter Id 0x{FilterId:X}"); 247 | } 248 | 249 | internal static class NativeBridge { 250 | 251 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 252 | public static extern IntPtr GetModuleHandle(string lpModuleName); 253 | 254 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 255 | public static extern IntPtr LoadLibrary(string lpFileName); 256 | 257 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] 258 | public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 259 | 260 | [DllImport("ole32.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] 261 | public static extern uint CoInitializeEx([In, Optional] IntPtr pvReserved, [In] COINIT dwCoInit); 262 | 263 | [DllImport("ole32.dll", CharSet = CharSet.Auto, SetLastError = true)] 264 | public static extern uint CoCreateInstance(Guid rclsid, IntPtr pUnkOuter, CLSCTX dwClsContext, Guid riid, out IntPtr ppv); 265 | 266 | public delegate uint FwpmEngineOpen0Delegate(IntPtr serverName, uint authnService, IntPtr authIdentity, IntPtr session, ref IntPtr engineHandle); 267 | public static uint FwpmEngineOpen0(IntPtr serverName, uint authnService, IntPtr authIdentity, IntPtr session, ref IntPtr engineHandle) { 268 | return GetDelegate("FWPUClnt.dll", "FwpmEngineOpen0")(serverName, authnService, authIdentity, session, ref engineHandle); 269 | } 270 | 271 | public delegate uint FwpmEngineClose0Delegate(IntPtr engineHandle); 272 | public static uint FwpmEngineClose0(IntPtr engineHandle) { 273 | return GetDelegate("FWPUClnt.dll", "FwpmEngineClose0")(engineHandle); 274 | } 275 | 276 | public delegate uint FwpmTransactionBegin0Delegate(IntPtr engineHandle, uint flags); 277 | public static uint FwpmTransactionBegin0(IntPtr engineHandle, uint flags) { 278 | return GetDelegate("FWPUClnt.dll", "FwpmTransactionBegin0")(engineHandle, flags); 279 | } 280 | 281 | public delegate uint FwpmTransactionCommit0Delegate(IntPtr engineHandle); 282 | public static uint FwpmTransactionCommit0(IntPtr engineHandle) { 283 | return GetDelegate("FWPUClnt.dll", "FwpmTransactionCommit0")(engineHandle); 284 | } 285 | 286 | public delegate uint FwpmFilterAdd0Delegate(IntPtr engineHandle, ref FWPM_FILTER0 filter, IntPtr sd, ref IntPtr id); 287 | public static uint FwpmFilterAdd0(IntPtr engineHandle, ref FWPM_FILTER0 filter, IntPtr sd, ref IntPtr id) { 288 | return GetDelegate("FWPUClnt.dll", "FwpmFilterAdd0")(engineHandle, ref filter, sd, ref id); 289 | } 290 | 291 | public delegate uint FwpmProviderAdd0Delegate(IntPtr engineHandle, ref FWPM_PROVIDER0 provider, IntPtr sd); 292 | public static uint FwpmProviderAdd0(IntPtr engineHandle, ref FWPM_PROVIDER0 provider, IntPtr sd) { 293 | return GetDelegate("FWPUClnt.dll", "FwpmProviderAdd0")(engineHandle, ref provider, sd); 294 | } 295 | 296 | // UWP won't allow importing from FWPUClnt.dll 297 | public static T GetDelegate(string DllName, string FunctionName) { 298 | var moduleHandle = GetModuleHandle(DllName); 299 | if (moduleHandle == IntPtr.Zero) { 300 | moduleHandle = LoadLibrary(DllName); 301 | if (moduleHandle == IntPtr.Zero) { 302 | throw new Exception($"Cannot natively load the DLL {DllName} for method delegation"); 303 | } 304 | } 305 | var functionHandle = GetProcAddress(moduleHandle, FunctionName); 306 | if (functionHandle == IntPtr.Zero) { 307 | throw new Exception($"Cannot find {DllName}!{FunctionName}"); 308 | } 309 | return Marshal.GetDelegateForFunctionPointer(functionHandle); 310 | } 311 | 312 | public const ulong RPC_C_AUTHN_DEFAULT = 0xFFFFFFFFL; // The system default authentication service 313 | public const uint FWP_E_ALREADY_EXISTS = 0x80320009; 314 | 315 | public enum COINIT : uint { 316 | COINIT_MULTITHREADED = 0x0, 317 | COINIT_APARTMENTTHREADED = 0x2, 318 | COINIT_DISABLE_OLE1DDE = 0x4, 319 | COINIT_SPEED_OVER_MEMORY = 0x8, 320 | } 321 | 322 | [Flags] 323 | public enum CLSCTX : uint { 324 | INPROC_SERVER = 0x1, 325 | INPROC_HANDLER = 0x2, 326 | LOCAL_SERVER = 0x4, 327 | INPROC_SERVER16 = 0x8, 328 | REMOTE_SERVER = 0x10, 329 | INPROC_HANDLER16 = 0x20, 330 | RESERVED1 = 0x40, 331 | RESERVED2 = 0x80, 332 | RESERVED3 = 0x100, 333 | RESERVED4 = 0x200, 334 | NO_CODE_DOWNLOAD = 0x400, 335 | RESERVED5 = 0x800, 336 | NO_CUSTOM_MARSHAL = 0x1000, 337 | ENABLE_CODE_DOWNLOAD = 0x2000, 338 | NO_FAILURE_LOG = 0x4000, 339 | DISABLE_AAA = 0x8000, 340 | ENABLE_AAA = 0x10000, 341 | FROM_DEFAULT_CONTEXT = 0x20000, 342 | INPROC = INPROC_SERVER | INPROC_HANDLER, 343 | SERVER = INPROC_SERVER | LOCAL_SERVER | REMOTE_SERVER, 344 | ALL = SERVER | INPROC_HANDLER 345 | } 346 | 347 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 348 | public struct FWPM_FILTER0 { 349 | public Guid filterKey; 350 | public FWPM_DISPLAY_DATA0 displayData; 351 | public FirewallFilterFlags flags; 352 | public IntPtr providerKey; // GUID* 353 | public FWP_BYTE_BLOB providerData; 354 | public Guid layerKey; 355 | public Guid subLayerKey; 356 | public FWP_VALUE0 weight; 357 | public int numFilterConditions; 358 | public IntPtr filterCondition; // FWPM_FILTER_CONDITION0* 359 | public FWPM_ACTION0 action; 360 | public FWPM_FILTER0_UNION context; 361 | public IntPtr reserved; // GUID* 362 | public ulong filterId; 363 | public FWP_VALUE0 effectiveWeight; 364 | } 365 | 366 | [StructLayout(LayoutKind.Explicit)] 367 | public struct FWPM_FILTER0_UNION { 368 | [FieldOffset(0)] 369 | public ulong rawContext; 370 | [FieldOffset(0)] 371 | public Guid providerContextKey; 372 | } 373 | 374 | [StructLayout(LayoutKind.Explicit)] 375 | public struct FWPM_ACTION0_UNION { 376 | [FieldOffset(0)] 377 | public Guid filterType; 378 | [FieldOffset(0)] 379 | public Guid calloutKey; 380 | [FieldOffset(0)] 381 | public byte bitmapIndex; 382 | } 383 | 384 | [StructLayoutAttribute(LayoutKind.Sequential)] 385 | public struct FWPM_FILTER_CONDITION0 { 386 | public Guid fieldKey; 387 | public FWP_MATCH_TYPE matchType; 388 | public FWP_CONDITION_VALUE0 conditionValue; 389 | } 390 | 391 | [StructLayoutAttribute(LayoutKind.Sequential)] 392 | public struct FWP_CONDITION_VALUE0 { 393 | public FWP_DATA_TYPE type; 394 | public FWP_CONDITION_VALUE0_UNION anonymous; 395 | } 396 | 397 | [StructLayoutAttribute(LayoutKind.Explicit)] 398 | public struct FWP_CONDITION_VALUE0_UNION { 399 | [FieldOffsetAttribute(0)] 400 | public byte uint8; 401 | [FieldOffsetAttribute(0)] 402 | public ushort uint16; 403 | [FieldOffsetAttribute(0)] 404 | public int uint32; 405 | [FieldOffsetAttribute(0)] 406 | public System.IntPtr uint64; 407 | [FieldOffsetAttribute(0)] 408 | public byte int8; 409 | [FieldOffsetAttribute(0)] 410 | public short int16; 411 | [FieldOffsetAttribute(0)] 412 | public int int32; 413 | [FieldOffsetAttribute(0)] 414 | public System.IntPtr int64; 415 | [FieldOffsetAttribute(0)] 416 | public float float32; 417 | [FieldOffsetAttribute(0)] 418 | public System.IntPtr double64; 419 | [FieldOffsetAttribute(0)] 420 | public System.IntPtr byteArray16; 421 | [FieldOffsetAttribute(0)] 422 | public System.IntPtr byteBlob; 423 | [FieldOffsetAttribute(0)] 424 | public System.IntPtr sid; 425 | [FieldOffsetAttribute(0)] 426 | public System.IntPtr sd; 427 | [FieldOffsetAttribute(0)] 428 | public System.IntPtr tokenInformation; 429 | [FieldOffsetAttribute(0)] 430 | public System.IntPtr tokenAccessInformation; 431 | [FieldOffsetAttribute(0)] 432 | public System.IntPtr unicodeString; 433 | [FieldOffsetAttribute(0)] 434 | public System.IntPtr byteArray6; 435 | [FieldOffsetAttribute(0)] 436 | public System.IntPtr v4AddrMask; 437 | [FieldOffsetAttribute(0)] 438 | public System.IntPtr v6AddrMask; 439 | [FieldOffsetAttribute(0)] 440 | public System.IntPtr rangeValue; 441 | } 442 | 443 | public enum FWP_DATA_TYPE : int { 444 | FWP_EMPTY = 0, 445 | FWP_UINT8 = 1, 446 | FWP_UINT16 = 2, 447 | FWP_UINT32 = 3, 448 | FWP_UINT64 = 4, 449 | FWP_INT8 = 5, 450 | FWP_INT16 = 6, 451 | FWP_INT32 = 7, 452 | FWP_INT64 = 8, 453 | FWP_FLOAT = 9, 454 | FWP_DOUBLE = 10, 455 | FWP_BYTE_ARRAY16_TYPE = 11, 456 | FWP_BYTE_BLOB_TYPE = 12, 457 | FWP_SID = 13, 458 | FWP_SECURITY_DESCRIPTOR_TYPE = 14, 459 | FWP_TOKEN_INFORMATION_TYPE = 15, 460 | FWP_TOKEN_ACCESS_INFORMATION_TYPE = 16, 461 | 462 | /// FWP_UNICODE_STRING_TYPE -> 17 463 | FWP_UNICODE_STRING_TYPE = 17, 464 | 465 | /// FWP_BYTE_ARRAY6_TYPE -> 18 466 | FWP_BYTE_ARRAY6_TYPE = 18, 467 | 468 | /// FWP_SINGLE_DATA_TYPE_MAX -> 0xff 469 | FWP_SINGLE_DATA_TYPE_MAX = 255, 470 | 471 | /// FWP_V4_ADDR_MASK -> 0x100 472 | FWP_V4_ADDR_MASK = 256, 473 | 474 | /// FWP_V6_ADDR_MASK -> 0x101 475 | FWP_V6_ADDR_MASK = 257, 476 | 477 | /// FWP_RANGE_TYPE -> 0x102 478 | FWP_RANGE_TYPE = 258, 479 | 480 | /// FWP_DATA_TYPE_MAX -> 0x103 481 | FWP_DATA_TYPE_MAX = 259, 482 | } 483 | 484 | public enum FWP_MATCH_TYPE : int { 485 | FWP_MATCH_EQUAL = 0, 486 | FWP_MATCH_GREATER = 1, 487 | FWP_MATCH_LESS = 2, 488 | FWP_MATCH_GREATER_OR_EQUAL = 3, 489 | FWP_MATCH_LESS_OR_EQUAL = 4, 490 | FWP_MATCH_RANGE = 5, 491 | FWP_MATCH_FLAGS_ALL_SET = 6, 492 | FWP_MATCH_FLAGS_ANY_SET = 7, 493 | FWP_MATCH_FLAGS_NONE_SET = 8, 494 | FWP_MATCH_EQUAL_CASE_INSENSITIVE = 9, 495 | FWP_MATCH_NOT_EQUAL = 10, 496 | FWP_MATCH_TYPE_MAX = 11, 497 | } 498 | 499 | 500 | [StructLayout(LayoutKind.Sequential)] 501 | public struct FWPM_ACTION0 { 502 | public FirewallActionType type; 503 | public FWPM_ACTION0_UNION action; 504 | } 505 | 506 | [StructLayout(LayoutKind.Explicit)] 507 | public struct FWP_VALUE0_UNION { 508 | [FieldOffset(0)] 509 | public byte uint8; 510 | [FieldOffset(0)] 511 | public ushort uint16; 512 | [FieldOffset(0)] 513 | public uint uint32; 514 | [FieldOffset(0)] 515 | public IntPtr uint64; // UINT64* 516 | [FieldOffset(0)] 517 | public sbyte int8; 518 | [FieldOffset(0)] 519 | public short int16; 520 | [FieldOffset(0)] 521 | public int int32; 522 | [FieldOffset(0)] 523 | public IntPtr int64; // INT64* 524 | [FieldOffset(0)] 525 | public float float32; 526 | [FieldOffset(0)] 527 | public IntPtr double64; // double* 528 | [FieldOffset(0)] 529 | public IntPtr byteArray16; // FWP_BYTE_ARRAY16* 530 | [FieldOffset(0)] 531 | public IntPtr byteBlob; // FWP_BYTE_BLOB* 532 | [FieldOffset(0)] 533 | public IntPtr sid; // SID* 534 | [FieldOffset(0)] 535 | public IntPtr sd; // FWP_BYTE_BLOB* 536 | [FieldOffset(0)] 537 | public IntPtr tokenInformation; // FWP_TOKEN_INFORMATION* 538 | [FieldOffset(0)] 539 | public IntPtr tokenAccessInformation; // FWP_BYTE_BLOB* 540 | [FieldOffset(0)] 541 | public IntPtr unicodeString; // LPWSTR 542 | [FieldOffset(0)] 543 | public IntPtr byteArray6; // FWP_BYTE_ARRAY6* 544 | [FieldOffset(0)] 545 | public IntPtr bitmapArray64; // FWP_BITMAP_ARRAY64* 546 | [FieldOffset(0)] 547 | public IntPtr v4AddrMask; // FWP_V4_ADDR_AND_MASK* 548 | [FieldOffset(0)] 549 | public IntPtr v6AddrMask; // FWP_V6_ADDR_AND_MASK* 550 | [FieldOffset(0)] 551 | public IntPtr rangeValue; // FWP_RANGE0* 552 | } 553 | 554 | [StructLayout(LayoutKind.Sequential)] 555 | public struct FWP_VALUE0 { 556 | public FirewallDataType type; 557 | public FWP_VALUE0_UNION value; 558 | } 559 | 560 | [StructLayout(LayoutKind.Sequential)] 561 | public struct FWP_BYTE_BLOB { 562 | public int size; 563 | /* [unique][size_is] */ 564 | public IntPtr data; 565 | 566 | public byte[] ToArray() { 567 | if (size <= 0 || data == IntPtr.Zero) { 568 | return new byte[0]; 569 | } 570 | byte[] ret = new byte[size]; 571 | Marshal.Copy(data, ret, 0, ret.Length); 572 | return ret; 573 | } 574 | 575 | public Guid ToGuid() { 576 | var bytes = ToArray(); 577 | if (bytes.Length != 16) 578 | return Guid.Empty; 579 | return new Guid(bytes); 580 | } 581 | } 582 | 583 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 584 | public struct FWPM_DISPLAY_DATA0 { 585 | [MarshalAs(UnmanagedType.LPWStr)] 586 | public string name; 587 | [MarshalAs(UnmanagedType.LPWStr)] 588 | public string description; 589 | } 590 | 591 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 592 | public struct FWPM_PROVIDER0 { 593 | public Guid providerKey; 594 | public FWPM_DISPLAY_DATA0 displayData; 595 | public FirewallProviderFlags flags; 596 | public FWP_BYTE_BLOB providerData; 597 | [MarshalAs(UnmanagedType.LPWStr)] 598 | public string serviceName; 599 | } 600 | 601 | // https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/blob/280826ad554f33e5e799d9b860a68c2b7becbc06/NtApiDotNet/Net/Firewall/FirewallLayerGuids.cs#L22 602 | public static class FirewallLayerGuids { 603 | public static Guid FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 = new Guid(0xe1cd9fe7, 0xf4b5, 0x4273, 0x96, 0xc0, 0x59, 0x2e, 0x48, 0x7b, 0x86, 0x50); 604 | public static Guid FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD = new Guid(0x9eeaa99b, 0xbd22, 0x4227, 0x91, 0x9f, 0x00, 0x73, 0xc6, 0x33, 0x57, 0xb1); 605 | public static Guid FWPM_CONDITION_IP_LOCAL_PORT = new Guid(0x0c1ba1af, 0x5765, 0x453f, 0xaf, 0x22, 0xa8, 0xf7, 0x91, 0xac, 0x77, 0x5b); 606 | } 607 | 608 | [Flags] 609 | public enum FirewallProviderFlags { 610 | None = 0, 611 | Persistent = 0x00000001, 612 | Disabled = 0x00000010 613 | } 614 | 615 | public enum FirewallDataType { 616 | Empty = 0, 617 | UInt8 = Empty + 1, 618 | UInt16 = UInt8 + 1, 619 | UInt32 = UInt16 + 1, 620 | UInt64 = UInt32 + 1, 621 | Int8 = UInt64 + 1, 622 | Int16 = Int8 + 1, 623 | Int32 = Int16 + 1, 624 | Int64 = Int32 + 1, 625 | Float = Int64 + 1, 626 | Double = Float + 1, 627 | ByteArray16 = Double + 1, 628 | ByteBlob = ByteArray16 + 1, 629 | Sid = ByteBlob + 1, 630 | SecurityDescriptor = Sid + 1, 631 | TokenInformation = SecurityDescriptor + 1, 632 | TokenAccessInformation = TokenInformation + 1, 633 | UnicodeString = TokenAccessInformation + 1, 634 | ByteArray6 = UnicodeString + 1, 635 | BitmapIndex = ByteArray6 + 1, 636 | BitmapArray64 = BitmapIndex + 1, 637 | SingleDataTypeMax = 0xff, 638 | V4AddrMask = SingleDataTypeMax + 1, 639 | V6AddrMask = V4AddrMask + 1, 640 | Range = V6AddrMask + 1 641 | } 642 | public enum FirewallActionType : uint { 643 | Terminating = 0x00001000, 644 | Block = 0x00000001 | Terminating, 645 | Permit = 0x00000002 | Terminating, 646 | CalloutTerminating = 0x00000003 | Callout | Terminating, 647 | CalloutInspection = 0x00000004 | Callout | NonTerminating, 648 | CalloutUnknown = 0x00000005 | Callout, 649 | Continue = 0x00000006 | NonTerminating, 650 | None = 0x00000007, 651 | NoneNoMatch = 0x00000008, 652 | BitmapIndexSet = 0x00000009, 653 | NonTerminating = 0x00002000, 654 | Callout = 0x00004000, 655 | All = 0xFFFFFFFF 656 | } 657 | 658 | [Flags] 659 | public enum FirewallFilterFlags { 660 | None = 0x00000000, 661 | Persistent = 0x00000001, 662 | Boottime = 0x00000002, 663 | HasProviderContext = 0x00000004, 664 | ClearActionRight = 0x00000008, 665 | PermitIfCalloutUnregistered = 0x00000010, 666 | Disabled = 0x00000020, 667 | Indexed = 0x00000040, 668 | HasSecurityRealmProviderContext = 0x00000080, 669 | SystemOSOnly = 0x00000100, 670 | GameOSOnly = 0x00000200, 671 | SilentMode = 0x00000400, 672 | IPSecNoAcquireInitiate = 0x00000800, 673 | } 674 | 675 | public enum NetFwProfileType2 { 676 | Domain = 0x00000001, 677 | Private = 0x00000002, 678 | Public = 0x00000004, 679 | All = 0x7FFFFFFF 680 | } 681 | 682 | public enum NetFwAction { 683 | Block, 684 | Allow 685 | } 686 | public enum NetFwRuleDirection { 687 | Inbound = 1, 688 | Outbound = 2 689 | } 690 | public enum NetFwModifyState { 691 | Ok, 692 | GroupPolicyOverride, 693 | InboundBlocked 694 | } 695 | 696 | [Guid("98325047-C671-4174-8D81-DEFCD3F03186")] 697 | [ComImport] 698 | public interface INetFwPolicy2 { 699 | [DispId(1)] 700 | int CurrentProfileTypes { 701 | [DispId(1)] 702 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 703 | get; 704 | } 705 | 706 | [DispId(2)] 707 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 708 | bool get_FirewallEnabled([In] NetFwProfileType2 profileType); 709 | 710 | [DispId(2)] 711 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 712 | void set_FirewallEnabled([In] NetFwProfileType2 profileType, [In] bool enabled); 713 | 714 | [DispId(3)] 715 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 716 | object get_ExcludedInterfaces([In] NetFwProfileType2 profileType); 717 | 718 | [DispId(3)] 719 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 720 | void set_ExcludedInterfaces( 721 | [In] NetFwProfileType2 profileType, 722 | [In] object interfaces); 723 | 724 | [DispId(4)] 725 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 726 | bool get_BlockAllInboundTraffic([In] NetFwProfileType2 profileType); 727 | 728 | [DispId(4)] 729 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 730 | void set_BlockAllInboundTraffic([In] NetFwProfileType2 profileType, [In] bool block); 731 | 732 | [DispId(5)] 733 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 734 | bool get_NotificationsDisabled([In] NetFwProfileType2 profileType); 735 | 736 | [DispId(5)] 737 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 738 | void set_NotificationsDisabled([In] NetFwProfileType2 profileType, [In] bool disabled); 739 | 740 | [DispId(6)] 741 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 742 | bool get_UnicastResponsesToMulticastBroadcastDisabled([In] NetFwProfileType2 profileType); 743 | 744 | [DispId(6)] 745 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 746 | void set_UnicastResponsesToMulticastBroadcastDisabled( 747 | [In] NetFwProfileType2 profileType, 748 | [In] bool disabled 749 | ); 750 | 751 | [DispId(7)] 752 | INetFwRules Rules { 753 | [DispId(7)] 754 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 755 | [return: MarshalAs(UnmanagedType.Interface)] 756 | get; 757 | } 758 | 759 | [DispId(8)] 760 | INetFwServiceRestriction ServiceRestriction { 761 | [DispId(8)] 762 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 763 | [return: MarshalAs(UnmanagedType.Interface)] 764 | get; 765 | } 766 | 767 | [DispId(9)] 768 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 769 | void EnableRuleGroup( 770 | [In] int profileTypesBitmask, 771 | [MarshalAs(UnmanagedType.BStr)][In] string group, 772 | [In] bool enable 773 | ); 774 | 775 | [DispId(10)] 776 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 777 | bool IsRuleGroupEnabled([In] int profileTypesBitmask, [MarshalAs(UnmanagedType.BStr)][In] string group); 778 | 779 | [DispId(11)] 780 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 781 | void RestoreLocalFirewallDefaults(); 782 | 783 | [DispId(12)] 784 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 785 | NetFwAction get_DefaultInboundAction([In] NetFwProfileType2 profileType); 786 | 787 | [DispId(12)] 788 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 789 | void set_DefaultInboundAction([In] NetFwProfileType2 profileType, [In] NetFwAction action); 790 | 791 | [DispId(13)] 792 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 793 | NetFwAction get_DefaultOutboundAction([In] NetFwProfileType2 profileType); 794 | 795 | [DispId(13)] 796 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 797 | void set_DefaultOutboundAction([In] NetFwProfileType2 profileType, [In] NetFwAction action); 798 | 799 | [DispId(14)] 800 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 801 | bool get_IsRuleGroupCurrentlyEnabled([MarshalAs(UnmanagedType.BStr)][In] string group); 802 | 803 | [DispId(15)] 804 | NetFwModifyState LocalPolicyModifyState { 805 | [DispId(15)] 806 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 807 | get; 808 | } 809 | } 810 | 811 | [Guid("9C4C6277-5027-441E-AFAE-CA1F542DA009")] 812 | [ComImport] 813 | public interface INetFwRules : System.Collections.IEnumerable { 814 | [DispId(1)] 815 | int Count { 816 | [DispId(1)] 817 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 818 | get; 819 | } 820 | 821 | [DispId(2)] 822 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 823 | // ReSharper disable once MethodNameNotMeaningful 824 | void Add( 825 | [MarshalAs(UnmanagedType.Interface)] [In] 826 | INetFwRule rule 827 | ); 828 | 829 | [DispId(3)] 830 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 831 | void Remove([MarshalAs(UnmanagedType.BStr)][In] string name); 832 | 833 | [DispId(4)] 834 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 835 | [return: MarshalAs(UnmanagedType.Interface)] 836 | INetFwRule Item([MarshalAs(UnmanagedType.BStr)][In] string name); 837 | 838 | [DispId(-4)] 839 | IEnumVARIANT GetEnumeratorVariant(); 840 | } 841 | 842 | [Guid("AF230D27-BABA-4E42-ACED-F524F22CFCE2")] 843 | [ComImport] 844 | public interface INetFwRule { 845 | [DispId(1)] 846 | string Name { 847 | [DispId(1)] 848 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 849 | [return: MarshalAs(UnmanagedType.BStr)] 850 | get; 851 | [DispId(1)] 852 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 853 | [param: MarshalAs(UnmanagedType.BStr)] 854 | [param: In] 855 | set; 856 | } 857 | 858 | [DispId(2)] 859 | string Description { 860 | [DispId(2)] 861 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 862 | [return: MarshalAs(UnmanagedType.BStr)] 863 | get; 864 | [DispId(2)] 865 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 866 | [param: MarshalAs(UnmanagedType.BStr)] 867 | [param: In] 868 | set; 869 | } 870 | 871 | [DispId(3)] 872 | string ApplicationName { 873 | [DispId(3)] 874 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 875 | [return: MarshalAs(UnmanagedType.BStr)] 876 | get; 877 | [DispId(3)] 878 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 879 | [param: MarshalAs(UnmanagedType.BStr)] 880 | [param: In] 881 | set; 882 | } 883 | 884 | [DispId(4)] 885 | string serviceName { 886 | [DispId(4)] 887 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 888 | [return: MarshalAs(UnmanagedType.BStr)] 889 | get; 890 | [DispId(4)] 891 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 892 | [param: MarshalAs(UnmanagedType.BStr)] 893 | [param: In] 894 | set; 895 | } 896 | 897 | [DispId(5)] 898 | int Protocol { 899 | [DispId(5)] 900 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 901 | get; 902 | [DispId(5)] 903 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 904 | [param: In] 905 | set; 906 | } 907 | 908 | [DispId(6)] 909 | string LocalPorts { 910 | [DispId(6)] 911 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 912 | [return: MarshalAs(UnmanagedType.BStr)] 913 | get; 914 | [DispId(6)] 915 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 916 | [param: MarshalAs(UnmanagedType.BStr)] 917 | [param: In] 918 | set; 919 | } 920 | 921 | [DispId(7)] 922 | string RemotePorts { 923 | [DispId(7)] 924 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 925 | [return: MarshalAs(UnmanagedType.BStr)] 926 | get; 927 | [DispId(7)] 928 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 929 | [param: MarshalAs(UnmanagedType.BStr)] 930 | [param: In] 931 | set; 932 | } 933 | 934 | [DispId(8)] 935 | string LocalAddresses { 936 | [DispId(8)] 937 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 938 | [return: MarshalAs(UnmanagedType.BStr)] 939 | get; 940 | [DispId(8)] 941 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 942 | [param: MarshalAs(UnmanagedType.BStr)] 943 | [param: In] 944 | set; 945 | } 946 | 947 | [DispId(9)] 948 | string RemoteAddresses { 949 | [DispId(9)] 950 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 951 | [return: MarshalAs(UnmanagedType.BStr)] 952 | get; 953 | [DispId(9)] 954 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 955 | [param: MarshalAs(UnmanagedType.BStr)] 956 | [param: In] 957 | set; 958 | } 959 | 960 | [DispId(10)] 961 | string IcmpTypesAndCodes { 962 | [DispId(10)] 963 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 964 | [return: MarshalAs(UnmanagedType.BStr)] 965 | get; 966 | [DispId(10)] 967 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 968 | [param: MarshalAs(UnmanagedType.BStr)] 969 | [param: In] 970 | set; 971 | } 972 | 973 | [DispId(11)] 974 | NetFwRuleDirection Direction { 975 | [DispId(11)] 976 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 977 | get; 978 | [DispId(11)] 979 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 980 | [param: In] 981 | set; 982 | } 983 | 984 | [DispId(12)] 985 | object Interfaces { 986 | [DispId(12)] 987 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 988 | get; 989 | [DispId(12)] 990 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 991 | [param: In] 992 | set; 993 | } 994 | 995 | [DispId(13)] 996 | string InterfaceTypes { 997 | [DispId(13)] 998 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 999 | [return: MarshalAs(UnmanagedType.BStr)] 1000 | get; 1001 | [DispId(13)] 1002 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1003 | [param: MarshalAs(UnmanagedType.BStr)] 1004 | [param: In] 1005 | set; 1006 | } 1007 | 1008 | [DispId(14)] 1009 | bool Enabled { 1010 | [DispId(14)] 1011 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1012 | get; 1013 | [DispId(14)] 1014 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1015 | [param: In] 1016 | set; 1017 | } 1018 | 1019 | [DispId(15)] 1020 | string Grouping { 1021 | [DispId(15)] 1022 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1023 | [return: MarshalAs(UnmanagedType.BStr)] 1024 | get; 1025 | [DispId(15)] 1026 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1027 | [param: MarshalAs(UnmanagedType.BStr)] 1028 | [param: In] 1029 | set; 1030 | } 1031 | 1032 | [DispId(16)] 1033 | int Profiles { 1034 | [DispId(16)] 1035 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1036 | get; 1037 | [DispId(16)] 1038 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1039 | [param: In] 1040 | set; 1041 | } 1042 | 1043 | [DispId(17)] 1044 | bool EdgeTraversal { 1045 | [DispId(17)] 1046 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1047 | get; 1048 | [DispId(17)] 1049 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1050 | [param: In] 1051 | set; 1052 | } 1053 | 1054 | [DispId(18)] 1055 | NetFwAction Action { 1056 | [DispId(18)] 1057 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1058 | get; 1059 | [DispId(18)] 1060 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1061 | [param: In] 1062 | set; 1063 | } 1064 | } 1065 | 1066 | [Guid("8267BBE3-F890-491C-B7B6-2DB1EF0E5D2B")] 1067 | [ComImport] 1068 | public interface INetFwServiceRestriction { 1069 | [DispId(1)] 1070 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1071 | // ReSharper disable once TooManyArguments 1072 | void RestrictService( 1073 | [MarshalAs(UnmanagedType.BStr)][In] string serviceName, 1074 | [MarshalAs(UnmanagedType.BStr)][In] string appName, 1075 | [In] bool restrictService, 1076 | [In] bool serviceSIDRestricted 1077 | ); 1078 | 1079 | [DispId(2)] 1080 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1081 | bool ServiceRestricted( 1082 | [MarshalAs(UnmanagedType.BStr)][In] string serviceName, 1083 | [MarshalAs(UnmanagedType.BStr)][In] string appName 1084 | ); 1085 | 1086 | [DispId(3)] 1087 | INetFwRules Rules { 1088 | [DispId(3)] 1089 | [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 1090 | [return: MarshalAs(UnmanagedType.Interface)] 1091 | get; 1092 | } 1093 | } 1094 | } 1095 | } 1096 | } 1097 | -------------------------------------------------------------------------------- /src/LicenseManager.cs: -------------------------------------------------------------------------------- 1 | [Guid("2769c3a8-d8e3-41ba-b38b-01d05dd2374e")] 2 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 3 | public interface IClipLicenseManager 4 | { 5 | void StoreLicense(string licenseBuffer, uint flags, out IntPtr clipLicense); 6 | } 7 | 8 | public class LicenseManager 9 | { 10 | static readonly Guid CLSID = new Guid("7e480b22-b679-4542-9b30-d5a52da92ce5"); 11 | static readonly IClipLicenseManager _manager; 12 | 13 | static LicenseManager() 14 | { 15 | COM.CoInitializeEx(IntPtr.Zero, 0); 16 | 17 | _manager = COM.ActivateClass(CLSID); 18 | } 19 | 20 | /// 21 | /// Loads a full license (base64 representation of the license.xml) 22 | /// 23 | /// 24 | /// true on success, false otherwise 25 | public static bool LoadLicenseBase64(string licenseBuffer) 26 | { 27 | _manager.StoreLicense(licenseBuffer, 0x1, out IntPtr license); 28 | return license != IntPtr.Zero; 29 | } 30 | 31 | public static bool LoadLicenseFile(string filePath) 32 | { 33 | // 34 | // Read and convert license contents to base64 35 | // Just assume the license is valid, it'll fail anyway if it's not 36 | // 37 | string content = File.ReadAllText(filePath); 38 | if (string.IsNullOrEmpty(content)) 39 | { 40 | throw new InvalidDataException("Provided file is empty"); 41 | } 42 | 43 | var licenseBlob = Encoding.UTF8.GetBytes(content); 44 | var base64Blob = Convert.ToBase64String(licenseBlob); 45 | return LoadLicenseBase64(base64Blob); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Shellcode.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// Load shellcode/PE via solstice's stage2.bin (PE Loader shellcode) 3 | /// 4 | /// Examples 5 | /// 6 | /// ``` 7 | /// Add-Type -Path sc.cs 8 | /// [ShellCodeLoader]::LoadCS("D:\sc\stage2.bin", "D:\sc\daemon.exe", "") 9 | /// ``` 10 | /// 11 | 12 | public static class ShellCodeLoader 13 | { 14 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 15 | public struct ShellcodeArgs 16 | { 17 | public string ImageName; 18 | public string Args; 19 | } 20 | 21 | [Flags] 22 | public enum PageProtection : uint 23 | { 24 | PAGE_EXECUTE = 0x10, 25 | PAGE_EXECUTE_READ = 0x20, 26 | PAGE_EXECUTE_READWRITE = 0x40, 27 | PAGE_EXECUTE_WRITECOPY = 0x80, 28 | PAGE_NOACCESS = 0x01, 29 | PAGE_READONLY = 0x02, 30 | PAGE_READWRITE = 0x04, 31 | PAGE_WRITECOPY = 0x08, 32 | PAGE_TARGETS_INVALID = 0x40000000, 33 | PAGE_TARGETS_NO_UPDATE = 0x40000000, 34 | PAGE_GUARD = 0x100, 35 | PAGE_NOCACHE = 0x200, 36 | PAGE_WRITECOMBINE = 0x400 37 | } 38 | 39 | [DllImport("kernelbase.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 40 | public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, PageProtection flNewProtect, out PageProtection lpflOldProtect); 41 | 42 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 43 | internal delegate void ShellCodeCaller(ShellcodeArgs args); 44 | 45 | public static int Invoke(byte[] sc, string executablePath, string args) 46 | { 47 | unsafe 48 | { 49 | fixed (void* ptr = &sc[0]) 50 | { 51 | PageProtection flOld; 52 | VirtualProtect((IntPtr)ptr, (uint)sc.Length, PageProtection.PAGE_EXECUTE_READWRITE, out flOld); 53 | 54 | var scArgs = new ShellcodeArgs() 55 | { 56 | ImageName = executablePath, 57 | Args = args, 58 | }; 59 | 60 | ShellCodeCaller s = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer((IntPtr)ptr, typeof(ShellCodeCaller)); 61 | s(scArgs); 62 | } 63 | } 64 | 65 | return 0; 66 | } 67 | 68 | public static int LoadSC(string shellcodepath, string executablePath, string args) 69 | { 70 | var sc = File.ReadAllBytes(shellcodepath); 71 | return Invoke(sc, executablePath, args); 72 | } 73 | } -------------------------------------------------------------------------------- /src/UserManager.cs: -------------------------------------------------------------------------------- 1 | public class UserManager : IDisposable 2 | { 3 | private static readonly string RuntimeClass_Windows_Xbox_System_Internal_UserManager = "Windows.Xbox.System.Internal.UserManager"; 4 | 5 | // Interface is a part of the implementation of type Windows.Xbox.System.Internal.UserManager 6 | private static readonly byte[] IID_IConsoleUserManagement = Guid.Parse("D65AE869-659F-4AF9-8393-99FB0CF7F22C").ToByteArray(); 7 | 8 | /* 9 | // Windows.Xbox.System.Internal.IConsoleUserManagement::get_ConsoleUsers, method index: 6 10 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 11 | private delegate IntPtr IConsoleUserManagementGetConsoleUsersDelegate(IntPtr instance, out IntPtr consoleUsers); 12 | */ 13 | 14 | // Windows.Xbox.System.Internal.IConsoleUserManagement::CreateConsoleUser, method index: 7 15 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 16 | private delegate IntPtr IConsoleUserManagementCreateConsoleUserDelegate(IntPtr instance, IntPtr emailAddress, byte persistCredentials, out uint retval); 17 | 18 | // Windows.Xbox.System.Internal.IConsoleUserManagement::DeleteConsoleUser, method index: 8 19 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 20 | private delegate IntPtr IConsoleUserManagementDeleteConsoleUserDelegate(IntPtr instance, uint consoleUserId); 21 | 22 | // Windows.Xbox.System.Internal.IConsoleUserManagement::UpdateConsoleUser, method index: 9 23 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 24 | private delegate IntPtr IConsoleUserManagementUpdateConsoleUserDelegate(IntPtr instance, uint consoleUserId, IntPtr emailAddress, byte persistCredentials, byte enableKinectSignin); 25 | 26 | // Windows.Xbox.System.Internal.IConsoleUserManagement::ClearNewUserStatus, method index: 10 27 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 28 | private delegate IntPtr IConsoleUserManagementClearNewUserStatusDelegate(IntPtr instance, uint consoleUserId); 29 | 30 | // Windows.Xbox.System.Internal.IConsoleUserManagement::AllocateSponsoredUserId, method index: 11 31 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 32 | private delegate IntPtr IConsoleUserManagementAllocateSponsoredUserIdDelegate(IntPtr instance, out uint retval); 33 | 34 | // Windows.Xbox.System.Internal.IConsoleUserManagement::FreeSponsoredUserId, method index: 12 35 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 36 | private delegate IntPtr IConsoleUserManagementFreeSponsoredUserIdDelegate(IntPtr instance, uint consoleUserId); 37 | 38 | // Windows.Xbox.System.Internal.IConsoleUserManagement::IsUserIdValidForLocalStorage, method index: 13 39 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 40 | private delegate IntPtr IConsoleUserManagementIsUserIdValidForLocalStorageDelegate(IntPtr instance, uint consoleUserId); 41 | 42 | // Windows.Xbox.System.Internal.IConsoleUserManagement::UpdateConsoleUserSignIn, method index: 16 43 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 44 | private delegate IntPtr IConsoleUserManagementUpdateConsoleUserSignInDelegate(IntPtr instance, uint consoleUserId, byte persistCredentials, byte enableKinectSignIn, byte challengeSignIn, byte signOutSpopForKinectSignIn); 45 | 46 | // Windows.Xbox.System.Internal.IConsoleUserManagement::UpdateConsoleUserEmail, method index: 17 47 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 48 | private delegate IntPtr IConsoleUserManagementUpdateConsoleUserEmailDelegate(IntPtr instance, uint consoleUserId, IntPtr emailAddress); 49 | 50 | // Windows.Xbox.System.Internal.IConsoleUserManagement::UpdateConsoleUserAutoSignIn, method index: 18 51 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 52 | private delegate IntPtr IConsoleUserManagementUpdateConsoleUserAutoSignInDelegate(IntPtr instance, uint consoleUserId, byte autoSignIn); 53 | 54 | 55 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 56 | private static bool IsSucceeded(IntPtr result) => (long)result >= 0L; 57 | 58 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 59 | private static byte BoolToByte(bool value) => value ? (byte)1 : (byte)0; 60 | 61 | private static bool _roInitialized = false; 62 | private static IntPtr _classId = IntPtr.Zero; 63 | private static IntPtr _instance = IntPtr.Zero; 64 | 65 | static UserManager() 66 | { 67 | if (!IsSucceeded(WinRT.RoInitialize(WinRT.RO_INIT_TYPE.RO_INIT_SINGLETHREADED))) 68 | { 69 | throw new Exception("RoInitialize failed"); 70 | } 71 | _roInitialized = true; 72 | 73 | if (!IsSucceeded(WinRT.WindowsCreateString(RuntimeClass_Windows_Xbox_System_Internal_UserManager, RuntimeClass_Windows_Xbox_System_Internal_UserManager.Length, out _classId))) 74 | { 75 | throw new Exception("WindowsCreateString (classID) failed"); 76 | } 77 | 78 | if (!IsSucceeded(WinRT.RoGetActivationFactory(_classId, IID_IConsoleUserManagement, out _instance))) 79 | { 80 | throw new Exception("RoGetActivationFactory failed"); 81 | } 82 | } 83 | 84 | /* 85 | public static IReadOnlyList GetConsoleUsers() 86 | { 87 | throw new NotImplementedException(); 88 | } 89 | */ 90 | 91 | public static uint CreateConsoleUser(string emailAddress, bool persistCredentials) 92 | { 93 | if (!IsSucceeded(WinRT.WindowsCreateString(emailAddress, emailAddress.Length, out IntPtr emailAddrPtr))) 94 | { 95 | throw new Exception("Failed to initialize email HSTRING"); 96 | } 97 | 98 | var method = WinRT.GetVirtualMethodPointer(_instance, 7); 99 | method.Invoke(_instance, emailAddrPtr, BoolToByte(persistCredentials), out uint ret); 100 | WinRT.WindowsDeleteString(emailAddrPtr); 101 | return ret; 102 | } 103 | 104 | public static void DeleteConsoleUser(uint consoleUserId) 105 | { 106 | var method = WinRT.GetVirtualMethodPointer(_instance, 8); 107 | method.Invoke(_instance, consoleUserId); 108 | } 109 | 110 | public static void UpdateConsoleUser(uint consoleUserId, string emailAddress, bool persistCredentials, bool enableKinectSignin) 111 | { 112 | if (!IsSucceeded(WinRT.WindowsCreateString(emailAddress, emailAddress.Length, out IntPtr emailAddrPtr))) 113 | { 114 | throw new Exception("Failed to initialize email HSTRING"); 115 | } 116 | 117 | var method = WinRT.GetVirtualMethodPointer(_instance, 9); 118 | method.Invoke(_instance, consoleUserId, emailAddrPtr, BoolToByte(persistCredentials), BoolToByte(enableKinectSignin)); 119 | 120 | WinRT.WindowsDeleteString(emailAddrPtr); 121 | } 122 | 123 | public static void ClearNewUserStatus(uint consoleUserId) 124 | { 125 | var method = WinRT.GetVirtualMethodPointer(_instance, 10); 126 | method.Invoke(_instance, consoleUserId); 127 | } 128 | 129 | public static uint AllocateSponsoredUserId() 130 | { 131 | var method = WinRT.GetVirtualMethodPointer(_instance, 11); 132 | method.Invoke(_instance, out uint ret); 133 | return ret; 134 | } 135 | 136 | public static void FreeSponsoredUserId(uint consoleUserId) 137 | { 138 | var method = WinRT.GetVirtualMethodPointer(_instance, 12); 139 | method.Invoke(_instance, consoleUserId); 140 | } 141 | 142 | public static void IsUserIdValidForLocalStorage(uint consoleUserId) 143 | { 144 | var method = WinRT.GetVirtualMethodPointer(_instance, 13); 145 | method.Invoke(_instance, consoleUserId); 146 | } 147 | 148 | public static void UpdateConsoleUserSignIn(uint consoleUserId, bool persistCredentials, bool enableKinectSignIn, bool challengeSignIn, bool signOutSpopForKinectSignIn) 149 | { 150 | var method = WinRT.GetVirtualMethodPointer(_instance, 16); 151 | method.Invoke(_instance, consoleUserId, BoolToByte(persistCredentials), BoolToByte(enableKinectSignIn), BoolToByte(challengeSignIn), BoolToByte(signOutSpopForKinectSignIn)); 152 | } 153 | 154 | public static void UpdateConsoleUserEmail(uint consoleUserId, string emailAddress) 155 | { 156 | if (!IsSucceeded(WinRT.WindowsCreateString(emailAddress, emailAddress.Length, out IntPtr emailAddrPtr))) 157 | { 158 | throw new Exception("Failed to initialize email HSTRING"); 159 | } 160 | 161 | var method = WinRT.GetVirtualMethodPointer(_instance, 17); 162 | method.Invoke(_instance, consoleUserId, emailAddrPtr); 163 | 164 | WinRT.WindowsDeleteString(emailAddrPtr); 165 | } 166 | 167 | public static void UpdateConsoleUserAutoSignIn(uint consoleUserId, bool autoSignIn) 168 | { 169 | var method = WinRT.GetVirtualMethodPointer(_instance, 18); 170 | method.Invoke(_instance, consoleUserId, BoolToByte(autoSignIn)); 171 | } 172 | 173 | public void Dispose() 174 | { 175 | if (_instance != IntPtr.Zero) 176 | Marshal.Release(_instance); 177 | if (_classId != IntPtr.Zero) 178 | WinRT.WindowsDeleteString(_classId); 179 | if (_roInitialized) 180 | WinRT.RoUninitialize(); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/WinUserManager.cs: -------------------------------------------------------------------------------- 1 | public static class WinUser 2 | { 3 | public enum SID_NAME_USE : uint 4 | { 5 | SidTypeUser = 1, 6 | SidTypeGroup, 7 | SidTypeDomain, 8 | SidTypeAlias, 9 | SidTypeWellKnownGroup, 10 | SidTypeDeletedAccount, 11 | SidTypeInvalid, 12 | SidTypeUnknown, 13 | SidTypeComputer, 14 | SidTypeLabel 15 | } 16 | 17 | [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 18 | public static extern bool LookupAccountName( 19 | string lpSystemName, 20 | string lpAccountName, 21 | IntPtr Sid, 22 | ref uint cbSid, 23 | StringBuilder referencedDomainName, 24 | ref uint cchReferencedDomainName, 25 | out SID_NAME_USE peUse); 26 | 27 | [DllImport("userenv.dll", CharSet = CharSet.Unicode, SetLastError = true)] 28 | public static extern int CreateProfile( 29 | [MarshalAs(UnmanagedType.LPWStr)] string pszUserSid, 30 | [MarshalAs(UnmanagedType.LPWStr)] string pszUserName, 31 | [Out][MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszProfilePath, 32 | uint cchProfilePath 33 | ); 34 | 35 | [DllImport("userenv.dll", CharSet = CharSet.Unicode, SetLastError = true)] 36 | public static extern bool DeleteProfileW( 37 | [MarshalAs(UnmanagedType.LPWStr)] string lpszSidString, 38 | [MarshalAs(UnmanagedType.LPWStr)] string lpszProfilePath, 39 | [MarshalAs(UnmanagedType.LPWStr)] string lpszComputerName 40 | ); 41 | 42 | [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 43 | public static extern int NetUserAdd( 44 | [MarshalAs(UnmanagedType.LPWStr)] string servername, 45 | UInt32 level, 46 | ref USER_INFO_1 userinfo, 47 | out UInt32 parm_err 48 | ); 49 | 50 | [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 51 | public static extern int NetUserDel( 52 | [MarshalAs(UnmanagedType.LPWStr)] string servername, 53 | [MarshalAs(UnmanagedType.LPWStr)] string username 54 | ); 55 | 56 | [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 57 | public static extern int NetLocalGroupAddMembers( 58 | string servername, 59 | string groupname, 60 | UInt32 level, 61 | ref LOCALGROUP_MEMBERS_INFO_3 members, 62 | UInt32 totalentries 63 | ); 64 | 65 | [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 66 | public static extern int NetLocalGroupDelMembers( 67 | string servername, 68 | string groupname, 69 | UInt32 level, 70 | ref LOCALGROUP_MEMBERS_INFO_3 members, 71 | UInt32 totalentries 72 | ); 73 | 74 | [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 75 | public static extern int NetUserEnum( 76 | [MarshalAs(UnmanagedType.LPWStr)] string servername, 77 | int level, 78 | int filter, 79 | out IntPtr bufptr, 80 | int prefmaxlen, 81 | out int entriesread, 82 | out int totalentries, 83 | out int resume_handle 84 | ); 85 | 86 | [DllImport("netapi32.dll")] 87 | public static extern int NetApiBufferFree(IntPtr buffer); 88 | 89 | // Constants for NetUserEnum function 90 | public const int FILTER_NORMAL_ACCOUNT = 0x0002; 91 | public const int NERR_Success = 0; 92 | 93 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 94 | public struct USER_INFO_0 95 | { 96 | public string name; 97 | } 98 | 99 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 100 | public struct USER_INFO_1 101 | { 102 | [MarshalAs(UnmanagedType.LPWStr)] public string sUsername; 103 | [MarshalAs(UnmanagedType.LPWStr)] public string sPassword; 104 | public uint uiPasswordAge; 105 | public uint uiPriv; 106 | [MarshalAs(UnmanagedType.LPWStr)] public string sHome_Dir; 107 | [MarshalAs(UnmanagedType.LPWStr)] public string sComment; 108 | public uint uiFlags; 109 | [MarshalAs(UnmanagedType.LPWStr)] public string sScript_Path; 110 | } 111 | 112 | 113 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 114 | public struct LOCALGROUP_MEMBERS_INFO_3 115 | { 116 | public IntPtr lgrmi3_domainandname; 117 | } 118 | } 119 | 120 | public static class WinUserManager 121 | { 122 | /// 123 | /// Add user by username and password 124 | /// 125 | /// 126 | /// 127 | /// 0 on success 128 | public static int CreateAccount(string username, string password) 129 | { 130 | WinUser.USER_INFO_1 userInfo = new WinUser.USER_INFO_1 131 | { 132 | sUsername = username, 133 | sPassword = password, 134 | uiPasswordAge = 0, 135 | uiPriv = 1, // USER_PRIV_USER 136 | sHome_Dir = null, 137 | sComment = "xboxacc", 138 | uiFlags = 0x0040 | 0x0200, // UF_PASSWD_CANT_CHANGE or 0 139 | sScript_Path = null 140 | }; 141 | 142 | Console.WriteLine("Adding user..."); 143 | 144 | int result = WinUser.NetUserAdd(null, 1, ref userInfo, out _); 145 | if (result != 0) 146 | { 147 | Console.WriteLine("NetUserAdd failed with error code: " + result); 148 | return result; 149 | } 150 | 151 | AddAccountToGroup(username, "Administrators"); 152 | return 0; 153 | } 154 | 155 | /// 156 | /// Add Account to group by name 157 | /// 158 | /// Target username 159 | /// Group to add to 160 | /// 0 on success 161 | public static int AddAccountToGroup(string username, string group) 162 | { 163 | WinUser.LOCALGROUP_MEMBERS_INFO_3 membersInfo = new WinUser.LOCALGROUP_MEMBERS_INFO_3 164 | { 165 | lgrmi3_domainandname = Marshal.StringToCoTaskMemUni(username) 166 | }; 167 | int result = WinUser.NetLocalGroupAddMembers(null, group, 3, ref membersInfo, 1); 168 | if (result != 0) 169 | { 170 | Console.WriteLine("NetLocalGroupAddMembers failed with error code: " + result); 171 | } 172 | else { 173 | Console.WriteLine($"User added to group: {group}"); 174 | } 175 | Marshal.FreeCoTaskMem(membersInfo.lgrmi3_domainandname); 176 | return result; 177 | } 178 | 179 | /// 180 | /// Remove Account from group by name 181 | /// 182 | /// Target username 183 | /// Group to remove 184 | /// 0 on success 185 | public static int RemoveAccountFromGroup(string username, string group) 186 | { 187 | WinUser.LOCALGROUP_MEMBERS_INFO_3 membersInfo = new WinUser.LOCALGROUP_MEMBERS_INFO_3 188 | { 189 | lgrmi3_domainandname = Marshal.StringToCoTaskMemUni(username) 190 | }; 191 | int result = WinUser.NetLocalGroupDelMembers(null, group, 3, ref membersInfo, 1); 192 | if (result != 0) 193 | { 194 | Console.WriteLine("NetLocalGroupRemoveMembers failed with error code: " + result); 195 | } 196 | else { 197 | Console.WriteLine($"User remove from group: {group}"); 198 | } 199 | Marshal.FreeCoTaskMem(membersInfo.lgrmi3_domainandname); 200 | return result; 201 | } 202 | 203 | /// 204 | /// Delete useraccount by name 205 | /// 206 | /// 207 | /// 0 on success 208 | public static int DeleteAccount(string username) 209 | { 210 | Console.WriteLine("Deleting user..."); 211 | 212 | int result = WinUser.NetUserDel(null, username); 213 | if (result != 0) 214 | { 215 | Console.WriteLine("NetUserDel failed with error code: " + result); 216 | return result; 217 | } 218 | 219 | Console.WriteLine("User deleted!"); 220 | return 0; 221 | } 222 | 223 | public static List ListLocalUsers() 224 | { 225 | List localUsers = new List(); 226 | 227 | // Call NetUserEnum function 228 | IntPtr buffer; 229 | int entriesRead, totalEntries; 230 | int resumeHandle; 231 | 232 | int result = WinUser.NetUserEnum(null, 0, WinUser.FILTER_NORMAL_ACCOUNT, out buffer, -1, out entriesRead, out totalEntries, out resumeHandle); 233 | 234 | if (result == WinUser.NERR_Success) 235 | { 236 | // Get the array of USER_INFO_0 structures 237 | WinUser.USER_INFO_0[] userInfos = new WinUser.USER_INFO_0[entriesRead]; 238 | IntPtr iter = buffer; 239 | 240 | for (int i = 0; i < entriesRead; i++) 241 | { 242 | userInfos[i] = (WinUser.USER_INFO_0)Marshal.PtrToStructure(iter, typeof(WinUser.USER_INFO_0)); 243 | iter += Marshal.SizeOf(typeof(WinUser.USER_INFO_0)); 244 | } 245 | 246 | // Add the usernames to the list 247 | foreach (WinUser.USER_INFO_0 userInfo in userInfos) 248 | { 249 | localUsers.Add(userInfo.name); 250 | } 251 | } 252 | 253 | // Free the memory allocated by NetUserEnum 254 | WinUser.NetApiBufferFree(buffer); 255 | 256 | return localUsers; 257 | } 258 | 259 | public static string GetSidString(string domain, string userName) 260 | { 261 | // Initialize variables needed for the LookupAccountName function 262 | const int ERROR_INSUFFICIENT_BUFFER = 122; 263 | uint sidLength = 0; 264 | uint domainNameLength = 0; 265 | WinUser.SID_NAME_USE sidType; 266 | 267 | // First call to LookupAccountName to get the size needed for the buffer 268 | if (!WinUser.LookupAccountName(domain, userName, IntPtr.Zero, ref sidLength, null, ref domainNameLength, out sidType)) 269 | { 270 | int error = Marshal.GetLastWin32Error(); 271 | if (error != ERROR_INSUFFICIENT_BUFFER) 272 | { 273 | throw new System.ComponentModel.Win32Exception(error); 274 | } 275 | } 276 | 277 | // Allocate memory for the buffers 278 | IntPtr sidBytesPtr = Marshal.AllocCoTaskMem((int)sidLength); 279 | StringBuilder domainName = new StringBuilder((int)domainNameLength); 280 | 281 | // Second call to LookupAccountName to retrieve the actual SID and domain name 282 | if (!WinUser.LookupAccountName(domain, userName, sidBytesPtr, ref sidLength, domainName, ref domainNameLength, out sidType)) 283 | { 284 | Marshal.FreeCoTaskMem(sidBytesPtr); 285 | throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); 286 | } 287 | 288 | // Convert the SID bytes to a string representation 289 | byte[] sidBytes = new byte[sidLength]; 290 | Marshal.Copy(sidBytesPtr, sidBytes, 0, (int)sidLength); 291 | string sidString = new SecurityIdentifier(sidBytes, 0).ToString(); 292 | Marshal.FreeCoTaskMem(sidBytesPtr); 293 | return sidString; 294 | } 295 | 296 | public static int AddProfile(string username) 297 | { 298 | string userSid = GetSidString(Environment.MachineName, username); 299 | 300 | // Create a string builder to hold the profile path 301 | StringBuilder profilePathBuffer = new StringBuilder(260); 302 | uint bufferSize = (uint)profilePathBuffer.Capacity; 303 | 304 | // Call CreateProfile 305 | int result = WinUser.CreateProfile(userSid, username, profilePathBuffer, bufferSize); 306 | 307 | // Check the result 308 | if (result == 0) 309 | { 310 | // Successfully created profile 311 | Console.WriteLine($"Profile path for user '{username}' is: {profilePathBuffer}"); 312 | } 313 | else 314 | { 315 | // Failed to create profile 316 | Console.WriteLine($"Failed to create profile for user '{username}'."); 317 | } 318 | 319 | return result; 320 | } 321 | 322 | /// 323 | /// Delete profile of a user 324 | /// 325 | /// 326 | /// true on success 327 | public static bool DeleteProfile(string username) 328 | { 329 | string userSid = GetSidString(Environment.MachineName, username); 330 | bool result = WinUser.DeleteProfileW(userSid, null, null); 331 | 332 | if (result) 333 | { 334 | Console.WriteLine($"Profile for user '{username}' deleted"); 335 | } 336 | else 337 | { 338 | Console.WriteLine($"Failed to delete profile for user '{username}'."); 339 | } 340 | return result; 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /src/XCrd.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Bless ol' xcrdutil 3 | // 4 | public static class XCrd 5 | { 6 | [DllImport("xcrdapi.dll", PreserveSig = false)] 7 | public static extern uint XCrdOpenAdapter(out IntPtr hAdapter); 8 | 9 | [DllImport("xcrdapi.dll", PreserveSig = false)] 10 | public static extern uint XCrdCloseAdapter(IntPtr hAdapter); 11 | 12 | [DllImport("xcrdapi.dll", PreserveSig = false)] 13 | public static extern uint XCrdMount(out IntPtr hDevice, IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string crdPath, uint mountFlags); 14 | 15 | [DllImport("xcrdapi.dll", PreserveSig = false)] 16 | public static extern uint XCrdUnmount(IntPtr hAdapter, IntPtr hDevice); 17 | 18 | // 1 page == 0x1000 (4k) 19 | [DllImport("xcrdapi.dll", PreserveSig = false)] 20 | public static extern uint XCrdCreateXVD( 21 | IntPtr hAdapter, 22 | [MarshalAs(UnmanagedType.LPWStr)] string crdPath, 23 | Guid someId, 24 | XvdCreateFlags createFlags, 25 | ulong drivePages, 26 | XvdType xvdType, 27 | XvdContentType xvdContentType, 28 | out Guid outputGuid, 29 | Guid productId, 30 | string sandboxId, 31 | uint sandboxLen, 32 | [MarshalAs(UnmanagedType.LPWStr)] string templateXvd 33 | ); 34 | 35 | [DllImport("xcrdapi.dll", PreserveSig = false)] 36 | public static extern uint XCrdDeleteXVD(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string crdPath, uint flags); 37 | 38 | [DllImport("xcrdapi.dll", PreserveSig = false)] 39 | public static extern uint XCrdUnmountByPath(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string crdPath); 40 | 41 | [DllImport("xcrdapi.dll", PreserveSig = false)] 42 | public static extern uint XCrdQueryCrdInformation(IntPtr hAdapter, int xcrdId, int xcrdQueryClass, out IntPtr info, ulong length); 43 | 44 | [DllImport("xcrdapi.dll", PreserveSig = false)] 45 | public static extern uint XCrdQueryXvdInformation(IntPtr hAdapter, string crdPath, ulong infoClass, out IntPtr infoBuffer, ulong length); 46 | 47 | [DllImport("xcrdapi.dll", PreserveSig = false)] 48 | public static extern uint XCrdQueryDevicePath([MarshalAs(UnmanagedType.LPWStr)] out string devicePath, IntPtr hDeviceHandle); 49 | 50 | [DllImport("xcrdapi.dll", PreserveSig = false)] 51 | public static extern uint XCrdReadUserDataXVD(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string srcPath, ulong offset, IntPtr buffer, ref uint length); 52 | 53 | [DllImport("xcrdapi.dll", PreserveSig = false)] 54 | public static extern uint XCrdStorageReadBlob(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string srcPath, IntPtr buf, ref uint readSize); 55 | [DllImport("xcrdapi.dll", PreserveSig = false)] 56 | public static extern uint XCrdStorageWriteBlob(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string dstPath, byte[] buf, uint writeSize); 57 | [DllImport("xcrdapi.dll", PreserveSig = false)] 58 | public static extern uint XCrdStorageMoveBlob(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string src, [MarshalAs(UnmanagedType.LPWStr)] string dst, uint flags); 59 | [DllImport("xcrdapi.dll", PreserveSig = false)] 60 | public static extern uint XCrdStorageDeleteBlob(IntPtr hAdapter, [MarshalAs(UnmanagedType.LPWStr)] string path); 61 | 62 | [DllImport("xcrdapi.dll", PreserveSig = false)] 63 | public static extern uint XCrdXBlobCreate( 64 | IntPtr hAdapter, 65 | [MarshalAs(UnmanagedType.LPWStr)] string path, 66 | ulong size, 67 | uint flags 68 | ); 69 | [DllImport("xcrdapi.dll", PreserveSig = false)] 70 | public static extern uint XCrdXBlobCopy( 71 | IntPtr hAdapter, 72 | [MarshalAs(UnmanagedType.LPWStr)] string srcPath, 73 | [MarshalAs(UnmanagedType.LPWStr)] string dstPath, 74 | ulong offset, 75 | ulong length, 76 | uint flags, 77 | ref ulong bytesRead 78 | ); 79 | [DllImport("xcrdapi.dll", PreserveSig = false)] 80 | public static extern uint XCrdXBlobDelete( 81 | IntPtr hAdapter, 82 | [MarshalAs(UnmanagedType.LPWStr)] string path 83 | ); 84 | 85 | [DllImport("xcrdapi.dll", PreserveSig = false)] 86 | public static extern uint XCrdFindFirstBlob( 87 | out IntPtr hEnum, 88 | ref IntPtr data, 89 | uint xcrdId, 90 | [MarshalAs(UnmanagedType.LPWStr)] string path, 91 | uint flags 92 | ); 93 | 94 | [DllImport("xcrdapi.dll", PreserveSig = false)] 95 | public static extern uint XCrdFindNextBlob( 96 | IntPtr hEnum, ref IntPtr data 97 | ); 98 | 99 | [DllImport("xcrdapi.dll", PreserveSig = false)] 100 | public static extern uint XCrdFindCloseBlob(IntPtr hEnum); 101 | 102 | [DllImport("xcrdapi.dll", PreserveSig = false)] 103 | public static extern uint XCrdStreamingStart( 104 | out IntPtr hStreamAdapter, 105 | IntPtr hAdapter, 106 | [MarshalAs(UnmanagedType.LPWStr)] string xcrdSourcePath, 107 | [MarshalAs(UnmanagedType.LPWStr)] string unkPath, 108 | [MarshalAs(UnmanagedType.LPWStr)] string xcrdDestPath, 109 | [MarshalAs(UnmanagedType.LPWStr)] string unkPath2, 110 | [MarshalAs(UnmanagedType.LPWStr)] string unkPath3, 111 | uint SpecifierCount, 112 | IntPtr Specifiers, 113 | uint Flags, 114 | out ulong DstSize, 115 | out IntPtr ErrorSource 116 | ); 117 | [DllImport("xcrdapi.dll", PreserveSig = false)] 118 | public static extern uint XCrdStreamingStop(IntPtr hAdapter, IntPtr hInstance, uint flags); 119 | [DllImport("xcrdapi.dll", PreserveSig = false)] 120 | public static extern uint XCrdStreamingQueryActiveInstanceId(IntPtr hAdapter, out IntPtr hInstanceId); 121 | [DllImport("xcrdapi.dll", PreserveSig = false)] 122 | // QueryInformation untested 123 | public static extern uint XCrdStreamingQueryInformation(IntPtr info, IntPtr hAdapter, IntPtr hInstance); 124 | 125 | [Flags] 126 | public enum XCrdAttributes : uint 127 | { 128 | DetectBufferAvailable = 1, 129 | Directory = 2, 130 | DosPathAvailable = 4 131 | } 132 | 133 | public enum XCrdQueryInformationType 134 | { 135 | XCrdQueryBasicInfo = 0, 136 | XCrdQueryXvcKeyIdInfo = 1, 137 | XCrdQueryMinSysVer = 2, 138 | XCrdQueryBasicInfoHeaderOnly = 3, 139 | XCrdQueryPlsInfo = 4, 140 | XCrdQueryVersionId = 5, 141 | XCrdQueryConsistencyChecked = 6, 142 | XCrdQueryXasCounters = 7, 143 | XCrdQueryXVCSCounters = 8, 144 | XCrdQuerySigningInfo = 9, 145 | XCrdQueryUpdateInfo = 10, 146 | XCrdQueryBaseXvdCounters = 11, 147 | XCrdQueryXvdPointerInfo = 12, 148 | XCrdQuerySupportedPlatforms = 17, 149 | XCrdSystemQueryXCloudFeatureBits = 18, 150 | XCrdQueryXvdLocalPointerInfo = 19 151 | } 152 | 153 | public enum XvdType 154 | { 155 | XvdTypeFixed = 0, 156 | XvdTypeDynamic, 157 | XvdTypeMax 158 | } 159 | 160 | public enum XvdContentType : uint 161 | { 162 | Data = 0, 163 | Title = 1, 164 | SystemOS = 2, 165 | EraOS = 3, 166 | Scratch = 4, 167 | ResetData = 5, 168 | Application = 6, 169 | HostOS = 7, 170 | X360STFS = 8, 171 | X360FATX = 9, 172 | X360GDFX = 0xA, 173 | Updater = 0xB, 174 | OfflineUpdater = 0xC, 175 | Template = 0xD, 176 | MteHost = 0xE, 177 | MteApp = 0xF, 178 | MteTitle = 0x10, 179 | MteEraOS = 0x11, 180 | EraTools = 0x12, 181 | SystemTools = 0x13, 182 | SystemAux = 0x14, 183 | AcousticModel = 0x15, 184 | SystemCodecsVolume = 0x16, 185 | QasltPackage = 0x17, 186 | AppDlc = 0x18, 187 | TitleDlc = 0x19, 188 | UniversalDlc = 0x1A, 189 | SystemDataVolume = 0x1B, 190 | TestVolume = 0x1C, 191 | HardwareTestVolume = 0x1D, 192 | KioskContent = 0x1E, 193 | HostProfiler = 0x20, 194 | Uwa = 0x21, 195 | Unknown22 = 0x22, 196 | Unknown23 = 0x23, 197 | Unknown24 = 0x24, 198 | ServerAgent = 0x25 199 | } 200 | 201 | public enum XvdVolumeFlags : uint 202 | { 203 | ReadOnly = 1, 204 | EncryptionDisabled = 2, // data decrypted, no encrypted CIKs 205 | DataIntegrityDisabled = 4, // unsigned and unhashed 206 | LegacySectorSize = 8, 207 | ResiliencyEnabled = 0x10, 208 | SraReadOnly = 0x20, 209 | RegionIdInXts = 0x40, 210 | TitleSpecific = 0x80, 211 | PointerXvd = 0x100, 212 | StreamingRoamable = 0x200, 213 | DiffusiveDisabled = 0x400, 214 | SpoofedDuid = 0x800, 215 | Reserved0 = 0x1000, // old TrimSupported 216 | TrimSupported = 0x2000, 217 | RoamingEnabled = 0x4000, 218 | Unknown0 = 0x8000, 219 | } 220 | 221 | public enum XvdCreateFlags: ulong 222 | { 223 | EncryptionEnabled = 1, 224 | DataIntegrityEnabled = 2, 225 | // Unsure about this, could be read-only 226 | Unknown = 4, 227 | NativePaths = 0x20, 228 | ResiliencyEnabled = 0x40, 229 | TitleSpecific = 0x100, 230 | SraReadOnly = 0x200, 231 | EphemeralKey = 0x10_000, 232 | StreamingRoamableEnabled = 0x20_000, 233 | TrimEnabled = 0x100_000, 234 | RoamingEnabled = 0x200_000, 235 | EphemeralKeyShared = 0x400_000, 236 | 237 | // ACL 238 | ACL_APPCONTAINER = 0x80, 239 | ACL_SYSTEM = 0x1_000, 240 | ACL_WER = 0x1_080 241 | } 242 | 243 | public enum StreamingSource : uint 244 | { 245 | Cache, 246 | Update, 247 | FsDefragmenting, 248 | NandDefragmenting 249 | } 250 | 251 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 252 | public struct XCrdXvdBasicInfo 253 | { 254 | public ushort FormatVersion; 255 | public byte SupportedPlatforms; 256 | public byte Unknown; 257 | public XvdType Type; 258 | public XvdContentType ContentType; 259 | public XvdVolumeFlags Flags; 260 | public ulong CreationTime; 261 | public ulong DriveSize; 262 | 263 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 264 | public byte[] VDUID; 265 | 266 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 267 | public byte[] UVUID; 268 | 269 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 270 | public byte[] PDUID; 271 | 272 | public ulong PackageVersion; 273 | 274 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 275 | public char[] SandboxId; 276 | 277 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 278 | public byte[] ProductId; 279 | 280 | public ulong BlobSize; 281 | } 282 | 283 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 284 | public struct XCrdBuffer 285 | { 286 | public uint Length; // 0x00 287 | public uint Type; // 0x04 288 | } 289 | 290 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 291 | public struct Utf16StringPtr 292 | { 293 | public uint StringPtr; // 0x00 294 | public uint StringLen; // 0x04 295 | } 296 | 297 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 298 | public struct XCrdInfo 299 | { 300 | // Skipping \\ prefix of filename 301 | public Utf16StringPtr Filename; // 0x00 302 | public Utf16StringPtr DosPath; // 0x08 303 | public Utf16StringPtr CrdPath; // 0x10 304 | public IntPtr Buffer; // 0x18 305 | public ulong Size; // 0x20 306 | public ulong CreationTime; // 0x28 307 | public XCrdAttributes Attributes; // 0x30 308 | /* END 0x34 */ 309 | } 310 | 311 | 312 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 313 | public struct XvdStreamingInfo 314 | { 315 | public ulong StreamId; // 0x00 316 | 317 | ulong Unknown08; // 0x08 - UNKNOWN 318 | 319 | public ulong StreamedBytes; // 0x10 320 | public ulong SourceStreamedBytes; // 0x18 321 | public ulong CacheStreamedBytes; // 0x20 322 | public ulong UpdateStreamedBytes; // 0x28 323 | public ulong FallbackStreamedBytes; // 0x30 324 | 325 | ulong Unknown38; // 0x38 - UNKNOWN 326 | 327 | public ulong DownloadSize; // 0x40 328 | public ulong StagingSize; // 0x48 329 | public ulong BlobSize; // 0x50 330 | public ulong ActiveRegion; // 0x58 331 | public ulong ActiveRegionStreamedBytes; // 0x60 332 | public ulong RegionCount; // 0x68 333 | public ulong StreamedRegionCount; // 0x70 334 | public uint InitialPlayRegionId; // 0x78 335 | public uint CacheLastIoStatus; // 0x7C 336 | public ulong InitialPlayRegionOffset; // 0x80 337 | public ulong PaddingBytes; // 0x88 338 | public uint SourceLastIoStatus; // 0x90 339 | public uint DestinationLastIoStatus; // 0x94 340 | public uint SourceStreaming; // 0x98 341 | public uint RegionSpecifierCount; // 0x9C 342 | public uint StreamingDisc; // 0xA0 343 | public uint NeededDisc; // 0xA4 344 | public ulong SegmentCount; // 0xA8 345 | 346 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] 347 | byte[] UnknownB0; // 0xB0 - MISSING 348 | 349 | public ulong XipMissBytes; // 0xC0 350 | public uint XipMissCount; // 0xC8 351 | public uint XipReadAhead; // 0xCC 352 | public Guid StreamingPlanId; // 0xD0 353 | public ulong FsDefragmentedBytes; // 0xE0 354 | public ulong FsDefragmentedRequiredBytes; // 0xE8 355 | public ulong NandDefragmentedBytes; // 0xF0 356 | public ulong NandDefragmentRequiredBytes; // 0xF8 357 | 358 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 359 | public byte[] Reserved; // 0x100 360 | /* END 0x110 */ 361 | } 362 | 363 | public static readonly string[] XcrdIdMapping = new string[]{ 364 | "[XTE:]", 365 | "[XUC:]", 366 | "[XSS:]", 367 | "[XSU:]", 368 | null, 369 | "[XFG:]", 370 | null, 371 | "[XTF:]", 372 | "[XBL:]", 373 | "[XOD:]", 374 | "[XVE:]", 375 | "[XT0:]", 376 | "[XT1:]", 377 | "[XT2:]", 378 | "[XT3:]", 379 | "[XT4:]", 380 | "[XT5:]", 381 | "[XT6:]", 382 | "[XT7:]", 383 | "[XE0:]", 384 | "[XE1:]", 385 | "[XE2:]", 386 | "[XE3:]", 387 | "[XE4:]", 388 | "[XE5:]", 389 | "[XE6:]", 390 | "[XE7:]", 391 | "[XBX:]", 392 | "[XSR:]", 393 | null, 394 | "[XAS:]", 395 | "[XRT:]", 396 | "[XRU:]", 397 | "[XRS:]", 398 | "[XRI:]", 399 | null, 400 | "[XCC:]" 401 | }; 402 | } 403 | 404 | public class XCrdManager : IDisposable 405 | { 406 | const int CHUNK_SIZE = 16 * 1024 * 1024; // 16MB 407 | readonly IntPtr _adapterHandle; 408 | 409 | public XCrdManager() 410 | { 411 | uint result = XCrd.XCrdOpenAdapter(out IntPtr hAdapter); 412 | if (hAdapter == IntPtr.Zero) 413 | { 414 | throw new Exception($"Failed to open XCRD adapter, code: {result:08x}"); 415 | } 416 | _adapterHandle = hAdapter; 417 | } 418 | 419 | public string Mount(string xvdPath) 420 | { 421 | uint result = XCrd.XCrdMount(out IntPtr hDevice, _adapterHandle, xvdPath, 0); 422 | if (result != 0 || hDevice == IntPtr.Zero) 423 | { 424 | Console.WriteLine("Failed to mount target! Result: " + result); 425 | return null; 426 | } 427 | 428 | result = XCrd.XCrdQueryDevicePath(out string devicePath, hDevice); 429 | if (result != 0) 430 | { 431 | Console.WriteLine("Failed to read device path! Result: " + result); 432 | return null; 433 | } 434 | 435 | return devicePath; 436 | } 437 | 438 | /// 439 | /// Unmount an XVD based on XCRD path (host-relevant path) 440 | /// 441 | /// 442 | /// 0 on success 443 | public uint Unmount(string xcrdPath) 444 | { 445 | uint result = XCrd.XCrdUnmountByPath(_adapterHandle, xcrdPath); 446 | if (result != 0) 447 | { 448 | Console.WriteLine("[x] Failed to unmount target xvd!"); 449 | Console.WriteLine("[x] Result: " + result); 450 | return result; 451 | } 452 | Console.WriteLine("Unmounted successfully"); 453 | return 0; 454 | } 455 | 456 | // 1 page = 0x1000 (4k) 457 | public uint CreateXVD(string crdPath, Guid someId, XCrd.XvdCreateFlags createFlags, ulong drivePages, XCrd.XvdType xvdType, XCrd.XvdContentType contentType, out Guid outputGuid, Guid productId, string sandboxId) 458 | { 459 | uint result = XCrd.XCrdCreateXVD(_adapterHandle, crdPath, someId, createFlags, drivePages, xvdType, contentType, out outputGuid, productId, sandboxId, (uint)sandboxId.Length, null); 460 | if (result != 0) 461 | { 462 | Console.WriteLine("[x] Failed to create xvd! Result:" + result.ToString()); 463 | } 464 | return result; 465 | } 466 | 467 | public uint DeleteXVD(string xvdPath) 468 | { 469 | uint result = XCrd.XCrdDeleteXVD(_adapterHandle, xvdPath, 0); 470 | if (result != 0) 471 | { 472 | Console.WriteLine("[x] Failed to delete xvd! Result:" + result.ToString()); 473 | } 474 | return result; 475 | } 476 | 477 | public IntPtr QueryXvdInfo(string xvdPath) 478 | { 479 | uint result = XCrd.XCrdQueryXvdInformation(_adapterHandle, xvdPath, 0, out IntPtr infoBuffer, 128); 480 | if (result != 0) 481 | { 482 | Console.WriteLine("Failed to query xvd info: " + result.ToString()); 483 | return IntPtr.Zero; 484 | } 485 | 486 | return infoBuffer; 487 | } 488 | 489 | public uint ReadUserdata(string srcPath, ulong offset, int length, string dstPath) 490 | { 491 | IntPtr buf = Marshal.AllocHGlobal(length); 492 | if (buf == IntPtr.Zero) 493 | { 494 | Console.WriteLine("Failed to allocate buffer"); 495 | return 1; 496 | } 497 | 498 | uint readLen = (uint)length; 499 | uint result = XCrd.XCrdReadUserDataXVD(_adapterHandle, srcPath, offset, buf, ref readLen); 500 | if (result != 0) 501 | { 502 | Console.WriteLine("Failed to read userdata: " + result.ToString()); 503 | Marshal.FreeHGlobal(buf); 504 | return result; 505 | } 506 | else if (readLen != length) { 507 | Console.WriteLine("Mismatch: expected " + length + " bytes, got " + readLen + " bytes"); 508 | } 509 | 510 | byte[] byteBuffer = new byte[readLen]; 511 | Marshal.Copy(buf, byteBuffer, 0, (int)readLen); 512 | File.WriteAllBytes(dstPath, byteBuffer); 513 | 514 | Marshal.FreeHGlobal(buf); 515 | return 0; 516 | } 517 | 518 | /* 519 | Reads VBI file from System XVD 520 | 521 | Src paths to try: 522 | 523 | - F:\system.xvd 524 | - R:\A\system.xvd or [XSU:]\A\system.xvd 525 | - R:\B\system.xvd or [XSU:]\B\system.xvd 526 | 527 | */ 528 | public uint ReadVbi(string srcPath, string dstPath) 529 | { 530 | byte[] lenBuf = new byte[0x10]; 531 | IntPtr lenBufPtr = Marshal.AllocHGlobal(lenBuf.Length); 532 | if (lenBufPtr == IntPtr.Zero) 533 | { 534 | Console.WriteLine("Failed to allocate len-buffer"); 535 | return 1; 536 | } 537 | 538 | // Read first 0x10 bytes from header (offset 0x8 SizeOfHeaders, offset 0xC ImageSize) 539 | uint readLen = (uint)lenBuf.Length; 540 | uint result = XCrd.XCrdReadUserDataXVD(_adapterHandle, srcPath, 0, lenBufPtr, ref readLen); 541 | if (result != 0 || readLen != lenBuf.Length) 542 | { 543 | Console.WriteLine($"Failed to read userdata header: {result} readLen: {readLen}"); 544 | Marshal.FreeHGlobal(lenBufPtr); 545 | return result; 546 | } 547 | 548 | // Copy header bytes to managed memory 549 | Marshal.Copy(lenBufPtr, lenBuf, 0, lenBuf.Length); 550 | 551 | // Read sizes from header 552 | uint size = BitConverter.ToUInt32(lenBuf, 0x8); // SizeOfHeader 553 | size += BitConverter.ToUInt32(lenBuf, 0xC); // ImageSize 554 | 555 | Console.WriteLine($"Full VBI Size: {size} bytes"); 556 | 557 | // Read final VBI 558 | byte[] vbiBuf = new byte[size]; 559 | IntPtr vbiBufPtr = Marshal.AllocHGlobal((int)size); 560 | if (vbiBufPtr == IntPtr.Zero) 561 | { 562 | Console.WriteLine("Failed to allocate vbi-buffer"); 563 | return 1; 564 | } 565 | 566 | readLen = size; 567 | result = XCrd.XCrdReadUserDataXVD(_adapterHandle, srcPath, 0, vbiBufPtr, ref readLen); 568 | if (result != 0 || readLen != size) 569 | { 570 | Console.WriteLine($"Failed to read userdata (3): {result} readLen: {readLen}"); 571 | Marshal.FreeHGlobal(lenBufPtr); 572 | Marshal.FreeHGlobal(vbiBufPtr); 573 | return result; 574 | } 575 | 576 | Marshal.Copy(vbiBufPtr, vbiBuf, 0, (int)readLen); 577 | 578 | File.WriteAllBytes(dstPath, vbiBuf); 579 | 580 | Marshal.FreeHGlobal(lenBufPtr); 581 | Marshal.FreeHGlobal(vbiBufPtr); 582 | 583 | return result; 584 | } 585 | 586 | public uint EnumBlobs(uint xcrdId, string path, uint flags) 587 | { 588 | uint ret; 589 | if (xcrdId >= 0x25) { 590 | return 0x80070057; 591 | } 592 | 593 | var xcrdName = XCrd.XcrdIdMapping[xcrdId]; 594 | 595 | Console.WriteLine($"Enumerating blob at {xcrdName}/{path}"); 596 | 597 | if (path == "*") { 598 | path = null; 599 | } 600 | 601 | IntPtr pInfoBuffer = Marshal.AllocHGlobal(0x200); 602 | ret = XCrd.XCrdFindFirstBlob(out IntPtr hEnum, ref pInfoBuffer, xcrdId, path, flags); 603 | if (ret < 0) { 604 | Console.WriteLine("Failed to find first blob: 0x{ret:X}"); 605 | return ret; 606 | } 607 | 608 | int pos = 0; 609 | do { 610 | Console.WriteLine("--- Entry {0} ---", pos); 611 | Console.WriteLine(XcrdInfoToString(pInfoBuffer)); 612 | ret = XCrd.XCrdFindNextBlob(hEnum, ref pInfoBuffer); 613 | pos++; 614 | } while (ret != 0x80070012); 615 | 616 | XCrd.XCrdFindCloseBlob(hEnum); 617 | return ret; 618 | } 619 | 620 | string ReadUnicodeString(IntPtr ptr, uint offset, uint len) 621 | { 622 | byte[] buffer = new byte[len]; 623 | GCHandle pinnedArray = GCHandle.Alloc(buffer, GCHandleType.Pinned); 624 | IntPtr ptrToBuffer = pinnedArray.AddrOfPinnedObject(); 625 | Marshal.Copy(IntPtr.Add(ptr, (int)offset), buffer, 0, (int)len); 626 | return Encoding.Unicode.GetString(buffer); 627 | } 628 | 629 | string XcrdInfoToString(IntPtr ptrInfo) 630 | { 631 | var info = Marshal.PtrToStructure(ptrInfo); 632 | 633 | StringBuilder sb = new(); 634 | sb.AppendFormat("{0}\n", ReadUnicodeString(ptrInfo, info.Filename.StringPtr, info.Filename.StringLen)); 635 | sb.AppendFormat("Attributes ({0:X}) :\n", info.Attributes); 636 | if (info.Attributes.HasFlag(XCrd.XCrdAttributes.DetectBufferAvailable)) { 637 | sb.AppendLine("- DetectBufferAvailable"); 638 | } 639 | if (info.Attributes.HasFlag(XCrd.XCrdAttributes.Directory)) { 640 | sb.AppendLine("- Directory"); 641 | } 642 | if (info.Attributes.HasFlag(XCrd.XCrdAttributes.DosPathAvailable)) { 643 | sb.AppendLine("- DosPathAvailable"); 644 | } 645 | sb.AppendFormat("Size: {0:X}\n", info.Size); 646 | //sb.AppendFormat("Crd ID: {0} (0x{0:X})\n", info.XCrdId); 647 | sb.AppendFormat("Crd Path: {0}\n", ReadUnicodeString(ptrInfo, info.CrdPath.StringPtr, info.CrdPath.StringLen)); 648 | if (info.Attributes.HasFlag(XCrd.XCrdAttributes.DosPathAvailable)) 649 | { 650 | sb.AppendLine("DOS Path: (0)"); 651 | } 652 | else 653 | { 654 | sb.AppendFormat("DOS Path: {0}\n", ReadUnicodeString(ptrInfo, info.DosPath.StringPtr, info.DosPath.StringLen)); 655 | } 656 | sb.AppendFormat("Creation Time: {0}\n", info.CreationTime); 657 | //sb.AppendFormat("Detect HR: 0x{0:X}\n", info.DetectHr); 658 | sb.AppendLine("--------------------------------------"); 659 | 660 | return sb.ToString(); 661 | } 662 | 663 | string StreamingInfoToString(XCrd.XvdStreamingInfo info) 664 | { 665 | StringBuilder sb = new(); 666 | sb.AppendFormat("Active Region = 0x{0:X16}\n", info.ActiveRegion); 667 | sb.AppendFormat("Active Region Streamed Bytes = 0x{0:X16}\n", info.ActiveRegionStreamedBytes); 668 | sb.AppendFormat("Blob Size = 0x{0:X16}\n", info.BlobSize); 669 | sb.AppendFormat("Staging Size = 0x{0:X16}\n", info.StagingSize); 670 | sb.AppendFormat("Initial Play Region Id = 0x{0:X}\n", info.InitialPlayRegionId); 671 | sb.AppendFormat("Initial Play Region Offset = 0x{0:X16}\n", info.InitialPlayRegionOffset); 672 | sb.AppendFormat("Region Count = 0x{0:X16}\n", info.RegionCount); 673 | sb.AppendFormat("Segment Count = 0x{0:X16}\n", info.SegmentCount); 674 | sb.AppendFormat("Region Specifier Count = 0x{0:X}\n", info.RegionSpecifierCount); 675 | sb.AppendFormat("Streamed Region Count = 0x{0:X16}\n", info.StreamedRegionCount); 676 | sb.AppendFormat("Streamed Bytes = 0x{0:X16}\n", info.StreamedBytes); 677 | sb.AppendFormat("Source Streamed Bytes = 0x{0:X16}\n", info.SourceStreamedBytes); 678 | sb.AppendFormat("Cache Streamed Bytes = 0x{0:X16}\n", info.CacheStreamedBytes); 679 | sb.AppendFormat("Update Streamed Bytes = 0x{0:X16}\n", info.UpdateStreamedBytes); 680 | sb.AppendFormat("Fallback Streamed Bytes = 0x{0:X16}\n", info.FallbackStreamedBytes); 681 | sb.AppendFormat("Padding Bytes = 0x{0:X16}\n", info.PaddingBytes); 682 | sb.AppendFormat("Stream ID = 0x{0:X16}\n", info.StreamId); 683 | sb.AppendFormat("Download Size = 0x{0:X16}\n", info.DownloadSize); 684 | sb.AppendFormat("Source Last Io Status = 0x{0:X}\n", info.SourceLastIoStatus); 685 | sb.AppendFormat("Cache Last Io Status = 0x{0:X}\n", info.CacheLastIoStatus); 686 | sb.AppendFormat("Destination Last Io Status = 0x{0:X}\n", info.DestinationLastIoStatus); 687 | sb.AppendFormat("Source Streaming = {0:X}\n", info.SourceStreaming); 688 | // sb.AppendFormat("Cache Streaming = {0:X}"); 689 | // sb.AppendFormat("Update Streaming = {0:X}"); 690 | // sb.AppendFormat("FS Defragmenting = {0:X}"); 691 | // sb.AppendFormat("NAND Defragmenting = {0:X}"); 692 | sb.AppendFormat("Streaming Disc = {0:X}\n", info.StreamingDisc); 693 | sb.AppendFormat("Needed Disc = {0:X}\n", info.NeededDisc); 694 | sb.AppendFormat("XIP Miss Bytes = {0:X}\n", info.XipMissBytes); 695 | sb.AppendFormat("XIP Miss Count = {0:X}\n", info.XipMissCount); 696 | sb.AppendFormat("XIP Read Ahead (s) = {0:X}\n", info.XipReadAhead); 697 | // sb.AppendFormat("XIP Plan Type = {0}"); 698 | sb.AppendFormat("Streaming Plan Id = {0}\n", info.StreamingPlanId); 699 | sb.AppendFormat("FS Defragmented Bytes = {0:X}\n", info.FsDefragmentedBytes); 700 | sb.AppendFormat("FS Defragment Required Bytes = {0:X}\n", info.FsDefragmentedRequiredBytes); 701 | sb.AppendFormat("NAND Defragmented Bytes = {0:X}\n", info.NandDefragmentedBytes); 702 | sb.AppendFormat("NAND Defragment Required Bytes= {0:X}\n", info.NandDefragmentRequiredBytes); 703 | 704 | return sb.ToString(); 705 | } 706 | 707 | public uint Stream(string srcPath, string dstPath) 708 | { 709 | uint result = XCrd.XCrdStreamingStart( 710 | out IntPtr hInstanceId, 711 | _adapterHandle, 712 | srcPath, 713 | null, 714 | dstPath, 715 | null, 716 | null, 717 | 0, 718 | IntPtr.Zero, 719 | 0, 720 | out ulong dstSize, 721 | out IntPtr errorSource 722 | ); 723 | 724 | if (result != 0) 725 | { 726 | Console.WriteLine("Starting streaming failed: " + result.ToString()); 727 | return result; 728 | } 729 | Console.WriteLine("Streaming handle: 0x{0:X}", hInstanceId); 730 | 731 | IntPtr ptrInfoBuf = Marshal.AllocHGlobal(Marshal.SizeOf()); 732 | if (ptrInfoBuf == IntPtr.Zero) 733 | { 734 | Console.WriteLine("Failed to allocate XvdStreamingInfo buffer"); 735 | return 1; 736 | } 737 | 738 | while (true) 739 | { 740 | result = XCrd.XCrdStreamingQueryInformation(ptrInfoBuf, _adapterHandle, hInstanceId); 741 | if (result != 0) 742 | { 743 | Console.WriteLine("Failed to query streaming infos: " + result.ToString()); 744 | Marshal.FreeHGlobal(ptrInfoBuf); 745 | return result; 746 | } 747 | 748 | var streamingInfo = Marshal.PtrToStructure(ptrInfoBuf); 749 | Console.WriteLine(":: Streaming Info ::\n{0}", StreamingInfoToString(streamingInfo)); 750 | 751 | if (streamingInfo.BlobSize == streamingInfo.StreamedBytes) 752 | { 753 | Console.WriteLine("Streaming of {0:X16} bytes finished!", streamingInfo.StreamedBytes); 754 | break; 755 | } 756 | 757 | // Wait 5 seconds between queries 758 | Thread.Sleep(1000 * 5); 759 | } 760 | 761 | Marshal.FreeHGlobal(ptrInfoBuf); 762 | 763 | Console.WriteLine("Stopping streaming"); 764 | result = XCrd.XCrdStreamingStop(_adapterHandle, hInstanceId, 0); 765 | if (result != 0) 766 | { 767 | Console.WriteLine("Failed to stop streaming: " + result.ToString()); 768 | } 769 | 770 | return result; 771 | } 772 | 773 | public uint GetBlobSize(string srcHostPath) 774 | { 775 | uint fileSize = 0; 776 | // Get filesize 777 | uint result = XCrd.XCrdStorageReadBlob(_adapterHandle, srcHostPath, IntPtr.Zero, ref fileSize); 778 | if (result != 0) 779 | { 780 | Console.WriteLine("Failed to enumerate filesize: " + result.ToString()); 781 | return 0; 782 | } 783 | return fileSize; 784 | } 785 | 786 | public uint ReadBlob(string srcHostPath, string dstPath) 787 | { 788 | // Get filesize 789 | uint fileSize = GetBlobSize(srcHostPath); 790 | if (fileSize != 0) 791 | { 792 | Console.WriteLine("Failed to enumerate filesize for {0}", srcHostPath); 793 | return 1; 794 | } 795 | 796 | Console.WriteLine("FileSize: 0x{0:X} ({0})", fileSize); 797 | IntPtr buf = Marshal.AllocHGlobal((int)fileSize); 798 | if (buf == IntPtr.Zero) 799 | { 800 | Console.WriteLine("Failed to allocate buffer"); 801 | return 1; 802 | } 803 | 804 | uint result = XCrd.XCrdStorageReadBlob(_adapterHandle, srcHostPath, buf, ref fileSize); 805 | if (result != 0) 806 | { 807 | Console.WriteLine("Failed to read blob: " + result.ToString()); 808 | Marshal.FreeHGlobal(buf); 809 | return result; 810 | } 811 | 812 | uint position = 0; 813 | byte[] chunkBuffer = new byte[CHUNK_SIZE]; 814 | using var outFile = File.Open(dstPath, FileMode.Create); 815 | while (position < fileSize) 816 | { 817 | uint numBytes = Math.Min(CHUNK_SIZE, fileSize - position); 818 | Marshal.Copy(IntPtr.Add(buf, (int)position), chunkBuffer, 0, (int)numBytes); 819 | outFile.Write(chunkBuffer, 0, (int)numBytes); 820 | position += numBytes; 821 | } 822 | 823 | Marshal.FreeHGlobal(buf); 824 | return 0; 825 | } 826 | 827 | public uint WriteBlob(string dstHostPath, byte[] data) 828 | { 829 | uint result = XCrd.XCrdStorageWriteBlob(_adapterHandle, dstHostPath, data, (uint)data.Length); 830 | if (result != 0) 831 | { 832 | Console.WriteLine("Failed to write blob: " + result.ToString()); 833 | } 834 | 835 | return result; 836 | } 837 | 838 | public uint MoveBlob(string srcPath, string dstPath) 839 | { 840 | uint result = XCrd.XCrdStorageMoveBlob(_adapterHandle, srcPath, dstPath, 0); 841 | if (result != 0) 842 | { 843 | Console.WriteLine("Moving blob failed: " + result.ToString()); 844 | } 845 | return result; 846 | } 847 | 848 | public uint DeleteBlob(string filePath) 849 | { 850 | uint result = XCrd.XCrdStorageDeleteBlob(_adapterHandle, filePath); 851 | if (result != 0) 852 | { 853 | Console.WriteLine("Deleting blob failed: " + result.ToString()); 854 | } 855 | return result; 856 | } 857 | 858 | public void Dispose() 859 | { 860 | if (_adapterHandle != IntPtr.Zero) 861 | { 862 | XCrd.XCrdCloseAdapter(_adapterHandle); 863 | } 864 | } 865 | } 866 | -------------------------------------------------------------------------------- /src/modules/xcrdutil.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | # Script module or binary module file associated with this manifest 3 | RootModule = 'xcrdutil.psm1' 4 | 5 | # Version number of this module. 6 | ModuleVersion = '1.0.0' 7 | 8 | # Supported PSEditions 9 | CompatiblePSEditions = @('Desktop', 'Core', 'Core-7.2.3') 10 | 11 | # ID used to uniquely identify this module 12 | GUID = 'c56a4180-65aa-42ec-a945-5fd21dec0538' 13 | 14 | # Author of this module 15 | Author = 'Shadow LAG' 16 | 17 | # Company or vendor of this module 18 | CompanyName = 'XOS Team' 19 | 20 | # Description of the functionality provided by this module 21 | Description = 'Utility module for XCRD operations' 22 | 23 | # Minimum version of the Windows PowerShell engine required by this module 24 | PowerShellVersion = '5.1' 25 | 26 | # Modules that must be imported into the global environment prior to importing this module 27 | RequiredModules = @() 28 | 29 | # Assemblies that must be loaded prior to importing this module 30 | RequiredAssemblies = @('.\xcrd.dll') 31 | 32 | # Script files (.ps1) that are run in the caller's environment prior to importing this module 33 | ScriptsToProcess = @() 34 | 35 | # Type files (.ps1xml) to be loaded when importing this module 36 | TypesToProcess = @() 37 | 38 | # Format files (.ps1xml) to be loaded when importing this module 39 | FormatsToProcess = @() 40 | 41 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 42 | NestedModules = @() 43 | 44 | # Functions to export from this module 45 | FunctionsToExport = @('xcrdutil') 46 | 47 | # Cmdlets to export from this module 48 | CmdletsToExport = @() 49 | 50 | # Variables to export from this module 51 | VariablesToExport = @() 52 | 53 | # Aliases to export from this module 54 | AliasesToExport = @() 55 | 56 | # List of all modules packaged with this module 57 | FileList = @('xcrdutil.psm1', 'xcrd.dll') 58 | 59 | # Private data to pass to the module specified in RootModule/ModuleToProcess 60 | PrivateData = @{ 61 | 62 | } 63 | 64 | # HelpInfo URI of this module 65 | HelpInfoURI = '' 66 | 67 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix 68 | DefaultCommandPrefix = 'xcrd' 69 | } 70 | -------------------------------------------------------------------------------- /src/modules/xcrdutil.psm1: -------------------------------------------------------------------------------- 1 | # Usage information text 2 | $global:usageText = @" 3 | Usage : xcrdutil [parameters/options] 4 | 5 | Operations & parameters: 6 | -h - Usage information 7 | -m - mounts a xvd file as a virtual drive 8 | -um - unmounts a xvd drive for the specified xvd file 9 | -del - deletes a xvd file using a XCRD path 10 | -enum - enumerate blobs. path = * - enum root; flags = 1 - detect blob. 11 | -read_ud 12 | 13 | XCRD ID List: 14 | HDD Temp : 0 15 | HDD User Content : 1 16 | HDD System Support : 2 17 | HDD System Image : 3 18 | HDD Future Growth : 5 19 | XTF Remote Storage : 7 20 | XBL XBox Live Storage : 8 21 | XODD (System VM) : 9 22 | USB Transfer Storage : 11 - 18 23 | USB External Storage : 19 - 26 24 | XBOX (Copy-Over-Lan) : 27 25 | SRA (local or SMB) : 28 26 | "@ 27 | 28 | # Function to display usage information 29 | function Show-Usage { 30 | Write-Host $global:usageText 31 | } 32 | 33 | # Main function 34 | function xcrdutil { 35 | [CmdletBinding(DefaultParameterSetName="Help")] 36 | param ( 37 | [Parameter(ParameterSetName="Help")] 38 | [switch]$h, 39 | 40 | [Parameter(ParameterSetName="Mount")] 41 | [string]$m, 42 | 43 | [Parameter(ParameterSetName="Unmount")] 44 | [string]$um, 45 | 46 | [Parameter(ParameterSetName="Delete")] 47 | [string]$del, 48 | 49 | [Parameter(ParameterSetName="Enum")] 50 | [switch]$enum, 51 | 52 | [Parameter(ParameterSetName="Enum", Position=1)] 53 | [string]$xcrd_id, 54 | 55 | [Parameter(ParameterSetName="Enum", Position=2)] 56 | [string]$enum_rel_path, 57 | 58 | [Parameter(ParameterSetName="Enum", Position=3)] 59 | [string]$flags, 60 | 61 | [Parameter(ParameterSetName="ReadUserdata")] 62 | [switch]$read_ud, 63 | 64 | [Parameter(ParameterSetName="ReadUserdata", Position=1)] 65 | [string]$read_ud_src, 66 | 67 | [Parameter(ParameterSetName="ReadUserdata", Position=2)] 68 | [string]$read_ud_offset, 69 | 70 | [Parameter(ParameterSetName="ReadUserdata", Position=3)] 71 | [string]$read_ud_length, 72 | 73 | [Parameter(ParameterSetName="ReadUserdata", Position=4)] 74 | [string]$read_ud_destination, 75 | 76 | [Parameter(ParameterSetName="ReadVbi")] 77 | [switch]$read_vbi, 78 | 79 | [Parameter(ParameterSetName="ReadVbi", Position=1)] 80 | [string]$read_vbi_src, 81 | 82 | [Parameter(ParameterSetName="ReadVbi", Position=2)] 83 | [string]$read_vbi_destination 84 | ) 85 | 86 | # Check if no parameters are provided 87 | if (-not $PSCmdlet.MyInvocation.BoundParameters.Count) { 88 | Show-Usage 89 | return 90 | } 91 | 92 | if ($h) { 93 | Show-Usage 94 | return 95 | } 96 | 97 | Add-Type -Path .\xcrd.cs 98 | $xcrd = [XCrdManager]::new() 99 | 100 | if ($m) { 101 | Write-Host "-m: $m" 102 | $xcrd.Mount($m) 103 | } 104 | elseif ($um) { 105 | Write-Host "-um: $um" 106 | $xcrd.Unmount($um) 107 | } 108 | elseif ($del) { 109 | Write-Host "-del: $del" 110 | $xcrd.DeleteXVD($del) 111 | } 112 | elseif ($enum) { 113 | $xcrdIdUint = [uint32]::Parse($xcrd_id) 114 | $flagsUint = [uint32]::Parse($flags) 115 | Write-Host "-enum: $xcrdIdUint $enum_rel_path $flagsUint" 116 | $xcrd.EnumBlobs($xcrdIdUint, $enum_rel_path, $flagsUint) 117 | } 118 | elseif ($read_ud) { 119 | $udOffset = [uint64]::Parse($read_ud_offset) 120 | $udLength = [int32]::Parse($read_ud_length) 121 | Write-Host "-read_ud: $read_ud_src $udOffset $udLength $read_ud_destination" 122 | $xcrd.ReadUserdata($read_ud_src, $udOffset, $udLength, $read_ud_destination) 123 | } 124 | elseif ($read_vbi) { 125 | Write-Host "-read_vbi: $read_vbi_src $read_vbi_dst" 126 | $xcrd.ReadVbi($read_vbi_src, $read_vbi_dst) 127 | } 128 | } 129 | 130 | Export-ModuleMember -Function xcrdutil 131 | --------------------------------------------------------------------------------