├── .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 | [](https://github.com/xboxoneresearch/Interop/actions/workflows/build.yml)
2 | 
3 | [](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 |
--------------------------------------------------------------------------------