RDP Wrapper rewritten in Rust.
English | 한국어
| Component | Description |
|---|---|
| termwrap-dll | Core RDP patching — multi-session support, policy bypass for Home/non-Server editions. 7 patch types: DefPolicy, SingleUser, LocalOnly, NonRDP, PropertyDevice, SLPolicy, CSLQuery::Initialize |
| umwrap-dll | USB/camera PnP device redirection for all SKUs (legacy + modern Windows) |
| endpwrap-dll | Audio recording redirection (TSAudioCaptureAllowed) |
| patcher | Shared library — PE parsing, x86/x64 disassembly, ARM64 .pdata function scanning, runtime pattern matching, 18 bytecode patches |
| ARM64 support | aarch64-pc-windows-msvc build target with experimental ARM64 termwrap/umwrap/endpwrap runtime patchers. Real Windows ARM64 validation is still required before calling it production-supported |
| offset-finder | Standalone CLI tool for x86/x64/ARM64 offset detection (pelite-based, no PDB required) |
| rdprrap-installer | Rust CLI installer/uninstaller — service registration, registry setup, firewall rules, cohort service restart, install-dir ACL hardening (replaces Delphi RDPWInst.exe) |
| rdprrap-check | RDP connection tester — loopback 127.0.0.2 via mstsc.exe, NLA guard RAII, 44 disconnect-reason codes (replaces RDPCheck.exe) |
| rdprrap-conf | Configuration GUI — native-windows-gui panel for diagnostics + runtime RDP settings (Enable/Port/SingleSession/HideUsers/AllowCustom/AuthMode/Shadow), replaces RDPConf.exe |
| Layer | Technology |
|---|---|
| Language | Rust (stable, MSVC toolchain) |
| Disassembler | iced-x86 (pure Rust) |
| PE Parsing | pelite |
| Windows API | windows-rs |
| Target | x86_64-pc-windows-msvc, i686-pc-windows-msvc, aarch64-pc-windows-msvc |
| CI | GitHub Actions (Linux check + Windows x64/x86 build, ARM64 build/static artifact checks) |
- Rust toolchain (stable, MSVC)
- Windows SDK
git clone https://github.com/kernalix7/rdprrap.git
cd rdprrap
rustup target add x86_64-pc-windows-msvc
rustup target add i686-pc-windows-msvc
rustup target add aarch64-pc-windows-msvc
cargo build --releaseFrom an elevated (Administrator) command prompt on the target Windows host:
# Install — copies DLLs, writes registry, opens firewall (TCP+UDP 3389),
# grants install-dir ACL (SYSTEM + LocalService), restarts TermService cohort
rdprrap-installer.exe install --source <dir-containing-built-DLLs>
# Check current state (ServiceDll, registry, firewall, termsrv.dll version)
rdprrap-installer.exe status
# Print the install contract (paths, DLL names, registry keys+values,
# firewall rules) — pure documentation, no I/O, no elevation required
rdprrap-installer.exe plan
# Uninstall — restores original ServiceDll, AllowMultipleTSSessions,
# fDenyTSConnections, AddIns, and removes firewall rules
rdprrap-installer.exe uninstallAdditional flags:
| Flag | Effect |
|---|---|
--source DIR |
Directory to copy DLLs from (defaults to the installer's own directory) |
--force |
Reinstall and replace existing wrapper DLLs even if ServiceDll already points to the wrapper |
--skip-firewall |
Do not add/remove firewall rules |
--skip-restart |
Do not restart TermService (apply changes manually or on reboot) |
--disable-nla |
Set UserAuthentication=0 (opt-in, required for legacy clients) |
-i / -u |
Legacy aliases for install / uninstall (RDPWInst compatibility) |
After install, the two GUIs are launched from %ProgramFiles%\RDP Wrapper\:
# Configuration panel — live state + runtime settings toggles
rdprrap-conf.exe
# Loopback RDP test — spawns mstsc /v:127.0.0.2 with NLA-guard RAII
rdprrap-check.exeManual install (without rdprrap-installer.exe) remains possible — copy the DLLs into %ProgramFiles%\RDP Wrapper\ and merge the appropriate registry file. See the original TermWrap for the DLL interface reference.
rdprrap/
├── crates/
│ ├── patcher/ # Shared: PE parsing, disassembly, pattern matching, memory patching
│ │ └── src/
│ │ ├── pe.rs # PE header/section/import/exception table parsing
│ │ ├── pattern.rs # 4-byte aligned string pattern matching in .rdata
│ │ ├── disasm.rs # iced-x86 decoder wrapper, xref search, branch helpers
│ │ ├── arm64.rs # ARM64 .pdata function scan + ADR/ADRP/ADD/BL helpers
│ │ └── patch.rs # WriteProcessMemory wrapper, NOP fill, 18 bytecode constants
│ ├── termwrap-dll/ # cdylib: termsrv.dll proxy (core RDP)
│ │ └── src/patches/ # DefPolicy, SingleUser, LocalOnly, NonRDP, PropertyDevice, SLPolicy
│ ├── umwrap-dll/ # cdylib: umrdp.dll proxy (USB/camera redirection)
│ ├── endpwrap-dll/ # cdylib: rdpendp.dll proxy (audio recording)
│ ├── offset-finder/ # Binary: standalone offset detection CLI
│ ├── rdprrap-installer/ # Binary: install/uninstall CLI (registry, service, firewall, ACL)
│ ├── rdprrap-check/ # Binary: RDP loopback tester (mstsc + NLA guard)
│ └── rdprrap-conf/ # Binary: configuration GUI (native-windows-gui)
├── .github/
│ └── workflows/ci.yml # Linux check + Windows x64/x86 build matrix + ARM64 static checks
└── docs/ # Korean documentation
- Wrapper DLLs proxy original system DLLs (
termsrv.dll,umrdp.dll,rdpendp.dll) - On
DLL_PROCESS_ATTACH, the original DLL is loaded and exports are forwarded - All threads are suspended, in-memory patches applied via
WriteProcessMemory, then resumed - Patch offsets found at runtime:
- x64: Scan
.rdatafor known strings → search exception table for LEA xrefs → backtrace unwind chains to function start - x86: Scan
.textfor function prologues (8B FF 55 8B EC) → follow branches → match PUSH/MOV immediates to string RVAs - ARM64:
.pdatafunction ranges plus ADR/ADRP+ADD string references locate policy checks.termwrappatches ARM64 DefPolicy, SingleUser, LocalOnly, AppServer/NonRDP, PropertyDevice, and SL policy paths with ARM64-specific bytecodes;umwrappatches PnP/camera BL calls tomov w0,#1;endpwrappatches the referenced audio-capture function start tomov w0,#1; ret.
- x64: Scan
| Patch | Purpose | Mechanism |
|---|---|---|
| DefPolicyPatch | Allow multiple RDP sessions | Replace CMP at offset 0x63c/0x320 with mov reg, 0x100 |
| SingleUserPatch | Disable per-user session limit | NOP out VerifyVersionInfoW call or CMP instruction |
| LocalOnlyPatch | Remove local-only license restriction | Convert JZ to unconditional JMP |
| NonRDPPatch | Allow non-RDP stack | Replace CALL with inc [ecx]; xor eax,eax |
| PropertyDevicePatch | Enable PnP device redirection | Replace SHR+AND with mov reg, 0 |
| SLPolicyPatch | Set SL policy variables to 1 | Direct memory write to bRemoteConnAllowed, bFUSEnabled, etc. |
cargo test # Unit tests
cargo clippy --all-targets -- -D warnings # Lint
cargo fmt --check # Format checkCI runs automatically on push/PR: Linux check + Windows x64/x86 full build + ARM64 build/static artifact checks.
See CONTRIBUTING.md for development setup and workflow.
For security issues, follow the process in SECURITY.md.
- stascorp/rdpwrap — Original RDP Wrapper
- llccd/TermWrap — C++ rewrite with integrated offset finder
- llccd/RDPWrapOffsetFinder — PDB-based offset finder
MIT License — see LICENSE for details.
Portions of rdprrap are ports or reimplementations of upstream
projects (rdpwrap under Apache-2.0; TermWrap and RDPWrapOffsetFinder
under MIT). See NOTICE for attribution, the full texts of
those upstream licenses under vendor/licenses/,
and THIRD_PARTY_LICENSES.txt (generated at release time; bundled
inside each release ZIP) for the compiled Rust-dependency attributions.