diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..a41d6d9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,25 @@ +# CODEOWNERS +# GitHub automatically requests a review from the listed owners whenever a PR +# modifies files matching the pattern. More specific rules override less specific +# ones (last match wins), so list broad patterns first. +# +# Docs: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +# Catch-all: maintainer reviews everything +* @sjackson0109 + +# C++ DLL source +src-x86-x64-Fusix/ @sjackson0109 + +# C# tools (installer, configurator, checker, offset-finder) +src-csharp/ @sjackson0109 + +# WiX MSI packaging +msi/ @sjackson0109 + +# CI/CD pipelines +.github/ @sjackson0109 + +# Documentation +docs/ @sjackson0109 +README.md @sjackson0109 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 36bdd9e..5e1061f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -58,6 +58,7 @@ body: options: - x64 (64-bit) - x86 (32-bit) + - ARM64 validations: required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d97f5ed --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,34 @@ +version: 2 + +updates: + # Keep GitHub Actions pinned to their latest minor/patch releases + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 10 + groups: + actions-minor: + patterns: ["*"] + + # Keep .NET SDK NuGet dependencies up to date (for src-csharp/) + - package-ecosystem: nuget + directory: /src-csharp + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 10 + + # Monitor git submodules for upstream releases + # Covers: src-csharp/RDPOffsetFinder (llccd/RDPWrapOffsetFinder) + # src-csharp/RDPOffsetFinder/zydis (zyantific/zydis) + # Note: gitsubmodule ecosystem is currently in Dependabot beta. + # Enable once the feature is available for the repository, or track + # submodule versions manually via the pinned SHA in .gitmodules. + - package-ecosystem: gitsubmodule + directory: / + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 5 diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml new file mode 100644 index 0000000..5725d77 --- /dev/null +++ b/.github/workflows/build-and-release.yml @@ -0,0 +1,776 @@ +name: Build and Release + +on: + push: + branches: [main, master] + paths: + - 'msi/rdpwrap.ini' + - 'msi/rdpwrap-arm-kb.ini' + - 'msi/**' + - 'src-x86-x64-Fusix/**' + - 'src-csharp/**' + - '.github/workflows/build-and-release.yml' + workflow_dispatch: + inputs: + tag: + description: 'Release tag (e.g. v2026.4.2). Leave blank to auto-generate from date.' + required: false + default: '' + prerelease: + description: 'Mark as pre-release' + type: boolean + required: false + default: false + +concurrency: + group: release + cancel-in-progress: true + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +permissions: + contents: write + +# ──────────────────────────────────────────────────────────────────────────── +# Job dependency / parallelism map +# +# build-dll ───────────────► build-csharp ──────────► build-msi ──┐ +# build-offsetfinder ───────────────────────────────────────────► release +# download-sergiye ───────────────────────────────────────────► release +# build-dll ─┘ +# ──────────────────────────────────────────────────────────────────────────── + +jobs: + + # ── Job 1: Build rdpwrap.dll (x64, x86, ARM64) ──────────────────────────── + # No job dependencies — starts immediately. + build-dll: + name: Build rdpwrap DLL + runs-on: windows-2022 + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v3 + + - name: Build rdpwrap.dll (x64, Win32, ARM64) + shell: pwsh + run: | + foreach ($platform in @('x64', 'Win32', 'ARM64')) { + msbuild src-x86-x64-Fusix/RDPWrap.vcxproj ` + /p:Configuration=Release ` + /p:Platform="$platform" ` + /p:PlatformToolset=v143 ` + /p:WindowsTargetPlatformVersion=10.0 ` + /v:minimal + } + Copy-Item src-x86-x64-Fusix/Release/x64/rdpwrap.dll .\rdpwrap_x64.dll + Copy-Item src-x86-x64-Fusix/Release/x86/rdpwrap.dll .\rdpwrap_x86.dll + Copy-Item src-x86-x64-Fusix/Release/arm64/rdpwrap.dll .\rdpwrap_arm64.dll + Write-Host "Built DLLs:" + Get-Item .\rdpwrap_x64.dll, .\rdpwrap_x86.dll, .\rdpwrap_arm64.dll | Format-Table Name, Length + + - name: Upload rdpwrap DLLs + uses: actions/upload-artifact@v4 + with: + name: rdpwrap-dlls + path: | + rdpwrap_x64.dll + rdpwrap_x86.dll + rdpwrap_arm64.dll + if-no-files-found: error + + + # ── Job 2: Build RDPWrapOffsetFinder (x64, x86) — parallel to build-dll ─── + # No job dependencies — starts immediately. + build-offsetfinder: + name: Build OffsetFinder + runs-on: windows-2022 + outputs: + finder_ver: ${{ steps.finder.outputs.finder_ver }} + + steps: + - name: Checkout repository (with submodules) + uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v3 + + - name: Build RDPWrapOffsetFinder from submodule + id: finder + shell: pwsh + run: | + $version = (git -C src-csharp/RDPOffsetFinder describe --tags --always).Trim() + Write-Host "Submodule version: $version" + + foreach ($cfg in @( + @{ Platform = 'x64'; ZydisCfg = 'Release MD DLL'; ZydisBin = 'ReleaseX64'; Arch = 'x64' } + @{ Platform = 'Win32'; ZydisCfg = 'Release MD DLL'; ZydisBin = 'ReleaseX86'; Arch = 'x86' } + )) { + # Build Zydis DLL + msbuild src-csharp/RDPOffsetFinder/zydis/msvc/zydis/Zydis.vcxproj ` + /p:Configuration="$($cfg.ZydisCfg)" ` + /p:Platform="$($cfg.Platform)" ` + /p:PlatformToolset=v143 ` + /v:minimal + + # Build RDPWrapOffsetFinder + msbuild src-csharp/RDPOffsetFinder/RDPWrapOffsetFinder/RDPWrapOffsetFinder.vcxproj ` + /p:Configuration=Release ` + /p:Platform="$($cfg.Platform)" ` + /p:PlatformToolset=v143 ` + /v:minimal + + $arch = $cfg.Arch + $exeSrc = "src-csharp/RDPOffsetFinder/RDPWrapOffsetFinder/$($cfg.Platform)/Release/RDPWrapOffsetFinder.exe" + $dllSrc = "src-csharp/RDPOffsetFinder/zydis/msvc/bin/$($cfg.ZydisBin)/Zydis.dll" + Copy-Item $exeSrc ".\RDPWrapOffsetFinder_$arch.exe" + Copy-Item $dllSrc ".\Zydis_$arch.dll" + } + + Write-Host "Built finder tools (version $version):" + Get-Item .\RDPWrapOffsetFinder_*.exe, .\Zydis_*.dll | Format-Table Name, Length + + echo "finder_ver=$version" >> $env:GITHUB_OUTPUT + + - name: Upload OffsetFinder binaries + uses: actions/upload-artifact@v4 + with: + name: offsetfinder-binaries + path: | + RDPWrapOffsetFinder_x64.exe + RDPWrapOffsetFinder_x86.exe + Zydis_x64.dll + Zydis_x86.dll + if-no-files-found: error + + + # ── Job 3: Download rdpWrapper GUI from sergiye — parallel to build-dll ──── + # No job dependencies — starts immediately. + download-sergiye: + name: Download sergiye rdpWrapper + runs-on: windows-2022 + outputs: + wrapper_ver: ${{ steps.wrapper.outputs.wrapper_ver }} + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Download rdpWrapper (sergiye) + id: wrapper + shell: pwsh + run: | + $apiUrl = "https://api.github.com/repos/sergiye/rdpWrapper/releases/latest" + $release = Invoke-RestMethod -Uri $apiUrl -Headers @{ "User-Agent" = "rdpwrap-ci" } + + foreach ($arch in @('x64', 'x86')) { + $asset = $release.assets | + Where-Object { $_.name -eq "rdpWrapper_$arch.exe" } | + Select-Object -First 1 + if (-not $asset) { + throw "Could not find rdpWrapper_$arch.exe in sergiye release $($release.tag_name)" + } + Write-Host "Downloading $($asset.browser_download_url)" + Invoke-WebRequest -Uri $asset.browser_download_url -OutFile ".\rdpWrapper_$arch.exe" + } + + Write-Host "Wrapper exes:" + Get-Item .\rdpWrapper_x64.exe, .\rdpWrapper_x86.exe | Format-Table Name, Length + echo "wrapper_ver=$($release.tag_name)" >> $env:GITHUB_OUTPUT + + # ── SHA-256 audit log for third-party binaries ────────────────────────── + # Records the hash of every downloaded sergiye binary in the workflow log. + # This provides a tamper-evident paper trail without blocking the release. + - name: Audit SHA-256 of downloaded binaries + shell: pwsh + run: | + $files = Get-Item .\rdpWrapper_x64.exe, .\rdpWrapper_x86.exe + Write-Host "SHA-256 audit (third-party downloads from sergiye/rdpWrapper):" + foreach ($f in $files) { + $hash = (Get-FileHash $f.FullName -Algorithm SHA256).Hash + Write-Host " $($f.Name) $hash" + } + + # ── Verify hashes against pinned values in tools/sergiye-hashes.json ──── + # If the file contains a non-empty 'release' key, hashes must match exactly. + # If 'release' is empty this step is skipped (bootstrap scenario). + - name: Verify sergiye binary hashes + shell: pwsh + run: | + $pinFile = 'tools/sergiye-hashes.json' + $pin = Get-Content $pinFile -Raw | ConvertFrom-Json + if ([string]::IsNullOrEmpty($pin.release)) { + Write-Host "Hash pinning not yet configured (tools/sergiye-hashes.json 'release' is empty) — skipping." + Write-Host "To enable pinning: download the binaries, compute hashes with Get-FileHash, and update $pinFile." + } else { + Write-Host "Verifying against pinned release: $($pin.release)" + $pass = $true + foreach ($name in @('rdpWrapper_x64.exe', 'rdpWrapper_x86.exe')) { + $expected = $pin.$name + $actual = (Get-FileHash ".\$name" -Algorithm SHA256).Hash + if ($actual -ne $expected) { + Write-Error "Hash mismatch for $name!" + Write-Error " Expected: $expected" + Write-Error " Actual: $actual" + $pass = $false + } else { + Write-Host " $name OK ($actual)" + } + } + if (-not $pass) { throw "One or more sergiye binary hashes did not match the pinned values." } + } + + - name: Upload sergiye wrappers + uses: actions/upload-artifact@v4 + with: + name: sergiye-wrappers + path: | + rdpWrapper_x64.exe + rdpWrapper_x86.exe + if-no-files-found: error + + + # ── Job 4: Build C# tools (FD + SC) — waits for build-dll ──────────────── + # Waits for build-dll so the DLLs can be embedded into single-file EXEs. + build-csharp: + name: Build C# Tools + runs-on: windows-2022 + needs: [build-dll] + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Download rdpwrap DLLs + uses: actions/download-artifact@v4 + with: + name: rdpwrap-dlls + path: . + + # Stage embedded resources for RDPWInst offline/bundled mode. + # RDPWInst.csproj embeds these files when present (Condition="Exists(...)"). + # Copying them here ensures the single-file EXE can install without network. + - name: Stage RDPWInst embedded resources + shell: pwsh + run: | + $res = 'src-csharp/RDPWInst/Resources' + New-Item -ItemType Directory -Path $res -Force | Out-Null + Copy-Item .\rdpwrap_x86.dll "$res\rdpw32.dll" -Force + Copy-Item .\rdpwrap_x64.dll "$res\rdpw64.dll" -Force + Copy-Item msi\rdpwrap.ini "$res\rdpwrap.ini" -Force + Copy-Item LICENSE "$res\license.txt" -Force + Write-Host "Staged resources:" + Get-ChildItem $res | Format-Table Name, Length + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.x' + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: nuget-${{ runner.os }}-${{ hashFiles('**/Directory.Build.props', '**/*.csproj') }} + restore-keys: | + nuget-${{ runner.os }}- + + # Compute version once so it's consistent across all publish and sign steps + - name: Get build version + id: build_ver + shell: pwsh + run: | + $v = Get-Date -Format "yyyy.M.d" + echo "version=$v" >> $env:GITHUB_OUTPUT + Write-Host "Build version: $v" + + # ── Build framework-dependent variants ────────────────────────────────── + - name: Publish C# tools (x64, x86, arm64) + shell: pwsh + env: + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + run: | + $projects = @('RDPWInst', 'RDPConf', 'RDPCheck') + $rids = [ordered]@{ x64 = 'win-x64'; x86 = 'win-x86'; arm64 = 'win-arm64' } + $ver = '${{ steps.build_ver.outputs.version }}' + foreach ($proj in $projects) { + foreach ($plat in $rids.Keys) { + $rid = $rids[$plat] + dotnet publish "src-csharp/$proj/$proj.csproj" ` + -c Release ` + -r $rid ` + -p:Platform=$plat ` + -p:PublishSingleFile=true ` + -p:SelfContained=false ` + -p:Version=$ver ` + -p:AssemblyVersion="$ver.0" ` + -p:FileVersion="$ver.0" ` + --output "dist_cs\$plat\$proj" + Copy-Item "dist_cs\$plat\$proj\$proj.exe" ".\${proj}_${plat}.exe" + } + } + Write-Host "C# tool executables:" + Get-Item .\RDPWInst_*.exe, .\RDPConf_*.exe, .\RDPCheck_*.exe | Format-Table Name, Length + + # ── Build self-contained variants (no .NET runtime required) ───────────── + # Self-contained exes are larger (~60 MB) but work without a .NET install. + # Suffixed with _sc to distinguish from the framework-dependent versions. + - name: Publish self-contained C# tools (x64, x86, arm64) + shell: pwsh + env: + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + run: | + $projects = @('RDPWInst', 'RDPConf', 'RDPCheck') + $rids = [ordered]@{ x64 = 'win-x64'; x86 = 'win-x86'; arm64 = 'win-arm64' } + $ver = '${{ steps.build_ver.outputs.version }}' + foreach ($proj in $projects) { + foreach ($plat in $rids.Keys) { + $rid = $rids[$plat] + dotnet publish "src-csharp/$proj/$proj.csproj" ` + -c Release ` + -r $rid ` + -p:Platform=$plat ` + -p:PublishSingleFile=true ` + -p:SelfContained=true ` + -p:Version=$ver ` + -p:AssemblyVersion="$ver.0" ` + -p:FileVersion="$ver.0" ` + --output "dist_cs_sc\$plat\$proj" + Copy-Item "dist_cs_sc\$plat\$proj\$proj.exe" ".\${proj}_${plat}_sc.exe" + } + } + Write-Host "Self-contained executables:" + Get-Item .\RDPWInst_*_sc.exe, .\RDPConf_*_sc.exe, .\RDPCheck_*_sc.exe | Format-Table Name, Length + + # ── Optional: code-sign all C# executables ────────────────────────────── + # Enable by setting repository variable USE_CERT_SIGNING=true and adding + # secrets CODESIGN_CERT_BASE64 (PFX as base64) and CODESIGN_CERT_PASSWORD. + - name: Sign C# executables + if: vars.USE_CERT_SIGNING == 'true' + env: + CODESIGN_CERT_BASE64: ${{ secrets.CODESIGN_CERT_BASE64 }} + CODESIGN_CERT_PASSWORD: ${{ secrets.CODESIGN_CERT_PASSWORD }} + shell: pwsh + run: | + $pfxPath = "$env:RUNNER_TEMP\codesign.pfx" + [IO.File]::WriteAllBytes($pfxPath, + [Convert]::FromBase64String($env:CODESIGN_CERT_BASE64)) + $signtool = (Resolve-Path "${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\signtool.exe" | + Sort-Object | Select-Object -Last 1).Path + # Sign both framework-dependent and self-contained variants (glob picks up all _*.exe files) + $exes = Get-Item .\RDPWInst_*.exe, .\RDPConf_*.exe, .\RDPCheck_*.exe + foreach ($exe in $exes) { + & $signtool sign /fd SHA256 /f $pfxPath ` + /p $env:CODESIGN_CERT_PASSWORD ` + /tr http://timestamp.digicert.com /td SHA256 $exe.FullName + } + Remove-Item $pfxPath -Force + + - name: Upload C# tools + uses: actions/upload-artifact@v4 + with: + name: csharp-tools + path: | + RDPWInst_*.exe + RDPConf_*.exe + RDPCheck_*.exe + if-no-files-found: error + + + # ── Job 5: Build MSI packages — waits for build-csharp (implies build-dll) ─ + build-msi: + name: Build MSI Packages + runs-on: windows-2022 + needs: [build-csharp] + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Download rdpwrap DLLs + uses: actions/download-artifact@v4 + with: + name: rdpwrap-dlls + path: . + + - name: Download C# tools + uses: actions/download-artifact@v4 + with: + name: csharp-tools + path: . + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.x' + + - name: Cache NuGet packages (WiX restore) + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: nuget-${{ runner.os }}-${{ hashFiles('msi/global.json', 'msi/*.wixproj') }} + restore-keys: | + nuget-${{ runner.os }}- + + # Get version (same formula as build-csharp for filename consistency) + - name: Get build version + id: build_ver + shell: pwsh + run: | + $v = Get-Date -Format "yyyy.M.d" + echo "version=$v" >> $env:GITHUB_OUTPUT + Write-Host "Build version: $v" + + # ── Build MSI installers (WiX v5, x64 / x86 / arm64) ────────────────── + - name: Build MSI packages + shell: pwsh + run: | + $ver = '${{ steps.build_ver.outputs.version }}' + foreach ($arch in @('x64', 'x86', 'arm64')) { + # Stage arch-specific inputs next to the .wixproj + Copy-Item ".\rdpwrap_$arch.dll" "msi\rdpwrap_$arch.dll" -Force + Copy-Item ".\RDPWInst_$arch.exe" "msi\RDPWInst_$arch.exe" -Force + Copy-Item ".\RDPConf_$arch.exe" "msi\RDPConf_$arch.exe" -Force + Copy-Item ".\RDPCheck_$arch.exe" "msi\RDPCheck_$arch.exe" -Force + + dotnet build msi/RDPWInst.wixproj ` + -c Release ` + /p:Platform=$arch ` + /p:OutputName="RDPWrapper-$arch" ` + /p:PackageVersion=$ver ` + /p:OutputPath="$PWD/msi_out/$arch" + if ($LASTEXITCODE -ne 0) { throw "WiX build failed for $arch" } + + $msiSrc = Get-Item "msi_out\$arch\RDPWrapper-$arch.msi" -ErrorAction SilentlyContinue + if (-not $msiSrc) { + $msiSrc = Get-ChildItem "msi\bin" -Recurse -Filter "RDPWrapper-$arch.msi" | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 + } + if (-not $msiSrc) { throw "Could not locate RDPWrapper-$arch.msi after WiX build" } + Copy-Item $msiSrc.FullName ".\RDPWrapper-${ver}-$arch.msi" + Write-Host "Produced: RDPWrapper-${ver}-$arch.msi ($([math]::Round($msiSrc.Length/1MB,1)) MB)" + } + Write-Host "MSI packages:" + Get-Item .\RDPWrapper-*-*.msi | Format-Table Name, Length + + # ── Optional: sign the MSI packages ──────────────────────────────────── + # Enable by setting repository variable USE_CERT_SIGNING=true and adding + # secrets CODESIGN_CERT_BASE64 (PFX as base64) and CODESIGN_CERT_PASSWORD. + - name: Sign MSI packages + if: vars.USE_CERT_SIGNING == 'true' + env: + CODESIGN_CERT_BASE64: ${{ secrets.CODESIGN_CERT_BASE64 }} + CODESIGN_CERT_PASSWORD: ${{ secrets.CODESIGN_CERT_PASSWORD }} + shell: pwsh + run: | + $pfxPath = "$env:RUNNER_TEMP\codesign.pfx" + [IO.File]::WriteAllBytes($pfxPath, + [Convert]::FromBase64String($env:CODESIGN_CERT_BASE64)) + $signtool = (Resolve-Path "${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\signtool.exe" | + Sort-Object | Select-Object -Last 1).Path + foreach ($msi in (Get-Item .\RDPWrapper-*-*.msi)) { + & $signtool sign /fd SHA256 /f $pfxPath ` + /p $env:CODESIGN_CERT_PASSWORD ` + /tr http://timestamp.digicert.com /td SHA256 ` + $msi.FullName + } + Remove-Item $pfxPath -Force + + - name: Upload MSI packages + uses: actions/upload-artifact@v4 + with: + name: msi-packages + path: RDPWrapper-*-*.msi + if-no-files-found: error + + + # ── Job 6: Publish GitHub Release — waits for all build jobs ────────────── + release: + name: Publish Release + runs-on: windows-2022 + needs: [build-dll, build-csharp, build-offsetfinder, download-sergiye, build-msi] + # Attach to the 'release' GitHub Environment so repository admins can add + # required-reviewer gates in Settings → Environments → release. + # If the environment doesn't exist yet it will be created without gates. + environment: release + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Download rdpwrap DLLs + uses: actions/download-artifact@v4 + with: + name: rdpwrap-dlls + path: . + + - name: Download C# tools + uses: actions/download-artifact@v4 + with: + name: csharp-tools + path: . + + - name: Download OffsetFinder binaries + uses: actions/download-artifact@v4 + with: + name: offsetfinder-binaries + path: . + + - name: Download sergiye wrappers + uses: actions/download-artifact@v4 + with: + name: sergiye-wrappers + path: . + + - name: Download MSI packages + uses: actions/download-artifact@v4 + with: + name: msi-packages + path: . + + - name: Verify all release assets are present + shell: pwsh + run: | + $required = @( + 'rdpwrap_x64.dll', 'rdpwrap_x86.dll', 'rdpwrap_arm64.dll', + 'RDPWInst_x64.exe', 'RDPWInst_x86.exe', 'RDPWInst_arm64.exe', + 'RDPConf_x64.exe', 'RDPConf_x86.exe', 'RDPConf_arm64.exe', + 'RDPCheck_x64.exe', 'RDPCheck_x86.exe', 'RDPCheck_arm64.exe', + 'RDPWrapOffsetFinder_x64.exe', 'RDPWrapOffsetFinder_x86.exe', + 'Zydis_x64.dll', 'Zydis_x86.dll', + 'rdpWrapper_x64.exe', 'rdpWrapper_x86.exe' + ) + $missing = $required | Where-Object { -not (Test-Path $_) } + if ($missing) { + throw "Missing required release assets: $($missing -join ', ')" + } + Write-Host "All required assets present." + Get-ChildItem *.exe, *.dll, *.msi | Format-Table Name, Length + + # ── Extract the date string used for tagging and the updated field ─────── + - name: Get release metadata + id: meta + shell: pwsh + run: | + $date = Get-Date -Format "yyyy.MM.dd.HHmm" + $stamp = Get-Date -Format "yyyy-MM-dd HH:mm UTC" + + # Pull the Updated= line out of the INI to surface in release notes + $iniContent = Get-Content msi/rdpwrap.ini -Raw + $iniDate = if ($iniContent -match 'Updated=([^\r\n]+)') { $Matches[1] } else { 'unknown' } + + $inputTag = '${{ inputs.tag }}'.Trim() + $tagName = if ($inputTag -ne '') { $inputTag } else { "ini-$date" } + $outputName = if ($inputTag -ne '') { "Release $inputTag" } else { "INI Update $date" } + + echo "date=$date" >> $env:GITHUB_OUTPUT + echo "stamp=$stamp" >> $env:GITHUB_OUTPUT + echo "inidate=$iniDate" >> $env:GITHUB_OUTPUT + echo "tag_name=$tagName" >> $env:GITHUB_OUTPUT + echo "release_name=$outputName" >> $env:GITHUB_OUTPUT + + # ── Validate the INI has required sections and mandatory per-version keys ─ + - name: Validate INI + shell: pwsh + run: | + $ini = Get-Content msi/rdpwrap.ini -Raw + $lines = Get-Content msi/rdpwrap.ini + + # 1) Check mandatory top-level sections exist + foreach ($section in @('[Main]', '[SLPolicy]', '[PatchCodes]')) { + if ($ini -notmatch [regex]::Escape($section)) { + throw "INI validation failed: missing required section $section" + } + } + + # 2) Parse every Windows-version section and verify it contains the + # mandatory keys LocalOnlyPatch and SLInitHook. + $sectionKeys = [System.Collections.Generic.Dictionary[string, System.Collections.Generic.List[string]]]::new() + $currentSection = $null + + foreach ($line in $lines) { + if ($line -match '^\[(\d[\d\.]+)\]') { + $currentSection = $Matches[1] + $sectionKeys[$currentSection] = [System.Collections.Generic.List[string]]::new() + } elseif ($null -ne $currentSection -and $line -match '^([A-Za-z][A-Za-z0-9_]*)[\s]*=') { + $sectionKeys[$currentSection].Add($Matches[1]) + } + } + + $mandatoryKeys = @('LocalOnlyPatch', 'SLInitHook') + $errors = [System.Collections.Generic.List[string]]::new() + + foreach ($sec in $sectionKeys.Keys) { + foreach ($key in $mandatoryKeys) { + if (-not $sectionKeys[$sec].Contains($key)) { + $errors.Add(" Section [$sec] is missing mandatory key: $key") + } + } + } + + if ($errors.Count -gt 0) { + Write-Error "INI mandatory-key check failed ($($errors.Count) issue(s)):" + $errors | ForEach-Object { Write-Error $_ } + throw "INI validation failed — see errors above." + } + + $sectionCount = $sectionKeys.Count + Write-Host "INI is valid. Windows-version sections: $sectionCount (all contain LocalOnlyPatch + SLInitHook)" + + # ── Auto-generate changelog from merged PRs since last release ─────────── + - name: Generate changelog + id: changelog + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: | + # Get the tag of the previous release so we can scope the PR list + $prevTag = (gh release list --limit 1 --json tagName --jq '.[0].tagName' 2>$null) ?? '' + if ($prevTag) { + Write-Host "Generating changelog since: $prevTag" + $since = gh release view $prevTag --json publishedAt --jq .publishedAt + $prs = gh pr list --state merged --base main --search "merged:>=$since" ` + --json number,title,author --limit 50 | ConvertFrom-Json + } else { + Write-Host "No previous release found; skipping per-PR changelog." + $prs = @() + } + if ($prs.Count -gt 0) { + $lines = $prs | ForEach-Object { "- #$($_.number) $($_.title) (@$($_.author.login))" } + $body = $lines -join "`n" + } else { + $body = "_No merged pull requests found since the previous release._" + } + # Write multi-line output safely + $delim = [guid]::NewGuid().ToString('N') + echo "prs<<$delim" >> $env:GITHUB_OUTPUT + echo $body >> $env:GITHUB_OUTPUT + echo $delim >> $env:GITHUB_OUTPUT + + # ── Assemble the three user-facing distribution bundles ────────────────── + - name: Create distribution bundles + shell: pwsh + run: | + # RDPWrapper.zip - complete install package (all arches, framework-dependent) + $d = ".\bundle_wrapper" + New-Item -ItemType Directory -Path $d -Force | Out-Null + Copy-Item .\rdpwrap_x64.dll "$d\rdpwrap_x64.dll" + Copy-Item .\rdpwrap_x86.dll "$d\rdpwrap_x86.dll" + Copy-Item .\rdpwrap_arm64.dll "$d\rdpwrap_arm64.dll" + Copy-Item .\rdpWrapper_x64.exe "$d\rdpWrapper_x64.exe" + Copy-Item .\rdpWrapper_x86.exe "$d\rdpWrapper_x86.exe" + # Framework-dependent C# tools (require .NET 10 Desktop Runtime) + foreach ($proj in @('RDPWInst', 'RDPConf', 'RDPCheck')) { + foreach ($arch in @('x64', 'x86', 'arm64')) { + $src = ".\${proj}_${arch}.exe" + if (Test-Path $src) { Copy-Item $src "$d\${proj}_${arch}.exe" } + } + } + Copy-Item msi\rdpwrap.ini "$d\rdpwrap.ini" + Compress-Archive -Path "$d\*" -DestinationPath ".\RDPWrapper.zip" -Force + Remove-Item $d -Recurse -Force + + # RDPWrapper-SelfContained.zip - apps bundled with .NET runtime (~60 MB each) + $sc = ".\bundle_sc" + New-Item -ItemType Directory -Path $sc -Force | Out-Null + foreach ($proj in @('RDPWInst', 'RDPConf', 'RDPCheck')) { + foreach ($arch in @('x64', 'x86', 'arm64')) { + $src = ".\${proj}_${arch}_sc.exe" + if (Test-Path $src) { Copy-Item $src "$sc\${proj}_${arch}_sc.exe" } + } + } + Copy-Item msi\rdpwrap.ini "$sc\rdpwrap.ini" + Compress-Archive -Path "$sc\*" -DestinationPath ".\RDPWrapper-SelfContained.zip" -Force + Remove-Item $sc -Recurse -Force + + # RDPWrapOffsetFinder.zip - offset finder with per-arch subfolders + $f = ".\bundle_finder" + foreach ($arch in @('x64', 'x86')) { + $dir = "$f\$arch" + New-Item -ItemType Directory -Path $dir -Force | Out-Null + Copy-Item ".\RDPWrapOffsetFinder_$arch.exe" "$dir\RDPWrapOffsetFinder.exe" + Copy-Item ".\Zydis_$arch.dll" "$dir\Zydis.dll" + } + Compress-Archive -Path "$f\*" -DestinationPath ".\RDPWrapOffsetFinder.zip" -Force + Remove-Item $f -Recurse -Force + + Write-Host "Distribution bundles:" + Get-Item .\RDPWrapper.zip, .\RDPWrapper-SelfContained.zip, .\RDPWrapOffsetFinder.zip | Format-Table Name, Length + + # ── Create/update a versioned GitHub Release with all assets ───────────── + - name: Publish release + # Pinned to v2 tag SHA for supply-chain safety. + # Bump this SHA when upgrading: https://github.com/softprops/action-gh-release/releases + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 + with: + tag_name: "${{ steps.meta.outputs.tag_name }}" + name: "${{ steps.meta.outputs.release_name }}" + prerelease: ${{ inputs.prerelease || false }} + make_latest: true + body: | + ## RDP Wrapper - Automated Release + + | Field | Value | + |---|---| + | INI `Updated` date | `${{ steps.meta.outputs.inidate }}` | + | Published | ${{ steps.meta.outputs.stamp }} | + | rdpWrapper (sergiye) | ${{ needs.download-sergiye.outputs.wrapper_ver }} | + | RDPWrapOffsetFinder (llccd) | ${{ needs.build-offsetfinder.outputs.finder_ver }} | + + > **Framework-dependent tools** (default) require **.NET 10 Desktop Runtime** on the target machine. + > Download: https://dotnet.microsoft.com/download/dotnet/10.0 + > For environments without a runtime install, use the `*_sc.exe` files from `RDPWrapper-SelfContained.zip`. + + ### Downloads + + | File | Contents | Use | + |---|---|---| + | `RDPWrapper.zip` | rdpwrap DLLs, C# tools (x64/x86/arm64), rdpWrapper GUI, rdpwrap.ini | **Main install package** — extract and run `RDPWInst_x64.exe -i -o` (or matching arch) | + | `RDPWrapper-SelfContained.zip` | Same C# tools bundled with .NET runtime (no separate runtime install needed) | Use when .NET 10 Desktop Runtime cannot be deployed | + | `RDPWrapper--x64.msi` / `x86` / `arm64` | Windows Installer packages — GUI-friendly, self-registering uninstall | Preferred for managed/enterprise deployments | + | `RDPWrapOffsetFinder.zip` | RDPWrapOffsetFinder.exe + Zydis.dll for x64 and x86 | Generate offsets for an unknown termsrv.dll version manually | + + ### Merged pull requests + + ${{ steps.changelog.outputs.prs }} + + ### Individual loose files (used by the automated installer) + + | File | Purpose | + |---|---| + | `rdpwrap.ini` | Offset database fetched automatically by the installer | + | `RDPWrapOffsetFinder_x64.exe` / `Zydis_x64.dll` | Loose x64 binaries downloaded by `TryAutoGenerateOffsets` | + | `RDPWrapOffsetFinder_x86.exe` / `Zydis_x86.dll` | Loose x86 binaries downloaded by `TryAutoGenerateOffsets` | + files: | + RDPWrapper.zip + RDPWrapper-SelfContained.zip + RDPWrapper-*-x64.msi + RDPWrapper-*-x86.msi + RDPWrapper-*-arm64.msi + RDPWrapOffsetFinder.zip + msi/rdpwrap.ini + msi/rdpwrap-arm-kb.ini + rdpwrap_x64.dll + rdpwrap_x86.dll + rdpwrap_arm64.dll + RDPWInst_x64.exe + RDPWInst_x86.exe + RDPWInst_arm64.exe + RDPConf_x64.exe + RDPConf_x86.exe + RDPConf_arm64.exe + RDPCheck_x64.exe + RDPCheck_x86.exe + RDPCheck_arm64.exe + RDPWrapOffsetFinder_x64.exe + RDPWrapOffsetFinder_x86.exe + Zydis_x64.dll + Zydis_x86.dll diff --git a/.github/workflows/build-cpp.yml b/.github/workflows/build-cpp.yml index a9bf0b6..0aab122 100644 --- a/.github/workflows/build-cpp.yml +++ b/.github/workflows/build-cpp.yml @@ -1,7 +1,14 @@ -name: Build C++ DLL +name: Build C++ DLL -# Trigger on version tags (e.g. v1.7.0) or manually +# Trigger on: +# - PRs targeting main/master that touch C++ source (compile check before merge) +# - Version tag pushes (e.g. v1.7.0) +# - Manual dispatch on: + pull_request: + branches: [main, master] + paths: + - 'src-x86-x64-Fusix/**' push: tags: - 'v*' @@ -14,12 +21,18 @@ permissions: contents: write jobs: - # ── Build x64 and Win32 release DLLs ───────────────────────────────────────── + # ── Build x64 and Win32 release DLLs ───────────────────────────────────────── build: runs-on: windows-2022 strategy: matrix: - platform: [x64, Win32] + include: + - platform: x64 + msbuild_platform: x64 + - platform: x86 + msbuild_platform: Win32 + - platform: arm64 + msbuild_platform: ARM64 steps: - name: Checkout repository @@ -36,7 +49,7 @@ jobs: run: | msbuild RDPWrap.vcxproj ` /p:Configuration=Release ` - /p:Platform="${{ matrix.platform }}" ` + /p:Platform="${{ matrix.msbuild_platform }}" ` /p:PlatformToolset=v143 ` /p:WindowsTargetPlatformVersion=10.0 @@ -44,50 +57,9 @@ jobs: uses: actions/upload-artifact@v4 with: name: rdpwrap-dll-${{ matrix.platform }} - path: src-x86-x64-Fusix/${{ matrix.platform }}/Release/rdpwrap.dll + path: src-x86-x64-Fusix/Release/${{ matrix.platform }}/rdpwrap.dll if-no-files-found: error - # ── Assemble a GitHub Release from both DLL artifacts ──────────────────────── - release: - needs: build - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/') - - steps: - - name: Download x64 artifact - uses: actions/download-artifact@v4 - with: - name: rdpwrap-dll-x64 - path: ./dist/x64 - - - name: Download Win32 artifact - uses: actions/download-artifact@v4 - with: - name: rdpwrap-dll-Win32 - path: ./dist/x86 - - - name: Rename DLLs for release - run: | - mv dist/x64/rdpwrap.dll dist/rdpwrap_x64.dll - mv dist/x86/rdpwrap.dll dist/rdpwrap_x86.dll - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - prerelease: false - make_latest: false - body: | - ## RDP Wrapper DLL – ${{ github.ref_name }} - - Built from `src-x86-x64-Fusix/` with MSVC v143 (VS 2022). - - | File | Architecture | - |---|---| - | `rdpwrap_x64.dll` | x86-64 (64-bit Windows) | - | `rdpwrap_x86.dll` | x86 (32-bit Windows) | - - > Place the appropriate DLL in `C:\Program Files\RDP Wrapper\rdpwrap.dll` - > and run `RDPWInst.exe -i` to install. - files: | - dist/rdpwrap_x64.dll - dist/rdpwrap_x86.dll + # NOTE: Full GitHub Releases (including rdpwrap DLLs) are published by build-and-release.yml. + # This workflow stops at the artifact upload step so that partial releases are never + # created on tag pushes. Run build-and-release.yml to produce the canonical release. diff --git a/.github/workflows/build-csharp.yml b/.github/workflows/build-csharp.yml new file mode 100644 index 0000000..468eae5 --- /dev/null +++ b/.github/workflows/build-csharp.yml @@ -0,0 +1,141 @@ +name: Build C# Tools + +# Trigger on: +# - PRs targeting main/master that touch C# source (compile check before merge) +# - Version tag pushes (e.g. v1.7.0) +# - Manual dispatch +# Produces self-contained, single-file RDPWInst / RDPConf / RDPCheck +# executables for x64 and x86. +on: + pull_request: + branches: [main, master] + paths: + - 'src-csharp/**' + push: + tags: + - 'v*' + workflow_dispatch: + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +permissions: + contents: write + +jobs: + # ── Publish self-contained executables ──────────────────────────────────────── + build: + runs-on: windows-2022 + strategy: + matrix: + platform: [x64, x86, arm64] + include: + - platform: x64 + rid: win-x64 + - platform: x86 + rid: win-x86 + - platform: arm64 + rid: win-arm64 + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.x' + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: nuget-${{ runner.os }}-${{ hashFiles('**/Directory.Build.props', '**/*.csproj') }} + restore-keys: | + nuget-${{ runner.os }}- + + - name: Publish RDPWInst (${{ matrix.platform }}) + run: | + dotnet publish src-csharp/RDPWInst/RDPWInst.csproj ` + -c Release ` + -r ${{ matrix.rid }} ` + -p:Platform=${{ matrix.platform }} ` + -p:PublishSingleFile=true ` + -p:SelfContained=false ` + --output dist/${{ matrix.platform }}/RDPWInst + + - name: Publish RDPConf (${{ matrix.platform }}) + run: | + dotnet publish src-csharp/RDPConf/RDPConf.csproj ` + -c Release ` + -r ${{ matrix.rid }} ` + -p:Platform=${{ matrix.platform }} ` + -p:PublishSingleFile=true ` + -p:SelfContained=false ` + --output dist/${{ matrix.platform }}/RDPConf + + - name: Publish RDPCheck (${{ matrix.platform }}) + run: | + dotnet publish src-csharp/RDPCheck/RDPCheck.csproj ` + -c Release ` + -r ${{ matrix.rid }} ` + -p:Platform=${{ matrix.platform }} ` + -p:PublishSingleFile=true ` + -p:SelfContained=false ` + --output dist/${{ matrix.platform }}/RDPCheck + + # ── Optional: code-sign all three executables ───────────────────────────── + # Enable by setting repository variable USE_CERT_SIGNING=true and adding + # secrets CODESIGN_CERT_BASE64 (PFX as base64) and CODESIGN_CERT_PASSWORD. + - name: Sign executables (${{ matrix.platform }}) + if: vars.USE_CERT_SIGNING == 'true' + env: + CODESIGN_CERT_BASE64: ${{ secrets.CODESIGN_CERT_BASE64 }} + CODESIGN_CERT_PASSWORD: ${{ secrets.CODESIGN_CERT_PASSWORD }} + shell: pwsh + run: | + $pfxPath = "$env:RUNNER_TEMP\codesign.pfx" + [IO.File]::WriteAllBytes($pfxPath, + [Convert]::FromBase64String($env:CODESIGN_CERT_BASE64)) + + $exes = @( + "dist\${{ matrix.platform }}\RDPWInst\RDPWInst.exe", + "dist\${{ matrix.platform }}\RDPConf\RDPConf.exe", + "dist\${{ matrix.platform }}\RDPCheck\RDPCheck.exe" + ) + + $signtool = (Resolve-Path "${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\signtool.exe" | + Sort-Object | Select-Object -Last 1).Path + foreach ($exe in $exes) { + & $signtool sign ` + /fd SHA256 ` + /f $pfxPath ` + /p $env:CODESIGN_CERT_PASSWORD ` + /tr http://timestamp.digicert.com ` + /td SHA256 ` + $exe + } + Remove-Item $pfxPath -Force + + - name: Collect artifacts (${{ matrix.platform }}) + run: | + Copy-Item dist/${{ matrix.platform }}/RDPWInst/RDPWInst.exe RDPWInst_${{ matrix.platform }}.exe + Copy-Item dist/${{ matrix.platform }}/RDPConf/RDPConf.exe RDPConf_${{ matrix.platform }}.exe + Copy-Item dist/${{ matrix.platform }}/RDPCheck/RDPCheck.exe RDPCheck_${{ matrix.platform }}.exe + + - name: Upload ${{ matrix.platform }} artifacts + uses: actions/upload-artifact@v4 + with: + name: csharp-tools-${{ matrix.platform }} + path: | + RDPWInst_${{ matrix.platform }}.exe + RDPConf_${{ matrix.platform }}.exe + RDPCheck_${{ matrix.platform }}.exe + if-no-files-found: error + + # NOTE: Full GitHub Releases (including C# tools) are published by publish-ini.yml. + # This workflow intentionally stops at the artifact upload step so that partial + # releases are never created on the tag. Run publish-ini.yml manually or let it + # fire from an INI push to produce the canonical release. diff --git a/.github/workflows/build-msi-check.yml b/.github/workflows/build-msi-check.yml new file mode 100644 index 0000000..cb7e01a --- /dev/null +++ b/.github/workflows/build-msi-check.yml @@ -0,0 +1,73 @@ +name: Build MSI Check + +# Lightweight PR check that validates msi/RDPWInst.wxs compiles cleanly. +# We stub the binary inputs (DLL/EXE) with placeholder files so WiX can +# validate the package structure without needing a full C++ / C# build. +# For the real release build with actual binaries, see build-and-release.yml. +on: + pull_request: + branches: [main, master] + paths: + - 'msi/**' + - '.github/workflows/build-msi-check.yml' + workflow_dispatch: + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +permissions: + contents: read + +jobs: + wix-check: + runs-on: windows-2022 + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.x' + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: nuget-${{ runner.os }}-${{ hashFiles('**/Directory.Build.props', '**/*.csproj', '**/global.json') }} + restore-keys: | + nuget-${{ runner.os }}- + + # Create minimal placeholder files so WiX can resolve all File references + # in RDPWInst.wxs without requiring an actual C++ or C# build. + # WiX v5 harvests file size at build time but does not validate binary content. + - name: Create placeholder binary inputs + shell: pwsh + run: | + $arch = 'x64' + # Placeholder DLL and EXEs — WiX only needs the files to exist + foreach ($name in @("rdpwrap_$arch.dll", "RDPWInst_$arch.exe", "RDPConf_$arch.exe", "RDPCheck_$arch.exe")) { + $dest = "msi\$name" + if (-not (Test-Path $dest)) { + [System.IO.File]::WriteAllBytes($dest, [byte[]](0x4D, 0x5A)) # MZ stub + Write-Host "Created stub: $dest" + } + } + Write-Host "Placeholder files in msi\:" + Get-ChildItem msi\ -File | Format-Table Name, Length + + # Build only the x64 MSI — enough to validate WXS structure and WiX rules. + # A failure here means a real WiX schema/syntax/reference error that would + # also break the release build. + - name: Build MSI (x64 WiX check) + shell: pwsh + run: | + dotnet build msi/RDPWInst.wixproj ` + -c Release ` + /p:Platform=x64 ` + /p:PackageVersion=0.0.1 ` + /p:OutputPath="$PWD/msi_check_out/x64" + if ($LASTEXITCODE -ne 0) { throw "WiX build failed — review errors above" } + Write-Host "WiX check passed." + Get-ChildItem msi_check_out -Recurse -Filter "*.msi" | Format-Table FullName, Length diff --git a/.github/workflows/build-offsetfinder.yml b/.github/workflows/build-offsetfinder.yml new file mode 100644 index 0000000..858ef16 --- /dev/null +++ b/.github/workflows/build-offsetfinder.yml @@ -0,0 +1,93 @@ +name: Build RDPWrapOffsetFinder + +# Trigger on: +# - PRs targeting main/master that touch the OffsetFinder submodule or Zydis +# - Version tag pushes (e.g. v1.7.0) +# - Manual dispatch +on: + pull_request: + branches: [main, master] + paths: + - 'src-csharp/RDPOffsetFinder/**' + push: + tags: + - 'v*' + workflow_dispatch: + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +permissions: + contents: write + +jobs: + # ── Build x64 and Win32 release exes ───────────────────────────────────────── + build: + runs-on: windows-2022 + strategy: + matrix: + include: + - platform: x64 + zydis_cfg: "Release MD DLL" + zydis_bin: ReleaseX64 + finder_plat: x64 + - platform: Win32 + zydis_cfg: "Release MD DLL" + zydis_bin: ReleaseX86 + finder_plat: Win32 + + steps: + - name: Checkout repository (with submodules) + uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v3 + + # Build Zydis as a shared DLL so we can ship Zydis.dll alongside the exe + - name: Build Zydis (${{ matrix.platform }}) + working-directory: src-csharp/RDPOffsetFinder + run: | + msbuild zydis\msvc\zydis\Zydis.vcxproj ` + /p:Configuration="${{ matrix.zydis_cfg }}" ` + /p:Platform="${{ matrix.platform }}" ` + /p:PlatformToolset=v143 ` + /v:minimal + + # Build the offset finder (links against the Zydis import lib just produced) + - name: Build RDPWrapOffsetFinder (${{ matrix.platform }}) + working-directory: src-csharp/RDPOffsetFinder + run: | + msbuild RDPWrapOffsetFinder\RDPWrapOffsetFinder.vcxproj ` + /p:Configuration=Release ` + /p:Platform="${{ matrix.platform }}" ` + /p:PlatformToolset=v143 ` + /v:minimal + + - name: Collect outputs + shell: pwsh + run: | + $arch = if ("${{ matrix.platform }}" -eq "Win32") { "x86" } else { "x64" } + $root = "src-csharp/RDPOffsetFinder" + $exe = "$root/RDPWrapOffsetFinder/${{ matrix.finder_plat }}/Release/RDPWrapOffsetFinder.exe" + $dll = "$root/zydis/msvc/bin/${{ matrix.zydis_bin }}/Zydis.dll" + + Write-Host "Exe: $(Get-Item $exe | Select-Object -Exp Length) bytes" + Write-Host "Dll: $(Get-Item $dll | Select-Object -Exp Length) bytes" + + Copy-Item $exe ".\RDPWrapOffsetFinder_$arch.exe" + Copy-Item $dll ".\Zydis_$arch.dll" + + - name: Upload ${{ matrix.platform }} artifact + uses: actions/upload-artifact@v4 + with: + name: finder-${{ matrix.platform }} + path: | + RDPWrapOffsetFinder_*.exe + Zydis_*.dll + if-no-files-found: error + + # NOTE: Full GitHub Releases (including OffsetFinder binaries) are published by build-and-release.yml. + # This workflow stops at the artifact upload step so that partial releases are never + # created on tag pushes. Run build-and-release.yml to produce the canonical release. diff --git a/.github/workflows/publish-ini.yml b/.github/workflows/publish-ini.yml deleted file mode 100644 index 2824531..0000000 --- a/.github/workflows/publish-ini.yml +++ /dev/null @@ -1,188 +0,0 @@ -name: Publish INI and Offset Finder Tools - -on: - push: - branches: [main, master] - paths: - - 'res/rdpwrap.ini' - - 'tools/RDPWrapOffsetFinder/**' - - '.github/workflows/publish-ini.yml' - workflow_dispatch: - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -permissions: - contents: write - -jobs: - publish: - runs-on: windows-2022 - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - # ── Build rdpwrap.dll for both x64 and Win32 ──────────────────────────── - - name: Setup MSBuild - uses: microsoft/setup-msbuild@v3 - - - name: Build rdpwrap.dll (x64 and Win32) - shell: pwsh - run: | - foreach ($platform in @('x64', 'Win32')) { - msbuild src-x86-x64-Fusix/RDPWrap.vcxproj ` - /p:Configuration=Release ` - /p:Platform="$platform" ` - /p:PlatformToolset=v143 ` - /p:WindowsTargetPlatformVersion=10.0 ` - /v:minimal - } - Copy-Item src-x86-x64-Fusix/x64/Release/rdpwrap.dll .\rdpwrap_x64.dll - Copy-Item src-x86-x64-Fusix/Win32/Release/rdpwrap.dll .\rdpwrap_x86.dll - Write-Host "Built DLLs:" - Get-Item .\rdpwrap_x64.dll, .\rdpwrap_x86.dll | Format-Table Name, Length - - # ── Extract the date string used for tagging and the updated field ────── - - name: Get release metadata - id: meta - shell: pwsh - run: | - $date = Get-Date -Format "yyyy.MM.dd.HHmm" - $stamp = Get-Date -Format "yyyy-MM-dd HH:mm UTC" - - # Pull the Updated= line out of the INI to surface in release notes - $iniContent = Get-Content res/rdpwrap.ini -Raw - $iniDate = if ($iniContent -match 'Updated=([^\r\n]+)') { $Matches[1] } else { 'unknown' } - - echo "date=$date" >> $env:GITHUB_OUTPUT - echo "stamp=$stamp" >> $env:GITHUB_OUTPUT - echo "inidate=$iniDate" >> $env:GITHUB_OUTPUT - - # ── Stage RDPWrapOffsetFinder from committed tools/ ────────────────────── - - name: Stage RDPWrapOffsetFinder from tools/ - id: finder - shell: pwsh - run: | - $version = (Get-Content tools/RDPWrapOffsetFinder/VERSION -Raw).Trim() - - Copy-Item tools/RDPWrapOffsetFinder/x64/RDPWrapOffsetFinder.exe .\RDPWrapOffsetFinder_x64.exe - Copy-Item tools/RDPWrapOffsetFinder/x64/Zydis.dll .\Zydis_x64.dll - Copy-Item tools/RDPWrapOffsetFinder/x86/RDPWrapOffsetFinder.exe .\RDPWrapOffsetFinder_x86.exe - Copy-Item tools/RDPWrapOffsetFinder/x86/Zydis.dll .\Zydis_x86.dll - - Write-Host "Staged finder tools (version $version):" - Get-Item .\RDPWrapOffsetFinder_*.exe, .\Zydis_*.dll | Format-Table Name, Length - - echo "finder_ver=$version" >> $env:GITHUB_OUTPUT - - # ── Download the latest rdpWrapper GUI app from sergiye ───────────────── - - name: Download rdpWrapper (sergiye) - id: wrapper - shell: pwsh - run: | - $apiUrl = "https://api.github.com/repos/sergiye/rdpWrapper/releases/latest" - $release = Invoke-RestMethod -Uri $apiUrl -Headers @{ "User-Agent" = "rdpwrap-ci" } - - foreach ($arch in @('x64', 'x86')) { - $asset = $release.assets | - Where-Object { $_.name -eq "rdpWrapper_$arch.exe" } | - Select-Object -First 1 - if (-not $asset) { - throw "Could not find rdpWrapper_$arch.exe in sergiye release $($release.tag_name)" - } - Write-Host "Downloading $($asset.browser_download_url)" - Invoke-WebRequest -Uri $asset.browser_download_url -OutFile ".\rdpWrapper_$arch.exe" - } - - Write-Host "Wrapper exes:" - Get-Item .\rdpWrapper_x64.exe, .\rdpWrapper_x86.exe | Format-Table Name, Length - echo "wrapper_ver=$($release.tag_name)" >> $env:GITHUB_OUTPUT - - # ── Validate the INI has required sections ─────────────────────────────── - - name: Validate INI - shell: pwsh - run: | - $ini = Get-Content res/rdpwrap.ini -Raw - foreach ($section in @('[Main]', '[SLPolicy]', '[PatchCodes]')) { - if ($ini -notmatch [regex]::Escape($section)) { - throw "INI validation failed: missing required section $section" - } - } - $sectionCount = ([regex]::Matches($ini, '^\[[\d\.]+\]', 'Multiline')).Count - Write-Host "INI is valid. Windows-version sections: $sectionCount" - - # ── Assemble the two user-facing distribution bundles ──────────────────── - - name: Create distribution bundles - shell: pwsh - run: | - # RDPWrapper.zip - complete install package - $d = ".\bundle_wrapper" - New-Item -ItemType Directory -Path $d -Force | Out-Null - Copy-Item .\rdpwrap_x64.dll "$d\rdpwrap_x64.dll" - Copy-Item .\rdpwrap_x86.dll "$d\rdpwrap_x86.dll" - Copy-Item .\rdpWrapper_x64.exe "$d\rdpWrapper_x64.exe" - Copy-Item .\rdpWrapper_x86.exe "$d\rdpWrapper_x86.exe" - Copy-Item res\rdpwrap.ini "$d\rdpwrap.ini" - Copy-Item bin\install.bat "$d\install.bat" - Copy-Item bin\uninstall.bat "$d\uninstall.bat" - Copy-Item bin\update.bat "$d\update.bat" - Compress-Archive -Path "$d\*" -DestinationPath ".\RDPWrapper.zip" -Force - Remove-Item $d -Recurse -Force - - # RDPWrapOffsetFinder.zip - offset finder with per-arch subfolders - $f = ".\bundle_finder" - foreach ($arch in @('x64', 'x86')) { - $dir = "$f\$arch" - New-Item -ItemType Directory -Path $dir -Force | Out-Null - Copy-Item ".\RDPWrapOffsetFinder_$arch.exe" "$dir\RDPWrapOffsetFinder.exe" - Copy-Item ".\Zydis_$arch.dll" "$dir\Zydis.dll" - } - Compress-Archive -Path "$f\*" -DestinationPath ".\RDPWrapOffsetFinder.zip" -Force - Remove-Item $f -Recurse -Force - - Write-Host "Distribution bundles:" - Get-Item .\RDPWrapper.zip, .\RDPWrapOffsetFinder.zip | Format-Table Name, Length - - # ── Create/update a versioned GitHub Release with all assets ───────────── - - name: Publish release - uses: softprops/action-gh-release@v2 - with: - tag_name: "ini-${{ steps.meta.outputs.date }}" - name: "INI Update ${{ steps.meta.outputs.date }}" - prerelease: false - make_latest: true - body: | - ## RDP Wrapper - Automated Release - - | Field | Value | - |---|---| - | INI `Updated` date | `${{ steps.meta.outputs.inidate }}` | - | Published | ${{ steps.meta.outputs.stamp }} | - | rdpWrapper (sergiye) | ${{ steps.wrapper.outputs.wrapper_ver }} | - | RDPWrapOffsetFinder (llccd) | ${{ steps.finder.outputs.finder_ver }} | - - ### Downloads - - | File | Contents | Use | - |---|---|---| - | `RDPWrapper.zip` | rdpwrap_x64.dll, rdpwrap_x86.dll, rdpWrapper_x64.exe, rdpWrapper_x86.exe, rdpwrap.ini, install/uninstall/update.bat | Main install package - extract and run `rdpWrapper_x64.exe` | - | `RDPWrapOffsetFinder.zip` | x64\RDPWrapOffsetFinder.exe + Zydis.dll, x86\RDPWrapOffsetFinder.exe + Zydis.dll | Generate offsets for an unknown termsrv.dll version manually | - - ### Individual files (used by the automated installer) - - | File | Purpose | - |---|---| - | `rdpwrap.ini` | Offset database fetched automatically by the installer | - | `RDPWrapOffsetFinder_x64.exe` / `Zydis_x64.dll` | Loose x64 binaries downloaded by `TryAutoGenerateOffsets` | - | `RDPWrapOffsetFinder_x86.exe` / `Zydis_x86.dll` | Loose x86 binaries downloaded by `TryAutoGenerateOffsets` | - files: | - RDPWrapper.zip - RDPWrapOffsetFinder.zip - res/rdpwrap.ini - rdpwrap_x64.dll - rdpwrap_x86.dll - RDPWrapOffsetFinder_x64.exe - RDPWrapOffsetFinder_x86.exe - Zydis_x64.dll - Zydis_x86.dll diff --git a/.github/workflows/update-finder-tools.yml b/.github/workflows/update-finder-tools.yml deleted file mode 100644 index f80c27d..0000000 --- a/.github/workflows/update-finder-tools.yml +++ /dev/null @@ -1,120 +0,0 @@ -name: Update RDPWrapOffsetFinder tools - -# Run manually to pull a new version of llccd/RDPWrapOffsetFinder into tools/. -# The workflow commits the updated binaries and opens a pull request. -on: - workflow_dispatch: - inputs: - tag: - description: "llccd release tag to fetch (leave blank for latest)" - required: false - default: "" - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -permissions: - contents: write - pull-requests: write - -jobs: - update: - runs-on: windows-2022 - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Download and extract RDPWrapOffsetFinder - id: fetch - shell: pwsh - run: | - $tag = "${{ github.event.inputs.tag }}" - if ($tag -eq "") { - $apiUrl = "https://api.github.com/repos/llccd/RDPWrapOffsetFinder/releases/latest" - } else { - $apiUrl = "https://api.github.com/repos/llccd/RDPWrapOffsetFinder/releases/tags/$tag" - } - - $release = Invoke-RestMethod -Uri $apiUrl -Headers @{ "User-Agent" = "rdpwrap-ci" } - $version = $release.tag_name - Write-Host "Fetching version $version" - - $asset = $release.assets | Where-Object { $_.name -like "*.zip" } | Select-Object -First 1 - if (-not $asset) { throw "No zip asset found in release $version" } - - Invoke-WebRequest -Uri $asset.browser_download_url -OutFile finder.zip -UseBasicParsing - Expand-Archive -Path finder.zip -DestinationPath .\finder -Force - - Write-Host "Zip contents:" - Get-ChildItem -Recurse .\finder | Select-Object FullName, Length - - # The llccd zip uses "64bit/" and "32bit/" subfolder names. - # We pick the symbol-enabled exe (not the _nosymbol variant) from each arch folder. - function Get-Bin($filter, $archHint) { - $hits = Get-ChildItem -Recurse .\finder -Filter $filter | - Where-Object { $_.FullName -match $archHint } | - Where-Object { $_.Name -notmatch "nosymbol" } - return ($hits | Select-Object -First 1) - } - - $x64exe = Get-Bin "RDPWrapOffsetFinder*.exe" "64bit" - $x64dll = Get-Bin "Zydis*.dll" "64bit" - $x86exe = Get-Bin "RDPWrapOffsetFinder*.exe" "32bit" - $x86dll = Get-Bin "Zydis*.dll" "32bit" - - # Fall back to x64 if the release only ships one arch - if (-not $x86exe) { $x86exe = $x64exe } - if (-not $x86dll) { $x86dll = $x64dll } - if (-not $x64exe) { throw "Could not locate x64 exe" } - if (-not $x64dll) { throw "Could not locate x64 Zydis.dll" } - - New-Item -ItemType Directory -Path tools\RDPWrapOffsetFinder\x64 -Force | Out-Null - New-Item -ItemType Directory -Path tools\RDPWrapOffsetFinder\x86 -Force | Out-Null - - Copy-Item $x64exe.FullName tools\RDPWrapOffsetFinder\x64\RDPWrapOffsetFinder.exe -Force - Copy-Item $x64dll.FullName tools\RDPWrapOffsetFinder\x64\Zydis.dll -Force - Copy-Item $x86exe.FullName tools\RDPWrapOffsetFinder\x86\RDPWrapOffsetFinder.exe -Force - Copy-Item $x86dll.FullName tools\RDPWrapOffsetFinder\x86\Zydis.dll -Force - Set-Content -Path tools\RDPWrapOffsetFinder\VERSION -Value $version - - Write-Host "Staged tools:" - Get-ChildItem -Recurse tools\RDPWrapOffsetFinder | Select-Object FullName, Length - - echo "version=$version" >> $env:GITHUB_OUTPUT - - - name: Commit and push to a new branch - id: push - shell: pwsh - run: | - $version = "${{ steps.fetch.outputs.version }}" - $branch = "chore/update-finder-tools-$version" - - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git checkout -b $branch - git add tools/RDPWrapOffsetFinder - if ((git diff --cached --name-only) -eq "") { - Write-Host "No changes - tools already up to date" - exit 0 - } - git commit -m "chore: update RDPWrapOffsetFinder tools to $version" - git push origin $branch - echo "branch=$branch" >> $env:GITHUB_OUTPUT - - - name: Create pull request - if: steps.push.outputs.branch != '' - shell: pwsh - run: | - $version = "${{ steps.fetch.outputs.version }}" - $branch = "${{ steps.push.outputs.branch }}" - gh pr create ` - --title "chore: update RDPWrapOffsetFinder tools to $version" ` - --body "Automated update of the committed RDPWrapOffsetFinder binaries in ``tools/RDPWrapOffsetFinder/`` to upstream release $version. - -Triggered manually via the **Update RDPWrapOffsetFinder tools** workflow. -Merge to include the updated binaries in the next INI release." ` - --base master ` - --head $branch - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 56e5ba3..10e5e1a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ __history/ *.~* +# Local build output (produced by local builds; not committed) +build/ + # Compiled binaries *.dcu *.exe @@ -15,3 +18,24 @@ __history/ # MSI local stuff *.wixobj *.wixpdb +msi/bin/ +msi/obj/ +msi_out/ + +# Staged CI inputs inside msi/ (DLLs and EXEs copied there before WiX runs; +# generated at build time — not source files) +msi/*.dll +msi/*.exe + +# C# build outputs +src-csharp/**/bin/ +src-csharp/**/obj/ +# Staged resource: copied from msi/rdpwrap.ini at build time, not source +src-csharp/RDPWInst/Resources/rdpwrap.ini +src-csharp/RDPWInst/Resources/rdpw32.dll +src-csharp/RDPWInst/Resources/rdpw64.dll +src-csharp/RDPWInst/Resources/license.txt + +# C++ build outputs +src-x86-x64-Fusix/Release/ +src-x86-x64-Fusix/obj/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c7ed6aa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "src-csharp/RDPOffsetFinder"] + path = src-csharp/RDPOffsetFinder + url = https://github.com/llccd/RDPWrapOffsetFinder + shallow = true diff --git a/README.md b/README.md index d38bafe..0cd83fb 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,12 @@ > **Maintained fork** by [@sjackson0109](https://github.com/sjackson0109) — based on the original work by [Stas'M / binarymaster](https://github.com/stascorp/rdpwrap). -[![Telegram](https://img.shields.io/badge/chat-Telegram-blue.svg)](https://t.me/rdpwrap) ![Environment](https://img.shields.io/badge/Windows-Vista%20through%2011-brightgreen.svg) [![Release](https://img.shields.io/github/release/sjackson0109/rdpwrap.svg)](https://github.com/sjackson0109/rdpwrap/releases) -[![INI publish](https://github.com/sjackson0109/rdpwrap/actions/workflows/publish-ini.yml/badge.svg)](https://github.com/sjackson0109/rdpwrap/actions/workflows/publish-ini.yml) +[![Build and Release](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-and-release.yml/badge.svg)](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-and-release.yml) [![Build C++ DLL](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-cpp.yml/badge.svg)](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-cpp.yml) +[![Build C# tools](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-csharp.yml/badge.svg)](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-csharp.yml) +[![Build OffsetFinder](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-offsetfinder.yml/badge.svg)](https://github.com/sjackson0109/rdpwrap/actions/workflows/build-offsetfinder.yml) ![License](https://img.shields.io/github/license/sjackson0109/rdpwrap.svg) ![Downloads](https://img.shields.io/github/downloads/sjackson0109/rdpwrap/latest/total.svg) ![TotalDownloads](https://img.shields.io/github/downloads/sjackson0109/rdpwrap/total.svg) @@ -15,41 +16,22 @@ The goal of this project is to enable Remote Desktop Host support and concurrent RDP Wrapper works as a layer between Service Control Manager and Terminal Services, so the original termsrv.dll file remains untouched. Also this method is very strong against Windows Update. -[pVistaST]: http://stascorp.com/images/rdpwrap/pVistaST.jpg -[pVistaHB]: http://stascorp.com/images/rdpwrap/pVistaHB.jpg -[pWin7ST]: http://stascorp.com/images/rdpwrap/pWin7ST.jpg -[pWin7HB]: http://stascorp.com/images/rdpwrap/pWin7HB.jpg -[pWin8DP]: http://stascorp.com/images/rdpwrap/pWin8DP.jpg -[pWin8CP]: http://stascorp.com/images/rdpwrap/pWin8CP.jpg -[pWin8RP]: http://stascorp.com/images/rdpwrap/pWin8RP.jpg -[pWin8]: http://stascorp.com/images/rdpwrap/pWin8.jpg -[pWin81P]: http://stascorp.com/images/rdpwrap/pWin81P.jpg -[pWin81]: http://stascorp.com/images/rdpwrap/pWin81.jpg -[pWin10TP]: http://stascorp.com/images/rdpwrap/pWin10TP.jpg -[pWin10PTP]: http://stascorp.com/images/rdpwrap/pWin10PTP.jpg -[pWin10]: http://stascorp.com/images/rdpwrap/pWin10.jpg - -[fVistaST]: http://stascorp.com/images/rdpwrap/VistaST.png -[fVistaHB]: http://stascorp.com/images/rdpwrap/VistaHB.png -[fWin7ST]: http://stascorp.com/images/rdpwrap/Win7ST.png -[fWin7HB]: http://stascorp.com/images/rdpwrap/Win7HB.png -[fWin8DP]: http://stascorp.com/images/rdpwrap/Win8DP.png -[fWin8CP]: http://stascorp.com/images/rdpwrap/Win8CP.png -[fWin8RP]: http://stascorp.com/images/rdpwrap/Win8RP.png -[fWin8]: http://stascorp.com/images/rdpwrap/Win8.png -[fWin81P]: http://stascorp.com/images/rdpwrap/Win81P.png -[fWin81]: http://stascorp.com/images/rdpwrap/Win81.png -[fWin10TP]: http://stascorp.com/images/rdpwrap/Win10TP.png -[fWin10PTP]: http://stascorp.com/images/rdpwrap/Win10PTP.png -[fWin10]: http://stascorp.com/images/rdpwrap/Win10.png - -| NT Version | Screenshots | -| ------------- | ----------- | -| Windows Vista | [![Windows Vista Starter][pVistaST]][fVistaST] [![Windows Vista Home Basic][pVistaHB]][fVistaHB] | -| Windows 7 | [![Windows 7 Starter][pWin7ST]][fWin7ST] [![Windows 7 Home Basic][pWin7HB]][fWin7HB] | -| Windows 8 | [![Windows 8 Developer Preview][pWin8DP]][fWin8DP] [![Windows 8 Consumer Preview][pWin8CP]][fWin8CP] [![Windows 8 Release Preview][pWin8RP]][fWin8RP] [![Windows 8][pWin8]][fWin8] | -| Windows 8.1 | [![Windows 8.1 Preview][pWin81P]][fWin81P] [![Windows 8.1][pWin81]][fWin81] | -| Windows 10 | [![Windows 10 Technical Preview][pWin10TP]][fWin10TP] [![Windows 10 Pro Technical Preview][pWin10PTP]][fWin10PTP] [![Windows 10][pWin10]][fWin10] | +> **Historical screenshots** (Vista / 7 / 8 / 10 from the original Stas'M project) are archived at: +> https://web.archive.org/web/2015*/http://stascorp.com/images/rdpwrap/* + +### Screenshots + +> Screenshots are captured on Windows 11 after a successful install. +> Source files live in [`docs/images/`](docs/images/) — see the [capture guide](docs/images/README.md) if you want to contribute updated screenshots. + +| RDPConf — configuration | RDPCheck — supported | RDPCheck — warning | +|:---:|:---:|:---:| +| ![RDPConf configuration window](docs/images/RDPWrapperConfig.png) | ![RDPCheck showing Supported](docs/images/RDPWrapperCheck.png) | ![RDPCheck showing Warning](docs/images/RDPWrapperCheckWarning.png) | + +| MSI Installer — welcome | MSI Installer — complete | +|:---:|:---:| +| ![MSI installer welcome screen](docs/images/RDPWrapperMSI1.png) | ![MSI installer completion screen](docs/images/RDPWrapperMSI2.png) | + --- [WinPPE]: http://forums.mydigitallife.info/threads/39411-Windows-Product-Policy-Editor @@ -82,16 +64,72 @@ It's recommended to have original termsrv.dll file with the RDP Wrapper installa - **ARM** for Windows RT (see links below) - **IA-64** for Itanium-based Windows Server? *Well, I have no idea* :) +### Repository structure: + +``` +├── msi/ # WiX v5 MSI project + INI offset databases (rdpwrap.ini, rdpwrap-arm-kb.ini) +├── docs/ # Developer documentation +├── src-x86-x64-Fusix/ # C++ — core rdpwrap.dll (native Win32, MSVC) +└── src-csharp/ # C# .NET 10 — all management-plane tools + ├── Directory.Build.props # Shared build settings (framework, author metadata) + ├── RDPWrap.sln # Visual Studio solution + ├── RDPWrap/ # Shared helper library (P/Invoke, registry, service helpers) + ├── RDPWInst/ # Command-line installer / uninstaller + ├── RDPConf/ # WinForms configuration GUI + ├── RDPCheck/ # WinForms RDP loopback tester + └── RDPOffsetFinder/ # Git submodule — llccd/RDPWrapOffsetFinder (C++) + └── zydis/ # Git submodule — zyantific/zydis disassembler +``` + ### Building the binaries: -- **x86 Delphi version** (installer, config tool, checker) — requires *Embarcadero RAD Studio 2010* or later; no automated CI yet -- **x86/x64 C++ version** (`rdpwrap.dll`) — can be built locally with *Visual Studio 2013+*, or automatically via the [Build C++ DLL](.github/workflows/build-cpp.yml) GitHub Actions workflow (uses MSVC v143 / VS 2022) by pushing a `v*` tag + +#### Prerequisites +- **.NET SDK 10** — all C# tools (`src-csharp/`) + - Download: https://dotnet.microsoft.com/download/dotnet/10.0 +- **Visual Studio 2022 / MSVC Build Tools v143** — two C++ components: + - `src-x86-x64-Fusix/` — core `rdpwrap.dll` + - `src-csharp/RDPOffsetFinder/` — offset finder (pulled via git submodule) + +#### Clone with submodules +```powershell +git clone --recurse-submodules https://github.com/sjackson0109/rdpwrap.git +# or if already cloned: +git submodule update --init --recursive +``` + +#### Build C# tools locally +```powershell +# Debug build (both platforms) +dotnet build src-csharp/RDPWrap.sln -p:Platform=x64 +dotnet build src-csharp/RDPWrap.sln -p:Platform=x86 + +# Release publish — single-file EXE (requires .NET 10 Desktop Runtime on target) +dotnet publish src-csharp/RDPWInst/RDPWInst.csproj -c Release -r win-x64 -p:PublishSingleFile=true -p:SelfContained=false +dotnet publish src-csharp/RDPConf/RDPConf.csproj -c Release -r win-x64 -p:PublishSingleFile=true -p:SelfContained=false +dotnet publish src-csharp/RDPCheck/RDPCheck.csproj -c Release -r win-x64 -p:PublishSingleFile=true -p:SelfContained=false +``` + +#### Build `rdpwrap.dll` locally +```powershell +msbuild src-x86-x64-Fusix/RDPWrap.vcxproj /p:Configuration=Release /p:Platform=x64 /p:PlatformToolset=v143 +``` + +#### Build `RDPWrapOffsetFinder` locally +```powershell +# Build Zydis DLL first +msbuild src-csharp/RDPOffsetFinder/zydis/msvc/zydis/Zydis.vcxproj /p:Configuration="Release MD DLL" /p:Platform=x64 /p:PlatformToolset=v143 +# Then build the offset finder +msbuild src-csharp/RDPOffsetFinder/RDPWrapOffsetFinder/RDPWrapOffsetFinder.vcxproj /p:Configuration=Release /p:Platform=x64 /p:PlatformToolset=v143 +``` ### CI/CD Pipelines: | Workflow | Trigger | Output | |---|---|---| -| [publish-ini.yml](.github/workflows/publish-ini.yml) | Push to `main`/`master` touching `res/rdpwrap.ini`, or manual | GitHub Release with `rdpwrap.ini`, `RDPWrapOffsetFinder_x64/x86.exe`, `Zydis_x64/x86.dll` | -| [build-cpp.yml](.github/workflows/build-cpp.yml) | Version tag push (`v*`) | GitHub Release with `rdpwrap_x64.dll` and `rdpwrap_x86.dll` | +| [build-and-release.yml](.github/workflows/build-and-release.yml) | Push to `main`/`master` touching any source, INI, or the workflow file itself; or manual | **Canonical GitHub Release** — DLLs (x64/x86/arm64), C# tools, MSI packages, self-contained bundles, OffsetFinder, `rdpwrap.ini`, `rdpwrap-arm-kb.ini` | +| [build-csharp.yml](.github/workflows/build-csharp.yml) | PR to `main`/`master` touching `src-csharp/**`; version tag push (`v*`); or manual | PR compile check + artifact upload (no release) — use `build-and-release.yml` for a full release | +| [build-cpp.yml](.github/workflows/build-cpp.yml) | PR to `main`/`master` touching `src-x86-x64-Fusix/**`; version tag push (`v*`); or manual | PR compile check + artifact upload (no release) — use `build-and-release.yml` for a full release | +| [build-offsetfinder.yml](.github/workflows/build-offsetfinder.yml) | PR to `main`/`master` touching `src-csharp/RDPOffsetFinder/**`; version tag push (`v*`); or manual | PR compile check + artifact upload (no release) — use `build-and-release.yml` for a full release | [andrewblock]: http://web.archive.org/web/20150810054558/http://andrewblock.net/enable-remote-desktop-on-windows-8-core/ [mydigitallife]: http://forums.mydigitallife.info/threads/55935-RDP-Wrapper-Library-(works-with-Windows-8-1-Basic) @@ -125,14 +163,17 @@ It's recommended to have original termsrv.dll file with the RDP Wrapper installa ### Files in release package: -| File name | Description | -| --------- | ----------- | -| `RDPWInst.exe` | RDP Wrapper Library installer/uninstaller | -| `RDPCheck.exe` | Local RDP Checker (you can check the RDP is working) | -| `RDPConf.exe` | RDP Wrapper Configuration | -| `install.bat` | Quick install batch file | -| `uninstall.bat` | Quick uninstall batch file | -| `update.bat` | Quick update batch file | +| File name | Architecture | Description | +| --------- | ------------ | ----------- | +| `RDPWInst_x64.exe` | x64 | RDP Wrapper Library installer/uninstaller (C#, requires .NET 10) | +| `RDPWInst_x86.exe` | x86 | RDP Wrapper Library installer/uninstaller (C#, requires .NET 10) | +| `RDPCheck_x64.exe` | x64 | Local RDP Checker — verify RDP is working (C#, requires .NET 10) | +| `RDPCheck_x86.exe` | x86 | Local RDP Checker — verify RDP is working (C#, requires .NET 10) | +| `RDPConf_x64.exe` | x64 | RDP Wrapper Configuration GUI (C#, requires .NET 10) | +| `RDPConf_x86.exe` | x86 | RDP Wrapper Configuration GUI (C#, requires .NET 10) | +| `rdpwrap_x64.dll` | x64 | Core RDP Wrapper DLL (C++, no runtime required) | +| `rdpwrap_x86.dll` | x86 | Core RDP Wrapper DLL (C++, no runtime required) | +| `rdpwrap.ini` | — | Offset database (updated automatically on every INI push) | ### Frequently Asked Questions @@ -146,11 +187,11 @@ There is no definitive answer, see [this discussion](https://github.com/stascorp > The installer tries to access the Internet, is it normal behaviour? -Yes, it works in online mode by default. You may disable it by removing `-o` flag in the `install.bat` file. +Yes, it works in online mode by default. You may disable it by passing `-i` without the `-o` flag: `RDPWInst_x64.exe -i`. > What is online install mode? -Online install mode was introduced in version 1.6.1. When installing for the first time using this mode, the installer downloads the [latest `rdpwrap.ini`](https://github.com/sjackson0109/rdpwrap/releases/latest/download/rdpwrap.ini) from this repository's GitHub Releases — published automatically by CI/CD whenever `res/rdpwrap.ini` is updated. If your `termsrv.dll` version is not yet listed in the downloaded INI, the installer will additionally download [RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder) and attempt to auto-generate the missing offsets on the spot. +Online install mode was introduced in version 1.6.1. When installing for the first time using this mode, the installer downloads the [latest `rdpwrap.ini`](https://github.com/sjackson0109/rdpwrap/releases/latest/download/rdpwrap.ini) from this repository's GitHub Releases — published automatically by CI/CD whenever `msi/rdpwrap.ini` is updated. If your `termsrv.dll` version is not yet listed in the downloaded INI, the installer will additionally download [RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder) and attempt to auto-generate the missing offsets on the spot. > What is INI file and why we need it? @@ -162,7 +203,7 @@ Beginning with version 1.5 the `rdpwrap.dll` is not updated anymore, since all s > Config Tool shows `[not supported]` and RDP doesn't work. What can I do? -Make sure you're connected to the Internet and run `update.bat`. This will download the latest INI from GitHub Releases and, if your `termsrv.dll` version is still missing, will automatically run [RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder) to generate offsets for your specific build. +Make sure you're connected to the Internet and run `RDPWInst_x64.exe -w` from an Administrator command prompt. This will download the latest INI from GitHub Releases and, if your `termsrv.dll` version is still missing, will automatically run [RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder) to generate offsets for your specific build. > Update doesn't help, it still shows `[not supported]`. @@ -187,10 +228,41 @@ Check the [issues](https://github.com/sjackson0109/rdpwrap/issues) section to se ### Change log: +#### 2026.03.31 +- **Repository housekeeping** — removed six obsolete files: `res/legacy.install.bat`, `res/clearres.bat`, `res/build_wxs.bat`, `res/RDPWInst.wxs` (WiX v3.11 MSI, unmaintained), `res/rdpwrap-ini-kb.txt` (stale 2018 INI snapshot), and empty `src-csharp/RDPWrap.Common/` stub directory +- `bin/install.bat`, `bin/uninstall.bat`, `bin/update.bat` — rewritten with architecture detection; now invoke the correct `RDPWInst_x64.exe` / `RDPWInst_x86.exe` (previously called non-existent `RDPWInst.exe`); later removed in favour of the MSI installer +- CI/CD: `build-cpp.yml`, `build-csharp.yml`, `build-offsetfinder.yml` — standalone `release` jobs removed; `build-and-release.yml` is now the sole release publisher, eliminating duplicate partial releases on tag pushes +- `build-csharp.yml` runner harmonised to `windows-2022`; hardcoded `signtool.exe` SDK path replaced with glob-based discovery +- `build-and-release.yml` — added **embedded-resource staging** step (copies built DLLs + INI into `RDPWInst/Resources/` before `dotnet publish`, enabling offline bundled install); added **SHA-256 audit log** for third-party sergiye binaries; `msi/rdpwrap-arm-kb.ini` added to release assets +- **ARM64 support** — `Release|ARM64` added to `src-x86-x64-Fusix/RDPWrap.vcxproj`; `build-cpp.yml` and `build-and-release.yml` now build and ship `rdpwrap_arm64.dll`; `build-csharp.yml` and `build-and-release.yml` publish `RDPWInst_arm64.exe`, `RDPConf_arm64.exe`, `RDPCheck_arm64.exe`; `Directory.Build.props` adds `arm64` to `Platforms` +- **WiX v5 MSI packaging** — new `msi/RDPWInst.wxs` (WiX v5 schema v4, dual-arch, MajorUpgrade) and `msi/RDPWInst.wixproj`; replaces the deleted v3.11 artefacts; MSI build steps are now inlined into `build-and-release.yml` (a standalone `build-msi.yml` was created then removed as redundant) +- **Self-contained publish** — `build-and-release.yml` produces `*_x64_sc.exe`, `*_x86_sc.exe`, `*_arm64_sc.exe` for all three C# tools and bundles them into `RDPWrapper-SelfContained.zip`; users without .NET 10 Desktop Runtime can use these +- **Version stamp automation** — `build-and-release.yml` computes a `yyyy.M.d` stamp and passes `-p:Version=` to every `dotnet publish` call; `Directory.Build.props` documents the CI override pattern +- **Changelog automation** — `build-and-release.yml` now includes a `Generate changelog` step that queries merged PRs since the previous release and embeds them in the GitHub Release body +- **Dependabot** — `.github/dependabot.yml` added for `github-actions` and `nuget` ecosystems (weekly, Monday schedule) +- **Sergiye hash-pin scaffold** — `tools/sergiye-hashes.json` created; `build-and-release.yml` validates downloaded `rdpWrapper_*.exe` hashes against this file when populated +- **Code-signing guide** added — `docs/CODE-SIGNING.md` documents certificate acquisition, PFX export, base64 encoding, and GitHub secret upload; the signing step in `build-and-release.yml` and `build-csharp.yml` fires automatically once `CODESIGN_CERT_BASE64` and `CODESIGN_CERT_PASSWORD` secrets are set +- **Sergiye hash pins live** — `tools/update-sergiye-hashes.ps1` automation script created; `tools/sergiye-hashes.json` populated with verified SHA-256 hashes for `sergiye/rdpWrapper` release `2.10`; `build-and-release.yml` hash-verification step is now enforcing the pinned values +- **Screenshot infrastructure** — `docs/images/` directory and capture guide created; README restored with four-cell screenshot table using relative in-repo paths (PNG files pending first capture) +- **Submodule shallow-clone** — `shallow = true` added to `.gitmodules`; `docs/SUBMODULE-UPDATE.md` documents check-out, update, and rollback procedures (`RDPOffsetFinder` is already pinned to `v0.9`) +- **`tools/` reference added to `docs/`** — `update-sergiye-hashes.ps1` is self-documenting via `Get-Help`; `CODE-SIGNING.md`, `SUBMODULE-UPDATE.md`, `images/README.md` added to `docs/` + +#### 2026.03.30 +- **Full C# port complete** — `RDPWInst`, `RDPConf`, `RDPCheck`, and shared library all ported from Delphi to C# / .NET 10; Delphi is no longer required to build +- Obsolete Delphi source folders removed (`src-installer/`, `src-rdpcheck/`, `src-rdpconfig/`, `src-x86-binarymaster/`) +- Shared library renamed from `RDPWrap.Common/` to `RDPWrap/` for a cleaner folder layout; namespace `RDPWrap.Common` preserved for source compatibility +- **[llccd/RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder) added as a git submodule** at `src-csharp/RDPOffsetFinder/` (including nested `zydis` → `zycore` submodules) — offset finder now built from source rather than fetching pre-built binaries +- Pre-built binary cache (`tools/RDPWrapOffsetFinder/`) and `update-finder-tools.yml` workflow removed; `build-and-release.yml` now builds the offset finder directly from the submodule +- New workflow [`build-offsetfinder.yml`](.github/workflows/build-offsetfinder.yml) — builds `RDPWrapOffsetFinder` + `Zydis.dll` for x64 and Win32 from source on version tag push +- New workflow [`build-csharp.yml`](.github/workflows/build-csharp.yml) — publishes self-contained single-file x64/x86 EXEs on version tag push; optional `signtool.exe` code-signing step wired to `CODESIGN_CERT_BASE64` / `CODESIGN_CERT_PASSWORD` repository secrets +- [`build-and-release.yml`](.github/workflows/build-and-release.yml) updated — checkout uses `submodules: recursive`; builds and bundles `RDPWInst`, `RDPConf`, `RDPCheck`, and `RDPWrapOffsetFinder` (all x64 + x86) alongside the existing DLL and INI assets +- Author metadata (`Simon Jackson / @sjackson0109`, copyright, repository URL) embedded into all four C# assemblies via `Directory.Build.props` +- `src-csharp/Directory.Build.props` targets `net10.0-windows`; `x86` and `x64` platforms; `Nullable` + `ImplicitUsings` enabled + #### 2026.03.29 - Fork maintained by [@sjackson0109](https://github.com/sjackson0109) - INI source redirected from unmaintained stascorp upstream to this repository's GitHub Releases -- **CI/CD pipeline added** — [`publish-ini.yml`](.github/workflows/publish-ini.yml) publishes `rdpwrap.ini` and the `RDPWrapOffsetFinder` tools as release assets on every INI change +- **CI/CD pipeline added** — [`build-and-release.yml`](.github/workflows/build-and-release.yml) publishes `rdpwrap.ini` and the `RDPWrapOffsetFinder` tools as release assets on every INI change - **CI/CD pipeline added** — [`build-cpp.yml`](.github/workflows/build-cpp.yml) builds `rdpwrap_x64.dll` / `rdpwrap_x86.dll` via MSVC v143 (VS 2022) on version tag push - **Auto-offset generation** added to `RDPWInst.dpr` — on install (`-i`) and update (`-w`), if the running `termsrv.dll` version is absent from the INI the installer downloads `RDPWrapOffsetFinder` from release assets and appends the generated `[x.x.xxxxx.xxxxx]` section automatically; inspired by [sergiye/rdpWrapper](https://github.com/sergiye/rdpWrapper) - New installer helpers: `DownloadFileToDisk`, `INIHasSection`, `TryAutoGenerateOffsets` @@ -476,15 +548,15 @@ Check the [issues](https://github.com/sjackson0109/rdpwrap/issues) section to se - Windows Server 2016 Technical Preview Installation instructions: -- Download latest release binaries and unpack files -- Right-click on **`install.bat`** and select Run as Administrator +- Download `RDPWrapper-.msi` from the [GitHub Releases](https://github.com/sjackson0109/rdpwrap/releases) page +- Double-click the MSI and accept the UAC prompt — the installer detects your architecture automatically - See command output for details To update INI file: -- Right-click on **`update.bat`** and select Run as Administrator +- Open an Administrator command prompt in `%ProgramFiles%\RDP Wrapper` +- Run `RDPWInst_x64.exe -w` (or `RDPWInst_x86.exe -w` on 32-bit Windows) - See command output for details To uninstall: -- Go to the directory where you extracted the files -- Right-click on **`uninstall.bat`** and select Run as Administrator -- See command output for details +- Open **Add or Remove Programs** and uninstall **RDP Wrapper Library** +- Alternatively run `msiexec /x RDPWrapper-.msi` from an elevated prompt diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..0371884 --- /dev/null +++ b/TODO.md @@ -0,0 +1,3 @@ +# TODO + +All items complete. Nothing pending. diff --git a/bin/install.bat b/bin/install.bat deleted file mode 100644 index 5e6ed34..0000000 --- a/bin/install.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -if not exist "%~dp0RDPWInst.exe" goto :error -"%~dp0RDPWInst" -i -o -echo ______________________________________________________________ -echo. -echo You can check RDP functionality with RDPCheck program. -echo Also you can configure advanced settings with RDPConf program. -echo. -goto :anykey -:error -echo [-] Installer executable not found. -echo Please extract all files from the downloaded package or check your anti-virus. -:anykey -pause diff --git a/bin/uninstall.bat b/bin/uninstall.bat deleted file mode 100644 index 1c72289..0000000 --- a/bin/uninstall.bat +++ /dev/null @@ -1,10 +0,0 @@ -@echo off -if not exist "%~dp0RDPWInst.exe" goto :error -"%~dp0RDPWInst" -u -echo. -goto :anykey -:error -echo [-] Installer executable not found. -echo Please extract all files from the downloaded package or check your anti-virus. -:anykey -pause diff --git a/bin/update.bat b/bin/update.bat deleted file mode 100644 index f3874aa..0000000 --- a/bin/update.bat +++ /dev/null @@ -1,10 +0,0 @@ -@echo off -if not exist "%~dp0RDPWInst.exe" goto :error -"%~dp0RDPWInst" -w -echo. -goto :anykey -:error -echo [-] Installer executable not found. -echo Please extract all files from the downloaded package or check your anti-virus. -:anykey -pause diff --git a/docs/BUILDING.md b/docs/BUILDING.md new file mode 100644 index 0000000..9d2ee66 --- /dev/null +++ b/docs/BUILDING.md @@ -0,0 +1,255 @@ +# Building RDP Wrapper Locally + +This document covers the full local build pipeline — from prerequisites to the final `./build/` artefacts. + +--- + +## Prerequisites + +| Component | Version | Notes | +|---|---|---| +| Windows 10/11 x64 | any | Host OS | +| .NET SDK | 10.0+ | `winget install Microsoft.DotNet.SDK.10` | +| Visual Studio 2019 Build Tools | 16.x | For C++ DLL only | +| MSVC v142 toolset | 14.29+ | Installed via VS Build Tools installer | +| Windows SDK | 10.0.19041+ | Installed via VS Build Tools installer | + +> **ARM64 DLL note:** Building `rdpwrap_arm64.dll` locally requires Visual Studio 2022 +> with the "MSVC v143 — VS 2022 C++ ARM64 build tools" component. The GitHub Actions +> CI uses a hosted `windows-latest` runner which provides this. For local work, the +> x64 and Win32 DLLs are sufficient for testing. + +--- + +## 1. Clone the repository + +```powershell +git clone --recurse-submodules https://github.com//rdpwrap.git +cd rdpwrap +``` + +If you already cloned without `--recurse-submodules`: + +```powershell +git submodule update --init --recursive +``` + +--- + +## 2. Generate application icons + +The C# tool icons are generated programmatically via a helper script and are **not** +committed to source control. Run this once after cloning (and again if you delete them): + +```powershell +.\tools\make-icons.ps1 +``` + +This creates: + +- `src-csharp/RDPConf/app.ico` — blue "C" icon for RDPConf +- `src-csharp/RDPCheck/app.ico` — green "K" icon for RDPCheck + +Both files are `.gitignore`-exempt (not listed) so they persist in your working tree. + +--- + +## 3. Build the C++ DLL (`rdpwrap.dll`) + +### Locate MSBuild + +Visual Studio 2019 Build Tools installs MSBuild to a non-standard path. +Add it to your session PATH once (or use the full path as shown below): + +```powershell +$msbuild = "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\amd64\MSBuild.exe" +``` + +> If you have Visual Studio IDE installed instead of Build Tools, the path is: +> `C:\Program Files\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\amd64\MSBuild.exe` + +### One-time vcxproj fix + +The Windows SDK 10.0.19041 headers emit a C2338 packing warning that is treated as an +error under `/WX`. It has **no behavioural effect** — the fix is already applied in +`src-x86-x64-Fusix/RDPWrap.vcxproj` via the `WINDOWS_IGNORE_PACKING_MISMATCH` define. +No manual action is required. + +### Build x64 and Win32 + +```powershell +$msbuild = "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\amd64\MSBuild.exe" + +& $msbuild src-x86-x64-Fusix\RDPWrap.sln ` + /p:Configuration=Release /p:Platform=x64 ` + /p:PlatformToolset=v142 ` + /p:WindowsTargetPlatformVersion=10.0.19041.0 ` + /m /v:m + +& $msbuild src-x86-x64-Fusix\RDPWrap.sln ` + /p:Configuration=Release /p:Platform=Win32 ` + /p:PlatformToolset=v142 ` + /p:WindowsTargetPlatformVersion=10.0.19041.0 ` + /m /v:m +``` + +> Expect `C4244` / `C4267` type-conversion warnings from the Zydis disassembler +> submodule — these are benign and can be ignored. + +### Output locations + +| Platform | Output path | +|---|---| +| x64 | `src-x86-x64-Fusix/x64/Release/RDPWrap.dll` | +| Win32 | `src-x86-x64-Fusix/Release/RDPWrap.dll` | + +--- + +## 4. Build C# tools + +All three C# tools are published as self-contained single-file executables using +`dotnet publish`. + +### Architectures + +| RID | Description | +|---|---| +| `win-x64` | 64-bit Intel/AMD | +| `win-x86` | 32-bit Intel/AMD | +| `win-arm64` | ARM64 (cross-compiled, no native toolchain needed) | + +### Commands + +```powershell +$TOOLS = @("RDPConf", "RDPCheck", "RDPWInst") +$RIDS = @("win-x64", "win-x86", "win-arm64") + +foreach ($tool in $TOOLS) { + foreach ($rid in $RIDS) { + $arch = $rid -replace "win-", "" + $out = "build\staging\$tool\$rid" + dotnet publish "src-csharp\$tool\$tool.csproj" ` + -c Release -r $rid ` + --self-contained true ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true ` + -p:PublishTrimmed=false ` + -p:Version=1.0.0 ` + -o $out + } +} +``` + +### Output + +After publishing, executables are in `build/staging///`: + +``` +build\staging\RDPConf\win-x64\RDPConf.exe +build\staging\RDPConf\win-x86\RDPConf.exe +build\staging\RDPConf\win-arm64\RDPConf.exe +build\staging\RDPCheck\win-x64\RDPCheck.exe +... +``` + +--- + +## 5. Assemble `./build/` + +Copy all artefacts to a flat `./build/` directory: + +```powershell +New-Item -Force -ItemType Directory build | Out-Null + +# DLLs +Copy-Item src-x86-x64-Fusix\x64\Release\RDPWrap.dll build\rdpwrap_x64.dll +Copy-Item src-x86-x64-Fusix\Release\RDPWrap.dll build\rdpwrap_x86.dll + +# C# executables +foreach ($tool in @("RDPConf","RDPCheck","RDPWInst")) { + foreach ($rid in @("win-x64","win-x86","win-arm64")) { + $arch = $rid -replace "win-","" + Copy-Item "build\staging\$tool\$rid\$tool.exe" ` + "build\${tool}_${arch}.exe" + } +} + +# Cleanup staging +Remove-Item -Recurse -Force build\staging +``` + +### Final `./build/` layout + +``` +build/ + rdpwrap_x64.dll # x64 termsrv.dll hook + rdpwrap_x86.dll # x86 termsrv.dll hook + RDPConf_x64.exe # GUI config tool (x64) + RDPConf_x86.exe # GUI config tool (x86) + RDPConf_arm64.exe # GUI config tool (ARM64) + RDPCheck_x64.exe # RDP loopback tester (x64) + RDPCheck_x86.exe # RDP loopback tester (x86) + RDPCheck_arm64.exe # RDP loopback tester (ARM64) + RDPWInst_x64.exe # CLI installer (x64) + RDPWInst_x86.exe # CLI installer (x86) + RDPWInst_arm64.exe # CLI installer (ARM64) +``` + +> `./build/` is listed in `.gitignore` — artefacts are not committed. + +--- + +## 6. Automated script + +All steps 2–5 are automated in `tools/build-local.ps1`. +Run it from the repo root: + +```powershell +.\tools\build-local.ps1 +``` + +Optional flag to skip the DLL rebuild (faster during C# iteration): + +```powershell +.\tools\build-local.ps1 -SkipCpp +``` + +--- + +## 7. Troubleshooting + +### MSBuild not found +Verify VS 2019 Build Tools are installed. +Open the **Visual Studio Installer** → Modify → ensure +"Desktop development with C++" and "MSVC v142 build tools" are checked. + +### ARM64 DLL: `error MSB8013` +No ARM64 cross-compiler found. Either install VS 2022 with ARM64 tools or skip ARM64 +(`-SkipArm64Dll` flag in `build-local.ps1`). The ARM64 DLL is produced by CI. + +### `error C2338: Windows headers require the default packing option` +`WINDOWS_IGNORE_PACKING_MISMATCH` is missing from `PreprocessorDefinitions`. +Run the following once then rebuild: + +```powershell +(Get-Content src-x86-x64-Fusix\RDPWrap.vcxproj) ` + -replace '()([^<]+)(<)', ` + '$1$2;WINDOWS_IGNORE_PACKING_MISMATCH$3' | + Set-Content src-x86-x64-Fusix\RDPWrap.vcxproj +``` + +### `dotnet publish` fails with SDK not found +Ensure .NET 10 SDK is installed: `dotnet --version` should print `10.x.x`. + +--- + +## Appendix: CI vs local comparison + +| Feature | Local build | GitHub Actions CI | +|---|---|---| +| x64 DLL | ✅ | ✅ | +| x86 DLL | ✅ | ✅ | +| ARM64 DLL | ❌ (needs VS 2022) | ✅ | +| C# x64/x86/arm64 | ✅ (cross-compiled) | ✅ | +| Code signing | ❌ | ✅ (if cert configured) | +| GitHub Release | ❌ | ✅ (on tag push) | diff --git a/docs/CODE-SIGNING.md b/docs/CODE-SIGNING.md new file mode 100644 index 0000000..000faa7 --- /dev/null +++ b/docs/CODE-SIGNING.md @@ -0,0 +1,100 @@ +# Code Signing Guide + +Both `build-and-release.yml` and `build-csharp.yml` include a code-signing step that is already wired up and waiting. The step fires automatically as soon as the two secrets below are present in the repository — no workflow edits are needed. + +--- + +## What gets signed + +All six framework-dependent executables and all six self-contained executables produced per release: + +| File | Contents | +|---|---| +| `RDPWInst_x64.exe`, `RDPWInst_x86.exe`, `RDPWInst_arm64.exe` | CLI installer | +| `RDPConf_x64.exe`, `RDPConf_x86.exe`, `RDPConf_arm64.exe` | GUI configuration tool | +| `RDPCheck_x64.exe`, `RDPCheck_x86.exe`, `RDPCheck_arm64.exe` | GUI connection tester | +| `*_sc.exe` variants | Self-contained copies of the above | + +The signing step runs on every `build-and-release.yml` and `build-csharp.yml` triggered build (tag push and manual dispatch), and is **skipped silently** when the secrets are absent. + +--- + +## Obtaining a code-signing certificate + +### Option A — Commercial certificate (recommended for public distribution) + +Purchase an **EV (Extended Validation) Code Signing Certificate** from a trusted CA: + +- [DigiCert Code Signing](https://www.digicert.com/signing/code-signing-certificates) +- [Sectigo (Comodo)](https://sectigo.com/ssl-certificates-tls/code-signing) +- [GlobalSign](https://www.globalsign.com/en/code-signing-certificate/) + +> **Windows SmartScreen** initially blocks unsigned or low-reputation executables. A commercial EV certificate builds reputation immediately; a standard OV certificate requires time to accumulate reputation through user downloads. Self-signed certificates (Option B) will always trigger SmartScreen warnings. + +### Option B — Self-signed certificate (testing / internal use only) + +```powershell +# Run in an elevated PowerShell session +$cert = New-SelfSignedCertificate ` + -Type CodeSigningCert ` + -Subject "CN=RDP Wrapper" ` + -KeySpec Signature ` + -KeyAlgorithm RSA ` + -KeyLength 4096 ` + -HashAlgorithm SHA256 ` + -CertStoreLocation "Cert:\CurrentUser\My" ` + -NotAfter (Get-Date).AddYears(3) + +# Export to PFX (set a strong password) +$pw = Read-Host "PFX password" -AsSecureString +Export-PfxCertificate -Cert $cert -FilePath "rdpwrap-codesign.pfx" -Password $pw +``` + +--- + +## Preparing the PFX for GitHub Actions + +```powershell +# Base64-encode the PFX so it can be stored as a secret +$b64 = [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\rdpwrap-codesign.pfx")) +$b64 | Set-Clipboard +Write-Host "Base64 PFX copied to clipboard" +``` + +--- + +## Adding the secrets to GitHub + +Navigate to: **Settings → Secrets and variables → Actions → New repository secret** + +| Secret name | Value | +|---|---| +| `CODESIGN_CERT_BASE64` | Paste the base64-encoded PFX string | +| `CODESIGN_CERT_PASSWORD` | The password chosen when exporting the PFX | + +> ⚠️ **Security:** Never commit the `.pfx` file or raw base64 string to the repository. Revoke and reissue the certificate if it is accidentally exposed. + +--- + +## Verifying a signed executable + +After a signed release is published: + +```powershell +# Check signature status +Get-AuthenticodeSignature .\RDPWInst_x64.exe | Format-List + +# Expected output (commercial cert): +# Status : Valid +# SignerCertificate : [CN=Your Name, O=Your Org, ...] +# TimeStamperCertificate : [CN=DigiCert Timestamp 2023, ...] +``` + +--- + +## Renewing / rotating the certificate + +1. Export the new PFX and base64-encode it (see above). +2. Update both `CODESIGN_CERT_BASE64` and `CODESIGN_CERT_PASSWORD` via **Settings → Secrets**. +3. No workflow changes are needed — the `Sign C# executables` step always reads from secrets at runtime. +4. Remove the old PFX from your local machine and revoke the old certificate with the CA if it has not expired. diff --git a/docs/HOW-TO-ADD-NEW-WINDOWS-BUILDS.md b/docs/HOW-TO-ADD-NEW-WINDOWS-BUILDS.md index c78f3ee..b6826d8 100644 --- a/docs/HOW-TO-ADD-NEW-WINDOWS-BUILDS.md +++ b/docs/HOW-TO-ADD-NEW-WINDOWS-BUILDS.md @@ -4,7 +4,88 @@ This guide explains the technical process for reverse engineering new Windows bu ## Overview -When Microsoft releases new Windows updates, the `termsrv.dll` file changes, and RDP Wrapper needs updated offset configurations to function properly. This document outlines the manual reverse engineering process required to find these offsets. +When Microsoft releases new Windows updates, the `termsrv.dll` file changes, and RDP Wrapper needs updated offset configurations to function properly. This document covers **two paths**: + +1. **[Quick path — RDPWrapOffsetFinder (recommended)](#quick-path-rdpwrapoffsetfinder-automated):** the compiled tool bundled in every release can generate a valid INI section in seconds on most builds. +2. **[Manual path — disassembly and reverse engineering](#manual-path-disassembly-and-reverse-engineering):** used when the automated tool cannot find all offsets for a new or unusual build. + +--- + +## Quick path: RDPWrapOffsetFinder (automated) + +> **TL;DR** — run the tool, copy the generated INI block, open a PR. + +RDPWrapOffsetFinder (by **llccd**, bundled in every release as `RDPWrapOffsetFinder_x64.exe` and `RDPWrapOffsetFinder_x86.exe`) performs automated static analysis on the installed `termsrv.dll` and emits a ready-to-use INI section. + +### Step A: Run RDPWrapOffsetFinder + +```powershell +# Locate termsrv.dll version (so you know what tag to add) +(Get-Item C:\Windows\System32\termsrv.dll).VersionInfo.ProductVersion + +# Run the tool (run as Administrator; it reads the locked DLL via sharing flags) +.\RDPWrapOffsetFinder_x64.exe +``` + +On success the tool prints an INI block similar to: + +```ini +[10.0.26100.3915] +SingleUserPatch.x64=1 +SingleUserOffset.x64=0A1B2C +... +``` + +If the tool exits with `Unsupported version`, try the nosym (no-symbols) variant: + +```powershell +.\RDPWrapOffsetFinder_nosym_x64.exe +``` + +### Step B: Use the autoupdate helper (optional) + +The `autoupdate/` directory in `src-csharp/RDPOffsetFinder/` contains a convenience script that wraps the tool, appends the output to a local copy of `rdpwrap.ini`, and validates the result: + +```batch +cd src-csharp\RDPOffsetFinder\RDPWrapOffsetFinder\autoupdate +autoupdate.bat +``` + +The script will: +1. Run `RDPWrapOffsetFinder.exe` against the current system's `termsrv.dll`. +2. Merge the new section into `rdpwrap_template.ini`. +3. Print the diff so you can review before committing. + +### Step C: Validate the generated block + +Before opening a pull request: + +```powershell +# Quick sanity check — restart Terminal Services with the new INI +net stop TermService +Copy-Item .\rdpwrap_updated.ini "C:\Program Files\RDP Wrapper\rdpwrap.ini" +net start TermService + +# Visual validation +.\RDPCheck.exe # should show "Installed", "Listening", and "Supported" +``` + +### Step D: Submit a pull request + +1. Add (or update) the version block in `msi/rdpwrap.ini`. +2. Commit with message: `ini: add support for 10.0.XXXXX.YYYY`. +3. Open a pull request against the `main` branch using the [bug_report](.github/ISSUE_TEMPLATE/bug_report.yml) template. + Include: the output of `RDPWrapOffsetFinder.exe`, your `termsrv.dll` version, and a screenshot of `RDPCheck.exe` showing "Supported". + +> **Security note:** Never attach the actual `termsrv.dll` binary — this would infringe Microsoft's licence. The version string and SHA-256 hash are sufficient for reproducibility. + +--- + +## Manual path: disassembly and reverse engineering + +Use this path when: +- RDPWrapOffsetFinder cannot find all offsets (prints partial output or crashes), **or** +- You want to understand *why* a patch works, not just *where* to apply it. ## Prerequisites diff --git a/docs/SUBMODULE-UPDATE.md b/docs/SUBMODULE-UPDATE.md new file mode 100644 index 0000000..0ba02df --- /dev/null +++ b/docs/SUBMODULE-UPDATE.md @@ -0,0 +1,101 @@ +# Submodule Update Guide + +This repository includes one git submodule (with nested sub-submodules): + +| Submodule | Upstream | Current tag | +|---|---|---| +| `src-csharp/RDPOffsetFinder` | [llccd/RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder) | `v0.9` | +| `src-csharp/RDPOffsetFinder/zydis` | [zyantific/zydis](https://github.com/zyantific/zydis) | (pinned by upstream) | +| `src-csharp/RDPOffsetFinder/zydis/dependencies/zycore` | [zyantific/zycore-c](https://github.com/zyantific/zycore-c) | (pinned by upstream) | + +The nested `zydis` and `zycore` submodule commits are controlled by llccd's repository — update only the outer submodule and the inner ones follow automatically. + +--- + +## Cloning with submodules + +```bash +# Full clone (recommended for builds) +git clone --recurse-submodules https://github.com/sjackson0109/rdpwrap + +# If you already cloned without --recurse-submodules: +git submodule update --init --recursive +``` + +--- + +## Checking current submodule version + +```powershell +git submodule status --recursive +# Expected output (one line per submodule): +# 68da37acab6593c329776644944f55695a131731 src-csharp/RDPOffsetFinder (v0.9) +# 5a68f639e4f01604cc7bfc8d313f583a8137e3d3 src-csharp/RDPOffsetFinder/zydis (...) +# fb69402566a15a719e5df7a64a3db95105590b7e src-csharp/RDPOffsetFinder/zydis/dependencies/zycore (...) +``` + +--- + +## Updating to a new upstream release + +> **Do this only when a new tagged release of [llccd/RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder) is published** and you have verified that the new version produces correct INI sections for a known Windows build. + +```powershell +# 1. Fetch all tags from upstream +cd src-csharp/RDPOffsetFinder +git fetch --tags origin + +# 2. List available tags to find the new release +git tag --list --sort=-version:refname | Select-Object -First 10 + +# 3. Check out the desired tag +git checkout # e.g. v1.0 + +# 4. Update nested submodules to match the new tag's references +git submodule update --init --recursive + +# 5. Return to repo root and record the new pointer +cd ../.. +git add src-csharp/RDPOffsetFinder +git commit -m "chore: update RDPOffsetFinder submodule to " +git push +``` + +--- + +## Verifying the updated submodule builds + +```powershell +# From repo root — builds x64 and x86 offset finder binaries +cd src-csharp/RDPOffsetFinder + +cmake -B build-x64 -A x64 . +cmake --build build-x64 --config Release + +cmake -B build-x86 -A Win32 . +cmake --build build-x86 --config Release +``` + +Or trigger the `build-offsetfinder.yml` workflow on your push branch to let CI validate it. + +--- + +## Rollback + +If the update causes build failures, revert the submodule pointer: + +```powershell +git revert HEAD # creates a revert commit +git push +``` + +Or manually: + +```powershell +cd src-csharp/RDPOffsetFinder +git checkout v0.9 # previous known-good tag +cd ../.. +git add src-csharp/RDPOffsetFinder +git commit -m "chore: rollback RDPOffsetFinder submodule to v0.9" +git push +``` diff --git a/docs/images/RDPWrapperCheck.png b/docs/images/RDPWrapperCheck.png new file mode 100644 index 0000000..81b02e9 Binary files /dev/null and b/docs/images/RDPWrapperCheck.png differ diff --git a/docs/images/RDPWrapperCheckWarning.png b/docs/images/RDPWrapperCheckWarning.png new file mode 100644 index 0000000..263a879 Binary files /dev/null and b/docs/images/RDPWrapperCheckWarning.png differ diff --git a/docs/images/RDPWrapperConfig.png b/docs/images/RDPWrapperConfig.png new file mode 100644 index 0000000..9a03ec0 Binary files /dev/null and b/docs/images/RDPWrapperConfig.png differ diff --git a/docs/images/RDPWrapperMSI1.png b/docs/images/RDPWrapperMSI1.png new file mode 100644 index 0000000..d62f59d Binary files /dev/null and b/docs/images/RDPWrapperMSI1.png differ diff --git a/docs/images/RDPWrapperMSI2.png b/docs/images/RDPWrapperMSI2.png new file mode 100644 index 0000000..594c7eb Binary files /dev/null and b/docs/images/RDPWrapperMSI2.png differ diff --git a/docs/images/README.md b/docs/images/README.md new file mode 100644 index 0000000..f687bfd --- /dev/null +++ b/docs/images/README.md @@ -0,0 +1,51 @@ +# Screenshots — `docs/images/` + +This directory holds in-repo screenshot assets referenced by the project README. + +--- + +## Files present + +The following PNG screenshots are committed and referenced by the README: + +| Filename | Contents | +|---|---| +| `RDPWrapperConfig.png` | RDPConf.exe configuration window | +| `RDPWrapperCheck.png` | RDPCheck.exe showing green "Supported" status | +| `RDPWrapperCheckWarning.png` | RDPCheck.exe showing "Warning" / not-yet-supported state | +| `RDPWrapperMSI1.png` | MSI installer welcome / licence screen | +| `RDPWrapperMSI2.png` | MSI installer completion screen | + +--- + +## Files that would still be welcome + +The following screenshots would improve documentation coverage but are not blocking any CI step: + +| Filename | What to capture | +|---|---| +| `RDPWrapperConfig-advanced.png` | RDPConf.exe Advanced / License tab — SL policy and licensing status fields | +| `rdpwrapper-gui.png` | sergiye/rdpWrapper GUI — main window with connection status | +| `install-success.png` | Terminal output of `RDPWInst_x64.exe -i -o` completing successfully | + +--- + +## Capture tips + +- Use **1:1 scaling** (100 % DPI) so button labels are legible at small display size. +- Crop to exclude desktop wallpaper — show only the tool window, with a 4 px neutral border all round. +- Use PNG format (lossless); aim for < 200 KB each (resize if needed — 900 px wide is more than enough). +- Redact any username, hostname, or licence strings visible in the window before committing. +- Filename convention: `tool-state.png` — all lowercase, hyphen-delimited. + +--- + +## Adding a new screenshot + +```bash +# After copying the PNG here: +git add docs/images/.png +git commit -m "docs: add screenshot" +``` + +The README references each file with a relative path, so the image will render automatically on GitHub once committed. diff --git a/msi/RDPWInst.wixproj b/msi/RDPWInst.wixproj new file mode 100644 index 0000000..94a9575 --- /dev/null +++ b/msi/RDPWInst.wixproj @@ -0,0 +1,24 @@ + + + + + RDPWrapper-$(Platform) + + 26.3.31 + + PackageVersion=$(PackageVersion) + + ICE61 + + diff --git a/msi/RDPWInst.wxs b/msi/RDPWInst.wxs new file mode 100644 index 0000000..664acea --- /dev/null +++ b/msi/RDPWInst.wxs @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msi/global.json b/msi/global.json new file mode 100644 index 0000000..cb8627f --- /dev/null +++ b/msi/global.json @@ -0,0 +1,5 @@ +{ + "msbuild-sdks": { + "WixToolset.Sdk": "5.0.2" + } +} diff --git a/res/rdpwrap-arm-kb.ini b/msi/rdpwrap-arm-kb.ini similarity index 100% rename from res/rdpwrap-arm-kb.ini rename to msi/rdpwrap-arm-kb.ini diff --git a/res/rdpwrap.ini b/msi/rdpwrap.ini similarity index 99% rename from res/rdpwrap.ini rename to msi/rdpwrap.ini index d9f862d..b651523 100644 --- a/res/rdpwrap.ini +++ b/msi/rdpwrap.ini @@ -2,7 +2,7 @@ ; Do not modify without special knowledge [Main] -Updated=2026-01-25 +Updated=2026-04-02 LogFile=\rdpwrap.txt SLPolicyHookNT60=1 SLPolicyHookNT61=1 diff --git a/res/RDPWInst.wxs b/res/RDPWInst.wxs deleted file mode 100644 index 9352ffc..0000000 --- a/res/RDPWInst.wxs +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NOT Installed AND NOT WIX_UPGRADE_DETECTED - REMOVE AND NOT UPGRADINGPRODUCTCODE - UPGRADINGPRODUCTCODE - - - - - diff --git a/res/build_wxs.bat b/res/build_wxs.bat deleted file mode 100644 index 9eeef72..0000000 --- a/res/build_wxs.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -"%ProgramFiles%\WiX Toolset v3.11\bin\candle" RDPWInst.wxs -"%ProgramFiles%\WiX Toolset v3.11\bin\light" RDPWInst.wixobj diff --git a/res/clearres.bat b/res/clearres.bat deleted file mode 100644 index 278e6cd..0000000 --- a/res/clearres.bat +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -echo [FILENAMES]> clearres.txt -echo Exe=%1>> clearres.txt -echo SaveAs=%1>> clearres.txt -echo Log=>> clearres.txt -echo.>> clearres.txt -echo [COMMANDS]>> clearres.txt -echo -delete RCDATA,CHARTABLE,>> clearres.txt -echo -delete RCDATA,DVCLAL,>> clearres.txt -echo -delete RCDATA,PACKAGEINFO,>> clearres.txt -echo -delete CURSORGROUP,32761,>> clearres.txt -echo -delete CURSORGROUP,32762,>> clearres.txt -echo -delete CURSORGROUP,32763,>> clearres.txt -echo -delete CURSORGROUP,32764,>> clearres.txt -echo -delete CURSORGROUP,32765,>> clearres.txt -echo -delete CURSORGROUP,32766,>> clearres.txt -echo -delete CURSORGROUP,32767,>> clearres.txt -"C:\Program Files\Resource Hacker\ResHacker.exe" -script clearres.txt -del clearres.txt diff --git a/res/legacy.install.bat b/res/legacy.install.bat deleted file mode 100644 index 303cc32..0000000 --- a/res/legacy.install.bat +++ /dev/null @@ -1,92 +0,0 @@ -@echo off -setlocal EnableDelayedExpansion -echo RDP Wrapper Library Installer v1.0 -echo Copyright (C) Stas'M Corp. 2013 -echo. - -set PROCESSOR_ARCHITECTURE | find "x86" > nul -if !errorlevel!==0 ( - goto WOW64CHK -) else ( - goto UNSUPPORTED -) - -:WOW64CHK -echo [*] Check if running WOW64 subsystem... -set PROCESSOR_ARCHITEW6432 > nul -if !errorlevel!==0 ( - goto UNSUPPORTED -) else ( - goto SUPPORTED -) - -:SUPPORTED -echo [+] Processor architecture is Intel x86 [supported] -goto INSTALL - -:UNSUPPORTED -echo [-] Unsupported processor architecture -goto END - -:INSTALL -echo [*] Installing... -if not exist rdpwrap.dll ( - echo [-] Error: rdpwrap.dll file not found - goto END -) -echo [*] Copying file to Program Files... -md "%ProgramFiles%\RDP Wrapper" -xcopy /y rdpwrap.dll "%ProgramFiles%\RDP Wrapper\" -if not !errorlevel!==0 ( - echo [-] Failed to copy rdpwrap.dll to Program Files folder - goto END -) -echo [*] Modifying registry... -reg add "HKLM\SYSTEM\CurrentControlSet\Services\TermService\Parameters" /v ServiceDll /t REG_EXPAND_SZ /d "%ProgramFiles%\RDP Wrapper\rdpwrap.dll" /f -if not !errorlevel!==0 ( - echo [-] Failed to modify registry - goto END -) -echo [*] Setting firewall configuration... -reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f -netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=tcp localport=3389 profile=any action=allow -netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=udp localport=3389 profile=any action=allow -echo [*] Looking for TermService PID... -tasklist /SVC /FI "SERVICES eq TermService" | find "PID" /V -echo. -if !errorlevel!==0 ( - goto DONE -) else ( - goto SVCSTART -) - -:SVCSTART -echo [*] TermService is stopped. Starting it... -sc config TermService start= auto | find "1060" > nul -if !errorlevel!==0 ( - echo [-] TermService is not installed. You need to install it manually. - goto END -) else ( - net start TermService - goto DONE -) - -:DONE -echo [+] Installation complete! -echo Now reboot or restart service. -echo. -echo To reboot computer type: -echo shutdown /r -echo. -echo To restart TermService type: -echo taskkill /f /pid 1234 ^(replace 1234 with real PID which is shown above^) -echo net start TermService -echo. -echo If second method is used, and there are another services sharing svchost.exe, -echo you must start it too: -echo net start Service1 -echo net start Service2 -echo etc. -goto END - -:END diff --git a/res/rdpwrap-ini-kb.txt b/res/rdpwrap-ini-kb.txt deleted file mode 100644 index a258ab4..0000000 --- a/res/rdpwrap-ini-kb.txt +++ /dev/null @@ -1,6289 +0,0 @@ -[Main] -; Last updated date -Updated=2018-10-10 -; Address to log file (RDP Wrapper will write it, if exists) -LogFile=\rdpwrap.txt -; Hook SLPolicy API on Windows NT 6.0 -SLPolicyHookNT60=1 -; Hook SLPolicy API on Windows NT 6.1 -SLPolicyHookNT61=1 - -[SLPolicy] -; Allow Remote Connections -TerminalServices-RemoteConnectionManager-AllowRemoteConnections=1 -; Allow Multiple Sessions -TerminalServices-RemoteConnectionManager-AllowMultipleSessions=1 -; Allow Multiple Sessions (Application Server Mode) -TerminalServices-RemoteConnectionManager-AllowAppServerMode=1 -; Allow Multiple Monitors -TerminalServices-RemoteConnectionManager-AllowMultimon=1 -; Max User Sessions (0 = unlimited) -TerminalServices-RemoteConnectionManager-MaxUserSessions=0 -; Max Debug Sessions (Windows 8, 0 = unlimited) -TerminalServices-RemoteConnectionManager-ce0ad219-4670-4988-98fb-89b14c2f072b-MaxSessions=0 -; Max Sessions -; 0 - logon not possible even from console -; 1 - only one active user (console or remote) -; 2 - allow concurrent sessions -TerminalServices-RemoteConnectionManager-45344fe7-00e6-4ac6-9f01-d01fd4ffadfb-MaxSessions=2 -; Allow Advanced Compression with RDP 7 Protocol -TerminalServices-RDP-7-Advanced-Compression-Allowed=1 -; IsTerminalTypeLocalOnly = 0 -TerminalServices-RemoteConnectionManager-45344fe7-00e6-4ac6-9f01-d01fd4ffadfb-LocalOnly=0 -; Max Sessions (hard limit) -TerminalServices-RemoteConnectionManager-8dc86f1d-9969-4379-91c1-06fe1dc60575-MaxSessions=1000 -; Allow EasyPrint -TerminalServices-DeviceRedirection-Licenses-TSEasyPrintAllowed=1 -; Allow PnP Redirection -TerminalServices-DeviceRedirection-Licenses-PnpRedirectionAllowed=1 -; Allow Media Foundation plugins -TerminalServices-DeviceRedirection-Licenses-TSMFPluginAllowed=1 -; Allow DWM Remoting -TerminalServices-RemoteConnectionManager-UiEffects-DWMRemotingAllowed=1 - -[PatchCodes] -nop=90 -Zero=00 -jmpshort=EB -nopjmp=90E9 -CDefPolicy_Query_edx_ecx=BA000100008991200300005E90 -CDefPolicy_Query_eax_rcx_jmp=B80001000089813806000090EB -CDefPolicy_Query_eax_esi=B80001000089862003000090 -CDefPolicy_Query_eax_rdi=B80001000089873806000090 -CDefPolicy_Query_eax_ecx=B80001000089812003000090 -CDefPolicy_Query_eax_ecx_jmp=B800010000898120030000EB0E -CDefPolicy_Query_eax_rcx=B80001000089813806000090 -CDefPolicy_Query_edi_rcx=BF0001000089B938060000909090 - -[6.0.6000.16386] -; HOW TO search CSessionArbitrationHelper::IsSingleSessionPerUserEnabled function in IDA Pro: -; 1. Search text: CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; 2. All xrefs will point to this function (in x64 version xref points to subroutine, so you need to go one level up) -; 3. Go to first graph block and find memset, VersionInformation, call GetVersionExW, and so on - -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F320000 -; .text:6F3360B9 lea eax, [ebp+VersionInformation] -; .text:6F3360BF inc ebx <- nop -; .text:6F3360C0 push eax ; lpVersionInformation -; .text:6F3360C1 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F3360CB mov [esi], ebx -; .text:6F3360CD call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=160BF -SingleUserCode.x86=nop -; Imagebase: 7FF756E0000 -; .text:000007FF75745E38 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75745E3D mov ebx, 1 <- 0 -; .text:000007FF75745E42 mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75745E4A mov [rdi], ebx -; .text:000007FF75745E4C call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=65E3E -SingleUserCode.x64=Zero -; HOW TO search CDefPolicy::Query function in IDA Pro: -; 1. Search text: CDefPolicy::Query -; 2. All xrefs will point to this function (in x64 version xref sometimes points to subroutine, so you need to go one level up) -; 3. Go to first graph block and find cmp/jz instructions on the bottom of block - -; Patch CDefPolicy::Query -; Original -; .text:6F335CD8 cmp edx, [ecx+320h] -; .text:6F335CDE pop esi -; .text:6F335CDF jz loc_6F3426F1 -; Changed -; .text:6F335CD8 mov edx, 100h -; .text:6F335CDD mov [ecx+320h], edx -; .text:6F335CE3 pop esi -; .text:6F335CE4 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=15CD8 -DefPolicyCode.x86=CDefPolicy_Query_edx_ecx -; Original -; .text:000007FF7573C88F mov eax, [rcx+638h] -; .text:000007FF7573C895 cmp [rcx+63Ch], eax -; .text:000007FF7573C89B jnz short loc_7FF7573C8B3 -; Changed -; .text:000007FF7573C88F mov eax, 100h -; .text:000007FF7573C894 mov [rcx+638h], eax -; .text:000007FF7573C89A nop -; .text:000007FF7573C89B jmp short loc_7FF7573C8B3 -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=5C88F -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx_jmp - -[6.0.6001.18000] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6E800000 -; .text:6E8185DE lea eax, [ebp+VersionInformation] -; .text:6E8185E4 inc ebx <- nop -; .text:6E8185E5 push eax ; lpVersionInformation -; .text:6E8185E6 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6E8185F0 mov [esi], ebx -; .text:6E8185F2 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=185E4 -SingleUserCode.x86=nop -; Imagebase: 7FF76220000 -; .text:000007FF76290DB4 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF76290DB9 mov ebx, 1 <- 0 -; .text:000007FF76290DBE mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF76290DC6 mov [rdi], ebx -; .text:000007FF76290DC8 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=70DBA -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6E817FD8 cmp edx, [ecx+320h] -; .text:6E817FDE pop esi -; .text:6E817FDF jz loc_6E826F16 -; Changed -; .text:6E817FD8 mov edx, 100h -; .text:6E817FDD mov [ecx+320h], edx -; .text:6E817FE3 pop esi -; .text:6E817FE4 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=17FD8 -DefPolicyCode.x86=CDefPolicy_Query_edx_ecx -; Original -; .text:000007FF76285BD7 mov eax, [rcx+638h] -; .text:000007FF76285BDD cmp [rcx+63Ch], eax -; .text:000007FF76285BE3 jnz short loc_7FF76285BFB -; Changed -; .text:000007FF76285BD7 mov eax, 100h -; .text:000007FF76285BDC mov [rcx+638h], eax -; .text:000007FF76285BE2 nop -; .text:000007FF76285BE3 jmp short loc_7FF76285BFB -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=65BD7 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx_jmp - -[6.0.6002.18005] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F580000 -; .text:6F597FA2 lea eax, [ebp+VersionInformation] -; .text:6F597FA8 inc ebx <- nop -; .text:6F597FA9 push eax ; lpVersionInformation -; .text:6F597FAA mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F597FB4 mov [esi], ebx -; .text:6F597FB6 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=17FA8 -SingleUserCode.x86=nop -; Imagebase: 7FF766C0000 -; .text:000007FF76730FF0 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF76730FF5 mov ebx, 1 <- 0 -; .text:000007FF76730FFA mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF76731002 mov [rdi], ebx -; .text:000007FF76731004 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=70FF6 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F5979C0 cmp edx, [ecx+320h] -; .text:6F5979C6 pop esi -; .text:6F5979C7 jz loc_6F5A6F26 -; Changed -; .text:6F5979C0 mov edx, 100h -; .text:6F5979C5 mov [ecx+320h], edx -; .text:6F5979CB pop esi -; .text:6F5979CC nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=179C0 -DefPolicyCode.x86=CDefPolicy_Query_edx_ecx -; Original -; .text:000007FF76725E83 mov eax, [rcx+638h] -; .text:000007FF76725E89 cmp [rcx+63Ch], eax -; .text:000007FF76725E8F jz short loc_7FF76725EA7 -; Changed -; .text:000007FF76725E83 mov eax, 100h -; .text:000007FF76725E88 mov [rcx+638h], eax -; .text:000007FF76725E8E nop -; .text:000007FF76725E8F jmp short loc_7FF76725EA7 -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=65E83 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx_jmp - -[6.0.6002.19214] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F580000 -; .text:6F597FBE lea eax, [ebp+VersionInformation] -; .text:6F597FC4 inc ebx <- nop -; .text:6F597FC5 push eax ; lpVersionInformation -; .text:6F597FC6 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F597FD0 mov [esi], ebx -; .text:6F597FD2 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=17FC4 -SingleUserCode.x86=nop -; Imagebase: 7FF75AC0000 -; .text:000007FF75B312A4 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75B312A9 mov ebx, 1 <- 0 -; .text:000007FF75B312AE mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75B312B6 mov [rdi], ebx -; .text:000007FF75B312B8 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=712AA -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F5979B8 cmp edx, [ecx+320h] -; .text:6F5979BE pop esi -; .text:6F5979BF jz loc_6F5A6F3E -; Changed -; .text:6F5979B8 mov edx, 100h -; .text:6F5979BD mov [ecx+320h], edx -; .text:6F5979C3 pop esi -; .text:6F5979C4 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=179B8 -DefPolicyCode.x86=CDefPolicy_Query_edx_ecx -; Original -; .text:000007FF75B25FF7 mov eax, [rcx+638h] -; .text:000007FF75B25FFD cmp [rcx+63Ch], eax -; .text:000007FF75B26003 jnz short loc_7FF75B2601B -; Changed -; .text:000007FF75B25FF7 mov eax, 100h -; .text:000007FF75B25FFC mov [rcx+638h], eax -; .text:000007FF75B26002 nop -; .text:000007FF75B26003 jmp short loc_7FF75B2601B -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=65FF7 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx_jmp - -[6.0.6002.23521] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F580000 -; .text:6F597FAE lea eax, [ebp+VersionInformation] -; .text:6F597FB4 inc ebx <- nop -; .text:6F597FB5 push eax ; lpVersionInformation -; .text:6F597FB6 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F597FC0 mov [esi], ebx -; .text:6F597FC2 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=17FB4 -SingleUserCode.x86=nop -; Imagebase: 7FF75AC0000 -; .text:000007FF75B31EA4 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75B31EA9 mov ebx, 1 <- 0 -; .text:000007FF75B31EAE mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75B31EB6 mov [rdi], ebx -; .text:000007FF75B31EB8 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=71EAA -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F5979CC cmp edx, [ecx+320h] -; .text:6F5979D2 pop esi -; .text:6F5979D3 jz loc_6F5A6F2E -; Changed -; .text:6F5979CC mov edx, 100h -; .text:6F5979D1 mov [ecx+320h], edx -; .text:6F5979D7 pop esi -; .text:6F5979D8 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=179CC -DefPolicyCode.x86=CDefPolicy_Query_edx_ecx -; Original -; .text:000007FF75B269CB mov eax, [rcx+638h] -; .text:000007FF75B269D1 cmp [rcx+63Ch], eax -; .text:000007FF75B269D7 jnz short loc_7FF75B269EF -; Changed -; .text:000007FF75B269CB mov eax, 100h -; .text:000007FF75B269D0 mov [rcx+638h], eax -; .text:000007FF75B269D6 nop -; .text:000007FF75B269D7 jmp short loc_7FF75B269EF -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=669CB -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx_jmp - -[6.1.7600.16385] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F2E0000 -; .text:6F2F9E1F lea eax, [ebp+VersionInformation] -; .text:6F2F9E25 inc ebx <- nop -; .text:6F2F9E26 push eax ; lpVersionInformation -; .text:6F2F9E27 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F2F9E31 mov [esi], ebx -; .text:6F2F9E33 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=19E25 -SingleUserCode.x86=nop -; Imagebase: 7FF75A80000 -; .text:000007FF75A97D90 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75A97D95 mov ebx, 1 <- 0 -; .text:000007FF75A97D9A mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75A97DA2 mov [rdi], ebx -; .text:000007FF75A97DA4 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=17D96 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F2F96F3 cmp eax, [esi+320h] -; .text:6F2F96F9 jz loc_6F30E256 -; Changed -; .text:6F2F96F3 mov eax, 100h -; .text:6F2F96F8 mov [esi+320h], eax -; .text:6F2F96FE nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=196F3 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000007FF75A97AD2 cmp [rdi+63Ch], eax -; .text:000007FF75A97AD8 jz loc_7FF75AA4978 -; Changed -; .text:000007FF75A97AD2 mov eax, 100h -; .text:000007FF75A97AD7 mov [rdi+638h], eax -; .text:000007FF75A97ADD nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17AD2 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7600.20890] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=19E2D -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=17DF2 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=196FB -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17B0E -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7600.21316] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=19E2D -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=17E3E -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=196FB -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17B5E -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.17514] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F2E0000 -; .text:6F2FA497 lea eax, [ebp+VersionInformation] -; .text:6F2FA49D inc ebx <- nop -; .text:6F2FA49E push eax ; lpVersionInformation -; .text:6F2FA49F mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F2FA4A9 mov [esi], ebx -; .text:6F2FA4AB call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A49D -SingleUserCode.x86=nop -; Imagebase: 7FF75A80000 -; .text:000007FF75A980DC lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75A980E1 mov ebx, 1 <- 0 -; .text:000007FF75A980E6 mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75A980EE mov [rdi], ebx -; .text:000007FF75A980F0 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=180E2 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F2F9D53 cmp eax, [esi+320h] -; .text:6F2F9D59 jz loc_6F30B25E -; Changed -; .text:6F2F9D53 mov eax, 100h -; .text:6F2F9D58 mov [esi+320h], eax -; .text:6F2F9D5E nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19D53 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000007FF75A97D8A cmp [rdi+63Ch], eax -; .text:000007FF75A97D90 jz loc_7FF75AA40F4 -; Changed -; .text:000007FF75A97D8A mov eax, 100h -; .text:000007FF75A97D8F mov [rdi+638h], eax -; .text:000007FF75A97D95 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17D8A -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.18540] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F2E0000 -; .text:6F2FA4DF lea eax, [ebp+VersionInformation] -; .text:6F2FA4E5 inc ebx <- nop -; .text:6F2FA4E6 push eax ; lpVersionInformation -; .text:6F2FA4E7 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F2FA4F1 mov [esi], ebx -; .text:6F2FA4F3 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A4E5 -SingleUserCode.x86=nop -; Imagebase: 7FF75A80000 -; .text:000007FF75A98000 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75A98005 mov ebx, 1 <- 0 -; .text:000007FF75A9800A mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75A98012 mov [rdi], ebx -; .text:000007FF75A98014 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=18006 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F2F9D9F cmp eax, [esi+320h] -; .text:6F2F9DA5 jz loc_6F30B2AE -; Changed -; .text:6F2F9D9F mov eax, 100h -; .text:6F2F9DA4 mov [esi+320h], eax -; .text:6F2F9DAA nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19D9F -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000007FF75A97C82 cmp [rdi+63Ch], eax -; .text:000007FF75A97C88 jz loc_7FF75AA3FBD -; Changed -; .text:000007FF75A97C82 mov eax, 100h -; .text:000007FF75A97C87 mov [rdi+638h], eax -; .text:000007FF75A97C8D nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17C82 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.22750] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F2E0000 -; .text:6F2FA64F lea eax, [ebp+VersionInformation] -; .text:6F2FA655 inc ebx <- nop -; .text:6F2FA656 push eax ; lpVersionInformation -; .text:6F2FA657 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F2FA661 mov [esi], ebx -; .text:6F2FA663 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A655 -SingleUserCode.x86=nop -; Imagebase: 7FF75A80000 -; .text:000007FF75A97E88 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75A97E8D mov ebx, 1 <- 0 -; .text:000007FF75A97E92 mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75A97E9A mov [rdi], ebx -; .text:000007FF75A97E9C call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=17E8E -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F2F9E21 cmp eax, [esi+320h] -; .text:6F2F9E27 jz loc_6F30B6CE -; Changed -; .text:6F2F9E21 mov eax, 100h -; .text:6F2F9E26 mov [esi+320h], eax -; .text:6F2F9E2C nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19E21 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000007FF75A97C92 cmp [rdi+63Ch], eax -; .text:000007FF75A97C98 jz loc_7FF75AA40A2 -; Changed -; .text:000007FF75A97C92 mov eax, 100h -; .text:000007FF75A97C97 mov [rdi+638h], eax -; .text:000007FF75A97C9D nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17C92 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.18637] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F2E0000 -; .text:6F2FA4D7 lea eax, [ebp+VersionInformation] -; .text:6F2FA4DD inc ebx <- nop -; .text:6F2FA4DE push eax ; lpVersionInformation -; .text:6F2FA4DF mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F2FA4E9 mov [esi], ebx -; .text:6F2FA4EB call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A4DD -SingleUserCode.x86=nop -; Imagebase: 7FF75A80000 -; .text:000007FF75A980F4 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75A980F9 mov ebx, 1 <- 0 -; .text:000007FF75A980FE mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75A98106 mov [rdi], ebx -; .text:000007FF75A98108 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=180FA -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F2F9DBB cmp eax, [esi+320h] -; .text:6F2F9DC1 jz loc_6F30B2A6 -; Changed -; .text:6F2F9DBB mov eax, 100h -; .text:6F2F9DC0 mov [esi+320h], eax -; .text:6F2F9DC6 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19DBB -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000007FF75A97DC6 cmp [rdi+63Ch], eax -; .text:000007FF75A97DCC jz loc_7FF75AA40BD -; Changed -; .text:000007FF75A97DC6 mov eax, 100h -; .text:000007FF75A97DCB mov [rdi+638h], eax -; .text:000007FF75A97DD1 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17DC6 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.21650] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A49D -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=180BE -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19D53 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17D5A -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.21866] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A49D -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=180BE -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19D53 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17D5A -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.22104] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A49D -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=180C6 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19D53 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17D5E -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.22843] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; Imagebase: 6F2E0000 -; .text:6F2FA64F lea eax, [ebp+VersionInformation] -; .text:6F2FA655 inc ebx <- nop -; .text:6F2FA656 push eax ; lpVersionInformation -; .text:6F2FA657 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:6F2FA661 mov [esi], ebx -; .text:6F2FA663 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A655 -SingleUserCode.x86=nop -; Imagebase: 7FF75A80000 -; .text:000007FF75A97F90 lea rcx, [rsp+198h+VersionInformation] ; lpVersionInformation -; .text:000007FF75A97F95 mov ebx, 1 <- 0 -; .text:000007FF75A97F9A mov [rsp+198h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000007FF75A97FA2 mov [rdi], ebx -; .text:000007FF75A97FA4 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=17F96 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:6F2F9E25 cmp eax, [esi+320h] -; .text:6F2F9E2B jz loc_6F30B6D6 -; Changed -; .text:6F2F9E25 mov eax, 100h -; .text:6F2F9E2A mov [esi+320h], eax -; .text:6F2F9E30 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19E25 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000007FF75A97D6E cmp [rdi+63Ch], eax -; .text:000007FF75A97D74 jz loc_7FF75AA4182 -; Changed -; .text:000007FF75A97D6E mov eax, 100h -; .text:000007FF75A97D73 mov [rdi+638h], eax -; .text:000007FF75A97D79 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17D6E -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.23403] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A65D -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=17F62 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19E29 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17CE2 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.1.7601.24234] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=1A675 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=17F56 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=19E41 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17D2E -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi - -[6.2.8102.0] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:1000F7E5 lea eax, [esp+150h+VersionInformation] -; .text:1000F7E9 inc esi <- nop -; .text:1000F7EA push eax ; lpVersionInformation -; .text:1000F7EB mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:1000F7F3 mov [edi], esi -; .text:1000F7F5 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=F7E9 -SingleUserCode.x86=nop -; .text:000000018000D83A lea rcx, [rsp+180h+VersionInformation] ; lpVersionInformation -; .text:000000018000D83F mov ebx, 1 <- 0 -; .text:000000018000D844 mov [rsp+180h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000000018000D84C mov [rdi], ebx -; .text:000000018000D84E call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=D840 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1000E47C cmp eax, [esi+320h] -; .text:1000E482 jz loc_1002D775 -; Changed -; .text:1000E47C mov eax, 100h -; .text:1000E481 mov [esi+320h], eax -; .text:1000E487 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=E47C -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000000018000D3E6 cmp [rdi+63Ch], eax -; .text:000000018000D3EC jz loc_180027792 -; Changed -; .text:000000018000D3E6 mov eax, 100h -; .text:000000018000D3EB mov [rdi+638h], eax -; .text:000000018000D3F1 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=D3E6 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi -; Hook SLGetWindowsInformationDWORDWrapper -SLPolicyInternal.x86=1 -SLPolicyOffset.x86=1B909 -SLPolicyFunc.x86=New_Win8SL -SLPolicyInternal.x64=1 -SLPolicyOffset.x64=1A484 -SLPolicyFunc.x64=New_Win8SL - -[6.2.8250.0] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:100159C5 lea eax, [esp+150h+VersionInformation] -; .text:100159C9 inc esi <- nop -; .text:100159CA push eax ; lpVersionInformation -; .text:100159CB mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:100159D3 mov [edi], esi -; .text:100159D5 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=159C9 -SingleUserCode.x86=nop -; .text:0000000180011E6E lea rcx, [rsp+180h+VersionInformation] ; lpVersionInformation -; .text:0000000180011E73 mov ebx, 1 <- 0 -; .text:0000000180011E78 mov [rsp+180h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180011E80 mov [rdi], ebx -; .text:0000000180011E82 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=11E74 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:10013520 cmp eax, [esi+320h] -; .text:10013526 jz loc_1002DB85 -; Changed -; .text:10013520 mov eax, 100h -; .text:10013525 mov [esi+320h], eax -; .text:1001352B nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=13520 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000000018001187A cmp [rdi+63Ch], eax -; .text:0000000180011880 jz loc_1800273A2 -; Changed -; .text:000000018001187A mov eax, 100h -; .text:000000018001187F mov [rdi+638h], eax -; .text:0000000180011885 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1187A -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi -; Hook SLGetWindowsInformationDWORDWrapper -SLPolicyInternal.x86=1 -SLPolicyOffset.x86=1A0A9 -SLPolicyFunc.x86=New_Win8SL_CP -SLPolicyInternal.x64=1 -SLPolicyOffset.x64=18FAC -SLPolicyFunc.x64=New_Win8SL - -[6.2.8400.0] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:1001547E lea eax, [esp+150h+VersionInformation] -; .text:10015482 inc esi <- nop -; .text:10015483 push eax ; lpVersionInformation -; .text:10015484 mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:1001548C mov [edi], esi -; .text:1001548E call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=15482 -SingleUserCode.x86=nop -; .text:000000018002081E lea rcx, [rsp+180h+VersionInformation] ; lpVersionInformation -; .text:0000000180020823 mov ebx, 1 <- 0 -; .text:0000000180020828 mov [rsp+180h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180020830 mov [rdi], ebx -; .text:0000000180020832 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=20824 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:10013E48 cmp eax, [esi+320h] -; .text:10013E4E jz loc_1002E079 -; Changed -; .text:10013E48 mov eax, 100h -; .text:10013E4D mov [esi+320h], eax -; .text:10013E53 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=13E48 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000000018001F102 cmp [rdi+63Ch], eax -; .text:000000018001F108 jz loc_18003A02E -; Changed -; .text:000000018001F102 mov eax, 100h -; .text:000000018001F107 mov [rdi+638h], eax -; .text:000000018001F10D nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1F102 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi -; Hook SLGetWindowsInformationDWORDWrapper -SLPolicyInternal.x86=1 -SLPolicyOffset.x86=19629 -SLPolicyFunc.x86=New_Win8SL -SLPolicyInternal.x64=1 -SLPolicyOffset.x64=2492C -SLPolicyFunc.x64=New_Win8SL - -[6.2.9200.16384] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:1001554E lea eax, [esp+150h+VersionInformation] -; .text:10015552 inc esi <- nop -; .text:10015553 push eax ; lpVersionInformation -; .text:10015554 mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:1001555C mov [edi], esi -; .text:1001555E call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=15552 -SingleUserCode.x86=nop -; .text:000000018002BAA2 lea rcx, [rsp+180h+VersionInformation] ; lpVersionInformation -; .text:000000018002BAA7 mov ebx, 1 <- 0 -; .text:000000018002BAAC mov [rsp+180h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000000018002BAB4 mov [rdi], ebx -; .text:000000018002BAB6 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=2BAA8 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:10013F08 cmp eax, [esi+320h] -; .text:10013F0E jz loc_1002E161 -; Changed -; .text:10013F08 mov eax, 100h -; .text:10013F0D mov [esi+320h], eax -; .text:10013F13 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=13F08 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000000018002A31A cmp [rdi+63Ch], eax -; .text:000000018002A320 jz loc_18003A0F9 -; Changed -; .text:000000018002A31A mov eax, 100h -; .text:000000018002A31F mov [rdi+638h], eax -; .text:000000018002A325 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=2A31A -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi -; Hook SLGetWindowsInformationDWORDWrapper -SLPolicyInternal.x86=1 -SLPolicyOffset.x86=19559 -SLPolicyFunc.x86=New_Win8SL -SLPolicyInternal.x64=1 -SLPolicyOffset.x64=21FA8 -SLPolicyFunc.x64=New_Win8SL - -[6.2.9200.17048] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:1002058E lea eax, [esp+150h+VersionInformation] -; .text:10020592 inc esi <- nop -; .text:10020593 push eax ; lpVersionInformation -; .text:10020594 mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:1002059C mov [edi], esi -; .text:1002059E call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=20592 -SingleUserCode.x86=nop -; .text:0000000180020942 lea rcx, [rsp+180h+VersionInformation] ; lpVersionInformation -; .text:0000000180020947 mov ebx, 1 <- 0 -; .text:000000018002094C mov [rsp+180h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180020954 mov [rdi], ebx -; .text:0000000180020956 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=20948 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1001F408 cmp eax, [esi+320h] -; .text:1001F40E jz loc_1002E201 -; Changed -; .text:1001F408 mov eax, 100h -; .text:1001F40D mov [esi+320h], eax -; .text:1001F413 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=1F408 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000000018001F206 cmp [rdi+63Ch], eax -; .text:000000018001F20C jz loc_18003A1B4 -; Changed -; .text:000000018001F206 mov eax, 100h -; .text:000000018001F20B mov [rdi+638h], eax -; .text:000000018001F211 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1F206 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi -; Hook SLGetWindowsInformationDWORDWrapper -SLPolicyInternal.x86=1 -SLPolicyOffset.x86=17059 -SLPolicyFunc.x86=New_Win8SL -SLPolicyInternal.x64=1 -SLPolicyOffset.x64=24570 -SLPolicyFunc.x64=New_Win8SL - -[6.2.9200.21166] -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10015576 lea eax, [esp+150h+VersionInformation] -; .text:1001557A inc esi <- nop -; .text:1001557B push eax ; lpVersionInformation -; .text:1001557C mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:10015584 mov [edi], esi -; .text:10015586 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=1557A -SingleUserCode.x86=nop -; .text:000000018002BAF2 lea rcx, [rsp+180h+VersionInformation] ; lpVersionInformation -; .text:000000018002BAF7 mov ebx, 1 <- 0 -; .text:000000018002BAFC mov [rsp+180h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000000018002BB04 mov [rdi], ebx -; .text:000000018002BB06 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=2BAF8 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:10013F30 cmp eax, [esi+320h] -; .text:10013F36 jz loc_1002E189 -; Changed -; .text:10013F30 mov eax, 100h -; .text:10013F35 mov [esi+320h], eax -; .text:10013F3B nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=13F30 -DefPolicyCode.x86=CDefPolicy_Query_eax_esi -; Original -; .text:000000018002A3B6 cmp [rdi+63Ch], eax -; .text:000000018002A3BC jz loc_18003A174 -; Changed -; .text:000000018002A3B6 mov eax, 100h -; .text:000000018002A3BB mov [rdi+638h], eax -; .text:000000018002A3C1 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=2A3B6 -DefPolicyCode.x64=CDefPolicy_Query_eax_rdi -; Hook SLGetWindowsInformationDWORDWrapper -SLPolicyInternal.x86=1 -SLPolicyOffset.x86=19581 -SLPolicyFunc.x86=New_Win8SL -SLPolicyInternal.x64=1 -SLPolicyOffset.x64=21FD0 -SLPolicyFunc.x64=New_Win8SL - -[6.3.9431.0] -; HOW TO search CEnforcementCore::GetInstanceOfTSLicense function in IDA Pro: -; 1. Search text: CSLQuery::IsLicenseTypeLocalOnly -; 2. All xrefs will point to this function -; 3. Go to function beginning and check ; CODE XREF string, it will point to GetInstanceOfTSLicense function -; 4. Follow CODE XREF, switch to graph view, the next block below is to patch -; Another way: -; 1. Search text: CEnforcementCore::GetInstanceOfTSLicense FAILED - License type me -; 2. All xrefs will point to GetInstanceOfTSLicense -; 3. Follow xref, the previous block above is to patch - -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:1008A604 call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:1008A609 test eax, eax -; .text:1008A60B js short loc_1008A628 -; .text:1008A60D cmp [ebp+var_8], 0 -; .text:1008A611 jz short loc_1008A628 <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=8A611 -LocalOnlyCode.x86=jmpshort -; .text:000000018009F713 call ?IsLicenseTypeLocalOnly@CSLQuery@@SAJAEAU_GUID@@PEAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:000000018009F718 test eax, eax -; .text:000000018009F71A js short loc_18009F73B -; .text:000000018009F71C cmp [rsp+48h+arg_18], 0 -; .text:000000018009F721 jz short loc_18009F73B <- jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=9F721 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:100306A4 lea eax, [esp+150h+VersionInformation] -; .text:100306A8 inc ebx <- nop -; .text:100306A9 mov [edi], ebx -; .text:100306AB push eax ; lpVersionInformation -; .text:100306AC call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=306A8 -SingleUserCode.x86=nop -; .text:00000001800367F3 lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:00000001800367F8 mov ebx, 1 <- 0 -; .text:00000001800367FD mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180036805 mov [rdi], ebx -; .text:0000000180036807 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=367F9 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1002EA25 cmp eax, [ecx+320h] -; .text:1002EA2B jz loc_100348C1 -; Changed -; .text:1002EA25 mov eax, 100h -; .text:1002EA2A mov [ecx+320h], eax -; .text:1002EA30 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2EA25 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:00000001800350FD cmp [rcx+63Ch], eax -; .text:0000000180035103 jz loc_18004F6AE -; Changed -; .text:00000001800350FD mov eax, 100h -; .text:0000000180035102 mov [rcx+638h], eax -; .text:0000000180035108 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=350FD -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; HOW TO search CSLQuery::Initialize function in IDA Pro: -; 1. Search text: CSLQuery::Initialize - SLGetWindowsInformationDWORD failed -; 2. All xrefs will point to this function - -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=196B0 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2F9C0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.3.9600.16384] -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:100A271C call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:100A2721 test eax, eax -; .text:100A2723 js short loc_100A2740 -; .text:100A2725 cmp [ebp+var_8], 0 -; .text:100A2729 jz short loc_100A2740 <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A2729 -LocalOnlyCode.x86=jmpshort -; .text:000000018008181F cmp [rsp+48h+arg_18], 0 -; .text:0000000180081824 jz loc_180031DEF <- nop + jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=81824 -LocalOnlyCode.x64=nopjmp -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10018024 lea eax, [esp+150h+VersionInformation] -; .text:10018028 inc ebx <- nop -; .text:10018029 mov [edi], ebx -; .text:1001802B push eax ; lpVersionInformation -; .text:1001802C call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=18028 -SingleUserCode.x86=nop -; .text:000000018002023B lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:0000000180020240 mov ebx, 1 <- 0 -; .text:0000000180020245 mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:000000018002024D mov [rdi], ebx -; .text:000000018002024F call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=20241 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:10016115 cmp eax, [ecx+320h] -; .text:1001611B jz loc_10034DE1 -; Changed -; .text:10016115 mov eax, 100h -; .text:1001611A mov [ecx+320h], eax -; .text:10016120 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=16115 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:0000000180057829 cmp [rcx+63Ch], eax -; .text:000000018005782F jz loc_18005E850 -; Changed -; .text:0000000180057829 mov eax, 100h -; .text:000000018005782E mov [rcx+638h], eax -; .text:0000000180057834 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=57829 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=1CEB0 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=554C0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.3.9600.17095] -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:100A36C4 call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:100A36C9 test eax, eax -; .text:100A36CB js short loc_100A36E8 -; .text:100A36CD cmp [ebp+var_8], 0 -; .text:100A36D1 jz short loc_100A36E8 <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A36D1 -LocalOnlyCode.x86=jmpshort -; .text:00000001800B914B call ?IsLicenseTypeLocalOnly@CSLQuery@@SAJAEAU_GUID@@PEAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:00000001800B9150 test eax, eax -; .text:00000001800B9152 js short loc_1800B9173 -; .text:00000001800B9154 cmp [rsp+48h+arg_18], 0 -; .text:00000001800B9159 jz short loc_1800B9173 <- jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=B9159 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10036BA5 lea eax, [esp+150h+VersionInformation] -; .text:10036BA9 inc ebx <- nop -; .text:10036BAA mov [edi], ebx -; .text:10036BAC push eax ; lpVersionInformation -; .text:10036BAD call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=36BA9 -SingleUserCode.x86=nop -; .text:0000000180021823 lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:0000000180021828 mov ebx, 1 <- 0 -; .text:000000018002182D mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180021835 mov [rdi], ebx -; .text:0000000180021837 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=21829 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:10037529 cmp eax, [ecx+320h] -; .text:1003752F jz loc_10043662 -; Changed -; .text:10037529 mov eax, 100h -; .text:1003752E mov [ecx+320h], eax -; .text:10037534 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=37529 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:000000018001F6A1 cmp [rcx+63Ch], eax -; .text:000000018001F6A7 jz loc_18007284B -; Changed -; .text:000000018001F6A1 mov eax, 100h -; .text:000000018001F6A6 mov [rcx+638h], eax -; .text:000000018001F6AC nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1F6A1 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=117F1 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=3B110 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.3.9600.17415] -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:100B33EB call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:100B33F0 test eax, eax -; .text:100B33F2 js short loc_100B340F -; .text:100B33F4 cmp [ebp+var_C], 0 -; .text:100B33F8 jz short loc_100B340F <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=B33F8 -LocalOnlyCode.x86=jmpshort -; .text:000000018008B2D4 cmp [rsp+58h+arg_18], 0 -; .text:000000018008B2D9 jz loc_180025C39 <- nop + jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8B2D9 -LocalOnlyCode.x64=nopjmp -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10037111 lea eax, [esp+150h+VersionInformation] -; .text:10037115 inc ebx <- nop -; .text:10037116 mov [edi], ebx -; .text:10037118 push eax ; lpVersionInformation -; .text:10037119 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=37115 -SingleUserCode.x86=nop -; .text:0000000180033CE3 lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:0000000180033CE8 mov ebx, 1 <- 0 -; .text:0000000180033CED mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180033CF5 mov [rdi], ebx -; .text:0000000180033CF7 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=33CE9 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1003CFF9 cmp eax, [ecx+320h] -; .text:1003CFFF jz loc_1004A52F -; Changed -; .text:1003CFF9 mov eax, 100h -; .text:1003CFFE mov [ecx+320h], eax -; .text:1003D004 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3CFF9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:0000000180045825 cmp [rcx+63Ch], eax -; .text:000000018004582B jz loc_180067704 -; Changed -; .text:0000000180045825 mov eax, 100h -; .text:000000018004582A mov [rcx+638h], eax -; .text:0000000180045830 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=45825 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=18478 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=5DBC0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.3.9600.18692] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=B3458 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8B2E9 -LocalOnlyCode.x64=nopjmp -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=37105 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=37039 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3CFE9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=45835 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=18488 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=5DBD0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.3.9600.18708] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=B35D8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8B376 -LocalOnlyCode.x64=nopjmp -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=370F5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=36FE9 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3CFD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=457D5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=18308 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=5DB70 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.3.9600.18928] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=B39D8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8B25D -LocalOnlyCode.x64=nopjmp -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=37D25 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=36C09 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3D6F9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=45495 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=18328 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=5D830 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.3.9600.19093] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=B3958 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8AE4E -LocalOnlyCode.x64=nopjmp -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3F045 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=36BC9 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3D899 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=45305 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=18288 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=5D660 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.4.9841.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:1009569B call sub_100B7EE5 -; .text:100956A0 test eax, eax -; .text:100956A2 js short loc_100956BF -; .text:100956A4 cmp [ebp+var_C], 0 -; .text:100956A8 jz short loc_100956BF <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=956A8 -LocalOnlyCode.x86=jmpshort -; .text:0000000180081133 call sub_1800A9048 -; .text:0000000180081138 test eax, eax -; .text:000000018008113A js short loc_18008115B -; .text:000000018008113C cmp [rsp+58h+arg_18], 0 -; .text:0000000180081141 jz short loc_18008115B <- jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=81141 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10030121 lea eax, [esp+150h+VersionInformation] -; .text:10030125 inc ebx <- nop -; .text:10030126 mov [edi], ebx -; .text:10030128 push eax ; lpVersionInformation -; .text:10030129 call ds:GetVersionExW -SingleUserPatch.x86=1 -SingleUserOffset.x86=30125 -SingleUserCode.x86=nop -; .text:0000000180012153 lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:0000000180012158 mov ebx, 1 <- 0 -; .text:000000018001215D mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180012165 mov [rdi], ebx -; .text:0000000180012167 call cs:GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=12159 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1003B989 cmp eax, [ecx+320h] -; .text:1003B98F jz loc_1005E809 -; Changed -; .text:1003B989 mov eax, 100h -; .text:1003B98E mov [ecx+320h], eax -; .text:1003B994 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3B989 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:000000018000C125 cmp [rcx+63Ch], eax -; .text:000000018000C12B jz sub_18003BABC -; Changed -; .text:000000018000C125 mov eax, 100h -; .text:000000018000C12A mov [rcx+638h], eax -; .text:000000018000C130 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=C125 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46A68 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=1EA50 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.4.9860.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:100962BB call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:100962C0 test eax, eax -; .text:100962C2 js short loc_100962DF -; .text:100962C4 cmp [ebp+var_C], 0 -; .text:100962C8 jz short loc_100962DF <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=962C8 -LocalOnlyCode.x86=jmpshort -; .text:0000000180081083 call ?IsLicenseTypeLocalOnly@CSLQuery@@SAJAEAU_GUID@@PEAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:0000000180081088 test eax, eax -; .text:000000018008108A js short loc_1800810AB -; .text:000000018008108C cmp [rsp+58h+arg_18], 0 -; .text:0000000180081091 jz short loc_1800810AB <- jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=81091 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10030841 lea eax, [esp+150h+VersionInformation] -; .text:10030845 inc ebx <- nop -; .text:10030846 mov [edi], ebx -; .text:10030848 push eax ; lpVersionInformation -; .text:10030849 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=30845 -SingleUserCode.x86=nop -; .text:0000000180011AA3 lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:0000000180011AA8 mov ebx, 1 <- 0 -; .text:0000000180011AAD mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180011AB5 mov [rdi], ebx -; .text:0000000180011AB7 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=11AA9 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1003BEC9 cmp eax, [ecx+320h] -; .text:1003BECF jz loc_1005EE1A -; Changed -; .text:1003BEC9 mov eax, 100h -; .text:1003BECE mov [ecx+320h], eax -; .text:1003BED4 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3BEC9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:000000018000B9F5 cmp [rcx+63Ch], eax -; .text:000000018000B9FB jz sub_18003B9C8 -; Changed -; .text:000000018000B9F5 mov eax, 100h -; .text:000000018000B9FA mov [rcx+638h], eax -; .text:000000018000BA00 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=B9F5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46F18 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=1EB00 -SLInitFunc.x64=New_CSLQuery_Initialize - -[6.4.9879.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:100A9CBB call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:100A9CC0 test eax, eax -; .text:100A9CC2 js short loc_100A9CDF -; .text:100A9CC4 cmp [ebp+var_C], 0 -; .text:100A9CC8 jz short loc_100A9CDF <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9CC8 -LocalOnlyCode.x86=jmpshort -; .text:0000000180095603 call ?IsLicenseTypeLocalOnly@CSLQuery@@SAJAEAU_GUID@@PEAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:0000000180095608 test eax, eax -; .text:000000018009560A js short loc_18009562B -; .text:000000018009560C cmp [rsp+58h+arg_18], 0 -; .text:0000000180095611 jz short loc_18009562B <- jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=95611 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10030C51 lea eax, [esp+150h+VersionInformation] -; .text:10030C55 inc ebx <- nop -; .text:10030C56 mov [edi], ebx -; .text:10030C58 push eax ; lpVersionInformation -; .text:10030C59 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=30C55 -SingleUserCode.x86=nop -; .text:0000000180016A2E call memset_0 -; .text:0000000180016A33 mov ebx, 1 <- 0 -; .text:0000000180016A38 mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180016A40 lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:0000000180016A45 mov [rdi], ebx -; .text:0000000180016A47 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=16A34 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1002DAB9 cmp eax, [ecx+320h] -; .text:1002DABF jz loc_1006C38A -; Changed -; .text:1002DAB9 mov eax, 100h -; .text:1002DABE mov [ecx+320h], eax -; .text:1002DAC4 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2DAB9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:000000018001BDC5 cmp [rcx+63Ch], eax -; .text:000000018001BDCB jz sub_180045540 -; Changed -; .text:000000018001BDC5 mov eax, 100h -; .text:000000018001BDCA mov [rcx+638h], eax -; .text:000000018001BDD0 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1BDC5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=41132 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=24750 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.9926.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8C28 -LocalOnlyCode.x86=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=31725 -SingleUserCode.x86=nop -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3CF99 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=3F140 -SLInitFunc.x86=New_CSLQuery_Initialize -; x64 contributed by v-yadli -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x64=1 -;;;OFFSET = 0x61 -;;;BASE = 0x95F90 -LocalOnlyOffset.x64=95FF1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x64=1 -;;;OFFSET = 0x43 -;;;BASE = 0x12F90 -;;;;instruction = 0xBB 0x01 0x00 0x00 0x00 -;;; ^^^ +1 offset -SingleUserOffset.x64=12A34 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x64=1 -;;; -;;;BASE = 0xBDF0 -;;;OFFSET = 0x15 -DefPolicyOffset.x64=BE05 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x64=1 -SLInitOffset.x64=24EC0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.10041.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -; .text:100A9D7B call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:100A9D80 test eax, eax -; .text:100A9D82 js short loc_100A9D9F -; .text:100A9D84 cmp [ebp+var_C], 0 -; .text:100A9D88 jz short loc_100A9D9F <- jmp -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9D88 -LocalOnlyCode.x86=jmpshort -; .text:0000000180097133 call ?IsLicenseTypeLocalOnly@CSLQuery@@SAJAEAU_GUID@@PEAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) -; .text:0000000180097138 test eax, eax -; .text:000000018009713A js short loc_18009715B -; .text:000000018009713C cmp [rsp+58h+arg_18], 0 -; .text:0000000180097141 jz short loc_18009715B <- jmp -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=97141 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -; .text:10032211 lea eax, [esp+150h+VersionInformation] -; .text:10032215 inc ebx <- nop -; .text:10032216 mov [edi], ebx -; .text:10032218 push eax ; lpVersionInformation -; .text:10032219 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x) -SingleUserPatch.x86=1 -SingleUserOffset.x86=32215 -SingleUserCode.x86=nop -; .text:0000000180015C5E call memset_0 -; .text:0000000180015C63 mov ebx, 1 <- 0 -; .text:0000000180015C68 mov [rsp+190h+VersionInformation.dwOSVersionInfoSize], 11Ch -; .text:0000000180015C70 lea rcx, [rsp+190h+VersionInformation] ; lpVersionInformation -; .text:0000000180015C75 mov [rdi], ebx -; .text:0000000180015C77 call cs:__imp_GetVersionExW -SingleUserPatch.x64=1 -SingleUserOffset.x64=15C64 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -; Original -; .text:1002DFC9 cmp eax, [ecx+320h] -; .text:1002DFCF jz loc_10056550 -; Changed -; .text:1002DFC9 mov eax, 100h -; .text:1002DFCE mov [ecx+320h], eax -; .text:1002DFD4 nop -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2DFC9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Original -; .text:000000018000B795 cmp [rcx+63Ch], eax -; .text:000000018000B79B jz sub_18003A79A -; Changed -; .text:000000018000B795 mov eax, 100h -; .text:000000018000B79A mov [rcx+638h], eax -; .text:000000018000B7A0 nop -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=B795 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46960 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22E40 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.10240.16384] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7D38 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=96901 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=32A95 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=18F74 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2F5B9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=22865 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46581 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=250F0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.10586.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7C18 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=96AA1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=353B5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=190D4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30B69 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=229A5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=469DE -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=25220 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.10586.589] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7BE8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=96A51 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=353B5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=190D4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30B69 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=229A5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=469DE -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=25220 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.11082.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7C98 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=96AB1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35405 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=190D4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30BB9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=229A5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46A3E -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=25220 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.11102.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5D58 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=95CD1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35A85 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=2A9C4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30159 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B5D5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=44FD2 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D160 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14251.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5D58 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=95CD1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35A85 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=2A9C4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30159 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B5D5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=44FD2 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D160 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14271.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A4CE8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=941E1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35915 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=263F4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF79 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1C185 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=47725 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CE50 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14279.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A4D28 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=94191 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35915 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=263F4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF79 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1C185 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=47725 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CE50 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14295.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A4D28 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D691 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35925 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=25514 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1BA35 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=47748 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C860 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14300.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F5F1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x64=1 -SingleUserOffset.x64=26B04 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1D125 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CC60 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14316.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E88 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F5F1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=32B55 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=26B04 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3C1C9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1D295 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46ABD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CC60 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14328.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E88 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F5F1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=32B55 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=26B04 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3C1C9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1D365 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46ABD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CC60 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14332.1001] -; contributed by maxpiva -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E98 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F601 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=357E5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=2AE44 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=316A9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1C025 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4755F -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CAD0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14342.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E98 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8EF31 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=357E5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=26774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=316A9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1CEF5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4755F -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CA20 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14352.1002] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A4478 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D911 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35465 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=24474 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30099 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1AC05 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=44792 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CDB0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14366.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9088 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FB01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34F65 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=21DE4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=316E9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1A855 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4793E -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CCE0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14367.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9088 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FB01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34F65 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=21DE4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=316E9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1A855 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4793E -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CCE0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14372.0] -; x64 contributed by kbmorris -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7698 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F931 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34635 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=295A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF69 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B295 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=460D2 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CC10 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14379.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7698 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F941 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34635 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=295A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF69 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B295 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=460D2 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CC10 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14383.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7698 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F941 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34635 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=295A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF69 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B295 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=460D2 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CC10 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14385.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7698 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F941 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34635 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=295A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF69 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B295 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=460D2 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CC10 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14388.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6038 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D781 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=359C5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=299A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF29 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1AFC5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45636 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C930 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14393.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6038 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D781 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=359C5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=299A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF29 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1AFC5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45636 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C930 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14393.1198] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6088 -LocalOnlyCode.x86=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=359C5 -SingleUserCode.x86=nop -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF29 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45636 -SLInitFunc.x86=New_CSLQuery_Initialize - -[10.0.14393.1737] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6198 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D861 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35AD5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=299A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30039 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1AFC5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45724 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C930 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14393.2457] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6248 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D811 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36CE5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=29CF4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31209 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B545 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45824 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C920 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14901.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6038 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D781 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=359C5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=299A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF29 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1AFC5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45636 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C930 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14905.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6038 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D781 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=359C5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=299A4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF29 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1AFC5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45636 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C930 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14915.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6D98 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E241 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35E35 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=29EB4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=30399 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B4A5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46092 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CE40 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14926.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A6D18 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E071 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35E55 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=29EB4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=303B9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1B4A5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=460A2 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=CE40 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14931.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A4908 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8B411 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35705 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=29264 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FF69 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1AD05 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=452FD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C7FC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14936.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A3F38 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8B9A1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35355 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=25174 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FCD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1BB55 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=44CFE -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=C62C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14942.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A3F38 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=9115B -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35355 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=199BD -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FCD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1064E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=44CFE -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=258EC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14946.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A4018 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=911AB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35355 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=199AD -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FCD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1064E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=44CFD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=258DC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14951.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A78D8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=94A6B -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3BA85 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1CEDD -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=32629 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=11E9E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=3F680 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22EE0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14955.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A78D8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=94A6B -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3BA85 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1CEDD -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=32629 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=11E9E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=3F680 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22EE0 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14959.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A79B8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=934AB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=2EF05 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=16A0D -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2A4E9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10A8E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=448A0 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=26960 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14965.1001] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7868 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=9345B -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3BA85 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=17DFD -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=32A59 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1212E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=3F680 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=26610 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14971.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7968 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=925FB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36FE5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1803D -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3D9A9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=11FBE -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46500 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=26180 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14986.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7878 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=926BB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36FA5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=17FFD -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3D979 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=11F7E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=464A0 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=26140 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.14997.1001] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=931EB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x64=1 -SingleUserOffset.x64=274ED -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1D95E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x64=1 -SLInitOffset.x64=E000 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15002.1001] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9698 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=931EB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=346B5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=274ED -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3D779 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1D95E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=47D90 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=E000 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15007.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9648 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=931EB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34665 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=274ED -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3D719 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1D95E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=47D30 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=E000 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15014.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9648 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=931EB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34685 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=274ED -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3D739 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1D95E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=47D50 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=E000 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15019.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A39F8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=928FB -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=BADF5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=FBDD -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=A8479 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx_jmp -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=20AAE -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=3C240 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=24480 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15025.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=9259B -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x64=1 -SingleUserOffset.x64=2C08D -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1DD0E -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x64=1 -SLInitOffset.x64=E5B8 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15031.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5BA8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E221 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=30A75 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=2A114 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2B1D9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1C7B5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4532D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D80C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15042.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5BA8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E221 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=30A75 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=2A114 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2B1D9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1C7B5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4532D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D80C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15046.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=80BB8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E361 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=31E95 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=15E14 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=38A19 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=E745 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=9422D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=21FFC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15048.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=80BB8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E361 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=31E95 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=15E14 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=38A19 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=E745 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=9422D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=21FFC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15055.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5348 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8D2E1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=374C5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=181E4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3BAD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10B65 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=44EFF -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22AEC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15058.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5D68 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8CAA1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35075 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=24E74 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FCD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=2DD65 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4549D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D1EC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15061.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5D68 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8CAA1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35075 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=24E74 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FCD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=2DD65 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4549D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D1EC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15063.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5D68 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8CAA1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35075 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=24E74 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FCD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=2DD65 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4549D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D1EC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15063.296] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A5D68 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8CAA1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=35075 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=24E74 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=2FCD9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=2DD65 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4549D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=D1EC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15063.994] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8CB01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x64=1 -SingleUserOffset.x64=15EA4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=FAE5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x64=1 -SLInitOffset.x64=234DC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.15063.1155] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8CB01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x64=1 -SingleUserOffset.x64=15EA4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=FAE5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x64=1 -SLInitOffset.x64=234DC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16179.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AA568 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8C141 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34425 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=16F84 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31219 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1E7F5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45F30 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=21700 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16184.1001] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AA568 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8C141 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=34425 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=16F84 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31219 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1E7F5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45F30 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=21700 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16199.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=ABA68 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8CED1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=348C5 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=28C14 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=319B9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=CB25 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=469B0 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=FA30 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16215.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7CE8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8DE21 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39F05 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=28724 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3E019 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=CC15 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=46462 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=FB00 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16232.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7D38 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8DD41 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39F35 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=287B4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3E0C9 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=CC15 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4650F -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=FB00 -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16237.1001] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7F38 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E911 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39F85 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1BC84 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3E119 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=DA55 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4655D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2180C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16241.1001] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A7F38 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E911 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39F85 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1BC84 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3E119 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=DA55 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4655D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2180C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16251.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=ABC88 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8EC21 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3A525 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1BCB4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31779 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=DAF5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=447FD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2183C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16251.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=ABC88 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8EC21 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3A525 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1BCB4 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31779 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=DAF5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=447FD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2183C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16257.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AB718 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E841 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=33925 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=11364 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3C409 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1EFD5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4504D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2495C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16257.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AB718 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E841 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=33925 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=11364 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3C409 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1EFD5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4504D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2495C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16273.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AB798 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8E871 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=33925 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=11364 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3C409 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=1EFD5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4504D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2495C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16275.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9388 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=90001 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39435 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C724 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DE89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D75 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=463D4 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D0C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16278.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9388 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=90001 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39435 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C724 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DE89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D75 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=463D4 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D0C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16281.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E08 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FD01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39215 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DC89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=461BD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D5C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16288.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E08 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FD01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39215 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DC89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=461BD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D5C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16291.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E08 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FD01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39215 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DC89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=461BD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D5C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16294.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E08 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FD01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39215 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DC89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=461BD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D5C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16296.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E08 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FD01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39215 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DC89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=461BD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D5C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16299.0] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E08 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FD01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39215 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DC89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=461BD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D5C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16299.15] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E08 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FD01 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39215 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C774 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DC89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=461BD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D5C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16353.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A9388 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=90001 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=39435 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1C724 -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DE89 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D75 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=463D4 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D0C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.16362.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8E38 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FBA1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=2F61C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=19D1C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DE99 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=463D4 -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D9C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17004.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=A8EB8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8FB41 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=2F65C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=19D1C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=3DF09 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=12D85 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=4643F -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22D9C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17017.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AB388 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F291 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3477C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1977C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31049 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=125A5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45CDD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=227DC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17025.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AB498 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F291 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=3477C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1977C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31049 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=125A5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45CDD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=227DC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17035.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AB3F8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F271 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=354AC -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=14E7C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31F19 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10CB5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45C4D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22AEC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17046.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AB3F8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=8F281 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=354AC -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=14E8C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=31F19 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10CC5 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=45C4D -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22AFC -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17063.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AD7F8 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=92671 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36B0C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=153CC -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=33569 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=111CE -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=474AD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=2318C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17115.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AD738 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=925D1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36B0C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1511C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=33569 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10E78 -DefPolicyCode.x64=CDefPolicy_Query_edi_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=474AD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22E6C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17128.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AD738 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=925D1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36B0C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1511C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=33569 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10E78 -DefPolicyCode.x64=CDefPolicy_Query_edi_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=474AD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22E6C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17133.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AD738 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=925D1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36B0C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1511C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=33569 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10E78 -DefPolicyCode.x64=CDefPolicy_Query_edi_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=474AD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22E6C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17134.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AD738 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=925D1 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=36B0C -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1511C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=33569 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=10E78 -DefPolicyCode.x64=CDefPolicy_Query_edi_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=474AD -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=22E6C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17723.1000] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=75D91 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelperMgr::IsSingleSessionPerUserEnabled -SingleUserPatch.x64=1 -SingleUserOffset.x64=1296C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17A45 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x64=1 -SLInitOffset.x64=1B10C -SLInitFunc.x64=New_CSLQuery_Initialize - -[10.0.17763.1] -; Patch CEnforcementCore::GetInstanceOfTSLicense -LocalOnlyPatch.x86=1 -LocalOnlyOffset.x86=AF8E4 -LocalOnlyCode.x86=jmpshort -LocalOnlyPatch.x64=1 -LocalOnlyOffset.x64=77941 -LocalOnlyCode.x64=jmpshort -; Patch CSessionArbitrationHelperMgr::IsSingleSessionPerUserEnabled -SingleUserPatch.x86=1 -SingleUserOffset.x86=4D505 -SingleUserCode.x86=nop -SingleUserPatch.x64=1 -SingleUserOffset.x64=1322C -SingleUserCode.x64=Zero -; Patch CDefPolicy::Query -DefPolicyPatch.x86=1 -DefPolicyOffset.x86=4BD09 -DefPolicyCode.x86=CDefPolicy_Query_eax_ecx -DefPolicyPatch.x64=1 -DefPolicyOffset.x64=17F45 -DefPolicyCode.x64=CDefPolicy_Query_eax_rcx -; Hook CSLQuery::Initialize -SLInitHook.x86=1 -SLInitOffset.x86=5B02A -SLInitFunc.x86=New_CSLQuery_Initialize -SLInitHook.x64=1 -SLInitOffset.x64=1ABFC -SLInitFunc.x64=New_CSLQuery_Initialize - -[SLInit] -; Is server -bServerSku=1 -; Enable listener - allow remote connections -bRemoteConnAllowed=1 -; Allow fast user switching -bFUSEnabled=1 -; Allow RemoteApp server -bAppServerAllowed=1 -; Allow multi monitor -bMultimonAllowed=1 -; Maximum user sessions (0 - unlimited) -lMaxUserSessions=0 -; Maximum debug/glass sessions (0 - unlimited) -ulMaxDebugSessions=0 -; SLInit function is succeeded -bInitialized=1 - -[6.3.9431.0-SLInit] -; HOW TO search SLInit global variables in IDA Pro: -; 1. Search text: The SL policy for ',27h,'Allow Multiple Sessions',27h,' is not defined -; 2. Xref will point to CSLQuery::Initialize function -; 3. Follow xref, look for cmp instruction nearby -; 4. It will be comparsion with CSLQuery::bServerSku constant -; 5. Now it's easy to find other constants - -; Strings to find other values: -; CSLQuery::GetMaxUserSessions -; CSLQuery::IsAppServerInstalled failed: -; CSLQuery::AreRemoteConnectionsAllowed f -; CSLQuery::IsMultimonAllowed -; CSLQuery::GetMaxDebugSessions -; CSLQuery::IsFUSEnabled - -bFUSEnabled.x86 =A22A8 -lMaxUserSessions.x86 =A22AC -bAppServerAllowed.x86 =A22B0 -bInitialized.x86 =A22B4 -bMultimonAllowed.x86 =A22B8 -bServerSku.x86 =A22BC -ulMaxDebugSessions.x86=A22C0 -bRemoteConnAllowed.x86=A22C4 - -bFUSEnabled.x64 =C4490 -lMaxUserSessions.x64 =C4494 -bAppServerAllowed.x64 =C4498 -bInitialized.x64 =C449C -bMultimonAllowed.x64 =C44A0 -bServerSku.x64 =C44A4 -ulMaxDebugSessions.x64=C44A8 -bRemoteConnAllowed.x64=C44AC - -[6.3.9600.16384-SLInit] -bFUSEnabled.x86 =C02A8 -lMaxUserSessions.x86 =C02AC -bAppServerAllowed.x86 =C02B0 -bInitialized.x86 =C02B4 -bMultimonAllowed.x86 =C02B8 -bServerSku.x86 =C02BC -ulMaxDebugSessions.x86=C02C0 -bRemoteConnAllowed.x86=C02C4 - -bServerSku.x64 =E6494 -ulMaxDebugSessions.x64=E6498 -bRemoteConnAllowed.x64=E649C -bFUSEnabled.x64 =E64A0 -lMaxUserSessions.x64 =E64A4 -bAppServerAllowed.x64 =E64A8 -bInitialized.x64 =E64AC -bMultimonAllowed.x64 =E64B0 - -[6.3.9600.17095-SLInit] -bFUSEnabled.x86 =C12A8 -lMaxUserSessions.x86 =C12AC -bAppServerAllowed.x86 =C12B0 -bInitialized.x86 =C12B4 -bMultimonAllowed.x86 =C12B8 -bServerSku.x86 =C12BC -ulMaxDebugSessions.x86=C12C0 -bRemoteConnAllowed.x86=C12C4 - -bServerSku.x64 =E4494 -ulMaxDebugSessions.x64=E4498 -bRemoteConnAllowed.x64=E449C -bFUSEnabled.x64 =E44A0 -lMaxUserSessions.x64 =E44A4 -bAppServerAllowed.x64 =E44A8 -bInitialized.x64 =E44AC -bMultimonAllowed.x64 =E44B0 - -[6.3.9600.17415-SLInit] -bFUSEnabled.x86 =D3068 -lMaxUserSessions.x86 =D306C -bAppServerAllowed.x86 =D3070 -bInitialized.x86 =D3074 -bMultimonAllowed.x86 =D3078 -bServerSku.x86 =D307C -ulMaxDebugSessions.x86=D3080 -bRemoteConnAllowed.x86=D3084 - -bFUSEnabled.x64 =F9054 -lMaxUserSessions.x64 =F9058 -bAppServerAllowed.x64 =F905C -bInitialized.x64 =F9060 -bMultimonAllowed.x64 =F9064 -bServerSku.x64 =F9068 -ulMaxDebugSessions.x64=F906C -bRemoteConnAllowed.x64=F9070 - -[6.3.9600.18692-SLInit] -bFUSEnabled.x86 =D3068 -lMaxUserSessions.x86 =D306C -bAppServerAllowed.x86 =D3070 -bInitialized.x86 =D3074 -bMultimonAllowed.x86 =D3078 -bServerSku.x86 =D307C -ulMaxDebugSessions.x86=D3080 -bRemoteConnAllowed.x86=D3084 - -bFUSEnabled.x64 =F9054 -lMaxUserSessions.x64 =F9058 -bAppServerAllowed.x64 =F905C -bInitialized.x64 =F9060 -bMultimonAllowed.x64 =F9064 -bServerSku.x64 =F9068 -ulMaxDebugSessions.x64=F906C -bRemoteConnAllowed.x64=F9070 - -[6.3.9600.18708-SLInit] -bFUSEnabled.x86 =D3068 -lMaxUserSessions.x86 =D306C -bAppServerAllowed.x86 =D3070 -bInitialized.x86 =D3074 -bMultimonAllowed.x86 =D3078 -bServerSku.x86 =D307C -ulMaxDebugSessions.x86=D3080 -bRemoteConnAllowed.x86=D3084 - -bFUSEnabled.x64 =FA054 -lMaxUserSessions.x64 =FA058 -bAppServerAllowed.x64 =FA05C -bInitialized.x64 =FA060 -bMultimonAllowed.x64 =FA064 -bServerSku.x64 =FA068 -ulMaxDebugSessions.x64=FA06C -bRemoteConnAllowed.x64=FA070 - -[6.3.9600.18928-SLInit] -bFUSEnabled.x86 =D3068 -lMaxUserSessions.x86 =D306C -bAppServerAllowed.x86 =D3070 -bInitialized.x86 =D3074 -bMultimonAllowed.x86 =D3078 -bServerSku.x86 =D307C -ulMaxDebugSessions.x86=D3080 -bRemoteConnAllowed.x86=D3084 - -bFUSEnabled.x64 =FA054 -lMaxUserSessions.x64 =FA058 -bAppServerAllowed.x64 =FA05C -bInitialized.x64 =FA060 -bMultimonAllowed.x64 =FA064 -bServerSku.x64 =FA068 -ulMaxDebugSessions.x64=FA06C -bRemoteConnAllowed.x64=FA070 - -[6.3.9600.19093-SLInit] -bFUSEnabled.x86 =D3068 -lMaxUserSessions.x86 =D306C -bAppServerAllowed.x86 =D3070 -bInitialized.x86 =D3074 -bMultimonAllowed.x86 =D3078 -bServerSku.x86 =D307C -ulMaxDebugSessions.x86=D3080 -bRemoteConnAllowed.x86=D3084 - -bFUSEnabled.x64 =FA054 -lMaxUserSessions.x64 =FA058 -bAppServerAllowed.x64 =FA05C -bInitialized.x64 =FA060 -bMultimonAllowed.x64 =FA064 -bServerSku.x64 =FA068 -ulMaxDebugSessions.x64=FA06C -bRemoteConnAllowed.x64=FA070 - -[6.4.9841.0-SLInit] -bFUSEnabled.x86 =BF9F0 -lMaxUserSessions.x86 =BF9F4 -bAppServerAllowed.x86 =BF9F8 -bInitialized.x86 =BF9FC -bMultimonAllowed.x86 =BFA00 -bServerSku.x86 =BFA04 -ulMaxDebugSessions.x86=BFA08 -bRemoteConnAllowed.x86=BFA0C - -bFUSEnabled.x64 =ECFF8 -lMaxUserSessions.x64 =ECFFC -bAppServerAllowed.x64 =ED000 -bInitialized.x64 =ED004 -bMultimonAllowed.x64 =ED008 -bServerSku.x64 =ED00C -ulMaxDebugSessions.x64=ED010 -bRemoteConnAllowed.x64=ED014 - -[6.4.9860.0-SLInit] -bFUSEnabled.x86 =BF7E0 -lMaxUserSessions.x86 =BF7E4 -bAppServerAllowed.x86 =BF7E8 -bInitialized.x86 =BF7EC -bMultimonAllowed.x86 =BF7F0 -bServerSku.x86 =BF7F4 -ulMaxDebugSessions.x86=BF7F8 -bRemoteConnAllowed.x86=BF7FC - -bFUSEnabled.x64 =ECBD8 -lMaxUserSessions.x64 =ECBDC -bAppServerAllowed.x64 =ECBE0 -bInitialized.x64 =ECBE4 -bMultimonAllowed.x64 =ECBE8 -bServerSku.x64 =ECBEC -ulMaxDebugSessions.x64=ECBF0 -bRemoteConnAllowed.x64=ECBF4 - -[6.4.9879.0-SLInit] -bFUSEnabled.x86 =C27D8 -lMaxUserSessions.x86 =C27DC -bAppServerAllowed.x86 =C27E0 -bInitialized.x86 =C27E4 -bMultimonAllowed.x86 =C27E8 -bServerSku.x86 =C27EC -ulMaxDebugSessions.x86=C27F0 -bRemoteConnAllowed.x86=C27F4 - -bFUSEnabled.x64 =EDBF0 -lMaxUserSessions.x64 =EDBF4 -bAppServerAllowed.x64 =EDBF8 -bInitialized.x64 =EDBFC -bMultimonAllowed.x64 =EDC00 -bServerSku.x64 =EDC04 -ulMaxDebugSessions.x64=EDC08 -bRemoteConnAllowed.x64=EDC0C - -[10.0.9926.0-SLInit] -bFUSEnabled.x86 =C17D8 -lMaxUserSessions.x86 =C17DC -bAppServerAllowed.x86 =C17E0 -bInitialized.x86 =C17E4 -bMultimonAllowed.x86 =C17E8 -bServerSku.x86 =C17EC -ulMaxDebugSessions.x86=C17F0 -bRemoteConnAllowed.x86=C17F4 -; x64 contributed by v-yadli -bFUSEnabled.x64 =EEBF0 -lMaxUserSessions.x64 =EEBF4 -bAppServerAllowed.x64 =EEBF8 -bInitialized.x64 =EEBFC -bMultimonAllowed.x64 =EEC00 -bServerSku.x64 =EEC04 -ulMaxDebugSessions.x64=EEC08 -bRemoteConnAllowed.x64=EEC0C - -[10.0.10041.0-SLInit] -bFUSEnabled.x86 =C5F60 -lMaxUserSessions.x86 =C5F64 -bAppServerAllowed.x86 =C5F68 -bInitialized.x86 =C5F6C -bMultimonAllowed.x86 =C5F70 -bServerSku.x86 =C5F74 -ulMaxDebugSessions.x86=C5F78 -bRemoteConnAllowed.x86=C5F7C - -bFUSEnabled.x64 =F3448 -lMaxUserSessions.x64 =F344C -bAppServerAllowed.x64 =F3450 -bInitialized.x64 =F3454 -bMultimonAllowed.x64 =F3458 -bServerSku.x64 =F345C -ulMaxDebugSessions.x64=F3460 -bRemoteConnAllowed.x64=F3464 - -[10.0.10240.16384-SLInit] -bFUSEnabled.x86 =C3F60 -lMaxUserSessions.x86 =C3F64 -bAppServerAllowed.x86 =C3F68 -bInitialized.x86 =C3F6C -bMultimonAllowed.x86 =C3F70 -bServerSku.x86 =C3F74 -ulMaxDebugSessions.x86=C3F78 -bRemoteConnAllowed.x86=C3F7C - -lMaxUserSessions.x64 =F23B0 -bAppServerAllowed.x64 =F23B4 -bServerSku.x64 =F23B8 -bFUSEnabled.x64 =F3460 -bInitialized.x64 =F3464 -bMultimonAllowed.x64 =F3468 -ulMaxDebugSessions.x64=F346C -bRemoteConnAllowed.x64=F3470 - -[10.0.10586.0-SLInit] -bFUSEnabled.x86 =C3F60 -lMaxUserSessions.x86 =C3F64 -bAppServerAllowed.x86 =C3F68 -bInitialized.x86 =C3F6C -bMultimonAllowed.x86 =C3F70 -bServerSku.x86 =C3F74 -ulMaxDebugSessions.x86=C3F78 -bRemoteConnAllowed.x86=C3F7C - -lMaxUserSessions.x64 =F23B0 -bAppServerAllowed.x64 =F23B4 -bServerSku.x64 =F23B8 -bFUSEnabled.x64 =F3460 -bInitialized.x64 =F3464 -bMultimonAllowed.x64 =F3468 -ulMaxDebugSessions.x64=F346C -bRemoteConnAllowed.x64=F3470 - -[10.0.10586.589-SLInit] -bFUSEnabled.x86 =C3F60 -lMaxUserSessions.x86 =C3F64 -bAppServerAllowed.x86 =C3F68 -bInitialized.x86 =C3F6C -bMultimonAllowed.x86 =C3F70 -bServerSku.x86 =C3F74 -ulMaxDebugSessions.x86=C3F78 -bRemoteConnAllowed.x86=C3F7C - -lMaxUserSessions.x64 =F23B0 -bAppServerAllowed.x64 =F23B4 -bServerSku.x64 =F23B8 -bFUSEnabled.x64 =F3460 -bInitialized.x64 =F3464 -bMultimonAllowed.x64 =F3468 -ulMaxDebugSessions.x64=F346C -bRemoteConnAllowed.x64=F3470 - -[10.0.11082.1000-SLInit] -bFUSEnabled.x86 =C3F60 -lMaxUserSessions.x86 =C3F64 -bAppServerAllowed.x86 =C3F68 -bInitialized.x86 =C3F6C -bMultimonAllowed.x86 =C3F70 -bServerSku.x86 =C3F74 -ulMaxDebugSessions.x86=C3F78 -bRemoteConnAllowed.x86=C3F7C - -lMaxUserSessions.x64 =F23B0 -bAppServerAllowed.x64 =F23B4 -bServerSku.x64 =F23B8 -bFUSEnabled.x64 =F3460 -bInitialized.x64 =F3464 -bMultimonAllowed.x64 =F3468 -ulMaxDebugSessions.x64=F346C -bRemoteConnAllowed.x64=F3470 - -[10.0.11102.1000-SLInit] -bInitialized.x86 =C1F5C -bServerSku.x86 =C1F60 -lMaxUserSessions.x86 =C1F64 -bAppServerAllowed.x86 =C1F68 -bRemoteConnAllowed.x86=C1F6C -bMultimonAllowed.x86 =C1F70 -ulMaxDebugSessions.x86=C1F74 -bFUSEnabled.x86 =C1F78 - -bInitialized.x64 =F2430 -bRemoteConnAllowed.x64=F2434 -bMultimonAllowed.x64 =F2438 -ulMaxDebugSessions.x64=F243C -bFUSEnabled.x64 =F2440 -bServerSku.x64 =F244C -lMaxUserSessions.x64 =F2450 -bAppServerAllowed.x64 =F2454 - -[10.0.14251.1000-SLInit] -bInitialized.x86 =C1F5C -bServerSku.x86 =C1F60 -lMaxUserSessions.x86 =C1F64 -bAppServerAllowed.x86 =C1F68 -bRemoteConnAllowed.x86=C1F6C -bMultimonAllowed.x86 =C1F70 -ulMaxDebugSessions.x86=C1F74 -bFUSEnabled.x86 =C1F78 - -bInitialized.x64 =F2430 -bRemoteConnAllowed.x64=F2434 -bMultimonAllowed.x64 =F2438 -ulMaxDebugSessions.x64=F243C -bFUSEnabled.x64 =F2440 -bServerSku.x64 =F244C -lMaxUserSessions.x64 =F2450 -bAppServerAllowed.x64 =F2454 - -[10.0.14271.1000-SLInit] -bInitialized.x86 =C0F5C -bServerSku.x86 =C0F60 -lMaxUserSessions.x86 =C0F64 -bAppServerAllowed.x86 =C0F68 -bRemoteConnAllowed.x86=C0F6C -bMultimonAllowed.x86 =C0F70 -ulMaxDebugSessions.x86=C0F74 -bFUSEnabled.x86 =C0F78 - -bServerSku.x64 =EF3C0 -lMaxUserSessions.x64 =EF3C4 -bAppServerAllowed.x64 =EF3C8 -bInitialized.x64 =F0460 -bRemoteConnAllowed.x64=F0464 -bMultimonAllowed.x64 =F0468 -ulMaxDebugSessions.x64=F046C -bFUSEnabled.x64 =F0470 - -[10.0.14279.1000-SLInit] -bInitialized.x86 =C0F5C -bServerSku.x86 =C0F60 -lMaxUserSessions.x86 =C0F64 -bAppServerAllowed.x86 =C0F68 -bRemoteConnAllowed.x86=C0F6C -bMultimonAllowed.x86 =C0F70 -ulMaxDebugSessions.x86=C0F74 -bFUSEnabled.x86 =C0F78 - -bServerSku.x64 =EF3C0 -lMaxUserSessions.x64 =EF3C4 -bAppServerAllowed.x64 =EF3C8 -bInitialized.x64 =F0460 -bRemoteConnAllowed.x64=F0464 -bMultimonAllowed.x64 =F0468 -ulMaxDebugSessions.x64=F046C -bFUSEnabled.x64 =F0470 - -[10.0.14295.1000-SLInit] -bInitialized.x86 =C0F5C -bServerSku.x86 =C0F60 -lMaxUserSessions.x86 =C0F64 -bAppServerAllowed.x86 =C0F68 -bRemoteConnAllowed.x86=C0F6C -bMultimonAllowed.x86 =C0F70 -ulMaxDebugSessions.x86=C0F74 -bFUSEnabled.x86 =C0F78 - -bServerSku.x64 =E73C0 -lMaxUserSessions.x64 =E73C4 -bAppServerAllowed.x64 =E73C8 -bInitialized.x64 =E8460 -bRemoteConnAllowed.x64=E8464 -bMultimonAllowed.x64 =E8468 -ulMaxDebugSessions.x64=E846C -bFUSEnabled.x64 =E8470 - -[10.0.14300.1000-SLInit] -bServerSku.x64 =E93C0 -lMaxUserSessions.x64 =E93C4 -bAppServerAllowed.x64 =E93C8 -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 - -[10.0.14316.1000-SLInit] -bInitialized.x86 =C4F58 -bServerSku.x86 =C4F5C -lMaxUserSessions.x86 =C4F60 -bAppServerAllowed.x86 =C4F64 -bRemoteConnAllowed.x86=C4F68 -bMultimonAllowed.x86 =C4F6C -ulMaxDebugSessions.x86=C4F70 -bFUSEnabled.x86 =C4F74 - -bServerSku.x64 =E93C0 -lMaxUserSessions.x64 =E93C4 -bAppServerAllowed.x64 =E93C8 -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 - -[10.0.14328.1000-SLInit] -bInitialized.x86 =C4F58 -bServerSku.x86 =C4F5C -lMaxUserSessions.x86 =C4F60 -bAppServerAllowed.x86 =C4F64 -bRemoteConnAllowed.x86=C4F68 -bMultimonAllowed.x86 =C4F6C -ulMaxDebugSessions.x86=C4F70 -bFUSEnabled.x86 =C4F74 - -bServerSku.x64 =E93C0 -lMaxUserSessions.x64 =E93C4 -bAppServerAllowed.x64 =E93C8 -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 - -[10.0.14332.1001-SLInit] -; contributed by maxpiva -bInitialized.x86 =C4F58 -bServerSku.x86 =C4F5C -lMaxUserSessions.x86 =C4F60 -bAppServerAllowed.x86 =C4F64 -bRemoteConnAllowed.x86=C4F68 -bMultimonAllowed.x86 =C4F6C -ulMaxDebugSessions.x86=C4F70 -bFUSEnabled.x86 =C4F74 - -bServerSku.x64 =E93C0 -lMaxUserSessions.x64 =E93C4 -bAppServerAllowed.x64 =E93C8 -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 - -[10.0.14342.1000-SLInit] -bInitialized.x86 =C4F58 -bServerSku.x86 =C4F5C -lMaxUserSessions.x86 =C4F60 -bAppServerAllowed.x86 =C4F64 -bRemoteConnAllowed.x86=C4F68 -bMultimonAllowed.x86 =C4F6C -ulMaxDebugSessions.x86=C4F70 -bFUSEnabled.x86 =C4F74 - -bInitialized.x64 =E9430 -bRemoteConnAllowed.x64=E9434 -bMultimonAllowed.x64 =E9438 -ulMaxDebugSessions.x64=E943C -bFUSEnabled.x64 =E9440 -bServerSku.x64 =E944C -lMaxUserSessions.x64 =E9450 -bAppServerAllowed.x64 =E9454 - -[10.0.14352.1002-SLInit] -bInitialized.x86 =C0F5C -bServerSku.x86 =C0F60 -lMaxUserSessions.x86 =C0F64 -bAppServerAllowed.x86 =C0F68 -bRemoteConnAllowed.x86=C0F6C -bMultimonAllowed.x86 =C0F70 -ulMaxDebugSessions.x86=C0F74 -bFUSEnabled.x86 =C0F78 - -bServerSku.x64 =E73C0 -lMaxUserSessions.x64 =E73C4 -bAppServerAllowed.x64 =E73C8 -bInitialized.x64 =E8460 -bRemoteConnAllowed.x64=E8464 -bMultimonAllowed.x64 =E8468 -ulMaxDebugSessions.x64=E846C -bFUSEnabled.x64 =E8470 - -[10.0.14366.0-SLInit] -bInitialized.x86 =C4F68 -bServerSku.x86 =C4F6C -lMaxUserSessions.x86 =C4F70 -bAppServerAllowed.x86 =C4F74 -bRemoteConnAllowed.x86=C4F78 -bMultimonAllowed.x86 =C4F7C -ulMaxDebugSessions.x86=C4F80 -bFUSEnabled.x86 =C4F84 - -bServerSku.x64 =E93E0 -lMaxUserSessions.x64 =E93E4 -bAppServerAllowed.x64 =E93E8 -bInitialized.x64 =EA480 -bRemoteConnAllowed.x64=EA484 -bMultimonAllowed.x64 =EA488 -ulMaxDebugSessions.x64=EA48C -bFUSEnabled.x64 =EA490 - -[10.0.14367.0-SLInit] -bInitialized.x86 =C4F68 -bServerSku.x86 =C4F6C -lMaxUserSessions.x86 =C4F70 -bAppServerAllowed.x86 =C4F74 -bRemoteConnAllowed.x86=C4F78 -bMultimonAllowed.x86 =C4F7C -ulMaxDebugSessions.x86=C4F80 -bFUSEnabled.x86 =C4F84 - -bServerSku.x64 =E93E0 -lMaxUserSessions.x64 =E93E4 -bAppServerAllowed.x64 =E93E8 -bInitialized.x64 =EA480 -bRemoteConnAllowed.x64=EA484 -bMultimonAllowed.x64 =EA488 -ulMaxDebugSessions.x64=EA48C -bFUSEnabled.x64 =EA490 - -[10.0.14372.0-SLInit] -bInitialized.x86 =C3F68 -bServerSku.x86 =C3F6C -lMaxUserSessions.x86 =C3F70 -bAppServerAllowed.x86 =C3F74 -bRemoteConnAllowed.x86=C3F78 -bMultimonAllowed.x86 =C3F7C -ulMaxDebugSessions.x86=C3F80 -bFUSEnabled.x86 =C3F84 -; x64 contributed by kbmorris -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 -bServerSku.x64 =EA47C -lMaxUserSessions.x64 =EA480 -bAppServerAllowed.x64 =EA484 - -[10.0.14379.0-SLInit] -bInitialized.x86 =C3F68 -bServerSku.x86 =C3F6C -lMaxUserSessions.x86 =C3F70 -bAppServerAllowed.x86 =C3F74 -bRemoteConnAllowed.x86=C3F78 -bMultimonAllowed.x86 =C3F7C -ulMaxDebugSessions.x86=C3F80 -bFUSEnabled.x86 =C3F84 - -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 -bServerSku.x64 =EA47C -lMaxUserSessions.x64 =EA480 -bAppServerAllowed.x64 =EA484 - -[10.0.14383.0-SLInit] -bInitialized.x86 =C3F68 -bServerSku.x86 =C3F6C -lMaxUserSessions.x86 =C3F70 -bAppServerAllowed.x86 =C3F74 -bRemoteConnAllowed.x86=C3F78 -bMultimonAllowed.x86 =C3F7C -ulMaxDebugSessions.x86=C3F80 -bFUSEnabled.x86 =C3F84 - -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 -bServerSku.x64 =EA47C -lMaxUserSessions.x64 =EA480 -bAppServerAllowed.x64 =EA484 - -[10.0.14385.0-SLInit] -bInitialized.x86 =C3F68 -bServerSku.x86 =C3F6C -lMaxUserSessions.x86 =C3F70 -bAppServerAllowed.x86 =C3F74 -bRemoteConnAllowed.x86=C3F78 -bMultimonAllowed.x86 =C3F7C -ulMaxDebugSessions.x86=C3F80 -bFUSEnabled.x86 =C3F84 - -bInitialized.x64 =EA460 -bRemoteConnAllowed.x64=EA464 -bMultimonAllowed.x64 =EA468 -ulMaxDebugSessions.x64=EA46C -bFUSEnabled.x64 =EA470 -bServerSku.x64 =EA47C -lMaxUserSessions.x64 =EA480 -bAppServerAllowed.x64 =EA484 - -[10.0.14388.0-SLInit] -bInitialized.x86 =C1F6C -bServerSku.x86 =C1F70 -lMaxUserSessions.x86 =C1F74 -bAppServerAllowed.x86 =C1F78 -bRemoteConnAllowed.x86=C1F7C -bMultimonAllowed.x86 =C1F80 -ulMaxDebugSessions.x86=C1F84 -bFUSEnabled.x86 =C1F88 - -bServerSku.x64 =E73D0 -lMaxUserSessions.x64 =E73D4 -bAppServerAllowed.x64 =E73D8 -bInitialized.x64 =E8470 -bRemoteConnAllowed.x64=E8474 -bMultimonAllowed.x64 =E8478 -ulMaxDebugSessions.x64=E847C -bFUSEnabled.x64 =E8480 - -[10.0.14393.0-SLInit] -bInitialized.x86 =C1F6C -bServerSku.x86 =C1F70 -lMaxUserSessions.x86 =C1F74 -bAppServerAllowed.x86 =C1F78 -bRemoteConnAllowed.x86=C1F7C -bMultimonAllowed.x86 =C1F80 -ulMaxDebugSessions.x86=C1F84 -bFUSEnabled.x86 =C1F88 - -bServerSku.x64 =E73D0 -lMaxUserSessions.x64 =E73D4 -bAppServerAllowed.x64 =E73D8 -bInitialized.x64 =E8470 -bRemoteConnAllowed.x64=E8474 -bMultimonAllowed.x64 =E8478 -ulMaxDebugSessions.x64=E847C -bFUSEnabled.x64 =E8480 - -[10.0.14393.1198-SLInit] -bInitialized.x86 =C1F6C -bServerSku.x86 =C1F70 -lMaxUserSessions.x86 =C1F74 -bAppServerAllowed.x86 =C1F78 -bRemoteConnAllowed.x86=C1F7C -bMultimonAllowed.x86 =C1F80 -ulMaxDebugSessions.x86=C1F84 -bFUSEnabled.x86 =C1F88 - -[10.0.14393.1737-SLInit] -bInitialized.x86 =C1F6C -bServerSku.x86 =C1F70 -lMaxUserSessions.x86 =C1F74 -bAppServerAllowed.x86 =C1F78 -bRemoteConnAllowed.x86=C1F7C -bMultimonAllowed.x86 =C1F80 -ulMaxDebugSessions.x86=C1F84 -bFUSEnabled.x86 =C1F88 - -bServerSku.x64 =E73D0 -lMaxUserSessions.x64 =E73D4 -bAppServerAllowed.x64 =E73D8 -bInitialized.x64 =E8470 -bRemoteConnAllowed.x64=E8474 -bMultimonAllowed.x64 =E8478 -ulMaxDebugSessions.x64=E847C -bFUSEnabled.x64 =E8480 - -[10.0.14393.2457-SLInit] -bInitialized.x86 =C1F94 -bServerSku.x86 =C1F98 -lMaxUserSessions.x86 =C1F9C -bAppServerAllowed.x86 =C1FA0 -bRemoteConnAllowed.x86=C1FA4 -bMultimonAllowed.x86 =C1FA8 -ulMaxDebugSessions.x86=C1FAC -bFUSEnabled.x86 =C1FB0 - -bServerSku.x64 =E73D0 -lMaxUserSessions.x64 =E73D4 -bAppServerAllowed.x64 =E73D8 -bInitialized.x64 =E8470 -bRemoteConnAllowed.x64=E8474 -bMultimonAllowed.x64 =E8478 -ulMaxDebugSessions.x64=E847C -bFUSEnabled.x64 =E8480 - -[10.0.14901.1000-SLInit] -bInitialized.x86 =C1F6C -bServerSku.x86 =C1F70 -lMaxUserSessions.x86 =C1F74 -bAppServerAllowed.x86 =C1F78 -bRemoteConnAllowed.x86=C1F7C -bMultimonAllowed.x86 =C1F80 -ulMaxDebugSessions.x86=C1F84 -bFUSEnabled.x86 =C1F88 - -bServerSku.x64 =E73D0 -lMaxUserSessions.x64 =E73D4 -bAppServerAllowed.x64 =E73D8 -bInitialized.x64 =E8470 -bRemoteConnAllowed.x64=E8474 -bMultimonAllowed.x64 =E8478 -ulMaxDebugSessions.x64=E847C -bFUSEnabled.x64 =E8480 - -[10.0.14905.1000-SLInit] -bInitialized.x86 =C1F6C -bServerSku.x86 =C1F70 -lMaxUserSessions.x86 =C1F74 -bAppServerAllowed.x86 =C1F78 -bRemoteConnAllowed.x86=C1F7C -bMultimonAllowed.x86 =C1F80 -ulMaxDebugSessions.x86=C1F84 -bFUSEnabled.x86 =C1F88 - -bServerSku.x64 =E73D0 -lMaxUserSessions.x64 =E73D4 -bAppServerAllowed.x64 =E73D8 -bInitialized.x64 =E8470 -bRemoteConnAllowed.x64=E8474 -bMultimonAllowed.x64 =E8478 -ulMaxDebugSessions.x64=E847C -bFUSEnabled.x64 =E8480 - -[10.0.14915.1000-SLInit] -bInitialized.x86 =C4F6C -bServerSku.x86 =C4F70 -lMaxUserSessions.x86 =C4F74 -bAppServerAllowed.x86 =C4F78 -bRemoteConnAllowed.x86=C4F7C -bMultimonAllowed.x86 =C4F80 -ulMaxDebugSessions.x86=C4F84 -bFUSEnabled.x86 =C4F88 - -bServerSku.x64 =E93D0 -lMaxUserSessions.x64 =E93D4 -bAppServerAllowed.x64 =E93D8 -bInitialized.x64 =EA470 -bRemoteConnAllowed.x64=EA474 -bMultimonAllowed.x64 =EA478 -ulMaxDebugSessions.x64=EA47C -bFUSEnabled.x64 =EA480 - -[10.0.14926.1000-SLInit] -bInitialized.x86 =C4F6C -bServerSku.x86 =C4F70 -lMaxUserSessions.x86 =C4F74 -bAppServerAllowed.x86 =C4F78 -bRemoteConnAllowed.x86=C4F7C -bMultimonAllowed.x86 =C4F80 -ulMaxDebugSessions.x86=C4F84 -bFUSEnabled.x86 =C4F88 - -bServerSku.x64 =E93D0 -lMaxUserSessions.x64 =E93D4 -bAppServerAllowed.x64 =E93D8 -bInitialized.x64 =EA470 -bRemoteConnAllowed.x64=EA474 -bMultimonAllowed.x64 =EA478 -ulMaxDebugSessions.x64=EA47C -bFUSEnabled.x64 =EA480 - -[10.0.14931.1000-SLInit] -bInitialized.x86 =C1F6C -bServerSku.x86 =C1F70 -lMaxUserSessions.x86 =C1F74 -bAppServerAllowed.x86 =C1F78 -bRemoteConnAllowed.x86=C1F7C -bMultimonAllowed.x86 =C1F80 -ulMaxDebugSessions.x86=C1F84 -bFUSEnabled.x86 =C1F88 - -bServerSku.x64 =E63D0 -lMaxUserSessions.x64 =E63D4 -bAppServerAllowed.x64 =E63D8 -bInitialized.x64 =E7470 -bRemoteConnAllowed.x64=E7474 -bMultimonAllowed.x64 =E7478 -ulMaxDebugSessions.x64=E747C -bFUSEnabled.x64 =E7480 - -[10.0.14936.1000-SLInit] -bInitialized.x86 =C0F6C -bServerSku.x86 =C0F70 -lMaxUserSessions.x86 =C0F74 -bAppServerAllowed.x86 =C0F78 -bRemoteConnAllowed.x86=C0F7C -bMultimonAllowed.x86 =C0F80 -ulMaxDebugSessions.x86=C0F84 -bFUSEnabled.x86 =C0F88 - -bInitialized.x64 =E8460 -bRemoteConnAllowed.x64=E8464 -bMultimonAllowed.x64 =E8468 -ulMaxDebugSessions.x64=E846C -bFUSEnabled.x64 =E8470 -bServerSku.x64 =E847C -lMaxUserSessions.x64 =E8480 -bAppServerAllowed.x64 =E8484 - -[10.0.14942.1000-SLInit] -bInitialized.x86 =C0F6C -bServerSku.x86 =C0F70 -lMaxUserSessions.x86 =C0F74 -bAppServerAllowed.x86 =C0F78 -bRemoteConnAllowed.x86=C0F7C -bMultimonAllowed.x86 =C0F80 -ulMaxDebugSessions.x86=C0F84 -bFUSEnabled.x86 =C0F88 - -bInitialized.x64 =EC460 -bRemoteConnAllowed.x64=EC464 -bMultimonAllowed.x64 =EC468 -ulMaxDebugSessions.x64=EC46C -bFUSEnabled.x64 =EC470 -bServerSku.x64 =EC47C -lMaxUserSessions.x64 =EC480 -bAppServerAllowed.x64 =EC484 - -[10.0.14946.1000-SLInit] -bInitialized.x86 =C0F6C -bServerSku.x86 =C0F70 -lMaxUserSessions.x86 =C0F74 -bAppServerAllowed.x86 =C0F78 -bRemoteConnAllowed.x86=C0F7C -bMultimonAllowed.x86 =C0F80 -ulMaxDebugSessions.x86=C0F84 -bFUSEnabled.x86 =C0F88 - -bInitialized.x64 =EC460 -bRemoteConnAllowed.x64=EC464 -bMultimonAllowed.x64 =EC468 -ulMaxDebugSessions.x64=EC46C -bFUSEnabled.x64 =EC470 -bServerSku.x64 =EC47C -lMaxUserSessions.x64 =EC480 -bAppServerAllowed.x64 =EC484 - -[10.0.14951.1000-SLInit] -bInitialized.x86 =C5F68 -bServerSku.x86 =C5F6C -lMaxUserSessions.x86 =C5F70 -bAppServerAllowed.x86 =C5F74 -bRemoteConnAllowed.x86=C5F78 -bMultimonAllowed.x86 =C5F7C -ulMaxDebugSessions.x86=C5F80 -bFUSEnabled.x86 =C5F84 - -bServerSku.x64 =EF3D0 -lMaxUserSessions.x64 =EF3D4 -bAppServerAllowed.x64 =EF3D8 -bInitialized.x64 =F0470 -bRemoteConnAllowed.x64=F0474 -bMultimonAllowed.x64 =F0478 -ulMaxDebugSessions.x64=F047C -bFUSEnabled.x64 =F0480 - -[10.0.14955.1000-SLInit] -bInitialized.x86 =C5F68 -bServerSku.x86 =C5F6C -lMaxUserSessions.x86 =C5F70 -bAppServerAllowed.x86 =C5F74 -bRemoteConnAllowed.x86=C5F78 -bMultimonAllowed.x86 =C5F7C -ulMaxDebugSessions.x86=C5F80 -bFUSEnabled.x86 =C5F84 - -bServerSku.x64 =EF3D0 -lMaxUserSessions.x64 =EF3D4 -bAppServerAllowed.x64 =EF3D8 -bInitialized.x64 =F0470 -bRemoteConnAllowed.x64=F0474 -bMultimonAllowed.x64 =F0478 -ulMaxDebugSessions.x64=F047C -bFUSEnabled.x64 =F0480 - -[10.0.14959.1000-SLInit] -bInitialized.x86 =C4F68 -bServerSku.x86 =C4F6C -lMaxUserSessions.x86 =C4F70 -bAppServerAllowed.x86 =C4F74 -bRemoteConnAllowed.x86=C4F78 -bMultimonAllowed.x86 =C4F7C -ulMaxDebugSessions.x86=C4F80 -bFUSEnabled.x86 =C4F84 - -bServerSku.x64 =EE3D0 -lMaxUserSessions.x64 =EE3D4 -bAppServerAllowed.x64 =EE3D8 -bInitialized.x64 =EF470 -bRemoteConnAllowed.x64=EF474 -bMultimonAllowed.x64 =EF478 -ulMaxDebugSessions.x64=EF47C -bFUSEnabled.x64 =EF480 - -[10.0.14965.1001-SLInit] -bInitialized.x86 =C5F68 -bServerSku.x86 =C5F6C -lMaxUserSessions.x86 =C5F70 -bAppServerAllowed.x86 =C5F74 -bRemoteConnAllowed.x86=C5F78 -bMultimonAllowed.x86 =C5F7C -ulMaxDebugSessions.x86=C5F80 -bFUSEnabled.x86 =C5F84 - -bInitialized.x64 =EF460 -bRemoteConnAllowed.x64=EF464 -bMultimonAllowed.x64 =EF468 -ulMaxDebugSessions.x64=EF46C -bFUSEnabled.x64 =EF470 -bServerSku.x64 =EF47C -lMaxUserSessions.x64 =EF480 -bAppServerAllowed.x64 =EF484 - -[10.0.14971.1000-SLInit] -bInitialized.x86 =C5F68 -bServerSku.x86 =C5F6C -lMaxUserSessions.x86 =C5F70 -bAppServerAllowed.x86 =C5F74 -bRemoteConnAllowed.x86=C5F78 -bMultimonAllowed.x86 =C5F7C -ulMaxDebugSessions.x86=C5F80 -bFUSEnabled.x86 =C5F84 - -bServerSku.x64 =EE3C0 -lMaxUserSessions.x64 =EE3C4 -bAppServerAllowed.x64 =EE3C8 -bInitialized.x64 =EE470 -bRemoteConnAllowed.x64=EE474 -bMultimonAllowed.x64 =EE478 -ulMaxDebugSessions.x64=EE47C -bFUSEnabled.x64 =EE480 - -[10.0.14986.1000-SLInit] -bInitialized.x86 =C5F68 -bServerSku.x86 =C5F6C -lMaxUserSessions.x86 =C5F70 -bAppServerAllowed.x86 =C5F74 -bRemoteConnAllowed.x86=C5F78 -bMultimonAllowed.x86 =C5F7C -ulMaxDebugSessions.x86=C5F80 -bFUSEnabled.x86 =C5F84 - -bServerSku.x64 =EE3C0 -lMaxUserSessions.x64 =EE3C4 -bAppServerAllowed.x64 =EE3C8 -bInitialized.x64 =EE470 -bRemoteConnAllowed.x64=EE474 -bMultimonAllowed.x64 =EE478 -ulMaxDebugSessions.x64=EE47C -bFUSEnabled.x64 =EE480 - -[10.0.14997.1001-SLInit] -bServerSku.x64 =F0408 -lMaxUserSessions.x64 =F040C -bAppServerAllowed.x64 =F0410 -bInitialized.x64 =F0480 -bRemoteConnAllowed.x64=F0484 -bMultimonAllowed.x64 =F0488 -ulMaxDebugSessions.x64=F048C -bFUSEnabled.x64 =F0490 - -[10.0.15002.1001-SLInit] -bInitialized.x86 =C6F74 -bServerSku.x86 =C6F78 -lMaxUserSessions.x86 =C6F7C -bAppServerAllowed.x86 =C6F80 -bRemoteConnAllowed.x86=C6F84 -bMultimonAllowed.x86 =C6F88 -ulMaxDebugSessions.x86=C6F8C -bFUSEnabled.x86 =C6F90 - -bServerSku.x64 =F0408 -lMaxUserSessions.x64 =F040C -bAppServerAllowed.x64 =F0410 -bInitialized.x64 =F0480 -bRemoteConnAllowed.x64=F0484 -bMultimonAllowed.x64 =F0488 -ulMaxDebugSessions.x64=F048C -bFUSEnabled.x64 =F0490 - -[10.0.15007.1000-SLInit] -bInitialized.x86 =C6F74 -bServerSku.x86 =C6F78 -lMaxUserSessions.x86 =C6F7C -bAppServerAllowed.x86 =C6F80 -bRemoteConnAllowed.x86=C6F84 -bMultimonAllowed.x86 =C6F88 -ulMaxDebugSessions.x86=C6F8C -bFUSEnabled.x86 =C6F90 - -bServerSku.x64 =F0408 -lMaxUserSessions.x64 =F040C -bAppServerAllowed.x64 =F0410 -bInitialized.x64 =F0480 -bRemoteConnAllowed.x64=F0484 -bMultimonAllowed.x64 =F0488 -ulMaxDebugSessions.x64=F048C -bFUSEnabled.x64 =F0490 - -[10.0.15014.1000-SLInit] -bInitialized.x86 =C6F74 -bServerSku.x86 =C6F78 -lMaxUserSessions.x86 =C6F7C -bAppServerAllowed.x86 =C6F80 -bRemoteConnAllowed.x86=C6F84 -bMultimonAllowed.x86 =C6F88 -ulMaxDebugSessions.x86=C6F8C -bFUSEnabled.x86 =C6F90 - -bServerSku.x64 =F0408 -lMaxUserSessions.x64 =F040C -bAppServerAllowed.x64 =F0410 -bInitialized.x64 =F0480 -bRemoteConnAllowed.x64=F0484 -bMultimonAllowed.x64 =F0488 -ulMaxDebugSessions.x64=F048C -bFUSEnabled.x64 =F0490 - -[10.0.15019.1000-SLInit] -bInitialized.x86 =C5F68 -bServerSku.x86 =C5F6C -lMaxUserSessions.x86 =C5F70 -bAppServerAllowed.x86 =C5F74 -bRemoteConnAllowed.x86=C5F78 -bMultimonAllowed.x86 =C5F7C -ulMaxDebugSessions.x86=C5F80 -bFUSEnabled.x86 =C5F84 - -bServerSku.x64 =ECBDC -lMaxUserSessions.x64 =ECBE0 -bAppServerAllowed.x64 =ECBE4 -bInitialized.x64 =F0490 -bRemoteConnAllowed.x64=F0494 -bMultimonAllowed.x64 =F0498 -ulMaxDebugSessions.x64=F049C -bFUSEnabled.x64 =F04A0 - -[10.0.15025.1000-SLInit] -bServerSku.x64 =EE3E0 -lMaxUserSessions.x64 =EE3E4 -bAppServerAllowed.x64 =EE3E8 -bInitialized.x64 =EF488 -bRemoteConnAllowed.x64=EF48C -bMultimonAllowed.x64 =EF490 -ulMaxDebugSessions.x64=EF494 -bFUSEnabled.x64 =EF498 - -[10.0.15031.0-SLInit] -bInitialized.x86 =C2F6C -bServerSku.x86 =C2F70 -lMaxUserSessions.x86 =C2F74 -bAppServerAllowed.x86 =C2F78 -bRemoteConnAllowed.x86=C2F7C -bMultimonAllowed.x86 =C2F80 -ulMaxDebugSessions.x86=C2F84 -bFUSEnabled.x86 =C2F88 - -bServerSku.x64 =E93E0 -lMaxUserSessions.x64 =E93E4 -bAppServerAllowed.x64 =E93E8 -bInitialized.x64 =EA488 -bRemoteConnAllowed.x64=EA48C -bMultimonAllowed.x64 =EA490 -ulMaxDebugSessions.x64=EA494 -bFUSEnabled.x64 =EA498 - -[10.0.15042.0-SLInit] -bInitialized.x86 =C2F6C -bServerSku.x86 =C2F70 -lMaxUserSessions.x86 =C2F74 -bAppServerAllowed.x86 =C2F78 -bRemoteConnAllowed.x86=C2F7C -bMultimonAllowed.x86 =C2F80 -ulMaxDebugSessions.x86=C2F84 -bFUSEnabled.x86 =C2F88 - -bServerSku.x64 =E93E0 -lMaxUserSessions.x64 =E93E4 -bAppServerAllowed.x64 =E93E8 -bInitialized.x64 =EA488 -bRemoteConnAllowed.x64=EA48C -bMultimonAllowed.x64 =EA490 -ulMaxDebugSessions.x64=EA494 -bFUSEnabled.x64 =EA498 - -[10.0.15046.0-SLInit] -bInitialized.x86 =C4F18 -bServerSku.x86 =C4F1C -lMaxUserSessions.x86 =C4F20 -bAppServerAllowed.x86 =C4F24 -bRemoteConnAllowed.x86=C4F28 -ulMaxDebugSessions.x86=C4F2C -bMultimonAllowed.x86 =C5010 -bFUSEnabled.x86 =C5014 - -bInitialized.x64 =EB468 -bRemoteConnAllowed.x64=EB46C -bMultimonAllowed.x64 =EB470 -ulMaxDebugSessions.x64=EB474 -bFUSEnabled.x64 =EB478 -bServerSku.x64 =EB484 -lMaxUserSessions.x64 =EB488 -bAppServerAllowed.x64 =EB48C - -[10.0.15048.0-SLInit] -bInitialized.x86 =C4F18 -bServerSku.x86 =C4F1C -lMaxUserSessions.x86 =C4F20 -bAppServerAllowed.x86 =C4F24 -bRemoteConnAllowed.x86=C4F28 -ulMaxDebugSessions.x86=C4F2C -bMultimonAllowed.x86 =C5010 -bFUSEnabled.x86 =C5014 - -bInitialized.x64 =EB468 -bRemoteConnAllowed.x64=EB46C -bMultimonAllowed.x64 =EB470 -ulMaxDebugSessions.x64=EB474 -bFUSEnabled.x64 =EB478 -bServerSku.x64 =EB484 -lMaxUserSessions.x64 =EB488 -bAppServerAllowed.x64 =EB48C - -[10.0.15055.0-SLInit] -bInitialized.x86 =C2F70 -bServerSku.x86 =C2F74 -lMaxUserSessions.x86 =C2F78 -bAppServerAllowed.x86 =C2F7C -bRemoteConnAllowed.x86=C2F80 -bMultimonAllowed.x86 =C2F84 -ulMaxDebugSessions.x86=C2F88 -bFUSEnabled.x86 =C2F8C - -bServerSku.x64 =E83D8 -lMaxUserSessions.x64 =E83DC -bAppServerAllowed.x64 =E83E0 -bInitialized.x64 =E9490 -bRemoteConnAllowed.x64=E9494 -bMultimonAllowed.x64 =E9498 -ulMaxDebugSessions.x64=E949C -bFUSEnabled.x64 =E94A0 - -[10.0.15058.0-SLInit] -bInitialized.x86 =C2F70 -bServerSku.x86 =C2F74 -lMaxUserSessions.x86 =C2F78 -bAppServerAllowed.x86 =C2F7C -bRemoteConnAllowed.x86=C2F80 -bMultimonAllowed.x86 =C2F84 -ulMaxDebugSessions.x86=C2F88 -bFUSEnabled.x86 =C2F8C - -bInitialized.x64 =E9468 -bRemoteConnAllowed.x64=E946C -bMultimonAllowed.x64 =E9470 -ulMaxDebugSessions.x64=E9474 -bFUSEnabled.x64 =E9478 -bServerSku.x64 =E9484 -lMaxUserSessions.x64 =E9488 -bAppServerAllowed.x64 =E948C - -[10.0.15061.0-SLInit] -bInitialized.x86 =C2F70 -bServerSku.x86 =C2F74 -lMaxUserSessions.x86 =C2F78 -bAppServerAllowed.x86 =C2F7C -bRemoteConnAllowed.x86=C2F80 -bMultimonAllowed.x86 =C2F84 -ulMaxDebugSessions.x86=C2F88 -bFUSEnabled.x86 =C2F8C - -bInitialized.x64 =E9468 -bRemoteConnAllowed.x64=E946C -bMultimonAllowed.x64 =E9470 -ulMaxDebugSessions.x64=E9474 -bFUSEnabled.x64 =E9478 -bServerSku.x64 =E9484 -lMaxUserSessions.x64 =E9488 -bAppServerAllowed.x64 =E948C - -[10.0.15063.0-SLInit] -bInitialized.x86 =C2F70 -bServerSku.x86 =C2F74 -lMaxUserSessions.x86 =C2F78 -bAppServerAllowed.x86 =C2F7C -bRemoteConnAllowed.x86=C2F80 -bMultimonAllowed.x86 =C2F84 -ulMaxDebugSessions.x86=C2F88 -bFUSEnabled.x86 =C2F8C - -bInitialized.x64 =E9468 -bRemoteConnAllowed.x64=E946C -bMultimonAllowed.x64 =E9470 -ulMaxDebugSessions.x64=E9474 -bFUSEnabled.x64 =E9478 -bServerSku.x64 =E9484 -lMaxUserSessions.x64 =E9488 -bAppServerAllowed.x64 =E948C - -[10.0.15063.296-SLInit] -bInitialized.x86 =C2F70 -bServerSku.x86 =C2F74 -lMaxUserSessions.x86 =C2F78 -bAppServerAllowed.x86 =C2F7C -bRemoteConnAllowed.x86=C2F80 -bMultimonAllowed.x86 =C2F84 -ulMaxDebugSessions.x86=C2F88 -bFUSEnabled.x86 =C2F8C - -bInitialized.x64 =E9468 -bRemoteConnAllowed.x64=E946C -bMultimonAllowed.x64 =E9470 -ulMaxDebugSessions.x64=E9474 -bFUSEnabled.x64 =E9478 -bServerSku.x64 =E9484 -lMaxUserSessions.x64 =E9488 -bAppServerAllowed.x64 =E948C - -[10.0.15063.994-SLInit] -bInitialized.x64 =E9468 -bRemoteConnAllowed.x64=E946C -bMultimonAllowed.x64 =E9470 -ulMaxDebugSessions.x64=E9474 -bFUSEnabled.x64 =E9478 -bServerSku.x64 =E9484 -lMaxUserSessions.x64 =E9488 -bAppServerAllowed.x64 =E948C - -[10.0.15063.1155-SLInit] -bInitialized.x64 =E9468 -bRemoteConnAllowed.x64=E946C -bMultimonAllowed.x64 =E9470 -ulMaxDebugSessions.x64=E9474 -bFUSEnabled.x64 =E9478 -bServerSku.x64 =E9484 -lMaxUserSessions.x64 =E9488 -bAppServerAllowed.x64 =E948C - -[10.0.16179.1000-SLInit] -bInitialized.x86 =C7F6C -bServerSku.x86 =C7F70 -lMaxUserSessions.x86 =C7F74 -bAppServerAllowed.x86 =C7F78 -bRemoteConnAllowed.x86=C7F7C -bMultimonAllowed.x86 =C7F80 -ulMaxDebugSessions.x86=C7F84 -bFUSEnabled.x86 =C7F88 - -bServerSku.x64 =E83D8 -lMaxUserSessions.x64 =E83DC -bAppServerAllowed.x64 =E83E0 -bInitialized.x64 =E9490 -bRemoteConnAllowed.x64=E9494 -bMultimonAllowed.x64 =E9498 -ulMaxDebugSessions.x64=E949C -bFUSEnabled.x64 =E94A0 - -[10.0.16184.1001-SLInit] -bInitialized.x86 =C7F6C -bServerSku.x86 =C7F70 -lMaxUserSessions.x86 =C7F74 -bAppServerAllowed.x86 =C7F78 -bRemoteConnAllowed.x86=C7F7C -bMultimonAllowed.x86 =C7F80 -ulMaxDebugSessions.x86=C7F84 -bFUSEnabled.x86 =C7F88 - -bServerSku.x64 =E83D8 -lMaxUserSessions.x64 =E83DC -bAppServerAllowed.x64 =E83E0 -bInitialized.x64 =E9490 -bRemoteConnAllowed.x64=E9494 -bMultimonAllowed.x64 =E9498 -ulMaxDebugSessions.x64=E949C -bFUSEnabled.x64 =E94A0 - -[10.0.16199.1000-SLInit] -bInitialized.x86 =C8F74 -bServerSku.x86 =C8F78 -lMaxUserSessions.x86 =C8F7C -bAppServerAllowed.x86 =C8F80 -bRemoteConnAllowed.x86=C8F84 -bMultimonAllowed.x86 =C8F88 -ulMaxDebugSessions.x86=C8F8C -bFUSEnabled.x86 =C8F90 - -bServerSku.x64 =E83E8 -lMaxUserSessions.x64 =E83EC -bAppServerAllowed.x64 =E83F0 -bInitialized.x64 =E94A0 -bRemoteConnAllowed.x64=E94A4 -bMultimonAllowed.x64 =E94A8 -ulMaxDebugSessions.x64=E94AC -bFUSEnabled.x64 =E94B0 - -[10.0.16215.1000-SLInit] -bInitialized.x86 =C5F78 -bServerSku.x86 =C5F7C -lMaxUserSessions.x86 =C5F80 -bAppServerAllowed.x86 =C5F84 -bRemoteConnAllowed.x86=C5F88 -bMultimonAllowed.x86 =C5F8C -ulMaxDebugSessions.x86=C5F90 -bFUSEnabled.x86 =C5F94 - -bServerSku.x64 =EA3E8 -lMaxUserSessions.x64 =EA3EC -bAppServerAllowed.x64 =EA3F0 -bInitialized.x64 =EB4A0 -bRemoteConnAllowed.x64=EB4A4 -bMultimonAllowed.x64 =EB4A8 -ulMaxDebugSessions.x64=EB4AC -bFUSEnabled.x64 =EB4B0 - -[10.0.16232.1000-SLInit] -bInitialized.x86 =C5F78 -bServerSku.x86 =C5F7C -lMaxUserSessions.x86 =C5F80 -bAppServerAllowed.x86 =C5F84 -bRemoteConnAllowed.x86=C5F88 -bMultimonAllowed.x86 =C5F8C -ulMaxDebugSessions.x86=C5F90 -bFUSEnabled.x86 =C5F94 - -bServerSku.x64 =EA3E8 -lMaxUserSessions.x64 =EA3EC -bAppServerAllowed.x64 =EA3F0 -bInitialized.x64 =EB4A0 -bRemoteConnAllowed.x64=EB4A4 -bMultimonAllowed.x64 =EB4A8 -ulMaxDebugSessions.x64=EB4AC -bFUSEnabled.x64 =EB4B0 - -[10.0.16237.1001-SLInit] -bInitialized.x86 =C5F78 -bServerSku.x86 =C5F7C -lMaxUserSessions.x86 =C5F80 -bAppServerAllowed.x86 =C5F84 -bRemoteConnAllowed.x86=C5F88 -bMultimonAllowed.x86 =C5F8C -ulMaxDebugSessions.x86=C5F90 -bFUSEnabled.x86 =C5F94 - -bServerSku.x64 =EB3EC -lMaxUserSessions.x64 =EB3F0 -bAppServerAllowed.x64 =EB3F4 -bInitialized.x64 =EC4A0 -bRemoteConnAllowed.x64=EC4A4 -bMultimonAllowed.x64 =EC4A8 -ulMaxDebugSessions.x64=EC4AC -bFUSEnabled.x64 =EC4B0 - -[10.0.16241.1001-SLInit] -bInitialized.x86 =C5F78 -bServerSku.x86 =C5F7C -lMaxUserSessions.x86 =C5F80 -bAppServerAllowed.x86 =C5F84 -bRemoteConnAllowed.x86=C5F88 -bMultimonAllowed.x86 =C5F8C -ulMaxDebugSessions.x86=C5F90 -bFUSEnabled.x86 =C5F94 - -bServerSku.x64 =EB3EC -lMaxUserSessions.x64 =EB3F0 -bAppServerAllowed.x64 =EB3F4 -bInitialized.x64 =EC4A0 -bRemoteConnAllowed.x64=EC4A4 -bMultimonAllowed.x64 =EC4A8 -ulMaxDebugSessions.x64=EC4AC -bFUSEnabled.x64 =EC4B0 - -[10.0.16251.0-SLInit] -bInitialized.x86 =C9F78 -bServerSku.x86 =C9F7C -lMaxUserSessions.x86 =C9F80 -bAppServerAllowed.x86 =C9F84 -bRemoteConnAllowed.x86=C9F88 -bMultimonAllowed.x86 =C9F8C -ulMaxDebugSessions.x86=C9F90 -bFUSEnabled.x86 =C9F94 - -bServerSku.x64 =EB3EC -lMaxUserSessions.x64 =EB3F0 -bAppServerAllowed.x64 =EB3F4 -bInitialized.x64 =EC4A0 -bRemoteConnAllowed.x64=EC4A4 -bMultimonAllowed.x64 =EC4A8 -ulMaxDebugSessions.x64=EC4AC -bFUSEnabled.x64 =EC4B0 - -[10.0.16251.1000-SLInit] -bInitialized.x86 =C9F78 -bServerSku.x86 =C9F7C -lMaxUserSessions.x86 =C9F80 -bAppServerAllowed.x86 =C9F84 -bRemoteConnAllowed.x86=C9F88 -bMultimonAllowed.x86 =C9F8C -ulMaxDebugSessions.x86=C9F90 -bFUSEnabled.x86 =C9F94 - -bServerSku.x64 =EB3EC -lMaxUserSessions.x64 =EB3F0 -bAppServerAllowed.x64 =EB3F4 -bInitialized.x64 =EC4A0 -bRemoteConnAllowed.x64=EC4A4 -bMultimonAllowed.x64 =EC4A8 -ulMaxDebugSessions.x64=EC4AC -bFUSEnabled.x64 =EC4B0 - -[10.0.16257.1-SLInit] -bInitialized.x86 =C9F7C -bServerSku.x86 =C9F80 -lMaxUserSessions.x86 =C9F84 -bAppServerAllowed.x86 =C9F88 -bRemoteConnAllowed.x86=C9F8C -bMultimonAllowed.x86 =C9F90 -ulMaxDebugSessions.x86=C9F94 -bFUSEnabled.x86 =C9F98 - -bServerSku.x64 =EB3F0 -lMaxUserSessions.x64 =EB3F4 -bAppServerAllowed.x64 =EB3F8 -bInitialized.x64 =EC4A0 -bRemoteConnAllowed.x64=EC4A4 -bMultimonAllowed.x64 =EC4A8 -ulMaxDebugSessions.x64=EC4AC -bFUSEnabled.x64 =EC4B0 - -[10.0.16257.1000-SLInit] -bInitialized.x86 =C9F7C -bServerSku.x86 =C9F80 -lMaxUserSessions.x86 =C9F84 -bAppServerAllowed.x86 =C9F88 -bRemoteConnAllowed.x86=C9F8C -bMultimonAllowed.x86 =C9F90 -ulMaxDebugSessions.x86=C9F94 -bFUSEnabled.x86 =C9F98 - -bServerSku.x64 =EB3F0 -lMaxUserSessions.x64 =EB3F4 -bAppServerAllowed.x64 =EB3F8 -bInitialized.x64 =EC4A0 -bRemoteConnAllowed.x64=EC4A4 -bMultimonAllowed.x64 =EC4A8 -ulMaxDebugSessions.x64=EC4AC -bFUSEnabled.x64 =EC4B0 - -[10.0.16273.1000-SLInit] -bInitialized.x86 =C9F7C -bServerSku.x86 =C9F80 -lMaxUserSessions.x86 =C9F84 -bAppServerAllowed.x86 =C9F88 -bRemoteConnAllowed.x86=C9F8C -bMultimonAllowed.x86 =C9F90 -ulMaxDebugSessions.x86=C9F94 -bFUSEnabled.x86 =C9F98 - -bServerSku.x64 =EB3F0 -lMaxUserSessions.x64 =EB3F4 -bAppServerAllowed.x64 =EB3F8 -bInitialized.x64 =EC4A0 -bRemoteConnAllowed.x64=EC4A4 -bMultimonAllowed.x64 =EC4A8 -ulMaxDebugSessions.x64=EC4AC -bFUSEnabled.x64 =EC4B0 - -[10.0.16275.1000-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16278.1000-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16281.1000-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16288.1-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16291.0-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16294.1-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16296.0-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16299.0-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16299.15-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16353.1000-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.16362.1000-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.17004.1000-SLInit] -bInitialized.x86 =C6F7C -bServerSku.x86 =C6F80 -lMaxUserSessions.x86 =C6F84 -bAppServerAllowed.x86 =C6F88 -bRemoteConnAllowed.x86=C6F8C -bMultimonAllowed.x86 =C6F90 -ulMaxDebugSessions.x86=C6F94 -bFUSEnabled.x86 =C6F98 - -bServerSku.x64 =ED3E8 -lMaxUserSessions.x64 =ED3EC -bAppServerAllowed.x64 =ED3F0 -bInitialized.x64 =EE4A0 -bRemoteConnAllowed.x64=EE4A4 -bMultimonAllowed.x64 =EE4A8 -ulMaxDebugSessions.x64=EE4AC -bFUSEnabled.x64 =EE4B0 - -[10.0.17017.1000-SLInit] -bInitialized.x86 =C9EB8 -bServerSku.x86 =C9EBC -lMaxUserSessions.x86 =C9EC0 -bAppServerAllowed.x86 =C9EC4 -bRemoteConnAllowed.x86=C9EC8 -bMultimonAllowed.x86 =C9ECC -ulMaxDebugSessions.x86=C9ED0 -bFUSEnabled.x86 =C9ED4 - -bServerSku.x64 =EC2E8 -lMaxUserSessions.x64 =EC2EC -bAppServerAllowed.x64 =EC2F0 -bInitialized.x64 =ED3A0 -bRemoteConnAllowed.x64=ED3A4 -bMultimonAllowed.x64 =ED3A8 -ulMaxDebugSessions.x64=ED3AC -bFUSEnabled.x64 =ED3B0 - -[10.0.17025.1000-SLInit] -bInitialized.x86 =C9EB8 -bServerSku.x86 =C9EBC -lMaxUserSessions.x86 =C9EC0 -bAppServerAllowed.x86 =C9EC4 -bRemoteConnAllowed.x86=C9EC8 -bMultimonAllowed.x86 =C9ECC -ulMaxDebugSessions.x86=C9ED0 -bFUSEnabled.x86 =C9ED4 - -bServerSku.x64 =EC2E8 -lMaxUserSessions.x64 =EC2EC -bAppServerAllowed.x64 =EC2F0 -bInitialized.x64 =ED3A0 -bRemoteConnAllowed.x64=ED3A4 -bMultimonAllowed.x64 =ED3A8 -ulMaxDebugSessions.x64=ED3AC -bFUSEnabled.x64 =ED3B0 - -[10.0.17035.1000-SLInit] -bInitialized.x86 =C9ED8 -bServerSku.x86 =C9EDC -lMaxUserSessions.x86 =C9EE0 -bAppServerAllowed.x86 =C9EE4 -bRemoteConnAllowed.x86=C9EE8 -bMultimonAllowed.x86 =C9EEC -ulMaxDebugSessions.x86=C9EF0 -bFUSEnabled.x86 =C9EF4 - -bServerSku.x64 =EC2E8 -lMaxUserSessions.x64 =EC2EC -bAppServerAllowed.x64 =EC2F0 -bInitialized.x64 =ED3A0 -bRemoteConnAllowed.x64=ED3A4 -bMultimonAllowed.x64 =ED3A8 -ulMaxDebugSessions.x64=ED3AC -bFUSEnabled.x64 =ED3B0 - -[10.0.17046.1000-SLInit] -bInitialized.x86 =C9ED8 -bServerSku.x86 =C9EDC -lMaxUserSessions.x86 =C9EE0 -bAppServerAllowed.x86 =C9EE4 -bRemoteConnAllowed.x86=C9EE8 -bMultimonAllowed.x86 =C9EEC -ulMaxDebugSessions.x86=C9EF0 -bFUSEnabled.x86 =C9EF4 - -bServerSku.x64 =EC2E8 -lMaxUserSessions.x64 =EC2EC -bAppServerAllowed.x64 =EC2F0 -bInitialized.x64 =ED3A0 -bRemoteConnAllowed.x64=ED3A4 -bMultimonAllowed.x64 =ED3A8 -ulMaxDebugSessions.x64=ED3AC -bFUSEnabled.x64 =ED3B0 - -[10.0.17063.1000-SLInit] -bInitialized.x86 =CBF38 -bServerSku.x86 =CBF3C -lMaxUserSessions.x86 =CBF40 -bAppServerAllowed.x86 =CBF44 -bRemoteConnAllowed.x86=CBF48 -bMultimonAllowed.x86 =CBF4C -ulMaxDebugSessions.x86=CBF50 -bFUSEnabled.x86 =CBF54 - -bServerSku.x64 =F1378 -lMaxUserSessions.x64 =F137C -bAppServerAllowed.x64 =F1380 -bInitialized.x64 =F2430 -bRemoteConnAllowed.x64=F2434 -bMultimonAllowed.x64 =F2438 -ulMaxDebugSessions.x64=F243C -bFUSEnabled.x64 =F2440 - -[10.0.17115.1-SLInit] -bInitialized.x86 =CBF38 -bServerSku.x86 =CBF3C -lMaxUserSessions.x86 =CBF40 -bAppServerAllowed.x86 =CBF44 -bRemoteConnAllowed.x86=CBF48 -bMultimonAllowed.x86 =CBF4C -ulMaxDebugSessions.x86=CBF50 -bFUSEnabled.x86 =CBF54 - -bServerSku.x64 =F1378 -lMaxUserSessions.x64 =F137C -bAppServerAllowed.x64 =F1380 -bInitialized.x64 =F2430 -bRemoteConnAllowed.x64=F2434 -bMultimonAllowed.x64 =F2438 -ulMaxDebugSessions.x64=F243C -bFUSEnabled.x64 =F2440 - -[10.0.17128.1-SLInit] -bInitialized.x86 =CBF38 -bServerSku.x86 =CBF3C -lMaxUserSessions.x86 =CBF40 -bAppServerAllowed.x86 =CBF44 -bRemoteConnAllowed.x86=CBF48 -bMultimonAllowed.x86 =CBF4C -ulMaxDebugSessions.x86=CBF50 -bFUSEnabled.x86 =CBF54 - -bServerSku.x64 =F1378 -lMaxUserSessions.x64 =F137C -bAppServerAllowed.x64 =F1380 -bInitialized.x64 =F2430 -bRemoteConnAllowed.x64=F2434 -bMultimonAllowed.x64 =F2438 -ulMaxDebugSessions.x64=F243C -bFUSEnabled.x64 =F2440 - -[10.0.17133.1-SLInit] -bInitialized.x86 =CBF38 -bServerSku.x86 =CBF3C -lMaxUserSessions.x86 =CBF40 -bAppServerAllowed.x86 =CBF44 -bRemoteConnAllowed.x86=CBF48 -bMultimonAllowed.x86 =CBF4C -ulMaxDebugSessions.x86=CBF50 -bFUSEnabled.x86 =CBF54 - -bServerSku.x64 =F1378 -lMaxUserSessions.x64 =F137C -bAppServerAllowed.x64 =F1380 -bInitialized.x64 =F2430 -bRemoteConnAllowed.x64=F2434 -bMultimonAllowed.x64 =F2438 -ulMaxDebugSessions.x64=F243C -bFUSEnabled.x64 =F2440 - -[10.0.17134.1-SLInit] -bInitialized.x86 =CBF38 -bServerSku.x86 =CBF3C -lMaxUserSessions.x86 =CBF40 -bAppServerAllowed.x86 =CBF44 -bRemoteConnAllowed.x86=CBF48 -bMultimonAllowed.x86 =CBF4C -ulMaxDebugSessions.x86=CBF50 -bFUSEnabled.x86 =CBF54 - -bServerSku.x64 =F1378 -lMaxUserSessions.x64 =F137C -bAppServerAllowed.x64 =F1380 -bInitialized.x64 =F2430 -bRemoteConnAllowed.x64=F2434 -bMultimonAllowed.x64 =F2438 -ulMaxDebugSessions.x64=F243C -bFUSEnabled.x64 =F2440 - -[10.0.17723.1000-SLInit] -bInitialized.x64 =E9AB0 -bServerSku.x64 =E9AB4 -lMaxUserSessions.x64 =E9AB8 -bAppServerAllowed.x64 =E9AC0 -bRemoteConnAllowed.x64=E9AC4 -bMultimonAllowed.x64 =E9AC8 -ulMaxDebugSessions.x64=E9ACC -bFUSEnabled.x64 =E9AD0 - -[10.0.17763.1-SLInit] -bInitialized.x86 =CD798 -bServerSku.x86 =CD79C -lMaxUserSessions.x86 =CD7A0 -bAppServerAllowed.x86 =CD7A8 -bRemoteConnAllowed.x86=CD7AC -bMultimonAllowed.x86 =CD7B0 -ulMaxDebugSessions.x86=CD7B4 -bFUSEnabled.x86 =CD7B8 - -bInitialized.x64 =ECAB0 -bServerSku.x64 =ECAB4 -lMaxUserSessions.x64 =ECAB8 -bAppServerAllowed.x64 =ECAC0 -bRemoteConnAllowed.x64=ECAC4 -bMultimonAllowed.x64 =ECAC8 -ulMaxDebugSessions.x64=ECACC -bFUSEnabled.x64 =ECAD0 diff --git a/src-csharp/Directory.Build.props b/src-csharp/Directory.Build.props new file mode 100644 index 0000000..48868ce --- /dev/null +++ b/src-csharp/Directory.Build.props @@ -0,0 +1,44 @@ + + + net10.0-windows + x86;x64;arm64 + latest + enable + enable + true + $(Platform) + + false + + true + + + $([System.DateTime]::Now.ToString("yyyy.M.d")) + $([System.DateTime]::Now.ToString("yyyy.M.d")).0 + $([System.DateTime]::Now.ToString("yyyy.M.d")).0 + + Simon Jackson + Simon Jackson (@sjackson0109) + Copyright © 2026 Simon Jackson (@sjackson0109) + RDP Wrapper + https://github.com/sjackson0109/rdpwrap + git + https://github.com/sjackson0109/rdpwrap + + + true + + diff --git a/src-csharp/RDPCheck/MainForm.cs b/src-csharp/RDPCheck/MainForm.cs new file mode 100644 index 0000000..bc33caf --- /dev/null +++ b/src-csharp/RDPCheck/MainForm.cs @@ -0,0 +1,160 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// Hosts the MsRdpClient2 ActiveX control, connects to 127.0.0.2, and +// reports the disconnect reason, mirroring the Delphi RDPDisconnected handler. + +using RDPWrap.Common; + +namespace RDPCheck; + +internal sealed class MainForm : Form +{ + private readonly AxRdpClient2 _rdp; + + // Registry values saved on load — restored on disconnect + private int _savedSecurityLayer; + private int _savedUserAuthentication; + + // ── Constructor / Layout ────────────────────────────────────────────────── + + public MainForm() + { + SuspendLayout(); + + Text = "RDP Wrapper Check"; + ClientSize = new Size(800, 600); + StartPosition = FormStartPosition.CenterScreen; + FormBorderStyle = FormBorderStyle.Sizable; + + _rdp = new AxRdpClient2 + { + Dock = DockStyle.Fill + }; + + Controls.Add(_rdp); + ResumeLayout(false); + + _rdp.Disconnected += OnRdpDisconnected; + Load += OnFormLoad; + } + + // ── FormLoad — mirrors TFrm.FormCreate ──────────────────────────────────── + + private void OnFormLoad(object? sender, EventArgs e) + { + const string rdpTcpKey = + @"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"; + + _rdp.DisconnectedText = "Disconnected."; + _rdp.ConnectingText = "Connecting..."; + _rdp.ConnectedStatusText = "Connected."; + _rdp.UserName = string.Empty; + _rdp.Server = "127.0.0.2"; + + // Read, then zero-out SecurityLayer / UserAuthentication + _savedSecurityLayer = RegistryHelper.ReadInt(rdpTcpKey, "SecurityLayer", 0); + _savedUserAuthentication = RegistryHelper.ReadInt(rdpTcpKey, "UserAuthentication", 0); + + try + { + RegistryHelper.WriteInt(rdpTcpKey, "SecurityLayer", 0); + RegistryHelper.WriteInt(rdpTcpKey, "UserAuthentication", 0); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[RDP] Registry write failed: {ex.Message}"); + } + + // Read port + int port = RegistryHelper.ReadInt(rdpTcpKey, "PortNumber", 3389); + _rdp.SetPort(port); + + // Subscribe to COM events now that the handle exists + _rdp.SubscribeEvents(); + + // Brief delay then connect — matches Delphi Sleep(1000); RDP.Connect; + Task.Delay(1000).ContinueWith(_ => Invoke((Action)_rdp.Connect)); + } + + // ── OnDisconnected — mirrors TFrm.RDPDisconnected ───────────────────────── + + private void OnRdpDisconnected(object? sender, int discReason) + { + string errStr = discReason switch + { + 0x001 => "Local disconnection.", + 0x002 => "Disconnected by user.", + 0x003 => "Disconnected by server.", + 0x904 => "Socket closed.", + 0xC08 => "Decompress error.", + 0x108 => "Connection timed out.", + 0xC06 => "Decryption error.", + 0x104 => "DNS name lookup failure.", + 0x508 => "DNS lookup failed.", + 0xB06 => "Encryption error.", + 0x604 => "Windows Sockets gethostbyname() call failed.", + 0x208 => "Host not found error.", + 0x408 => "Internal error.", + 0x906 => "Internal security error.", + 0xA06 => "Internal security error.", + 0x506 => "The encryption method specified is not valid.", + 0x804 => "Bad IP address specified.", + 0x606 => "Server security data is not valid.", + 0x406 => "Security data is not valid.", + 0x308 => "The IP address specified is not valid.", + 0x808 => "License negotiation failed.", + 0x908 => "Licensing time-out.", + 0x106 => "Out of memory.", + 0x206 => "Out of memory.", + 0x306 => "Out of memory.", + 0x706 => "Failed to unpack server certificate.", + 0x204 => "Socket connection failed.", + 0x404 => "Windows Sockets recv() call failed.", + 0x704 => "Time-out occurred.", + 0x608 => "Internal timer error.", + 0x304 => "Windows Sockets send() call failed.", + 0xB07 => "The account is disabled.", + 0xE07 => "The account is expired.", + 0xD07 => "The account is locked out.", + 0xC07 => "The account is restricted.", + 0x1B07 => "The received certificate is expired.", + 0x1607 => "The policy does not support delegation of credentials to the target server.", + 0x2107 => "The server authentication policy does not allow connection requests using saved credentials. The user must enter new credentials.", + 0x807 => "Login failed.", + 0x1807 => "No authority could be contacted for authentication. The domain name of the authenticating party could be wrong, the domain could be unreachable, or there might have been a trust relationship failure.", + 0xA07 => "The specified user has no account.", + 0xF07 => "The password is expired.", + 0x1207 => "The user password must be changed before logging on for the first time.", + 0x1707 => "Delegation of credentials to the target server is not allowed unless mutual authentication has been achieved.", + 0x2207 => "The smart card is blocked.", + 0x1C07 => "An incorrect PIN was presented to the smart card.", + 0xB09 => "Network Level Authentication is required, run RDPCheck as administrator.", + 0x708 => "RDP is working, but the client doesn't allow loopback connections. Try to connect to your PC from another device in the network.", + _ => $"Unknown code 0x{discReason:X}" + }; + + if (discReason > 2) + { + MessageBox.Show(errStr, "Disconnected", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + // Restore registry + const string rdpTcpKey = + @"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"; + try + { + RegistryHelper.WriteInt(rdpTcpKey, "SecurityLayer", _savedSecurityLayer); + RegistryHelper.WriteInt(rdpTcpKey, "UserAuthentication", _savedUserAuthentication); + } + catch { } + + Application.Exit(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) _rdp.Dispose(); + base.Dispose(disposing); + } +} diff --git a/src-csharp/RDPCheck/Program.cs b/src-csharp/RDPCheck/Program.cs new file mode 100644 index 0000000..f4af297 --- /dev/null +++ b/src-csharp/RDPCheck/Program.cs @@ -0,0 +1,15 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// RDPCheck — WinForms RDP tester entry point. + +namespace RDPCheck; + +internal static class Program +{ + [STAThread] + internal static void Main() + { + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); + } +} diff --git a/src-csharp/RDPCheck/RDPCheck.csproj b/src-csharp/RDPCheck/RDPCheck.csproj new file mode 100644 index 0000000..a97d497 --- /dev/null +++ b/src-csharp/RDPCheck/RDPCheck.csproj @@ -0,0 +1,32 @@ + + + WinExe + true + RDPCheck + RDPCheck + app.manifest + app.ico + WinForms RDP loopback connection tester — validates that RDP Wrapper is installed and accepting connections correctly. + + + + + + + + + + + + diff --git a/src-csharp/RDPCheck/RdpComInterop.cs b/src-csharp/RDPCheck/RdpComInterop.cs new file mode 100644 index 0000000..84a6ea2 --- /dev/null +++ b/src-csharp/RDPCheck/RdpComInterop.cs @@ -0,0 +1,147 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// COM interop helpers for hosting the MsRdpClient2 ActiveX control and +// receiving its disconnection event without requiring pre-generated TLB wrappers. + +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace RDPCheck; + +// ── COM interfaces needed for connection-point event subscription ──────────── + +[ComImport] +[Guid("B196B284-BAB4-101A-B69C-00AA00341D07")] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IConnectionPointContainer +{ + void EnumConnectionPoints(out IntPtr ppEnum); + void FindConnectionPoint(ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IConnectionPoint ppCP); +} + +[ComImport] +[Guid("B196B287-BAB4-101A-B69C-00AA00341D07")] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IConnectionPoint +{ + void GetConnectionInterface(out Guid pIID); + void GetConnectionPointContainer([MarshalAs(UnmanagedType.Interface)] out IConnectionPointContainer ppCPC); + void Advise([MarshalAs(UnmanagedType.Interface)] object pUnkSink, out uint pdwCookie); + void Unadvise(uint dwCookie); + void EnumConnections(out IntPtr ppEnum); +} + +// ── IDispatch-based event interface (dispinterface) ────────────────────────── +// Matching the DIID of IMsTscAxEvents so the RDP control can route events here. + +[ComVisible(true)] +[Guid("336D5562-EBA6-11D0-B0B0-00C04FD610D0")] +[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] +internal interface IRdpEvents +{ + [DispId(1)] void OnConnecting(); + [DispId(2)] void OnConnected(); + [DispId(3)] void OnLoginComplete(); + [DispId(4)] void OnDisconnected(int discReason); + // Additional high-DISPID events are ignored (not listed here) +} + +// ── Managed event sink ──────────────────────────────────────────────────────── + +[ComVisible(true)] +[ClassInterface(ClassInterfaceType.None)] +internal sealed class RdpEventSink : IRdpEvents +{ + private readonly Action _onDisconnected; + + public RdpEventSink(Action onDisconnected) => _onDisconnected = onDisconnected; + + public void OnConnecting() { } + public void OnConnected() { } + public void OnLoginComplete() { } + public void OnDisconnected(int discReason) => _onDisconnected(discReason); +} + +// ── AxHost wrapper for MsRdpClient2 ────────────────────────────────────────── + +internal sealed class AxRdpClient2 : AxHost +{ + // CLSID for MsRdpClient2 (msrdp.ocx / mstscax.dll) + private static readonly Guid Clsid = new("9059F30F-4EB1-4BD2-9FDC-36F43A218F4A"); + // DIID for the default source interface (IMsTscAxEvents / DIMsTscAxEvents) + private static readonly Guid DiidEvents = new("336D5562-EBA6-11D0-B0B0-00C04FD610D0"); + + private dynamic? _ocx; + private IConnectionPoint? _cp; + private uint _cookie; + private RdpEventSink? _sink; + + /// Raised on the UI thread when the RDP control disconnects. + public event EventHandler? Disconnected; + + public AxRdpClient2() : base(Clsid.ToString("B")) { } + + protected override void AttachInterfaces() + { + _ocx = GetOcx() as dynamic; + } + + /// + /// Wires up the COM event sink. Call once after the handle has been created + /// (i.e. after the form is shown). + /// + public void SubscribeEvents() + { + if (_ocx is null) return; + try + { + var cpContainer = (IConnectionPointContainer)_ocx; + var eventsIid = DiidEvents; + cpContainer.FindConnectionPoint(ref eventsIid, out var cp); + _sink = new RdpEventSink(reason => Invoke( + (Action)(() => Disconnected?.Invoke(this, reason)))); + cp.Advise(_sink, out _cookie); + _cp = cp; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[RDP] SubscribeEvents failed: {ex.Message}"); + } + } + + /// Unsubscribes the event sink. + public void UnsubscribeEvents() + { + try { _cp?.Unadvise(_cookie); } catch { } + _cp = null; + } + + // ── Typed property / method wrappers ──────────────────────────────────── + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Server { set { if (_ocx != null) _ocx.Server = value; } } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string UserName { set { if (_ocx != null) _ocx.UserName = value; } } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string DisconnectedText { set { if (_ocx != null) _ocx.DisconnectedText = value; } } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ConnectingText { set { if (_ocx != null) _ocx.ConnectingText = value; } } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ConnectedStatusText { set { if (_ocx != null) _ocx.ConnectedStatusText = value; } } + + public void SetPort(int port) + { + try { if (_ocx != null) _ocx.AdvancedSettings2.RDPPort = port; } catch { } + } + + public void Connect() + { + try { _ocx?.Connect(); } catch { } + } + + protected override void Dispose(bool disposing) + { + if (disposing) UnsubscribeEvents(); + base.Dispose(disposing); + } +} diff --git a/src-csharp/RDPCheck/app.ico b/src-csharp/RDPCheck/app.ico new file mode 100644 index 0000000..2a72a4d Binary files /dev/null and b/src-csharp/RDPCheck/app.ico differ diff --git a/src-csharp/RDPCheck/app.manifest b/src-csharp/RDPCheck/app.manifest new file mode 100644 index 0000000..c0e2d9b --- /dev/null +++ b/src-csharp/RDPCheck/app.manifest @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src-csharp/RDPCheck/packages.lock.json b/src-csharp/RDPCheck/packages.lock.json new file mode 100644 index 0000000..59ebcea --- /dev/null +++ b/src-csharp/RDPCheck/packages.lock.json @@ -0,0 +1,10 @@ +{ + "version": 1, + "dependencies": { + "net10.0-windows7.0": { + "rdpwrap": { + "type": "Project" + } + } + } +} \ No newline at end of file diff --git a/src-csharp/RDPConf/LicenseForm.cs b/src-csharp/RDPConf/LicenseForm.cs new file mode 100644 index 0000000..bff9b94 --- /dev/null +++ b/src-csharp/RDPConf/LicenseForm.cs @@ -0,0 +1,53 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// LicenseForm — mirrors LicenseUnit.pas (TLicenseForm). +// Shows a readonly multiline license text with Accept / Decline buttons. + +namespace RDPConf; + +internal sealed class LicenseForm : Form +{ + public LicenseForm(string licenseText) + { + Text = "License Agreement"; + ClientSize = new Size(600, 440); + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + StartPosition = FormStartPosition.CenterParent; + Font = new Font("Segoe UI", 9f); + + var mText = new TextBox + { + Multiline = true, + ReadOnly = true, + ScrollBars = ScrollBars.Vertical, + Text = licenseText, + Location = new Point(8, 8), + Size = new Size(576, 380), + Font = new Font("Courier New", 8.5f), + BackColor = SystemColors.Window + }; + + var bAccept = new Button + { + Text = "Accept", + DialogResult = DialogResult.OK, + Location = new Point(428, 398), + Size = new Size(75, 26) + }; + + var bDecline = new Button + { + Text = "Decline", + DialogResult = DialogResult.Cancel, + Location = new Point(509, 398), + Size = new Size(75, 26) + }; + + AcceptButton = bAccept; + CancelButton = bDecline; + + Controls.AddRange(new Control[] { mText, bAccept, bDecline }); + } +} diff --git a/src-csharp/RDPConf/MainForm.cs b/src-csharp/RDPConf/MainForm.cs new file mode 100644 index 0000000..57bc5ad --- /dev/null +++ b/src-csharp/RDPConf/MainForm.cs @@ -0,0 +1,540 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// All logic, registry keys, and label text match the Delphi original. + +using System.Runtime.InteropServices; +using RDPWrap.Common; + +namespace RDPConf; + +internal sealed class MainForm : Form +{ + // ── Controls ────────────────────────────────────────────────────────────── + private readonly CheckBox cbAllowTSConnections = new(); + private readonly CheckBox cbSingleSessionPerUser = new(); + private readonly CheckBox cbHideUsers = new(); + private readonly CheckBox cbCustomPrg = new(); + private readonly NumericUpDown seRDPPort = new(); + private readonly Label lRDPPort = new(); + private readonly GroupBox gbGeneral = new(); + + // NLA radio group + private readonly GroupBox gbNLA = new(); + private readonly RadioButton rbNLA0 = new(); + private readonly RadioButton rbNLA1 = new(); + private readonly RadioButton rbNLA2 = new(); + + // Shadow radio group + private readonly GroupBox gbShadow = new(); + private readonly RadioButton rbShadow0 = new(); + private readonly RadioButton rbShadow1 = new(); + private readonly RadioButton rbShadow2 = new(); + private readonly RadioButton rbShadow3 = new(); + private readonly RadioButton rbShadow4 = new(); + + // Diagnostics + private readonly GroupBox gbDiag = new(); + private readonly Label lService = new(); + private readonly Label lsService = new(); + private readonly Label lListener = new(); + private readonly Label lsListener = new(); + private readonly Label lWrapper = new(); + private readonly Label lsWrapper = new(); + private readonly Label lTSVer = new(); + private readonly Label lsTSVer = new(); + private readonly Label lWrapVer = new(); + private readonly Label lsWrapVer = new(); + private readonly Label lsSuppVer = new(); + + // Buttons / Timer + private readonly Button bOK = new(); + private readonly Button bCancel = new(); + private readonly Button bApply = new(); + private readonly Button bLicense = new(); + private readonly System.Windows.Forms.Timer timer = new(); + + // State (mirrors Delphi globals) + private bool _ready; + private int _oldPort; + + // ── Constructor ─────────────────────────────────────────────────────────── + + public MainForm() + { + SuspendLayout(); + BuildLayout(); + ResumeLayout(false); + PerformLayout(); + + // Wire events + cbAllowTSConnections.CheckedChanged += OnAnyChange; + cbSingleSessionPerUser.CheckedChanged += OnAnyChange; + cbHideUsers.CheckedChanged += OnAnyChange; + cbCustomPrg.CheckedChanged += OnAnyChange; + seRDPPort.ValueChanged += OnAnyChange; + rbNLA0.CheckedChanged += OnAnyChange; + rbNLA1.CheckedChanged += OnAnyChange; + rbNLA2.CheckedChanged += OnAnyChange; + rbShadow0.CheckedChanged += OnAnyChange; + rbShadow1.CheckedChanged += OnAnyChange; + rbShadow2.CheckedChanged += OnAnyChange; + rbShadow3.CheckedChanged += OnAnyChange; + rbShadow4.CheckedChanged += OnAnyChange; + bApply.Click += (_, _) => { WriteSettings(); bApply.Enabled = false; }; + bOK.Click += (_, _) => { if (bApply.Enabled) { WriteSettings(); bApply.Enabled = false; } Close(); }; + bCancel.Click += (_, _) => Close(); + bLicense.Click += OnLicenseClick; + timer.Interval = 1000; + timer.Tick += TimerTimer; + FormClosing += OnFormClosing; + Shown += OnShown; + FormClosed += (_, _) => { if (ArchHelper.Is64Bit) ArchHelper.RevertWow64Redirection(); timer.Stop(); }; + + if (ArchHelper.Is64Bit) ArchHelper.DisableWow64Redirection(); + ReadSettings(); + _ready = true; + } + + private void OnShown(object? sender, EventArgs e) + { + TimerTimer(sender, e); // immediate first tick + timer.Start(); + } + + // ── Layout ──────────────────────────────────────────────────────────────── + + private void BuildLayout() + { + Text = "RDP Wrapper Configuration"; + ClientSize = new Size(540, 383); + FormBorderStyle = FormBorderStyle.FixedSingle; + MaximizeBox = false; + StartPosition = FormStartPosition.CenterScreen; + Font = new Font("Segoe UI", 9f); + + // ── General GroupBox ────────────────────────────────────────────────── + gbGeneral.Text = "General"; + gbGeneral.Location = new Point(8, 8); + gbGeneral.Size = new Size(260, 175); + + cbAllowTSConnections.Text = "Allow Remote Desktop connections"; + cbAllowTSConnections.Location = new Point(10, 22); + cbAllowTSConnections.AutoSize = true; + + cbSingleSessionPerUser.Text = "Single session per user"; + cbSingleSessionPerUser.Location = new Point(10, 46); + cbSingleSessionPerUser.AutoSize = true; + + cbHideUsers.Text = "Hide users on logon screen"; + cbHideUsers.Location = new Point(10, 70); + cbHideUsers.AutoSize = true; + + cbCustomPrg.Text = "Custom program support (HonorLegacySettings)"; + cbCustomPrg.Location = new Point(10, 94); + cbCustomPrg.AutoSize = true; + + lRDPPort.Text = "RDP Port:"; + lRDPPort.Location = new Point(10, 124); + lRDPPort.AutoSize = true; + + seRDPPort.Location = new Point(80, 121); + seRDPPort.Minimum = 1; + seRDPPort.Maximum = 65535; + seRDPPort.Value = 3389; + seRDPPort.Width = 70; + + gbGeneral.Controls.AddRange(new Control[] + { + cbAllowTSConnections, cbSingleSessionPerUser, cbHideUsers, + cbCustomPrg, lRDPPort, seRDPPort + }); + + // ── NLA GroupBox ────────────────────────────────────────────────────── + gbNLA.Text = "Network Level Authentication"; + gbNLA.Location = new Point(276, 8); + gbNLA.Size = new Size(254, 88); + + rbNLA0.Text = "No NLA"; + rbNLA0.Location = new Point(10, 20); + rbNLA0.AutoSize = true; + + rbNLA1.Text = "Negotiate (server-side NLA)"; + rbNLA1.Location = new Point(10, 42); + rbNLA1.AutoSize = true; + + rbNLA2.Text = "Require NLA (client + server)"; + rbNLA2.Location = new Point(10, 64); + rbNLA2.AutoSize = true; + + gbNLA.Controls.AddRange(new Control[] { rbNLA0, rbNLA1, rbNLA2 }); + + // ── Shadow GroupBox ─────────────────────────────────────────────────── + gbShadow.Text = "Shadowing"; + gbShadow.Location = new Point(276, 100); + gbShadow.Size = new Size(254, 135); + + rbShadow0.Text = "Disabled"; + rbShadow0.Location = new Point(10, 20); rbShadow0.AutoSize = true; + rbShadow1.Text = "Full Access (with confirmation)"; + rbShadow1.Location = new Point(10, 42); rbShadow1.AutoSize = true; + rbShadow2.Text = "Full Access (no confirmation)"; + rbShadow2.Location = new Point(10, 62); rbShadow2.AutoSize = true; + rbShadow3.Text = "View Only (with confirmation)"; + rbShadow3.Location = new Point(10, 82); rbShadow3.AutoSize = true; + rbShadow4.Text = "View Only (no confirmation)"; + rbShadow4.Location = new Point(10, 102); rbShadow4.AutoSize = true; + + gbShadow.Controls.AddRange(new Control[] + { rbShadow0, rbShadow1, rbShadow2, rbShadow3, rbShadow4 }); + + // ── Diagnostics GroupBox ────────────────────────────────────────────── + gbDiag.Text = "Diagnostics"; + gbDiag.Location = new Point(8, 190); + gbDiag.Size = new Size(522, 140); + + AddDiagRow(gbDiag, "Service:", lService, lsService, new Point(10, 22)); + AddDiagRow(gbDiag, "Listener:", lListener, lsListener, new Point(10, 44)); + AddDiagRow(gbDiag, "Wrapper:", lWrapper, lsWrapper, new Point(10, 66)); + AddDiagRow(gbDiag, "TS version:", lTSVer, lsTSVer, new Point(10, 88)); + AddDiagRow(gbDiag, "Wrapper version:", lWrapVer, lsWrapVer, new Point(10, 110)); + + lsSuppVer.Location = new Point(280, 88); + lsSuppVer.AutoSize = true; + lsSuppVer.Visible = false; + gbDiag.Controls.Add(lsSuppVer); + + // ── Buttons ─────────────────────────────────────────────────────────── + bLicense.Text = "License"; + bLicense.Size = new Size(80, 26); + bLicense.Location = new Point(8, 345); + + bApply.Text = "Apply"; + bApply.Enabled = false; + bApply.Size = new Size(80, 26); + bApply.Location = new Point(276, 345); + + bOK.Text = "OK"; + bOK.Size = new Size(80, 26); + bOK.Location = new Point(364, 345); + + bCancel.Text = "Cancel"; + bCancel.Size = new Size(80, 26); + bCancel.Location = new Point(452, 345); + + Controls.AddRange(new Control[] + { + gbGeneral, gbNLA, gbShadow, gbDiag, + bLicense, bApply, bOK, bCancel + }); + } + + private static void AddDiagRow(GroupBox parent, string labelText, + Label lbl, Label status, Point origin) + { + lbl.Text = labelText; + lbl.Location = new Point(origin.X, origin.Y); + lbl.AutoSize = true; + + status.Text = "..."; + status.Location = new Point(origin.X + 120, origin.Y); + status.AutoSize = true; + status.ForeColor = SystemColors.GrayText; + + parent.Controls.Add(lbl); + parent.Controls.Add(status); + } + + private void OnAnyChange(object? sender, EventArgs e) + { + if (_ready) bApply.Enabled = true; + } + + // ── ReadSettings (mirrors Delphi ReadSettings) ──────────────────────────── + + private void ReadSettings() + { + const string tsKey = @"SYSTEM\CurrentControlSet\Control\Terminal Server"; + const string rdpTcp = @"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"; + const string policies = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"; + + cbAllowTSConnections.Checked = !RegistryHelper.ReadBool(tsKey, "fDenyTSConnections", false); + cbSingleSessionPerUser.Checked = RegistryHelper.ReadBool(tsKey, "fSingleSessionPerUser", false); + cbCustomPrg.Checked = RegistryHelper.ReadBool(tsKey, "HonorLegacySettings", false); + + int port = RegistryHelper.ReadInt(rdpTcp, "PortNumber", 3389); + seRDPPort.Value = Math.Clamp(port, 1, 65535); + _oldPort = port; + + int secLayer = RegistryHelper.ReadInt(rdpTcp, "SecurityLayer", 0); + int userAuth = RegistryHelper.ReadInt(rdpTcp, "UserAuthentication", 0); + int shadow = RegistryHelper.ReadInt(rdpTcp, "Shadow", -1); + + _ = (secLayer, userAuth) switch + { + (0, 0) => rbNLA0.Checked = true, + (1, 0) => rbNLA1.Checked = true, + (2, 1) => rbNLA2.Checked = true, + _ => rbNLA0.Checked = true + }; + + SetShadowRadio(shadow); + + cbHideUsers.Checked = RegistryHelper.ReadBool(policies, "dontdisplaylastusername", false); + } + + private void SetShadowRadio(int idx) + { + RadioButton[] rbs = { rbShadow0, rbShadow1, rbShadow2, rbShadow3, rbShadow4 }; + if (idx >= 0 && idx < rbs.Length) + rbs[idx].Checked = true; + } + + private int GetShadowIndex() + { + RadioButton[] rbs = { rbShadow0, rbShadow1, rbShadow2, rbShadow3, rbShadow4 }; + for (int i = 0; i < rbs.Length; i++) + if (rbs[i].Checked) return i; + return -1; + } + + // ── WriteSettings (mirrors Delphi WriteSettings) ────────────────────────── + + private void WriteSettings() + { + const string tsKey = @"SYSTEM\CurrentControlSet\Control\Terminal Server"; + const string rdpTcp = @"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"; + const string policiesRdp = @"SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services"; + const string policies = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"; + + RegistryHelper.WriteBool(tsKey, "fDenyTSConnections", !cbAllowTSConnections.Checked); + RegistryHelper.WriteBool(tsKey, "fSingleSessionPerUser", cbSingleSessionPerUser.Checked); + RegistryHelper.WriteBool(tsKey, "HonorLegacySettings", cbCustomPrg.Checked); + + int newPort = (int)seRDPPort.Value; + RegistryHelper.WriteInt(rdpTcp, "PortNumber", newPort); + if (_oldPort != newPort) + { + _oldPort = newPort; + ProcessHelper.ExecWait( + $"netsh advfirewall firewall set rule name=\"Remote Desktop\" new localport={newPort}"); + } + + // NLA + (int sl, int ua) = (rbNLA0.Checked, rbNLA1.Checked, rbNLA2.Checked) switch + { + (true, _, _ ) => (0, 0), + (_, true, _ ) => (1, 0), + (_, _, true) => (2, 1), + _ => (-1, -1) + }; + if (sl >= 0) + { + RegistryHelper.WriteInt(rdpTcp, "SecurityLayer", sl); + RegistryHelper.WriteInt(rdpTcp, "UserAuthentication", ua); + } + + // Shadow + int shadowIdx = GetShadowIndex(); + if (shadowIdx >= 0) + { + RegistryHelper.WriteInt(rdpTcp, "Shadow", shadowIdx); + RegistryHelper.WriteInt(policiesRdp, "Shadow", shadowIdx); + } + + RegistryHelper.WriteBool(policies, "dontdisplaylastusername", cbHideUsers.Checked); + } + + // ── TimerTimer (mirrors Delphi TimerTimer) ──────────────────────────────── + + private void TimerTimer(object? sender, EventArgs e) + { + // ── Wrapper state ── + string wrapperPath = string.Empty; + int wrapState = IsWrapperInstalled(ref wrapperPath); + bool checkSupp = false; + string iniPath = string.Empty; + + switch (wrapState) + { + case -1: + SetStatus(lsWrapper, "Unknown", SystemColors.GrayText); + break; + case 0: + SetStatus(lsWrapper, "Not installed", SystemColors.GrayText); + break; + case 1: + SetStatus(lsWrapper, "Installed", Color.Green); + iniPath = Path.Combine( + Path.GetDirectoryName(ArchHelper.ExpandPath(wrapperPath))!, + "rdpwrap.ini"); + checkSupp = File.Exists(iniPath); + break; + case 2: + SetStatus(lsWrapper, "3rd-party", Color.Red); + break; + } + + // ── Service state ── + int svcState = GetTermSrvState(); + // dwCurrentState constants (mirrors NativeMethods SERVICE_* constants) + string svcText = svcState switch + { + 1 => "Stopped", + 2 => "Starting...", + 3 => "Stopping...", + 4 => "Running", + 5 => "Resuming...", + 6 => "Suspending...", + 7 => "Suspended", + _ => "Unknown" + }; + Color svcColor = svcState == 4 ? Color.Green // SERVICE_RUNNING + : svcState == 1 ? Color.Red // SERVICE_STOPPED + : SystemColors.GrayText; + SetStatus(lsService, svcText, svcColor); + + // ── Listener ── + bool listening = IsListenerWorking(); + SetStatus(lsListener, + listening ? "Listening" : "Not listening", + listening ? Color.Green : Color.Red); + + // ── Wrapper version ── + string wrapExp = ArchHelper.ExpandPath(wrapperPath); + var wrapVer = string.IsNullOrEmpty(wrapperPath) ? null + : FileVersionHelper.GetVersion(wrapExp); + if (wrapVer is null) + SetStatus(lsWrapVer, "N/A", SystemColors.GrayText); + else + SetStatus(lsWrapVer, wrapVer.ToString(), SystemColors.WindowText); + + // ── TS version ── + var tsVer = FileVersionHelper.GetVersionExpanded(@"%SystemRoot%\System32\termsrv.dll"); + if (tsVer is null) + { + SetStatus(lsTSVer, "N/A", SystemColors.GrayText); + lsSuppVer.Visible = false; + return; + } + + SetStatus(lsTSVer, tsVer.ToString(), SystemColors.WindowText); + lsSuppVer.Visible = checkSupp; + + if (checkSupp) + { + string iniContent = IniHelper.LoadText(iniPath); + int level = IniHelper.CheckSupportLevel(iniContent, tsVer); + (string suppText, Color suppColor) = level switch + { + 0 => ("[not supported]", Color.Red), + 1 => ("[supported partially]", Color.Olive), + _ => ("[fully supported]", Color.Green) + }; + lsSuppVer.Text = suppText; + lsSuppVer.ForeColor = suppColor; + } + } + + // ── Helper: IsWrapperInstalled ──────────────────────────────────────────── + + /// -1=error, 0=not installed, 1=installed, 2=3rd-party + private static int IsWrapperInstalled(ref string wrapperPath) + { + wrapperPath = string.Empty; + var host = RegistryHelper.ReadString( + @"SYSTEM\CurrentControlSet\Services\TermService", "ImagePath") ?? string.Empty; + + if (!host.Contains("svchost.exe", StringComparison.OrdinalIgnoreCase)) return 2; + + var svcDll = RegistryHelper.ReadString( + @"SYSTEM\CurrentControlSet\Services\TermService\Parameters", "ServiceDll") ?? string.Empty; + + if (svcDll.Length == 0) return -1; + + if (!svcDll.Contains("termsrv.dll", StringComparison.OrdinalIgnoreCase) && + !svcDll.Contains("rdpwrap.dll", StringComparison.OrdinalIgnoreCase)) + return 2; + + if (svcDll.Contains("rdpwrap.dll", StringComparison.OrdinalIgnoreCase)) + { + wrapperPath = svcDll; + return 1; + } + return 0; + } + + // ── Helper: GetTermSrvState (via SCM) ───────────────────────────────────── + + private static int GetTermSrvState() + => ServiceHelper.GetCurrentState("TermService"); + + // ── Helper: IsListenerWorking (via WinStationEnumerateW) ────────────────── + + private static bool IsListenerWorking() + { + if (!NativeMethods.WinStationEnumerate(IntPtr.Zero, + out IntPtr pSessions, out uint count)) return false; + + bool found = false; + try + { + // Each entry is { DWORD SessionId; WCHAR[34] Name; DWORD State } + // = 4 + 68 + 4 = 76 bytes on x64 (with natural alignment the struct is 76 bytes) + const int stride = 76; // sizeof(WTS_SESSION_INFOW) — matches Delphi packed array + for (uint i = 0; i < count; i++) + { + IntPtr entry = pSessions + (int)(i * stride); + // Name is at offset 4, WCHAR[34] + string name = Marshal.PtrToStringUni(entry + 4, 34).TrimEnd('\0'); + if (name.Equals("RDP-Tcp", StringComparison.Ordinal)) + { + found = true; + break; + } + } + } + finally + { + NativeMethods.WinStationFreeMemory(pSessions); + } + + return found; + } + + // ── Helper: SetStatus ───────────────────────────────────────────────────── + + private static void SetStatus(Label lbl, string text, Color color) + { + lbl.Text = text; + lbl.ForeColor = color; + } + + // ── OnFormClosing — unsaved-changes guard ───────────────────────────────── + + private void OnFormClosing(object? sender, FormClosingEventArgs e) + { + if (bApply.Enabled) + { + var result = MessageBox.Show( + "Settings are not saved. Do you want to exit?", + "Warning", + MessageBoxButtons.YesNo, + MessageBoxIcon.Warning); + e.Cancel = result != DialogResult.Yes; + } + } + + // ── License button ──────────────────────────────────────────────────────── + + private void OnLicenseClick(object? sender, EventArgs e) + { + var text = ResourceHelper.ReadText( + "RDPConf.Resources.license.txt", + System.Reflection.Assembly.GetExecutingAssembly()); + text ??= ResourceHelper.ReadText("RDPWInst.Resources.license.txt") ?? "(license not found)"; + + using var dlg = new LicenseForm(text); + if (dlg.ShowDialog(this) != DialogResult.OK) + Application.Exit(); + } +} diff --git a/src-csharp/RDPConf/Program.cs b/src-csharp/RDPConf/Program.cs new file mode 100644 index 0000000..9270d84 --- /dev/null +++ b/src-csharp/RDPConf/Program.cs @@ -0,0 +1,15 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// RDPConf — WinForms configuration GUI entry point. + +namespace RDPConf; + +internal static class Program +{ + [STAThread] + internal static void Main() + { + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); + } +} diff --git a/src-csharp/RDPConf/RDPConf.csproj b/src-csharp/RDPConf/RDPConf.csproj new file mode 100644 index 0000000..96725c9 --- /dev/null +++ b/src-csharp/RDPConf/RDPConf.csproj @@ -0,0 +1,24 @@ + + + WinExe + true + RDPConf + RDPConf + app.manifest + app.ico + WinForms configuration GUI for RDP Wrapper — manage concurrent session limits, RDP port, and security settings. + + + + + + + + + + + + + + + diff --git a/src-csharp/RDPConf/app.ico b/src-csharp/RDPConf/app.ico new file mode 100644 index 0000000..b083a31 Binary files /dev/null and b/src-csharp/RDPConf/app.ico differ diff --git a/src-csharp/RDPConf/app.manifest b/src-csharp/RDPConf/app.manifest new file mode 100644 index 0000000..a24b3eb --- /dev/null +++ b/src-csharp/RDPConf/app.manifest @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src-csharp/RDPConf/packages.lock.json b/src-csharp/RDPConf/packages.lock.json new file mode 100644 index 0000000..59ebcea --- /dev/null +++ b/src-csharp/RDPConf/packages.lock.json @@ -0,0 +1,10 @@ +{ + "version": 1, + "dependencies": { + "net10.0-windows7.0": { + "rdpwrap": { + "type": "Project" + } + } + } +} \ No newline at end of file diff --git a/src-csharp/RDPOffsetFinder b/src-csharp/RDPOffsetFinder new file mode 160000 index 0000000..68da37a --- /dev/null +++ b/src-csharp/RDPOffsetFinder @@ -0,0 +1 @@ +Subproject commit 68da37acab6593c329776644944f55695a131731 diff --git a/src-csharp/RDPWInst/InstallerEngine.cs b/src-csharp/RDPWInst/InstallerEngine.cs new file mode 100644 index 0000000..d22b93d --- /dev/null +++ b/src-csharp/RDPWInst/InstallerEngine.cs @@ -0,0 +1,744 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// InstallerEngine — translates every procedure in RDPWInst.dpr to C#. + +using System.Reflection; +using RDPWrap.Common; + +namespace RDPWInst; + +/// +/// Orchestrates install / uninstall / update / restart of the RDP Wrapper. +/// All public methods return an exit code (0 = success). +/// +internal sealed class InstallerEngine +{ + // ── State (mirrors Delphi globals) ──────────────────────────────────────── + + private bool _installed; + private bool _online; + private string _wrapPath = string.Empty; + private string _termServicePath = string.Empty; + private string _termSrvVerTxt = string.Empty; + private uint _termServicePid; + private string[] _shareServices = Array.Empty(); + + private const string TermService = "TermService"; + + // Latest release download base URL + private const string ReleaseBaseUrl = + "https://github.com/sjackson0109/rdpwrap/releases/latest/download/"; + + // ── Public entry points ─────────────────────────────────────────────────── + + /// + /// Install the wrapper. Mirrors the -i branch in RDPWInst.dpr. + /// + public int Install(bool toSystem32, bool online, bool force = false) + { + if (_installed) + { + if (!force) + { + Console.WriteLine("[*] RDP Wrapper Library is already installed."); + return unchecked((int)NativeMethods.ERROR_ACCESS_DENIED); + } + + Console.WriteLine("[*] Existing installation detected -- uninstalling first (force mode)..."); + int urc = Uninstall(keepSettings: true); + if (urc != 0) + { + Console.Error.WriteLine($"[-] Force-uninstall failed (code {urc}) -- aborting install."); + return urc; + } + // Refresh state: after a successful uninstall _installed should now be false. + CheckInstall(); + } + + Console.WriteLine("[*] Notice to user:"); + Console.WriteLine(" - By using all or any portion of this software, you are agreeing"); + Console.WriteLine(" to be bound by all the terms and conditions of the license agreement."); + Console.WriteLine(" - To read the license agreement, run the installer with -l parameter."); + Console.WriteLine(" - If you do not agree to any terms of the license agreement,"); + Console.WriteLine(" do not use the software."); + Console.WriteLine("[*] Installing..."); + + _wrapPath = toSystem32 + ? @"%SystemRoot%\system32\rdpwrap.dll" + : @"%ProgramFiles%\RDP Wrapper\rdpwrap.dll"; + + if (ArchHelper.Is64Bit) ArchHelper.DisableWow64Redirection(); + + CheckTermsrvVersion(); + CheckTermsrvProcess(); + + Console.WriteLine("[*] Extracting files..."); + _online = online; + ExtractFiles(); + + Console.WriteLine("[*] Checking INI coverage for installed termsrv.dll version..."); + TryAutoGenerateOffsets(); + + Console.WriteLine("[*] Configuring service library..."); + SetWrapperDll(); + + Console.WriteLine("[*] Checking dependencies..."); + CheckTermsrvDependencies(); + + Console.WriteLine("[*] Terminating service..."); + SecurityHelper.AddPrivilege(NativeMethods.SE_DEBUG_NAME); + ProcessHelper.KillProcess(_termServicePid); + Thread.Sleep(1000); + + RestartSharedServices(); + Thread.Sleep(500); + ServiceHelper.StartService(TermService); + Thread.Sleep(500); + + Console.WriteLine("[*] Configuring registry..."); + TSConfigRegistry(enable: true); + Console.WriteLine("[*] Configuring firewall..."); + TSConfigFirewall(enable: true); + + Console.WriteLine("[+] Successfully installed."); + + if (ArchHelper.Is64Bit) ArchHelper.RevertWow64Redirection(); + return 0; + } + + /// + /// Uninstall the wrapper. Mirrors the -u branch. + /// + public int Uninstall(bool keepSettings) + { + if (!_installed) + { + Console.WriteLine("[*] RDP Wrapper Library is not installed."); + return unchecked((int)NativeMethods.ERROR_ACCESS_DENIED); + } + + Console.WriteLine("[*] Uninstalling..."); + if (ArchHelper.Is64Bit) ArchHelper.DisableWow64Redirection(); + + CheckTermsrvProcess(); + + Console.WriteLine("[*] Resetting service library..."); + ResetServiceDll(); + + Console.WriteLine("[*] Terminating service..."); + SecurityHelper.AddPrivilege(NativeMethods.SE_DEBUG_NAME); + ProcessHelper.KillProcess(_termServicePid); + Thread.Sleep(1000); + + Console.WriteLine("[*] Removing files..."); + DeleteFiles(); + + RestartSharedServices(); + Thread.Sleep(500); + ServiceHelper.StartService(TermService); + Thread.Sleep(500); + + if (!keepSettings) + { + Console.WriteLine("[*] Configuring registry..."); + TSConfigRegistry(enable: false); + Console.WriteLine("[*] Configuring firewall..."); + TSConfigFirewall(enable: false); + } + + if (ArchHelper.Is64Bit) ArchHelper.RevertWow64Redirection(); + Console.WriteLine("[+] Successfully uninstalled."); + return 0; + } + + /// + /// Download the latest rdpwrap.ini. Mirrors the -w / CheckUpdate branch. + /// + public int Update() + { + if (!_installed) + { + Console.WriteLine("[*] RDP Wrapper Library is not installed."); + return unchecked((int)NativeMethods.ERROR_ACCESS_DENIED); + } + + Console.WriteLine("[*] Checking for updates..."); + return CheckUpdate(); + } + + /// + /// Force-restart Terminal Services. Mirrors the -r branch. + /// + public int Restart() + { + Console.WriteLine("[*] Restarting..."); + CheckTermsrvProcess(); + + Console.WriteLine("[*] Terminating service..."); + SecurityHelper.AddPrivilege(NativeMethods.SE_DEBUG_NAME); + ProcessHelper.KillProcess(_termServicePid); + Thread.Sleep(1000); + + RestartSharedServices(); + Thread.Sleep(500); + ServiceHelper.StartService(TermService); + + Console.WriteLine("[+] Done."); + return 0; + } + + // ── CheckInstall ────────────────────────────────────────────────────────── + + /// + /// Validates the TermService registry image path and sets + /// and . + /// Mirrors the Delphi CheckInstall procedure. + /// + public void CheckInstall() + { + const string svcKey = @"SYSTEM\CurrentControlSet\Services\TermService"; + const string paramsKey = @"SYSTEM\CurrentControlSet\Services\TermService\Parameters"; + + var imagePath = RegistryHelper.ReadString(svcKey, "ImagePath") ?? string.Empty; + if (!imagePath.Contains("svchost.exe", StringComparison.OrdinalIgnoreCase) && + !imagePath.Contains("svchost -k", StringComparison.OrdinalIgnoreCase)) + { + Console.Error.WriteLine("[-] TermService is hosted in a custom application (BeTwin, etc.) - unsupported."); + Console.Error.WriteLine($"[*] ImagePath: \"{imagePath}\"."); + Environment.Exit(unchecked((int)NativeMethods.ERROR_NOT_SUPPORTED)); + } + + var serviceDll = RegistryHelper.ReadString(paramsKey, "ServiceDll") ?? string.Empty; + if (!serviceDll.Contains("termsrv.dll", StringComparison.OrdinalIgnoreCase) && + !serviceDll.Contains("rdpwrap.dll", StringComparison.OrdinalIgnoreCase)) + { + Console.Error.WriteLine("[-] Another third-party TermService library is installed."); + Console.Error.WriteLine($"[*] ServiceDll: \"{serviceDll}\"."); + Environment.Exit(unchecked((int)NativeMethods.ERROR_NOT_SUPPORTED)); + } + + _termServicePath = serviceDll; + _installed = serviceDll.Contains("rdpwrap.dll", StringComparison.OrdinalIgnoreCase); + } + + // ── CheckTermsrvProcess ──────────────────────────────────────────────────── + + /// + /// Finds the TermService process ID, auto-starts the service if needed, + /// and collects co-hosted service names. Mirrors CheckTermsrvProcess. + /// + private void CheckTermsrvProcess() + { + bool started = false; + retry: + var services = ServiceHelper.EnumServiceProcesses(); + var ts = services.FirstOrDefault(s => + s.ServiceName.Equals(TermService, StringComparison.OrdinalIgnoreCase)); + + if (ts is null) + { + Console.Error.WriteLine($"[-] {TermService} not found."); + Environment.Exit(unchecked((int)NativeMethods.ERROR_SERVICE_DOES_NOT_EXIST)); + return; + } + + if (ts.ProcessId == 0) + { + if (started) + { + Console.Error.WriteLine("[-] Failed to set up TermService. Unknown error."); + Environment.Exit(unchecked((int)NativeMethods.ERROR_SERVICE_NOT_ACTIVE)); + return; + } + ServiceHelper.SetStartType(TermService, NativeMethods.SERVICE_AUTO_START); + ServiceHelper.StartService(TermService); + started = true; + goto retry; + } + + _termServicePid = ts.ProcessId; + Console.WriteLine($"[+] TermService found (pid {_termServicePid})."); + + _shareServices = services + .Where(s => s.ProcessId == _termServicePid && + !s.ServiceName.Equals(TermService, StringComparison.OrdinalIgnoreCase)) + .Select(s => s.ServiceName) + .ToArray(); + + if (_shareServices.Length > 0) + Console.WriteLine($"[*] Shared services found: {string.Join(", ", _shareServices)}"); + else + Console.WriteLine("[*] No shared services found."); + } + + // ── CheckTermsrvDependencies ─────────────────────────────────────────────── + + /// + /// Ensures CertPropSvc and SessionEnv are not disabled. + /// Mirrors the Delphi CheckTermsrvDependencies procedure. + /// + private static void CheckTermsrvDependencies() + { + foreach (var svc in new[] { "CertPropSvc", "SessionEnv" }) + { + if (ServiceHelper.GetStartType(svc) == (int)NativeMethods.SERVICE_DISABLED) + ServiceHelper.SetStartType(svc, NativeMethods.SERVICE_DEMAND_START); + } + } + + // ── CheckTermsrvVersion ──────────────────────────────────────────────────── + + /// + /// Reads the termsrv.dll version and classifies support level. + /// Mirrors the Delphi CheckTermsrvVersion procedure. + /// + private void CheckTermsrvVersion() + { + var fv = FileVersionHelper.GetVersionExpanded(_termServicePath); + if (fv is null) + { + Console.Error.WriteLine("[-] Could not read termsrv.dll version."); + return; + } + + _termSrvVerTxt = fv.ToString(); + Console.WriteLine($"[*] Terminal Services version: {_termSrvVerTxt}"); + + // Unsupported legacy versions + if (fv.Major == 5) + { + var label = (ArchHelper.Arch == 32) ? "x86" : "x64"; + Console.WriteLine($"[!] Windows XP / Server 2003 ({label}) is not supported."); + return; + } + + // Load the built-in INI to check support level + var builtInIni = ResourceHelper.ReadText( + "RDPWInst.Resources.rdpwrap.ini", + Assembly.GetExecutingAssembly()) ?? string.Empty; + + int level = IniHelper.CheckSupportLevel(builtInIni, fv); + + switch (level) + { + case 0: + Console.WriteLine("[-] This version of Terminal Services is not supported."); + Console.WriteLine("Try running \"update.bat\" or \"RDPWInst -w\" to download latest INI file."); + break; + case 1: + Console.WriteLine("[!] This version of Terminal Services is supported partially."); + Console.WriteLine("It means you may have some limitations such as only 2 concurrent sessions."); + Console.WriteLine("Try running \"update.bat\" or \"RDPWInst -w\" to download latest INI file."); + break; + case 2: + Console.WriteLine("[+] This version of Terminal Services is fully supported."); + break; + } + } + + // ── TSConfigRegistry ────────────────────────────────────────────────────── + + /// + /// Writes (or clears) the TS-enable registry values. + /// Mirrors the Delphi TSConfigRegistry procedure. + /// + private static void TSConfigRegistry(bool enable) + { + const string tsKey = @"SYSTEM\CurrentControlSet\Control\Terminal Server"; + const string licKey = @"SYSTEM\CurrentControlSet\Control\Terminal Server\Licensing Core"; + const string winlogon = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"; + const string addInsBase = @"SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns"; + + RegistryHelper.WriteBool(tsKey, "fDenyTSConnections", !enable); + + if (enable) + { + RegistryHelper.WriteBool(licKey, "EnableConcurrentSessions", true); + RegistryHelper.WriteBool(winlogon, "AllowMultipleTSSessions", true); + RegistryHelper.WriteBool(tsKey, "AllowRemoteRPC", true); + RegistryHelper.WriteBool(tsKey, "EnableLinkedConnections", true); + + // AddIns sub-keys (only create if the parent key is absent) + if (Microsoft.Win32.Registry.LocalMachine.OpenSubKey(addInsBase) is null) + { + RegistryHelper.WriteString(addInsBase + @"\Clip Redirector", "Name", "RDPClip"); + RegistryHelper.WriteInt (addInsBase + @"\Clip Redirector", "Type", 3); + RegistryHelper.WriteString(addInsBase + @"\DND Redirector", "Name", "RDPDND"); + RegistryHelper.WriteInt (addInsBase + @"\DND Redirector", "Type", 3); + RegistryHelper.WriteInt (addInsBase + @"\Dynamic VC", "Type", -1); + } + } + } + + // ── TSConfigFirewall ────────────────────────────────────────────────────── + + private static void TSConfigFirewall(bool enable) + { + if (enable) + { + ProcessHelper.ExecWait( + "netsh advfirewall firewall add rule name=\"Remote Desktop\" " + + "dir=in protocol=tcp localport=3389 profile=any action=allow"); + ProcessHelper.ExecWait( + "netsh advfirewall firewall add rule name=\"Remote Desktop\" " + + "dir=in protocol=udp localport=3389 profile=any action=allow"); + } + else + { + ProcessHelper.ExecWait( + "netsh advfirewall firewall delete rule name=\"Remote Desktop\""); + } + } + + // ── ExtractFiles ────────────────────────────────────────────────────────── + + /// + /// Creates the install directory, sets ACLs, downloads or extracts the + /// INI file, and extracts the correct rdpwrap DLL + optional helpers. + /// Mirrors the Delphi ExtractFiles procedure. + /// + private void ExtractFiles() + { + var asm = Assembly.GetExecutingAssembly(); + var fullPath = ArchHelper.ExpandPath(_wrapPath); + var dir = Path.GetDirectoryName(fullPath)!; + + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + Console.WriteLine($"[+] Folder created: {dir}"); + SecurityHelper.GrantSidFullAccess(dir, "S-1-5-18"); // Local System + SecurityHelper.GrantSidFullAccess(dir, "S-1-5-6"); // Service group + } + + // ── INI file ── + var iniPath = Path.Combine(dir, "rdpwrap.ini"); + if (_online) + { + Console.WriteLine("[*] Downloading latest INI file..."); + var content = HttpHelper.DownloadString(ReleaseBaseUrl + "rdpwrap.ini"); + if (content is not null) + { + File.WriteAllText(iniPath, content, System.Text.Encoding.UTF8); + Console.WriteLine($"[+] Latest INI file -> {iniPath}"); + } + else + { + Console.WriteLine("[-] Failed to get online INI file, using built-in."); + _online = false; + } + } + + if (!_online) + { + // Try a local rdpwrap.ini beside the installer first + var localIni = Path.Combine( + Path.GetDirectoryName(Environment.ProcessPath ?? string.Empty) ?? ".", + "rdpwrap.ini"); + + if (File.Exists(localIni)) + { + File.Copy(localIni, iniPath, overwrite: true); + Console.WriteLine($"[+] Current INI file -> {iniPath}"); + } + else + { + ResourceHelper.ExtractToDisk("RDPWInst.Resources.rdpwrap.ini", iniPath, asm); + } + } + + // ── Core DLL ── + var dllRes = ArchHelper.Is64Bit ? "RDPWInst.Resources.rdpw64.dll" + : "RDPWInst.Resources.rdpw32.dll"; + ResourceHelper.ExtractToDisk(dllRes, fullPath, asm); + + // ── Optional helpers (Vista / Win7 clipboard redirect, Win10 RFX codec) ── + ExtractOptionalHelper(asm, dir); + } + + private void ExtractOptionalHelper(Assembly asm, string dir) + { + var fv = FileVersionHelper.GetVersionExpanded(_termServicePath); + if (fv is null) return; + + var arch = ArchHelper.Is64Bit ? "64" : "32"; + + // rdpclip: Vista 6.0 and Win7 6.1 + string? clipRes = (fv.Major, fv.Minor) switch + { + (6, 0) => $"RDPWInst.Resources.rdpclip60{arch}.exe", + (6, 1) => $"RDPWInst.Resources.rdpclip61{arch}.exe", + _ => null + }; + if (clipRes is not null) + { + var dest = ArchHelper.ExpandPath(@"%SystemRoot%\System32\rdpclip.exe"); + if (!File.Exists(dest)) + ResourceHelper.ExtractToDisk(clipRes, dest, asm); + } + + // rfxvmt.dll: Windows 10 (6.10.x maps to 10.0 in NT versioning) + if (fv.Major == 10 && fv.Minor == 0) + { + var rfxRes = $"RDPWInst.Resources.rfxvmt{arch}.dll"; + var rfxDest = ArchHelper.ExpandPath(@"%SystemRoot%\System32\rfxvmt.dll"); + if (!File.Exists(rfxDest)) + ResourceHelper.ExtractToDisk(rfxRes, rfxDest, asm); + } + } + + // ── SetWrapperDll / ResetServiceDll ────────────────────────────────────── + + private void SetWrapperDll() + { + const string key = @"SYSTEM\CurrentControlSet\Services\TermService\Parameters"; + RegistryHelper.WriteExpandString(key, "ServiceDll", _wrapPath); + + // Vista 6.0 workaround — reg.exe write to bypass WOW64 quirk + var fv = FileVersionHelper.GetVersionExpanded(_termServicePath); + if (fv is { Major: 6, Minor: 0 } && ArchHelper.Is64Bit) + { + ProcessHelper.ExecWait( + $"\"{ArchHelper.ExpandPath("%SystemRoot%")}\\system32\\reg.exe\" " + + $"add HKLM\\SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters " + + $"/v ServiceDll /t REG_EXPAND_SZ /d \"{_wrapPath}\" /f"); + } + } + + private static void ResetServiceDll() + { + const string key = @"SYSTEM\CurrentControlSet\Services\TermService\Parameters"; + RegistryHelper.WriteExpandString(key, "ServiceDll", + @"%SystemRoot%\System32\termsrv.dll"); + } + + // ── DeleteFiles ─────────────────────────────────────────────────────────── + + private void DeleteFiles() + { + var fullPath = ArchHelper.ExpandPath(_termServicePath); + var dir = Path.GetDirectoryName(fullPath)!; + var iniPath = Path.Combine(dir, "rdpwrap.ini"); + + TryDelete(iniPath); + TryDelete(fullPath); + TryRemoveDir(dir); + } + + private static void TryDelete(string path) + { + try + { + File.Delete(path); + Console.WriteLine($"[+] Removed file: {path}"); + } + catch (Exception ex) + { + Console.Error.WriteLine($"[-] DeleteFile error: {ex.Message}"); + } + } + + private static void TryRemoveDir(string dir) + { + try + { + Directory.Delete(dir); + Console.WriteLine($"[+] Removed folder: {dir}"); + } + catch (Exception ex) + { + Console.Error.WriteLine($"[-] RemoveDirectory error: {ex.Message}"); + } + } + + // ── TryAutoGenerateOffsets ──────────────────────────────────────────────── + + /// + /// If the running termsrv.dll version is absent from rdpwrap.ini, downloads + /// RDPWrapOffsetFinder + Zydis from the release assets and runs the finder + /// to append generated offsets. Mirrors the Delphi TryAutoGenerateOffsets. + /// + private void TryAutoGenerateOffsets() + { + if (string.IsNullOrEmpty(_termSrvVerTxt)) return; + + var fullPath = ArchHelper.ExpandPath(_wrapPath); + var iniPath = Path.Combine(Path.GetDirectoryName(fullPath)!, "rdpwrap.ini"); + + if (IniHelper.HasSection(iniPath, _termSrvVerTxt)) + { + Console.WriteLine($"[+] Version {_termSrvVerTxt} is covered in INI."); + return; + } + + Console.WriteLine($"[!] Version {_termSrvVerTxt} not found in INI."); + Console.WriteLine("[*] Attempting automatic offset generation via RDPWrapOffsetFinder..."); + + var archSuffix = ArchHelper.Is64Bit ? "_x64" : "_x86"; + var tempDir = Path.Combine(Path.GetTempPath(), "rdpwrapoffset"); + + try { Directory.CreateDirectory(tempDir); } + catch + { + Console.Error.WriteLine("[-] Could not create temp directory. Skipping auto-generation."); + return; + } + + var exePath = Path.Combine(tempDir, "RDPWrapOffsetFinder.exe"); + var dllPath = Path.Combine(tempDir, "Zydis.dll"); + + Console.WriteLine($"[*] Downloading RDPWrapOffsetFinder{archSuffix}.exe ..."); + if (!HttpHelper.DownloadFile(ReleaseBaseUrl + $"RDPWrapOffsetFinder{archSuffix}.exe", exePath)) + { + Console.Error.WriteLine("[-] Download failed. The release asset may not yet be published."); + Console.Error.WriteLine("[!] Run the publish-ini workflow on the sjackson0109/rdpwrap repository,"); + Console.Error.WriteLine("[!] then re-run this installer to enable auto-generation."); + return; + } + + Console.WriteLine($"[*] Downloading Zydis{archSuffix}.dll ..."); + if (!HttpHelper.DownloadFile(ReleaseBaseUrl + $"Zydis{archSuffix}.dll", dllPath)) + { + Console.Error.WriteLine("[-] Zydis download failed. Skipping auto-generation."); + File.Delete(exePath); + return; + } + + Console.WriteLine($"[*] Running offset finder for termsrv.dll {_termSrvVerTxt} ..."); + // Run via cmd.exe so that >> redirect to the INI file functions correctly + var sysCmd = ArchHelper.ExpandPath(@"%SystemRoot%\System32\cmd.exe"); + ProcessHelper.ExecWait($"\"{sysCmd}\" /c \"\"{exePath}\" >> \"{iniPath}\"\""); + + if (IniHelper.HasSection(iniPath, _termSrvVerTxt)) + Console.WriteLine($"[+] Offsets generated successfully for version {_termSrvVerTxt}"); + else + Console.WriteLine($"[!] Offset finder ran but [{_termSrvVerTxt}] was not added. " + + "Session may be limited or unstable for this build."); + + // Clean up temporary tool files + try + { + File.Delete(exePath); + File.Delete(dllPath); + Directory.Delete(tempDir); + } + catch { /* best-effort */ } + } + + // ── CheckUpdate (GitINIFile path) ───────────────────────────────────────── + + private int CheckUpdate() + { + var fullPath = ArchHelper.ExpandPath(_termServicePath); + var iniPath = Path.Combine(Path.GetDirectoryName(fullPath)!, "rdpwrap.ini"); + + if (!TryGetIniDate(iniPath, null, out int oldDate)) + return unchecked((int)NativeMethods.ERROR_ACCESS_DENIED); + + Console.WriteLine($"[*] Current update date: {FormatDate(oldDate)}"); + + var latest = HttpHelper.DownloadString(ReleaseBaseUrl + "rdpwrap.ini"); + if (latest is null) + { + Console.Error.WriteLine("[-] Failed to download latest INI from GitHub."); + return unchecked((int)NativeMethods.ERROR_ACCESS_DENIED); + } + + if (!TryGetIniDate(null, latest, out int newDate)) + return unchecked((int)NativeMethods.ERROR_ACCESS_DENIED); + + Console.WriteLine($"[*] Latest update date: {FormatDate(newDate)}"); + + if (newDate == oldDate) + { + Console.WriteLine("[*] Everything is up to date."); + return 0; + } + + if (newDate > oldDate) + { + Console.WriteLine("[+] New update is available, updating..."); + CheckTermsrvProcess(); + + Console.WriteLine("[*] Terminating service..."); + SecurityHelper.AddPrivilege(NativeMethods.SE_DEBUG_NAME); + ProcessHelper.KillProcess(_termServicePid); + Thread.Sleep(1000); + + RestartSharedServices(); + Thread.Sleep(500); + + File.WriteAllText(iniPath, latest, System.Text.Encoding.UTF8); + Console.WriteLine($"[+] INI file updated: {iniPath}"); + + // Recompute version for offset generation + var fv = FileVersionHelper.GetVersionExpanded(_termServicePath); + if (fv is not null) _termSrvVerTxt = fv.ToString(); + + Console.WriteLine("[*] Checking INI coverage for installed termsrv.dll version..."); + TryAutoGenerateOffsets(); + + ServiceHelper.StartService(TermService); + Console.WriteLine("[+] Update completed."); + } + else + { + Console.WriteLine("[*] Your INI file is newer than public file. Are you a developer? :)"); + } + + return 0; + } + + // ── Helpers ─────────────────────────────────────────────────────────────── + + private void RestartSharedServices() + { + foreach (var svc in _shareServices) + ServiceHelper.StartService(svc); + } + + /// + /// Parses the Updated=YYYYMMDD line from an INI file or string. + /// Mirrors the Delphi CheckINIDate function. + /// + private static bool TryGetIniDate(string? filePath, string? content, out int date) + { + date = 0; + IEnumerable lines; + + if (filePath is not null) + { + if (!File.Exists(filePath)) + { + Console.Error.WriteLine("[-] Failed to read INI file."); + return false; + } + lines = File.ReadLines(filePath); + } + else + { + lines = (content ?? string.Empty).Split('\n'); + } + + foreach (var line in lines) + { + var trimmed = line.TrimEnd('\r'); + if (!trimmed.StartsWith("Updated=", StringComparison.Ordinal)) continue; + + var raw = trimmed["Updated=".Length..].Replace("-", ""); + if (int.TryParse(raw, out date)) return true; + + Console.Error.WriteLine("[-] Wrong INI date format."); + return false; + } + + Console.Error.WriteLine("[-] Failed to check INI date (Updated= line not found)."); + return false; + } + + private static string FormatDate(int d) + { + int y = d / 10000, m = (d / 100) % 100, day = d % 100; + return $"{y}.{m:D2}.{day:D2}"; + } +} diff --git a/src-csharp/RDPWInst/Program.cs b/src-csharp/RDPWInst/Program.cs new file mode 100644 index 0000000..f6dc5cb --- /dev/null +++ b/src-csharp/RDPWInst/Program.cs @@ -0,0 +1,114 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +// +// RDPWInst — RDP Wrapper Library Installer + +using RDPWrap.Common; + +namespace RDPWInst; + +internal static class Program +{ + private static string Banner + { + get + { + var v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + string version = v is null ? "unknown" : $"{v.Major}.{v.Minor}.{v.Build}"; + return + $"RDP Wrapper Library\r\n" + + $"Installer v{version} (C# edition)\r\n" + + "Copyright (C) Stas'M Corp. 2018\r\n" + + "Maintained by sjackson0109 2026\r\n"; + } + } + + private const string Usage = + "USAGE:\r\n" + + "RDPWInst.exe [-l|-i[-s][-o][-f]|-w|-u[-k]|-r]\r\n\r\n" + + "-l display the license agreement\r\n" + + "-i install wrapper to Program Files folder (default)\r\n" + + "-i -s install wrapper to System32 folder\r\n" + + "-i -o online install mode (loads latest INI file)\r\n" + + "-i -f force install: silently uninstall existing installation first\r\n" + + "-w get latest update for INI file\r\n" + + "-u uninstall wrapper\r\n" + + "-u -k uninstall wrapper and keep settings\r\n" + + "-r force restart Terminal Services\r\n"; + + internal static int Main(string[] args) + { + Console.OutputEncoding = System.Text.Encoding.UTF8; + Console.WriteLine(Banner); + + // Validate args + if (args.Length < 1 || + (args[0] != "-l" && + args[0] != "-i" && + args[0] != "-w" && + args[0] != "-u" && + args[0] != "-r")) + { + Console.WriteLine(Usage); + Pause(); + return 0; + } + + // -l print license + if (args[0] == "-l") + { + var license = ResourceHelper.ReadText("RDPWInst.Resources.license.txt", + System.Reflection.Assembly.GetExecutingAssembly()); + Console.WriteLine(license ?? "(license resource not found)"); + Pause(); + return 0; + } + + // Windows Vista / Server 2008 minimum check + if (Environment.OSVersion.Version < new Version(6, 0)) + { + Console.Error.WriteLine("[-] Unsupported Windows version:"); + Console.Error.WriteLine(" only >= 6.0 (Vista, Server 2008 and newer) are supported."); + Pause(); + return 1; + } + + if (!ArchHelper.IsSupported) + { + Console.Error.WriteLine("[-] Unsupported processor architecture."); + Pause(); + return 1; + } + + var engine = new InstallerEngine(); + engine.CheckInstall(); + + int rc = args[0] switch + { + "-i" => engine.Install( + toSystem32: args.Contains("-s"), + online: args.Contains("-o"), + force: args.Contains("-f")), + "-u" => engine.Uninstall(keepSettings: args.Contains("-k")), + "-w" => engine.Update(), + "-r" => engine.Restart(), + _ => 0 + }; + + Pause(); + return rc; + } + + /// + /// Waits for a keypress only when the process owns its console window + /// (i.e. was launched via double-click or UAC elevation rather than + /// piped/redirected from a script). + /// + private static void Pause() + { + if (!Console.IsInputRedirected && !Console.IsOutputRedirected) + { + Console.WriteLine("\nPress any key to exit..."); + Console.ReadKey(intercept: true); + } + } +} diff --git a/src-csharp/RDPWInst/RDPWInst.csproj b/src-csharp/RDPWInst/RDPWInst.csproj new file mode 100644 index 0000000..648a500 --- /dev/null +++ b/src-csharp/RDPWInst/RDPWInst.csproj @@ -0,0 +1,41 @@ + + + Exe + RDPWInst + RDPWInst + app.manifest + Command-line installer and manager for RDP Wrapper — installs rdpwrap.dll and configures the Terminal Services layer. + + + + + + + + + + + + + + + + + + + + diff --git a/src-csharp/RDPWInst/Resources/README.md b/src-csharp/RDPWInst/Resources/README.md new file mode 100644 index 0000000..556200b --- /dev/null +++ b/src-csharp/RDPWInst/Resources/README.md @@ -0,0 +1,31 @@ +# RDPWInst/Resources + +Place the compiled binary payloads here before building RDPWInst.exe. +These files are embedded as manifest resources at build time via `` entries in `RDPWInst.csproj` — if a file is absent the resource is simply omitted and the build still succeeds (online install mode is used as fallback). + +## CI-staged files (automatically copied by `build-and-release.yml`) + +| File | Source | Used when | +|---------------|--------------------------------------------------|-----------------------------| +| `rdpw32.dll` | Build output of `src-x86-x64-Fusix/` (Win32) | Always — 32-bit install | +| `rdpw64.dll` | Build output of `src-x86-x64-Fusix/` (x64) | Always — 64-bit install | +| `rdpwrap.ini` | `msi/rdpwrap.ini` from repo | Always — offline fallback | +| `license.txt` | Repo `LICENSE` (copied as plain text) | `RDPWInst -l` flag | + +## Optional legacy files (not in VCS, not staged by CI) + +| File | Purpose | Status / action required | +|-------------------|--------------------------------------------|--------------------------------------------------------------------------------------| +| `rdpclip6032.exe` | Updated rdpclip for Vista x86 | Not redistributable by this project — obtain from original stascorp release if needed | +| `rdpclip6064.exe` | Updated rdpclip for Vista x64 | Same as above | +| `rdpclip6132.exe` | Updated rdpclip for Win7 x86 | Same as above | +| `rdpclip6164.exe` | Updated rdpclip for Win7 x64 | Same as above | +| `rfxvmt32.dll` | RemoteFX codec for Win10 Home x86 | **Not redistributable** — must be extracted from a Windows 10 Home installation at `C:\Windows\System32\rfxvmt.dll`. See [#194](https://github.com/stascorp/rdpwrap/issues/194) for context. | +| `rfxvmt64.dll` | RemoteFX codec for Win10 Home x64 | Same as above | + +> **Decision note:** `rfxvmt.dll` is a Microsoft-owned component and cannot be legally bundled. +> `InstallerEngine.cs` handles the missing-rfxvmt case at runtime: if the file is absent from +> the embedded resources and absent from the install directory, a warning is printed and the +> user is directed to copy it manually. No CI step attempts to source or stage these files. + +All binary files in this folder are excluded from version control via `.gitignore`. diff --git a/src-csharp/RDPWInst/app.manifest b/src-csharp/RDPWInst/app.manifest new file mode 100644 index 0000000..4fcaaba --- /dev/null +++ b/src-csharp/RDPWInst/app.manifest @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-csharp/RDPWInst/packages.lock.json b/src-csharp/RDPWInst/packages.lock.json new file mode 100644 index 0000000..59ebcea --- /dev/null +++ b/src-csharp/RDPWInst/packages.lock.json @@ -0,0 +1,10 @@ +{ + "version": 1, + "dependencies": { + "net10.0-windows7.0": { + "rdpwrap": { + "type": "Project" + } + } + } +} \ No newline at end of file diff --git a/src-csharp/RDPWrap.sln b/src-csharp/RDPWrap.sln new file mode 100644 index 0000000..2a0b5fc --- /dev/null +++ b/src-csharp/RDPWrap.sln @@ -0,0 +1,58 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RDPWrap", "RDPWrap\RDPWrap.csproj", "{A1B2C3D4-0001-4000-8000-000000000001}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RDPWInst", "RDPWInst\RDPWInst.csproj", "{A1B2C3D4-0001-4000-8000-000000000002}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RDPConf", "RDPConf\RDPConf.csproj", "{A1B2C3D4-0001-4000-8000-000000000003}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RDPCheck", "RDPCheck\RDPCheck.csproj", "{A1B2C3D4-0001-4000-8000-000000000004}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A1B2C3D4-0001-4000-8000-000000000001}.Debug|x64.ActiveCfg = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000001}.Debug|x64.Build.0 = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000001}.Debug|x86.ActiveCfg = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000001}.Debug|x86.Build.0 = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000001}.Release|x64.ActiveCfg = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000001}.Release|x64.Build.0 = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000001}.Release|x86.ActiveCfg = Release|x86 + {A1B2C3D4-0001-4000-8000-000000000001}.Release|x86.Build.0 = Release|x86 + {A1B2C3D4-0001-4000-8000-000000000002}.Debug|x64.ActiveCfg = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000002}.Debug|x64.Build.0 = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000002}.Debug|x86.ActiveCfg = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000002}.Debug|x86.Build.0 = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000002}.Release|x64.ActiveCfg = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000002}.Release|x64.Build.0 = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000002}.Release|x86.ActiveCfg = Release|x86 + {A1B2C3D4-0001-4000-8000-000000000002}.Release|x86.Build.0 = Release|x86 + {A1B2C3D4-0001-4000-8000-000000000003}.Debug|x64.ActiveCfg = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000003}.Debug|x64.Build.0 = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000003}.Debug|x86.ActiveCfg = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000003}.Debug|x86.Build.0 = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000003}.Release|x64.ActiveCfg = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000003}.Release|x64.Build.0 = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000003}.Release|x86.ActiveCfg = Release|x86 + {A1B2C3D4-0001-4000-8000-000000000003}.Release|x86.Build.0 = Release|x86 + {A1B2C3D4-0001-4000-8000-000000000004}.Debug|x64.ActiveCfg = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000004}.Debug|x64.Build.0 = Debug|x64 + {A1B2C3D4-0001-4000-8000-000000000004}.Debug|x86.ActiveCfg = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000004}.Debug|x86.Build.0 = Debug|x86 + {A1B2C3D4-0001-4000-8000-000000000004}.Release|x64.ActiveCfg = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000004}.Release|x64.Build.0 = Release|x64 + {A1B2C3D4-0001-4000-8000-000000000004}.Release|x86.ActiveCfg = Release|x86 + {A1B2C3D4-0001-4000-8000-000000000004}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src-csharp/RDPWrap/ArchHelper.cs b/src-csharp/RDPWrap/ArchHelper.cs new file mode 100644 index 0000000..f6a8971 --- /dev/null +++ b/src-csharp/RDPWrap/ArchHelper.cs @@ -0,0 +1,80 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +using System.Runtime.InteropServices; + +namespace RDPWrap.Common; + +/// +/// Architecture detection and WOW64 file-system redirection control. +/// Mirrors the Arch / DisableWowRedirection / RevertWowRedirection logic +/// from RDPWInst.dpr and RDPConf MainUnit.pas. +/// +public static class ArchHelper +{ + private static readonly Lazy _arch = new(DetectArch); + + /// Raw architecture byte: 32 or 64. 0 = unsupported. + public static byte Arch => _arch.Value; + + /// true when running on a 64-bit Windows installation. + public static bool Is64Bit => Arch == 64; + + /// + /// Returns true when the processor architecture is supported + /// (x86 or x64). Itanium and unknown architectures return false. + /// + public static bool IsSupported => Arch != 0; + + private static byte DetectArch() + { + NativeMethods.GetNativeSystemInfo(out var si); + return si.wProcessorArchitecture switch + { + NativeMethods.PROCESSOR_ARCHITECTURE_INTEL => 32, + NativeMethods.PROCESSOR_ARCHITECTURE_AMD64 => 64, + _ => 0 // Itanium or unknown — unsupported + }; + } + + // ── WOW64 filesystem redirection ───────────────────────────────────────── + + private static IntPtr _wow64OldValue = IntPtr.Zero; + + /// + /// Disables WOW64 filesystem redirection so that 32-bit processes can + /// reach the real %SystemRoot%\System32. Call only on 64-bit hosts. + /// Returns true on success. + /// + public static bool DisableWow64Redirection() + { + if (!Is64Bit) return false; + return NativeMethods.Wow64DisableWow64FsRedirection(out _wow64OldValue); + } + + /// + /// Reverts the WOW64 filesystem redirection state saved by the last call + /// to . + /// + public static bool RevertWow64Redirection() + { + if (!Is64Bit) return false; + return NativeMethods.Wow64RevertWow64FsRedirection(_wow64OldValue); + } + + // ── Environment path expansion ──────────────────────────────────────────── + + /// + /// Expands environment strings in , replacing + /// %ProgramFiles% with %ProgramW6432% on 64-bit hosts + /// to avoid redirection to the x86 Program Files folder. + /// + public static string ExpandPath(string path) + { + if (Is64Bit) + path = path.Replace("%ProgramFiles%", "%ProgramW6432%", + StringComparison.OrdinalIgnoreCase); + + var buf = new System.Text.StringBuilder(1024); + NativeMethods.ExpandEnvironmentStrings(path, buf, (uint)buf.Capacity); + return buf.ToString(); + } +} diff --git a/src-csharp/RDPWrap/FileVersionHelper.cs b/src-csharp/RDPWrap/FileVersionHelper.cs new file mode 100644 index 0000000..cb98d64 --- /dev/null +++ b/src-csharp/RDPWrap/FileVersionHelper.cs @@ -0,0 +1,64 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +using System.Diagnostics; + +namespace RDPWrap.Common; + +/// +/// File-version reading helper. Mirrors the GetFileVersion function used in +/// RDPWInst.dpr and RDPConf MainUnit.pas. +/// +public static class FileVersionHelper +{ + /// + /// Strongly-typed representation of a Windows file version. + /// + public record FileVersionInfo( + ushort Major, + ushort Minor, + ushort Release, + ushort Build, + bool IsDebug, + bool IsPrerelease, + bool IsPrivate, + bool IsSpecial) + { + /// e.g. "10.0.26100.3476" + public override string ToString() => $"{Major}.{Minor}.{Release}.{Build}"; + } + + /// + /// Returns the file version of , or null + /// if the file does not exist or has no version resource. + /// Uses the BCL which does + /// not require loading the DLL as executable — safe for locked DLLs. + /// + public static FileVersionInfo? GetVersion(string filePath) + { + if (!File.Exists(filePath)) return null; + + try + { + var fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(filePath); + return new FileVersionInfo( + (ushort)(fvi.FileMajorPart), + (ushort)(fvi.FileMinorPart), + (ushort)(fvi.FileBuildPart), + (ushort)(fvi.FilePrivatePart), + fvi.IsDebug, + fvi.IsPreRelease, + fvi.IsPrivateBuild, + fvi.IsSpecialBuild); + } + catch + { + return null; + } + } + + /// + /// Convenience overload: resolves the path via + /// before reading. + /// + public static FileVersionInfo? GetVersionExpanded(string pathWithEnvVars) + => GetVersion(ArchHelper.ExpandPath(pathWithEnvVars)); +} diff --git a/src-csharp/RDPWrap/HttpHelper.cs b/src-csharp/RDPWrap/HttpHelper.cs new file mode 100644 index 0000000..a95aa4a --- /dev/null +++ b/src-csharp/RDPWrap/HttpHelper.cs @@ -0,0 +1,80 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 + +namespace RDPWrap.Common; + +/// +/// HTTP download helpers that replace the WinInet-based GitINIFile / +/// DownloadFileToDisk procedures from RDPWInst.dpr. +/// Uses with a shared static instance. +/// +public static class HttpHelper +{ + // Single shared instance — HttpClient is designed to be reused. + private static readonly HttpClient _client = new(new HttpClientHandler + { + AllowAutoRedirect = true, + MaxAutomaticRedirections = 5, + }) + { + Timeout = TimeSpan.FromSeconds(60), + DefaultRequestHeaders = { { "User-Agent", "RDP-Wrapper-Updater/1.0" } } + }; + + /// + /// Downloads the text content at and returns it as + /// a string. Returns null on any failure. + /// Mirrors the Delphi GitINIFile function. + /// + public static async Task DownloadStringAsync(string url) + { + try + { + return await _client.GetStringAsync(url).ConfigureAwait(false); + } + catch (Exception ex) + { + Console.Error.WriteLine($"[-] HTTP download failed ({url}): {ex.Message}"); + return null; + } + } + + /// + /// Downloads the binary content at and saves it to + /// . Returns true when the file exists + /// and is non-empty after download. + /// Mirrors the Delphi DownloadFileToDisk function. + /// + public static async Task DownloadFileAsync(string url, string destPath) + { + try + { + using var response = await _client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead) + .ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var file = File.Create(destPath); + await stream.CopyToAsync(file).ConfigureAwait(false); + + return new FileInfo(destPath).Length > 0; + } + catch (Exception ex) + { + Console.Error.WriteLine($"[-] HTTP file download failed ({url}): {ex.Message}"); + return false; + } + } + + /// + /// Synchronous wrapper for — suitable + /// for the installer's purely-sequential flow. + /// + public static string? DownloadString(string url) + => DownloadStringAsync(url).GetAwaiter().GetResult(); + + /// + /// Synchronous wrapper for . + /// + public static bool DownloadFile(string url, string destPath) + => DownloadFileAsync(url, destPath).GetAwaiter().GetResult(); +} diff --git a/src-csharp/RDPWrap/IniHelper.cs b/src-csharp/RDPWrap/IniHelper.cs new file mode 100644 index 0000000..f6c0919 --- /dev/null +++ b/src-csharp/RDPWrap/IniHelper.cs @@ -0,0 +1,61 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 + +namespace RDPWrap.Common; + +/// +/// Lightweight INI-file helpers used to check whether a specific version +/// section exists in rdpwrap.ini. Mirrors the INIHasSection function and +/// CheckSupport version-lookup logic from RDPWInst.dpr and RDPConf MainUnit.pas. +/// +public static class IniHelper +{ + /// + /// Returns true when the INI file at + /// contains the section header []. + /// Mirrors the Delphi INIHasSection function. + /// + public static bool HasSection(string iniPath, string section) + { + if (!File.Exists(iniPath)) return false; + var needle = $"[{section}]"; + foreach (var line in File.ReadLines(iniPath)) + { + if (line.Contains(needle, StringComparison.Ordinal)) + return true; + } + return false; + } + + /// + /// Loads the full text of and returns it, + /// or an empty string if the file does not exist. + /// + public static string LoadText(string iniPath) + => File.Exists(iniPath) ? File.ReadAllText(iniPath) : string.Empty; + + /// + /// Checks the support level of a given termsrv.dll version against the + /// INI content string . + /// + /// + /// 0 = not supported, 1 = partially supported (Vista/7 legacy), + /// 2 = fully supported (entry found in ini). + /// + public static int CheckSupportLevel(string iniContent, + FileVersionHelper.FileVersionInfo fv) + { + int level = 0; + + // Vista (6.0) and Windows 7 (6.1) are "partially" supported without + // a specific INI entry — mirrors the Delphi CheckSupport logic. + if ((fv.Major == 6 && fv.Minor == 0) || + (fv.Major == 6 && fv.Minor == 1)) + level = 1; + + var verTxt = fv.ToString(); // "major.minor.release.build" + if (iniContent.Contains($"[{verTxt}]", StringComparison.Ordinal)) + level = 2; + + return level; + } +} diff --git a/src-csharp/RDPWrap/NativeMethods.cs b/src-csharp/RDPWrap/NativeMethods.cs new file mode 100644 index 0000000..1312a72 --- /dev/null +++ b/src-csharp/RDPWrap/NativeMethods.cs @@ -0,0 +1,467 @@ +// Copyright 2026 sjackson0109 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Runtime.InteropServices; + +namespace RDPWrap.Common; + +/// +/// All P/Invoke declarations used across RDPWInst, RDPConf and RDPCheck. +/// Mirrors the unhooked Win32 imports from the original Delphi sources. +/// +internal static class NativeMethods +{ + // ─── DLL names ──────────────────────────────────────────────────────────── + internal const string Kernel32 = "kernel32.dll"; + internal const string Advapi32 = "advapi32.dll"; + internal const string WinSta = "winsta.dll"; + + // ─── Constants ──────────────────────────────────────────────────────────── + + // Architecture + internal const ushort PROCESSOR_ARCHITECTURE_INTEL = 0; + internal const ushort PROCESSOR_ARCHITECTURE_IA64 = 6; + internal const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9; + + // Registry + internal const uint KEY_WOW64_64KEY = 0x0100; + internal const uint KEY_WOW64_32KEY = 0x0200; + internal const uint KEY_READ = 0x20019; + internal const uint KEY_WRITE = 0x20006; + internal const uint KEY_QUERY_VALUE = 0x0001; + internal const uint KEY_SET_VALUE = 0x0002; + + // Service control manager + internal const uint SC_MANAGER_CONNECT = 0x0001; + internal const uint SC_MANAGER_CREATE_SERVICE = 0x0002; + internal const uint SC_MANAGER_ENUMERATE_SERVICE = 0x0004; + internal const uint SC_MANAGER_ALL_ACCESS = 0xF003F; + + internal const uint SERVICE_QUERY_CONFIG = 0x0001; + internal const uint SERVICE_CHANGE_CONFIG = 0x0002; + internal const uint SERVICE_QUERY_STATUS = 0x0004; + internal const uint SERVICE_START = 0x0010; + internal const uint SERVICE_STOP = 0x0020; + internal const uint SERVICE_ALL_ACCESS = 0xF01FF; + + internal const uint SERVICE_WIN32 = 0x30; + internal const uint SERVICE_STATE_ALL = 0x03; + internal const uint SERVICE_NO_CHANGE = 0xFFFFFFFF; + internal const uint SERVICE_AUTO_START = 0x02; + internal const uint SERVICE_DEMAND_START = 0x03; + internal const uint SERVICE_DISABLED = 0x04; + + internal const uint SERVICE_STOPPED = 0x00000001; + internal const uint SERVICE_START_PENDING = 0x00000002; + internal const uint SERVICE_STOP_PENDING = 0x00000003; + internal const uint SERVICE_RUNNING = 0x00000004; + internal const uint SERVICE_CONTINUE_PENDING = 0x00000005; + internal const uint SERVICE_PAUSE_PENDING = 0x00000006; + internal const uint SERVICE_PAUSED = 0x00000007; + + internal const uint SC_ENUM_PROCESS_INFO = 0; + internal const uint SC_STATUS_PROCESS_INFO = 0; + internal const uint ERROR_MORE_DATA = 234; + internal const uint ERROR_SERVICE_DOES_NOT_EXIST = 1060; + internal const uint ERROR_SERVICE_NOT_ACTIVE = 1062; + + // Process/Thread + internal const uint PROCESS_TERMINATE = 0x0001; + internal const uint THREAD_SUSPEND_RESUME = 0x0002; + internal const uint TH32CS_SNAPTHREAD = 0x00000004; + + // Token privileges + internal const uint TOKEN_ADJUST_PRIVILEGES = 0x0020; + internal const uint TOKEN_QUERY = 0x0008; + internal const uint SE_PRIVILEGE_ENABLED = 0x00000002; + + // Privilege names + internal const string SE_DEBUG_NAME = "SeDebugPrivilege"; + internal const string SE_RESTORE_NAME = "SeRestorePrivilege"; + internal const string SE_BACKUP_NAME = "SeBackupPrivilege"; + + // Security + internal const uint DACL_SECURITY_INFORMATION = 0x00000004; + internal const uint SE_FILE_OBJECT = 1; + internal const uint GRANT_ACCESS = 1; + internal const uint SUB_CONTAINERS_AND_OBJECTS_INHERIT = 0x3; + internal const uint NO_MULTIPLE_TRUSTEE = 0; + internal const uint TRUSTEE_IS_SID = 0; + internal const uint TRUSTEE_IS_WELL_KNOWN_GROUP = 5; + internal const uint GENERIC_ALL = 0x10000000; + + // LoadLibraryEx flags + internal const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; + + // Version resource type + internal const uint RT_VERSION = 16; + + // CreateProcess - STARTUPINFO flags + internal const uint STARTF_USESHOWWINDOW = 0x00000001; + internal const ushort SW_HIDE = 0; + + // GetModuleHandleEx + internal const uint GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 0x00000004; + internal const uint GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 0x00000002; + + // Error codes + internal const uint ERROR_SUCCESS = 0; + internal const uint ERROR_ACCESS_DENIED = 5; + internal const uint ERROR_NOT_SUPPORTED = 50; + internal const uint ERROR_SERVICE_ALREADY_RUNNING = 1056; + + // ─── Structures ─────────────────────────────────────────────────────────── + + [StructLayout(LayoutKind.Sequential)] + internal struct SYSTEM_INFO + { + internal ushort wProcessorArchitecture; + internal ushort wReserved; + internal uint dwPageSize; + internal IntPtr lpMinimumApplicationAddress; + internal IntPtr lpMaximumApplicationAddress; + internal UIntPtr dwActiveProcessorMask; + internal uint dwNumberOfProcessors; + internal uint dwProcessorType; + internal uint dwAllocationGranularity; + internal ushort wProcessorLevel; + internal ushort wProcessorRevision; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct STARTUPINFO + { + internal uint cb; + internal string? lpReserved; + internal string? lpDesktop; + internal string? lpTitle; + internal uint dwX, dwY, dwXSize, dwYSize, dwXCountChars, dwYCountChars; + internal uint dwFillAttribute; + internal uint dwFlags; + internal ushort wShowWindow; + internal ushort cbReserved2; + internal IntPtr lpReserved2; + internal IntPtr hStdInput, hStdOutput, hStdError; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct PROCESS_INFORMATION + { + internal IntPtr hProcess; + internal IntPtr hThread; + internal uint dwProcessId; + internal uint dwThreadId; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct THREADENTRY32 + { + internal uint dwSize; + internal uint cntUsage; + internal uint th32ThreadID; + internal uint th32OwnerProcessID; + internal int tpBasePri; + internal int tpDeltaPri; + internal uint dwFlags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SERVICE_STATUS_PROCESS + { + internal uint dwServiceType; + internal uint dwCurrentState; + internal uint dwControlsAccepted; + internal uint dwWin32ExitCode; + internal uint dwServiceSpecificExitCode; + internal uint dwCheckPoint; + internal uint dwWaitHint; + internal uint dwProcessId; + internal uint dwServiceFlags; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct ENUM_SERVICE_STATUS_PROCESS + { + internal string lpServiceName; + internal string lpDisplayName; + internal SERVICE_STATUS_PROCESS ServiceStatusProcess; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct QUERY_SERVICE_CONFIG + { + internal uint dwServiceType; + internal uint dwStartType; + internal uint dwErrorControl; + internal string lpBinaryPathName; + internal string lpLoadOrderGroup; + internal uint dwTagId; + internal string lpDependencies; + internal string lpServiceStartName; + internal string lpDisplayName; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct LUID + { + internal uint LowPart; + internal int HighPart; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct LUID_AND_ATTRIBUTES + { + internal LUID Luid; + internal uint Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TOKEN_PRIVILEGES + { + internal uint PrivilegeCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + internal LUID_AND_ATTRIBUTES[] Privileges; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct EXPLICIT_ACCESS + { + internal uint grfAccessPermissions; + internal uint grfAccessMode; + internal uint grfInheritance; + internal TRUSTEE Trustee; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct TRUSTEE + { + internal IntPtr pMultipleTrustee; + internal uint MultipleTrusteeOperation; + internal uint TrusteeForm; + internal uint TrusteeType; + internal IntPtr ptstrName; // SID pointer or string pointer + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct WTS_SESSION_INFO + { + internal uint SessionId; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 34)] + internal string Name; + internal uint State; + } + + // ─── kernel32.dll ───────────────────────────────────────────────────────── + + [DllImport(Kernel32, SetLastError = true)] + internal static extern void GetNativeSystemInfo(out SYSTEM_INFO lpSystemInfo); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Wow64DisableWow64FsRedirection(out IntPtr oldValue); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Wow64RevertWow64FsRedirection(IntPtr oldValue); + + [DllImport(Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FreeLibrary(IntPtr hModule); + + [DllImport(Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern IntPtr LockResource(IntPtr hResData); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo); + + [DllImport(Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CreateProcess( + string? lpApplicationName, + string lpCommandLine, + IntPtr lpProcessAttributes, + IntPtr lpThreadAttributes, + [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles, + uint dwCreationFlags, + IntPtr lpEnvironment, + string? lpCurrentDirectory, + ref STARTUPINFO lpStartupInfo, + out PROCESS_INFORMATION lpProcessInformation); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CloseHandle(IntPtr hObject); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern IntPtr OpenProcess(uint dwDesiredAccess, + [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern uint GetCurrentProcessId(); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern uint GetCurrentThreadId(); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Thread32First(IntPtr hSnapshot, ref THREADENTRY32 lpte); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Thread32Next(IntPtr hSnapshot, ref THREADENTRY32 lpte); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern IntPtr OpenThread(uint dwDesiredAccess, + [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwThreadId); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern uint SuspendThread(IntPtr hThread); + + [DllImport(Kernel32, SetLastError = true)] + internal static extern uint ResumeThread(IntPtr hThread); + + [DllImport(Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint GetModuleFileName(IntPtr hModule, + System.Text.StringBuilder lpFilename, uint nSize); + + [DllImport(Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GetModuleHandleEx(uint dwFlags, IntPtr lpModuleName, + out IntPtr phModule); + + [DllImport(Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint ExpandEnvironmentStrings(string lpSrc, + System.Text.StringBuilder lpDst, uint nSize); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeleteFile(string lpFileName); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool RemoveDirectory(string lpPathName); + + [DllImport(Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool OpenProcessToken(IntPtr processHandle, + uint desiredAccess, out IntPtr tokenHandle); + + // ─── advapi32.dll ───────────────────────────────────────────────────────── + + [DllImport(Advapi32, SetLastError = true)] + internal static extern IntPtr OpenSCManager(string? lpMachineName, + string? lpDatabaseName, uint dwDesiredAccess); + + [DllImport(Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern IntPtr OpenService(IntPtr hSCManager, + string lpServiceName, uint dwDesiredAccess); + + [DllImport(Advapi32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CloseServiceHandle(IntPtr hSCObject); + + [DllImport(Advapi32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool QueryServiceConfig(IntPtr hService, + IntPtr lpServiceConfig, uint cbBufSize, out uint pcbBytesNeeded); + + [DllImport(Advapi32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool QueryServiceStatusEx(IntPtr hService, + uint InfoLevel, IntPtr lpBuffer, uint cbBufSize, out uint pcbBytesNeeded); + + [DllImport(Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool ChangeServiceConfig(IntPtr hService, + uint dwServiceType, uint dwStartType, uint dwErrorControl, + string? lpBinaryPathName, string? lpLoadOrderGroup, IntPtr lpdwTagId, + string? lpDependencies, string? lpServiceStartName, string? lpPassword, + string? lpDisplayName); + + [DllImport(Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool StartService(IntPtr hService, + uint dwNumServiceArgs, string[]? lpServiceArgVectors); + + [DllImport(Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool EnumServicesStatusEx( + IntPtr hSCManager, uint InfoLevel, uint dwServiceType, uint dwServiceState, + IntPtr lpServices, uint cbBufSize, + out uint pcbBytesNeeded, out uint lpServicesReturned, + ref uint lpResumeHandle, string? pszGroupName); + + [DllImport(Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool LookupPrivilegeValue(string? lpSystemName, + string lpName, out LUID lpLuid); + + [DllImport(Advapi32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool AdjustTokenPrivileges(IntPtr tokenHandle, + [MarshalAs(UnmanagedType.Bool)] bool disableAllPrivileges, + ref TOKEN_PRIVILEGES newState, uint bufferLength, + IntPtr previousState, IntPtr returnLength); + + [DllImport(Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool ConvertStringSidToSid(string stringSid, out IntPtr sid); + + [DllImport(Advapi32, SetLastError = true)] + internal static extern uint SetEntriesInAcl(uint cCountOfExplicitEntries, + ref EXPLICIT_ACCESS pListOfExplicitEntries, IntPtr oldAcl, out IntPtr newAcl); + + [DllImport(Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint SetNamedSecurityInfo(string pObjectName, + uint ObjectType, uint SecurityInfo, + IntPtr psidOwner, IntPtr psidGroup, IntPtr pDacl, IntPtr pSacl); + + [DllImport(Advapi32, SetLastError = true)] + internal static extern IntPtr LocalFree(IntPtr hMem); + + // ─── winsta.dll ─────────────────────────────────────────────────────────── + + /// + /// Enumerates WTS sessions on the local server. + /// Pass IntPtr.Zero as hServer for the local machine. + /// + [DllImport(WinSta, EntryPoint = "WinStationEnumerateW", + CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool WinStationEnumerate(IntPtr hServer, + out IntPtr ppSessionInfo, out uint pCount); + + [DllImport(WinSta, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool WinStationFreeMemory(IntPtr p); +} diff --git a/src-csharp/RDPWrap/ProcessHelper.cs b/src-csharp/RDPWrap/ProcessHelper.cs new file mode 100644 index 0000000..8cee8fc --- /dev/null +++ b/src-csharp/RDPWrap/ProcessHelper.cs @@ -0,0 +1,63 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +using System.Runtime.InteropServices; + +namespace RDPWrap.Common; + +/// +/// Process creation and termination helpers. Mirrors ExecWait and KillProcess +/// from RDPWInst.dpr (console variant) and RDPConf MainUnit.pas (GUI variant). +/// +public static class ProcessHelper +{ + /// + /// Creates a process from , waits for it to + /// exit, then returns true. The process window is hidden. + /// Mirrors the Delphi ExecWait procedure. + /// + public static bool ExecWait(string commandLine, bool hideWindow = true) + { + var si = new NativeMethods.STARTUPINFO + { + cb = (uint)Marshal.SizeOf(), + dwFlags = hideWindow ? NativeMethods.STARTF_USESHOWWINDOW : 0u, + wShowWindow = hideWindow ? NativeMethods.SW_HIDE : (ushort)1 + }; + + // CommandLine must be mutable — pass a copy + string cmdCopy = new(commandLine); + + if (!NativeMethods.CreateProcess(null, cmdCopy, IntPtr.Zero, IntPtr.Zero, + true, 0, IntPtr.Zero, null, ref si, out var pi)) + { + Console.Error.WriteLine( + $"[-] CreateProcess error (code {Marshal.GetLastWin32Error()})."); + return false; + } + + NativeMethods.WaitForSingleObject(pi.hProcess, 0xFFFFFFFF); + NativeMethods.CloseHandle(pi.hThread); + NativeMethods.CloseHandle(pi.hProcess); + return true; + } + + /// + /// Terminates the process with . Mirrors the Delphi + /// KillProcess procedure. + /// + public static void KillProcess(uint pid) + { + var hProc = NativeMethods.OpenProcess(NativeMethods.PROCESS_TERMINATE, false, pid); + if (hProc == IntPtr.Zero) + { + Console.Error.WriteLine( + $"[-] OpenProcess error (code {Marshal.GetLastWin32Error()})."); + return; + } + + if (!NativeMethods.TerminateProcess(hProc, 0)) + Console.Error.WriteLine( + $"[-] TerminateProcess error (code {Marshal.GetLastWin32Error()})."); + + NativeMethods.CloseHandle(hProc); + } +} diff --git a/src-csharp/RDPWrap/RDPWrap.csproj b/src-csharp/RDPWrap/RDPWrap.csproj new file mode 100644 index 0000000..bee8351 --- /dev/null +++ b/src-csharp/RDPWrap/RDPWrap.csproj @@ -0,0 +1,15 @@ + + + Library + RDPWrap.Common + RDPWrap + Shared helper library (P/Invoke, registry, service, security helpers) for the RDP Wrapper tool suite. + + + + + + + + + diff --git a/src-csharp/RDPWrap/RegistryHelper.cs b/src-csharp/RDPWrap/RegistryHelper.cs new file mode 100644 index 0000000..49bc306 --- /dev/null +++ b/src-csharp/RDPWrap/RegistryHelper.cs @@ -0,0 +1,97 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +using Microsoft.Win32; + +namespace RDPWrap.Common; + +/// +/// Thin wrappers around that mirror the +/// Delphi TRegistry usage in RDPWInst and RDPConf, with optional WOW64 flag +/// support (KEY_WOW64_64KEY) for 64-bit registry views from 32-bit processes. +/// +public static class RegistryHelper +{ + // On 64-bit Windows we always open the 64-bit view to match the Delphi code + // that passes KEY_WOW64_64KEY when Arch = 64. + private static RegistryView ViewForArch() => + ArchHelper.Is64Bit ? RegistryView.Registry64 : RegistryView.Default; + + // ── Convenience open helpers ────────────────────────────────────────────── + + /// Opens a read-only key under HKLM, respecting the host architecture. + public static RegistryKey? OpenHklmRead(string subKey) + { + using var hive = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, ViewForArch()); + return hive.OpenSubKey(subKey, writable: false); + } + + /// Opens a writable key under HKLM (creates if absent). + public static RegistryKey OpenHklmWrite(string subKey) + { + using var hive = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, ViewForArch()); + return hive.CreateSubKey(subKey, writable: true) + ?? throw new InvalidOperationException($"Cannot open/create HKLM\\{subKey}"); + } + + // ── Typed read helpers ──────────────────────────────────────────────────── + + /// + /// Reads a string value from HKLM. Returns null if the key or + /// value does not exist. + /// + public static string? ReadString(string subKey, string valueName) + { + using var key = OpenHklmRead(subKey); + return key?.GetValue(valueName) as string; + } + + /// + /// Reads a DWORD value from HKLM. Returns + /// if the key or value does not exist. + /// + public static int ReadInt(string subKey, string valueName, int defaultValue = 0) + { + using var key = OpenHklmRead(subKey); + if (key is null) return defaultValue; + var raw = key.GetValue(valueName); + return raw is int i ? i : defaultValue; + } + + /// + /// Reads a DWORD as a bool (non-zero = true). Returns + /// if absent. + /// + public static bool ReadBool(string subKey, string valueName, bool defaultValue = false) + { + using var key = OpenHklmRead(subKey); + if (key is null) return defaultValue; + var raw = key.GetValue(valueName); + return raw is int i ? i != 0 : defaultValue; + } + + // ── Typed write helpers ─────────────────────────────────────────────────── + + /// Writes a REG_SZ string value. + public static void WriteString(string subKey, string valueName, string value) + { + using var key = OpenHklmWrite(subKey); + key.SetValue(valueName, value, RegistryValueKind.String); + } + + /// Writes a REG_EXPAND_SZ string value (mirrors Delphi WriteExpandString). + public static void WriteExpandString(string subKey, string valueName, string value) + { + using var key = OpenHklmWrite(subKey); + key.SetValue(valueName, value, RegistryValueKind.ExpandString); + } + + /// Writes a DWORD integer value. + public static void WriteInt(string subKey, string valueName, int value) + { + using var key = OpenHklmWrite(subKey); + key.SetValue(valueName, value, RegistryValueKind.DWord); + } + + /// Writes a boolean as a DWORD (1/0). + public static void WriteBool(string subKey, string valueName, bool value) + => WriteInt(subKey, valueName, value ? 1 : 0); +} diff --git a/src-csharp/RDPWrap/ResourceHelper.cs b/src-csharp/RDPWrap/ResourceHelper.cs new file mode 100644 index 0000000..51d1015 --- /dev/null +++ b/src-csharp/RDPWrap/ResourceHelper.cs @@ -0,0 +1,88 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +using System.Reflection; + +namespace RDPWrap.Common; + +/// +/// Helpers for reading and extracting managed embedded resources. +/// Mirrors the Delphi ExtractRes / ExtractResText procedures from RDPWInst.dpr +/// and RDPConf MainUnit.pas, translated to the .NET manifest-resource model. +/// +public static class ResourceHelper +{ + /// + /// Reads the contents of the embedded resource named + /// from + /// and returns it as a UTF-8 string. Returns null if not found. + /// + public static string? ReadText(string resourceName, + Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + using var stream = assembly.GetManifestResourceStream(resourceName); + if (stream is null) return null; + using var reader = new StreamReader(stream, System.Text.Encoding.UTF8); + return reader.ReadToEnd(); + } + + /// + /// Reads the contents of the embedded resource named + /// and returns the raw bytes. + /// Returns null if not found. + /// + public static byte[]? ReadBytes(string resourceName, + Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + using var stream = assembly.GetManifestResourceStream(resourceName); + if (stream is null) return null; + using var ms = new MemoryStream(); + stream.CopyTo(ms); + return ms.ToArray(); + } + + /// + /// Extracts the embedded resource to disk + /// at , creating parent directories as needed. + /// Returns true on success. Mirrors the Delphi ExtractRes procedure. + /// + public static bool ExtractToDisk(string resourceName, string destPath, + Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + using var stream = assembly.GetManifestResourceStream(resourceName); + if (stream is null) + { + Console.Error.WriteLine($"[-] Resource not found: {resourceName}"); + return false; + } + + var dir = Path.GetDirectoryName(destPath); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + try + { + using var file = File.Create(destPath); + stream.CopyTo(file); + Console.WriteLine($"[+] Extracted {resourceName} -> {destPath}"); + return true; + } + catch (Exception ex) + { + Console.Error.WriteLine( + $"[-] Failed to extract resource {resourceName} to {destPath}: {ex.Message}"); + return false; + } + } + + /// + /// Lists all manifest resource names in + /// — useful for debugging resource name mismatches. + /// + public static IEnumerable ListResources(Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + return assembly.GetManifestResourceNames(); + } +} diff --git a/src-csharp/RDPWrap/SecurityHelper.cs b/src-csharp/RDPWrap/SecurityHelper.cs new file mode 100644 index 0000000..3535834 --- /dev/null +++ b/src-csharp/RDPWrap/SecurityHelper.cs @@ -0,0 +1,168 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +using System.Runtime.InteropServices; + +namespace RDPWrap.Common; + +/// +/// Security helpers: granting SID-based DACL entries (GrantSidFullAccess) and +/// adjusting process token privileges (AddPrivilege). Mirrors the Delphi +/// implementations in RDPWInst.dpr. +/// +public static class SecurityHelper +{ + // ── DACL: grant a well-known SID full access to a file/folder ───────────── + + /// + /// Grants GENERIC_ALL access to the well-known SID string + /// on the file/directory at + /// . Mirrors the Delphi GrantSidFullAccess + /// procedure (used for "S-1-5-18" = Local System, "S-1-5-6" = Service). + /// + public static void GrantSidFullAccess(string path, string stringSid) + { + if (!NativeMethods.ConvertStringSidToSid(stringSid, out IntPtr pSid)) + { + Console.Error.WriteLine( + $"[-] ConvertStringSidToSid error (code {Marshal.GetLastWin32Error()}) " + + $"for SID {stringSid}."); + return; + } + + try + { + var ea = new NativeMethods.EXPLICIT_ACCESS + { + grfAccessPermissions = NativeMethods.GENERIC_ALL, + grfAccessMode = NativeMethods.GRANT_ACCESS, + grfInheritance = NativeMethods.SUB_CONTAINERS_AND_OBJECTS_INHERIT, + Trustee = new NativeMethods.TRUSTEE + { + pMultipleTrustee = IntPtr.Zero, + MultipleTrusteeOperation = NativeMethods.NO_MULTIPLE_TRUSTEE, + TrusteeForm = NativeMethods.TRUSTEE_IS_SID, + TrusteeType = NativeMethods.TRUSTEE_IS_WELL_KNOWN_GROUP, + ptstrName = pSid + } + }; + + uint result = NativeMethods.SetEntriesInAcl(1, ref ea, IntPtr.Zero, out IntPtr pNewAcl); + if (result == NativeMethods.ERROR_SUCCESS) + { + uint secResult = NativeMethods.SetNamedSecurityInfo( + path, + NativeMethods.SE_FILE_OBJECT, + NativeMethods.DACL_SECURITY_INFORMATION, + IntPtr.Zero, IntPtr.Zero, pNewAcl, IntPtr.Zero); + + if (secResult != NativeMethods.ERROR_SUCCESS) + Console.Error.WriteLine( + $"[-] SetNamedSecurityInfo error (code {secResult})."); + + NativeMethods.LocalFree(pNewAcl); + } + else + { + Console.Error.WriteLine($"[-] SetEntriesInAcl error (code {result})."); + } + } + finally + { + NativeMethods.LocalFree(pSid); + } + } + + // ── Token privileges ────────────────────────────────────────────────────── + + /// + /// Enables the named privilege (e.g. SeDebugPrivilege) for the + /// current process token. Mirrors the Delphi AddPrivilege function. + /// Returns true on success. + /// + public static bool AddPrivilege(string privilegeName) + { + if (!NativeMethods.OpenProcessToken( + System.Diagnostics.Process.GetCurrentProcess().Handle, + NativeMethods.TOKEN_ADJUST_PRIVILEGES | NativeMethods.TOKEN_QUERY, + out IntPtr hToken)) + { + Console.Error.WriteLine( + $"[-] OpenProcessToken error (code {Marshal.GetLastWin32Error()})."); + return false; + } + + try + { + if (!NativeMethods.LookupPrivilegeValue(null, privilegeName, out var luid)) + { + Console.Error.WriteLine( + $"[-] LookupPrivilegeValue error (code {Marshal.GetLastWin32Error()})."); + return false; + } + + var tp = new NativeMethods.TOKEN_PRIVILEGES + { + PrivilegeCount = 1, + Privileges = new[] + { + new NativeMethods.LUID_AND_ATTRIBUTES + { + Luid = luid, + Attributes = NativeMethods.SE_PRIVILEGE_ENABLED + } + } + }; + + if (!NativeMethods.AdjustTokenPrivileges( + hToken, false, ref tp, + (uint)Marshal.SizeOf(tp), + IntPtr.Zero, IntPtr.Zero)) + { + Console.Error.WriteLine( + $"[-] AdjustTokenPrivileges error (code {Marshal.GetLastWin32Error()})."); + return false; + } + + return true; + } + finally + { + NativeMethods.CloseHandle(hToken); + } + } + + // ── RDP-Tcp listener ────────────────────────────────────────────────────── + + /// + /// Returns true when there is an active "RDP-Tcp" WTS listener on + /// the local machine — i.e. WinStationEnumerateW returns a session + /// named "RDP-Tcp". Mirrors the Delphi IsListenerWorking function. + /// + public static bool IsRdpListenerWorking() + { + if (!NativeMethods.WinStationEnumerate(IntPtr.Zero, + out IntPtr ppInfo, out uint count)) + return false; + + try + { + int ptrSize = IntPtr.Size; + // WTS_SESSION_INFO is: DWORD SessionId + 34 WCHARs (Name) + DWORD State + // = 4 + 68 + 4 = 76 bytes, but aligned to 4-byte boundary → 76 bytes. + int entrySize = 4 + 34 * 2 + 4; // = 76 + + for (uint i = 0; i < count; i++) + { + IntPtr entry = ppInfo + (int)(i * (uint)entrySize); + // Name starts at offset 4 + string name = Marshal.PtrToStringUni(entry + 4, 34).TrimEnd('\0'); + if (name == "RDP-Tcp") return true; + } + } + finally + { + NativeMethods.WinStationFreeMemory(ppInfo); + } + + return false; + } +} diff --git a/src-csharp/RDPWrap/ServiceHelper.cs b/src-csharp/RDPWrap/ServiceHelper.cs new file mode 100644 index 0000000..486ad93 --- /dev/null +++ b/src-csharp/RDPWrap/ServiceHelper.cs @@ -0,0 +1,219 @@ +// Copyright 2026 sjackson0109 — Apache License 2.0 +using System.Runtime.InteropServices; + +namespace RDPWrap.Common; + +/// +/// Wrappers around the Windows Service Control Manager API, mirroring the +/// SvcGetStart / SvcConfigStart / SvcStart / CheckTermsrvProcess helpers +/// in RDPWInst.dpr and GetTermSrvState in RDPConf MainUnit.pas. +/// +public static class ServiceHelper +{ + // ── Start-type query / change ───────────────────────────────────────────── + + /// + /// Returns the configured start type of + /// (e.g. SERVICE_AUTO_START) or -1 on failure. + /// + public static int GetStartType(string serviceName) + { + var hSC = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_CONNECT); + if (hSC == IntPtr.Zero) return -1; + try + { + var hSvc = NativeMethods.OpenService(hSC, serviceName, + NativeMethods.SERVICE_QUERY_CONFIG); + if (hSvc == IntPtr.Zero) return -1; + try + { + NativeMethods.QueryServiceConfig(hSvc, IntPtr.Zero, 0, out uint needed); + var buf = Marshal.AllocHGlobal((int)needed); + try + { + if (!NativeMethods.QueryServiceConfig(hSvc, buf, needed, out _)) + return -1; + // dwStartType is the second DWORD in QUERY_SERVICE_CONFIG + return Marshal.ReadInt32(buf, 4); + } + finally { Marshal.FreeHGlobal(buf); } + } + finally { NativeMethods.CloseServiceHandle(hSvc); } + } + finally { NativeMethods.CloseServiceHandle(hSC); } + } + + /// + /// Changes the start type of to + /// (one of the SERVICE_*_START constants). + /// + public static bool SetStartType(string serviceName, uint startType) + { + var hSC = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_CONNECT); + if (hSC == IntPtr.Zero) return false; + try + { + var hSvc = NativeMethods.OpenService(hSC, serviceName, + NativeMethods.SERVICE_CHANGE_CONFIG); + if (hSvc == IntPtr.Zero) return false; + try + { + return NativeMethods.ChangeServiceConfig(hSvc, + NativeMethods.SERVICE_NO_CHANGE, startType, + NativeMethods.SERVICE_NO_CHANGE, + null, null, IntPtr.Zero, null, null, null, null); + } + finally { NativeMethods.CloseServiceHandle(hSvc); } + } + finally { NativeMethods.CloseServiceHandle(hSC); } + } + + // ── Start a service ─────────────────────────────────────────────────────── + + /// + /// Starts . If the service is already + /// running (error 1056) it waits 2 s and retries once, matching the + /// original Delphi SvcStart behaviour. + /// Returns true on success. + /// + public static bool StartService(string serviceName) + { + var hSC = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_CONNECT); + if (hSC == IntPtr.Zero) return false; + try + { + var hSvc = NativeMethods.OpenService(hSC, serviceName, + NativeMethods.SERVICE_START); + if (hSvc == IntPtr.Zero) return false; + try + { + if (NativeMethods.StartService(hSvc, 0, null)) return true; + + var err = Marshal.GetLastWin32Error(); + if (err == (int)NativeMethods.ERROR_SERVICE_ALREADY_RUNNING) + { + Thread.Sleep(2000); + return NativeMethods.StartService(hSvc, 0, null); + } + return false; + } + finally { NativeMethods.CloseServiceHandle(hSvc); } + } + finally { NativeMethods.CloseServiceHandle(hSC); } + } + + // ── Status query ────────────────────────────────────────────────────────── + + /// + /// Returns the dwCurrentState for + /// (e.g. SERVICE_RUNNING = 4) or -1 on failure. + /// + public static int GetCurrentState(string serviceName) + { + var hSC = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_CONNECT); + if (hSC == IntPtr.Zero) return -1; + try + { + var hSvc = NativeMethods.OpenService(hSC, serviceName, + NativeMethods.SERVICE_QUERY_STATUS); + if (hSvc == IntPtr.Zero) return -1; + try + { + NativeMethods.QueryServiceStatusEx(hSvc, + NativeMethods.SC_STATUS_PROCESS_INFO, + IntPtr.Zero, 0, out uint needed); + + var buf = Marshal.AllocHGlobal((int)needed); + try + { + if (!NativeMethods.QueryServiceStatusEx(hSvc, + NativeMethods.SC_STATUS_PROCESS_INFO, + buf, needed, out _)) return -1; + + // dwCurrentState is the second DWORD in SERVICE_STATUS_PROCESS + return Marshal.ReadInt32(buf, 4); + } + finally { Marshal.FreeHGlobal(buf); } + } + finally { NativeMethods.CloseServiceHandle(hSvc); } + } + finally { NativeMethods.CloseServiceHandle(hSC); } + } + + // ── Process-info enumeration ────────────────────────────────────────────── + + /// + /// Represents the name and PID of a service process returned by + /// . + /// + public record ServiceProcessInfo(string ServiceName, string DisplayName, uint ProcessId, uint CurrentState); + + /// + /// Enumerates all Win32 services (all states) and returns their + /// process information. Mirrors the EnumServicesStatusEx loop in + /// CheckTermsrvProcess. + /// + public static IReadOnlyList EnumServiceProcesses() + { + var result = new List(); + + var hSC = NativeMethods.OpenSCManager(null, null, + NativeMethods.SC_MANAGER_CONNECT | NativeMethods.SC_MANAGER_ENUMERATE_SERVICE); + if (hSC == IntPtr.Zero) return result; + + try + { + uint resumeHandle = 0; + // Ask for the required buffer size + NativeMethods.EnumServicesStatusEx(hSC, + NativeMethods.SC_ENUM_PROCESS_INFO, + NativeMethods.SERVICE_WIN32, + NativeMethods.SERVICE_STATE_ALL, + IntPtr.Zero, 0, + out uint needed, out _, ref resumeHandle, null); + + if (needed == 0) return result; + + var buf = Marshal.AllocHGlobal((int)needed); + try + { + resumeHandle = 0; + if (!NativeMethods.EnumServicesStatusEx(hSC, + NativeMethods.SC_ENUM_PROCESS_INFO, + NativeMethods.SERVICE_WIN32, + NativeMethods.SERVICE_STATE_ALL, + buf, needed, + out _, out uint returned, ref resumeHandle, null)) + return result; + + // ENUM_SERVICE_STATUS_PROCESS layout (Unicode, packed): + // IntPtr lpServiceName (pointer to string) + // IntPtr lpDisplayName (pointer to string) + // SERVICE_STATUS_PROCESS (9 × DWORD = 36 bytes) + int ptrSize = IntPtr.Size; + int entrySize = ptrSize * 2 + 36; // 2 string pointers + status struct + + for (int i = 0; i < (int)returned; i++) + { + var entryPtr = buf + i * entrySize; + var namePtr = Marshal.ReadIntPtr(entryPtr); + var dispPtr = Marshal.ReadIntPtr(entryPtr + ptrSize); + + var svcName = Marshal.PtrToStringUni(namePtr) ?? string.Empty; + var dispName = Marshal.PtrToStringUni(dispPtr) ?? string.Empty; + + // dwCurrentState at offset 4, dwProcessId at offset 28 + var statusBase = entryPtr + ptrSize * 2; + uint currentState = (uint)Marshal.ReadInt32(statusBase + 4); + uint pid = (uint)Marshal.ReadInt32(statusBase + 28); + + result.Add(new ServiceProcessInfo(svcName, dispName, pid, currentState)); + } + } + finally { Marshal.FreeHGlobal(buf); } + } + finally { NativeMethods.CloseServiceHandle(hSC); } + + return result; + } +} diff --git a/src-csharp/RDPWrap/packages.lock.json b/src-csharp/RDPWrap/packages.lock.json new file mode 100644 index 0000000..2a64009 --- /dev/null +++ b/src-csharp/RDPWrap/packages.lock.json @@ -0,0 +1,6 @@ +{ + "version": 1, + "dependencies": { + "net10.0-windows7.0": {} + } +} \ No newline at end of file diff --git a/src-installer/RDPWInst.dpr b/src-installer/RDPWInst.dpr deleted file mode 100644 index f419d82..0000000 --- a/src-installer/RDPWInst.dpr +++ /dev/null @@ -1,1463 +0,0 @@ -{ - Copyright 2018 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -program RDPWInst; - -{$APPTYPE CONSOLE} - -{$R resource.res} - -uses - SysUtils, - Windows, - Classes, - WinSvc, - Registry, - WinInet, - AccCtrl, - AclAPI; - -function EnumServicesStatusEx( - hSCManager: SC_HANDLE; - InfoLevel, - dwServiceType, - dwServiceState: DWORD; - lpServices: PByte; - cbBufSize: DWORD; - var pcbBytesNeeded, - lpServicesReturned, - lpResumeHandle: DWORD; - pszGroupName: PWideChar): BOOL; stdcall; - external advapi32 name 'EnumServicesStatusExW'; - -function ConvertStringSidToSid( - StringSid: PWideChar; - var Sid: PSID): BOOL; stdcall; - external advapi32 name 'ConvertStringSidToSidW'; - -type - FILE_VERSION = record - Version: record case Boolean of - True: (dw: DWORD); - False: (w: record - Minor, Major: Word; - end;) - end; - Release, Build: Word; - bDebug, bPrerelease, bPrivate, bSpecial: Boolean; - end; - SERVICE_STATUS_PROCESS = packed record - dwServiceType, - dwCurrentState, - dwControlsAccepted, - dwWin32ExitCode, - dwServiceSpecificExitCode, - dwCheckPoint, - dwWaitHint, - dwProcessId, - dwServiceFlags: DWORD; - end; - PSERVICE_STATUS_PROCESS = ^SERVICE_STATUS_PROCESS; - ENUM_SERVICE_STATUS_PROCESS = packed record - lpServiceName, - lpDisplayName: PWideChar; - ServiceStatusProcess: SERVICE_STATUS_PROCESS; - end; - PENUM_SERVICE_STATUS_PROCESS = ^ENUM_SERVICE_STATUS_PROCESS; - -const - SC_ENUM_PROCESS_INFO = 0; - TermService = 'TermService'; -var - Installed: Boolean; - Online: Boolean; - WrapPath: String; - Arch: Byte; - OldWow64RedirectionValue: LongBool; - - TermServicePath: String; - FV: FILE_VERSION; - TermServicePID: DWORD; - ShareSvc: Array of String; - sShareSvc: String; - TermSrvVerTxt: String; // e.g. '10.0.26100.7623' — set by CheckTermsrvVersion - -function SupportedArchitecture: Boolean; -var - SI: TSystemInfo; -begin - GetNativeSystemInfo(SI); - case SI.wProcessorArchitecture of - 0: - begin - Arch := 32; - Result := True; // Intel x86 - end; - 6: Result := False; // Itanium-based x64 - 9: begin - Arch := 64; - Result := True; // Intel/AMD x64 - end; - else Result := False; - end; -end; - -function DisableWowRedirection: Boolean; -type - TFunc = function(var Wow64FsEnableRedirection: LongBool): LongBool; stdcall; -var - hModule: THandle; - Wow64DisableWow64FsRedirection: TFunc; -begin - Result := False; - hModule := GetModuleHandle(kernel32); - if hModule <> 0 then - Wow64DisableWow64FsRedirection := GetProcAddress(hModule, 'Wow64DisableWow64FsRedirection') - else - Exit; - if @Wow64DisableWow64FsRedirection <> nil then - Result := Wow64DisableWow64FsRedirection(OldWow64RedirectionValue); -end; - -function RevertWowRedirection: Boolean; -type - TFunc = function(var Wow64RevertWow64FsRedirection: LongBool): LongBool; stdcall; -var - hModule: THandle; - Wow64RevertWow64FsRedirection: TFunc; -begin - Result := False; - hModule := GetModuleHandle(kernel32); - if hModule <> 0 then - Wow64RevertWow64FsRedirection := GetProcAddress(hModule, 'Wow64RevertWow64FsRedirection') - else - Exit; - if @Wow64RevertWow64FsRedirection <> nil then - Result := Wow64RevertWow64FsRedirection(OldWow64RedirectionValue); -end; - -procedure CheckInstall; -var - Code: DWORD; - TermServiceHost: String; - Reg: TRegistry; -begin - if Arch = 64 then - Reg := TRegistry.Create(KEY_WOW64_64KEY) - else - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService') then - begin - Reg.Free; - Code := GetLastError; - Writeln('[-] OpenKeyReadOnly error (code ', Code, ').'); - Halt(Code); - end; - TermServiceHost := Reg.ReadString('ImagePath'); - Reg.CloseKey; - if (Pos('svchost.exe', LowerCase(TermServiceHost)) = 0) - and (Pos('svchost -k', LowerCase(TermServiceHost)) = 0) then - begin - Reg.Free; - Writeln('[-] TermService is hosted in a custom application (BeTwin, etc.) - unsupported.'); - Writeln('[*] ImagePath: "', TermServiceHost, '".'); - Halt(ERROR_NOT_SUPPORTED); - end; - if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService\Parameters') then - begin - Reg.Free; - Code := GetLastError; - Writeln('[-] OpenKeyReadOnly error (code ', Code, ').'); - Halt(Code); - end; - TermServicePath := Reg.ReadString('ServiceDll'); - Reg.CloseKey; - if (Pos('termsrv.dll', LowerCase(TermServicePath)) = 0) - and (Pos('rdpwrap.dll', LowerCase(TermServicePath)) = 0) then - begin - Reg.Free; - Writeln('[-] Another third-party TermService library is installed.'); - Writeln('[*] ServiceDll: "', TermServicePath, '".'); - Halt(ERROR_NOT_SUPPORTED); - end; - Reg.Free; - - Installed := Pos('rdpwrap.dll', LowerCase(TermServicePath)) > 0; -end; - -function SvcGetStart(SvcName: String): Integer; -var - hSC: SC_HANDLE; - hSvc: THandle; - Code: DWORD; - lpServiceConfig: PQueryServiceConfig; - Buf: Pointer; - cbBufSize, pcbBytesNeeded: Cardinal; -begin - Result := -1; - Writeln('[*] Checking ', SvcName, '...'); - hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); - if hSC = 0 then - begin - Code := GetLastError; - Writeln('[-] OpenSCManager error (code ', Code, ').'); - Exit; - end; - - hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_QUERY_CONFIG); - if hSvc = 0 then - begin - CloseServiceHandle(hSC); - Code := GetLastError; - Writeln('[-] OpenService error (code ', Code, ').'); - Exit; - end; - - if QueryServiceConfig(hSvc, nil, 0, pcbBytesNeeded) then begin - Writeln('[-] QueryServiceConfig failed.'); - Exit; - end; - - cbBufSize := pcbBytesNeeded; - GetMem(Buf, cbBufSize); - - if not QueryServiceConfig(hSvc, Buf, cbBufSize, pcbBytesNeeded) then begin - FreeMem(Buf, cbBufSize); - CloseServiceHandle(hSvc); - CloseServiceHandle(hSC); - Code := GetLastError; - Writeln('[-] QueryServiceConfig error (code ', Code, ').'); - Exit; - end else begin - lpServiceConfig := Buf; - Result := Integer(lpServiceConfig^.dwStartType); - end; - FreeMem(Buf, cbBufSize); - CloseServiceHandle(hSvc); - CloseServiceHandle(hSC); -end; - -procedure SvcConfigStart(SvcName: String; dwStartType: Cardinal); -var - hSC: SC_HANDLE; - hSvc: THandle; - Code: DWORD; -begin - Writeln('[*] Configuring ', SvcName, '...'); - hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); - if hSC = 0 then - begin - Code := GetLastError; - Writeln('[-] OpenSCManager error (code ', Code, ').'); - Exit; - end; - - hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_CHANGE_CONFIG); - if hSvc = 0 then - begin - CloseServiceHandle(hSC); - Code := GetLastError; - Writeln('[-] OpenService error (code ', Code, ').'); - Exit; - end; - - if not ChangeServiceConfig(hSvc, SERVICE_NO_CHANGE, dwStartType, - SERVICE_NO_CHANGE, nil, nil, nil, nil, nil, nil, nil) then begin - CloseServiceHandle(hSvc); - CloseServiceHandle(hSC); - Code := GetLastError; - Writeln('[-] ChangeServiceConfig error (code ', Code, ').'); - Exit; - end; - CloseServiceHandle(hSvc); - CloseServiceHandle(hSC); -end; - -procedure SvcStart(SvcName: String); -var - hSC: SC_HANDLE; - hSvc: THandle; - Code: DWORD; - pch: PWideChar; - procedure ExitError(Func: String; ErrorCode: DWORD); - begin - if hSC > 0 then - CloseServiceHandle(hSC); - if hSvc > 0 then - CloseServiceHandle(hSvc); - Writeln('[-] ', Func, ' error (code ', ErrorCode, ').'); - end; -begin - hSC := 0; - hSvc := 0; - Writeln('[*] Starting ', SvcName, '...'); - hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); - if hSC = 0 then - begin - ExitError('OpenSCManager', GetLastError); - Exit; - end; - - hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_START); - if hSvc = 0 then - begin - ExitError('OpenService', GetLastError); - Exit; - end; - - pch := nil; - if not StartService(hSvc, 0, pch) then begin - Code := GetLastError; - if Code = 1056 then begin // Service already started - Sleep(2000); // or SCM hasn't registered killed process - if not StartService(hSvc, 0, pch) then begin - ExitError('StartService', Code); - Exit; - end; - end else begin - ExitError('StartService', Code); - Exit; - end; - end; - CloseServiceHandle(hSvc); - CloseServiceHandle(hSC); -end; - -procedure CheckTermsrvProcess; -label - back; -var - hSC: SC_HANDLE; - dwNeedBytes, dwReturnBytes, dwResumeHandle, Code: DWORD; - Svc: Array of ENUM_SERVICE_STATUS_PROCESS; - I: Integer; - Found, Started: Boolean; - TermServiceName: String; -begin - Started := False; - back: - hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT or SC_MANAGER_ENUMERATE_SERVICE); - if hSC = 0 then - begin - Code := GetLastError; - Writeln('[-] OpenSCManager error (code ', Code, ').'); - Halt(Code); - end; - - dwResumeHandle := 0; - - SetLength(Svc, 1489); - FillChar(Svc[0], sizeof(Svc[0])*Length(Svc), 0); - if not EnumServicesStatusEx(hSC, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, - @Svc[0], sizeof(Svc[0])*Length(Svc), dwNeedBytes, dwReturnBytes, dwResumeHandle, nil) then begin - Code := GetLastError; - if Code <> ERROR_MORE_DATA then - begin - CloseServiceHandle(hSC); - Writeln('[-] EnumServicesStatusEx error (code ', Code, ').'); - Halt(Code); - end - else - begin - SetLength(Svc, 5957); - FillChar(Svc[0], sizeof(Svc[0])*Length(Svc), 0); - if not EnumServicesStatusEx(hSC, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, - @Svc[0], sizeof(Svc[0])*Length(Svc), dwNeedBytes, dwReturnBytes, dwResumeHandle, nil) then begin - CloseServiceHandle(hSC); - Code := GetLastError; - Writeln('[-] EnumServicesStatusEx error (code ', Code, ').'); - Halt(Code); - end; - end; - end; - CloseServiceHandle(hSC); - - Found := False; - for I := 0 to Length(Svc) - 1 do - begin - if Svc[I].lpServiceName = nil then - Break; - if LowerCase(Svc[I].lpServiceName) = LowerCase(TermService) then - begin - Found := True; - TermServiceName := Svc[I].lpServiceName; - TermServicePID := Svc[I].ServiceStatusProcess.dwProcessId; - Break; - end; - end; - if not Found then - begin - Writeln('[-] TermService not found.'); - Halt(ERROR_SERVICE_DOES_NOT_EXIST); - end; - if TermServicePID = 0 then - begin - if Started then begin - Writeln('[-] Failed to set up TermService. Unknown error.'); - Halt(ERROR_SERVICE_NOT_ACTIVE); - end; - SvcConfigStart(TermService, SERVICE_AUTO_START); - SvcStart(TermService); - Started := True; - goto back; - end - else - Writeln('[+] TermService found (pid ', TermServicePID, ').'); - - SetLength(ShareSvc, 0); - for I := 0 to Length(Svc) - 1 do - begin - if Svc[I].lpServiceName = nil then - Break; - if Svc[I].ServiceStatusProcess.dwProcessId = TermServicePID then - if Svc[I].lpServiceName <> TermServiceName then - begin - SetLength(ShareSvc, Length(ShareSvc)+1); - ShareSvc[Length(ShareSvc)-1] := Svc[I].lpServiceName; - end; - end; - sShareSvc := ''; - for I := 0 to Length(ShareSvc) - 1 do - if sShareSvc = '' then - sShareSvc := ShareSvc[I] - else - sShareSvc := sShareSvc + ', ' + ShareSvc[I]; - if sShareSvc <> '' then - Writeln('[*] Shared services found: ', sShareSvc) - else - Writeln('[*] No shared services found.'); -end; - -function AddPrivilege(SePriv: String): Boolean; -var - hToken: THandle; - SeNameValue: Int64; - tkp: TOKEN_PRIVILEGES; - ReturnLength: Cardinal; - ErrorCode: Cardinal; -begin - Result := False; - if not OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES - or TOKEN_QUERY, hToken) then begin - ErrorCode := GetLastError; - Writeln('[-] OpenProcessToken error (code ' + IntToStr(ErrorCode) + ').'); - Exit; - end; - if not LookupPrivilegeValue(nil, PWideChar(SePriv), SeNameValue) then begin - ErrorCode := GetLastError; - Writeln('[-] LookupPrivilegeValue error (code ' + IntToStr(ErrorCode) + ').'); - Exit; - end; - tkp.PrivilegeCount := 1; - tkp.Privileges[0].Luid := SeNameValue; - tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; - if not AdjustTokenPrivileges(hToken, False, tkp, SizeOf(tkp), tkp, ReturnLength) then begin - ErrorCode := GetLastError; - Writeln('[-] AdjustTokenPrivileges error (code ' + IntToStr(ErrorCode) + ').'); - Exit; - end; - Result := True; -end; - -procedure KillProcess(PID: DWORD); -var - hProc: THandle; - Code: DWORD; -begin - hProc := OpenProcess(PROCESS_TERMINATE, False, PID); - if hProc = 0 then - begin - Code := GetLastError; - Writeln('[-] OpenProcess error (code ', Code, ').'); - Halt(Code); - end; - if not TerminateProcess(hProc, 0) then - begin - CloseHandle(hProc); - Code := GetLastError; - Writeln('[-] TerminateProcess error (code ', Code, ').'); - Halt(Code); - end; - CloseHandle(hProc); -end; - -function ExecWait(Cmdline: String): Boolean; -var - si: STARTUPINFO; - pi: PROCESS_INFORMATION; -begin - Result := False; - ZeroMemory(@si, sizeof(si)); - si.cb := sizeof(si); - UniqueString(Cmdline); - if not CreateProcess(nil, PWideChar(Cmdline), nil, nil, True, 0, nil, nil, si, pi) then begin - Writeln('[-] CreateProcess error (code: ', GetLastError, ').'); - Exit; - end; - CloseHandle(pi.hThread); - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - Result := True; -end; - -function ExpandPath(Path: String): String; -var - Str: Array[0..511] of Char; -begin - Result := ''; - FillChar(Str, 512, 0); - if Arch = 64 then - Path := StringReplace(Path, '%ProgramFiles%', '%ProgramW6432%', [rfReplaceAll, rfIgnoreCase]); - if ExpandEnvironmentStrings(PWideChar(Path), Str, 512) > 0 then - Result := Str; -end; - -procedure SetWrapperDll; -var - Reg: TRegistry; - Code: DWORD; -begin - if Arch = 64 then - Reg := TRegistry.Create(KEY_WRITE or KEY_WOW64_64KEY) - else - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Services\TermService\Parameters', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteExpandString('ServiceDll', WrapPath); - if (Arch = 64) and (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then - ExecWait('"'+ExpandPath('%SystemRoot%')+'\system32\reg.exe" add HKLM\SYSTEM\CurrentControlSet\Services\TermService\Parameters /v ServiceDll /t REG_EXPAND_SZ /d "'+WrapPath+'" /f'); - except - Writeln('[-] WriteExpandString error.'); - Halt(ERROR_ACCESS_DENIED); - end; - - Reg.CloseKey; - Reg.Free; -end; - -procedure ResetServiceDll; -var - Reg: TRegistry; - Code: DWORD; -begin - if Arch = 64 then - Reg := TRegistry.Create(KEY_WRITE or KEY_WOW64_64KEY) - else - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Services\TermService\Parameters', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteExpandString('ServiceDll', '%SystemRoot%\System32\termsrv.dll'); - except - Writeln('[-] WriteExpandString error.'); - Halt(ERROR_ACCESS_DENIED); - end; - Reg.CloseKey; - Reg.Free; -end; - -procedure ExtractRes(ResName, Path: String); -var - ResStream: TResourceStream; -begin - ResStream := TResourceStream.Create(HInstance, ResName, RT_RCDATA); - try - ResStream.SaveToFile(Path); - except - Writeln('[-] Failed to extract file.'); - Writeln('[*] Resource name: ' + ResName); - Writeln('[*] Destination path: ' + Path); - ResStream.Free; - Exit; - end; - Writeln('[+] Extracted ', ResName, ' -> ', Path); - ResStream.Free; -end; - -function ExtractResText(ResName: String): String; -var - ResStream: TResourceStream; - Str: TStringList; -begin - ResStream := TResourceStream.Create(HInstance, ResName, RT_RCDATA); - Str := TStringList.Create; - try - Str.LoadFromStream(ResStream); - except - - end; - ResStream.Free; - Result := Str.Text; - Str.Free; -end; - -function GitINIFile(var Content: String): Boolean; -const - // Points to the latest release artifact in the sjackson0109 fork. - // The publish-ini CI/CD workflow keeps this asset up to date automatically. - URL = 'https://github.com/sjackson0109/rdpwrap/releases/latest/download/rdpwrap.ini'; -var - NetHandle: HINTERNET; - UrlHandle: HINTERNET; - Str: String; - Buf: Array[0..1023] of Byte; - BytesRead: DWORD; -begin - Result := False; - Content := ''; - NetHandle := InternetOpen('RDP Wrapper Update', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); - if not Assigned(NetHandle) then - Exit; - UrlHandle := InternetOpenUrl(NetHandle, PChar(URL), nil, 0, INTERNET_FLAG_RELOAD, 0); - if not Assigned(UrlHandle) then - begin - InternetCloseHandle(NetHandle); - Exit; - end; - repeat - InternetReadFile(UrlHandle, @Buf[0], SizeOf(Buf), BytesRead); - SetString(Str, PAnsiChar(@Buf[0]), BytesRead); - Content := Content + Str; - until BytesRead = 0; - InternetCloseHandle(UrlHandle); - InternetCloseHandle(NetHandle); - Result := True; -end; - -procedure GrantSidFullAccess(Path, SID: String); -var - p_SID: PSID; - pDACL: PACL; - EA: EXPLICIT_ACCESS; - Code, Result: DWORD; -begin - p_SID := nil; - if not ConvertStringSidToSid(PChar(SID), p_SID) then - begin - Code := GetLastError; - Writeln('[-] ConvertStringSidToSid error (code ', Code, ').'); - Exit; - end; - EA.grfAccessPermissions := GENERIC_ALL; - EA.grfAccessMode := GRANT_ACCESS; - EA.grfInheritance := SUB_CONTAINERS_AND_OBJECTS_INHERIT; - EA.Trustee.pMultipleTrustee := nil; - EA.Trustee.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE; - EA.Trustee.TrusteeForm := TRUSTEE_IS_SID; - EA.Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP; - EA.Trustee.ptstrName := p_SID; - - Result := SetEntriesInAcl(1, @EA, nil, pDACL); - if Result = ERROR_SUCCESS then - begin - if SetNamedSecurityInfo(pchar(Path), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, pDACL, nil) <> ERROR_SUCCESS then - begin - Code := GetLastError; - Writeln('[-] SetNamedSecurityInfo error (code ', Code, ').'); - end; - LocalFree(Cardinal(pDACL)); - end - else begin - Code := GetLastError; - Writeln('[-] SetEntriesInAcl error (code ', Code, ').'); - end; -end; - -procedure ExtractFiles; -var - RDPClipRes, RfxvmtRes, S: String; - OnlineINI: TStringList; -begin - if not DirectoryExists(ExtractFilePath(ExpandPath(WrapPath))) then - if ForceDirectories(ExtractFilePath(ExpandPath(WrapPath))) then begin - S := ExtractFilePath(ExpandPath(WrapPath)); - Writeln('[+] Folder created: ', S); - GrantSidFullAccess(S, 'S-1-5-18'); // Local System account - GrantSidFullAccess(S, 'S-1-5-6'); // Service group - end - else begin - Writeln('[-] ForceDirectories error.'); - Writeln('[*] Path: ', ExtractFilePath(ExpandPath(WrapPath))); - Halt(0); - end; - if Online then - begin - Writeln('[*] Downloading latest INI file...'); - OnlineINI := TStringList.Create; - if GitINIFile(S) then begin - OnlineINI.Text := S; - S := ExtractFilePath(ExpandPath(WrapPath)) + 'rdpwrap.ini'; - OnlineINI.SaveToFile(S); - Writeln('[+] Latest INI file -> ', S); - end - else - begin - Writeln('[-] Failed to get online INI file, using built-in.'); - Online := False; - end; - OnlineINI.Free; - end; - if not Online then - begin - S := ExtractFilePath(ParamStr(0)) + 'rdpwrap.ini'; - if FileExists(S) then - begin - OnlineINI := TStringList.Create; - OnlineINI.LoadFromFile(S); - S := ExtractFilePath(ExpandPath(WrapPath)) + 'rdpwrap.ini'; - OnlineINI.SaveToFile(S); - Writeln('[+] Current INI file -> ', S); - OnlineINI.Free; - end else - ExtractRes('config', ExtractFilePath(ExpandPath(WrapPath)) + 'rdpwrap.ini'); - end; - - RDPClipRes := ''; - RfxvmtRes := ''; - case Arch of - 32: begin - ExtractRes('rdpw32', ExpandPath(WrapPath)); - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then - RDPClipRes := 'rdpclip6032'; - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then - RDPClipRes := 'rdpclip6132'; - if (FV.Version.w.Major = 10) and (FV.Version.w.Minor = 0) then - RfxvmtRes := 'rfxvmt32'; - end; - 64: begin - ExtractRes('rdpw64', ExpandPath(WrapPath)); - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then - RDPClipRes := 'rdpclip6064'; - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then - RDPClipRes := 'rdpclip6164'; - if (FV.Version.w.Major = 10) and (FV.Version.w.Minor = 0) then - RfxvmtRes := 'rfxvmt64'; - end; - end; - if RDPClipRes <> '' then - if not FileExists(ExpandPath('%SystemRoot%\System32\rdpclip.exe')) then - ExtractRes(RDPClipRes, ExpandPath('%SystemRoot%\System32\rdpclip.exe')); - if RfxvmtRes <> '' then - if not FileExists(ExpandPath('%SystemRoot%\System32\rfxvmt.dll')) then - ExtractRes(RfxvmtRes, ExpandPath('%SystemRoot%\System32\rfxvmt.dll')); -end; - -procedure DeleteFiles; -var - Code: DWORD; - FullPath, Path: String; -begin - FullPath := ExpandPath(TermServicePath); - Path := ExtractFilePath(FullPath); - - if not DeleteFile(PWideChar(Path + 'rdpwrap.ini')) then - begin - Code := GetLastError; - Writeln('[-] DeleteFile error (code ', Code, ').'); - Exit; - end; - Writeln('[+] Removed file: ', Path + 'rdpwrap.ini'); - - if not DeleteFile(PWideChar(FullPath)) then - begin - Code := GetLastError; - Writeln('[-] DeleteFile error (code ', Code, ').'); - Exit; - end; - Writeln('[+] Removed file: ', FullPath); - - if not RemoveDirectory(PWideChar(ExtractFilePath(ExpandPath(TermServicePath)))) then - begin - Code := GetLastError; - Writeln('[-] RemoveDirectory error (code ', Code, ').'); - Exit; - end; - Writeln('[+] Removed folder: ', ExtractFilePath(ExpandPath(TermServicePath))); -end; - -function GetFileVersion(const FileName: TFileName; var FileVersion: FILE_VERSION): Boolean; -type - VS_VERSIONINFO = record - wLength, wValueLength, wType: Word; - szKey: Array[1..16] of WideChar; - Padding1: Word; - Value: VS_FIXEDFILEINFO; - Padding2, Children: Word; - end; - PVS_VERSIONINFO = ^VS_VERSIONINFO; -const - VFF_DEBUG = 1; - VFF_PRERELEASE = 2; - VFF_PRIVATE = 8; - VFF_SPECIAL = 32; -var - hFile: HMODULE; - hResourceInfo: HRSRC; - VersionInfo: PVS_VERSIONINFO; -begin - Result := False; - - hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE); - if hFile = 0 then - Exit; - - hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10)); - if hResourceInfo = 0 then - Exit; - - VersionInfo := Pointer(LoadResource(hFile, hResourceInfo)); - if VersionInfo = nil then - Exit; - - FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS; - FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16); - FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS); - FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG; - FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE; - FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE; - FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL; - - FreeLibrary(hFile); - Result := True; -end; - -{ ────────────────────────────────────────────────────────────────────────────── - DownloadFileToDisk - Downloads the HTTP/HTTPS resource at URL and saves it to DestPath on disk. - Returns True only when the destination file exists and is non-empty. -────────────────────────────────────────────────────────────────────────────── } -function DownloadFileToDisk(const URL, DestPath: String): Boolean; -var - NetHandle: HINTERNET; - UrlHandle: HINTERNET; - FileHandle: THandle; - Buf: Array[0..4095] of Byte; - BytesRead, BytesWritten: DWORD; -begin - Result := False; - NetHandle := InternetOpen('RDP Wrapper', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); - if not Assigned(NetHandle) then Exit; - UrlHandle := InternetOpenUrl(NetHandle, PChar(URL), nil, 0, INTERNET_FLAG_RELOAD, 0); - if not Assigned(UrlHandle) then - begin - InternetCloseHandle(NetHandle); - Exit; - end; - FileHandle := CreateFile(PChar(DestPath), GENERIC_WRITE, 0, nil, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if FileHandle = INVALID_HANDLE_VALUE then - begin - InternetCloseHandle(UrlHandle); - InternetCloseHandle(NetHandle); - Exit; - end; - repeat - InternetReadFile(UrlHandle, @Buf[0], SizeOf(Buf), BytesRead); - if BytesRead > 0 then - WriteFile(FileHandle, Buf[0], BytesRead, BytesWritten, nil); - until BytesRead = 0; - CloseHandle(FileHandle); - InternetCloseHandle(UrlHandle); - InternetCloseHandle(NetHandle); - Result := FileExists(DestPath); -end; - -{ ────────────────────────────────────────────────────────────────────────────── - INIHasSection - Returns True when the INI file at INIPath contains [Section]. -────────────────────────────────────────────────────────────────────────────── } -function INIHasSection(const INIPath, Section: String): Boolean; -var - F: TStringList; -begin - Result := False; - if not FileExists(INIPath) then Exit; - F := TStringList.Create; - try - F.LoadFromFile(INIPath); - Result := Pos('[' + Section + ']', F.Text) > 0; - finally - F.Free; - end; -end; - -{ ────────────────────────────────────────────────────────────────────────────── - TryAutoGenerateOffsets - If the current termsrv.dll version (TermSrvVerTxt) is absent from the on-disk - rdpwrap.ini, download RDPWrapOffsetFinder + Zydis from the sjackson0109 release - assets and run the finder to append the generated section to the INI. - This mirrors the approach used by sergiye/rdpWrapper (Wrapper.cs GenerateIniFile). -────────────────────────────────────────────────────────────────────────────── } -procedure TryAutoGenerateOffsets; -const - BASE_URL = 'https://github.com/sjackson0109/rdpwrap/releases/latest/download/'; -var - TempDir, ExePath, DllPath, INIPath, ArchSuffix, SysCmd: String; -begin - if TermSrvVerTxt = '' then Exit; - - INIPath := ExtractFilePath(ExpandPath(WrapPath)) + 'rdpwrap.ini'; - - if INIHasSection(INIPath, TermSrvVerTxt) then - begin - Writeln('[+] Version ', TermSrvVerTxt, ' is covered in INI.'); - Exit; - end; - - Writeln('[!] Version ', TermSrvVerTxt, ' not found in INI.'); - Writeln('[*] Attempting automatic offset generation via RDPWrapOffsetFinder...'); - - if Arch = 64 then ArchSuffix := '_x64' else ArchSuffix := '_x86'; - - TempDir := ExpandPath('%TEMP%') + '\rdpwrapoffset'; - if not ForceDirectories(TempDir) and not DirectoryExists(TempDir) then - begin - Writeln('[-] Could not create temp directory. Skipping auto-generation.'); - Exit; - end; - - ExePath := TempDir + '\RDPWrapOffsetFinder.exe'; - DllPath := TempDir + '\Zydis.dll'; - - Writeln('[*] Downloading RDPWrapOffsetFinder', ArchSuffix, '.exe ...'); - if not DownloadFileToDisk(BASE_URL + 'RDPWrapOffsetFinder' + ArchSuffix + '.exe', ExePath) then - begin - Writeln('[-] Download failed. The release asset may not yet be published.'); - Writeln('[!] Run the publish-ini workflow on the sjackson0109/rdpwrap repository,'); - Writeln('[!] then re-run this installer to enable auto-generation.'); - Exit; - end; - - Writeln('[*] Downloading Zydis', ArchSuffix, '.dll ...'); - if not DownloadFileToDisk(BASE_URL + 'Zydis' + ArchSuffix + '.dll', DllPath) then - begin - Writeln('[-] Zydis download failed. Skipping auto-generation.'); - DeleteFile(ExePath); - Exit; - end; - - Writeln('[*] Running offset finder for termsrv.dll ', TermSrvVerTxt, ' ...'); - { Run via cmd.exe so >> redirect to the INI file works correctly. } - SysCmd := ExpandPath('%SystemRoot%') + '\System32\cmd.exe'; - ExecWait('"' + SysCmd + '" /c ""' + ExePath + '" >> "' + INIPath + '""'); - - if INIHasSection(INIPath, TermSrvVerTxt) then - Writeln('[+] Offsets generated successfully for version ', TermSrvVerTxt) - else - Writeln('[!] Offset finder ran but [', TermSrvVerTxt, '] was not added.', - ' Session may be limited or unstable for this build.'); - - { Clean up temporary tool files } - DeleteFile(ExePath); - DeleteFile(DllPath); - RemoveDirectory(PChar(TempDir)); -end; - -procedure CheckTermsrvVersion; -var - SuppLvl: Byte; - VerTxt: String; - - procedure UpdateMsg; - begin - Writeln('Try running "update.bat" or "RDPWInst -w" to download latest INI file.'); - Writeln('If it doesn''t help, send your termsrv.dll to project developer for support.'); - end; -begin - GetFileVersion(ExpandPath(TermServicePath), FV); - VerTxt := Format('%d.%d.%d.%d', - [FV.Version.w.Major, FV.Version.w.Minor, FV.Release, FV.Build]); - TermSrvVerTxt := VerTxt; // expose globally for TryAutoGenerateOffsets - Writeln('[*] Terminal Services version: ', VerTxt); - - if (FV.Version.w.Major = 5) and (FV.Version.w.Minor = 1) then - begin - if Arch = 32 then - begin - Writeln('[!] Windows XP is not supported.'); - Writeln('You may take a look at RDP Realtime Patch by Stas''M for Windows XP'); - Writeln('Link: http://stascorp.com/load/1-1-0-62'); - end; - if Arch = 64 then - Writeln('[!] Windows XP 64-bit Edition is not supported.'); - Exit; - end; - if (FV.Version.w.Major = 5) and (FV.Version.w.Minor = 2) then - begin - if Arch = 32 then - Writeln('[!] Windows Server 2003 is not supported.'); - if Arch = 64 then - Writeln('[!] Windows Server 2003 or XP 64-bit Edition is not supported.'); - Exit; - end; - SuppLvl := 0; - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then begin - SuppLvl := 1; - if (Arch = 32) and (FV.Release = 6000) and (FV.Build = 16386) then begin - Writeln('[!] This version of Terminal Services may crash on logon attempt.'); - Writeln('It''s recommended to upgrade to Service Pack 1 or higher.'); - end; - end; - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then - SuppLvl := 1; - if Pos('[' + VerTxt + ']', ExtractResText('config')) > 0 then - SuppLvl := 2; - case SuppLvl of - 0: begin - Writeln('[-] This version of Terminal Services is not supported.'); - UpdateMsg; - end; - 1: begin - Writeln('[!] This version of Terminal Services is supported partially.'); - Writeln('It means you may have some limitations such as only 2 concurrent sessions.'); - UpdateMsg; - end; - 2: begin - Writeln('[+] This version of Terminal Services is fully supported.'); - end; - end; -end; - -procedure CheckTermsrvDependencies; -const - CertPropSvc = 'CertPropSvc'; - SessionEnv = 'SessionEnv'; -begin - if SvcGetStart(CertPropSvc) = SERVICE_DISABLED then - SvcConfigStart(CertPropSvc, SERVICE_DEMAND_START); - if SvcGetStart(SessionEnv) = SERVICE_DISABLED then - SvcConfigStart(SessionEnv, SERVICE_DEMAND_START); -end; - -procedure TSConfigRegistry(Enable: Boolean); -var - Reg: TRegistry; - Code: DWORD; -begin - if Arch = 64 then - Reg := TRegistry.Create(KEY_WRITE or KEY_WOW64_64KEY) - else - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteBool('fDenyTSConnections', not Enable); - except - Writeln('[-] WriteBool error.'); - Halt(ERROR_ACCESS_DENIED); - end; - Reg.CloseKey; - if Enable then - begin - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\Licensing Core', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteBool('EnableConcurrentSessions', True); - except - Writeln('[-] WriteBool error.'); - Halt(ERROR_ACCESS_DENIED); - end; - Reg.CloseKey; - - if not Reg.OpenKey('\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteBool('AllowMultipleTSSessions', True); - except - Writeln('[-] WriteBool error.'); - Halt(ERROR_ACCESS_DENIED); - end; - Reg.CloseKey; - - if not Reg.KeyExists('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns') then begin - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - Reg.CloseKey; - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns\Clip Redirector', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteString('Name', 'RDPClip'); - Reg.WriteInteger('Type', 3); - except - Writeln('[-] WriteInteger error.'); - Halt(ERROR_ACCESS_DENIED); - end; - Reg.CloseKey; - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns\DND Redirector', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteString('Name', 'RDPDND'); - Reg.WriteInteger('Type', 3); - except - Writeln('[-] WriteInteger error.'); - Halt(ERROR_ACCESS_DENIED); - end; - Reg.CloseKey; - if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns\Dynamic VC', True) then - begin - Code := GetLastError; - Writeln('[-] OpenKey error (code ', Code, ').'); - Halt(Code); - end; - try - Reg.WriteInteger('Type', -1); - except - Writeln('[-] WriteInteger error.'); - Halt(ERROR_ACCESS_DENIED); - end; - Reg.CloseKey; - end; - end; - Reg.Free; -end; - -procedure TSConfigFirewall(Enable: Boolean); -begin - if Enable then - begin - ExecWait('netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=tcp localport=3389 profile=any action=allow'); - ExecWait('netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=udp localport=3389 profile=any action=allow'); - end else - ExecWait('netsh advfirewall firewall delete rule name="Remote Desktop"'); -end; - -function CheckINIDate(Filename, Content: String; var Date: Integer): Boolean; -var - Str: TStringList; - I: Integer; -begin - Result := False; - Str := TStringList.Create; - if Filename <> '' then begin - try - Str.LoadFromFile(Filename); - except - Writeln('[-] Failed to read INI file.'); - Exit; - end; - end else - Str.Text := Content; - for I := 0 to Str.Count - 1 do - if Pos('Updated=', Str[I]) = 1 then - Break; - if I >= Str.Count then begin - Writeln('[-] Failed to check INI date.'); - Exit; - end; - Content := StringReplace(Str[I], 'Updated=', '', []); - Content := StringReplace(Content, '-', '', [rfReplaceAll]); - Str.Free; - try - Date := StrToInt(Content); - except - Writeln('[-] Wrong INI date format.'); - Exit; - end; - Result := True; -end; - -procedure CheckUpdate; -var - INIPath, S: String; - Str: TStringList; - I, OldDate, NewDate: Integer; -begin - INIPath := ExtractFilePath(ExpandPath(TermServicePath)) + 'rdpwrap.ini'; - if not CheckINIDate(INIPath, '', OldDate) then - Halt(ERROR_ACCESS_DENIED); - Writeln('[*] Current update date: ', - Format('%d.%.2d.%.2d', [OldDate div 10000, OldDate div 100 mod 100, OldDate mod 100])); - - if not GitINIFile(S) then begin - Writeln('[-] Failed to download latest INI from GitHub.'); - Halt(ERROR_ACCESS_DENIED); - end; - if not CheckINIDate('', S, NewDate) then - Halt(ERROR_ACCESS_DENIED); - Writeln('[*] Latest update date: ', - Format('%d.%.2d.%.2d', [NewDate div 10000, NewDate div 100 mod 100, NewDate mod 100])); - - if NewDate = OldDate then - Writeln('[*] Everything is up to date.') - else - if NewDate > OldDate then begin - Writeln('[+] New update is available, updating...'); - - CheckTermsrvProcess; - - Writeln('[*] Terminating service...'); - AddPrivilege('SeDebugPrivilege'); - KillProcess(TermServicePID); - Sleep(1000); - - if Length(ShareSvc) > 0 then - for I := 0 to Length(ShareSvc) - 1 do - SvcStart(ShareSvc[I]); - Sleep(500); - - Str := TStringList.Create; - Str.Text := S; - try - Str.SaveToFile(INIPath); - except - Writeln('[-] Failed to write INI file.'); - Halt(ERROR_ACCESS_DENIED); - end; - Str.Free; - - { After writing updated INI, fill any missing section for the running - termsrv.dll. FV/TermSrvVerTxt may not be set in the -w path, so - compute the version here before calling TryAutoGenerateOffsets. } - GetFileVersion(ExpandPath(TermServicePath), FV); - TermSrvVerTxt := Format('%d.%d.%d.%d', - [FV.Version.w.Major, FV.Version.w.Minor, FV.Release, FV.Build]); - Writeln('[*] Checking INI coverage for installed termsrv.dll version...'); - TryAutoGenerateOffsets; - - SvcStart(TermService); - - Writeln('[+] Update completed.'); - end else - Writeln('[*] Your INI file is newer than public file. Are you a developer? :)'); -end; - -var - I: Integer; -begin - Writeln('RDP Wrapper Library v1.6.2'); - Writeln('Installer v2.6'); - Writeln('Copyright (C) Stas''M Corp. 2018'); - Writeln(''); - - if (ParamCount < 1) - or ( - (ParamStr(1) <> '-l') - and (ParamStr(1) <> '-i') - and (ParamStr(1) <> '-w') - and (ParamStr(1) <> '-u') - and (ParamStr(1) <> '-r') - ) then - begin - Writeln('USAGE:'); - Writeln('RDPWInst.exe [-l|-i[-s][-o]|-w|-u[-k]|-r]'); - Writeln(''); - Writeln('-l display the license agreement'); - Writeln('-i install wrapper to Program Files folder (default)'); - Writeln('-i -s install wrapper to System32 folder'); - Writeln('-i -o online install mode (loads latest INI file)'); - Writeln('-w get latest update for INI file'); - Writeln('-u uninstall wrapper'); - Writeln('-u -k uninstall wrapper and keep settings'); - Writeln('-r force restart Terminal Services'); - Exit; - end; - - if ParamStr(1) = '-l' then - begin - Writeln(ExtractResText('license')); - Exit; - end; - - if not CheckWin32Version(6,0) then - begin - Writeln('[-] Unsupported Windows version:'); - Writeln(' only >= 6.0 (Vista, Server 2008 and newer) are supported.'); - Exit; - end; - - if not SupportedArchitecture then - begin - Writeln('[-] Unsupported processor architecture.'); - Exit; - end; - - CheckInstall; - - if ParamStr(1) = '-i' then - begin - if Installed then - begin - Writeln('[*] RDP Wrapper Library is already installed.'); - Halt(ERROR_INVALID_FUNCTION); - end; - Writeln('[*] Notice to user:'); - Writeln(' - By using all or any portion of this software, you are agreeing'); - Writeln(' to be bound by all the terms and conditions of the license agreement.'); - Writeln(' - To read the license agreement, run the installer with -l parameter.'); - Writeln(' - If you do not agree to any terms of the license agreement,'); - Writeln(' do not use the software.'); - - Writeln('[*] Installing...'); - if ParamStr(2) = '-s' then - WrapPath := '%SystemRoot%\system32\rdpwrap.dll' - else - WrapPath := '%ProgramFiles%\RDP Wrapper\rdpwrap.dll'; - - if Arch = 64 then - DisableWowRedirection; - - CheckTermsrvVersion; - CheckTermsrvProcess; - - Writeln('[*] Extracting files...'); - Online := (ParamStr(2) = '-o') or (ParamStr(3) = '-o'); - ExtractFiles; - - Writeln('[*] Checking INI coverage for installed termsrv.dll version...'); - TryAutoGenerateOffsets; - - Writeln('[*] Configuring service library...'); - SetWrapperDll; - - Writeln('[*] Checking dependencies...'); - CheckTermsrvDependencies; - - Writeln('[*] Terminating service...'); - AddPrivilege('SeDebugPrivilege'); - KillProcess(TermServicePID); - Sleep(1000); - - if Length(ShareSvc) > 0 then - for I := 0 to Length(ShareSvc) - 1 do - SvcStart(ShareSvc[I]); - Sleep(500); - SvcStart(TermService); - Sleep(500); - - Writeln('[*] Configuring registry...'); - TSConfigRegistry(True); - Writeln('[*] Configuring firewall...'); - TSConfigFirewall(True); - - Writeln('[+] Successfully installed.'); - - if Arch = 64 then - RevertWowRedirection; - end; - if ParamStr(1) = '-u' then - begin - if not Installed then - begin - Writeln('[*] RDP Wrapper Library is not installed.'); - Halt(ERROR_INVALID_FUNCTION); - end; - Writeln('[*] Uninstalling...'); - - if Arch = 64 then - DisableWowRedirection; - - CheckTermsrvProcess; - - Writeln('[*] Resetting service library...'); - ResetServiceDll; - - Writeln('[*] Terminating service...'); - AddPrivilege('SeDebugPrivilege'); - KillProcess(TermServicePID); - Sleep(1000); - - Writeln('[*] Removing files...'); - DeleteFiles; - - if Length(ShareSvc) > 0 then - for I := 0 to Length(ShareSvc) - 1 do - SvcStart(ShareSvc[I]); - Sleep(500); - SvcStart(TermService); - Sleep(500); - - if ParamStr(2) <> '-k' then - begin - Writeln('[*] Configuring registry...'); - TSConfigRegistry(False); - Writeln('[*] Configuring firewall...'); - TSConfigFirewall(False); - end; - - if Arch = 64 then - RevertWowRedirection; - - Writeln('[+] Successfully uninstalled.'); - end; - - if ParamStr(1) = '-w' then - begin - if not Installed then - begin - Writeln('[*] RDP Wrapper Library is not installed.'); - Halt(ERROR_INVALID_FUNCTION); - end; - Writeln('[*] Checking for updates...'); - CheckUpdate; - end; - - if ParamStr(1) = '-r' then - begin - Writeln('[*] Restarting...'); - - CheckTermsrvProcess; - - Writeln('[*] Terminating service...'); - AddPrivilege('SeDebugPrivilege'); - KillProcess(TermServicePID); - Sleep(1000); - - if Length(ShareSvc) > 0 then - for I := 0 to Length(ShareSvc) - 1 do - SvcStart(ShareSvc[I]); - Sleep(500); - SvcStart(TermService); - - Writeln('[+] Done.'); - end; -end. diff --git a/src-installer/RDPWInst.dproj b/src-installer/RDPWInst.dproj deleted file mode 100644 index 6afda06..0000000 --- a/src-installer/RDPWInst.dproj +++ /dev/null @@ -1,106 +0,0 @@ - - - {AF9BEAA3-99CD-4B2E-BE67-3F3BD27B961A} - 12.0 - RDPWInst.dpr - Release - DCC32 - - - true - - - true - Base - true - - - true - Base - true - - - ..\bin\ - WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) - ..\bin\RDPWInst.exe - 00400000 - x86 - - - false - RELEASE;$(DCC_Define) - 0 - false - - - DEBUG;$(DCC_Define) - - - - MainSource - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - - - - - Delphi.Personality.12 - - - - - False - True - False - -w - - - False - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1049 - 1251 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - RDPWInst.dpr - - - - 12 - - diff --git a/src-installer/resource.res b/src-installer/resource.res deleted file mode 100644 index 0e896e1..0000000 Binary files a/src-installer/resource.res and /dev/null differ diff --git a/src-rdpcheck/MainUnit.dfm b/src-rdpcheck/MainUnit.dfm deleted file mode 100644 index 2533973..0000000 --- a/src-rdpcheck/MainUnit.dfm +++ /dev/null @@ -1,29 +0,0 @@ -object Frm: TFrm - Left = 0 - Top = 0 - BorderIcons = [biSystemMenu, biMinimize] - BorderStyle = bsSingle - Caption = 'Local RDP Checker' - ClientHeight = 480 - ClientWidth = 640 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - Position = poDesktopCenter - OnCreate = FormCreate - PixelsPerInch = 96 - TextHeight = 13 - object RDP: TMsRdpClient2 - Left = 0 - Top = 0 - Width = 640 - Height = 480 - TabOrder = 0 - OnDisconnected = RDPDisconnected - ControlData = {0003000008000200000000000B0000000B000000} - end -end diff --git a/src-rdpcheck/MainUnit.pas b/src-rdpcheck/MainUnit.pas deleted file mode 100644 index 3c4655f..0000000 --- a/src-rdpcheck/MainUnit.pas +++ /dev/null @@ -1,160 +0,0 @@ -{ - Copyright 2015 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -unit MainUnit; - -interface - -uses - Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, - Dialogs, OleServer, MSTSCLib_TLB, OleCtrls, Registry; - -type - TFrm = class(TForm) - RDP: TMsRdpClient2; - procedure RDPDisconnected(ASender: TObject; discReason: Integer); - procedure FormCreate(Sender: TObject); - private - { Private declarations } - public - { Public declarations } - end; - -var - Frm: TFrm; - SecurityLayer, UserAuthentication: DWORD; - -implementation - -{$R *.dfm} - -procedure TFrm.FormCreate(Sender: TObject); -var - Reg: TRegistry; -begin - RDP.DisconnectedText := 'Disconnected.'; - RDP.ConnectingText := 'Connecting...'; - RDP.ConnectedStatusText := 'Connected.'; - RDP.UserName := ''; - RDP.Server := '127.0.0.2'; - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - - if Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp', True) then - begin - try - SecurityLayer := Reg.ReadInteger('SecurityLayer'); - UserAuthentication := Reg.ReadInteger('UserAuthentication'); - Reg.WriteInteger('SecurityLayer', 0); - Reg.WriteInteger('UserAuthentication', 0); - except - - end; - Reg.CloseKey; - end; - - if Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp') then begin - try - RDP.AdvancedSettings2.RDPPort := Reg.ReadInteger('PortNumber'); - except - - end; - Reg.CloseKey; - end; - Reg.Free; - Sleep(1000); - RDP.Connect; -end; - -procedure TFrm.RDPDisconnected(ASender: TObject; discReason: Integer); -var - ErrStr: String; - Reg: TRegistry; -begin - case discReason of - 1: ErrStr := 'Local disconnection.'; - 2: ErrStr := 'Disconnected by user.'; - 3: ErrStr := 'Disconnected by server.'; - $904: ErrStr := 'Socket closed.'; - $C08: ErrStr := 'Decompress error.'; - $108: ErrStr := 'Connection timed out.'; - $C06: ErrStr := 'Decryption error.'; - $104: ErrStr := 'DNS name lookup failure.'; - $508: ErrStr := 'DNS lookup failed.'; - $B06: ErrStr := 'Encryption error.'; - $604: ErrStr := 'Windows Sockets gethostbyname() call failed.'; - $208: ErrStr := 'Host not found error.'; - $408: ErrStr := 'Internal error.'; - $906: ErrStr := 'Internal security error.'; - $A06: ErrStr := 'Internal security error.'; - $506: ErrStr := 'The encryption method specified is not valid.'; - $804: ErrStr := 'Bad IP address specified.'; - $606: ErrStr := 'Server security data is not valid.'; - $406: ErrStr := 'Security data is not valid.'; - $308: ErrStr := 'The IP address specified is not valid.'; - $808: ErrStr := 'License negotiation failed.'; - $908: ErrStr := 'Licensing time-out.'; - $106: ErrStr := 'Out of memory.'; - $206: ErrStr := 'Out of memory.'; - $306: ErrStr := 'Out of memory.'; - $706: ErrStr := 'Failed to unpack server certificate.'; - $204: ErrStr := 'Socket connection failed.'; - $404: ErrStr := 'Windows Sockets recv() call failed.'; - $704: ErrStr := 'Time-out occurred.'; - $608: ErrStr := 'Internal timer error.'; - $304: ErrStr := 'Windows Sockets send() call failed.'; - $B07: ErrStr := 'The account is disabled.'; - $E07: ErrStr := 'The account is expired.'; - $D07: ErrStr := 'The account is locked out.'; - $C07: ErrStr := 'The account is restricted.'; - $1B07: ErrStr := 'The received certificate is expired.'; - $1607: ErrStr := 'The policy does not support delegation of credentials to the target server.'; - $2107: ErrStr := 'The server authentication policy does not allow connection requests using saved credentials. The user must enter new credentials.'; - $807: ErrStr := 'Login failed.'; - $1807: ErrStr := 'No authority could be contacted for authentication. The domain name of the authenticating party could be wrong, the domain could be unreachable, or there might have been a trust relationship failure.'; - $A07: ErrStr := 'The specified user has no account.'; - $F07: ErrStr := 'The password is expired.'; - $1207: ErrStr := 'The user password must be changed before logging on for the first time.'; - $1707: ErrStr := 'Delegation of credentials to the target server is not allowed unless mutual authentication has been achieved.'; - $2207: ErrStr := 'The smart card is blocked.'; - $1C07: ErrStr := 'An incorrect PIN was presented to the smart card.'; - $B09: ErrStr := 'Network Level Authentication is required, run RDPCheck as administrator.'; - $708: ErrStr := 'RDP is working, but the client doesn''t allow loopback connections. Try to connect to your PC from another device in the network.'; - else ErrStr := 'Unknown code 0x'+IntToHex(discReason, 1); - end; - if (discReason > 2) then - MessageBox(Handle, PWideChar(ErrStr), 'Disconnected', mb_Ok or mb_IconError); - - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - - if Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp', True) then - begin - try - Reg.WriteInteger('SecurityLayer', SecurityLayer); - Reg.WriteInteger('UserAuthentication', UserAuthentication); - except - - end; - Reg.CloseKey; - end; - - Reg.Free; - - Halt(0); -end; - -end. diff --git a/src-rdpcheck/RDP.ico b/src-rdpcheck/RDP.ico deleted file mode 100644 index 05a7b71..0000000 Binary files a/src-rdpcheck/RDP.ico and /dev/null differ diff --git a/src-rdpcheck/RDPCheck.dpr b/src-rdpcheck/RDPCheck.dpr deleted file mode 100644 index 5f4c5ad..0000000 --- a/src-rdpcheck/RDPCheck.dpr +++ /dev/null @@ -1,31 +0,0 @@ -{ - Copyright 2014 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -program RDPCheck; - -uses - Forms, - MainUnit in 'MainUnit.pas' {Frm}; - -{$R *.res} - -begin - Application.Initialize; - Application.MainFormOnTaskbar := True; - Application.Title := 'Local RDP Checker'; - Application.CreateForm(TFrm, Frm); - Application.Run; -end. diff --git a/src-rdpcheck/RDPCheck.dproj b/src-rdpcheck/RDPCheck.dproj deleted file mode 100644 index c5027ce..0000000 --- a/src-rdpcheck/RDPCheck.dproj +++ /dev/null @@ -1,108 +0,0 @@ - - - {90AE83F6-26B8-45D4-92FE-CF4ACCDE9F68} - 12.0 - RDPCheck.dpr - Release - DCC32 - - - true - - - true - Base - true - - - true - Base - true - - - ..\bin\ - WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) - ..\bin\RDPCheck.exe - 00400000 - x86 - - - false - RELEASE;$(DCC_Define) - 0 - false - - - DEBUG;$(DCC_Define) - - - - MainSource - - -
Frm
-
- - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - -
- - - Delphi.Personality.12 - - - - - False - True - False - - - True - False - 2 - 2 - 0 - 0 - False - False - False - False - False - 1033 - 1252 - - - Stas'M Corp. - Local RDP Checker - 2.2.0.0 - RDPCheck - Copyright © Stas'M Corp. 2015 - Stas'M Corp. - RDPCheck.exe - RDP Host Support - 1.6.0.0 - http://stascorp.com - - - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - RDPCheck.dpr - - - - 12 - -
diff --git a/src-rdpcheck/RDPCheck.res b/src-rdpcheck/RDPCheck.res deleted file mode 100644 index 724bf2e..0000000 Binary files a/src-rdpcheck/RDPCheck.res and /dev/null differ diff --git a/src-rdpconfig/LicenseUnit.dfm b/src-rdpconfig/LicenseUnit.dfm deleted file mode 100644 index fae5719..0000000 --- a/src-rdpconfig/LicenseUnit.dfm +++ /dev/null @@ -1,47 +0,0 @@ -object LicenseForm: TLicenseForm - Left = 0 - Top = 0 - BorderIcons = [] - BorderStyle = bsDialog - Caption = 'License Agreement' - ClientHeight = 344 - ClientWidth = 386 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - Position = poOwnerFormCenter - PixelsPerInch = 96 - TextHeight = 13 - object mText: TMemo - Left = 8 - Top = 8 - Width = 370 - Height = 297 - ReadOnly = True - ScrollBars = ssBoth - TabOrder = 0 - WordWrap = False - end - object bAccept: TButton - Left = 115 - Top = 311 - Width = 75 - Height = 25 - Caption = '&Accept' - ModalResult = 1 - TabOrder = 1 - end - object bDecline: TButton - Left = 196 - Top = 311 - Width = 75 - Height = 25 - Caption = '&Decline' - ModalResult = 2 - TabOrder = 2 - end -end diff --git a/src-rdpconfig/LicenseUnit.pas b/src-rdpconfig/LicenseUnit.pas deleted file mode 100644 index a44a2ad..0000000 --- a/src-rdpconfig/LicenseUnit.pas +++ /dev/null @@ -1,43 +0,0 @@ -{ - Copyright 2014 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -unit LicenseUnit; - -interface - -uses - Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, - Dialogs, StdCtrls; - -type - TLicenseForm = class(TForm) - mText: TMemo; - bAccept: TButton; - bDecline: TButton; - private - { Private declarations } - public - { Public declarations } - end; - -var - LicenseForm: TLicenseForm; - -implementation - -{$R *.dfm} - -end. diff --git a/src-rdpconfig/MainUnit.dfm b/src-rdpconfig/MainUnit.dfm deleted file mode 100644 index c077af1..0000000 --- a/src-rdpconfig/MainUnit.dfm +++ /dev/null @@ -1,241 +0,0 @@ -object MainForm: TMainForm - Left = 0 - Top = 0 - BorderStyle = bsDialog - Caption = 'RDP Wrapper Configuration' - ClientHeight = 314 - ClientWidth = 404 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - Position = poDesktopCenter - OnCloseQuery = FormCloseQuery - OnCreate = FormCreate - OnDestroy = FormDestroy - PixelsPerInch = 96 - TextHeight = 13 - object bOK: TButton - Left = 40 - Top = 281 - Width = 75 - Height = 25 - Caption = 'OK' - ModalResult = 1 - TabOrder = 4 - OnClick = bOKClick - end - object bCancel: TButton - Left = 121 - Top = 281 - Width = 75 - Height = 25 - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 5 - OnClick = bCancelClick - end - object bApply: TButton - Left = 202 - Top = 281 - Width = 75 - Height = 25 - Caption = 'Apply' - Enabled = False - TabOrder = 6 - OnClick = bApplyClick - end - object rgNLA: TRadioGroup - Left = 202 - Top = 89 - Width = 194 - Height = 73 - Caption = 'Authentication Mode' - Items.Strings = ( - 'GUI Authentication Only' - 'Default RDP Authentication' - 'Network Level Authentication') - TabOrder = 2 - OnClick = cbAllowTSConnectionsClick - end - object rgShadow: TRadioGroup - Left = 202 - Top = 168 - Width = 194 - Height = 105 - Caption = 'Session Shadowing Mode' - Items.Strings = ( - 'Disable Shadowing' - 'Full access with user'#39's permission' - 'Full access without permission' - 'View only with user'#39's permission' - 'View only without permission') - TabOrder = 3 - OnClick = cbAllowTSConnectionsClick - end - object bLicense: TButton - Left = 283 - Top = 281 - Width = 87 - Height = 25 - Caption = 'View license...' - TabOrder = 7 - OnClick = bLicenseClick - end - object gbDiag: TGroupBox - Left = 8 - Top = 6 - Width = 388 - Height = 77 - Caption = 'Diagnostics' - TabOrder = 0 - object lListener: TLabel - Left = 11 - Top = 55 - Width = 70 - Height = 13 - Caption = 'Listener state:' - end - object lService: TLabel - Left = 11 - Top = 36 - Width = 67 - Height = 13 - Caption = 'Service state:' - end - object lsListener: TLabel - Left = 91 - Top = 55 - Width = 44 - Height = 13 - Caption = 'Unknown' - end - object lsService: TLabel - Left = 91 - Top = 36 - Width = 44 - Height = 13 - Caption = 'Unknown' - end - object lsTSVer: TLabel - Left = 226 - Top = 36 - Width = 44 - Height = 13 - Caption = 'Unknown' - end - object lsWrapper: TLabel - Left = 91 - Top = 17 - Width = 44 - Height = 13 - Caption = 'Unknown' - end - object lsWrapVer: TLabel - Left = 226 - Top = 17 - Width = 44 - Height = 13 - Caption = 'Unknown' - end - object lTSVer: TLabel - Left = 202 - Top = 36 - Width = 20 - Height = 13 - Caption = 'ver.' - end - object lWrapper: TLabel - Left = 11 - Top = 17 - Width = 74 - Height = 13 - Caption = 'Wrapper state:' - end - object lWrapVer: TLabel - Left = 202 - Top = 17 - Width = 20 - Height = 13 - Caption = 'ver.' - end - object lsSuppVer: TLabel - Left = 202 - Top = 55 - Width = 70 - Height = 13 - Caption = '[support level]' - end - end - object gbGeneral: TGroupBox - Left = 8 - Top = 89 - Width = 188 - Height = 184 - Caption = 'General Settings' - TabOrder = 1 - object lRDPPort: TLabel - Left = 8 - Top = 44 - Width = 47 - Height = 13 - Caption = 'RDP port:' - end - object cbAllowTSConnections: TCheckBox - Left = 8 - Top = 18 - Width = 132 - Height = 17 - Caption = 'Enable Remote Desktop' - TabOrder = 0 - OnClick = cbAllowTSConnectionsClick - end - object cbSingleSessionPerUser: TCheckBox - Left = 8 - Top = 69 - Width = 129 - Height = 17 - Caption = 'Single session per user' - TabOrder = 2 - OnClick = cbAllowTSConnectionsClick - end - object cbHideUsers: TCheckBox - Left = 8 - Top = 92 - Width = 149 - Height = 17 - Caption = 'Hide users on logon screen' - TabOrder = 3 - OnClick = cbAllowTSConnectionsClick - end - object seRDPPort: TSpinEdit - Left = 61 - Top = 41 - Width = 62 - Height = 22 - MaxValue = 65535 - MinValue = 0 - TabOrder = 1 - Value = 0 - OnChange = seRDPPortChange - end - object cbCustomPrg: TCheckBox - Left = 8 - Top = 115 - Width = 169 - Height = 17 - Caption = 'Allow to start custom programs' - TabOrder = 4 - OnClick = cbAllowTSConnectionsClick - end - end - object Timer: TTimer - Interval = 250 - OnTimer = TimerTimer - Left = 352 - Top = 27 - end -end diff --git a/src-rdpconfig/MainUnit.pas b/src-rdpconfig/MainUnit.pas deleted file mode 100644 index 48aa051..0000000 --- a/src-rdpconfig/MainUnit.pas +++ /dev/null @@ -1,722 +0,0 @@ -{ - Copyright 2017 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -unit MainUnit; - -interface - -uses - Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, - Dialogs, StdCtrls, Spin, ExtCtrls, Registry, WinSvc; - -type - TMainForm = class(TForm) - bOK: TButton; - bCancel: TButton; - bApply: TButton; - cbSingleSessionPerUser: TCheckBox; - rgNLA: TRadioGroup; - cbAllowTSConnections: TCheckBox; - rgShadow: TRadioGroup; - seRDPPort: TSpinEdit; - lRDPPort: TLabel; - lService: TLabel; - lListener: TLabel; - lWrapper: TLabel; - lsListener: TLabel; - lsService: TLabel; - lsWrapper: TLabel; - Timer: TTimer; - lTSVer: TLabel; - lsTSVer: TLabel; - lWrapVer: TLabel; - lsWrapVer: TLabel; - bLicense: TButton; - gbDiag: TGroupBox; - lsSuppVer: TLabel; - cbHideUsers: TCheckBox; - gbGeneral: TGroupBox; - cbCustomPrg: TCheckBox; - procedure FormCreate(Sender: TObject); - procedure cbAllowTSConnectionsClick(Sender: TObject); - procedure seRDPPortChange(Sender: TObject); - procedure bApplyClick(Sender: TObject); - procedure bCancelClick(Sender: TObject); - procedure bOKClick(Sender: TObject); - procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); - procedure bLicenseClick(Sender: TObject); - procedure TimerTimer(Sender: TObject); - procedure FormDestroy(Sender: TObject); - private - { Private declarations } - public - { Public declarations } - function ExecWait(Cmdline: String): Boolean; - procedure ReadSettings; - procedure WriteSettings; - end; - FILE_VERSION = record - Version: record case Boolean of - True: (dw: DWORD); - False: (w: record - Minor, Major: Word; - end;) - end; - Release, Build: Word; - bDebug, bPrerelease, bPrivate, bSpecial: Boolean; - end; - WTS_SESSION_INFOW = record - SessionId: DWORD; - Name: packed array [0..33] of WideChar; - State: DWORD; - end; - WTS_SESSION = Array[0..0] of WTS_SESSION_INFOW; - PWTS_SESSION_INFOW = ^WTS_SESSION; - -const - winstadll = 'winsta.dll'; -var - MainForm: TMainForm; - Ready: Boolean = False; - Arch: Byte; - OldWow64RedirectionValue: LongBool; - OldPort: Word; - INI: String; - -function WinStationEnumerateW(hServer: THandle; - var ppSessionInfo: PWTS_SESSION_INFOW; var pCount: DWORD): BOOL; stdcall; - external winstadll name 'WinStationEnumerateW'; -function WinStationFreeMemory(P: Pointer): BOOL; stdcall; external winstadll; - -implementation - -{$R *.dfm} -{$R resource.res} - -uses - LicenseUnit; - -function ExpandPath(Path: String): String; -var - Str: Array[0..511] of Char; -begin - Result := ''; - FillChar(Str, 512, 0); - if Arch = 64 then - Path := StringReplace(Path, '%ProgramFiles%', '%ProgramW6432%', [rfReplaceAll, rfIgnoreCase]); - if ExpandEnvironmentStrings(PWideChar(Path), Str, 512) > 0 then - Result := Str; -end; - -function DisableWowRedirection: Boolean; -type - TFunc = function(var Wow64FsEnableRedirection: LongBool): LongBool; stdcall; -var - hModule: THandle; - Wow64DisableWow64FsRedirection: TFunc; -begin - Result := False; - hModule := GetModuleHandle(kernel32); - if hModule <> 0 then - Wow64DisableWow64FsRedirection := GetProcAddress(hModule, 'Wow64DisableWow64FsRedirection') - else - Exit; - if @Wow64DisableWow64FsRedirection <> nil then - Result := Wow64DisableWow64FsRedirection(OldWow64RedirectionValue); -end; - -function RevertWowRedirection: Boolean; -type - TFunc = function(var Wow64RevertWow64FsRedirection: LongBool): LongBool; stdcall; -var - hModule: THandle; - Wow64RevertWow64FsRedirection: TFunc; -begin - Result := False; - hModule := GetModuleHandle(kernel32); - if hModule <> 0 then - Wow64RevertWow64FsRedirection := GetProcAddress(hModule, 'Wow64RevertWow64FsRedirection') - else - Exit; - if @Wow64RevertWow64FsRedirection <> nil then - Result := Wow64RevertWow64FsRedirection(OldWow64RedirectionValue); -end; - -function GetFileVersion(const FileName: TFileName; var FileVersion: FILE_VERSION): Boolean; -type - VS_VERSIONINFO = record - wLength, wValueLength, wType: Word; - szKey: Array[1..16] of WideChar; - Padding1: Word; - Value: VS_FIXEDFILEINFO; - Padding2, Children: Word; - end; - PVS_VERSIONINFO = ^VS_VERSIONINFO; -const - VFF_DEBUG = 1; - VFF_PRERELEASE = 2; - VFF_PRIVATE = 8; - VFF_SPECIAL = 32; -var - hFile: HMODULE; - hResourceInfo: HRSRC; - VersionInfo: PVS_VERSIONINFO; -begin - Result := False; - - hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE); - if hFile = 0 then - Exit; - - hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10)); - if hResourceInfo = 0 then - Exit; - - VersionInfo := Pointer(LoadResource(hFile, hResourceInfo)); - if VersionInfo = nil then - Exit; - - FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS; - FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16); - FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS); - FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG; - FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE; - FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE; - FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL; - - FreeLibrary(hFile); - Result := True; -end; - -function IsWrapperInstalled(var WrapperPath: String): ShortInt; -var - TermServiceHost, - TermServicePath: String; - Reg: TRegistry; -begin - Result := -1; - WrapperPath := ''; - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService') then begin - Reg.Free; - Exit; - end; - TermServiceHost := Reg.ReadString('ImagePath'); - Reg.CloseKey; - if Pos('svchost.exe', LowerCase(TermServiceHost)) = 0 then - begin - Result := 2; - Reg.Free; - Exit; - end; - if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService\Parameters') then - begin - Reg.Free; - Exit; - end; - TermServicePath := Reg.ReadString('ServiceDll'); - Reg.CloseKey; - Reg.Free; - if (Pos('termsrv.dll', LowerCase(TermServicePath)) = 0) - and (Pos('rdpwrap.dll', LowerCase(TermServicePath)) = 0) then - begin - Result := 2; - Exit; - end; - - if Pos('rdpwrap.dll', LowerCase(TermServicePath)) > 0 then begin - WrapperPath := TermServicePath; - Result := 1; - end else - Result := 0; -end; - -function GetTermSrvState: ShortInt; -type - SERVICE_STATUS_PROCESS = record - dwServiceType, - dwCurrentState, - dwControlsAccepted, - dwWin32ExitCode, - dwServiceSpecificExitCode, - dwCheckPoint, - dwWaitHint, - dwProcessId, - dwServiceFlags: DWORD; - end; - PSERVICE_STATUS_PROCESS = ^SERVICE_STATUS_PROCESS; -const - SvcName = 'TermService'; -var - hSC: SC_HANDLE; - hSvc: THandle; - lpServiceStatusProcess: PSERVICE_STATUS_PROCESS; - Buf: Pointer; - cbBufSize, pcbBytesNeeded: Cardinal; -begin - Result := -1; - hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); - if hSC = 0 then - Exit; - - hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_QUERY_STATUS); - if hSvc = 0 then - begin - CloseServiceHandle(hSC); - Exit; - end; - - if QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, nil, 0, pcbBytesNeeded) then - Exit; - - cbBufSize := pcbBytesNeeded; - GetMem(Buf, cbBufSize); - - if not QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, Buf, cbBufSize, pcbBytesNeeded) then begin - FreeMem(Buf, cbBufSize); - CloseServiceHandle(hSvc); - CloseServiceHandle(hSC); - Exit; - end else begin - lpServiceStatusProcess := Buf; - Result := ShortInt(lpServiceStatusProcess^.dwCurrentState); - end; - FreeMem(Buf, cbBufSize); - CloseServiceHandle(hSvc); - CloseServiceHandle(hSC); -end; - -function IsListenerWorking: Boolean; -var - pCount: DWORD; - SessionInfo: PWTS_SESSION_INFOW; - I: Integer; -begin - Result := False; - if not WinStationEnumerateW(0, SessionInfo, pCount) then - Exit; - for I := 0 to pCount - 1 do - if SessionInfo^[I].Name = 'RDP-Tcp' then begin - Result := True; - Break; - end; - WinStationFreeMemory(SessionInfo); -end; - -function ExtractResText(ResName: String): String; -var - ResStream: TResourceStream; - Str: TStringList; -begin - ResStream := TResourceStream.Create(HInstance, ResName, RT_RCDATA); - Str := TStringList.Create; - try - Str.LoadFromStream(ResStream); - except - - end; - ResStream.Free; - Result := Str.Text; - Str.Free; -end; - -function TMainForm.ExecWait(Cmdline: String): Boolean; -var - si: STARTUPINFO; - pi: PROCESS_INFORMATION; -begin - Result := False; - ZeroMemory(@si, sizeof(si)); - si.cb := sizeof(si); - si.dwFlags := STARTF_USESHOWWINDOW; - si.wShowWindow := SW_HIDE; - UniqueString(Cmdline); - if not CreateProcess(nil, PWideChar(Cmdline), nil, nil, True, 0, nil, nil, si, pi) then begin - MessageBox(Handle, - PWideChar('CreateProcess error (code: ' + IntToStr(GetLastError) + ').'), - 'Error', MB_ICONERROR or MB_OK); - Exit; - end; - CloseHandle(pi.hThread); - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - Result := True; -end; - -procedure TMainForm.ReadSettings; -var - Reg: TRegistry; - SecurityLayer, UserAuthentication: Integer; -begin - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Control\Terminal Server'); - try - cbAllowTSConnections.Checked := not Reg.ReadBool('fDenyTSConnections'); - except - - end; - try - cbSingleSessionPerUser.Checked := Reg.ReadBool('fSingleSessionPerUser'); - except - - end; - try - cbCustomPrg.Checked := Reg.ReadBool('HonorLegacySettings'); - except - - end; - Reg.CloseKey; - - Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'); - seRDPPort.Value := 3389; - try - seRDPPort.Value := Reg.ReadInteger('PortNumber'); - except - - end; - OldPort := seRDPPort.Value; - SecurityLayer := 0; - UserAuthentication := 0; - try - SecurityLayer := Reg.ReadInteger('SecurityLayer'); - UserAuthentication := Reg.ReadInteger('UserAuthentication'); - except - - end; - if (SecurityLayer = 0) and (UserAuthentication = 0) then - rgNLA.ItemIndex := 0; - if (SecurityLayer = 1) and (UserAuthentication = 0) then - rgNLA.ItemIndex := 1; - if (SecurityLayer = 2) and (UserAuthentication = 1) then - rgNLA.ItemIndex := 2; - try - rgShadow.ItemIndex := Reg.ReadInteger('Shadow'); - except - - end; - Reg.CloseKey; - Reg.OpenKeyReadOnly('\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'); - try - cbHideUsers.Checked := Reg.ReadBool('dontdisplaylastusername'); - except - - end; - Reg.CloseKey; - Reg.Free; -end; - -procedure TMainForm.WriteSettings; -var - Reg: TRegistry; - SecurityLayer, UserAuthentication: Integer; -begin - Reg := TRegistry.Create; - Reg.RootKey := HKEY_LOCAL_MACHINE; - Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server', True); - try - Reg.WriteBool('fDenyTSConnections', not cbAllowTSConnections.Checked); - except - - end; - try - Reg.WriteBool('fSingleSessionPerUser', cbSingleSessionPerUser.Checked); - except - - end; - try - Reg.WriteBool('HonorLegacySettings', cbCustomPrg.Checked); - except - - end; - Reg.CloseKey; - - Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp', True); - try - Reg.WriteInteger('PortNumber', seRDPPort.Value); - except - - end; - if OldPort <> seRDPPort.Value then - begin - OldPort := seRDPPort.Value; - ExecWait('netsh advfirewall firewall set rule name="Remote Desktop" new localport=' + IntToStr(OldPort)); - end; - case rgNLA.ItemIndex of - 0: begin - SecurityLayer := 0; - UserAuthentication := 0; - end; - 1: begin - SecurityLayer := 1; - UserAuthentication := 0; - end; - 2: begin - SecurityLayer := 2; - UserAuthentication := 1; - end; - else begin - SecurityLayer := -1; - UserAuthentication := -1; - end; - end; - if SecurityLayer >= 0 then begin - try - Reg.WriteInteger('SecurityLayer', SecurityLayer); - Reg.WriteInteger('UserAuthentication', UserAuthentication); - except - - end; - end; - if rgShadow.ItemIndex >= 0 then begin - try - Reg.WriteInteger('Shadow', rgShadow.ItemIndex); - except - - end; - end; - Reg.CloseKey; - Reg.OpenKey('\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services', True); - if rgShadow.ItemIndex >= 0 then begin - try - Reg.WriteInteger('Shadow', rgShadow.ItemIndex); - except - - end; - end; - Reg.CloseKey; - Reg.OpenKey('\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System', True); - try - Reg.WriteBool('dontdisplaylastusername', cbHideUsers.Checked); - except - - end; - Reg.CloseKey; - Reg.Free; -end; - -function CheckSupport(FV: FILE_VERSION): Byte; -var - VerTxt: String; -begin - Result := 0; - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then - Result := 1; - if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then - Result := 1; - VerTxt := Format('%d.%d.%d.%d', - [FV.Version.w.Major, FV.Version.w.Minor, FV.Release, FV.Build]); - if Pos('[' + VerTxt + ']', INI) > 0 then - Result := 2; -end; - -procedure TMainForm.TimerTimer(Sender: TObject); -var - WrapperPath, INIPath: String; - FV: FILE_VERSION; - L: TStringList; - CheckSupp: Boolean; -begin - CheckSupp := False; - case IsWrapperInstalled(WrapperPath) of - -1: begin - lsWrapper.Caption := 'Unknown'; - lsWrapper.Font.Color := clGrayText; - end; - 0: begin - lsWrapper.Caption := 'Not installed'; - lsWrapper.Font.Color := clGrayText; - end; - 1: begin - lsWrapper.Caption := 'Installed'; - lsWrapper.Font.Color := clGreen; - CheckSupp := True; - INIPath := ExtractFilePath(ExpandPath(WrapperPath)) + 'rdpwrap.ini'; - if not FileExists(INIPath) then - CheckSupp := False; - end; - 2: begin - lsWrapper.Caption := '3rd-party'; - lsWrapper.Font.Color := clRed; - end; - end; - case GetTermSrvState of - -1, 0: begin - lsService.Caption := 'Unknown'; - lsService.Font.Color := clGrayText; - end; - SERVICE_STOPPED: begin - lsService.Caption := 'Stopped'; - lsService.Font.Color := clRed; - end; - SERVICE_START_PENDING: begin - lsService.Caption := 'Starting...'; - lsService.Font.Color := clGrayText; - end; - SERVICE_STOP_PENDING: begin - lsService.Caption := 'Stopping...'; - lsService.Font.Color := clGrayText; - end; - SERVICE_RUNNING: begin - lsService.Caption := 'Running'; - lsService.Font.Color := clGreen; - end; - SERVICE_CONTINUE_PENDING: begin - lsService.Caption := 'Resuming...'; - lsService.Font.Color := clGrayText; - end; - SERVICE_PAUSE_PENDING: begin - lsService.Caption := 'Suspending...'; - lsService.Font.Color := clGrayText; - end; - SERVICE_PAUSED: begin - lsService.Caption := 'Suspended'; - lsService.Font.Color := clWindowText; - end; - end; - if IsListenerWorking then begin - lsListener.Caption := 'Listening'; - lsListener.Font.Color := clGreen; - end else begin - lsListener.Caption := 'Not listening'; - lsListener.Font.Color := clRed; - end; - if WrapperPath = '' then begin - lsWrapVer.Caption := 'N/A'; - lsWrapVer.Font.Color := clGrayText; - end else - if not GetFileVersion(ExpandPath(WrapperPath), FV) then begin - lsWrapVer.Caption := 'N/A'; - lsWrapVer.Font.Color := clGrayText; - end else begin - lsWrapVer.Caption := - IntToStr(FV.Version.w.Major)+'.'+ - IntToStr(FV.Version.w.Minor)+'.'+ - IntToStr(FV.Release)+'.'+ - IntToStr(FV.Build); - lsWrapVer.Font.Color := clWindowText; - end; - if not GetFileVersion('termsrv.dll', FV) then begin - lsTSVer.Caption := 'N/A'; - lsTSVer.Font.Color := clGrayText; - end else begin - lsTSVer.Caption := - IntToStr(FV.Version.w.Major)+'.'+ - IntToStr(FV.Version.w.Minor)+'.'+ - IntToStr(FV.Release)+'.'+ - IntToStr(FV.Build); - lsTSVer.Font.Color := clWindowText; - lsSuppVer.Visible := CheckSupp; - if CheckSupp then begin - if INI = '' then begin - L := TStringList.Create; - try - L.LoadFromFile(INIPath); - except - - end; - INI := L.Text; - L.Free; - end; - case CheckSupport(FV) of - 0: begin - lsSuppVer.Caption := '[not supported]'; - lsSuppVer.Font.Color := clRed; - end; - 1: begin - lsSuppVer.Caption := '[supported partially]'; - lsSuppVer.Font.Color := clOlive; - end; - 2: begin - lsSuppVer.Caption := '[fully supported]'; - lsSuppVer.Font.Color := clGreen; - end; - end; - end; - end; -end; - -procedure TMainForm.bLicenseClick(Sender: TObject); -begin - LicenseForm.mText.Text := ExtractResText('LICENSE'); - if LicenseForm.ShowModal <> mrOk then - Halt(0); -end; - -procedure TMainForm.cbAllowTSConnectionsClick(Sender: TObject); -begin - if Ready then - bApply.Enabled := True; -end; - -procedure TMainForm.seRDPPortChange(Sender: TObject); -begin - if Ready then - bApply.Enabled := True; -end; - -procedure TMainForm.FormCreate(Sender: TObject); -var - SI: TSystemInfo; -begin - GetNativeSystemInfo(SI); - case SI.wProcessorArchitecture of - 0: Arch := 32; - 6: Arch := 64; // Itanium-based x64 - 9: Arch := 64; // Intel/AMD x64 - else Arch := 0; - end; - if Arch = 64 then - DisableWowRedirection; - ReadSettings; - Ready := True; -end; - -procedure TMainForm.FormDestroy(Sender: TObject); -begin - if Arch = 64 then - RevertWowRedirection; -end; - -procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); -begin - if bApply.Enabled then - CanClose := MessageBox(Handle, 'Settings are not saved. Do you want to exit?', - 'Warning', mb_IconWarning or mb_YesNo) = mrYes; -end; - -procedure TMainForm.bOKClick(Sender: TObject); -begin - if bApply.Enabled then begin - WriteSettings; - bApply.Enabled := False; - end; - Close; -end; - -procedure TMainForm.bCancelClick(Sender: TObject); -begin - Close; -end; - -procedure TMainForm.bApplyClick(Sender: TObject); -begin - WriteSettings; - bApply.Enabled := False; -end; - -end. diff --git a/src-rdpconfig/RDPConf.dpr b/src-rdpconfig/RDPConf.dpr deleted file mode 100644 index 3fd645f..0000000 --- a/src-rdpconfig/RDPConf.dpr +++ /dev/null @@ -1,33 +0,0 @@ -{ - Copyright 2014 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -program RDPConf; - -uses - Forms, - MainUnit in 'MainUnit.pas' {MainForm}, - LicenseUnit in 'LicenseUnit.pas' {LicenseForm}; - -{$R *.res} - -begin - Application.Initialize; - Application.MainFormOnTaskbar := True; - Application.Title := 'Remote Desktop Protocol Configuration'; - Application.CreateForm(TMainForm, MainForm); - Application.CreateForm(TLicenseForm, LicenseForm); - Application.Run; -end. diff --git a/src-rdpconfig/RDPConf.dproj b/src-rdpconfig/RDPConf.dproj deleted file mode 100644 index aa9ab96..0000000 --- a/src-rdpconfig/RDPConf.dproj +++ /dev/null @@ -1,111 +0,0 @@ - - - {A7CB4C30-85F5-4D96-B510-6F0CDCF7C2DA} - 12.0 - RDPConf.dpr - Debug - DCC32 - - - true - - - true - Base - true - - - true - Base - true - - - ..\bin\ - WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) - ..\bin\RDPConf.exe - 00400000 - x86 - - - false - RELEASE;$(DCC_Define) - 0 - false - - - DEBUG;$(DCC_Define) - - - - MainSource - - -
MainForm
-
- -
LicenseForm
-
- - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - -
- - - Delphi.Personality.12 - - - - - RDPConf.dpr - - - False - True - False - - - False - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1033 - 1252 - - - Stas'M Corp. - RDP Configuration Program - 1.0.0.0 - RDPConf - Copyright © Stas'M Corp. 2014 - Stas'M Corp. - RDPConf.exe - RDP Host Support - 1.4.0.0 - http://stascorp.com - - - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - 12 - -
diff --git a/src-rdpconfig/RDPConf.res b/src-rdpconfig/RDPConf.res deleted file mode 100644 index f987dd9..0000000 Binary files a/src-rdpconfig/RDPConf.res and /dev/null differ diff --git a/src-rdpconfig/resource.res b/src-rdpconfig/resource.res deleted file mode 100644 index 68f82f2..0000000 Binary files a/src-rdpconfig/resource.res and /dev/null differ diff --git a/src-x86-binarymaster/LiteINI.pas b/src-x86-binarymaster/LiteINI.pas deleted file mode 100644 index 08d144d..0000000 --- a/src-x86-binarymaster/LiteINI.pas +++ /dev/null @@ -1,375 +0,0 @@ -{ - Copyright 2014 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -unit LiteINI; - -interface - -uses - SysUtils; - -type - SList = Array of String; - INIValue = record - Name: String; - Value: String; - end; - INISection = record - Name: String; - Values: Array of INIValue; - end; - INIFile = Array of INISection; - -procedure SListClear(var List: SList); -function SListAppend(var List: SList; S: String): Integer; -function SListFind(List: SList; Value: String): Integer; -function INIFindSection(INI: INIFile; Section: String): Integer; -function INIFindValue(INI: INIFile; Section: Integer; Value: String): Integer; -function INIAddSection(var INI: INIFile; Section: String): Integer; -function INIAddValue(var INI: INIFile; Section: Integer; ValueName, Value: String): Integer; -procedure INIUnload(var INI: INIFile); -procedure INILoad(var INI: INIFile; FileName: String); -function INISectionExists(INI: INIFile; Section: String): Boolean; -function INIValueExists(INI: INIFile; Section: String; Value: String): Boolean; -function INIReadSectionLowAPI(INI: INIFile; Section: Integer; var List: SList): Boolean; -function INIReadSection(INI: INIFile; Section: String): SList; -function INIReadStringLowAPI(INI: INIFile; Section, Value: Integer; var Str: String): Boolean; -function INIReadString(INI: INIFile; Section, Value, Default: String): String; -function INIReadInt(INI: INIFile; Section, Value: String; Default: Integer): Integer; -function INIReadDWord(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; -function INIReadIntHex(INI: INIFile; Section, Value: String; Default: Integer): Integer; -function INIReadDWordHex(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; -function INIReadBool(INI: INIFile; Section, Value: String; Default: Boolean): Boolean; -function INIReadBytes(INI: INIFile; Section, Value: String): TBytes; -function INIReadBytesDef(INI: INIFile; Section, Value: String; Default: TBytes): TBytes; - -implementation - -procedure SListClear(var List: SList); -begin - SetLength(List, 0); -end; - -function SListAppend(var List: SList; S: String): Integer; -begin - SetLength(List, Length(List) + 1); - List[Length(List) - 1] := S; - Result := Length(List) - 1; -end; - -function SListFind(List: SList; Value: String): Integer; -var - I: Integer; -begin - Result := -1; - for I := 0 to Length(List) - 1 do - if List[I] = Value then begin - Result := I; - Break; - end; -end; - -function INIFindSection(INI: INIFile; Section: String): Integer; -var - I: Integer; -begin - Result := -1; - for I := 0 to Length(INI) - 1 do - if INI[I].Name = Section then begin - Result := I; - Exit; - end; -end; - -function INIFindValue(INI: INIFile; Section: Integer; Value: String): Integer; -var - I: Integer; -begin - Result := -1; - if (Section < 0) or (Section >= Length(INI)) then - Exit; - for I := 0 to Length(INI[Section].Values) - 1 do - if INI[Section].Values[I].Name = Value then begin - Result := I; - Exit; - end; -end; - -function INIAddSection(var INI: INIFile; Section: String): Integer; -begin - Result := INIFindSection(INI, Section); - if Result >= 0 then - Exit; - Result := Length(INI); - SetLength(INI, Result + 1); - INI[Result].Name := Section; - SetLength(INI[Result].Values, 0); -end; - -function INIAddValue(var INI: INIFile; Section: Integer; ValueName, Value: String): Integer; -var - I: Integer; -begin - Result := -1; - if (Section < 0) or (Section >= Length(INI)) then - Exit; - I := INIFindValue(INI, Section, ValueName); - if I = -1 then begin - Result := Length(INI[Section].Values); - SetLength(INI[Section].Values, Result + 1); - INI[Section].Values[Result].Name := ValueName; - INI[Section].Values[Result].Value := Value; - end else begin - INI[Section].Values[I].Value := Value; - Result := I; - end; -end; - -procedure INIUnload(var INI: INIFile); -begin - SetLength(INI, 0); -end; - -procedure INILoad(var INI: INIFile; FileName: String); -var - F: TextFile; - S, ValueName, Value: String; - INIList: SList; - I, Sect: Integer; -begin - INIUnload(INI); - if not FileExists(FileName) then - Exit; - AssignFile(F, FileName); - Reset(F); - // Read and filter lines - while not EOF(F) do begin - Readln(F, S); - if (Pos(';', S) <> 1) - and (Pos('#', S) <> 1) - and ( - ((Pos('[', S) > 0) and (Pos(']', S) > 0)) or - (Pos('=', S) > 0) - ) - then - SListAppend(INIList, S); - end; - CloseFile(F); - // Parse 2 (parse format) - Sect := -1; - for I := 0 to Length(INIList) - 1 do begin - S := Trim(INIList[I]); - if Length(S) >= 2 then - if (S[1] = '[') and (S[Length(S)] = ']') then begin - S := Trim(Copy(S, 2, Length(S) - 2)); - Sect := INIAddSection(INI, S); - Continue; - end; - S := INIList[I]; - if Pos('=', S) > 0 then begin - ValueName := Trim(Copy(S, 1, Pos('=', S) - 1)); - Value := Copy(S, Pos('=', S) + 1, Length(S) - Pos('=', S)); - if Sect = -1 then - Sect := INIAddSection(INI, ''); - INIAddValue(INI, Sect, ValueName, Value); - end; - end; -end; - -function INISectionExists(INI: INIFile; Section: String): Boolean; -begin - Result := INIFindSection(INI, Section) > -1; -end; - -function INIValueExists(INI: INIFile; Section: String; Value: String): Boolean; -var - Sect: Integer; -begin - Sect := INIFindSection(INI, Section); - Result := INIFindValue(INI, Sect, Value) > -1; -end; - -function INIReadSectionLowAPI(INI: INIFile; Section: Integer; var List: SList): Boolean; -var - I: Integer; -begin - Result := False; - SetLength(List, 0); - if (Section < 0) or (Section >= Length(INI)) then - Exit; - for I := 0 to Length(INI[Section].Values) - 1 do - SListAppend(List, INI[Section].Values[I].Name); - Result := True; -end; - -function INIReadSection(INI: INIFile; Section: String): SList; -var - Sect: Integer; -begin - Sect := INIFindSection(INI, Section); - INIReadSectionLowAPI(INI, Sect, Result); -end; - -function INIReadStringLowAPI(INI: INIFile; Section, Value: Integer; var Str: String): Boolean; -begin - Result := False; - if (Section < 0) or (Section >= Length(INI)) then - Exit; - if (Value < 0) or (Value >= Length(INI[Section].Values)) then - Exit; - Str := INI[Section].Values[Value].Value; - Result := True; -end; - -function INIReadString(INI: INIFile; Section, Value, Default: String): String; -var - Sect, Val: Integer; -begin - Sect := INIFindSection(INI, Section); - Val := INIFindValue(INI, Sect, Value); - if not INIReadStringLowAPI(INI, Sect, Val, Result) then - Result := Default; -end; - -function INIReadInt(INI: INIFile; Section, Value: String; Default: Integer): Integer; -var - S: String; - E: Integer; -begin - S := INIReadString(INI, Section, Value, ''); - Val(S, Result, E); - if E <> 0 then - Result := Default; -end; - -function INIReadDWord(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; -var - S: String; - E: Integer; -begin - S := INIReadString(INI, Section, Value, ''); - Val(S, Result, E); - if E <> 0 then - Result := Default; -end; - -function INIReadIntHex(INI: INIFile; Section, Value: String; Default: Integer): Integer; -var - S: String; - E: Integer; -begin - S := INIReadString(INI, Section, Value, ''); - Val('$'+S, Result, E); - if E <> 0 then - Result := Default; -end; - -function INIReadDWordHex(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; -var - S: String; - E: Integer; -begin - S := INIReadString(INI, Section, Value, ''); - Val('$'+S, Result, E); - if E <> 0 then - Result := Default; -end; - -function INIReadBool(INI: INIFile; Section, Value: String; Default: Boolean): Boolean; -var - S: String; - I: Cardinal; - E: Integer; -begin - S := INIReadString(INI, Section, Value, ''); - Val(S, I, E); - if E <> 0 then - Result := Default - else - Result := I > 0; -end; - -function StringToBytes(S: String; var B: TBytes): Boolean; -var - I: Integer; -begin - Result := False; - if Odd(Length(S)) then - Exit; - SetLength(B, Length(S) div 2); - for I := 0 to Length(B) - 1 do begin - B[I] := 0; - case S[(I*2)+2] of - '0': ; - '1': B[I] := B[I] or $1; - '2': B[I] := B[I] or $2; - '3': B[I] := B[I] or $3; - '4': B[I] := B[I] or $4; - '5': B[I] := B[I] or $5; - '6': B[I] := B[I] or $6; - '7': B[I] := B[I] or $7; - '8': B[I] := B[I] or $8; - '9': B[I] := B[I] or $9; - 'A','a': B[I] := B[I] or $A; - 'B','b': B[I] := B[I] or $B; - 'C','c': B[I] := B[I] or $C; - 'D','d': B[I] := B[I] or $D; - 'E','e': B[I] := B[I] or $E; - 'F','f': B[I] := B[I] or $F; - else Exit; - end; - case S[(I*2)+1] of - '0': ; - '1': B[I] := B[I] or $10; - '2': B[I] := B[I] or $20; - '3': B[I] := B[I] or $30; - '4': B[I] := B[I] or $40; - '5': B[I] := B[I] or $50; - '6': B[I] := B[I] or $60; - '7': B[I] := B[I] or $70; - '8': B[I] := B[I] or $80; - '9': B[I] := B[I] or $90; - 'A','a': B[I] := B[I] or $A0; - 'B','b': B[I] := B[I] or $B0; - 'C','c': B[I] := B[I] or $C0; - 'D','d': B[I] := B[I] or $D0; - 'E','e': B[I] := B[I] or $E0; - 'F','f': B[I] := B[I] or $F0; - else Exit; - end; - end; - Result := True; -end; - -function INIReadBytes(INI: INIFile; Section, Value: String): TBytes; -var - S: String; -begin - S := INIReadString(INI, Section, Value, ''); - if not StringToBytes(S, Result) then - SetLength(Result, 0); -end; - -function INIReadBytesDef(INI: INIFile; Section, Value: String; Default: TBytes): TBytes; -var - S: String; -begin - S := INIReadString(INI, Section, Value, ''); - if not StringToBytes(S, Result) then - Result := Default; -end; - -end. diff --git a/src-x86-binarymaster/rdpwrap.dpr b/src-x86-binarymaster/rdpwrap.dpr deleted file mode 100644 index 38b85f6..0000000 --- a/src-x86-binarymaster/rdpwrap.dpr +++ /dev/null @@ -1,737 +0,0 @@ -{ - Copyright 2014 Stas'M Corp. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -} - -library rdpwrap; - -uses - SysUtils, - Windows, - TlHelp32, - LiteINI; - -{$R rdpwrap.res} - -// Hook core definitions - -type - OldCode = packed record - One: DWORD; - two: Word; - end; - - far_jmp = packed record - PushOp: Byte; - PushArg: Pointer; - RetOp: Byte; - end; - - mov_far_jmp = packed record - MovOp: Byte; - MovArg: Byte; - PushOp: Byte; - PushArg: Pointer; - RetOp: Byte; - end; - - TTHREADENTRY32 = packed record - dwSize: DWORD; - cntUsage: DWORD; - th32ThreadID: DWORD; - th32OwnerProcessID: DWORD; - tpBasePri: LongInt; - tpDeltaPri: LongInt; - dwFlags: DWORD; - end; - //IntArray = Array of Integer; - FILE_VERSION = record - Version: record case Boolean of - True: (dw: DWORD); - False: (w: record - Minor, Major: Word; - end;) - end; - Release, Build: Word; - bDebug, bPrerelease, bPrivate, bSpecial: Boolean; - end; - -const - THREAD_SUSPEND_RESUME = 2; - TH32CS_SNAPTHREAD = 4; -var - INI: INIFile; - LogFile: String = '\rdpwrap.txt'; - bw: {$if CompilerVersion>=16} NativeUInt {$else} DWORD {$endif}; - IsHooked: Boolean = False; - -// Unhooked import - -function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; - dwThreadId: DWORD): DWORD; stdcall; external kernel32; - -function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): DWORD; - stdcall; external kernel32; - -function Thread32First(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool; - stdcall; external kernel32; - -function Thread32Next(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool; - stdcall; external kernel32; - -// Wrapped import - -var - TSMain: function(dwArgc: DWORD; lpszArgv: PWideChar): DWORD; stdcall; - TSGlobals: function(lpGlobalData: Pointer): DWORD; stdcall; - -// Hooked import and vars - -var - SLGetWindowsInformationDWORD: function(pwszValueName: PWideChar; - pdwValue: PDWORD): HRESULT; stdcall; - TermSrvBase: Pointer; - FV: FILE_VERSION; - -var - Stub_SLGetWindowsInformationDWORD: far_jmp; - Old_SLGetWindowsInformationDWORD: OldCode; - -// Main code - -procedure WriteLog(S: AnsiString); -var - F: TextFile; -begin - if not FileExists(LogFile) then - Exit; - AssignFile(F, LogFile); - Append(F); - Write(F, S+#13#10); - CloseFile(F); -end; - -function GetModuleHandleEx(dwFlags: DWORD; lpModuleName: PWideChar; - var phModule: HMODULE): BOOL; stdcall; external kernel32 name 'GetModuleHandleExW'; - -function GetCurrentModule: HMODULE; -const - GET_MODULE_HANDLE_EX_FLAG_PIN = 1; - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2; - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 4; -begin - Result := 0; - GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, @GetCurrentModule, Result); -end; - -function GetBinaryPath: String; -var - Buf: Array[0..511] of Byte; -begin - ZeroMemory(@Buf[0], Length(Buf)); - GetModuleFileName(GetCurrentModule, PWideChar(@Buf[0]), Length(Buf)); - Result := PWideChar(@Buf[0]); -end; - -procedure StopThreads; -var - h, CurrTh, ThrHandle, CurrPr: DWORD; - Thread: TTHREADENTRY32; -begin - CurrTh := GetCurrentThreadId; - CurrPr := GetCurrentProcessId; - h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if h <> INVALID_HANDLE_VALUE then - begin - Thread.dwSize := SizeOf(TTHREADENTRY32); - if Thread32First(h, Thread) then - repeat - if (Thread.th32ThreadID <> CurrTh) and - (Thread.th32OwnerProcessID = CurrPr) then - begin - ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false, - Thread.th32ThreadID); - if ThrHandle > 0 then - begin - SuspendThread(ThrHandle); - CloseHandle(ThrHandle); - end; - end; - until not Thread32Next(h, Thread); - CloseHandle(h); - end; -end; - -procedure RunThreads; -var - h, CurrTh, ThrHandle, CurrPr: DWORD; - Thread: TTHREADENTRY32; -begin - CurrTh := GetCurrentThreadId; - CurrPr := GetCurrentProcessId; - h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if h <> INVALID_HANDLE_VALUE then - begin - Thread.dwSize := SizeOf(TTHREADENTRY32); - if Thread32First(h, Thread) then - repeat - if (Thread.th32ThreadID <> CurrTh) and - (Thread.th32OwnerProcessID = CurrPr) then - begin - ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false, - Thread.th32ThreadID); - if ThrHandle > 0 then - begin - ResumeThread(ThrHandle); - CloseHandle(ThrHandle); - end; - end; - until not Thread32Next(h, Thread); - CloseHandle(h); - end; -end; - -function GetModuleAddress(ModuleName: String; ProcessId: DWORD; var BaseAddr: Pointer; var BaseSize: DWORD): Boolean; -var - hSnap: THandle; - md: MODULEENTRY32; -begin - Result := False; - hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId); - if hSnap = INVALID_HANDLE_VALUE Then - Exit; - md.dwSize := SizeOf(MODULEENTRY32); - if Module32First(hSnap, md) then - begin - if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then - begin - Result := True; - BaseAddr := Pointer(md.modBaseAddr); - BaseSize := md.modBaseSize; - CloseHandle(hSnap); - Exit; - end; - while Module32Next(hSnap, md) Do - begin - if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then - begin - Result := True; - BaseAddr := Pointer(md.modBaseAddr); - BaseSize := md.modBaseSize; - Break; - end; - end; - end; - CloseHandle(hSnap); -end; - -{procedure FindMem(Mem: Pointer; MemSz: DWORD; Buf: Pointer; BufSz: DWORD; - From: DWORD; var A: IntArray); -var - I: Integer; -begin - SetLength(A, 0); - I:=From; - if From>0 then - Inc(PByte(Mem), From); - while I < MemSz - BufSz + 1 do - begin - if (not IsBadReadPtr(Mem, BufSz)) and (CompareMem(Mem, Buf, BufSz)) then - begin - SetLength(A, Length(A)+1); - A[Length(A)-1] := I; - end; - Inc(I); - Inc(PByte(Mem)); - end; -end;} - -function GetModuleVersion(const ModuleName: String; var FileVersion: FILE_VERSION): Boolean; -type - VS_VERSIONINFO = record - wLength, wValueLength, wType: Word; - szKey: Array[1..16] of WideChar; - Padding1: Word; - Value: VS_FIXEDFILEINFO; - Padding2, Children: Word; - end; - PVS_VERSIONINFO = ^VS_VERSIONINFO; -const - VFF_DEBUG = 1; - VFF_PRERELEASE = 2; - VFF_PRIVATE = 8; - VFF_SPECIAL = 32; -var - hMod: HMODULE; - hResourceInfo: HRSRC; - VersionInfo: PVS_VERSIONINFO; -begin - Result := False; - - if ModuleName = '' then - hMod := GetModuleHandle(nil) - else - hMod := GetModuleHandle(PWideChar(ModuleName)); - if hMod = 0 then - Exit; - - hResourceInfo := FindResource(hMod, PWideChar(1), PWideChar($10)); - if hResourceInfo = 0 then - Exit; - - VersionInfo := Pointer(LoadResource(hMod, hResourceInfo)); - if VersionInfo = nil then - Exit; - - FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS; - FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16); - FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS); - FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG; - FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE; - FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE; - FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL; - - Result := True; -end; - -function GetFileVersion(const FileName: String; var FileVersion: FILE_VERSION): Boolean; -type - VS_VERSIONINFO = record - wLength, wValueLength, wType: Word; - szKey: Array[1..16] of WideChar; - Padding1: Word; - Value: VS_FIXEDFILEINFO; - Padding2, Children: Word; - end; - PVS_VERSIONINFO = ^VS_VERSIONINFO; -const - VFF_DEBUG = 1; - VFF_PRERELEASE = 2; - VFF_PRIVATE = 8; - VFF_SPECIAL = 32; -var - hFile: HMODULE; - hResourceInfo: HRSRC; - VersionInfo: PVS_VERSIONINFO; -begin - Result := False; - - hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE); - if hFile = 0 then - Exit; - - hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10)); - if hResourceInfo = 0 then - Exit; - - VersionInfo := Pointer(LoadResource(hFile, hResourceInfo)); - if VersionInfo = nil then - Exit; - - FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS; - FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16); - FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS); - FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG; - FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE; - FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE; - FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL; - - Result := True; -end; - -function OverrideSL(ValueName: String; var Value: DWORD): Boolean; -begin - Result := True; - if INIValueExists(INI, 'SLPolicy', ValueName) then begin - Value := INIReadDWord(INI, 'SLPolicy', ValueName, 0); - Exit; - end; - Result := False; -end; - -function New_SLGetWindowsInformationDWORD(pwszValueName: PWideChar; - pdwValue: PDWORD): HRESULT; stdcall; -var - dw: DWORD; -begin - // wrapped SLGetWindowsInformationDWORD function - // termsrv.dll will call this function instead of original SLC.dll - - // Override SL Policy - - WriteLog('Policy query: ' + pwszValueName); - if OverrideSL(pwszValueName, dw) then begin - pdwValue^ := dw; - Result := S_OK; - WriteLog('Policy rewrite: ' + IntToStr(pdwValue^)); - Exit; - end; - - // If the requested value name is not defined above - - // revert to original SL Policy function - WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, - @Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw); - - // get result - Result := SLGetWindowsInformationDWORD(pwszValueName, pdwValue); - if Result = S_OK then - WriteLog('Policy result: ' + IntToStr(pdwValue^)) - else - WriteLog('Policy request failed'); - // wrap it back - WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, - @Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw); -end; - -function New_Win8SL(pwszValueName: PWideChar; pdwValue: PDWORD): HRESULT; register; -var - dw: DWORD; -begin - // wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll - // for Windows 8 support - - // Override SL Policy - - WriteLog('Policy query: ' + pwszValueName); - if OverrideSL(pwszValueName, dw) then begin - pdwValue^ := dw; - Result := S_OK; - WriteLog('Policy rewrite: ' + IntToStr(pdwValue^)); - Exit; - end; - - // If the requested value name is not defined above - // use function from SLC.dll - - Result := SLGetWindowsInformationDWORD(pwszValueName, pdwValue); - if Result = S_OK then - WriteLog('Policy result: ' + IntToStr(pdwValue^)) - else - WriteLog('Policy request failed'); -end; - -function New_Win8SL_CP(eax: DWORD; pdwValue: PDWORD; ecx: DWORD; pwszValueName: PWideChar): HRESULT; register; -begin - // wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll - // for Windows 8 Consumer Preview support - - Result := New_Win8SL(pwszValueName, pdwValue); -end; - -function New_CSLQuery_Initialize: HRESULT; stdcall; -var - Sect: String; - bServerSku, - bRemoteConnAllowed, - bFUSEnabled, - bAppServerAllowed, - bMultimonAllowed, - lMaxUserSessions, - ulMaxDebugSessions, - bInitialized: PDWORD; -begin - bServerSku := nil; - bRemoteConnAllowed := nil; - bFUSEnabled := nil; - bAppServerAllowed := nil; - bMultimonAllowed := nil; - lMaxUserSessions := nil; - ulMaxDebugSessions := nil; - bInitialized := nil; - WriteLog('>>> CSLQuery::Initialize'); - Sect := IntToStr(FV.Version.w.Major)+'.'+IntToStr(FV.Version.w.Minor)+'.'+ - IntToStr(FV.Release)+'.'+IntToStr(FV.Build)+'-SLInit'; - if INISectionExists(INI, Sect) then begin - bServerSku := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bServerSku.x86', 0)); - bRemoteConnAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bRemoteConnAllowed.x86', 0)); - bFUSEnabled := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bFUSEnabled.x86', 0)); - bAppServerAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bAppServerAllowed.x86', 0)); - bMultimonAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bMultimonAllowed.x86', 0)); - lMaxUserSessions := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'lMaxUserSessions.x86', 0)); - ulMaxDebugSessions := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'ulMaxDebugSessions.x86', 0)); - bInitialized := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bInitialized.x86', 0)); - end; - - if bServerSku <> nil then begin - bServerSku^ := INIReadDWord(INI, 'SLInit', 'bServerSku', 1); - WriteLog('SLInit [0x'+IntToHex(DWORD(bServerSku), 1)+'] bServerSku = ' + IntToStr(bServerSku^)); - end; - if bRemoteConnAllowed <> nil then begin - bRemoteConnAllowed^ := INIReadDWord(INI, 'SLInit', 'bRemoteConnAllowed', 1); - WriteLog('SLInit [0x'+IntToHex(DWORD(bRemoteConnAllowed), 1)+'] bRemoteConnAllowed = ' + IntToStr(bRemoteConnAllowed^)); - end; - if bFUSEnabled <> nil then begin - bFUSEnabled^ := INIReadDWord(INI, 'SLInit', 'bFUSEnabled', 1); - WriteLog('SLInit [0x'+IntToHex(DWORD(bFUSEnabled), 1)+'] bFUSEnabled = ' + IntToStr(bFUSEnabled^)); - end; - if bAppServerAllowed <> nil then begin - bAppServerAllowed^ := INIReadDWord(INI, 'SLInit', 'bAppServerAllowed', 1); - WriteLog('SLInit [0x'+IntToHex(DWORD(bAppServerAllowed), 1)+'] bAppServerAllowed = ' + IntToStr(bAppServerAllowed^)); - end; - if bMultimonAllowed <> nil then begin - bMultimonAllowed^ := INIReadDWord(INI, 'SLInit', 'bMultimonAllowed', 1); - WriteLog('SLInit [0x'+IntToHex(DWORD(bMultimonAllowed), 1)+'] bMultimonAllowed = ' + IntToStr(bMultimonAllowed^)); - end; - if lMaxUserSessions <> nil then begin - lMaxUserSessions^ := INIReadDWord(INI, 'SLInit', 'lMaxUserSessions', 0); - WriteLog('SLInit [0x'+IntToHex(DWORD(lMaxUserSessions), 1)+'] lMaxUserSessions = ' + IntToStr(lMaxUserSessions^)); - end; - if ulMaxDebugSessions <> nil then begin - ulMaxDebugSessions^ := INIReadDWord(INI, 'SLInit', 'ulMaxDebugSessions', 0); - WriteLog('SLInit [0x'+IntToHex(DWORD(ulMaxDebugSessions), 1)+'] ulMaxDebugSessions = ' + IntToStr(ulMaxDebugSessions^)); - end; - if bInitialized <> nil then begin - bInitialized^ := INIReadDWord(INI, 'SLInit', 'bInitialized', 1); - WriteLog('SLInit [0x'+IntToHex(DWORD(bInitialized), 1)+'] bInitialized = ' + IntToStr(bInitialized^)); - end; - Result := S_OK; - WriteLog('<<< CSLQuery::Initialize'); -end; - -procedure HookFunctions; -var - ConfigFile, Sect, FuncName: String; - V: DWORD; - TS_Handle, SLC_Handle: THandle; - TermSrvSize: DWORD; - SignPtr: Pointer; - I: Integer; - PatchList: SList; - Patch: Array of TBytes; - Jump: far_jmp; - MovJump: mov_far_jmp; -begin - { hook function ^^ - (called once) } - IsHooked := True; - TSMain := nil; - TSGlobals := nil; - SLGetWindowsInformationDWORD := nil; - - WriteLog('Loading configuration...'); - ConfigFile := ExtractFilePath(GetBinaryPath) + 'rdpwrap.ini'; - WriteLog('Configuration file: ' + ConfigFile); - INILoad(INI, ConfigFile); - if Length(INI) = 0 then begin - WriteLog('Error: Failed to load configuration'); - Exit; - end; - - LogFile := INIReadString(INI, 'Main', 'LogFile', ExtractFilePath(GetBinaryPath) + 'rdpwrap.txt'); - WriteLog('Initializing RDP Wrapper...'); - - // load termsrv.dll and get functions - TS_Handle := LoadLibrary('termsrv.dll'); - if TS_Handle = 0 then begin - WriteLog('Error: Failed to load Terminal Services library'); - Exit; - end; - TSMain := GetProcAddress(TS_Handle, 'ServiceMain'); - TSGlobals := GetProcAddress(TS_Handle, 'SvchostPushServiceGlobals'); - WriteLog( - 'Base addr: 0x' + IntToHex(TS_Handle, 8) + #13#10 + - 'SvcMain: termsrv.dll+0x' + IntToHex(Cardinal(@TSMain) - TS_Handle, 1) + #13#10 + - 'SvcGlobals: termsrv.dll+0x' + IntToHex(Cardinal(@TSGlobals) - TS_Handle, 1) - ); - - V := 0; - // check termsrv version - if GetModuleVersion('termsrv.dll', FV) then - V := Byte(FV.Version.w.Minor) or (Byte(FV.Version.w.Major) shl 8) - else begin - // check NT version - // V := GetVersion; // deprecated - // V := ((V and $FF) shl 8) or ((V and $FF00) shr 8); - end; - if V = 0 then begin - WriteLog('Error: Failed to detect Terminal Services version'); - Exit; - end; - - WriteLog('Version: '+ - IntToStr(FV.Version.w.Major)+'.'+ - IntToStr(FV.Version.w.Minor)+'.'+ - IntToStr(FV.Release)+'.'+ - IntToStr(FV.Build)); - - // temporarily freeze threads - WriteLog('Freezing threads...'); - StopThreads(); - - WriteLog('Caching patch codes...'); - PatchList := INIReadSection(INI, 'PatchCodes'); - SetLength(Patch, Length(PatchList)); - for I := 0 to Length(Patch) - 1 do begin - Patch[I] := INIReadBytes(INI, 'PatchCodes', PatchList[I]); - if Length(Patch[I]) > 16 then // for security reasons - SetLength(Patch[I], 16); // not more than 16 bytes - end; - - if (V = $0600) and (INIReadBool(INI, 'Main', 'SLPolicyHookNT60', True)) then begin - // Windows Vista - // uses SL Policy API (slc.dll) - - // load slc.dll and hook function - SLC_Handle := LoadLibrary('slc.dll'); - SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD'); - - if @SLGetWindowsInformationDWORD <> nil then - begin - // rewrite original function to call our function (make hook) - - WriteLog('Hook SLGetWindowsInformationDWORD'); - Stub_SLGetWindowsInformationDWORD.PushOp := $68; - Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD; - Stub_SLGetWindowsInformationDWORD.RetOp := $C3; - ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, - @Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw); - WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, - @Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw); - end; - end; - if (V = $0601) and (INIReadBool(INI, 'Main', 'SLPolicyHookNT61', True)) then begin - // Windows 7 - // uses SL Policy API (slc.dll) - - // load slc.dll and hook function - SLC_Handle := LoadLibrary('slc.dll'); - SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD'); - - if @SLGetWindowsInformationDWORD <> nil then - begin - // rewrite original function to call our function (make hook) - - WriteLog('Hook SLGetWindowsInformationDWORD'); - Stub_SLGetWindowsInformationDWORD.PushOp := $68; - Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD; - Stub_SLGetWindowsInformationDWORD.RetOp := $C3; - ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, - @Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw); - WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, - @Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw); - end; - end; - if V = $0602 then begin - // Windows 8 - // uses SL Policy internal unexported function - - // load slc.dll and get function - // (will be used on intercepting undefined values) - SLC_Handle := LoadLibrary('slc.dll'); - SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD'); - end; - if V = $0603 then begin - // Windows 8.1 - // uses SL Policy internal inline code - end; - if V = $0604 then begin - // Windows 10 - // uses SL Policy internal inline code - end; - - Sect := IntToStr(FV.Version.w.Major)+'.'+IntToStr(FV.Version.w.Minor)+'.'+ - IntToStr(FV.Release)+'.'+IntToStr(FV.Build); - - if INISectionExists(INI, Sect) then - if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin - if INIReadBool(INI, Sect, 'LocalOnlyPatch.x86', False) then begin - WriteLog('Patch CEnforcementCore::GetInstanceOfTSLicense'); - SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'LocalOnlyOffset.x86', 0)); - I := SListFind(PatchList, INIReadString(INI, Sect, 'LocalOnlyCode.x86', '')); - if I >= 0 then - WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw); - end; - if INIReadBool(INI, Sect, 'SingleUserPatch.x86', False) then begin - WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled'); - SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SingleUserOffset.x86', 0)); - I := SListFind(PatchList, INIReadString(INI, Sect, 'SingleUserCode.x86', '')); - if I >= 0 then - WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw); - end; - if INIReadBool(INI, Sect, 'DefPolicyPatch.x86', False) then begin - WriteLog('Patch CDefPolicy::Query'); - SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'DefPolicyOffset.x86', 0)); - I := SListFind(PatchList, INIReadString(INI, Sect, 'DefPolicyCode.x86', '')); - if I >= 0 then - WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw); - end; - if INIReadBool(INI, Sect, 'SLPolicyInternal.x86', False) then begin - WriteLog('Hook SLGetWindowsInformationDWORDWrapper'); - SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SLPolicyOffset.x86', 0)); - MovJump.MovOp := $89; // mov eax, ecx - MovJump.MovArg := $C8; // __msfastcall compatibility - MovJump.PushOp := $68; - MovJump.PushArg := @New_Win8SL; - MovJump.RetOp := $C3; - FuncName := INIReadString(INI, Sect, 'SLPolicyFunc.x86', 'New_Win8SL'); - if FuncName = 'New_Win8SL' then - MovJump.PushArg := @New_Win8SL; - if FuncName = 'New_Win8SL_CP' then - MovJump.PushArg := @New_Win8SL_CP; - WriteProcessMemory(GetCurrentProcess, SignPtr, - @MovJump, SizeOf(mov_far_jmp), bw); - end; - if INIReadBool(INI, Sect, 'SLInitHook.x86', False) then begin - WriteLog('Hook CSLQuery::Initialize'); - SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SLInitOffset.x86', 0)); - Jump.PushOp := $68; - Jump.PushArg := @New_CSLQuery_Initialize; - Jump.RetOp := $C3; - FuncName := INIReadString(INI, Sect, 'SLInitFunc.x86', 'New_CSLQuery_Initialize'); - if FuncName = 'New_CSLQuery_Initialize' then - Jump.PushArg := @New_CSLQuery_Initialize; - WriteProcessMemory(GetCurrentProcess, SignPtr, - @Jump, SizeOf(far_jmp), bw); - end; - end; - - // unfreeze threads - WriteLog('Resumimg threads...'); - RunThreads(); -end; - -function TermServiceMain(dwArgc: DWORD; lpszArgv: PWideChar): DWORD; stdcall; -begin - // wrap ServiceMain function - WriteLog('>>> ServiceMain'); - if not IsHooked then - HookFunctions; - Result := 0; - if @TSMain <> nil then - Result := TSMain(dwArgc, lpszArgv); - WriteLog('<<< ServiceMain'); -end; - -function TermServiceGlobals(lpGlobalData: Pointer): DWORD; stdcall; -begin - // wrap SvchostPushServiceGlobals function - WriteLog('>>> SvchostPushServiceGlobals'); - if not IsHooked then - HookFunctions; - Result := 0; - if @TSGlobals <> nil then - Result := TSGlobals(lpGlobalData); - WriteLog('<<< SvchostPushServiceGlobals'); -end; - -// export section - -exports - TermServiceMain index 1 name 'ServiceMain', - TermServiceGlobals index 2 name 'SvchostPushServiceGlobals'; - -begin - // DllMain procedure is not used -end. \ No newline at end of file diff --git a/src-x86-binarymaster/rdpwrap.dproj b/src-x86-binarymaster/rdpwrap.dproj deleted file mode 100644 index 2b81a43..0000000 --- a/src-x86-binarymaster/rdpwrap.dproj +++ /dev/null @@ -1,105 +0,0 @@ - - - {D6811241-D595-4809-B3B8-13BECEA56E11} - rdpwrap.dpr - Release - DCC32 - 12.0 - - - true - - - true - Base - true - - - true - Base - true - - - rdpwrap.dll - WinTypes=Windows;WinProcs=Windows;$(DCC_UnitAlias) - true - 00400000 - x86 - - - false - RELEASE;$(DCC_Define) - 0 - false - - - DEBUG;$(DCC_Define) - - - - MainSource - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - - - - - Delphi.Personality.12 - VCLApplication - - - - rdpwrap.dpr - - - False - True - False - - - False - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1049 - 1251 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - 12 - - diff --git a/src-x86-binarymaster/rdpwrap.res b/src-x86-binarymaster/rdpwrap.res deleted file mode 100644 index 853a58e..0000000 Binary files a/src-x86-binarymaster/rdpwrap.res and /dev/null differ diff --git a/src-x86-x64-Fusix/RDPWrap.vcxproj b/src-x86-x64-Fusix/RDPWrap.vcxproj index ebc2664..0f10868 100644 --- a/src-x86-x64-Fusix/RDPWrap.vcxproj +++ b/src-x86-x64-Fusix/RDPWrap.vcxproj @@ -1,4 +1,4 @@ - + @@ -17,6 +17,10 @@ Release x64 + + Release + ARM64 + {29E4E73B-EBA6-495B-A76C-FBB462196C64} @@ -49,8 +53,13 @@ v120 true Unicode - - + + DynamicLibrary + false + v143 + true + Unicode + @@ -65,6 +74,9 @@ + + + true @@ -74,16 +86,25 @@ false + $(ProjectDir)Release\x86\ + $(ProjectDir)obj\Release\x86\ false + $(ProjectDir)Release\x64\ + $(ProjectDir)obj\Release\x64\ + + + false + $(ProjectDir)Release\arm64\ + $(ProjectDir)obj\Release\arm64\ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;WINDOWS_IGNORE_PACKING_MISMATCH;%(PreprocessorDefinitions) true @@ -97,7 +118,7 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;WINDOWS_IGNORE_PACKING_MISMATCH;%(PreprocessorDefinitions) true @@ -112,7 +133,7 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;WINDOWS_IGNORE_PACKING_MISMATCH;%(PreprocessorDefinitions) true true Level3 @@ -137,7 +158,7 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;WINDOWS_IGNORE_PACKING_MISMATCH;%(PreprocessorDefinitions) true true Level3 @@ -156,6 +177,27 @@ true + + + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;WINDOWS_IGNORE_PACKING_MISMATCH;%(PreprocessorDefinitions) + true + true + Level3 + 1Byte + MultiThreaded + + + Windows + false + true + true + Export.def + + @@ -178,6 +220,9 @@ + false + + @@ -186,6 +231,7 @@ Create Create Create + Create @@ -194,4 +240,4 @@ - \ No newline at end of file + diff --git a/technical.txt b/technical.txt deleted file mode 100644 index eec609f..0000000 --- a/technical.txt +++ /dev/null @@ -1,561 +0,0 @@ -RDP Wrapper Library project by Stas'M - -Terminal Services supported versions -6.0.X.X (Windows Vista, any) [policy hook only] -6.0.6000.16386 (Windows Vista) [policy hook + extended patch] -6.0.6000.20723 (Windows Vista with KB944917) [todo] -6.0.6001.18000 (Windows Vista SP1) [policy hook + extended patch] -6.0.6001.22286 (Windows Vista SP1 with KB958612) [todo] -6.0.6001.22357 (Windows Vista SP1 with KB958612 v2) [todo] -6.0.6001.22323 (Windows Vista SP1 with KB960742) [todo] -6.0.6001.22392 (Windows Vista SP1 with KB968680) [todo] -6.0.6001.22565 (Windows Vista SP1 with KB977541) [todo] -6.0.6001.22635 (Windows Vista SP1 with KB970911) [todo] -6.0.6001.22801 (Windows Vista SP1 with KB2381675) [todo] -6.0.6002.18005 (Windows Vista SP2) [policy hook + extended patch] -6.0.6002.22269 (Windows Vista SP2 with KB977541) [todo] -6.0.6002.22340 (Windows Vista SP2 with KB970911) [todo] -6.0.6002.22515 (Windows Vista SP2 with KB2381675) [todo] -6.0.6002.22641 (Windows Vista SP2 with KB2523307) [todo] -6.0.6002.22790 (Windows Vista SP2 with KB2672601) [todo] -6.0.6002.19214 (Windows Vista SP2 with KB3003743 GDR) [policy hook + extended patch] -6.0.6002.23521 (Windows Vista SP2 with KB3003743 LDR) [policy hook + extended patch] -6.1.X.X (Windows 7, any) [policy hook only] -6.1.7100.0 (Windows 7 Release Candidate) [todo] -6.1.7600.16385 (Windows 7) [policy hook + extended patch] -6.1.7600.20661 (Windows 7 with KB951422) [todo] -6.1.7600.21085 (Windows 7 with KB951422 v2) [todo] -6.1.7600.20621 (Windows 7 with KB979470) [todo] -6.1.7600.20890 (Windows 7 with KB2479710) [policy hook + extended patch] -6.1.7600.21316 (Windows 7 with KB2750090) [policy hook + extended patch] -6.1.7600.21420 (Windows 7 with KB2800789) [todo] -6.1.7601.17514 (Windows 7 SP1) [policy hook + extended patch] -6.1.7601.21855 (Windows 7 SP1 with KB951422 v2) [todo] -6.1.7601.21650 (Windows 7 SP1 with KB2479710) [policy hook + extended patch] -6.1.7601.21866 (Windows 7 SP1 with KB2647409) [policy hook + extended patch] -6.1.7601.22104 (Windows 7 SP1 with KB2750090) [policy hook + extended patch] -6.1.7601.22213 (Windows 7 SP1 with KB2800789) [todo] -6.1.7601.22476 (Windows 7 SP1 with KB2870165) [todo] -6.1.7601.22435 (Windows 7 SP1 with KB2878424) [todo] -6.1.7601.22477 (Windows 7 SP1 with KB2896256) [todo] -6.1.7601.18540 (Windows 7 SP1 with KB2984972 GDR) [policy hook + extended patch] -6.1.7601.22750 (Windows 7 SP1 with KB2984972 LDR) [policy hook + extended patch] -6.1.7601.18637 (Windows 7 SP1 with KB3003743 GDR) [policy hook + extended patch] -6.1.7601.22843 (Windows 7 SP1 with KB3003743 LDR) [policy hook + extended patch] -6.1.7601.23403 (Windows 7 SP1 with KB3125574) [policy hook + extended patch] -6.1.7601.24234 (Windows 7 SP1 with KB4462923) [policy hook + extended patch] -6.2.8102.0 (Windows 8 Developer Preview) [policy hook + extended patch] -6.2.8250.0 (Windows 8 Consumer Preview) [policy hook + extended patch] -6.2.8400.0 (Windows 8 Release Preview) [policy hook + extended patch] -6.2.9200.16384 (Windows 8) [policy hook + extended patch] -6.2.9200.17048 (Windows 8 with KB2973501 GDR) [policy hook + extended patch] -6.2.9200.21166 (Windows 8 with KB2973501 LDR) [policy hook + extended patch] -6.3.9431.0 (Windows 8.1 Preview) [init hook + extended patch] -6.3.9600.16384 (Windows 8.1) [init hook + extended patch] -6.3.9600.17095 (Windows 8.1 with KB2959626) [init hook + extended patch] -6.3.9600.17415 (Windows 8.1 with KB3000850) [init hook + extended patch] -6.3.9600.18692 (Windows 8.1 with KB4022720) [init hook + extended patch] -6.3.9600.18708 (Windows 8.1 with KB4025335) [init hook + extended patch] -6.3.9600.18928 (Windows 8.1 with KB4088876) [init hook + extended patch] -6.3.9600.19093 (Windows 8.1 with KB4343891) [init hook + extended patch] -6.4.9841.0 (Windows 10 Technical Preview) [init hook + extended patch] -6.4.9860.0 (Windows 10 Technical Preview UP1) [init hook + extended patch] -6.4.9879.0 (Windows 10 Technical Preview UP2) [init hook + extended patch] -10.0.9926.0 (Windows 10 Pro Technical Preview) [init hook + extended patch] -10.0.10041.0 (Windows 10 Pro Technical Preview UP1) [init hook + extended patch] -10.0.10049.0 (Windows 10 Pro Technical Preview UP2) [todo] -10.0.10061.0 (Windows 10 Pro Technical Preview UP3) [todo] -10.0.10240.16384 (Windows 10 RTM) [init hook + extended patch] -10.0.10525.0 (Windows 10 th2_release.150812-1658) [todo] -10.0.10532.0 (Windows 10 th2_release.150822-1406) [todo] -10.0.10547.0 (Windows 10 th2_release.150913-1511) [todo] -10.0.10586.0 (Windows 10 th2_release.151029-1700) [init hook + extended patch] -10.0.10586.589 (Windows 10 th2_release.160906-1759) [init hook + extended patch] -10.0.11082.1000 (Windows 10 rs1_release.151210-2021) [init hook + extended patch] -10.0.11102.1000 (Windows 10 rs1_release.160113-1800) [init hook + extended patch] -10.0.14251.1000 (Windows 10 rs1_release.160124-1059) [init hook + extended patch] -10.0.14271.1000 (Windows 10 rs1_release.160218-2310) [init hook + extended patch] -10.0.14279.1000 (Windows 10 rs1_release.160229-1700) [init hook + extended patch] -10.0.14295.1000 (Windows 10 rs1_release.160318-1628) [init hook + extended patch] -10.0.14300.1000 (Windows Server 2016 Technical Preview 5) [init hook + extended patch] -10.0.14316.1000 (Windows 10 rs1_release.160402-2227) [init hook + extended patch] -10.0.14328.1000 (Windows 10 rs1_release.160418-1609) [init hook + extended patch] -10.0.14332.1001 (Windows 10 rs1_release.160422-1940) [init hook + extended patch] -10.0.14342.1000 (Windows 10 rs1_release.160506-1708) [init hook + extended patch] -10.0.14352.1002 (Windows 10 rs1_release.160522-1930) [init hook + extended patch] -10.0.14366.0 (Windows 10 rs1_release.160610-1700) [init hook + extended patch] -10.0.14367.0 (Windows 10 rs1_release.160613-1700) [init hook + extended patch] -10.0.14372.0 (Windows 10 rs1_release.160620-2342) [init hook + extended patch] -10.0.14379.0 (Windows 10 rs1_release.160627-1607) [init hook + extended patch] -10.0.14383.0 (Windows 10 rs1_release.160701-1839) [init hook + extended patch] -10.0.14385.0 (Windows 10 rs1_release.160706-1700) [init hook + extended patch] -10.0.14388.0 (Windows 10 rs1_release.160709-1635) [init hook + extended patch] -10.0.14393.0 (Windows 10 rs1_release.160715-1616) [init hook + extended patch] -10.0.14393.1198 (Windows 10 rs1_release_sec.170427-1353) [init hook + extended patch] -10.0.14393.1737 (Windows 10 rs1_release_inmarket.170914-1249) [init hook + extended patch] -10.0.14393.2457 (Windows 10 rs1_release_inmarket.180822-1743) [init hook + extended patch] -10.0.14901.1000 (Windows 10 rs_prerelease.160805-1700) [init hook + extended patch] -10.0.14905.1000 (Windows 10 rs_prerelease.160811-1739) [init hook + extended patch] -10.0.14915.1000 (Windows 10 rs_prerelease.160826-1902) [init hook + extended patch] -10.0.14926.1000 (Windows 10 rs_prerelease.160910-1529) [init hook + extended patch] -10.0.14931.1000 (Windows 10 rs_prerelease.160916-1700) [init hook + extended patch] -10.0.14936.1000 (Windows 10 rs_prerelease.160923-1700) [init hook + extended patch] -10.0.14942.1000 (Windows 10 rs_prerelease.161003-1929) [init hook + extended patch] -10.0.14946.1000 (Windows 10 rs_prerelease.161007-1700) [init hook + extended patch] -10.0.14951.1000 (Windows 10 rs_prerelease.161014-1700) [init hook + extended patch] -10.0.14955.1000 (Windows 10 rs_prerelease.161020-1700) [init hook + extended patch] -10.0.14959.1000 (Windows 10 rs_prerelease.161026-1700) [init hook + extended patch] -10.0.14965.1001 (Windows 10 rs_prerelease.161104-1700) [init hook + extended patch] -10.0.14971.1000 (Windows 10 rs_prerelease.161111-1700) [init hook + extended patch] -10.0.14986.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.14997.1001 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15002.1001 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15007.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15014.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15019.1000 (Windows 10 rs_prerelease.170121-1513) [init hook + extended patch] -10.0.15025.1000 (Windows 10 rs_prerelease.170127-1750) [init hook + extended patch] -10.0.15031.0 (Windows 10 rs2_release.170204-1546) [init hook + extended patch] -10.0.15042.0 (Windows 10 rs2_release.170219-2329) [init hook + extended patch] -10.0.15046.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15048.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15055.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15058.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15061.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15063.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15063.296 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15063.994 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.15063.1155 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16179.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16184.1001 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16199.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16215.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16232.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16237.1001 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16241.1001 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16251.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16251.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16257.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16257.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16273.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16275.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16278.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16281.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16288.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16291.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16294.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16296.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16299.0 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16299.15 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16353.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.16362.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17004.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17017.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17025.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17035.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17040.1000 (Windows 10 WinBuild.160101.0800) [todo] -10.0.17046.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17063.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17074.1002 (Windows 10 WinBuild.160101.0800) [todo] -10.0.17083.1000 (Windows 10 WinBuild.160101.0800) [todo] -10.0.17115.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17128.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17133.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17134.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17723.1000 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] -10.0.17763.1 (Windows 10 WinBuild.160101.0800) [init hook + extended patch] - -Source code changelog (rdpwrap library): - -2018.10.10 : -- added support for termsrv.dll 6.1.7601.24234 x86 - -2018.10.04 : -- added support for termsrv.dll 10.0.14393.2457 x86 - -2018.10.03 : -- added support for termsrv.dll 6.1.7601.24234 x64 -- added support for termsrv.dll 10.0.15063.994 x64 -- added support for termsrv.dll 10.0.17723.1000 x64 -- added support for termsrv.dll 10.0.17763.1 - -2018.09.10 : -- added support for termsrv.dll 6.1.7600.20890 -- added support for termsrv.dll 6.1.7600.21316 -- added support for termsrv.dll 6.1.7601.21650 -- added support for termsrv.dll 6.1.7601.21866 -- added support for termsrv.dll 6.1.7601.22104 -- added support for termsrv.dll 6.3.9600.19093 -- added support for termsrv.dll 10.0.14393.2457 x64 -- added support for termsrv.dll 10.0.15063.1155 x64 - -2018.05.16 : -- added support for termsrv.dll 10.0.17115.1 -- added support for termsrv.dll 10.0.17128.1 -- added support for termsrv.dll 10.0.17133.1 -- added support for termsrv.dll 10.0.17134.1 - -2018.03.26 : -- added support for termsrv.dll 6.3.9600.18928 by 1nd1g0 - -2017.12.27 : -- added support for termsrv.dll 10.0.17017.1000 -- added support for termsrv.dll 10.0.17025.1000 -- added support for termsrv.dll 10.0.17035.1000 -- added support for termsrv.dll 10.0.17046.1000 -- added support for termsrv.dll 10.0.17063.1000 - -2017.10.13 : -- added support for termsrv.dll 10.0.14393.1737 -- added support for termsrv.dll 10.0.16299.0 -- added support for termsrv.dll 10.0.16299.15 -- added support for termsrv.dll 10.0.17004.1000 - -2017.09.24 : -- added support for termsrv.dll 10.0.16291.0 -- added support for termsrv.dll 10.0.16294.1 -- added support for termsrv.dll 10.0.16296.0 -- added support for termsrv.dll 10.0.16362.1000 - -2017.09.15 : -- added support for termsrv.dll 10.0.16288.1 - -2017.09.06 : -- added support for termsrv.dll 10.0.16273.1000 -- added support for termsrv.dll 10.0.16275.1000 -- added support for termsrv.dll 10.0.16278.1000 -- added support for termsrv.dll 10.0.16281.1000 -- added support for termsrv.dll 10.0.16353.1000 - -2017.08.04 : -- added support for termsrv.dll 10.0.16257.1 -- added support for termsrv.dll 10.0.16257.1000 - -2017.07.30 : -- added support for termsrv.dll 6.3.9600.18708 -- added support for termsrv.dll 10.0.16232.1000 -- added support for termsrv.dll 10.0.16237.1001 -- added support for termsrv.dll 10.0.16241.1001 -- added support for termsrv.dll 10.0.16251.0 -- added support for termsrv.dll 10.0.16251.1000 - -2017.06.29 : -- added support for termsrv.dll 6.3.9600.18692 - -2017.06.10 : -- added support for termsrv.dll 10.0.15063.296 -- added support for termsrv.dll 10.0.16215.1000 - -2017.05.29 : -- added support for termsrv.dll 10.0.16199.1000 - -2017.05.17 : -- added support for termsrv.dll 10.0.14997.1001 x64 - -2017.05.12 : -- added support for termsrv.dll 10.0.14393.1198 x86 - -2017.05.03 : -- added support for termsrv.dll 10.0.16179.1000 -- added support for termsrv.dll 10.0.16184.1001 - -2017.03.22 : -- added support for termsrv.dll 10.0.15063.0 - -2017.03.21 : -- added support for termsrv.dll 10.0.15061.0 - -2017.03.16 : -- added support for termsrv.dll 10.0.15058.0 - -2017.03.14 : -- added support for termsrv.dll 10.0.15055.0 - -2017.03.05 : -- added support for termsrv.dll 10.0.15048.0 - -2017.03.02 : -- added support for termsrv.dll 10.0.15046.0 - -2017.03.01 : -- added support for termsrv.dll 10.0.15031.0 -- added support for termsrv.dll 10.0.15042.0 - -2017.02.03 : -- added support for termsrv.dll 10.0.15025.1000 x64 - -2017.01.28 : -- added support for termsrv.dll 10.0.15019.1000 - -2017.01.21 : -- added support for termsrv.dll 10.0.15014.1000 - -2017.01.15 : -- added support for termsrv.dll 10.0.15007.1000 - -2017.01.12 : -- added support for termsrv.dll 10.0.15002.1001 - -2016.12.23 : -- added support for termsrv.dll 10.0.14986.1000 - -2016.11.19 : -- added support for termsrv.dll 10.0.14959.1000 -- added support for termsrv.dll 10.0.14965.1001 -- added support for termsrv.dll 10.0.14971.1000 - -2016.10.28 : -- added support for termsrv.dll 10.0.14955.1000 - -2016.10.21 : -- added support for termsrv.dll 10.0.14951.1000 - -2016.10.19 : -- added support for termsrv.dll 10.0.14946.1000 - -2016.10.08 : -- added support for termsrv.dll 10.0.14942.1000 - -2016.09.30 : -- added support for termsrv.dll 10.0.14936.1000 - -2016.09.27 : -- added support for termsrv.dll 10.0.14931.1000 - -2016.09.15 : -- added support for termsrv.dll 10.0.14926.1000 - -2016.09.14 : -- added support for termsrv.dll 10.0.10586.589 - -2016.09.03 : -- added support for termsrv.dll 10.0.14915.1000 - -2016.08.28 : -- added support for termsrv.dll 6.1.7601.23403 -- added support for termsrv.dll 10.0.14901.1000 -- added support for termsrv.dll 10.0.14905.1000 - -2016.08.12 : -- added support for termsrv.dll 10.0.14385.0 - -2016.08.01 : -- preparing the release - -2016.07.23 : -- added online install mode to installer -- added feature to keep settings on uninstall -- fixed update firewall rule on port change in config tool -- added feature to hide users on logon - -2016.07.22 : -- added support for termsrv.dll 10.0.14393.0 - -2016.07.15 : -- added support for termsrv.dll 10.0.14383.0 -- added support for termsrv.dll 10.0.14388.0 - -2016.07.06 : -- added support for termsrv.dll 10.0.14379.0 - -2016.06.27 : -- added support for termsrv.dll 10.0.14372.0 x86 - -2016.06.26 : -- added support for termsrv.dll 10.0.14372.0 x64 by kbmorris - -2016.06.17 : -- fixed issue with termsrv.dll 10.0.14352.1002 -- added support for termsrv.dll 10.0.14366.0 -- added support for termsrv.dll 10.0.14367.0 - -2016.05.30 : -- added support for termsrv.dll 10.0.14352.1002 - -2016.05.14 : -- added support for termsrv.dll 10.0.14342.1000 - -2016.05.08 : -- added support for termsrv.dll 10.0.14300.1000 x64 -- added support for termsrv.dll 10.0.14328.1000 - -2016.04.29 : -- added support for termsrv.dll 10.0.14332.1001 by maxpiva - -2016.04.14 : -- added support for termsrv.dll 10.0.14316.1000 - -2016.04.06 : -- added support for termsrv.dll 10.0.14295.1000 - -2016.03.07 : -- added experimental codes for ARMv7 architecture (see rdpwrap-arm-kb.ini) -- Windows RT / termsrv.dll 6.2.9200.16384 -- Windows RT 8.1 / termsrv.dll 6.3.9600.16384 -- Windows RT 8.1 / termsrv.dll 6.3.9600.17095 - -2016.03.06 : -- added support for termsrv.dll 10.0.14279.1000 - -2016.02.29 : -- added support for termsrv.dll 10.0.14271.1000 - -2016.01.28 : -- added support for termsrv.dll 10.0.14251.1000 - -2016.01.26 : -- added support for termsrv.dll 10.0.11102.1000 - -2016.01.15 : -- updated messages in the installer -- added support for termsrv.dll 10.0.11082.1000 - -2015.11.14 : -- added support for termsrv.dll 10.0.10586.0 - -2015.08.11 : -- embed new rdpclip versions in the installer (for NT 6.0 and 6.1) -- preparing the release - -2015.08.07 : -- added INI update feature to installer - -2015.07.30 : -- fixed issue with Windows 10 Home x86 (wrong LocalOnly offset was specified in INI file) - -2015.07.17 : -- added support for termsrv.dll 10.0.10240.16384 -- added HOW TO hints to KB (so other reverse engineers can do this hard work more easier) - -2015.07.16 : -- moved all comments from INI file to Knowledge Base text file -- now INI file have smaller size -- updated RDP checker: changed IP Address to 127.0.0.2 (sometimes client doesn't want to connect .1), updated text message -- updated RDP config: list all possible shadowing modes, also write group policy -- updated installer: added workaround for 1056 error -- updated copyright years in source code -- obtained files from build 10.0.10240.16384 -- researching Windows 10 RTM - -2015.03.23 : -- researching Windows 10 Pro Technical Preview UP1 -- added support for termsrv.dll 10.0.10041.0 - -2015.03.20 : -- new build 10.0.10041.0 was released, obtaining files... - -2015.01.26 : -- researching Windows 10 Pro Technical Preview (10.0.9926.0 x86) -- added support for termsrv.dll 10.0.9926.0 (x86) - -2015.01.22 : -- v-yadli contributed offsets for version 10.0.9926.0 (x64) - -2014.12.13 : -- added more policy values to INI file - -2014.12.10 : -- C++ version seems to work well now! -- added support for termsrv.dll 6.4.9879.0 -- preparing the new release - -2014.12.09 : -- many bug fixes in C++ version, you can track it in the git history :) -- it can be compiled now :D -- we are getting closer to the finish line! - -2014.12.03 : -- added INI reader by Fusix for C++ version -- asulwer also helped with the development - -2014.11.25 : -- corrected some typos in INI file -- added EasyPrint policy value - -2014.11.24 : -- added support for termsrv.dll 6.3.9600.17415 - -2014.11.21 : -- new LiteINI module to read INI files -- added support to store patch settings in INI file -- version support can be extended without recompilation -- C++ version needs to be updated - -2014.11.20 : -- improved comments -- researching KB3000850 -- found required files -- improving RDPWrap... -- placing signatures, offsets, values, etc in separate config file -- working with code - -2014.11.13 : -- researching KB3003743 -- added support for version 6.0.6002.19214 -- added support for version 6.0.6002.23521 -- added support for version 6.1.7601.18637 -- added support for version 6.1.7601.22843 - -2014.11.02 : -- researching termsrv.dll 6.4.9860.0 -- done - -2014.10.19 : -- added support for version 6.0.6000.16386 (x64) -- added support for version 6.0.6001.18000 (x64) -- added support for version 6.1.7600.16385 - -2014.10.18 : -- corrected some typos in source -- simplified signature constants -- added support for version 6.0.6000.16386 (x86) -- added support for version 6.0.6001.18000 (x86) -- added support for version 6.0.6002.18005 -- added support for version 6.1.7601.17514 -- added support for version 6.1.7601.18540 -- added support for version 6.1.7601.22750 -- added support for version 6.2.9200.17048 -- added support for version 6.2.9200.21166 - -2014.10.17 : -- collecting information about all versions of Terminal Services beginning from Vista -- added [todo] to the versions list - -2014.10.16 : -- got new updates: KB2984972 for Win 7 (still works with 2 concurrent users) and KB2973501 for Win 8 (doesn't work) - -2014.10.02 : -- researching Windows 10 TP Remote Desktop -- done! even without debugging symbols ^^) - -2014.07.20 : -- added support for Windows 8 Release Preview -- added support for Windows 8 Consumer Preview -- added support for Windows 8 Developer Preview - -2014.07.19 : -- improved patching of Windows 8 -- added policy patches -- will patch CDefPolicy::Query -- will patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled - -2014.07.18 : -- researched patched files from MDL forum -- CSLQuery::GetMaxSessions requires no patching -- it's better to change the default policy, so... -- will patch CDefPolicy::Query -- will patch CEnforcementCore::GetInstanceOfTSLicense -- will patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled -- the function CSLQuery::Initialize is hooked correctly - -2014.07.17 : -- will hook only CSLQuery::Initialize function -- CSLQuery::GetMaxSessions will be patched -- added x86 signatures for 6.3.9431.0 (Windows 8.1 Preview) - -2014.07.16 : -- changing asm opcodes is bad, will hook CSL functions - -2014.07.15 : -- added x86 signatures for 6.3.9600.16384 (Windows 8.1) -2014.07.15 : -- added x86 signatures for 6.3.9600.17095 (Windows 8.1 with KB2959626) diff --git a/tools/RDPWrapOffsetFinder/README.md b/tools/RDPWrapOffsetFinder/README.md deleted file mode 100644 index e19777d..0000000 --- a/tools/RDPWrapOffsetFinder/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# RDPWrapOffsetFinder - -Pre-built binaries of [llccd/RDPWrapOffsetFinder](https://github.com/llccd/RDPWrapOffsetFinder), -committed here so that the CI pipeline and releases are self-contained and -reproducible without depending on an external release being available at build time. - -## Contents - -``` -x64/ - RDPWrapOffsetFinder.exe # x86-64 build - Zydis.dll # required runtime (x64) -x86/ - RDPWrapOffsetFinder.exe # x86 32-bit build - Zydis.dll # required runtime (x86) -VERSION # version tag of the upstream release -``` - -## Usage - -Extract the appropriate arch folder and run: - -``` -.\RDPWrapOffsetFinder.exe C:\Windows\System32\termsrv.dll -``` - -The output `[10.0.xxxxx.xxxxx]` section can be appended to `res/rdpwrap.ini` -and submitted as a pull request. - -## Updating - -To update the binaries when llccd releases a new version, trigger the -`Update RDPWrapOffsetFinder tools` workflow from the Actions tab -(`.github/workflows/update-finder-tools.yml`). -It will download the latest release, update this folder, and open a pull request. diff --git a/tools/RDPWrapOffsetFinder/VERSION b/tools/RDPWrapOffsetFinder/VERSION deleted file mode 100644 index 6d21a1c..0000000 --- a/tools/RDPWrapOffsetFinder/VERSION +++ /dev/null @@ -1 +0,0 @@ -v0.9 \ No newline at end of file diff --git a/tools/RDPWrapOffsetFinder/x64/RDPWrapOffsetFinder.exe b/tools/RDPWrapOffsetFinder/x64/RDPWrapOffsetFinder.exe deleted file mode 100644 index 312d013..0000000 Binary files a/tools/RDPWrapOffsetFinder/x64/RDPWrapOffsetFinder.exe and /dev/null differ diff --git a/tools/RDPWrapOffsetFinder/x64/Zydis.dll b/tools/RDPWrapOffsetFinder/x64/Zydis.dll deleted file mode 100644 index c747d83..0000000 Binary files a/tools/RDPWrapOffsetFinder/x64/Zydis.dll and /dev/null differ diff --git a/tools/RDPWrapOffsetFinder/x86/RDPWrapOffsetFinder.exe b/tools/RDPWrapOffsetFinder/x86/RDPWrapOffsetFinder.exe deleted file mode 100644 index dd74f4f..0000000 Binary files a/tools/RDPWrapOffsetFinder/x86/RDPWrapOffsetFinder.exe and /dev/null differ diff --git a/tools/RDPWrapOffsetFinder/x86/Zydis.dll b/tools/RDPWrapOffsetFinder/x86/Zydis.dll deleted file mode 100644 index 5909f0f..0000000 Binary files a/tools/RDPWrapOffsetFinder/x86/Zydis.dll and /dev/null differ diff --git a/tools/build-local.ps1 b/tools/build-local.ps1 new file mode 100644 index 0000000..bbe1c1e --- /dev/null +++ b/tools/build-local.ps1 @@ -0,0 +1,259 @@ +#!/usr/bin/env pwsh +# tools/build-local.ps1 +# Full local build: C++ DLLs + C# tools → ./build/ +# +# Usage (run from repo root): +# .\tools\build-local.ps1 # full build +# .\tools\build-local.ps1 -SkipCpp # skip C++ DLL (faster for C# iteration) +# .\tools\build-local.ps1 -SkipMsi # skip MSI build (no WiX needed) +# +# See docs/BUILDING.md for prerequisites and troubleshooting. + +#Requires -Version 5 + +param( + [switch]$SkipCpp, + [switch]$SkipIcons, + [switch]$SkipMsi +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$REPO = $PSScriptRoot | Split-Path -Parent +$BUILD = Join-Path $REPO "build" + +# ─── Helpers ────────────────────────────────────────────────────────────────── + +function Step([string]$msg) { + Write-Host "`n==> $msg" -ForegroundColor Cyan +} + +function Fail([string]$msg) { + Write-Host "[FAIL] $msg" -ForegroundColor Red + exit 1 +} + +# ─── Locate MSBuild ─────────────────────────────────────────────────────────── + +function Find-MSBuild { + $candidates = @( + # VS 2022 Build Tools / Community + "${env:ProgramFiles}\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\amd64\MSBuild.exe", + "${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\MSBuild.exe", + "${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe", + # VS 2019 Build Tools / Community + "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\amd64\MSBuild.exe", + "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\amd64\MSBuild.exe", + "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe" + ) + foreach ($p in $candidates) { + if (Test-Path $p) { return $p } + } + # Fall back to PATH + $found = Get-Command msbuild -ErrorAction SilentlyContinue + if ($found) { return $found.Source } + return $null +} + +# ─── 0. Stamp INI date ──────────────────────────────────────────────────────── + +Step "Stamping rdpwrap.ini with today's date" +$today = Get-Date -Format "yyyy-MM-dd" +$iniFile = "$REPO\msi\rdpwrap.ini" +(Get-Content $iniFile) -replace '^Updated=.*', "Updated=$today" | Set-Content $iniFile +Write-Host " Updated= $today" + +# Stage INI into RDPWInst embedded resources so it gets compiled in +$iniDest = "$REPO\src-csharp\RDPWInst\Resources\rdpwrap.ini" +New-Item -Force -ItemType Directory (Split-Path $iniDest) | Out-Null +Copy-Item $iniFile $iniDest -Force +Write-Host " Staged: src-csharp/RDPWInst/Resources/rdpwrap.ini" + +# ─── 1. Icons ───────────────────────────────────────────────────────────────── + +if (-not $SkipIcons) { + Step "Generating application icons" + & "$REPO\tools\make-icons.ps1" +} + +# ─── 2. C++ DLLs ────────────────────────────────────────────────────────────── + +if (-not $SkipCpp) { + Step "Building C++ DLLs (x64 + Win32)" + + $msbuild = Find-MSBuild + if (-not $msbuild) { + Fail "MSBuild not found. Install Visual Studio 2019 or 2022 Build Tools with 'Desktop development with C++'." + } + Write-Host " Using MSBuild: $msbuild" + + $msbuildArgs = @( + "$REPO\src-x86-x64-Fusix\RDPWrap.sln", + "/p:Configuration=Release", + "/p:PlatformToolset=v143", + "/p:WindowsTargetPlatformVersion=10.0", + "/m", "/v:m" + ) + + foreach ($platform in @("x64", "Win32", "ARM64")) { + Write-Host " Building $platform..." + & $msbuild @msbuildArgs "/p:Platform=$platform" + if ($LASTEXITCODE -ne 0) { Fail "MSBuild failed for $platform" } + } +} else { + Write-Host "[skip] C++ DLL build (-SkipCpp)" -ForegroundColor Yellow +} + +# ─── 3. C# tools ────────────────────────────────────────────────────────────── + +Step "Publishing C# tools" + +# Verify dotnet +$dotnetVer = (dotnet --version 2>&1) +Write-Host " .NET SDK: $dotnetVer" + +$tools = @("RDPConf", "RDPCheck", "RDPWInst") +$rids = @("win-x64", "win-x86", "win-arm64") + +foreach ($tool in $tools) { + foreach ($rid in $rids) { + $arch = $rid -replace "win-", "" + $staging = Join-Path $BUILD "staging\$tool\$rid" + Write-Host " $tool / $rid → $staging" + + dotnet publish "$REPO\src-csharp\$tool\$tool.csproj" ` + -c Release -r $rid ` + --self-contained true ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true ` + -p:PublishTrimmed=false ` + -p:Version=1.0.0 ` + -o $staging ` + --nologo -v quiet + + if ($LASTEXITCODE -ne 0) { Fail "dotnet publish failed for $tool/$rid" } + } +} + +# ─── 4. Assemble build/ ─────────────────────────────────────────────────────── + +Step "Assembling ./build/" + +New-Item -Force -ItemType Directory $BUILD | Out-Null + +# C++ DLLs +if (-not $SkipCpp) { + $dllMap = @{ + "rdpwrap_x64.dll" = "$REPO\src-x86-x64-Fusix\Release\x64\RDPWrap.dll" + "rdpwrap_x86.dll" = "$REPO\src-x86-x64-Fusix\Release\x86\RDPWrap.dll" + "rdpwrap_arm64.dll" = "$REPO\src-x86-x64-Fusix\Release\arm64\RDPWrap.dll" + } + foreach ($dest in $dllMap.Keys) { + $src = $dllMap[$dest] + if (Test-Path $src) { + Copy-Item $src "$BUILD\$dest" -Force + Write-Host " Copied: $dest" + } else { + Write-Warning " Not found (DLL build skipped?): $src" + } + } +} + +# C# executables +foreach ($tool in $tools) { + foreach ($rid in $rids) { + $arch = $rid -replace "win-", "" + $src = "$BUILD\staging\$tool\$rid\$tool.exe" + $dest = "$BUILD\${tool}_${arch}.exe" + if (Test-Path $src) { + Copy-Item $src $dest -Force + Write-Host " Copied: ${tool}_${arch}.exe" + } else { + Write-Warning " Not found: $src" + } + } +} + +# INI file (side-by-side with installer, and for reference) +Copy-Item $iniFile "$BUILD\rdpwrap.ini" -Force +Write-Host " Copied: rdpwrap.ini" + +# Remove staging area +Remove-Item -Recurse -Force "$BUILD\staging" -ErrorAction SilentlyContinue + +# ─── 5. MSI ─────────────────────────────────────────────────────────────────── + +if (-not $SkipMsi) { + Step "Building MSI (WiX v5)" + + $wixProj = "$REPO\msi\RDPWInst.wixproj" + $pkgVer = Get-Date -Format "yy.M.d" # MSI version: major<=255, e.g. 26.4.1 + + foreach ($arch in @('x64', 'x86', 'arm64')) { + # Verify this arch's inputs exist in build/ + $required = @( + "$BUILD\RDPWInst_$arch.exe", + "$BUILD\RDPConf_$arch.exe", + "$BUILD\RDPCheck_$arch.exe", + "$BUILD\rdpwrap_$arch.dll", + "$BUILD\rdpwrap.ini" + ) + $missing = $required | Where-Object { -not (Test-Path $_) } + if ($missing) { + Write-Warning " Skipping $arch MSI -- missing inputs:`n $($missing -join "`n ")" + continue + } + + # Stage inputs next to the .wixproj (WiX resolves Source= relative to the project) + foreach ($inputFile in $required) { + Copy-Item $inputFile "$REPO\msi\" -Force -ErrorAction Continue + } + + # Explicit OutputPath per-arch avoids WiX placing all builds in the same bin/x86 dir. + # Explicit OutputName overrides the $(Platform) token which WiX doesn't expand in OutputName. + $outDir = Join-Path $REPO "msi_out\$arch" + $wixOut = Join-Path $outDir "RDPWrapper-$arch.msi" + New-Item -Force -ItemType Directory $outDir | Out-Null + + # Use Continue so a non-zero exit from dotnet/WiX does NOT throw under ErrorActionPreference=Stop + $buildArgs = @('build', $wixProj, '-c', 'Release', + "/p:Platform=$arch", + "/p:OutputName=RDPWrapper-$arch", + "/p:OutputPath=$outDir", + "/p:PackageVersion=$pkgVer", + '--nologo') + & dotnet @buildArgs + $wixExit = $LASTEXITCODE + if ($wixExit -ne 0) { + Write-Warning " MSI build failed for $arch (exit $wixExit) -- continuing." + continue + } + + $msiSrc = if (Test-Path $wixOut) { + Get-Item $wixOut + } else { + # Fallback: WiX may insert a locale subdir (e.g. msi_out/x64/en-US/…) + Get-ChildItem $outDir -Recurse -Filter "RDPWrapper-$arch.msi" -ErrorAction SilentlyContinue | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 + } + if ($msiSrc) { + $dest = Join-Path $BUILD "RDPWrapper-$pkgVer-$arch.msi" + Copy-Item $msiSrc.FullName $dest -Force + Write-Host (" Produced: RDPWrapper-$pkgVer-$arch.msi ({0:N1} MB)" -f ($msiSrc.Length / 1MB)) + } else { + Write-Warning " MSI output not found after $arch build." + } + } +} else { + Write-Host "[skip] MSI build (-SkipMsi)" -ForegroundColor Yellow +} + +# ─── 6. Summary ─────────────────────────────────────────────────────────────── + +Step "Build complete" +Get-ChildItem $BUILD | Sort-Object Name | ForEach-Object { + $kb = [math]::Round($_.Length / 1KB, 0) + Write-Host (" {0,-28} {1,6} KB" -f $_.Name, $kb) +} +Write-Host "" diff --git a/tools/make-icons.ps1 b/tools/make-icons.ps1 new file mode 100644 index 0000000..c8c13b6 --- /dev/null +++ b/tools/make-icons.ps1 @@ -0,0 +1,109 @@ +#!/usr/bin/env pwsh +# tools/make-icons.ps1 +# Generates 32×32 ICO files for RDPConf and RDPCheck. +# Requires .NET (Windows / .NET 4.5+). Run from repo root: +# .\tools\make-icons.ps1 +# Output: +# src-csharp/RDPConf/app.ico +# src-csharp/RDPCheck/app.ico + +#Requires -Version 5 + +Add-Type -AssemblyName System.Drawing + +$REPO = Split-Path -Parent $PSScriptRoot + +function New-AppIcon { + param( + [string]$OutPath, + [System.Drawing.Color]$BackColor, + [string]$Letter, + [System.Drawing.Color]$ForeColor = [System.Drawing.Color]::White + ) + + $sz = 32 + $bmp = New-Object System.Drawing.Bitmap($sz, $sz, + [System.Drawing.Imaging.PixelFormat]::Format32bppArgb) + + $g = [System.Drawing.Graphics]::FromImage($bmp) + $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias + $g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::ClearTypeGridFit + $g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic + + # Rounded-rectangle background + $bg = New-Object System.Drawing.SolidBrush($BackColor) + $r = 5 # corner radius + $path = New-Object System.Drawing.Drawing2D.GraphicsPath + $path.AddArc(0, 0, $r*2, $r*2, 180, 90) + $path.AddArc($sz - $r*2, 0, $r*2, $r*2, 270, 90) + $path.AddArc($sz - $r*2, $sz - $r*2, $r*2, $r*2, 0, 90) + $path.AddArc(0, $sz - $r*2, $r*2, $r*2, 90, 90) + $path.CloseFigure() + $g.FillPath($bg, $path) + + # Centered letter + $font = New-Object System.Drawing.Font( + "Segoe UI", 18, [System.Drawing.FontStyle]::Bold, + [System.Drawing.GraphicsUnit]::Pixel) + $fg = New-Object System.Drawing.SolidBrush($ForeColor) + $sf = New-Object System.Drawing.StringFormat + $sf.Alignment = [System.Drawing.StringAlignment]::Center + $sf.LineAlignment = [System.Drawing.StringAlignment]::Center + $rect = New-Object System.Drawing.RectangleF(0, 0, $sz, $sz) + $g.DrawString($Letter, $font, $fg, $rect, $sf) + + $g.Dispose() + + # --- Encode as PNG then wrap in ICO on-disk --- + $ms = New-Object System.IO.MemoryStream + $bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png) + $png = $ms.ToArray() + $ms.Dispose() + $bmp.Dispose() + + # ICO file format: + # ICONDIR 6 bytes : reserved(2) type=1(2) count=1(2) + # ICONDIRENTRY 16 bytes : w(1),h(1),colors(1),resv(1),planes(2),bits(2),size(4),offset(4) + # PNG data + $null = New-Item -Force -ItemType File $OutPath + $stream = [System.IO.File]::Open($OutPath, + [System.IO.FileMode]::Create, + [System.IO.FileAccess]::Write) + $w = New-Object System.IO.BinaryWriter($stream, + [System.Text.Encoding]::ASCII, $false) + + # ICONDIR + $w.Write([uint16]0) # reserved + $w.Write([uint16]1) # type = ICON + $w.Write([uint16]1) # image count + + # ICONDIRENTRY + $w.Write([byte]$sz) # width (0 = 256) + $w.Write([byte]$sz) # height + $w.Write([byte]0) # color count (0 = true-color) + $w.Write([byte]0) # reserved + $w.Write([uint16]1) # color planes + $w.Write([uint16]32) # bits per pixel + $w.Write([uint32]$png.Length) # image data size + $w.Write([uint32]22) # offset to image data (6 + 16 = 22) + + # PNG bytes + $w.Write($png) + + $w.Close() + $stream.Close() + + Write-Host " Created: $OutPath" +} + +Write-Host "Generating application icons..." + +New-AppIcon -OutPath "$REPO\src-csharp\RDPConf\app.ico" ` + -BackColor ([System.Drawing.Color]::FromArgb(0, 84, 166)) ` + -Letter "C" + +New-AppIcon -OutPath "$REPO\src-csharp\RDPCheck\app.ico" ` + -BackColor ([System.Drawing.Color]::FromArgb(16, 124, 16)) ` + -Letter "K" + +Write-Host "Done." diff --git a/tools/sergiye-hashes.json b/tools/sergiye-hashes.json new file mode 100644 index 0000000..6279410 --- /dev/null +++ b/tools/sergiye-hashes.json @@ -0,0 +1,18 @@ +{ + "_comment": [ + "This file pins the expected SHA-256 hashes of the rdpWrapper binaries downloaded", + "from https://github.com/sergiye/rdpWrapper/releases during the build-and-release.yml CI run.", + "", + "How to update after a new sergiye release:", + " 1. Download rdpWrapper_x64.exe and rdpWrapper_x86.exe from the release page.", + " 2. Run: Get-FileHash rdpWrapper_x64.exe -Algorithm SHA256", + " 3. Update the hashes and 'release' field below, then open a PR.", + "", + "If this file contains an empty 'release' string the verification step is SKIPPED", + "(bootstrap / first-run scenario). Set a real release tag once the first verified", + "download has been confirmed." + ], + "release": "2.10", + "rdpWrapper_x64.exe": "EAEE55CA7813E728177295770C52FBE6287DF7A49999426E0C71D916B3DF841F", + "rdpWrapper_x86.exe": "F59FE1DA29965F2FB001655C9F856BE5FD903BBCB7D92E807268C4D7B40D5AF8" +} diff --git a/tools/update-sergiye-hashes.ps1 b/tools/update-sergiye-hashes.ps1 new file mode 100644 index 0000000..73e2d51 --- /dev/null +++ b/tools/update-sergiye-hashes.ps1 @@ -0,0 +1,106 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Fetches the latest sergiye/rdpWrapper release, downloads the x64 and x86 GUI + executables, computes their SHA-256 hashes, and writes them to + tools/sergiye-hashes.json — ready to commit. + +.DESCRIPTION + Run this script locally (or in CI) immediately after a new sergiye/rdpWrapper + release is published, then commit the updated JSON file. Once the file contains + a non-empty 'release' key, build-and-release.yml will enforce the hashes on every + subsequent release run and fail the workflow if the downloaded files differ. + +.PARAMETER OutFile + Path to the JSON hash file to update. Defaults to tools/sergiye-hashes.json + relative to the script's parent directory. + +.PARAMETER GithubToken + Optional GitHub personal access token (or value of GITHUB_TOKEN env var) to + avoid API rate-limiting during repeated local runs. + +.EXAMPLE + # Run from the repo root: + pwsh tools/update-sergiye-hashes.ps1 + +.EXAMPLE + # Override output path: + pwsh tools/update-sergiye-hashes.ps1 -OutFile ./my-hashes.json +#> +[CmdletBinding()] +param( + [string] $OutFile = $null, + [string] $GithubToken = $env:GITHUB_TOKEN +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# ── Resolve paths ───────────────────────────────────────────────────────────── +$repoRoot = Split-Path $PSScriptRoot -Parent +if (-not $OutFile) { + $OutFile = Join-Path $repoRoot 'tools\sergiye-hashes.json' +} + +# ── Fetch latest release metadata from GitHub API ───────────────────────────── +$apiUrl = 'https://api.github.com/repos/sergiye/rdpWrapper/releases/latest' +$headers = @{ Accept = 'application/vnd.github+json'; 'X-GitHub-Api-Version' = '2022-11-28' } +if ($GithubToken) { $headers['Authorization'] = "Bearer $GithubToken" } + +Write-Host "Querying GitHub API: $apiUrl" +$release = Invoke-RestMethod -Uri $apiUrl -Headers $headers -UseBasicParsing +$tag = $release.tag_name +Write-Host "Latest sergiye release: $tag" + +# ── Locate the two assets we pin ────────────────────────────────────────────── +$needed = @('rdpWrapper_x64.exe', 'rdpWrapper_x86.exe') +$assets = @{} +foreach ($name in $needed) { + $asset = $release.assets | Where-Object { $_.name -eq $name } + if (-not $asset) { + throw "Asset '$name' not found in release $tag. Available: $($release.assets.name -join ', ')" + } + $assets[$name] = $asset.browser_download_url + Write-Host " Found $name → $($asset.browser_download_url)" +} + +# ── Download to a temp directory and hash ───────────────────────────────────── +$tmp = Join-Path ([IO.Path]::GetTempPath()) "sergiye-hash-$([guid]::NewGuid().ToString('N'))" +$null = New-Item -ItemType Directory -Path $tmp -Force +$hashes = @{} + +try { + foreach ($name in $needed) { + $dest = Join-Path $tmp $name + Write-Host "Downloading $name …" + Invoke-WebRequest -Uri $assets[$name] -OutFile $dest -UseBasicParsing + $hash = (Get-FileHash $dest -Algorithm SHA256).Hash + $hashes[$name] = $hash + Write-Host " SHA-256: $hash" + } +} finally { + Remove-Item $tmp -Recurse -Force -ErrorAction SilentlyContinue +} + +# ── Build and write the JSON file ───────────────────────────────────────────── +$existing = @{ '_comment' = @() } +if (Test-Path $OutFile) { + $existing = Get-Content $OutFile -Raw | ConvertFrom-Json -AsHashtable +} + +$output = [ordered]@{ + '_comment' = $existing['_comment'] # preserve explanatory comment + 'release' = $tag + 'rdpWrapper_x64.exe' = $hashes['rdpWrapper_x64.exe'] + 'rdpWrapper_x86.exe' = $hashes['rdpWrapper_x86.exe'] +} + +$json = $output | ConvertTo-Json -Depth 5 +Set-Content -Path $OutFile -Value $json -Encoding UTF8 +Write-Host "" +Write-Host "Written: $OutFile" +Write-Host "" +Write-Host "Next steps:" +Write-Host " 1. Review the diff: git diff tools/sergiye-hashes.json" +Write-Host " 2. Commit: git add tools/sergiye-hashes.json && git commit -m 'chore: pin sergiye hashes to $tag'" +Write-Host " 3. Push: git push"