├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── autoupdate.zip ├── autoupdate_v1.1.zip ├── autoupdate_v1.2.zip ├── bin ├── autoupdate.bat ├── autoupdate.ver ├── helper │ ├── autoupdate__disable_autorun_on_startup.bat │ ├── autoupdate__enable_autorun_on_startup.bat │ └── autoupdate__info.txt ├── install.bat ├── uninstall.bat └── update.bat ├── binary-download.md ├── res ├── RDPWInst.wxs ├── build_wxs.bat ├── clearres.bat ├── legacy.install.bat ├── rdpwrap-arm-kb.ini ├── rdpwrap-ini-kb.txt └── rdpwrap.ini ├── src-installer ├── RDPWInst.dpr ├── RDPWInst.dproj └── resource.res ├── src-rdpcheck ├── MainUnit.dfm ├── MainUnit.pas ├── RDP.ico ├── RDPCheck.dpr ├── RDPCheck.dproj └── RDPCheck.res ├── src-rdpconfig ├── LicenseUnit.dfm ├── LicenseUnit.pas ├── MainUnit.dfm ├── MainUnit.pas ├── RDPConf.dpr ├── RDPConf.dproj ├── RDPConf.res └── resource.res ├── src-x86-binarymaster ├── LiteINI.pas ├── rdpwrap.dpr ├── rdpwrap.dproj └── rdpwrap.res ├── src-x86-x64-Fusix ├── Export.def ├── IniFile.cpp ├── IniFile.h ├── RDPWrap.cpp ├── RDPWrap.sln ├── RDPWrap.v11.suo ├── RDPWrap.vcxproj ├── RDPWrap.vcxproj.filters ├── ReadMe.txt ├── dllmain.cpp ├── stdafx.cpp ├── stdafx.h └── targetver.h └── technical.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Plain text (Windows) 5 | *.txt diff=astextplain eol=crlf 6 | *.ini diff=astextplain eol=crlf 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Delphi local files (user-specific info) 2 | *.local 3 | *.identcache 4 | 5 | # Delphi history and backups 6 | __history/ 7 | *.~* 8 | 9 | # Compiled binaries 10 | *.dcu 11 | *.exe 12 | *.dll 13 | *.msi 14 | 15 | # MSI local stuff 16 | *.wixobj 17 | *.wixpdb 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RDP Wrapper & Autoupdate 2 | 3 | ### Automatic RDP Wrapper installer and updater // asmtron (2024-04-29) 4 | 5 | #### Info: 6 | The autoupdater first use and check the official rdpwrap.ini. 7 | If a new termsrv.dll is not supported in the offical rdpwrap.ini, autoupdate uses the updated rdpwrap.ini files from the community. 8 | Contributors: "sebaxakerhtc, asmtron, affinityv, DrDrrae, saurav-biswas" 9 | Extra rdpwrap.ini sources can also be defined... 10 | 11 | #### autoupdate.bat Options: 12 | - `-log` = redirect display output to the file autoupdate.log 13 | - `-taskadd` = add autorun of autoupdate.bat on startup in schedule task 14 | - `-taskremove` = remove autorun of autoupdate.bat on startup in schedule task 15 | 16 | #### [Download and Install](https://github.com/asmtron/rdpwrap/blob/master/binary-download.md) 17 | 18 | # RDP Wrapper Library by Stas'M 19 | 20 | [![Telegram](https://img.shields.io/badge/chat-Telegram-blue.svg)](https://t.me/rdpwrap) 21 | ![Environment](https://img.shields.io/badge/Windows-Vista,%207,%208,%2010-brightgreen.svg) 22 | [![Release](https://img.shields.io/github/release/stascorp/rdpwrap.svg)](https://github.com/stascorp/rdpwrap/releases) 23 | ![License](https://img.shields.io/github/license/stascorp/rdpwrap.svg) 24 | ![Downloads](https://img.shields.io/github/downloads/stascorp/rdpwrap/latest/total.svg) 25 | ![TotalDownloads](https://img.shields.io/github/downloads/stascorp/rdpwrap/total.svg) 26 | 27 | The goal of this project is to enable Remote Desktop Host support and concurrent RDP sessions on reduced functionality systems for home usage. 28 | 29 | 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. 30 | 31 | [pVistaST]: http://stascorp.com/images/rdpwrap/pVistaST.jpg 32 | [pVistaHB]: http://stascorp.com/images/rdpwrap/pVistaHB.jpg 33 | [pWin7ST]: http://stascorp.com/images/rdpwrap/pWin7ST.jpg 34 | [pWin7HB]: http://stascorp.com/images/rdpwrap/pWin7HB.jpg 35 | [pWin8DP]: http://stascorp.com/images/rdpwrap/pWin8DP.jpg 36 | [pWin8CP]: http://stascorp.com/images/rdpwrap/pWin8CP.jpg 37 | [pWin8RP]: http://stascorp.com/images/rdpwrap/pWin8RP.jpg 38 | [pWin8]: http://stascorp.com/images/rdpwrap/pWin8.jpg 39 | [pWin81P]: http://stascorp.com/images/rdpwrap/pWin81P.jpg 40 | [pWin81]: http://stascorp.com/images/rdpwrap/pWin81.jpg 41 | [pWin10TP]: http://stascorp.com/images/rdpwrap/pWin10TP.jpg 42 | [pWin10PTP]: http://stascorp.com/images/rdpwrap/pWin10PTP.jpg 43 | [pWin10]: http://stascorp.com/images/rdpwrap/pWin10.jpg 44 | 45 | [fVistaST]: http://stascorp.com/images/rdpwrap/VistaST.png 46 | [fVistaHB]: http://stascorp.com/images/rdpwrap/VistaHB.png 47 | [fWin7ST]: http://stascorp.com/images/rdpwrap/Win7ST.png 48 | [fWin7HB]: http://stascorp.com/images/rdpwrap/Win7HB.png 49 | [fWin8DP]: http://stascorp.com/images/rdpwrap/Win8DP.png 50 | [fWin8CP]: http://stascorp.com/images/rdpwrap/Win8CP.png 51 | [fWin8RP]: http://stascorp.com/images/rdpwrap/Win8RP.png 52 | [fWin8]: http://stascorp.com/images/rdpwrap/Win8.png 53 | [fWin81P]: http://stascorp.com/images/rdpwrap/Win81P.png 54 | [fWin81]: http://stascorp.com/images/rdpwrap/Win81.png 55 | [fWin10TP]: http://stascorp.com/images/rdpwrap/Win10TP.png 56 | [fWin10PTP]: http://stascorp.com/images/rdpwrap/Win10PTP.png 57 | [fWin10]: http://stascorp.com/images/rdpwrap/Win10.png 58 | 59 | | NT Version | Screenshots | 60 | | ------------- | ----------- | 61 | | Windows Vista | [![Windows Vista Starter][pVistaST]][fVistaST] [![Windows Vista Home Basic][pVistaHB]][fVistaHB] | 62 | | Windows 7 | [![Windows 7 Starter][pWin7ST]][fWin7ST] [![Windows 7 Home Basic][pWin7HB]][fWin7HB] | 63 | | Windows 8 | [![Windows 8 Developer Preview][pWin8DP]][fWin8DP] [![Windows 8 Consumer Preview][pWin8CP]][fWin8CP] [![Windows 8 Release Preview][pWin8RP]][fWin8RP] [![Windows 8][pWin8]][fWin8] | 64 | | Windows 8.1 | [![Windows 8.1 Preview][pWin81P]][fWin81P] [![Windows 8.1][pWin81]][fWin81] | 65 | | Windows 10 | [![Windows 10 Technical Preview][pWin10TP]][fWin10TP] [![Windows 10 Pro Technical Preview][pWin10PTP]][fWin10PTP] [![Windows 10][pWin10]][fWin10] | 66 | --- 67 | [WinPPE]: https://forums.mydigitallife.net/threads/windows-product-policy-editor.39411/ 68 | 69 | This solution was inspired by [Windows Product Policy Editor][WinPPE], big thanks to **kost** :) 70 | 71 | — binarymaster 72 | 73 | ### Attention: 74 | It's recommended to have original `termsrv.dll` file with the RDP Wrapper installation. If you have modified it before with other patchers, it may become unstable and crash in any moment. 75 | 76 | ### Information: 77 | - Source code is available, so you can build it on your own 78 | - RDP Wrapper does not patch `termsrv.dll`, it loads `termsrv` with different parameters 79 | - `RDPWInst` and `RDPChecker` can be redistributed without development folder and batch files 80 | - `RDPWInst` can be used for unattended installation / deployment 81 | - Windows 2000, XP and Server 2003 will not be supported 82 | 83 | ### Key features: 84 | - RDP host server on any Windows edition beginning from Vista 85 | - Console and remote sessions at the same time 86 | - Using the same user simultaneously for local and remote logon (see configuration app) 87 | - Up to [15 concurrent sessions](https://github.com/stascorp/rdpwrap/issues/192) (the actual limitation depends on your hardware and OS version) 88 | - Console and RDP session shadowing (using [Task Manager in Windows 7](http://cdn.freshdesk.com/data/helpdesk/attachments/production/1009641577/original/remote_control.png?1413476051) and lower, and [Remote Desktop Connection in Windows 8](http://woshub.com/rds-shadow-how-to-connect-to-a-user-session-in-windows-server-2012-r2/) and higher) 89 | - Full [multi-monitor support](https://github.com/stascorp/rdpwrap/issues/163) for RDP host 90 | - ...and if you find a new feature not listed here, [tell us](https://github.com/stascorp/rdpwrap/issues/new) ;) 91 | 92 | ### Porting to other platforms: 93 | - **ARM** for Windows RT (see links below) 94 | - **IA-64** for Itanium-based Windows Server? *Well, I have no idea* :) 95 | 96 | ### Building the binaries: 97 | - **x86 Delphi version** can be built with *Embarcadero RAD Studio 2010* 98 | - **x86/x64 C++ version** can be built with *Microsoft Visual Studio 2013* 99 | 100 | [andrewblock]: http://web.archive.org/web/20150810054558/http://andrewblock.net/enable-remote-desktop-on-windows-8-core/ 101 | [mydigitallife]: http://forums.mydigitallife.info/threads/55935-RDP-Wrapper-Library-(works-with-Windows-8-1-Basic) 102 | [xda-dev]: http://forum.xda-developers.com/showthread.php?t=2093525&page=3 103 | [yt-updating]: http://www.youtube.com/watch?v=W9BpbEt1yJw 104 | [yt-offsets]: http://www.youtube.com/watch?v=FiD86tmRBtk 105 | 106 | ### Links: 107 | - Official GitHub repository: 108 |
https://github.com/stascorp/rdpwrap/ 109 | - Official Telegram chat: 110 |
https://t.me/rdpwrap 111 | - Active discussion in the comments here: 112 |
[Enable remote desktop on Windows 8 core / basic - Andrew Block .net][andrewblock] 113 | - MDL Projects and Applications thread here: 114 |
[RDP Wrapper Library (works with Windows 8.1 Basic)][mydigitallife] 115 | - Some ideas about porting to ARM for Windows RT (post #23): 116 |
[\[Q\] Mod Windows RT to enable Remote Desktop][xda-dev] 117 | - Adding «Remote Desktop Users» group: 118 |
http://superuser.com/questions/680572/ 119 | 120 | #### Tutorial videos: 121 | - [~~Updating RDP Wrapper INI file manually~~][yt-updating] (now use installer to update INI file) 122 | - [How to find offsets for new termsrv.dll versions][yt-offsets] 123 | 124 | ### Files in release package: 125 | 126 | | File name | Description | 127 | | --------- | ----------- | 128 | | `RDPWInst.exe` | RDP Wrapper Library installer/uninstaller | 129 | | `RDPCheck.exe` | Local RDP Checker (you can check the RDP is working) | 130 | | `RDPConf.exe` | RDP Wrapper Configuration | 131 | | `install.bat` | Quick install batch file | 132 | | `uninstall.bat` | Quick uninstall batch file | 133 | | `update.bat` | Quick update batch file | 134 | 135 | ### Frequently Asked Questions 136 | 137 | > Where can I download the installer or binaries? 138 | 139 | In the [GitHub Releases](https://github.com/stascorp/rdpwrap/releases) section. 140 | 141 | > Is it legal to use this application? 142 | 143 | There is no definitive answer, see [this discussion](https://github.com/stascorp/rdpwrap/issues/26). 144 | 145 | > The installer tries to access the Internet, is it normal behaviour? 146 | 147 | Yes, it works in online mode by default. You may disable it by removing `-o` flag in the `install.bat` file. 148 | 149 | > What is online install mode? 150 | 151 | Online install mode introduced in version 1.6.1. When you installing RDP Wrapper first time using this mode, it will download [latest INI file](https://github.com/stascorp/rdpwrap/blob/master/res/rdpwrap.ini) from GitHub. See [this discussion](https://github.com/stascorp/rdpwrap/issues/132). 152 | 153 | > What is INI file and why we need it? 154 | 155 | INI file was introduced in version 1.5. It stores system configuration for RDP Wrapper — general wrapping settings, binary patch codes, and per build specific data. When new `termsrv.dll` build comes out, developer adds support for it by updating INI file in repository. 156 | 157 | > Config Tool reports version 1.5, but I installed higher version. What's the matter? 158 | 159 | Beginning with version 1.5 the `rdpwrap.dll` is not updated anymore, since all settings are stored in INI file. Deal with it. 160 | 161 | > Config Tool shows `[not supported]` and RDP doesn't work. What can I do? 162 | 163 | Make sure you're connected to the Internet and run `update.bat`. 164 | 165 | > Update doesn't help, it still shows `[not supported]`. 166 | 167 | Visit [issues](https://github.com/stascorp/rdpwrap/issues) section, and check whether your `termsrv.dll` build is listed here. If you can't find such issue, create a new — specify your build version for adding to support. 168 | 169 | > Why `RDPCheck` doesn't allow to change resolution and other settings? 170 | 171 | `RDPCheck` is a very simple application and only for testing purposes. You need to use Microsoft Remote Desktop Client (`mstsc.exe`) if you want to customize the settings. You can use `127.0.0.1` or `127.0.0.2` address for loopback connection. 172 | 173 | ### Known issues: 174 | - Beginning with Windows 8 **on tablet PCs** inactive sessions will be logged out by system - [more info](https://github.com/stascorp/rdpwrap/issues/37) 175 | - Beginning with Windows 10 you can accidentally lock yourself from PC - [more info](https://github.com/stascorp/rdpwrap/issues/50) 176 | - Beginning with the Creators Update for Windows 10 Home, RDP Wrapper will no longer work, claiming that the listener is `[not listening]` because of `rfxvmt.dll` is missing - [more info](https://github.com/stascorp/rdpwrap/issues/194#issuecomment-323564111), [download links](https://github.com/stascorp/rdpwrap/issues/194#issuecomment-325627235) 177 | - Terminal Service does not start after installing some updates or "Access Denied" issue - [#215](https://github.com/stascorp/rdpwrap/issues/215), [#101](https://github.com/stascorp/rdpwrap/issues/101) 178 | - RDP Wrapper does not work with RemoteFX enabled hosts - [#127](https://github.com/stascorp/rdpwrap/issues/127), [#208](https://github.com/stascorp/rdpwrap/issues/208), [#216](https://github.com/stascorp/rdpwrap/issues/216) 179 | - RDP works, but termsrv.dll crashes on logon attempt - Windows Vista Starter RTM x86 (termsrv.dll `6.0.6000.16386`) 180 | - If Terminal Services hangs at startup, try to add **`rdpwrap.dll`** to antivirus exclusions. Also try to isolate RDP Wrapper from other shared services by the command: 181 |
`sc config TermService type= own` 182 | - RDP Wrapper can be removed by AVG Free Antivirus and [Norton Antivirus](https://github.com/stascorp/rdpwrap/issues/191) - first make sure you downloaded [official release](https://github.com/stascorp/rdpwrap/releases) from GitHub, then add it to exclusions. 183 | 184 | --- 185 | 186 | ### Change log: 187 | 188 | #### 2017.12.27 189 | - Version 1.6.2 190 | - Installer updated 191 | - Include updated INI file for latest Windows builds 192 | - Added check for supported Windows versions ([#155](https://github.com/stascorp/rdpwrap/issues/155)) 193 | - Added feature to take INI file from current directory ([#300](https://github.com/stascorp/rdpwrap/issues/300)) 194 | - Added feature to restore rfxvmt.dll (missing in Windows 10 Home [#194](https://github.com/stascorp/rdpwrap/issues/194)) 195 | - RDP Config updated 196 | - Added feature to allow custom start programs ([#13 (comment)](https://github.com/stascorp/rdpwrap/issues/13#issuecomment-77651843)) 197 | - MSI installation package added ([#14](https://github.com/stascorp/rdpwrap/issues/14)) 198 | 199 | #### 2016.08.01 200 | - Version 1.6.1 201 | - Include updated INI file for latest Windows builds 202 | - Installer updated 203 | - Added online install mode 204 | - Added feature to keep settings on uninstall 205 | - RDP Config updated 206 | - Fixed update firewall rule on RDP port change 207 | - Added feature to hide users on logon 208 | 209 | #### 2015.08.12 210 | - Version 1.6 211 | - Added support for Windows 10 212 | - INI file has smaller size now - all comments are moved to KB file 213 | - Installer updated 214 | - Added workaround for 1056 error (although it isn't an error) 215 | - Added update support to installer 216 | - Newest RDPClip versions are included with installer 217 | - RDP Checker updated 218 | - Changed connect IP to 127.0.0.2 219 | - Updated some text messages 220 | - RDP Config updated 221 | - Added all possible shadowing modes 222 | - Also it will write settings to the group policy 223 | 224 | #### 2014.12.11 225 | - Version 1.5 226 | - Added INI config support 227 | - Configuration is stored in INI file now 228 | - We can extend version support without building new binaries 229 | - Added support for Windows 8.1 with KB3000850 230 | - Added support for Windows 10 Technical Preview Update 2 231 | - Installer updated 232 | - RDP Config updated 233 | - Diagnostics feature added to RDP Config 234 | 235 | #### 2014.11.14 236 | - Version 1.4 237 | - Added support for Windows 10 Technical Preview Update 1 238 | - Added support for Windows Vista SP2 with KB3003743 239 | - Added support for Windows 7 SP1 with KB3003743 240 | - Added new RDP Configuration Program 241 | 242 | #### 2014.10.21 243 | - Installer updated 244 | - Added feature to install RDP Wrapper to System32 directory 245 | - Fixed issue in the installer - NLA setting now remains unchanged 246 | - Local RDP Checker updated 247 | - SecurityLayer and UserAuthentification values changed on check start 248 | - RDP Checker restores values on exit 249 | 250 | #### 2014.10.20 251 | - Version 1.3 252 | - Added support for Windows 10 Technical Preview 253 | - Added support for Windows 7 with KB2984972 254 | - Added support for Windows 8 with KB2973501 255 | - Added extended support for Windows Vista (SP0, SP1 and SP2) 256 | - Added extended support for Windows 7 (SP0 and SP1) 257 | - Some improvements in the source code 258 | - Installer updated to v2.2 259 | - Fixed installation bug in Vista x64 (wrong expand path) 260 | - Local RDP Checker updated 261 | - Added description to error 0x708 262 | 263 | #### 2014.07.26 264 | - Version 1.2 265 | - Added support for Windows 8 Developer Preview 266 | - Added support for Windows 8 Consumer Preview 267 | - Added support for Windows 8 Release Preview 268 | - Added support for Windows 8.1 Preview 269 | - Added support for Windows 8.1 270 | - More details you will see in the source code 271 | - Installer updated to v2.1 272 | 273 | #### 2013.12.09 274 | - C++ port of RDP Wrapper was made by Fusix 275 | - x64 architecture is supported now 276 | - Added new command line installer v2.0 277 | - Added local RDP checker 278 | - Source code (C++ port, installer 2.0, local RDP checker) is also included 279 | 280 | #### 2013.10.25 281 | - Version 1.1 source code is available 282 | 283 | #### 2013.10.22 284 | - Version 1.1 285 | - Stable release 286 | - Improved wrapper (now it can wrap internal unexported termsrv.dll SL Policy function) 287 | - Added support for Windows 8 Single Language (tested on Acer Tablet PC with Intel Atom Z2760) 288 | 289 | #### 2013.10.19 290 | - Version 1.0 291 | - First [beta] version 292 | - Basic SL Policy wrapper 293 | 294 | --- 295 | 296 | #### Supported Terminal Services versions: 297 | - 6.0.X.X (Windows Vista / Server 2008) 298 | - 6.0.6000.16386 (Windows Vista) 299 | - 6.0.6001.18000 (Windows Vista SP1) 300 | - 6.0.6002.18005 (Windows Vista SP2) 301 | - 6.0.6002.19214 (Windows Vista SP2 with KB3003743 GDR) 302 | - 6.0.6002.23521 (Windows Vista SP2 with KB3003743 LDR) 303 | - 6.1.X.X (Windows 7 / Server 2008 R2) 304 | - 6.1.7600.16385 (Windows 7) 305 | - 6.1.7600.20890 (Windows 7 with KB2479710) 306 | - 6.1.7600.21316 (Windows 7 with KB2750090) 307 | - 6.1.7601.17514 (Windows 7 SP1) 308 | - 6.1.7601.21650 (Windows 7 SP1 with KB2479710) 309 | - 6.1.7601.21866 (Windows 7 SP1 with KB2647409) 310 | - 6.1.7601.22104 (Windows 7 SP1 with KB2750090) 311 | - 6.1.7601.18540 (Windows 7 SP1 with KB2984972 GDR) 312 | - 6.1.7601.22750 (Windows 7 SP1 with KB2984972 LDR) 313 | - 6.1.7601.18637 (Windows 7 SP1 with KB3003743 GDR) 314 | - 6.1.7601.22843 (Windows 7 SP1 with KB3003743 LDR) 315 | - 6.1.7601.23403 (Windows 7 SP1 with KB3125574) 316 | - 6.1.7601.24234 (Windows 7 SP1 with KB4462923) 317 | - 6.2.8102.0 (Windows 8 Developer Preview) 318 | - 6.2.8250.0 (Windows 8 Consumer Preview) 319 | - 6.2.8400.0 (Windows 8 Release Preview) 320 | - 6.2.9200.16384 (Windows 8 / Server 2012) 321 | - 6.2.9200.17048 (Windows 8 with KB2973501 GDR) 322 | - 6.2.9200.21166 (Windows 8 with KB2973501 LDR) 323 | - 6.3.9431.0 (Windows 8.1 Preview) 324 | - 6.3.9600.16384 (Windows 8.1 / Server 2012 R2) 325 | - 6.3.9600.17095 (Windows 8.1 with KB2959626) 326 | - 6.3.9600.17415 (Windows 8.1 with KB3000850) 327 | - 6.3.9600.18692 (Windows 8.1 with KB4022720) 328 | - 6.3.9600.18708 (Windows 8.1 with KB4025335) 329 | - 6.3.9600.18928 (Windows 8.1 with KB4088876) 330 | - 6.3.9600.19093 (Windows 8.1 with KB4343891) 331 | - 6.4.9841.0 (Windows 10 Technical Preview) 332 | - 6.4.9860.0 (Windows 10 Technical Preview Update 1) 333 | - 6.4.9879.0 (Windows 10 Technical Preview Update 2) 334 | - 10.0.9926.0 (Windows 10 Pro Technical Preview) 335 | - 10.0.10041.0 (Windows 10 Pro Technical Preview Update 1) 336 | - 10.0.10240.16384 (Windows 10 RTM) 337 | - 10.0.10586.0 (Windows 10 TH2 Release 151029-1700) 338 | - 10.0.10586.589 (Windows 10 TH2 Release 160906-1759 with KB3185614) 339 | - 10.0.11082.1000 (Windows 10 RS1 Release 151210-2021) 340 | - 10.0.11102.1000 (Windows 10 RS1 Release 160113-1800) 341 | - 10.0.14251.1000 (Windows 10 RS1 Release 160124-1059) 342 | - 10.0.14271.1000 (Windows 10 RS1 Release 160218-2310) 343 | - 10.0.14279.1000 (Windows 10 RS1 Release 160229-1700) 344 | - 10.0.14295.1000 (Windows 10 RS1 Release 160318-1628) 345 | - 10.0.14300.1000 (Windows Server 2016 Technical Preview 5) 346 | - 10.0.14316.1000 (Windows 10 RS1 Release 160402-2227) 347 | - 10.0.14328.1000 (Windows 10 RS1 Release 160418-1609) 348 | - 10.0.14332.1001 (Windows 10 RS1 Release 160422-1940) 349 | - 10.0.14342.1000 (Windows 10 RS1 Release 160506-1708) 350 | - 10.0.14352.1002 (Windows 10 RS1 Release 160522-1930) 351 | - 10.0.14366.0 (Windows 10 RS1 Release 160610-1700) 352 | - 10.0.14367.0 (Windows 10 RS1 Release 160613-1700) 353 | - 10.0.14372.0 (Windows 10 RS1 Release 160620-2342) 354 | - 10.0.14379.0 (Windows 10 RS1 Release 160627-1607) 355 | - 10.0.14383.0 (Windows 10 RS1 Release 160701-1839) 356 | - 10.0.14385.0 (Windows 10 RS1 Release 160706-1700) 357 | - 10.0.14388.0 (Windows 10 RS1 Release 160709-1635) 358 | - 10.0.14393.0 (Windows 10 RS1 Release 160715-1616) 359 | - 10.0.14393.1198 (Windows 10 RS1 Release Sec 170427-1353 with KB4019472) 360 | - 10.0.14393.1737 (Windows 10 RS1 Release Inmarket 170914-1249 with KB4041691) 361 | - 10.0.14393.2457 (Windows 10 RS1 Release Inmarket 180822-1743 with KB4343884) 362 | - 10.0.14901.1000 (Windows 10 RS Pre-Release 160805-1700) 363 | - 10.0.14905.1000 (Windows 10 RS Pre-Release 160811-1739) 364 | - 10.0.14915.1000 (Windows 10 RS Pre-Release 160826-1902) 365 | - 10.0.14926.1000 (Windows 10 RS Pre-Release 160910-1529) 366 | - 10.0.14931.1000 (Windows 10 RS Pre-Release 160916-1700) 367 | - 10.0.14936.1000 (Windows 10 RS Pre-Release 160923-1700) 368 | - 10.0.14942.1000 (Windows 10 RS Pre-Release 161003-1929) 369 | - 10.0.14946.1000 (Windows 10 RS Pre-Release 161007-1700) 370 | - 10.0.14951.1000 (Windows 10 RS Pre-Release 161014-1700) 371 | - 10.0.14955.1000 (Windows 10 RS Pre-Release 161020-1700) 372 | - 10.0.14959.1000 (Windows 10 RS Pre-Release 161026-1700) 373 | - 10.0.14965.1001 (Windows 10 RS Pre-Release 161104-1700) 374 | - 10.0.14971.1000 (Windows 10 RS Pre-Release 161111-1700) 375 | - 10.0.14986.1000 (Windows 10 Build 160101.0800) 376 | - 10.0.14997.1001 (Windows 10 Build 160101.0800) 377 | - 10.0.15002.1001 (Windows 10 Build 160101.0800) 378 | - 10.0.15007.1000 (Windows 10 Build 160101.0800) 379 | - 10.0.15014.1000 (Windows 10 Build 160101.0800) 380 | - 10.0.15019.1000 (Windows 10 RS Pre-Release 170121-1513) 381 | - 10.0.15025.1000 (Windows 10 RS Pre-Release 170127-1750) 382 | - 10.0.15031.0 (Windows 10 RS2 Release 170204-1546) 383 | - 10.0.15042.0 (Windows 10 RS2 Release 170219-2329) 384 | - 10.0.15046.0 (Windows 10 Build 160101.0800) 385 | - 10.0.15048.0 (Windows 10 Build 160101.0800) 386 | - 10.0.15055.0 (Windows 10 Build 160101.0800) 387 | - 10.0.15058.0 (Windows 10 Build 160101.0800) 388 | - 10.0.15061.0 (Windows 10 Build 160101.0800) 389 | - 10.0.15063.0 (Windows 10 Build 160101.0800) 390 | - 10.0.15063.296 (Windows 10 Build 160101.0800) 391 | - 10.0.15063.994 (Windows 10 Build 160101.0800) 392 | - 10.0.15063.1155 (Windows 10 Build 160101.0800) 393 | - 10.0.16179.1000 (Windows 10 Build 160101.0800) 394 | - 10.0.16184.1001 (Windows 10 Build 160101.0800) 395 | - 10.0.16199.1000 (Windows 10 Build 160101.0800) 396 | - 10.0.16215.1000 (Windows 10 Build 160101.0800) 397 | - 10.0.16232.1000 (Windows 10 Build 160101.0800) 398 | - 10.0.16237.1001 (Windows 10 Build 160101.0800) 399 | - 10.0.16241.1001 (Windows 10 Build 160101.0800) 400 | - 10.0.16251.0 (Windows 10 Build 160101.0800) 401 | - 10.0.16251.1000 (Windows 10 Build 160101.0800) 402 | - 10.0.16257.1 (Windows 10 Build 160101.0800) 403 | - 10.0.16257.1000 (Windows 10 Build 160101.0800) 404 | - 10.0.16273.1000 (Windows 10 Build 160101.0800) 405 | - 10.0.16275.1000 (Windows 10 Build 160101.0800) 406 | - 10.0.16278.1000 (Windows 10 Build 160101.0800) 407 | - 10.0.16281.1000 (Windows 10 Build 160101.0800) 408 | - 10.0.16288.1 (Windows 10 Build 160101.0800) 409 | - 10.0.16291.0 (Windows 10 Build 160101.0800) 410 | - 10.0.16294.1 (Windows 10 Build 160101.0800) 411 | - 10.0.16296.0 (Windows 10 Build 160101.0800) 412 | - 10.0.16299.0 (Windows 10 Build 160101.0800) 413 | - 10.0.16299.15 (Windows 10 Build 160101.0800) 414 | - 10.0.16353.1000 (Windows 10 Build 160101.0800) 415 | - 10.0.16362.1000 (Windows 10 Build 160101.0800) 416 | - 10.0.17004.1000 (Windows 10 Build 160101.0800) 417 | - 10.0.17017.1000 (Windows 10 Build 160101.0800) 418 | - 10.0.17025.1000 (Windows 10 Build 160101.0800) 419 | - 10.0.17035.1000 (Windows 10 Build 160101.0800) 420 | - 10.0.17046.1000 (Windows 10 Build 160101.0800) 421 | - 10.0.17063.1000 (Windows 10 Build 160101.0800) 422 | - 10.0.17115.1 (Windows 10 Build 160101.0800) 423 | - 10.0.17128.1 (Windows 10 Build 160101.0800) 424 | - 10.0.17133.1 (Windows 10 Build 160101.0800) 425 | - 10.0.17134.1 (Windows 10 Build 160101.0800) 426 | - 10.0.17723.1000 (Windows 10 Build 160101.0800) 427 | - 10.0.17763.1 (Windows 10 Build 160101.0800) 428 | 429 | #### Confirmed working on: 430 | - Windows Vista Starter (x86 - Service Pack 1 and higher) 431 | - Windows Vista Home Basic 432 | - Windows Vista Home Premium 433 | - Windows Vista Business 434 | - Windows Vista Enterprise 435 | - Windows Vista Ultimate 436 | - Windows Server 2008 437 | - Windows 7 Starter 438 | - Windows 7 Home Basic 439 | - Windows 7 Home Premium 440 | - Windows 7 Professional 441 | - Windows 7 Enterprise 442 | - Windows 7 Ultimate 443 | - Windows Server 2008 R2 444 | - Windows 8 Developer Preview 445 | - Windows 8 Consumer Preview 446 | - Windows 8 Release Preview 447 | - Windows 8 448 | - Windows 8 Single Language 449 | - Windows 8 Pro 450 | - Windows 8 Enterprise 451 | - Windows Server 2012 452 | - Windows 8.1 Preview 453 | - Windows 8.1 454 | - Windows 8.1 Connected (with Bing) 455 | - Windows 8.1 Single Language 456 | - Windows 8.1 Connected Single Language (with Bing) 457 | - Windows 8.1 Pro 458 | - Windows 8.1 Enterprise 459 | - Windows Server 2012 R2 460 | - Windows 10 Technical Preview 461 | - Windows 10 Pro Technical Preview 462 | - Windows 10 Home 463 | - Windows 10 Home Single Language 464 | - Windows 10 Pro 465 | - Windows 10 Enterprise 466 | - Windows Server 2016 Technical Preview 467 | 468 | #### Installation instructions: 469 | - Download latest release binaries and unpack files 470 | - Right-click on **`install.bat`** and select Run as Administrator 471 | - See command output for details 472 | 473 | #### To update INI file: 474 | - Right-click on **`update.bat`** and select Run as Administrator 475 | - See command output for details 476 | 477 | #### To uninstall: 478 | - Go to the directory where you extracted the files 479 | - Right-click on **`uninstall.bat`** and select Run as Administrator 480 | - See command output for details 481 | -------------------------------------------------------------------------------- /autoupdate.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/autoupdate.zip -------------------------------------------------------------------------------- /autoupdate_v1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/autoupdate_v1.1.zip -------------------------------------------------------------------------------- /autoupdate_v1.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/autoupdate_v1.2.zip -------------------------------------------------------------------------------- /bin/autoupdate.bat: -------------------------------------------------------------------------------- 1 | 392 | 393 | 447 | 453 | 454 | -------------------------------------------------------------------------------- /bin/autoupdate.ver: -------------------------------------------------------------------------------- 1 | 1.3 2 | -------------------------------------------------------------------------------- /bin/helper/autoupdate__disable_autorun_on_startup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if exist "%~dp0autoupdate.bat" ( 3 | call "%~dp0autoupdate.bat" -taskremove 4 | ) else ( 5 | if exist "%~dp0..\autoupdate.bat" ( 6 | call "%~dp0..\autoupdate.bat" -taskremove 7 | ) 8 | ) 9 | pause -------------------------------------------------------------------------------- /bin/helper/autoupdate__enable_autorun_on_startup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if exist "%~dp0autoupdate.bat" ( 3 | call "%~dp0autoupdate.bat" -taskadd 4 | ) else ( 5 | if exist "%~dp0..\autoupdate.bat" ( 6 | call "%~dp0..\autoupdate.bat" -taskadd 7 | ) 8 | ) 9 | pause -------------------------------------------------------------------------------- /bin/helper/autoupdate__info.txt: -------------------------------------------------------------------------------- 1 | _ _ 2 | _ | | _ | | _ 3 | ____ _ _| |_ ___ _ _ ____ _ | | ____| |_ ____ | | _ ____| |_ 4 | / _ | | | | _)/ _ \| | | | _ \ / || |/ _ | _)/ _ ) | || \ / _ | _) 5 | ( ( | | |_| | |_| |_| | |_| | | | ( (_| ( ( | | |_( (/ / _| |_) ( ( | | |__ 6 | \_||_|\____|\___\___/ \____| ||_/ \____|\_||_|\___\____(_|____/ \_||_|\___) 7 | |_| 8 | 9 | Automatic RDP Wrapper installer and updater v.1.1 asmtron (2023-10-18) 10 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 | Options: 12 | -log = redirect display output to the file autoupdate.log 13 | -taskadd = add autorun of autoupdate.bat on startup in schedule task 14 | -taskremove = remove autorun of autoupdate.bat on startup in schedule task 15 | 16 | Info: 17 | The autoupdater first use and check the official rdpwrap.ini. 18 | If a new termsrv.dll is not supported in the offical rdpwrap.ini, 19 | autoupdate uses the updated rdpwrap.ini files from the community. 20 | contributors: "sebaxakerhtc, asmtron, affinityv, DrDrrae, saurav-biswas" 21 | Extra rdpwrap.ini sources can also be defined... 22 | 23 | { Special thanks to binarymaster and all other contributors } 24 | 25 | 26 | 27 | 28 | INSTALL of RDP Wrapper and Autoupdater 29 | ====================================== 30 | 31 | 1. Create the directory: "%ProgramFiles%\RDP Wrapper" 32 | (usually C:\Program Files\RDP Wrapper) 33 | 34 | 35 | 2. Set in your Antivirus or Windows Defender an exclusion on the folder "%ProgramFiles%\RDP Wrapper" to prevent the deletion of RDP Wrapper files... 36 | 37 | 38 | 3. Copy the files from the archive "RDPWrap-v1.6.2.zip" (or newer) to the directory: "%ProgramFiles%\RDP Wrapper" 39 | 40 | DO NOT use other directories to install/extract the RDP Wrapper files. 41 | USE ONLY the directory: "%ProgramFiles%\RDP Wrapper" (usually C:\Program Files\RDP Wrapper) 42 | 43 | 44 | 4. Copy the files/folder from the archive "autoupdate.zip" (or newer) to the directory: "%ProgramFiles%\RDP Wrapper" 45 | 46 | 47 | 5. To enable autorun of autoupdate.bat on system startup, run the following helper batch file as administrator: 48 | 49 | "%ProgramFiles%\RDP Wrapper\helper\autoupdate__enable_autorun_on_startup.bat" 50 | 51 | 52 | 6. Now you can use the autoupdate batch file to install and update the RDP Wrapper. Please run autoupdate.bat as administrator: 53 | 54 | "%ProgramFiles%\RDP Wrapper\autoupdate.bat" 55 | -------------------------------------------------------------------------------- /bin/install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if not exist "%~dp0RDPWInst.exe" goto :error 3 | "%~dp0RDPWInst" -i -o 4 | echo ______________________________________________________________ 5 | echo. 6 | echo You can check RDP functionality with RDPCheck program. 7 | echo Also you can configure advanced settings with RDPConf program. 8 | echo. 9 | goto :anykey 10 | :error 11 | echo [-] Installer executable not found. 12 | echo Please extract all files from the downloaded package or check your anti-virus. 13 | :anykey 14 | pause 15 | -------------------------------------------------------------------------------- /bin/uninstall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if not exist "%~dp0RDPWInst.exe" goto :error 3 | "%~dp0RDPWInst" -u 4 | echo. 5 | goto :anykey 6 | :error 7 | echo [-] Installer executable not found. 8 | echo Please extract all files from the downloaded package or check your anti-virus. 9 | :anykey 10 | pause 11 | -------------------------------------------------------------------------------- /bin/update.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if not exist "%~dp0RDPWInst.exe" goto :error 3 | "%~dp0RDPWInst" -w 4 | echo. 5 | goto :anykey 6 | :error 7 | echo [-] Installer executable not found. 8 | echo Please extract all files from the downloaded package or check your anti-virus. 9 | :anykey 10 | pause 11 | -------------------------------------------------------------------------------- /binary-download.md: -------------------------------------------------------------------------------- 1 | INSTALL of RDP Wrapper and Autoupdater 2 | -------------------------------------- 3 | 4 | 1. Create the directory: "%ProgramFiles%\RDP Wrapper" 5 | 6 | (usually C:\Program Files\RDP Wrapper) 7 | 8 | 3. Set in your Antivirus or Windows Defender an exclusion on the folder "%ProgramFiles%\RDP Wrapper" to prevent the deletion of RDP Wrapper files... 9 | 10 | 5. Download "RDPWrap-v1.6.2.zip" [LINK#1](https://github.com/stascorp/rdpwrap/releases) or [LINK#2](https://sabercathost.com/e2bm/RDPWrap-v1.6.2.zip) and extract all files to the "%ProgramFiles%\RDP Wrapper" directory 11 | 12 | DO NOT use other directories to install/extract the RDP Wrapper files. 13 | USE ONLY the "%ProgramFiles%\RDP Wrapper" directory 14 | (usually C:\Program Files\RDP Wrapper) 15 | 16 | 7. Download [autoupdate_v1.2.zip](https://github.com/asmtron/rdpwrap/raw/master/autoupdate_v1.2.zip) and extract all files to the "%ProgramFiles%\RDP Wrapper" directory 17 | 18 | 9. To enable autorun of autoupdate.bat on system startup, run the following helper batch file as administrator: 19 | 20 | "%ProgramFiles%\RDP Wrapper\helper\autoupdate__enable_autorun_on_startup.bat" 21 | 22 | 23 | 11. Now you can use the autoupdate batch file to install and update the RDP Wrapper. Please run autoupdate.bat as administrator: 24 | 25 | "%ProgramFiles%\RDP Wrapper\autoupdate.bat" 26 | 27 | -------------------------------------------------------------------------------- /res/RDPWInst.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | NOT Installed AND NOT WIX_UPGRADE_DETECTED 42 | REMOVE AND NOT UPGRADINGPRODUCTCODE 43 | UPGRADINGPRODUCTCODE 44 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /res/build_wxs.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | "%ProgramFiles%\WiX Toolset v3.11\bin\candle" RDPWInst.wxs 3 | "%ProgramFiles%\WiX Toolset v3.11\bin\light" RDPWInst.wixobj 4 | -------------------------------------------------------------------------------- /res/clearres.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo [FILENAMES]> clearres.txt 3 | echo Exe=%1>> clearres.txt 4 | echo SaveAs=%1>> clearres.txt 5 | echo Log=>> clearres.txt 6 | echo.>> clearres.txt 7 | echo [COMMANDS]>> clearres.txt 8 | echo -delete RCDATA,CHARTABLE,>> clearres.txt 9 | echo -delete RCDATA,DVCLAL,>> clearres.txt 10 | echo -delete RCDATA,PACKAGEINFO,>> clearres.txt 11 | echo -delete CURSORGROUP,32761,>> clearres.txt 12 | echo -delete CURSORGROUP,32762,>> clearres.txt 13 | echo -delete CURSORGROUP,32763,>> clearres.txt 14 | echo -delete CURSORGROUP,32764,>> clearres.txt 15 | echo -delete CURSORGROUP,32765,>> clearres.txt 16 | echo -delete CURSORGROUP,32766,>> clearres.txt 17 | echo -delete CURSORGROUP,32767,>> clearres.txt 18 | "C:\Program Files\Resource Hacker\ResHacker.exe" -script clearres.txt 19 | del clearres.txt 20 | -------------------------------------------------------------------------------- /res/legacy.install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal EnableDelayedExpansion 3 | echo RDP Wrapper Library Installer v1.0 4 | echo Copyright (C) Stas'M Corp. 2013 5 | echo. 6 | 7 | set PROCESSOR_ARCHITECTURE | find "x86" > nul 8 | if !errorlevel!==0 ( 9 | goto WOW64CHK 10 | ) else ( 11 | goto UNSUPPORTED 12 | ) 13 | 14 | :WOW64CHK 15 | echo [*] Check if running WOW64 subsystem... 16 | set PROCESSOR_ARCHITEW6432 > nul 17 | if !errorlevel!==0 ( 18 | goto UNSUPPORTED 19 | ) else ( 20 | goto SUPPORTED 21 | ) 22 | 23 | :SUPPORTED 24 | echo [+] Processor architecture is Intel x86 [supported] 25 | goto INSTALL 26 | 27 | :UNSUPPORTED 28 | echo [-] Unsupported processor architecture 29 | goto END 30 | 31 | :INSTALL 32 | echo [*] Installing... 33 | if not exist rdpwrap.dll ( 34 | echo [-] Error: rdpwrap.dll file not found 35 | goto END 36 | ) 37 | echo [*] Copying file to Program Files... 38 | md "%ProgramFiles%\RDP Wrapper" 39 | xcopy /y rdpwrap.dll "%ProgramFiles%\RDP Wrapper\" 40 | if not !errorlevel!==0 ( 41 | echo [-] Failed to copy rdpwrap.dll to Program Files folder 42 | goto END 43 | ) 44 | echo [*] Modifying registry... 45 | reg add "HKLM\SYSTEM\CurrentControlSet\Services\TermService\Parameters" /v ServiceDll /t REG_EXPAND_SZ /d "%ProgramFiles%\RDP Wrapper\rdpwrap.dll" /f 46 | if not !errorlevel!==0 ( 47 | echo [-] Failed to modify registry 48 | goto END 49 | ) 50 | echo [*] Setting firewall configuration... 51 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f 52 | netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=tcp localport=3389 profile=any action=allow 53 | netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=udp localport=3389 profile=any action=allow 54 | echo [*] Looking for TermService PID... 55 | tasklist /SVC /FI "SERVICES eq TermService" | find "PID" /V 56 | echo. 57 | if !errorlevel!==0 ( 58 | goto DONE 59 | ) else ( 60 | goto SVCSTART 61 | ) 62 | 63 | :SVCSTART 64 | echo [*] TermService is stopped. Starting it... 65 | sc config TermService start= auto | find "1060" > nul 66 | if !errorlevel!==0 ( 67 | echo [-] TermService is not installed. You need to install it manually. 68 | goto END 69 | ) else ( 70 | net start TermService 71 | goto DONE 72 | ) 73 | 74 | :DONE 75 | echo [+] Installation complete! 76 | echo Now reboot or restart service. 77 | echo. 78 | echo To reboot computer type: 79 | echo shutdown /r 80 | echo. 81 | echo To restart TermService type: 82 | echo taskkill /f /pid 1234 ^(replace 1234 with real PID which is shown above^) 83 | echo net start TermService 84 | echo. 85 | echo If second method is used, and there are another services sharing svchost.exe, 86 | echo you must start it too: 87 | echo net start Service1 88 | echo net start Service2 89 | echo etc. 90 | goto END 91 | 92 | :END 93 | -------------------------------------------------------------------------------- /res/rdpwrap-arm-kb.ini: -------------------------------------------------------------------------------- 1 | ; RDP Wrapper Library configuration 2 | ; for Windows RT (ARMv7) 3 | 4 | ; This is experimental file 5 | 6 | [Main] 7 | Updated=2016-03-07 8 | LogFile=\rdpwrap.txt 9 | 10 | [SLPolicy] 11 | TerminalServices-RemoteConnectionManager-AllowRemoteConnections=1 12 | TerminalServices-RemoteConnectionManager-AllowMultipleSessions=1 13 | TerminalServices-RemoteConnectionManager-AllowAppServerMode=1 14 | TerminalServices-RemoteConnectionManager-AllowMultimon=1 15 | TerminalServices-RemoteConnectionManager-MaxUserSessions=0 16 | TerminalServices-RemoteConnectionManager-ce0ad219-4670-4988-98fb-89b14c2f072b-MaxSessions=0 17 | TerminalServices-RemoteConnectionManager-45344fe7-00e6-4ac6-9f01-d01fd4ffadfb-MaxSessions=2 18 | TerminalServices-RDP-7-Advanced-Compression-Allowed=1 19 | TerminalServices-RemoteConnectionManager-45344fe7-00e6-4ac6-9f01-d01fd4ffadfb-LocalOnly=0 20 | TerminalServices-RemoteConnectionManager-8dc86f1d-9969-4379-91c1-06fe1dc60575-MaxSessions=1000 21 | TerminalServices-DeviceRedirection-Licenses-TSEasyPrintAllowed=1 22 | TerminalServices-DeviceRedirection-Licenses-PnpRedirectionAllowed=1 23 | TerminalServices-DeviceRedirection-Licenses-TSMFPluginAllowed=1 24 | TerminalServices-RemoteConnectionManager-UiEffects-DWMRemotingAllowed=1 25 | 26 | [PatchCodes] 27 | Zero=00 28 | bjmp5=05E0 29 | CDefPolicy_Query_r3_r5=40F20013C5F8203305E0 30 | CDefPolicy_Query_r3_r0=40F20013C0F8203305E0 31 | 32 | [6.2.9200.16384] 33 | ; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled 34 | ; .text:10066DCC MOV.W R3, #0x11C 35 | ; .text:10066DD0 STR R3, [SP,#0x16C+var_13C] 36 | ; .text:10066DD2 LDR R3, =__imp_GetVersionExW 37 | ; .text:10066DD4 MOVS R4, #1 <- 0 38 | ; .text:10066DD6 ADD R0, SP, #0x16C+var_13C 39 | ; .text:10066DD8 LDR R3, [R3] 40 | SingleUserPatch.arm=1 41 | SingleUserOffset.arm=66DD4 42 | SingleUserCode.arm=Zero 43 | ; Patch CDefPolicy::Query 44 | ; Original 45 | ; .text:10059164 LDR.W R2, [R5,#0x324] ; D5 F8 24 23 ; [R5,#0x324] -> R2 46 | ; .text:10059168 LDR.W R3, [R5,#0x320] ; D5 F8 20 33 ; [R5,#0x320] -> R3 47 | ; .text:1005916C CMP R2, R3 ; 9A 42 ; compare 48 | ; .text:1005916E BNE loc_1005917A ; 04 D1 ; jump if (R2 != R3) 49 | ; Changed 50 | ; .text:10059164 MOVW R3, #0x100 ; 40 F2 00 13 ; 0x100 -> R3 51 | ; .text:10059168 STR.W R3, [R5,#0x320] ; C5 F8 20 33 ; R3 -> [R5,#0x320] 52 | ; .text:1005916C B loc_1005917A ; 05 E0 ; jump 53 | ; .text:1005916E BNE loc_1005917A ; 04 D1 ; / never executed / 54 | DefPolicyPatch.arm=1 55 | DefPolicyOffset.arm=59164 56 | DefPolicyCode.arm=CDefPolicy_Query_r3_r5 57 | ; Hook SLGetWindowsInformationDWORDWrapper 58 | SLPolicyInternal.arm=1 59 | SLPolicyOffset.arm=5F934 60 | SLPolicyFunc.arm=New_Win8SL 61 | 62 | [6.3.9600.16384] 63 | ; Patch CEnforcementCore::GetInstanceOfTSLicense 64 | ; .text:1008E6C2 BL _IsLicenseTypeLocalOnly_CSLQuery__SAJAAU_GUID__PAH_Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) 65 | ; .text:1008E6C6 CMP R0, #0 66 | ; .text:1008E6C8 BLT loc_1008E6DA 67 | ; .text:1008E6CA LDR R3, [SP,#0x20+var_14] 68 | ; .text:1008E6CC CBZ R3, loc_1008E6DA ; 2B B1 ; jump if (R3 == 0) 69 | ; Changed 70 | ; .text:1008E6CC B loc_1008E6DA ; 05 E0 ; jump 71 | LocalOnlyPatch.arm=1 72 | LocalOnlyOffset.arm=8E6CC 73 | LocalOnlyCode.arm=bjmp5 74 | ; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled 75 | ; .text:10069E74 MOV.W R3, #0x11C 76 | ; .text:10069E78 STR R3, [SP,#0x164+var_13C] 77 | ; .text:10069E7A LDR R3, =__imp_GetVersionExW 78 | ; .text:10069E7C MOVS R4, #1 <- 0 79 | ; .text:10069E7E ADD R0, SP, #0x164+var_13C 80 | ; .text:10069E80 LDR R3, [R3] 81 | SingleUserPatch.arm=1 82 | SingleUserOffset.arm=69E7C 83 | SingleUserCode.arm=Zero 84 | ; Patch CDefPolicy::Query 85 | ; Original 86 | ; .text:10064D54 LDR.W R2, [R0,#0x324] ; D0 F8 24 23 ; [R0,#0x324] -> R2 87 | ; .text:10064D58 LDR.W R3, [R0,#0x320] ; D0 F8 20 33 ; [R0,#0x320] -> R3 88 | ; .text:10064D5C CMP R2, R3 ; 9A 42 ; compare 89 | ; .text:10064D5E BNE loc_10064D6A ; 04 D1 ; jump if (R2 != R3) 90 | ; Changed 91 | ; .text:10064D54 MOVW R3, #0x100 ; 40 F2 00 13 ; 0x100 -> R3 92 | ; .text:10064D58 STR.W R3, [R0,#0x320] ; C0 F8 20 33 ; R3 -> [R0,#0x320] 93 | ; .text:10064D5C B loc_10064D6A ; 05 E0 ; jump 94 | ; .text:10064D5E BNE loc_10064D6A ; 04 D1 ; / never executed / 95 | DefPolicyPatch.arm=1 96 | DefPolicyOffset.arm=64D54 97 | DefPolicyCode.arm=CDefPolicy_Query_r3_r0 98 | ; Hook CSLQuery::Initialize 99 | SLInitHook.arm=1 100 | SLInitOffset.arm=32188 101 | SLInitFunc.arm=New_CSLQuery_Initialize 102 | 103 | [6.3.9600.17095] 104 | ; Patch CEnforcementCore::GetInstanceOfTSLicense 105 | ; .text:1008E35A BL _IsLicenseTypeLocalOnly_CSLQuery__SAJAAU_GUID__PAH_Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *) 106 | ; .text:1008E35E CMP R0, #0 107 | ; .text:1008E360 BLT loc_1008E372 108 | ; .text:1008E362 LDR R3, [SP,#0x20+var_14] 109 | ; .text:1008E364 CBZ R3, loc_1008E372 ; 2B B1 ; jump if (R3 == 0) 110 | ; Changed 111 | ; .text:1008E364 B loc_1008E372 ; 05 E0 ; jump 112 | LocalOnlyPatch.arm=1 113 | LocalOnlyOffset.arm=8E364 114 | LocalOnlyCode.arm=bjmp5 115 | ; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled 116 | ; .text:10069C2C MOV.W R3, #0x11C 117 | ; .text:10069C30 STR R3, [SP,#0x164+var_13C] 118 | ; .text:10069C32 LDR R3, =GetVersionExW 119 | ; .text:10069C34 MOVS R4, #1 <- 0 120 | ; .text:10069C36 ADD R0, SP, #0x164+var_13C 121 | ; .text:10069C38 LDR R3, [R3] 122 | SingleUserPatch.arm=1 123 | SingleUserOffset.arm=69C34 124 | SingleUserCode.arm=Zero 125 | ; Patch CDefPolicy::Query 126 | ; Original 127 | ; .text:100649E0 LDR.W R2, [R0,#0x324] ; D0 F8 24 23 ; [R0,#0x324] -> R2 128 | ; .text:100649E4 LDR.W R3, [R0,#0x320] ; D0 F8 20 33 ; [R0,#0x320] -> R3 129 | ; .text:100649E8 CMP R2, R3 ; 9A 42 ; compare 130 | ; .text:100649EA BNE loc_100649F6 ; 04 D1 ; jump if (R2 != R3) 131 | ; Changed 132 | ; .text:100649E0 MOVW R3, #0x100 ; 40 F2 00 13 ; 0x100 -> R3 133 | ; .text:100649E4 STR.W R3, [R0,#0x320] ; C0 F8 20 33 ; R3 -> [R0,#0x320] 134 | ; .text:100649E8 B loc_10064D6A ; 05 E0 ; jump 135 | ; .text:100649EA BNE loc_10064D6A ; 04 D1 ; / never executed / 136 | DefPolicyPatch.arm=1 137 | DefPolicyOffset.arm=649E0 138 | DefPolicyCode.arm=CDefPolicy_Query_r3_r0 139 | ; Hook CSLQuery::Initialize 140 | SLInitHook.arm=1 141 | SLInitOffset.arm=32E3C 142 | SLInitFunc.arm=New_CSLQuery_Initialize 143 | 144 | [SLInit] 145 | bServerSku=1 146 | bRemoteConnAllowed=1 147 | bFUSEnabled=1 148 | bAppServerAllowed=1 149 | bMultimonAllowed=1 150 | lMaxUserSessions=0 151 | ulMaxDebugSessions=0 152 | bInitialized=1 153 | 154 | [6.3.9600.16384-SLInit] 155 | bFUSEnabled.arm =A57E0 156 | lMaxUserSessions.arm =A57E4 157 | bAppServerAllowed.arm =A57E8 158 | bInitialized.arm =A57EC 159 | bMultimonAllowed.arm =A57F0 160 | bServerSku.arm =A57F4 161 | ulMaxDebugSessions.arm=A57F8 162 | bRemoteConnAllowed.arm=A57FC 163 | 164 | [6.3.9600.17095-SLInit] 165 | bFUSEnabled.arm =A67E0 166 | lMaxUserSessions.arm =A67E4 167 | bAppServerAllowed.arm =A67E8 168 | bInitialized.arm =A67EC 169 | bMultimonAllowed.arm =A67F0 170 | bServerSku.arm =A67F4 171 | ulMaxDebugSessions.arm=A67F8 172 | bRemoteConnAllowed.arm=A67FC 173 | -------------------------------------------------------------------------------- /src-installer/RDPWInst.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {AF9BEAA3-99CD-4B2E-BE67-3F3BD27B961A} 4 | 12.0 5 | RDPWInst.dpr 6 | Release 7 | DCC32 8 | 9 | 10 | true 11 | 12 | 13 | true 14 | Base 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | ..\bin\ 24 | WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) 25 | ..\bin\RDPWInst.exe 26 | 00400000 27 | x86 28 | 29 | 30 | false 31 | RELEASE;$(DCC_Define) 32 | 0 33 | false 34 | 35 | 36 | DEBUG;$(DCC_Define) 37 | 38 | 39 | 40 | MainSource 41 | 42 | 43 | Base 44 | 45 | 46 | Cfg_1 47 | Base 48 | 49 | 50 | Cfg_2 51 | Base 52 | 53 | 54 | 55 | 56 | Delphi.Personality.12 57 | 58 | 59 | 60 | 61 | False 62 | True 63 | False 64 | -w 65 | 66 | 67 | False 68 | False 69 | 1 70 | 0 71 | 0 72 | 0 73 | False 74 | False 75 | False 76 | False 77 | False 78 | 1049 79 | 1251 80 | 81 | 82 | 83 | 84 | 1.0.0.0 85 | 86 | 87 | 88 | 89 | 90 | 1.0.0.0 91 | 92 | 93 | 94 | Embarcadero C++Builder Office 2000 Servers Package 95 | Embarcadero C++Builder Office XP Servers Package 96 | Microsoft Office 2000 Sample Automation Server Wrapper Components 97 | Microsoft Office XP Sample Automation Server Wrapper Components 98 | 99 | 100 | RDPWInst.dpr 101 | 102 | 103 | 104 | 12 105 | 106 | 107 | -------------------------------------------------------------------------------- /src-installer/resource.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-installer/resource.res -------------------------------------------------------------------------------- /src-rdpcheck/MainUnit.dfm: -------------------------------------------------------------------------------- 1 | object Frm: TFrm 2 | Left = 0 3 | Top = 0 4 | BorderIcons = [biSystemMenu, biMinimize] 5 | BorderStyle = bsSingle 6 | Caption = 'Local RDP Checker' 7 | ClientHeight = 480 8 | ClientWidth = 640 9 | Color = clBtnFace 10 | Font.Charset = DEFAULT_CHARSET 11 | Font.Color = clWindowText 12 | Font.Height = -11 13 | Font.Name = 'Tahoma' 14 | Font.Style = [] 15 | OldCreateOrder = False 16 | Position = poDesktopCenter 17 | OnCreate = FormCreate 18 | PixelsPerInch = 96 19 | TextHeight = 13 20 | object RDP: TMsRdpClient2 21 | Left = 0 22 | Top = 0 23 | Width = 640 24 | Height = 480 25 | TabOrder = 0 26 | OnDisconnected = RDPDisconnected 27 | ControlData = {0003000008000200000000000B0000000B000000} 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /src-rdpcheck/MainUnit.pas: -------------------------------------------------------------------------------- 1 | { 2 | Copyright 2015 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | } 16 | 17 | unit MainUnit; 18 | 19 | interface 20 | 21 | uses 22 | Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 23 | Dialogs, OleServer, MSTSCLib_TLB, OleCtrls, Registry; 24 | 25 | type 26 | TFrm = class(TForm) 27 | RDP: TMsRdpClient2; 28 | procedure RDPDisconnected(ASender: TObject; discReason: Integer); 29 | procedure FormCreate(Sender: TObject); 30 | private 31 | { Private declarations } 32 | public 33 | { Public declarations } 34 | end; 35 | 36 | var 37 | Frm: TFrm; 38 | SecurityLayer, UserAuthentication: DWORD; 39 | 40 | implementation 41 | 42 | {$R *.dfm} 43 | 44 | procedure TFrm.FormCreate(Sender: TObject); 45 | var 46 | Reg: TRegistry; 47 | begin 48 | RDP.DisconnectedText := 'Disconnected.'; 49 | RDP.ConnectingText := 'Connecting...'; 50 | RDP.ConnectedStatusText := 'Connected.'; 51 | RDP.UserName := ''; 52 | RDP.Server := '127.0.0.2'; 53 | Reg := TRegistry.Create; 54 | Reg.RootKey := HKEY_LOCAL_MACHINE; 55 | 56 | if Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp', True) then 57 | begin 58 | try 59 | SecurityLayer := Reg.ReadInteger('SecurityLayer'); 60 | UserAuthentication := Reg.ReadInteger('UserAuthentication'); 61 | Reg.WriteInteger('SecurityLayer', 0); 62 | Reg.WriteInteger('UserAuthentication', 0); 63 | except 64 | 65 | end; 66 | Reg.CloseKey; 67 | end; 68 | 69 | if Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp') then begin 70 | try 71 | RDP.AdvancedSettings2.RDPPort := Reg.ReadInteger('PortNumber'); 72 | except 73 | 74 | end; 75 | Reg.CloseKey; 76 | end; 77 | Reg.Free; 78 | Sleep(1000); 79 | RDP.Connect; 80 | end; 81 | 82 | procedure TFrm.RDPDisconnected(ASender: TObject; discReason: Integer); 83 | var 84 | ErrStr: String; 85 | Reg: TRegistry; 86 | begin 87 | case discReason of 88 | 1: ErrStr := 'Local disconnection.'; 89 | 2: ErrStr := 'Disconnected by user.'; 90 | 3: ErrStr := 'Disconnected by server.'; 91 | $904: ErrStr := 'Socket closed.'; 92 | $C08: ErrStr := 'Decompress error.'; 93 | $108: ErrStr := 'Connection timed out.'; 94 | $C06: ErrStr := 'Decryption error.'; 95 | $104: ErrStr := 'DNS name lookup failure.'; 96 | $508: ErrStr := 'DNS lookup failed.'; 97 | $B06: ErrStr := 'Encryption error.'; 98 | $604: ErrStr := 'Windows Sockets gethostbyname() call failed.'; 99 | $208: ErrStr := 'Host not found error.'; 100 | $408: ErrStr := 'Internal error.'; 101 | $906: ErrStr := 'Internal security error.'; 102 | $A06: ErrStr := 'Internal security error.'; 103 | $506: ErrStr := 'The encryption method specified is not valid.'; 104 | $804: ErrStr := 'Bad IP address specified.'; 105 | $606: ErrStr := 'Server security data is not valid.'; 106 | $406: ErrStr := 'Security data is not valid.'; 107 | $308: ErrStr := 'The IP address specified is not valid.'; 108 | $808: ErrStr := 'License negotiation failed.'; 109 | $908: ErrStr := 'Licensing time-out.'; 110 | $106: ErrStr := 'Out of memory.'; 111 | $206: ErrStr := 'Out of memory.'; 112 | $306: ErrStr := 'Out of memory.'; 113 | $706: ErrStr := 'Failed to unpack server certificate.'; 114 | $204: ErrStr := 'Socket connection failed.'; 115 | $404: ErrStr := 'Windows Sockets recv() call failed.'; 116 | $704: ErrStr := 'Time-out occurred.'; 117 | $608: ErrStr := 'Internal timer error.'; 118 | $304: ErrStr := 'Windows Sockets send() call failed.'; 119 | $B07: ErrStr := 'The account is disabled.'; 120 | $E07: ErrStr := 'The account is expired.'; 121 | $D07: ErrStr := 'The account is locked out.'; 122 | $C07: ErrStr := 'The account is restricted.'; 123 | $1B07: ErrStr := 'The received certificate is expired.'; 124 | $1607: ErrStr := 'The policy does not support delegation of credentials to the target server.'; 125 | $2107: ErrStr := 'The server authentication policy does not allow connection requests using saved credentials. The user must enter new credentials.'; 126 | $807: ErrStr := 'Login failed.'; 127 | $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.'; 128 | $A07: ErrStr := 'The specified user has no account.'; 129 | $F07: ErrStr := 'The password is expired.'; 130 | $1207: ErrStr := 'The user password must be changed before logging on for the first time.'; 131 | $1707: ErrStr := 'Delegation of credentials to the target server is not allowed unless mutual authentication has been achieved.'; 132 | $2207: ErrStr := 'The smart card is blocked.'; 133 | $1C07: ErrStr := 'An incorrect PIN was presented to the smart card.'; 134 | $B09: ErrStr := 'Network Level Authentication is required, run RDPCheck as administrator.'; 135 | $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.'; 136 | else ErrStr := 'Unknown code 0x'+IntToHex(discReason, 1); 137 | end; 138 | if (discReason > 2) then 139 | MessageBox(Handle, PWideChar(ErrStr), 'Disconnected', mb_Ok or mb_IconError); 140 | 141 | Reg := TRegistry.Create; 142 | Reg.RootKey := HKEY_LOCAL_MACHINE; 143 | 144 | if Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp', True) then 145 | begin 146 | try 147 | Reg.WriteInteger('SecurityLayer', SecurityLayer); 148 | Reg.WriteInteger('UserAuthentication', UserAuthentication); 149 | except 150 | 151 | end; 152 | Reg.CloseKey; 153 | end; 154 | 155 | Reg.Free; 156 | 157 | Halt(0); 158 | end; 159 | 160 | end. 161 | -------------------------------------------------------------------------------- /src-rdpcheck/RDP.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-rdpcheck/RDP.ico -------------------------------------------------------------------------------- /src-rdpcheck/RDPCheck.dpr: -------------------------------------------------------------------------------- 1 | { 2 | Copyright 2014 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | } 16 | 17 | program RDPCheck; 18 | 19 | uses 20 | Forms, 21 | MainUnit in 'MainUnit.pas' {Frm}; 22 | 23 | {$R *.res} 24 | 25 | begin 26 | Application.Initialize; 27 | Application.MainFormOnTaskbar := True; 28 | Application.Title := 'Local RDP Checker'; 29 | Application.CreateForm(TFrm, Frm); 30 | Application.Run; 31 | end. 32 | -------------------------------------------------------------------------------- /src-rdpcheck/RDPCheck.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {90AE83F6-26B8-45D4-92FE-CF4ACCDE9F68} 4 | 12.0 5 | RDPCheck.dpr 6 | Release 7 | DCC32 8 | 9 | 10 | true 11 | 12 | 13 | true 14 | Base 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | ..\bin\ 24 | WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) 25 | ..\bin\RDPCheck.exe 26 | 00400000 27 | x86 28 | 29 | 30 | false 31 | RELEASE;$(DCC_Define) 32 | 0 33 | false 34 | 35 | 36 | DEBUG;$(DCC_Define) 37 | 38 | 39 | 40 | MainSource 41 | 42 | 43 |
Frm
44 |
45 | 46 | Base 47 | 48 | 49 | Cfg_1 50 | Base 51 | 52 | 53 | Cfg_2 54 | Base 55 | 56 |
57 | 58 | 59 | Delphi.Personality.12 60 | 61 | 62 | 63 | 64 | False 65 | True 66 | False 67 | 68 | 69 | True 70 | False 71 | 2 72 | 2 73 | 0 74 | 0 75 | False 76 | False 77 | False 78 | False 79 | False 80 | 1033 81 | 1252 82 | 83 | 84 | Stas'M Corp. 85 | Local RDP Checker 86 | 2.2.0.0 87 | RDPCheck 88 | Copyright © Stas'M Corp. 2015 89 | Stas'M Corp. 90 | RDPCheck.exe 91 | RDP Host Support 92 | 1.6.0.0 93 | http://stascorp.com 94 | 95 | 96 | Embarcadero C++Builder Office 2000 Servers Package 97 | Embarcadero C++Builder Office XP Servers Package 98 | Microsoft Office 2000 Sample Automation Server Wrapper Components 99 | Microsoft Office XP Sample Automation Server Wrapper Components 100 | 101 | 102 | RDPCheck.dpr 103 | 104 | 105 | 106 | 12 107 | 108 |
109 | -------------------------------------------------------------------------------- /src-rdpcheck/RDPCheck.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-rdpcheck/RDPCheck.res -------------------------------------------------------------------------------- /src-rdpconfig/LicenseUnit.dfm: -------------------------------------------------------------------------------- 1 | object LicenseForm: TLicenseForm 2 | Left = 0 3 | Top = 0 4 | BorderIcons = [] 5 | BorderStyle = bsDialog 6 | Caption = 'License Agreement' 7 | ClientHeight = 344 8 | ClientWidth = 386 9 | Color = clBtnFace 10 | Font.Charset = DEFAULT_CHARSET 11 | Font.Color = clWindowText 12 | Font.Height = -11 13 | Font.Name = 'Tahoma' 14 | Font.Style = [] 15 | OldCreateOrder = False 16 | Position = poOwnerFormCenter 17 | PixelsPerInch = 96 18 | TextHeight = 13 19 | object mText: TMemo 20 | Left = 8 21 | Top = 8 22 | Width = 370 23 | Height = 297 24 | ReadOnly = True 25 | ScrollBars = ssBoth 26 | TabOrder = 0 27 | WordWrap = False 28 | end 29 | object bAccept: TButton 30 | Left = 115 31 | Top = 311 32 | Width = 75 33 | Height = 25 34 | Caption = '&Accept' 35 | ModalResult = 1 36 | TabOrder = 1 37 | end 38 | object bDecline: TButton 39 | Left = 196 40 | Top = 311 41 | Width = 75 42 | Height = 25 43 | Caption = '&Decline' 44 | ModalResult = 2 45 | TabOrder = 2 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /src-rdpconfig/LicenseUnit.pas: -------------------------------------------------------------------------------- 1 | { 2 | Copyright 2014 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | } 16 | 17 | unit LicenseUnit; 18 | 19 | interface 20 | 21 | uses 22 | Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 23 | Dialogs, StdCtrls; 24 | 25 | type 26 | TLicenseForm = class(TForm) 27 | mText: TMemo; 28 | bAccept: TButton; 29 | bDecline: TButton; 30 | private 31 | { Private declarations } 32 | public 33 | { Public declarations } 34 | end; 35 | 36 | var 37 | LicenseForm: TLicenseForm; 38 | 39 | implementation 40 | 41 | {$R *.dfm} 42 | 43 | end. 44 | -------------------------------------------------------------------------------- /src-rdpconfig/MainUnit.dfm: -------------------------------------------------------------------------------- 1 | object MainForm: TMainForm 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsDialog 5 | Caption = 'RDP Wrapper Configuration' 6 | ClientHeight = 314 7 | ClientWidth = 404 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | OldCreateOrder = False 15 | Position = poDesktopCenter 16 | OnCloseQuery = FormCloseQuery 17 | OnCreate = FormCreate 18 | OnDestroy = FormDestroy 19 | PixelsPerInch = 96 20 | TextHeight = 13 21 | object bOK: TButton 22 | Left = 40 23 | Top = 281 24 | Width = 75 25 | Height = 25 26 | Caption = 'OK' 27 | ModalResult = 1 28 | TabOrder = 4 29 | OnClick = bOKClick 30 | end 31 | object bCancel: TButton 32 | Left = 121 33 | Top = 281 34 | Width = 75 35 | Height = 25 36 | Caption = 'Cancel' 37 | ModalResult = 2 38 | TabOrder = 5 39 | OnClick = bCancelClick 40 | end 41 | object bApply: TButton 42 | Left = 202 43 | Top = 281 44 | Width = 75 45 | Height = 25 46 | Caption = 'Apply' 47 | Enabled = False 48 | TabOrder = 6 49 | OnClick = bApplyClick 50 | end 51 | object rgNLA: TRadioGroup 52 | Left = 202 53 | Top = 89 54 | Width = 194 55 | Height = 73 56 | Caption = 'Authentication Mode' 57 | Items.Strings = ( 58 | 'GUI Authentication Only' 59 | 'Default RDP Authentication' 60 | 'Network Level Authentication') 61 | TabOrder = 2 62 | OnClick = cbAllowTSConnectionsClick 63 | end 64 | object rgShadow: TRadioGroup 65 | Left = 202 66 | Top = 168 67 | Width = 194 68 | Height = 105 69 | Caption = 'Session Shadowing Mode' 70 | Items.Strings = ( 71 | 'Disable Shadowing' 72 | 'Full access with user'#39's permission' 73 | 'Full access without permission' 74 | 'View only with user'#39's permission' 75 | 'View only without permission') 76 | TabOrder = 3 77 | OnClick = cbAllowTSConnectionsClick 78 | end 79 | object bLicense: TButton 80 | Left = 283 81 | Top = 281 82 | Width = 87 83 | Height = 25 84 | Caption = 'View license...' 85 | TabOrder = 7 86 | OnClick = bLicenseClick 87 | end 88 | object gbDiag: TGroupBox 89 | Left = 8 90 | Top = 6 91 | Width = 388 92 | Height = 77 93 | Caption = 'Diagnostics' 94 | TabOrder = 0 95 | object lListener: TLabel 96 | Left = 11 97 | Top = 55 98 | Width = 70 99 | Height = 13 100 | Caption = 'Listener state:' 101 | end 102 | object lService: TLabel 103 | Left = 11 104 | Top = 36 105 | Width = 67 106 | Height = 13 107 | Caption = 'Service state:' 108 | end 109 | object lsListener: TLabel 110 | Left = 91 111 | Top = 55 112 | Width = 44 113 | Height = 13 114 | Caption = 'Unknown' 115 | end 116 | object lsService: TLabel 117 | Left = 91 118 | Top = 36 119 | Width = 44 120 | Height = 13 121 | Caption = 'Unknown' 122 | end 123 | object lsTSVer: TLabel 124 | Left = 226 125 | Top = 36 126 | Width = 44 127 | Height = 13 128 | Caption = 'Unknown' 129 | end 130 | object lsWrapper: TLabel 131 | Left = 91 132 | Top = 17 133 | Width = 44 134 | Height = 13 135 | Caption = 'Unknown' 136 | end 137 | object lsWrapVer: TLabel 138 | Left = 226 139 | Top = 17 140 | Width = 44 141 | Height = 13 142 | Caption = 'Unknown' 143 | end 144 | object lTSVer: TLabel 145 | Left = 202 146 | Top = 36 147 | Width = 20 148 | Height = 13 149 | Caption = 'ver.' 150 | end 151 | object lWrapper: TLabel 152 | Left = 11 153 | Top = 17 154 | Width = 74 155 | Height = 13 156 | Caption = 'Wrapper state:' 157 | end 158 | object lWrapVer: TLabel 159 | Left = 202 160 | Top = 17 161 | Width = 20 162 | Height = 13 163 | Caption = 'ver.' 164 | end 165 | object lsSuppVer: TLabel 166 | Left = 202 167 | Top = 55 168 | Width = 70 169 | Height = 13 170 | Caption = '[support level]' 171 | end 172 | end 173 | object gbGeneral: TGroupBox 174 | Left = 8 175 | Top = 89 176 | Width = 188 177 | Height = 184 178 | Caption = 'General Settings' 179 | TabOrder = 1 180 | object lRDPPort: TLabel 181 | Left = 8 182 | Top = 44 183 | Width = 47 184 | Height = 13 185 | Caption = 'RDP port:' 186 | end 187 | object cbAllowTSConnections: TCheckBox 188 | Left = 8 189 | Top = 18 190 | Width = 132 191 | Height = 17 192 | Caption = 'Enable Remote Desktop' 193 | TabOrder = 0 194 | OnClick = cbAllowTSConnectionsClick 195 | end 196 | object cbSingleSessionPerUser: TCheckBox 197 | Left = 8 198 | Top = 69 199 | Width = 129 200 | Height = 17 201 | Caption = 'Single session per user' 202 | TabOrder = 2 203 | OnClick = cbAllowTSConnectionsClick 204 | end 205 | object cbHideUsers: TCheckBox 206 | Left = 8 207 | Top = 92 208 | Width = 149 209 | Height = 17 210 | Caption = 'Hide users on logon screen' 211 | TabOrder = 3 212 | OnClick = cbAllowTSConnectionsClick 213 | end 214 | object seRDPPort: TSpinEdit 215 | Left = 61 216 | Top = 41 217 | Width = 62 218 | Height = 22 219 | MaxValue = 65535 220 | MinValue = 0 221 | TabOrder = 1 222 | Value = 0 223 | OnChange = seRDPPortChange 224 | end 225 | object cbCustomPrg: TCheckBox 226 | Left = 8 227 | Top = 115 228 | Width = 169 229 | Height = 17 230 | Caption = 'Allow to start custom programs' 231 | TabOrder = 4 232 | OnClick = cbAllowTSConnectionsClick 233 | end 234 | end 235 | object Timer: TTimer 236 | Interval = 250 237 | OnTimer = TimerTimer 238 | Left = 352 239 | Top = 27 240 | end 241 | end 242 | -------------------------------------------------------------------------------- /src-rdpconfig/MainUnit.pas: -------------------------------------------------------------------------------- 1 | { 2 | Copyright 2017 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | } 16 | 17 | unit MainUnit; 18 | 19 | interface 20 | 21 | uses 22 | Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 23 | Dialogs, StdCtrls, Spin, ExtCtrls, Registry, WinSvc; 24 | 25 | type 26 | TMainForm = class(TForm) 27 | bOK: TButton; 28 | bCancel: TButton; 29 | bApply: TButton; 30 | cbSingleSessionPerUser: TCheckBox; 31 | rgNLA: TRadioGroup; 32 | cbAllowTSConnections: TCheckBox; 33 | rgShadow: TRadioGroup; 34 | seRDPPort: TSpinEdit; 35 | lRDPPort: TLabel; 36 | lService: TLabel; 37 | lListener: TLabel; 38 | lWrapper: TLabel; 39 | lsListener: TLabel; 40 | lsService: TLabel; 41 | lsWrapper: TLabel; 42 | Timer: TTimer; 43 | lTSVer: TLabel; 44 | lsTSVer: TLabel; 45 | lWrapVer: TLabel; 46 | lsWrapVer: TLabel; 47 | bLicense: TButton; 48 | gbDiag: TGroupBox; 49 | lsSuppVer: TLabel; 50 | cbHideUsers: TCheckBox; 51 | gbGeneral: TGroupBox; 52 | cbCustomPrg: TCheckBox; 53 | procedure FormCreate(Sender: TObject); 54 | procedure cbAllowTSConnectionsClick(Sender: TObject); 55 | procedure seRDPPortChange(Sender: TObject); 56 | procedure bApplyClick(Sender: TObject); 57 | procedure bCancelClick(Sender: TObject); 58 | procedure bOKClick(Sender: TObject); 59 | procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); 60 | procedure bLicenseClick(Sender: TObject); 61 | procedure TimerTimer(Sender: TObject); 62 | procedure FormDestroy(Sender: TObject); 63 | private 64 | { Private declarations } 65 | public 66 | { Public declarations } 67 | function ExecWait(Cmdline: String): Boolean; 68 | procedure ReadSettings; 69 | procedure WriteSettings; 70 | end; 71 | FILE_VERSION = record 72 | Version: record case Boolean of 73 | True: (dw: DWORD); 74 | False: (w: record 75 | Minor, Major: Word; 76 | end;) 77 | end; 78 | Release, Build: Word; 79 | bDebug, bPrerelease, bPrivate, bSpecial: Boolean; 80 | end; 81 | WTS_SESSION_INFOW = record 82 | SessionId: DWORD; 83 | Name: packed array [0..33] of WideChar; 84 | State: DWORD; 85 | end; 86 | WTS_SESSION = Array[0..0] of WTS_SESSION_INFOW; 87 | PWTS_SESSION_INFOW = ^WTS_SESSION; 88 | 89 | const 90 | winstadll = 'winsta.dll'; 91 | var 92 | MainForm: TMainForm; 93 | Ready: Boolean = False; 94 | Arch: Byte; 95 | OldWow64RedirectionValue: LongBool; 96 | OldPort: Word; 97 | INI: String; 98 | 99 | function WinStationEnumerateW(hServer: THandle; 100 | var ppSessionInfo: PWTS_SESSION_INFOW; var pCount: DWORD): BOOL; stdcall; 101 | external winstadll name 'WinStationEnumerateW'; 102 | function WinStationFreeMemory(P: Pointer): BOOL; stdcall; external winstadll; 103 | 104 | implementation 105 | 106 | {$R *.dfm} 107 | {$R resource.res} 108 | 109 | uses 110 | LicenseUnit; 111 | 112 | function ExpandPath(Path: String): String; 113 | var 114 | Str: Array[0..511] of Char; 115 | begin 116 | Result := ''; 117 | FillChar(Str, 512, 0); 118 | if Arch = 64 then 119 | Path := StringReplace(Path, '%ProgramFiles%', '%ProgramW6432%', [rfReplaceAll, rfIgnoreCase]); 120 | if ExpandEnvironmentStrings(PWideChar(Path), Str, 512) > 0 then 121 | Result := Str; 122 | end; 123 | 124 | function DisableWowRedirection: Boolean; 125 | type 126 | TFunc = function(var Wow64FsEnableRedirection: LongBool): LongBool; stdcall; 127 | var 128 | hModule: THandle; 129 | Wow64DisableWow64FsRedirection: TFunc; 130 | begin 131 | Result := False; 132 | hModule := GetModuleHandle(kernel32); 133 | if hModule <> 0 then 134 | Wow64DisableWow64FsRedirection := GetProcAddress(hModule, 'Wow64DisableWow64FsRedirection') 135 | else 136 | Exit; 137 | if @Wow64DisableWow64FsRedirection <> nil then 138 | Result := Wow64DisableWow64FsRedirection(OldWow64RedirectionValue); 139 | end; 140 | 141 | function RevertWowRedirection: Boolean; 142 | type 143 | TFunc = function(var Wow64RevertWow64FsRedirection: LongBool): LongBool; stdcall; 144 | var 145 | hModule: THandle; 146 | Wow64RevertWow64FsRedirection: TFunc; 147 | begin 148 | Result := False; 149 | hModule := GetModuleHandle(kernel32); 150 | if hModule <> 0 then 151 | Wow64RevertWow64FsRedirection := GetProcAddress(hModule, 'Wow64RevertWow64FsRedirection') 152 | else 153 | Exit; 154 | if @Wow64RevertWow64FsRedirection <> nil then 155 | Result := Wow64RevertWow64FsRedirection(OldWow64RedirectionValue); 156 | end; 157 | 158 | function GetFileVersion(const FileName: TFileName; var FileVersion: FILE_VERSION): Boolean; 159 | type 160 | VS_VERSIONINFO = record 161 | wLength, wValueLength, wType: Word; 162 | szKey: Array[1..16] of WideChar; 163 | Padding1: Word; 164 | Value: VS_FIXEDFILEINFO; 165 | Padding2, Children: Word; 166 | end; 167 | PVS_VERSIONINFO = ^VS_VERSIONINFO; 168 | const 169 | VFF_DEBUG = 1; 170 | VFF_PRERELEASE = 2; 171 | VFF_PRIVATE = 8; 172 | VFF_SPECIAL = 32; 173 | var 174 | hFile: HMODULE; 175 | hResourceInfo: HRSRC; 176 | VersionInfo: PVS_VERSIONINFO; 177 | begin 178 | Result := False; 179 | 180 | hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE); 181 | if hFile = 0 then 182 | Exit; 183 | 184 | hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10)); 185 | if hResourceInfo = 0 then 186 | Exit; 187 | 188 | VersionInfo := Pointer(LoadResource(hFile, hResourceInfo)); 189 | if VersionInfo = nil then 190 | Exit; 191 | 192 | FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS; 193 | FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16); 194 | FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS); 195 | FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG; 196 | FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE; 197 | FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE; 198 | FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL; 199 | 200 | FreeLibrary(hFile); 201 | Result := True; 202 | end; 203 | 204 | function IsWrapperInstalled(var WrapperPath: String): ShortInt; 205 | var 206 | TermServiceHost, 207 | TermServicePath: String; 208 | Reg: TRegistry; 209 | begin 210 | Result := -1; 211 | WrapperPath := ''; 212 | Reg := TRegistry.Create; 213 | Reg.RootKey := HKEY_LOCAL_MACHINE; 214 | if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService') then begin 215 | Reg.Free; 216 | Exit; 217 | end; 218 | TermServiceHost := Reg.ReadString('ImagePath'); 219 | Reg.CloseKey; 220 | if Pos('svchost.exe', LowerCase(TermServiceHost)) = 0 then 221 | begin 222 | Result := 2; 223 | Reg.Free; 224 | Exit; 225 | end; 226 | if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService\Parameters') then 227 | begin 228 | Reg.Free; 229 | Exit; 230 | end; 231 | TermServicePath := Reg.ReadString('ServiceDll'); 232 | Reg.CloseKey; 233 | Reg.Free; 234 | if (Pos('termsrv.dll', LowerCase(TermServicePath)) = 0) 235 | and (Pos('rdpwrap.dll', LowerCase(TermServicePath)) = 0) then 236 | begin 237 | Result := 2; 238 | Exit; 239 | end; 240 | 241 | if Pos('rdpwrap.dll', LowerCase(TermServicePath)) > 0 then begin 242 | WrapperPath := TermServicePath; 243 | Result := 1; 244 | end else 245 | Result := 0; 246 | end; 247 | 248 | function GetTermSrvState: ShortInt; 249 | type 250 | SERVICE_STATUS_PROCESS = record 251 | dwServiceType, 252 | dwCurrentState, 253 | dwControlsAccepted, 254 | dwWin32ExitCode, 255 | dwServiceSpecificExitCode, 256 | dwCheckPoint, 257 | dwWaitHint, 258 | dwProcessId, 259 | dwServiceFlags: DWORD; 260 | end; 261 | PSERVICE_STATUS_PROCESS = ^SERVICE_STATUS_PROCESS; 262 | const 263 | SvcName = 'TermService'; 264 | var 265 | hSC: SC_HANDLE; 266 | hSvc: THandle; 267 | lpServiceStatusProcess: PSERVICE_STATUS_PROCESS; 268 | Buf: Pointer; 269 | cbBufSize, pcbBytesNeeded: Cardinal; 270 | begin 271 | Result := -1; 272 | hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); 273 | if hSC = 0 then 274 | Exit; 275 | 276 | hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_QUERY_STATUS); 277 | if hSvc = 0 then 278 | begin 279 | CloseServiceHandle(hSC); 280 | Exit; 281 | end; 282 | 283 | if QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, nil, 0, pcbBytesNeeded) then 284 | Exit; 285 | 286 | cbBufSize := pcbBytesNeeded; 287 | GetMem(Buf, cbBufSize); 288 | 289 | if not QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, Buf, cbBufSize, pcbBytesNeeded) then begin 290 | FreeMem(Buf, cbBufSize); 291 | CloseServiceHandle(hSvc); 292 | CloseServiceHandle(hSC); 293 | Exit; 294 | end else begin 295 | lpServiceStatusProcess := Buf; 296 | Result := ShortInt(lpServiceStatusProcess^.dwCurrentState); 297 | end; 298 | FreeMem(Buf, cbBufSize); 299 | CloseServiceHandle(hSvc); 300 | CloseServiceHandle(hSC); 301 | end; 302 | 303 | function IsListenerWorking: Boolean; 304 | var 305 | pCount: DWORD; 306 | SessionInfo: PWTS_SESSION_INFOW; 307 | I: Integer; 308 | begin 309 | Result := False; 310 | if not WinStationEnumerateW(0, SessionInfo, pCount) then 311 | Exit; 312 | for I := 0 to pCount - 1 do 313 | if SessionInfo^[I].Name = 'RDP-Tcp' then begin 314 | Result := True; 315 | Break; 316 | end; 317 | WinStationFreeMemory(SessionInfo); 318 | end; 319 | 320 | function ExtractResText(ResName: String): String; 321 | var 322 | ResStream: TResourceStream; 323 | Str: TStringList; 324 | begin 325 | ResStream := TResourceStream.Create(HInstance, ResName, RT_RCDATA); 326 | Str := TStringList.Create; 327 | try 328 | Str.LoadFromStream(ResStream); 329 | except 330 | 331 | end; 332 | ResStream.Free; 333 | Result := Str.Text; 334 | Str.Free; 335 | end; 336 | 337 | function TMainForm.ExecWait(Cmdline: String): Boolean; 338 | var 339 | si: STARTUPINFO; 340 | pi: PROCESS_INFORMATION; 341 | begin 342 | Result := False; 343 | ZeroMemory(@si, sizeof(si)); 344 | si.cb := sizeof(si); 345 | si.dwFlags := STARTF_USESHOWWINDOW; 346 | si.wShowWindow := SW_HIDE; 347 | UniqueString(Cmdline); 348 | if not CreateProcess(nil, PWideChar(Cmdline), nil, nil, True, 0, nil, nil, si, pi) then begin 349 | MessageBox(Handle, 350 | PWideChar('CreateProcess error (code: ' + IntToStr(GetLastError) + ').'), 351 | 'Error', MB_ICONERROR or MB_OK); 352 | Exit; 353 | end; 354 | CloseHandle(pi.hThread); 355 | WaitForSingleObject(pi.hProcess, INFINITE); 356 | CloseHandle(pi.hProcess); 357 | Result := True; 358 | end; 359 | 360 | procedure TMainForm.ReadSettings; 361 | var 362 | Reg: TRegistry; 363 | SecurityLayer, UserAuthentication: Integer; 364 | begin 365 | Reg := TRegistry.Create; 366 | Reg.RootKey := HKEY_LOCAL_MACHINE; 367 | Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Control\Terminal Server'); 368 | try 369 | cbAllowTSConnections.Checked := not Reg.ReadBool('fDenyTSConnections'); 370 | except 371 | 372 | end; 373 | try 374 | cbSingleSessionPerUser.Checked := Reg.ReadBool('fSingleSessionPerUser'); 375 | except 376 | 377 | end; 378 | try 379 | cbCustomPrg.Checked := Reg.ReadBool('HonorLegacySettings'); 380 | except 381 | 382 | end; 383 | Reg.CloseKey; 384 | 385 | Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'); 386 | seRDPPort.Value := 3389; 387 | try 388 | seRDPPort.Value := Reg.ReadInteger('PortNumber'); 389 | except 390 | 391 | end; 392 | OldPort := seRDPPort.Value; 393 | SecurityLayer := 0; 394 | UserAuthentication := 0; 395 | try 396 | SecurityLayer := Reg.ReadInteger('SecurityLayer'); 397 | UserAuthentication := Reg.ReadInteger('UserAuthentication'); 398 | except 399 | 400 | end; 401 | if (SecurityLayer = 0) and (UserAuthentication = 0) then 402 | rgNLA.ItemIndex := 0; 403 | if (SecurityLayer = 1) and (UserAuthentication = 0) then 404 | rgNLA.ItemIndex := 1; 405 | if (SecurityLayer = 2) and (UserAuthentication = 1) then 406 | rgNLA.ItemIndex := 2; 407 | try 408 | rgShadow.ItemIndex := Reg.ReadInteger('Shadow'); 409 | except 410 | 411 | end; 412 | Reg.CloseKey; 413 | Reg.OpenKeyReadOnly('\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'); 414 | try 415 | cbHideUsers.Checked := Reg.ReadBool('dontdisplaylastusername'); 416 | except 417 | 418 | end; 419 | Reg.CloseKey; 420 | Reg.Free; 421 | end; 422 | 423 | procedure TMainForm.WriteSettings; 424 | var 425 | Reg: TRegistry; 426 | SecurityLayer, UserAuthentication: Integer; 427 | begin 428 | Reg := TRegistry.Create; 429 | Reg.RootKey := HKEY_LOCAL_MACHINE; 430 | Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server', True); 431 | try 432 | Reg.WriteBool('fDenyTSConnections', not cbAllowTSConnections.Checked); 433 | except 434 | 435 | end; 436 | try 437 | Reg.WriteBool('fSingleSessionPerUser', cbSingleSessionPerUser.Checked); 438 | except 439 | 440 | end; 441 | try 442 | Reg.WriteBool('HonorLegacySettings', cbCustomPrg.Checked); 443 | except 444 | 445 | end; 446 | Reg.CloseKey; 447 | 448 | Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp', True); 449 | try 450 | Reg.WriteInteger('PortNumber', seRDPPort.Value); 451 | except 452 | 453 | end; 454 | if OldPort <> seRDPPort.Value then 455 | begin 456 | OldPort := seRDPPort.Value; 457 | ExecWait('netsh advfirewall firewall set rule name="Remote Desktop" new localport=' + IntToStr(OldPort)); 458 | end; 459 | case rgNLA.ItemIndex of 460 | 0: begin 461 | SecurityLayer := 0; 462 | UserAuthentication := 0; 463 | end; 464 | 1: begin 465 | SecurityLayer := 1; 466 | UserAuthentication := 0; 467 | end; 468 | 2: begin 469 | SecurityLayer := 2; 470 | UserAuthentication := 1; 471 | end; 472 | else begin 473 | SecurityLayer := -1; 474 | UserAuthentication := -1; 475 | end; 476 | end; 477 | if SecurityLayer >= 0 then begin 478 | try 479 | Reg.WriteInteger('SecurityLayer', SecurityLayer); 480 | Reg.WriteInteger('UserAuthentication', UserAuthentication); 481 | except 482 | 483 | end; 484 | end; 485 | if rgShadow.ItemIndex >= 0 then begin 486 | try 487 | Reg.WriteInteger('Shadow', rgShadow.ItemIndex); 488 | except 489 | 490 | end; 491 | end; 492 | Reg.CloseKey; 493 | Reg.OpenKey('\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services', True); 494 | if rgShadow.ItemIndex >= 0 then begin 495 | try 496 | Reg.WriteInteger('Shadow', rgShadow.ItemIndex); 497 | except 498 | 499 | end; 500 | end; 501 | Reg.CloseKey; 502 | Reg.OpenKey('\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System', True); 503 | try 504 | Reg.WriteBool('dontdisplaylastusername', cbHideUsers.Checked); 505 | except 506 | 507 | end; 508 | Reg.CloseKey; 509 | Reg.Free; 510 | end; 511 | 512 | function CheckSupport(FV: FILE_VERSION): Byte; 513 | var 514 | VerTxt: String; 515 | begin 516 | Result := 0; 517 | if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then 518 | Result := 1; 519 | if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then 520 | Result := 1; 521 | VerTxt := Format('%d.%d.%d.%d', 522 | [FV.Version.w.Major, FV.Version.w.Minor, FV.Release, FV.Build]); 523 | if Pos('[' + VerTxt + ']', INI) > 0 then 524 | Result := 2; 525 | end; 526 | 527 | procedure TMainForm.TimerTimer(Sender: TObject); 528 | var 529 | WrapperPath, INIPath: String; 530 | FV: FILE_VERSION; 531 | L: TStringList; 532 | CheckSupp: Boolean; 533 | begin 534 | CheckSupp := False; 535 | case IsWrapperInstalled(WrapperPath) of 536 | -1: begin 537 | lsWrapper.Caption := 'Unknown'; 538 | lsWrapper.Font.Color := clGrayText; 539 | end; 540 | 0: begin 541 | lsWrapper.Caption := 'Not installed'; 542 | lsWrapper.Font.Color := clGrayText; 543 | end; 544 | 1: begin 545 | lsWrapper.Caption := 'Installed'; 546 | lsWrapper.Font.Color := clGreen; 547 | CheckSupp := True; 548 | INIPath := ExtractFilePath(ExpandPath(WrapperPath)) + 'rdpwrap.ini'; 549 | if not FileExists(INIPath) then 550 | CheckSupp := False; 551 | end; 552 | 2: begin 553 | lsWrapper.Caption := '3rd-party'; 554 | lsWrapper.Font.Color := clRed; 555 | end; 556 | end; 557 | case GetTermSrvState of 558 | -1, 0: begin 559 | lsService.Caption := 'Unknown'; 560 | lsService.Font.Color := clGrayText; 561 | end; 562 | SERVICE_STOPPED: begin 563 | lsService.Caption := 'Stopped'; 564 | lsService.Font.Color := clRed; 565 | end; 566 | SERVICE_START_PENDING: begin 567 | lsService.Caption := 'Starting...'; 568 | lsService.Font.Color := clGrayText; 569 | end; 570 | SERVICE_STOP_PENDING: begin 571 | lsService.Caption := 'Stopping...'; 572 | lsService.Font.Color := clGrayText; 573 | end; 574 | SERVICE_RUNNING: begin 575 | lsService.Caption := 'Running'; 576 | lsService.Font.Color := clGreen; 577 | end; 578 | SERVICE_CONTINUE_PENDING: begin 579 | lsService.Caption := 'Resuming...'; 580 | lsService.Font.Color := clGrayText; 581 | end; 582 | SERVICE_PAUSE_PENDING: begin 583 | lsService.Caption := 'Suspending...'; 584 | lsService.Font.Color := clGrayText; 585 | end; 586 | SERVICE_PAUSED: begin 587 | lsService.Caption := 'Suspended'; 588 | lsService.Font.Color := clWindowText; 589 | end; 590 | end; 591 | if IsListenerWorking then begin 592 | lsListener.Caption := 'Listening'; 593 | lsListener.Font.Color := clGreen; 594 | end else begin 595 | lsListener.Caption := 'Not listening'; 596 | lsListener.Font.Color := clRed; 597 | end; 598 | if WrapperPath = '' then begin 599 | lsWrapVer.Caption := 'N/A'; 600 | lsWrapVer.Font.Color := clGrayText; 601 | end else 602 | if not GetFileVersion(ExpandPath(WrapperPath), FV) then begin 603 | lsWrapVer.Caption := 'N/A'; 604 | lsWrapVer.Font.Color := clGrayText; 605 | end else begin 606 | lsWrapVer.Caption := 607 | IntToStr(FV.Version.w.Major)+'.'+ 608 | IntToStr(FV.Version.w.Minor)+'.'+ 609 | IntToStr(FV.Release)+'.'+ 610 | IntToStr(FV.Build); 611 | lsWrapVer.Font.Color := clWindowText; 612 | end; 613 | if not GetFileVersion('termsrv.dll', FV) then begin 614 | lsTSVer.Caption := 'N/A'; 615 | lsTSVer.Font.Color := clGrayText; 616 | end else begin 617 | lsTSVer.Caption := 618 | IntToStr(FV.Version.w.Major)+'.'+ 619 | IntToStr(FV.Version.w.Minor)+'.'+ 620 | IntToStr(FV.Release)+'.'+ 621 | IntToStr(FV.Build); 622 | lsTSVer.Font.Color := clWindowText; 623 | lsSuppVer.Visible := CheckSupp; 624 | if CheckSupp then begin 625 | if INI = '' then begin 626 | L := TStringList.Create; 627 | try 628 | L.LoadFromFile(INIPath); 629 | except 630 | 631 | end; 632 | INI := L.Text; 633 | L.Free; 634 | end; 635 | case CheckSupport(FV) of 636 | 0: begin 637 | lsSuppVer.Caption := '[not supported]'; 638 | lsSuppVer.Font.Color := clRed; 639 | end; 640 | 1: begin 641 | lsSuppVer.Caption := '[supported partially]'; 642 | lsSuppVer.Font.Color := clOlive; 643 | end; 644 | 2: begin 645 | lsSuppVer.Caption := '[fully supported]'; 646 | lsSuppVer.Font.Color := clGreen; 647 | end; 648 | end; 649 | end; 650 | end; 651 | end; 652 | 653 | procedure TMainForm.bLicenseClick(Sender: TObject); 654 | begin 655 | LicenseForm.mText.Text := ExtractResText('LICENSE'); 656 | if LicenseForm.ShowModal <> mrOk then 657 | Halt(0); 658 | end; 659 | 660 | procedure TMainForm.cbAllowTSConnectionsClick(Sender: TObject); 661 | begin 662 | if Ready then 663 | bApply.Enabled := True; 664 | end; 665 | 666 | procedure TMainForm.seRDPPortChange(Sender: TObject); 667 | begin 668 | if Ready then 669 | bApply.Enabled := True; 670 | end; 671 | 672 | procedure TMainForm.FormCreate(Sender: TObject); 673 | var 674 | SI: TSystemInfo; 675 | begin 676 | GetNativeSystemInfo(SI); 677 | case SI.wProcessorArchitecture of 678 | 0: Arch := 32; 679 | 6: Arch := 64; // Itanium-based x64 680 | 9: Arch := 64; // Intel/AMD x64 681 | else Arch := 0; 682 | end; 683 | if Arch = 64 then 684 | DisableWowRedirection; 685 | ReadSettings; 686 | Ready := True; 687 | end; 688 | 689 | procedure TMainForm.FormDestroy(Sender: TObject); 690 | begin 691 | if Arch = 64 then 692 | RevertWowRedirection; 693 | end; 694 | 695 | procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 696 | begin 697 | if bApply.Enabled then 698 | CanClose := MessageBox(Handle, 'Settings are not saved. Do you want to exit?', 699 | 'Warning', mb_IconWarning or mb_YesNo) = mrYes; 700 | end; 701 | 702 | procedure TMainForm.bOKClick(Sender: TObject); 703 | begin 704 | if bApply.Enabled then begin 705 | WriteSettings; 706 | bApply.Enabled := False; 707 | end; 708 | Close; 709 | end; 710 | 711 | procedure TMainForm.bCancelClick(Sender: TObject); 712 | begin 713 | Close; 714 | end; 715 | 716 | procedure TMainForm.bApplyClick(Sender: TObject); 717 | begin 718 | WriteSettings; 719 | bApply.Enabled := False; 720 | end; 721 | 722 | end. 723 | -------------------------------------------------------------------------------- /src-rdpconfig/RDPConf.dpr: -------------------------------------------------------------------------------- 1 | { 2 | Copyright 2014 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | } 16 | 17 | program RDPConf; 18 | 19 | uses 20 | Forms, 21 | MainUnit in 'MainUnit.pas' {MainForm}, 22 | LicenseUnit in 'LicenseUnit.pas' {LicenseForm}; 23 | 24 | {$R *.res} 25 | 26 | begin 27 | Application.Initialize; 28 | Application.MainFormOnTaskbar := True; 29 | Application.Title := 'Remote Desktop Protocol Configuration'; 30 | Application.CreateForm(TMainForm, MainForm); 31 | Application.CreateForm(TLicenseForm, LicenseForm); 32 | Application.Run; 33 | end. 34 | -------------------------------------------------------------------------------- /src-rdpconfig/RDPConf.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {A7CB4C30-85F5-4D96-B510-6F0CDCF7C2DA} 4 | 12.0 5 | RDPConf.dpr 6 | Debug 7 | DCC32 8 | 9 | 10 | true 11 | 12 | 13 | true 14 | Base 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | ..\bin\ 24 | WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) 25 | ..\bin\RDPConf.exe 26 | 00400000 27 | x86 28 | 29 | 30 | false 31 | RELEASE;$(DCC_Define) 32 | 0 33 | false 34 | 35 | 36 | DEBUG;$(DCC_Define) 37 | 38 | 39 | 40 | MainSource 41 | 42 | 43 |
MainForm
44 |
45 | 46 |
LicenseForm
47 |
48 | 49 | Base 50 | 51 | 52 | Cfg_1 53 | Base 54 | 55 | 56 | Cfg_2 57 | Base 58 | 59 |
60 | 61 | 62 | Delphi.Personality.12 63 | 64 | 65 | 66 | 67 | RDPConf.dpr 68 | 69 | 70 | False 71 | True 72 | False 73 | 74 | 75 | False 76 | False 77 | 1 78 | 0 79 | 0 80 | 0 81 | False 82 | False 83 | False 84 | False 85 | False 86 | 1033 87 | 1252 88 | 89 | 90 | Stas'M Corp. 91 | RDP Configuration Program 92 | 1.0.0.0 93 | RDPConf 94 | Copyright © Stas'M Corp. 2014 95 | Stas'M Corp. 96 | RDPConf.exe 97 | RDP Host Support 98 | 1.4.0.0 99 | http://stascorp.com 100 | 101 | 102 | Embarcadero C++Builder Office 2000 Servers Package 103 | Embarcadero C++Builder Office XP Servers Package 104 | Microsoft Office 2000 Sample Automation Server Wrapper Components 105 | Microsoft Office XP Sample Automation Server Wrapper Components 106 | 107 | 108 | 109 | 12 110 | 111 |
112 | -------------------------------------------------------------------------------- /src-rdpconfig/RDPConf.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-rdpconfig/RDPConf.res -------------------------------------------------------------------------------- /src-rdpconfig/resource.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-rdpconfig/resource.res -------------------------------------------------------------------------------- /src-x86-binarymaster/LiteINI.pas: -------------------------------------------------------------------------------- 1 | { 2 | Copyright 2014 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | } 16 | 17 | unit LiteINI; 18 | 19 | interface 20 | 21 | uses 22 | SysUtils; 23 | 24 | type 25 | SList = Array of String; 26 | INIValue = record 27 | Name: String; 28 | Value: String; 29 | end; 30 | INISection = record 31 | Name: String; 32 | Values: Array of INIValue; 33 | end; 34 | INIFile = Array of INISection; 35 | 36 | procedure SListClear(var List: SList); 37 | function SListAppend(var List: SList; S: String): Integer; 38 | function SListFind(List: SList; Value: String): Integer; 39 | function INIFindSection(INI: INIFile; Section: String): Integer; 40 | function INIFindValue(INI: INIFile; Section: Integer; Value: String): Integer; 41 | function INIAddSection(var INI: INIFile; Section: String): Integer; 42 | function INIAddValue(var INI: INIFile; Section: Integer; ValueName, Value: String): Integer; 43 | procedure INIUnload(var INI: INIFile); 44 | procedure INILoad(var INI: INIFile; FileName: String); 45 | function INISectionExists(INI: INIFile; Section: String): Boolean; 46 | function INIValueExists(INI: INIFile; Section: String; Value: String): Boolean; 47 | function INIReadSectionLowAPI(INI: INIFile; Section: Integer; var List: SList): Boolean; 48 | function INIReadSection(INI: INIFile; Section: String): SList; 49 | function INIReadStringLowAPI(INI: INIFile; Section, Value: Integer; var Str: String): Boolean; 50 | function INIReadString(INI: INIFile; Section, Value, Default: String): String; 51 | function INIReadInt(INI: INIFile; Section, Value: String; Default: Integer): Integer; 52 | function INIReadDWord(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; 53 | function INIReadIntHex(INI: INIFile; Section, Value: String; Default: Integer): Integer; 54 | function INIReadDWordHex(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; 55 | function INIReadBool(INI: INIFile; Section, Value: String; Default: Boolean): Boolean; 56 | function INIReadBytes(INI: INIFile; Section, Value: String): TBytes; 57 | function INIReadBytesDef(INI: INIFile; Section, Value: String; Default: TBytes): TBytes; 58 | 59 | implementation 60 | 61 | procedure SListClear(var List: SList); 62 | begin 63 | SetLength(List, 0); 64 | end; 65 | 66 | function SListAppend(var List: SList; S: String): Integer; 67 | begin 68 | SetLength(List, Length(List) + 1); 69 | List[Length(List) - 1] := S; 70 | Result := Length(List) - 1; 71 | end; 72 | 73 | function SListFind(List: SList; Value: String): Integer; 74 | var 75 | I: Integer; 76 | begin 77 | Result := -1; 78 | for I := 0 to Length(List) - 1 do 79 | if List[I] = Value then begin 80 | Result := I; 81 | Break; 82 | end; 83 | end; 84 | 85 | function INIFindSection(INI: INIFile; Section: String): Integer; 86 | var 87 | I: Integer; 88 | begin 89 | Result := -1; 90 | for I := 0 to Length(INI) - 1 do 91 | if INI[I].Name = Section then begin 92 | Result := I; 93 | Exit; 94 | end; 95 | end; 96 | 97 | function INIFindValue(INI: INIFile; Section: Integer; Value: String): Integer; 98 | var 99 | I: Integer; 100 | begin 101 | Result := -1; 102 | if (Section < 0) or (Section >= Length(INI)) then 103 | Exit; 104 | for I := 0 to Length(INI[Section].Values) - 1 do 105 | if INI[Section].Values[I].Name = Value then begin 106 | Result := I; 107 | Exit; 108 | end; 109 | end; 110 | 111 | function INIAddSection(var INI: INIFile; Section: String): Integer; 112 | begin 113 | Result := INIFindSection(INI, Section); 114 | if Result >= 0 then 115 | Exit; 116 | Result := Length(INI); 117 | SetLength(INI, Result + 1); 118 | INI[Result].Name := Section; 119 | SetLength(INI[Result].Values, 0); 120 | end; 121 | 122 | function INIAddValue(var INI: INIFile; Section: Integer; ValueName, Value: String): Integer; 123 | var 124 | I: Integer; 125 | begin 126 | Result := -1; 127 | if (Section < 0) or (Section >= Length(INI)) then 128 | Exit; 129 | I := INIFindValue(INI, Section, ValueName); 130 | if I = -1 then begin 131 | Result := Length(INI[Section].Values); 132 | SetLength(INI[Section].Values, Result + 1); 133 | INI[Section].Values[Result].Name := ValueName; 134 | INI[Section].Values[Result].Value := Value; 135 | end else begin 136 | INI[Section].Values[I].Value := Value; 137 | Result := I; 138 | end; 139 | end; 140 | 141 | procedure INIUnload(var INI: INIFile); 142 | begin 143 | SetLength(INI, 0); 144 | end; 145 | 146 | procedure INILoad(var INI: INIFile; FileName: String); 147 | var 148 | F: TextFile; 149 | S, ValueName, Value: String; 150 | INIList: SList; 151 | I, Sect: Integer; 152 | begin 153 | INIUnload(INI); 154 | if not FileExists(FileName) then 155 | Exit; 156 | AssignFile(F, FileName); 157 | Reset(F); 158 | // Read and filter lines 159 | while not EOF(F) do begin 160 | Readln(F, S); 161 | if (Pos(';', S) <> 1) 162 | and (Pos('#', S) <> 1) 163 | and ( 164 | ((Pos('[', S) > 0) and (Pos(']', S) > 0)) or 165 | (Pos('=', S) > 0) 166 | ) 167 | then 168 | SListAppend(INIList, S); 169 | end; 170 | CloseFile(F); 171 | // Parse 2 (parse format) 172 | Sect := -1; 173 | for I := 0 to Length(INIList) - 1 do begin 174 | S := Trim(INIList[I]); 175 | if Length(S) >= 2 then 176 | if (S[1] = '[') and (S[Length(S)] = ']') then begin 177 | S := Trim(Copy(S, 2, Length(S) - 2)); 178 | Sect := INIAddSection(INI, S); 179 | Continue; 180 | end; 181 | S := INIList[I]; 182 | if Pos('=', S) > 0 then begin 183 | ValueName := Trim(Copy(S, 1, Pos('=', S) - 1)); 184 | Value := Copy(S, Pos('=', S) + 1, Length(S) - Pos('=', S)); 185 | if Sect = -1 then 186 | Sect := INIAddSection(INI, ''); 187 | INIAddValue(INI, Sect, ValueName, Value); 188 | end; 189 | end; 190 | end; 191 | 192 | function INISectionExists(INI: INIFile; Section: String): Boolean; 193 | begin 194 | Result := INIFindSection(INI, Section) > -1; 195 | end; 196 | 197 | function INIValueExists(INI: INIFile; Section: String; Value: String): Boolean; 198 | var 199 | Sect: Integer; 200 | begin 201 | Sect := INIFindSection(INI, Section); 202 | Result := INIFindValue(INI, Sect, Value) > -1; 203 | end; 204 | 205 | function INIReadSectionLowAPI(INI: INIFile; Section: Integer; var List: SList): Boolean; 206 | var 207 | I: Integer; 208 | begin 209 | Result := False; 210 | SetLength(List, 0); 211 | if (Section < 0) or (Section >= Length(INI)) then 212 | Exit; 213 | for I := 0 to Length(INI[Section].Values) - 1 do 214 | SListAppend(List, INI[Section].Values[I].Name); 215 | Result := True; 216 | end; 217 | 218 | function INIReadSection(INI: INIFile; Section: String): SList; 219 | var 220 | Sect: Integer; 221 | begin 222 | Sect := INIFindSection(INI, Section); 223 | INIReadSectionLowAPI(INI, Sect, Result); 224 | end; 225 | 226 | function INIReadStringLowAPI(INI: INIFile; Section, Value: Integer; var Str: String): Boolean; 227 | begin 228 | Result := False; 229 | if (Section < 0) or (Section >= Length(INI)) then 230 | Exit; 231 | if (Value < 0) or (Value >= Length(INI[Section].Values)) then 232 | Exit; 233 | Str := INI[Section].Values[Value].Value; 234 | Result := True; 235 | end; 236 | 237 | function INIReadString(INI: INIFile; Section, Value, Default: String): String; 238 | var 239 | Sect, Val: Integer; 240 | begin 241 | Sect := INIFindSection(INI, Section); 242 | Val := INIFindValue(INI, Sect, Value); 243 | if not INIReadStringLowAPI(INI, Sect, Val, Result) then 244 | Result := Default; 245 | end; 246 | 247 | function INIReadInt(INI: INIFile; Section, Value: String; Default: Integer): Integer; 248 | var 249 | S: String; 250 | E: Integer; 251 | begin 252 | S := INIReadString(INI, Section, Value, ''); 253 | Val(S, Result, E); 254 | if E <> 0 then 255 | Result := Default; 256 | end; 257 | 258 | function INIReadDWord(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; 259 | var 260 | S: String; 261 | E: Integer; 262 | begin 263 | S := INIReadString(INI, Section, Value, ''); 264 | Val(S, Result, E); 265 | if E <> 0 then 266 | Result := Default; 267 | end; 268 | 269 | function INIReadIntHex(INI: INIFile; Section, Value: String; Default: Integer): Integer; 270 | var 271 | S: String; 272 | E: Integer; 273 | begin 274 | S := INIReadString(INI, Section, Value, ''); 275 | Val('$'+S, Result, E); 276 | if E <> 0 then 277 | Result := Default; 278 | end; 279 | 280 | function INIReadDWordHex(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal; 281 | var 282 | S: String; 283 | E: Integer; 284 | begin 285 | S := INIReadString(INI, Section, Value, ''); 286 | Val('$'+S, Result, E); 287 | if E <> 0 then 288 | Result := Default; 289 | end; 290 | 291 | function INIReadBool(INI: INIFile; Section, Value: String; Default: Boolean): Boolean; 292 | var 293 | S: String; 294 | I: Cardinal; 295 | E: Integer; 296 | begin 297 | S := INIReadString(INI, Section, Value, ''); 298 | Val(S, I, E); 299 | if E <> 0 then 300 | Result := Default 301 | else 302 | Result := I > 0; 303 | end; 304 | 305 | function StringToBytes(S: String; var B: TBytes): Boolean; 306 | var 307 | I: Integer; 308 | begin 309 | Result := False; 310 | if Odd(Length(S)) then 311 | Exit; 312 | SetLength(B, Length(S) div 2); 313 | for I := 0 to Length(B) - 1 do begin 314 | B[I] := 0; 315 | case S[(I*2)+2] of 316 | '0': ; 317 | '1': B[I] := B[I] or $1; 318 | '2': B[I] := B[I] or $2; 319 | '3': B[I] := B[I] or $3; 320 | '4': B[I] := B[I] or $4; 321 | '5': B[I] := B[I] or $5; 322 | '6': B[I] := B[I] or $6; 323 | '7': B[I] := B[I] or $7; 324 | '8': B[I] := B[I] or $8; 325 | '9': B[I] := B[I] or $9; 326 | 'A','a': B[I] := B[I] or $A; 327 | 'B','b': B[I] := B[I] or $B; 328 | 'C','c': B[I] := B[I] or $C; 329 | 'D','d': B[I] := B[I] or $D; 330 | 'E','e': B[I] := B[I] or $E; 331 | 'F','f': B[I] := B[I] or $F; 332 | else Exit; 333 | end; 334 | case S[(I*2)+1] of 335 | '0': ; 336 | '1': B[I] := B[I] or $10; 337 | '2': B[I] := B[I] or $20; 338 | '3': B[I] := B[I] or $30; 339 | '4': B[I] := B[I] or $40; 340 | '5': B[I] := B[I] or $50; 341 | '6': B[I] := B[I] or $60; 342 | '7': B[I] := B[I] or $70; 343 | '8': B[I] := B[I] or $80; 344 | '9': B[I] := B[I] or $90; 345 | 'A','a': B[I] := B[I] or $A0; 346 | 'B','b': B[I] := B[I] or $B0; 347 | 'C','c': B[I] := B[I] or $C0; 348 | 'D','d': B[I] := B[I] or $D0; 349 | 'E','e': B[I] := B[I] or $E0; 350 | 'F','f': B[I] := B[I] or $F0; 351 | else Exit; 352 | end; 353 | end; 354 | Result := True; 355 | end; 356 | 357 | function INIReadBytes(INI: INIFile; Section, Value: String): TBytes; 358 | var 359 | S: String; 360 | begin 361 | S := INIReadString(INI, Section, Value, ''); 362 | if not StringToBytes(S, Result) then 363 | SetLength(Result, 0); 364 | end; 365 | 366 | function INIReadBytesDef(INI: INIFile; Section, Value: String; Default: TBytes): TBytes; 367 | var 368 | S: String; 369 | begin 370 | S := INIReadString(INI, Section, Value, ''); 371 | if not StringToBytes(S, Result) then 372 | Result := Default; 373 | end; 374 | 375 | end. 376 | -------------------------------------------------------------------------------- /src-x86-binarymaster/rdpwrap.dpr: -------------------------------------------------------------------------------- 1 | { 2 | Copyright 2014 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | } 16 | 17 | library rdpwrap; 18 | 19 | uses 20 | SysUtils, 21 | Windows, 22 | TlHelp32, 23 | LiteINI; 24 | 25 | {$R rdpwrap.res} 26 | 27 | // Hook core definitions 28 | 29 | type 30 | OldCode = packed record 31 | One: DWORD; 32 | two: Word; 33 | end; 34 | 35 | far_jmp = packed record 36 | PushOp: Byte; 37 | PushArg: Pointer; 38 | RetOp: Byte; 39 | end; 40 | 41 | mov_far_jmp = packed record 42 | MovOp: Byte; 43 | MovArg: Byte; 44 | PushOp: Byte; 45 | PushArg: Pointer; 46 | RetOp: Byte; 47 | end; 48 | 49 | TTHREADENTRY32 = packed record 50 | dwSize: DWORD; 51 | cntUsage: DWORD; 52 | th32ThreadID: DWORD; 53 | th32OwnerProcessID: DWORD; 54 | tpBasePri: LongInt; 55 | tpDeltaPri: LongInt; 56 | dwFlags: DWORD; 57 | end; 58 | //IntArray = Array of Integer; 59 | FILE_VERSION = record 60 | Version: record case Boolean of 61 | True: (dw: DWORD); 62 | False: (w: record 63 | Minor, Major: Word; 64 | end;) 65 | end; 66 | Release, Build: Word; 67 | bDebug, bPrerelease, bPrivate, bSpecial: Boolean; 68 | end; 69 | 70 | const 71 | THREAD_SUSPEND_RESUME = 2; 72 | TH32CS_SNAPTHREAD = 4; 73 | var 74 | INI: INIFile; 75 | LogFile: String = '\rdpwrap.txt'; 76 | bw: {$if CompilerVersion>=16} NativeUInt {$else} DWORD {$endif}; 77 | IsHooked: Boolean = False; 78 | 79 | // Unhooked import 80 | 81 | function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; 82 | dwThreadId: DWORD): DWORD; stdcall; external kernel32; 83 | 84 | function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): DWORD; 85 | stdcall; external kernel32; 86 | 87 | function Thread32First(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool; 88 | stdcall; external kernel32; 89 | 90 | function Thread32Next(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool; 91 | stdcall; external kernel32; 92 | 93 | // Wrapped import 94 | 95 | var 96 | TSMain: function(dwArgc: DWORD; lpszArgv: PWideChar): DWORD; stdcall; 97 | TSGlobals: function(lpGlobalData: Pointer): DWORD; stdcall; 98 | 99 | // Hooked import and vars 100 | 101 | var 102 | SLGetWindowsInformationDWORD: function(pwszValueName: PWideChar; 103 | pdwValue: PDWORD): HRESULT; stdcall; 104 | TermSrvBase: Pointer; 105 | FV: FILE_VERSION; 106 | 107 | var 108 | Stub_SLGetWindowsInformationDWORD: far_jmp; 109 | Old_SLGetWindowsInformationDWORD: OldCode; 110 | 111 | // Main code 112 | 113 | procedure WriteLog(S: AnsiString); 114 | var 115 | F: TextFile; 116 | begin 117 | if not FileExists(LogFile) then 118 | Exit; 119 | AssignFile(F, LogFile); 120 | Append(F); 121 | Write(F, S+#13#10); 122 | CloseFile(F); 123 | end; 124 | 125 | function GetModuleHandleEx(dwFlags: DWORD; lpModuleName: PWideChar; 126 | var phModule: HMODULE): BOOL; stdcall; external kernel32 name 'GetModuleHandleExW'; 127 | 128 | function GetCurrentModule: HMODULE; 129 | const 130 | GET_MODULE_HANDLE_EX_FLAG_PIN = 1; 131 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2; 132 | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 4; 133 | begin 134 | Result := 0; 135 | GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, @GetCurrentModule, Result); 136 | end; 137 | 138 | function GetBinaryPath: String; 139 | var 140 | Buf: Array[0..511] of Byte; 141 | begin 142 | ZeroMemory(@Buf[0], Length(Buf)); 143 | GetModuleFileName(GetCurrentModule, PWideChar(@Buf[0]), Length(Buf)); 144 | Result := PWideChar(@Buf[0]); 145 | end; 146 | 147 | procedure StopThreads; 148 | var 149 | h, CurrTh, ThrHandle, CurrPr: DWORD; 150 | Thread: TTHREADENTRY32; 151 | begin 152 | CurrTh := GetCurrentThreadId; 153 | CurrPr := GetCurrentProcessId; 154 | h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 155 | if h <> INVALID_HANDLE_VALUE then 156 | begin 157 | Thread.dwSize := SizeOf(TTHREADENTRY32); 158 | if Thread32First(h, Thread) then 159 | repeat 160 | if (Thread.th32ThreadID <> CurrTh) and 161 | (Thread.th32OwnerProcessID = CurrPr) then 162 | begin 163 | ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false, 164 | Thread.th32ThreadID); 165 | if ThrHandle > 0 then 166 | begin 167 | SuspendThread(ThrHandle); 168 | CloseHandle(ThrHandle); 169 | end; 170 | end; 171 | until not Thread32Next(h, Thread); 172 | CloseHandle(h); 173 | end; 174 | end; 175 | 176 | procedure RunThreads; 177 | var 178 | h, CurrTh, ThrHandle, CurrPr: DWORD; 179 | Thread: TTHREADENTRY32; 180 | begin 181 | CurrTh := GetCurrentThreadId; 182 | CurrPr := GetCurrentProcessId; 183 | h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 184 | if h <> INVALID_HANDLE_VALUE then 185 | begin 186 | Thread.dwSize := SizeOf(TTHREADENTRY32); 187 | if Thread32First(h, Thread) then 188 | repeat 189 | if (Thread.th32ThreadID <> CurrTh) and 190 | (Thread.th32OwnerProcessID = CurrPr) then 191 | begin 192 | ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false, 193 | Thread.th32ThreadID); 194 | if ThrHandle > 0 then 195 | begin 196 | ResumeThread(ThrHandle); 197 | CloseHandle(ThrHandle); 198 | end; 199 | end; 200 | until not Thread32Next(h, Thread); 201 | CloseHandle(h); 202 | end; 203 | end; 204 | 205 | function GetModuleAddress(ModuleName: String; ProcessId: DWORD; var BaseAddr: Pointer; var BaseSize: DWORD): Boolean; 206 | var 207 | hSnap: THandle; 208 | md: MODULEENTRY32; 209 | begin 210 | Result := False; 211 | hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId); 212 | if hSnap = INVALID_HANDLE_VALUE Then 213 | Exit; 214 | md.dwSize := SizeOf(MODULEENTRY32); 215 | if Module32First(hSnap, md) then 216 | begin 217 | if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then 218 | begin 219 | Result := True; 220 | BaseAddr := Pointer(md.modBaseAddr); 221 | BaseSize := md.modBaseSize; 222 | CloseHandle(hSnap); 223 | Exit; 224 | end; 225 | while Module32Next(hSnap, md) Do 226 | begin 227 | if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then 228 | begin 229 | Result := True; 230 | BaseAddr := Pointer(md.modBaseAddr); 231 | BaseSize := md.modBaseSize; 232 | Break; 233 | end; 234 | end; 235 | end; 236 | CloseHandle(hSnap); 237 | end; 238 | 239 | {procedure FindMem(Mem: Pointer; MemSz: DWORD; Buf: Pointer; BufSz: DWORD; 240 | From: DWORD; var A: IntArray); 241 | var 242 | I: Integer; 243 | begin 244 | SetLength(A, 0); 245 | I:=From; 246 | if From>0 then 247 | Inc(PByte(Mem), From); 248 | while I < MemSz - BufSz + 1 do 249 | begin 250 | if (not IsBadReadPtr(Mem, BufSz)) and (CompareMem(Mem, Buf, BufSz)) then 251 | begin 252 | SetLength(A, Length(A)+1); 253 | A[Length(A)-1] := I; 254 | end; 255 | Inc(I); 256 | Inc(PByte(Mem)); 257 | end; 258 | end;} 259 | 260 | function GetModuleVersion(const ModuleName: String; var FileVersion: FILE_VERSION): Boolean; 261 | type 262 | VS_VERSIONINFO = record 263 | wLength, wValueLength, wType: Word; 264 | szKey: Array[1..16] of WideChar; 265 | Padding1: Word; 266 | Value: VS_FIXEDFILEINFO; 267 | Padding2, Children: Word; 268 | end; 269 | PVS_VERSIONINFO = ^VS_VERSIONINFO; 270 | const 271 | VFF_DEBUG = 1; 272 | VFF_PRERELEASE = 2; 273 | VFF_PRIVATE = 8; 274 | VFF_SPECIAL = 32; 275 | var 276 | hMod: HMODULE; 277 | hResourceInfo: HRSRC; 278 | VersionInfo: PVS_VERSIONINFO; 279 | begin 280 | Result := False; 281 | 282 | if ModuleName = '' then 283 | hMod := GetModuleHandle(nil) 284 | else 285 | hMod := GetModuleHandle(PWideChar(ModuleName)); 286 | if hMod = 0 then 287 | Exit; 288 | 289 | hResourceInfo := FindResource(hMod, PWideChar(1), PWideChar($10)); 290 | if hResourceInfo = 0 then 291 | Exit; 292 | 293 | VersionInfo := Pointer(LoadResource(hMod, hResourceInfo)); 294 | if VersionInfo = nil then 295 | Exit; 296 | 297 | FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS; 298 | FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16); 299 | FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS); 300 | FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG; 301 | FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE; 302 | FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE; 303 | FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL; 304 | 305 | Result := True; 306 | end; 307 | 308 | function GetFileVersion(const FileName: String; var FileVersion: FILE_VERSION): Boolean; 309 | type 310 | VS_VERSIONINFO = record 311 | wLength, wValueLength, wType: Word; 312 | szKey: Array[1..16] of WideChar; 313 | Padding1: Word; 314 | Value: VS_FIXEDFILEINFO; 315 | Padding2, Children: Word; 316 | end; 317 | PVS_VERSIONINFO = ^VS_VERSIONINFO; 318 | const 319 | VFF_DEBUG = 1; 320 | VFF_PRERELEASE = 2; 321 | VFF_PRIVATE = 8; 322 | VFF_SPECIAL = 32; 323 | var 324 | hFile: HMODULE; 325 | hResourceInfo: HRSRC; 326 | VersionInfo: PVS_VERSIONINFO; 327 | begin 328 | Result := False; 329 | 330 | hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE); 331 | if hFile = 0 then 332 | Exit; 333 | 334 | hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10)); 335 | if hResourceInfo = 0 then 336 | Exit; 337 | 338 | VersionInfo := Pointer(LoadResource(hFile, hResourceInfo)); 339 | if VersionInfo = nil then 340 | Exit; 341 | 342 | FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS; 343 | FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16); 344 | FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS); 345 | FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG; 346 | FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE; 347 | FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE; 348 | FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL; 349 | 350 | Result := True; 351 | end; 352 | 353 | function OverrideSL(ValueName: String; var Value: DWORD): Boolean; 354 | begin 355 | Result := True; 356 | if INIValueExists(INI, 'SLPolicy', ValueName) then begin 357 | Value := INIReadDWord(INI, 'SLPolicy', ValueName, 0); 358 | Exit; 359 | end; 360 | Result := False; 361 | end; 362 | 363 | function New_SLGetWindowsInformationDWORD(pwszValueName: PWideChar; 364 | pdwValue: PDWORD): HRESULT; stdcall; 365 | var 366 | dw: DWORD; 367 | begin 368 | // wrapped SLGetWindowsInformationDWORD function 369 | // termsrv.dll will call this function instead of original SLC.dll 370 | 371 | // Override SL Policy 372 | 373 | WriteLog('Policy query: ' + pwszValueName); 374 | if OverrideSL(pwszValueName, dw) then begin 375 | pdwValue^ := dw; 376 | Result := S_OK; 377 | WriteLog('Policy rewrite: ' + IntToStr(pdwValue^)); 378 | Exit; 379 | end; 380 | 381 | // If the requested value name is not defined above 382 | 383 | // revert to original SL Policy function 384 | WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, 385 | @Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw); 386 | 387 | // get result 388 | Result := SLGetWindowsInformationDWORD(pwszValueName, pdwValue); 389 | if Result = S_OK then 390 | WriteLog('Policy result: ' + IntToStr(pdwValue^)) 391 | else 392 | WriteLog('Policy request failed'); 393 | // wrap it back 394 | WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, 395 | @Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw); 396 | end; 397 | 398 | function New_Win8SL(pwszValueName: PWideChar; pdwValue: PDWORD): HRESULT; register; 399 | var 400 | dw: DWORD; 401 | begin 402 | // wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll 403 | // for Windows 8 support 404 | 405 | // Override SL Policy 406 | 407 | WriteLog('Policy query: ' + pwszValueName); 408 | if OverrideSL(pwszValueName, dw) then begin 409 | pdwValue^ := dw; 410 | Result := S_OK; 411 | WriteLog('Policy rewrite: ' + IntToStr(pdwValue^)); 412 | Exit; 413 | end; 414 | 415 | // If the requested value name is not defined above 416 | // use function from SLC.dll 417 | 418 | Result := SLGetWindowsInformationDWORD(pwszValueName, pdwValue); 419 | if Result = S_OK then 420 | WriteLog('Policy result: ' + IntToStr(pdwValue^)) 421 | else 422 | WriteLog('Policy request failed'); 423 | end; 424 | 425 | function New_Win8SL_CP(eax: DWORD; pdwValue: PDWORD; ecx: DWORD; pwszValueName: PWideChar): HRESULT; register; 426 | begin 427 | // wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll 428 | // for Windows 8 Consumer Preview support 429 | 430 | Result := New_Win8SL(pwszValueName, pdwValue); 431 | end; 432 | 433 | function New_CSLQuery_Initialize: HRESULT; stdcall; 434 | var 435 | Sect: String; 436 | bServerSku, 437 | bRemoteConnAllowed, 438 | bFUSEnabled, 439 | bAppServerAllowed, 440 | bMultimonAllowed, 441 | lMaxUserSessions, 442 | ulMaxDebugSessions, 443 | bInitialized: PDWORD; 444 | begin 445 | bServerSku := nil; 446 | bRemoteConnAllowed := nil; 447 | bFUSEnabled := nil; 448 | bAppServerAllowed := nil; 449 | bMultimonAllowed := nil; 450 | lMaxUserSessions := nil; 451 | ulMaxDebugSessions := nil; 452 | bInitialized := nil; 453 | WriteLog('>>> CSLQuery::Initialize'); 454 | Sect := IntToStr(FV.Version.w.Major)+'.'+IntToStr(FV.Version.w.Minor)+'.'+ 455 | IntToStr(FV.Release)+'.'+IntToStr(FV.Build)+'-SLInit'; 456 | if INISectionExists(INI, Sect) then begin 457 | bServerSku := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bServerSku.x86', 0)); 458 | bRemoteConnAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bRemoteConnAllowed.x86', 0)); 459 | bFUSEnabled := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bFUSEnabled.x86', 0)); 460 | bAppServerAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bAppServerAllowed.x86', 0)); 461 | bMultimonAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bMultimonAllowed.x86', 0)); 462 | lMaxUserSessions := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'lMaxUserSessions.x86', 0)); 463 | ulMaxDebugSessions := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'ulMaxDebugSessions.x86', 0)); 464 | bInitialized := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bInitialized.x86', 0)); 465 | end; 466 | 467 | if bServerSku <> nil then begin 468 | bServerSku^ := INIReadDWord(INI, 'SLInit', 'bServerSku', 1); 469 | WriteLog('SLInit [0x'+IntToHex(DWORD(bServerSku), 1)+'] bServerSku = ' + IntToStr(bServerSku^)); 470 | end; 471 | if bRemoteConnAllowed <> nil then begin 472 | bRemoteConnAllowed^ := INIReadDWord(INI, 'SLInit', 'bRemoteConnAllowed', 1); 473 | WriteLog('SLInit [0x'+IntToHex(DWORD(bRemoteConnAllowed), 1)+'] bRemoteConnAllowed = ' + IntToStr(bRemoteConnAllowed^)); 474 | end; 475 | if bFUSEnabled <> nil then begin 476 | bFUSEnabled^ := INIReadDWord(INI, 'SLInit', 'bFUSEnabled', 1); 477 | WriteLog('SLInit [0x'+IntToHex(DWORD(bFUSEnabled), 1)+'] bFUSEnabled = ' + IntToStr(bFUSEnabled^)); 478 | end; 479 | if bAppServerAllowed <> nil then begin 480 | bAppServerAllowed^ := INIReadDWord(INI, 'SLInit', 'bAppServerAllowed', 1); 481 | WriteLog('SLInit [0x'+IntToHex(DWORD(bAppServerAllowed), 1)+'] bAppServerAllowed = ' + IntToStr(bAppServerAllowed^)); 482 | end; 483 | if bMultimonAllowed <> nil then begin 484 | bMultimonAllowed^ := INIReadDWord(INI, 'SLInit', 'bMultimonAllowed', 1); 485 | WriteLog('SLInit [0x'+IntToHex(DWORD(bMultimonAllowed), 1)+'] bMultimonAllowed = ' + IntToStr(bMultimonAllowed^)); 486 | end; 487 | if lMaxUserSessions <> nil then begin 488 | lMaxUserSessions^ := INIReadDWord(INI, 'SLInit', 'lMaxUserSessions', 0); 489 | WriteLog('SLInit [0x'+IntToHex(DWORD(lMaxUserSessions), 1)+'] lMaxUserSessions = ' + IntToStr(lMaxUserSessions^)); 490 | end; 491 | if ulMaxDebugSessions <> nil then begin 492 | ulMaxDebugSessions^ := INIReadDWord(INI, 'SLInit', 'ulMaxDebugSessions', 0); 493 | WriteLog('SLInit [0x'+IntToHex(DWORD(ulMaxDebugSessions), 1)+'] ulMaxDebugSessions = ' + IntToStr(ulMaxDebugSessions^)); 494 | end; 495 | if bInitialized <> nil then begin 496 | bInitialized^ := INIReadDWord(INI, 'SLInit', 'bInitialized', 1); 497 | WriteLog('SLInit [0x'+IntToHex(DWORD(bInitialized), 1)+'] bInitialized = ' + IntToStr(bInitialized^)); 498 | end; 499 | Result := S_OK; 500 | WriteLog('<<< CSLQuery::Initialize'); 501 | end; 502 | 503 | procedure HookFunctions; 504 | var 505 | ConfigFile, Sect, FuncName: String; 506 | V: DWORD; 507 | TS_Handle, SLC_Handle: THandle; 508 | TermSrvSize: DWORD; 509 | SignPtr: Pointer; 510 | I: Integer; 511 | PatchList: SList; 512 | Patch: Array of TBytes; 513 | Jump: far_jmp; 514 | MovJump: mov_far_jmp; 515 | begin 516 | { hook function ^^ 517 | (called once) } 518 | IsHooked := True; 519 | TSMain := nil; 520 | TSGlobals := nil; 521 | SLGetWindowsInformationDWORD := nil; 522 | 523 | WriteLog('Loading configuration...'); 524 | ConfigFile := ExtractFilePath(GetBinaryPath) + 'rdpwrap.ini'; 525 | WriteLog('Configuration file: ' + ConfigFile); 526 | INILoad(INI, ConfigFile); 527 | if Length(INI) = 0 then begin 528 | WriteLog('Error: Failed to load configuration'); 529 | Exit; 530 | end; 531 | 532 | LogFile := INIReadString(INI, 'Main', 'LogFile', ExtractFilePath(GetBinaryPath) + 'rdpwrap.txt'); 533 | WriteLog('Initializing RDP Wrapper...'); 534 | 535 | // load termsrv.dll and get functions 536 | TS_Handle := LoadLibrary('termsrv.dll'); 537 | if TS_Handle = 0 then begin 538 | WriteLog('Error: Failed to load Terminal Services library'); 539 | Exit; 540 | end; 541 | TSMain := GetProcAddress(TS_Handle, 'ServiceMain'); 542 | TSGlobals := GetProcAddress(TS_Handle, 'SvchostPushServiceGlobals'); 543 | WriteLog( 544 | 'Base addr: 0x' + IntToHex(TS_Handle, 8) + #13#10 + 545 | 'SvcMain: termsrv.dll+0x' + IntToHex(Cardinal(@TSMain) - TS_Handle, 1) + #13#10 + 546 | 'SvcGlobals: termsrv.dll+0x' + IntToHex(Cardinal(@TSGlobals) - TS_Handle, 1) 547 | ); 548 | 549 | V := 0; 550 | // check termsrv version 551 | if GetModuleVersion('termsrv.dll', FV) then 552 | V := Byte(FV.Version.w.Minor) or (Byte(FV.Version.w.Major) shl 8) 553 | else begin 554 | // check NT version 555 | // V := GetVersion; // deprecated 556 | // V := ((V and $FF) shl 8) or ((V and $FF00) shr 8); 557 | end; 558 | if V = 0 then begin 559 | WriteLog('Error: Failed to detect Terminal Services version'); 560 | Exit; 561 | end; 562 | 563 | WriteLog('Version: '+ 564 | IntToStr(FV.Version.w.Major)+'.'+ 565 | IntToStr(FV.Version.w.Minor)+'.'+ 566 | IntToStr(FV.Release)+'.'+ 567 | IntToStr(FV.Build)); 568 | 569 | // temporarily freeze threads 570 | WriteLog('Freezing threads...'); 571 | StopThreads(); 572 | 573 | WriteLog('Caching patch codes...'); 574 | PatchList := INIReadSection(INI, 'PatchCodes'); 575 | SetLength(Patch, Length(PatchList)); 576 | for I := 0 to Length(Patch) - 1 do begin 577 | Patch[I] := INIReadBytes(INI, 'PatchCodes', PatchList[I]); 578 | if Length(Patch[I]) > 16 then // for security reasons 579 | SetLength(Patch[I], 16); // not more than 16 bytes 580 | end; 581 | 582 | if (V = $0600) and (INIReadBool(INI, 'Main', 'SLPolicyHookNT60', True)) then begin 583 | // Windows Vista 584 | // uses SL Policy API (slc.dll) 585 | 586 | // load slc.dll and hook function 587 | SLC_Handle := LoadLibrary('slc.dll'); 588 | SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD'); 589 | 590 | if @SLGetWindowsInformationDWORD <> nil then 591 | begin 592 | // rewrite original function to call our function (make hook) 593 | 594 | WriteLog('Hook SLGetWindowsInformationDWORD'); 595 | Stub_SLGetWindowsInformationDWORD.PushOp := $68; 596 | Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD; 597 | Stub_SLGetWindowsInformationDWORD.RetOp := $C3; 598 | ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, 599 | @Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw); 600 | WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, 601 | @Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw); 602 | end; 603 | end; 604 | if (V = $0601) and (INIReadBool(INI, 'Main', 'SLPolicyHookNT61', True)) then begin 605 | // Windows 7 606 | // uses SL Policy API (slc.dll) 607 | 608 | // load slc.dll and hook function 609 | SLC_Handle := LoadLibrary('slc.dll'); 610 | SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD'); 611 | 612 | if @SLGetWindowsInformationDWORD <> nil then 613 | begin 614 | // rewrite original function to call our function (make hook) 615 | 616 | WriteLog('Hook SLGetWindowsInformationDWORD'); 617 | Stub_SLGetWindowsInformationDWORD.PushOp := $68; 618 | Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD; 619 | Stub_SLGetWindowsInformationDWORD.RetOp := $C3; 620 | ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, 621 | @Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw); 622 | WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD, 623 | @Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw); 624 | end; 625 | end; 626 | if V = $0602 then begin 627 | // Windows 8 628 | // uses SL Policy internal unexported function 629 | 630 | // load slc.dll and get function 631 | // (will be used on intercepting undefined values) 632 | SLC_Handle := LoadLibrary('slc.dll'); 633 | SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD'); 634 | end; 635 | if V = $0603 then begin 636 | // Windows 8.1 637 | // uses SL Policy internal inline code 638 | end; 639 | if V = $0604 then begin 640 | // Windows 10 641 | // uses SL Policy internal inline code 642 | end; 643 | 644 | Sect := IntToStr(FV.Version.w.Major)+'.'+IntToStr(FV.Version.w.Minor)+'.'+ 645 | IntToStr(FV.Release)+'.'+IntToStr(FV.Build); 646 | 647 | if INISectionExists(INI, Sect) then 648 | if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin 649 | if INIReadBool(INI, Sect, 'LocalOnlyPatch.x86', False) then begin 650 | WriteLog('Patch CEnforcementCore::GetInstanceOfTSLicense'); 651 | SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'LocalOnlyOffset.x86', 0)); 652 | I := SListFind(PatchList, INIReadString(INI, Sect, 'LocalOnlyCode.x86', '')); 653 | if I >= 0 then 654 | WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw); 655 | end; 656 | if INIReadBool(INI, Sect, 'SingleUserPatch.x86', False) then begin 657 | WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled'); 658 | SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SingleUserOffset.x86', 0)); 659 | I := SListFind(PatchList, INIReadString(INI, Sect, 'SingleUserCode.x86', '')); 660 | if I >= 0 then 661 | WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw); 662 | end; 663 | if INIReadBool(INI, Sect, 'DefPolicyPatch.x86', False) then begin 664 | WriteLog('Patch CDefPolicy::Query'); 665 | SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'DefPolicyOffset.x86', 0)); 666 | I := SListFind(PatchList, INIReadString(INI, Sect, 'DefPolicyCode.x86', '')); 667 | if I >= 0 then 668 | WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw); 669 | end; 670 | if INIReadBool(INI, Sect, 'SLPolicyInternal.x86', False) then begin 671 | WriteLog('Hook SLGetWindowsInformationDWORDWrapper'); 672 | SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SLPolicyOffset.x86', 0)); 673 | MovJump.MovOp := $89; // mov eax, ecx 674 | MovJump.MovArg := $C8; // __msfastcall compatibility 675 | MovJump.PushOp := $68; 676 | MovJump.PushArg := @New_Win8SL; 677 | MovJump.RetOp := $C3; 678 | FuncName := INIReadString(INI, Sect, 'SLPolicyFunc.x86', 'New_Win8SL'); 679 | if FuncName = 'New_Win8SL' then 680 | MovJump.PushArg := @New_Win8SL; 681 | if FuncName = 'New_Win8SL_CP' then 682 | MovJump.PushArg := @New_Win8SL_CP; 683 | WriteProcessMemory(GetCurrentProcess, SignPtr, 684 | @MovJump, SizeOf(mov_far_jmp), bw); 685 | end; 686 | if INIReadBool(INI, Sect, 'SLInitHook.x86', False) then begin 687 | WriteLog('Hook CSLQuery::Initialize'); 688 | SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SLInitOffset.x86', 0)); 689 | Jump.PushOp := $68; 690 | Jump.PushArg := @New_CSLQuery_Initialize; 691 | Jump.RetOp := $C3; 692 | FuncName := INIReadString(INI, Sect, 'SLInitFunc.x86', 'New_CSLQuery_Initialize'); 693 | if FuncName = 'New_CSLQuery_Initialize' then 694 | Jump.PushArg := @New_CSLQuery_Initialize; 695 | WriteProcessMemory(GetCurrentProcess, SignPtr, 696 | @Jump, SizeOf(far_jmp), bw); 697 | end; 698 | end; 699 | 700 | // unfreeze threads 701 | WriteLog('Resumimg threads...'); 702 | RunThreads(); 703 | end; 704 | 705 | function TermServiceMain(dwArgc: DWORD; lpszArgv: PWideChar): DWORD; stdcall; 706 | begin 707 | // wrap ServiceMain function 708 | WriteLog('>>> ServiceMain'); 709 | if not IsHooked then 710 | HookFunctions; 711 | Result := 0; 712 | if @TSMain <> nil then 713 | Result := TSMain(dwArgc, lpszArgv); 714 | WriteLog('<<< ServiceMain'); 715 | end; 716 | 717 | function TermServiceGlobals(lpGlobalData: Pointer): DWORD; stdcall; 718 | begin 719 | // wrap SvchostPushServiceGlobals function 720 | WriteLog('>>> SvchostPushServiceGlobals'); 721 | if not IsHooked then 722 | HookFunctions; 723 | Result := 0; 724 | if @TSGlobals <> nil then 725 | Result := TSGlobals(lpGlobalData); 726 | WriteLog('<<< SvchostPushServiceGlobals'); 727 | end; 728 | 729 | // export section 730 | 731 | exports 732 | TermServiceMain index 1 name 'ServiceMain', 733 | TermServiceGlobals index 2 name 'SvchostPushServiceGlobals'; 734 | 735 | begin 736 | // DllMain procedure is not used 737 | end. -------------------------------------------------------------------------------- /src-x86-binarymaster/rdpwrap.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {D6811241-D595-4809-B3B8-13BECEA56E11} 4 | rdpwrap.dpr 5 | Release 6 | DCC32 7 | 12.0 8 | 9 | 10 | true 11 | 12 | 13 | true 14 | Base 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | rdpwrap.dll 24 | WinTypes=Windows;WinProcs=Windows;$(DCC_UnitAlias) 25 | true 26 | 00400000 27 | x86 28 | 29 | 30 | false 31 | RELEASE;$(DCC_Define) 32 | 0 33 | false 34 | 35 | 36 | DEBUG;$(DCC_Define) 37 | 38 | 39 | 40 | MainSource 41 | 42 | 43 | Base 44 | 45 | 46 | Cfg_1 47 | Base 48 | 49 | 50 | Cfg_2 51 | Base 52 | 53 | 54 | 55 | 56 | Delphi.Personality.12 57 | VCLApplication 58 | 59 | 60 | 61 | rdpwrap.dpr 62 | 63 | 64 | False 65 | True 66 | False 67 | 68 | 69 | False 70 | False 71 | 1 72 | 0 73 | 0 74 | 0 75 | False 76 | False 77 | False 78 | False 79 | False 80 | 1049 81 | 1251 82 | 83 | 84 | 85 | 86 | 1.0.0.0 87 | 88 | 89 | 90 | 91 | 92 | 1.0.0.0 93 | 94 | 95 | 96 | Embarcadero C++Builder Office 2000 Servers Package 97 | Embarcadero C++Builder Office XP Servers Package 98 | Microsoft Office 2000 Sample Automation Server Wrapper Components 99 | Microsoft Office XP Sample Automation Server Wrapper Components 100 | 101 | 102 | 103 | 12 104 | 105 | 106 | -------------------------------------------------------------------------------- /src-x86-binarymaster/rdpwrap.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-x86-binarymaster/rdpwrap.res -------------------------------------------------------------------------------- /src-x86-x64-Fusix/Export.def: -------------------------------------------------------------------------------- 1 | LIBRARY BTREE 2 | EXPORTS 3 | ServiceMain 4 | SvchostPushServiceGlobals -------------------------------------------------------------------------------- /src-x86-x64-Fusix/IniFile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include "stdafx.h" 18 | #include 19 | #include 20 | #include "IniFile.h" 21 | 22 | INI_FILE::INI_FILE(wchar_t *FilePath) 23 | { 24 | DWORD Status = 0; 25 | DWORD NumberOfBytesRead = 0; 26 | 27 | HANDLE hFile = CreateFile(FilePath, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, 28 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 29 | 30 | if (hFile == INVALID_HANDLE_VALUE) 31 | { 32 | return; 33 | } 34 | 35 | FileSize = GetFileSize(hFile, NULL); 36 | if (FileSize == INVALID_FILE_SIZE) 37 | { 38 | return; 39 | } 40 | 41 | FileRaw = new char[FileSize]; 42 | Status = ReadFile(hFile, FileRaw, FileSize, &NumberOfBytesRead, NULL); 43 | if (!Status) 44 | { 45 | return; 46 | } 47 | 48 | CreateStringsMap(); 49 | Parse(); 50 | } 51 | 52 | 53 | INI_FILE::~INI_FILE() 54 | { 55 | for (DWORD i = 0; i < IniData.SectionCount; i++) 56 | { 57 | delete[] IniData.Section[i].Variables; 58 | } 59 | delete[] IniData.Section; 60 | delete[] FileStringsMap; 61 | delete FileRaw; 62 | } 63 | 64 | bool INI_FILE::CreateStringsMap() 65 | { 66 | DWORD StringsCount = 1; 67 | 68 | for (DWORD i = 0; i < FileSize; i++) 69 | { 70 | if (FileRaw[i] == '\r' && FileRaw[i + 1] == '\n') StringsCount++; 71 | } 72 | 73 | FileStringsCount = StringsCount; 74 | 75 | FileStringsMap = new DWORD[StringsCount]; 76 | FileStringsMap[0] = 0; 77 | 78 | StringsCount = 1; 79 | 80 | for (DWORD i = 0; i < FileSize; i++) 81 | { 82 | if (FileRaw[i] == '\r' && FileRaw[i + 1] == '\n') 83 | { 84 | FileStringsMap[StringsCount] = i + 2; 85 | StringsCount++; 86 | } 87 | } 88 | 89 | return true; 90 | } 91 | 92 | int INI_FILE::StrTrim(char* Str) 93 | { 94 | int i = 0, j; 95 | while ((Str[i] == ' ') || (Str[i] == '\t')) 96 | { 97 | i++; 98 | } 99 | if (i>0) 100 | { 101 | for (j = 0; j < strlen(Str); j++) 102 | { 103 | Str[j] = Str[j + i]; 104 | } 105 | Str[j] = '\0'; 106 | } 107 | 108 | i = strlen(Str) - 1; 109 | while ((Str[i] == ' ') || (Str[i] == '\t')) 110 | { 111 | i--; 112 | } 113 | if (i < (strlen(Str) - 1)) 114 | { 115 | Str[i + 1] = '\0'; 116 | } 117 | return 0; 118 | } 119 | 120 | DWORD INI_FILE::GetFileStringFromNum(DWORD StringNumber, char *RetString, DWORD Size) 121 | { 122 | DWORD CurrentStringNum = 0; 123 | DWORD EndStringPos = 0; 124 | DWORD StringSize = 0; 125 | 126 | if (StringNumber > FileStringsCount) return 0; 127 | 128 | for (DWORD i = FileStringsMap[StringNumber]; i < FileSize; i++) 129 | { 130 | if (i == (FileSize - 1)) 131 | { 132 | EndStringPos = FileSize; 133 | break; 134 | } 135 | if (FileRaw[i] == '\r' && FileRaw[i + 1] == '\n') 136 | { 137 | EndStringPos = i; 138 | break; 139 | } 140 | } 141 | 142 | StringSize = EndStringPos - FileStringsMap[StringNumber]; 143 | 144 | if (Size < StringSize) return 0; 145 | 146 | memset(RetString, 0x00, Size); 147 | memcpy(RetString, &(FileRaw[FileStringsMap[StringNumber]]), StringSize); 148 | return StringSize; 149 | } 150 | 151 | bool INI_FILE::IsVariable(char *Str, DWORD StrSize) 152 | { 153 | bool Quotes = false; 154 | 155 | for (DWORD i = 0; i < StrSize; i++) 156 | { 157 | if (Str[i] == '"' || Str[i] == '\'') Quotes = !Quotes; 158 | if (Str[i] == '=' && !Quotes) return true; 159 | } 160 | return false; 161 | } 162 | 163 | bool INI_FILE::FillVariable(INI_SECTION_VARIABLE *Variable, char *Str, DWORD StrSize) 164 | { 165 | bool Quotes = false; 166 | 167 | for (DWORD i = 0; i < StrSize; i++) 168 | { 169 | if (Str[i] == '"' || Str[i] == '\'') Quotes = !Quotes; 170 | if (Str[i] == '=' && !Quotes) 171 | { 172 | memset(Variable->VariableName, 0, MAX_STRING_LEN); 173 | memset(Variable->VariableValue, 0, MAX_STRING_LEN); 174 | memcpy(Variable->VariableName, Str, i); 175 | memcpy(Variable->VariableValue, &(Str[i + 1]), StrSize - (i - 1)); 176 | StrTrim(Variable->VariableName); 177 | StrTrim(Variable->VariableValue); 178 | break; 179 | } 180 | } 181 | return true; 182 | } 183 | 184 | bool INI_FILE::Parse() 185 | { 186 | DWORD CurrentStringNum = 0; 187 | char CurrentString[512]; 188 | DWORD CurrentStringSize = 0; 189 | 190 | DWORD SectionsCount = 0; 191 | DWORD VariablesCount = 0; 192 | 193 | DWORD CurrentSectionNum = -1; 194 | DWORD CurrentVariableNum = -1; 195 | 196 | // Calculate sections count 197 | for (DWORD CurrentStringNum = 0; CurrentStringNum < FileStringsCount; CurrentStringNum++) 198 | { 199 | CurrentStringSize = GetFileStringFromNum(CurrentStringNum, CurrentString, 512); 200 | 201 | if (CurrentString[0] == ';') continue; // It's a comment 202 | 203 | if (CurrentString[0] == '[' && CurrentString[CurrentStringSize - 1] == ']') // It's section declaration 204 | { 205 | SectionsCount++; 206 | continue; 207 | } 208 | } 209 | 210 | DWORD *SectionVariableCount = new DWORD[SectionsCount]; 211 | memset(SectionVariableCount, 0x00, sizeof(DWORD)*SectionsCount); 212 | 213 | for (DWORD CurrentStringNum = 0; CurrentStringNum < FileStringsCount; CurrentStringNum++) 214 | { 215 | CurrentStringSize = GetFileStringFromNum(CurrentStringNum, CurrentString, 512); 216 | 217 | if (CurrentString[0] == ';') continue; // It's a comment 218 | 219 | 220 | if (CurrentString[0] == '[' && CurrentString[CurrentStringSize - 1] == ']') // It's section declaration 221 | { 222 | CurrentSectionNum++; 223 | continue; 224 | } 225 | if (IsVariable(CurrentString, CurrentStringSize)) 226 | { 227 | VariablesCount++; 228 | SectionVariableCount[CurrentSectionNum]++; 229 | continue; 230 | } 231 | } 232 | 233 | IniData.SectionCount = SectionsCount; 234 | IniData.Section = new INI_SECTION[SectionsCount]; 235 | memset(IniData.Section, 0x00, sizeof(PINI_SECTION)*SectionsCount); 236 | 237 | for (DWORD i = 0; i < SectionsCount; i++) 238 | { 239 | IniData.Section[i].VariablesCount = SectionVariableCount[i]; 240 | IniData.Section[i].Variables = new INI_SECTION_VARIABLE[SectionVariableCount[i]]; 241 | memset(IniData.Section[i].Variables, 0x00, sizeof(INI_SECTION_VARIABLE)*SectionVariableCount[i]); 242 | } 243 | 244 | delete[] SectionVariableCount; 245 | 246 | CurrentSectionNum = -1; 247 | CurrentVariableNum = -1; 248 | 249 | for (DWORD CurrentStringNum = 0; CurrentStringNum < FileStringsCount; CurrentStringNum++) 250 | { 251 | CurrentStringSize = GetFileStringFromNum(CurrentStringNum, CurrentString, 512); 252 | 253 | if (CurrentString[0] == ';') // It's a comment 254 | { 255 | continue; 256 | } 257 | 258 | if (CurrentString[0] == '[' && CurrentString[CurrentStringSize - 1] == ']') 259 | { 260 | CurrentSectionNum++; 261 | CurrentVariableNum = 0; 262 | memset(IniData.Section[CurrentSectionNum].SectionName, 0, MAX_STRING_LEN); 263 | memcpy(IniData.Section[CurrentSectionNum].SectionName, &(CurrentString[1]), (CurrentStringSize - 2)); 264 | continue; 265 | } 266 | 267 | if (IsVariable(CurrentString, CurrentStringSize)) 268 | { 269 | FillVariable(&(IniData.Section[CurrentSectionNum].Variables[CurrentVariableNum]), CurrentString, CurrentStringSize); 270 | CurrentVariableNum++; 271 | continue; 272 | } 273 | } 274 | 275 | return true; 276 | } 277 | 278 | PINI_SECTION INI_FILE::GetSection(char *SectionName) 279 | { 280 | for (DWORD i = 0; i < IniData.SectionCount; i++) 281 | { 282 | if ( 283 | (strlen(IniData.Section[i].SectionName) == strlen(SectionName)) && 284 | (memcmp(IniData.Section[i].SectionName, SectionName, strlen(SectionName)) == 0) 285 | ) 286 | { 287 | return &IniData.Section[i]; 288 | } 289 | } 290 | return NULL; 291 | } 292 | 293 | bool INI_FILE::SectionExists(char *SectionName) 294 | { 295 | if (GetSection(SectionName) == NULL) return false; 296 | return true; 297 | } 298 | 299 | bool INI_FILE::VariableExists(char *SectionName, char *VariableName) 300 | { 301 | INI_SECTION_VARIABLE Variable = { 0 }; 302 | return GetVariableInSectionPrivate(SectionName, VariableName, &Variable); 303 | } 304 | 305 | bool INI_FILE::GetVariableInSectionPrivate(char *SectionName, char *VariableName, INI_SECTION_VARIABLE *RetVariable) 306 | { 307 | INI_SECTION *Section = NULL; 308 | INI_SECTION_VARIABLE *Variable = NULL; 309 | 310 | // Find section 311 | Section = GetSection(SectionName); 312 | if (Section == NULL) 313 | { 314 | SetLastError(318); // This region is not found 315 | return false; 316 | } 317 | 318 | // Find variable 319 | for (DWORD i = 0; i < Section->VariablesCount; i++) 320 | { 321 | if ( 322 | (strlen(Section->Variables[i].VariableName) == strlen(VariableName)) && 323 | (memcmp(Section->Variables[i].VariableName, VariableName, strlen(VariableName)) == 0) 324 | ) 325 | { 326 | Variable = &(Section->Variables[i]); 327 | break; 328 | } 329 | } 330 | if (Variable == NULL) 331 | { 332 | SetLastError(1898); // Member of the group is not found 333 | return false; 334 | } 335 | 336 | memset(RetVariable, 0x00, sizeof(*RetVariable)); 337 | memcpy(RetVariable, Variable, sizeof(*Variable)); 338 | 339 | return true; 340 | } 341 | 342 | bool INI_FILE::GetVariableInSection(char *SectionName, char *VariableName, INI_VAR_STRING *RetVariable) 343 | { 344 | bool Status = false; 345 | INI_SECTION_VARIABLE Variable = {}; 346 | 347 | Status = GetVariableInSectionPrivate(SectionName, VariableName, &Variable); 348 | if (!Status) return Status; 349 | 350 | memset(RetVariable, 0x00, sizeof(*RetVariable)); 351 | memcpy(RetVariable->Name, Variable.VariableName, strlen(Variable.VariableName)); 352 | memcpy(RetVariable->Value, Variable.VariableValue, strlen(Variable.VariableValue)); 353 | 354 | return true; 355 | } 356 | 357 | bool INI_FILE::GetVariableInSection(char *SectionName, char *VariableName, INI_VAR_DWORD *RetVariable) 358 | { 359 | bool Status = false; 360 | INI_SECTION_VARIABLE Variable = {}; 361 | 362 | Status = GetVariableInSectionPrivate(SectionName, VariableName, &Variable); 363 | if (!Status) return Status; 364 | 365 | memset(RetVariable, 0x00, sizeof(*RetVariable)); 366 | memcpy(RetVariable->Name, Variable.VariableName, strlen(Variable.VariableName)); 367 | 368 | #ifndef _WIN64 369 | RetVariable->ValueDec = strtol(Variable.VariableValue, NULL, 10); 370 | RetVariable->ValueHex = strtol(Variable.VariableValue, NULL, 16); 371 | #else 372 | RetVariable->ValueDec = _strtoi64(Variable.VariableValue, NULL, 10); 373 | RetVariable->ValueHex = _strtoi64(Variable.VariableValue, NULL, 16); 374 | #endif 375 | return true; 376 | } 377 | 378 | bool INI_FILE::GetVariableInSection(char *SectionName, char *VariableName, INI_VAR_BYTEARRAY *RetVariable) 379 | { 380 | bool Status = false; 381 | INI_SECTION_VARIABLE Variable = {}; 382 | 383 | Status = GetVariableInSectionPrivate(SectionName, VariableName, &Variable); 384 | if (!Status) return Status; 385 | 386 | DWORD ValueLen = strlen(Variable.VariableValue); 387 | if ((ValueLen % 2) != 0) return false; 388 | 389 | // for security reasons not more than 16 bytes 390 | if (ValueLen > 32) ValueLen = 32; // 32 hex digits 391 | 392 | memset(RetVariable, 0x00, sizeof(*RetVariable)); 393 | memcpy(RetVariable->Name, Variable.VariableName, strlen(Variable.VariableName)); 394 | 395 | for (DWORD i = 0; i <= ValueLen; i++) 396 | { 397 | if ((i % 2) != 0) continue; 398 | 399 | switch (Variable.VariableValue[i]) 400 | { 401 | case '0': break; 402 | case '1': RetVariable->Value[(i / 2)] += (1 << 4); break; 403 | case '2': RetVariable->Value[(i / 2)] += (2 << 4); break; 404 | case '3': RetVariable->Value[(i / 2)] += (3 << 4); break; 405 | case '4': RetVariable->Value[(i / 2)] += (4 << 4); break; 406 | case '5': RetVariable->Value[(i / 2)] += (5 << 4); break; 407 | case '6': RetVariable->Value[(i / 2)] += (6 << 4); break; 408 | case '7': RetVariable->Value[(i / 2)] += (7 << 4); break; 409 | case '8': RetVariable->Value[(i / 2)] += (8 << 4); break; 410 | case '9': RetVariable->Value[(i / 2)] += (9 << 4); break; 411 | case 'A': RetVariable->Value[(i / 2)] += (10 << 4); break; 412 | case 'B': RetVariable->Value[(i / 2)] += (11 << 4); break; 413 | case 'C': RetVariable->Value[(i / 2)] += (12 << 4); break; 414 | case 'D': RetVariable->Value[(i / 2)] += (13 << 4); break; 415 | case 'E': RetVariable->Value[(i / 2)] += (14 << 4); break; 416 | case 'F': RetVariable->Value[(i / 2)] += (15 << 4); break; 417 | } 418 | 419 | switch (Variable.VariableValue[i + 1]) 420 | { 421 | case '0': break; 422 | case '1': RetVariable->Value[(i / 2)] += 1; break; 423 | case '2': RetVariable->Value[(i / 2)] += 2; break; 424 | case '3': RetVariable->Value[(i / 2)] += 3; break; 425 | case '4': RetVariable->Value[(i / 2)] += 4; break; 426 | case '5': RetVariable->Value[(i / 2)] += 5; break; 427 | case '6': RetVariable->Value[(i / 2)] += 6; break; 428 | case '7': RetVariable->Value[(i / 2)] += 7; break; 429 | case '8': RetVariable->Value[(i / 2)] += 8; break; 430 | case '9': RetVariable->Value[(i / 2)] += 9; break; 431 | case 'A': RetVariable->Value[(i / 2)] += 10; break; 432 | case 'B': RetVariable->Value[(i / 2)] += 11; break; 433 | case 'C': RetVariable->Value[(i / 2)] += 12; break; 434 | case 'D': RetVariable->Value[(i / 2)] += 13; break; 435 | case 'E': RetVariable->Value[(i / 2)] += 14; break; 436 | case 'F': RetVariable->Value[(i / 2)] += 15; break; 437 | } 438 | } 439 | RetVariable->ArraySize = ValueLen / 2; 440 | return true; 441 | } 442 | 443 | bool INI_FILE::GetVariableInSection(char *SectionName, char *VariableName, bool *RetVariable) 444 | { 445 | bool Status = false; 446 | INI_SECTION_VARIABLE Variable = {}; 447 | 448 | Status = GetVariableInSectionPrivate(SectionName, VariableName, &Variable); 449 | if (!Status) return Status; 450 | 451 | *RetVariable = (bool)strtol(Variable.VariableValue, NULL, 10); 452 | return true; 453 | } 454 | 455 | bool INI_FILE::GetSectionVariablesList(char *SectionName, INI_SECTION_VARLIST *VariablesList) 456 | { 457 | INI_SECTION *Section = NULL; 458 | 459 | Section = GetSection(SectionName); 460 | if (Section == NULL) 461 | { 462 | SetLastError(318); // This region is not found 463 | return false; 464 | } 465 | 466 | VariablesList->EntriesCount = Section->VariablesCount; 467 | 468 | VariablesList->NamesEntries = new INI_SECTION_VARLIST_ENTRY[VariablesList->EntriesCount]; 469 | memset(VariablesList->NamesEntries, 0x00, sizeof(INI_SECTION_VARLIST_ENTRY)*VariablesList->EntriesCount); 470 | 471 | VariablesList->ValuesEntries = new INI_SECTION_VARLIST_ENTRY[VariablesList->EntriesCount]; 472 | memset(VariablesList->ValuesEntries, 0x00, sizeof(INI_SECTION_VARLIST_ENTRY)*VariablesList->EntriesCount); 473 | 474 | for (DWORD i = 0; i < Section->VariablesCount; i++) 475 | { 476 | memcpy(VariablesList->NamesEntries[i].String, Section->Variables[i].VariableName, 477 | strlen(Section->Variables[i].VariableName)); 478 | 479 | memcpy(VariablesList->ValuesEntries[i].String, Section->Variables[i].VariableValue, 480 | strlen(Section->Variables[i].VariableValue)); 481 | } 482 | 483 | return true; 484 | } 485 | 486 | 487 | // ---------------------------- WCHAR_T BLOCK ---------------------------------------------- 488 | 489 | bool INI_FILE::SectionExists(wchar_t *SectionName) 490 | { 491 | char cSectionName[MAX_STRING_LEN] = { 0x00 }; 492 | 493 | wcstombs(cSectionName, SectionName, MAX_STRING_LEN); 494 | 495 | return GetSection(cSectionName); 496 | } 497 | 498 | bool INI_FILE::VariableExists(wchar_t *SectionName, wchar_t *VariableName) 499 | { 500 | INI_SECTION_VARIABLE Variable = { 0 }; 501 | 502 | char cSectionName[MAX_STRING_LEN] = { 0x00 }; 503 | char cVariableName[MAX_STRING_LEN] = { 0x00 }; 504 | 505 | wcstombs(cSectionName, SectionName, MAX_STRING_LEN); 506 | wcstombs(cVariableName, VariableName, MAX_STRING_LEN); 507 | 508 | return GetVariableInSectionPrivate(cSectionName, cVariableName, &Variable); 509 | } 510 | 511 | bool INI_FILE::GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, INI_VAR_STRING *RetVariable) 512 | { 513 | char cSectionName[MAX_STRING_LEN] = { 0x00 }; 514 | char cVariableName[MAX_STRING_LEN] = { 0x00 }; 515 | 516 | wcstombs(cSectionName, SectionName, MAX_STRING_LEN); 517 | wcstombs(cVariableName, VariableName, MAX_STRING_LEN); 518 | 519 | return GetVariableInSection(cSectionName, cVariableName, RetVariable); 520 | } 521 | 522 | bool INI_FILE::GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, INI_VAR_DWORD *RetVariable) 523 | { 524 | char cSectionName[MAX_STRING_LEN] = { 0x00 }; 525 | char cVariableName[MAX_STRING_LEN] = { 0x00 }; 526 | 527 | wcstombs(cSectionName, SectionName, MAX_STRING_LEN); 528 | wcstombs(cVariableName, VariableName, MAX_STRING_LEN); 529 | 530 | return GetVariableInSection(cSectionName, cVariableName, RetVariable); 531 | } 532 | 533 | bool INI_FILE::GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, INI_VAR_BYTEARRAY *RetVariable) 534 | { 535 | char cSectionName[MAX_STRING_LEN] = { 0x00 }; 536 | char cVariableName[MAX_STRING_LEN] = { 0x00 }; 537 | 538 | wcstombs(cSectionName, SectionName, MAX_STRING_LEN); 539 | wcstombs(cVariableName, VariableName, MAX_STRING_LEN); 540 | 541 | return GetVariableInSection(cSectionName, cVariableName, RetVariable); 542 | } 543 | 544 | bool INI_FILE::GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, bool *RetVariable) 545 | { 546 | char cSectionName[MAX_STRING_LEN] = { 0x00 }; 547 | char cVariableName[MAX_STRING_LEN] = { 0x00 }; 548 | 549 | wcstombs(cSectionName, SectionName, MAX_STRING_LEN); 550 | wcstombs(cVariableName, VariableName, MAX_STRING_LEN); 551 | 552 | return GetVariableInSection(cSectionName, cVariableName, RetVariable); 553 | } 554 | 555 | bool INI_FILE::GetSectionVariablesList(wchar_t *SectionName, INI_SECTION_VARLIST *VariablesList) 556 | { 557 | char cSectionName[MAX_STRING_LEN] = { 0x00 }; 558 | 559 | wcstombs(cSectionName, SectionName, MAX_STRING_LEN); 560 | 561 | return GetSectionVariablesList(cSectionName, VariablesList); 562 | } -------------------------------------------------------------------------------- /src-x86-x64-Fusix/IniFile.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Stas'M Corp. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include "stdafx.h" 18 | #include 19 | 20 | #define MAX_STRING_LEN 255 21 | 22 | // Out values struсts 23 | typedef struct _INI_VAR_STRING 24 | { 25 | char Name[MAX_STRING_LEN]; 26 | char Value[MAX_STRING_LEN]; 27 | } INI_VAR_STRING, *PINI_VAR_STRING; 28 | 29 | typedef struct _INI_VAR_DWORD 30 | { 31 | char Name[MAX_STRING_LEN]; 32 | #ifndef _WIN64 33 | DWORD ValueDec; 34 | DWORD ValueHex; 35 | #else 36 | DWORD64 ValueDec; 37 | DWORD64 ValueHex; 38 | #endif 39 | 40 | } INI_VAR_DWORD, *PINI_VAR_DWORD; 41 | 42 | typedef struct _INI_VAR_BYTEARRAY 43 | { 44 | char Name[MAX_STRING_LEN]; 45 | BYTE ArraySize; 46 | char Value[MAX_STRING_LEN]; 47 | } INI_VAR_BYTEARRAY, *PINI_VAR_BYTEARRAY; 48 | 49 | typedef struct _INI_SECTION_VARLIST_ENTRY 50 | { 51 | char String[MAX_STRING_LEN]; 52 | } INI_SECTION_VARLIST_ENTRY, *PINI_SECTION_VARLIST_ENTRY; 53 | 54 | typedef struct _INI_SECTION_VARLIST 55 | { 56 | DWORD EntriesCount; 57 | [length_is(EntriesCount)] INI_SECTION_VARLIST_ENTRY *NamesEntries; 58 | [length_is(EntriesCount)] INI_SECTION_VARLIST_ENTRY *ValuesEntries; 59 | } INI_SECTION_VARLIST, *PINI_SECTION_VARLIST; 60 | 61 | // end 62 | 63 | typedef struct _INI_SECTION_VARIABLE 64 | { 65 | char VariableName[MAX_STRING_LEN]; 66 | char VariableValue[MAX_STRING_LEN]; 67 | } INI_SECTION_VARIABLE, *PINI_SECTION_VARIABLE; 68 | 69 | 70 | typedef struct _INI_SECTION 71 | { 72 | char SectionName[MAX_STRING_LEN]; 73 | DWORD VariablesCount; 74 | [length_is(SectionCount)] INI_SECTION_VARIABLE *Variables; 75 | 76 | } INI_SECTION, *PINI_SECTION; 77 | 78 | typedef struct _INI_DATA 79 | { 80 | DWORD SectionCount; 81 | [length_is(SectionCount)] INI_SECTION *Section; 82 | } INI_DATA, *PINI_DATA; 83 | 84 | class INI_FILE 85 | { 86 | public: 87 | INI_FILE(wchar_t*); 88 | ~INI_FILE(); 89 | 90 | // char block 91 | bool SectionExists(char *SectionName); 92 | bool VariableExists(char *SectionName, char *VariableName); 93 | bool GetVariableInSection(char *SectionName, char *VariableName, INI_VAR_STRING *Variable); 94 | bool GetVariableInSection(char *SectionName, char *VariableName, INI_VAR_DWORD *Variable); 95 | bool GetVariableInSection(char *SectionName, char *VariableName, bool *Variable); 96 | bool GetVariableInSection(char *SectionName, char *VariableName, INI_VAR_BYTEARRAY *Variable); 97 | bool GetSectionVariablesList(char *SectionName, INI_SECTION_VARLIST *VariablesList); 98 | 99 | // wchar_t tramps 100 | bool SectionExists(wchar_t *SectionName); 101 | bool VariableExists(wchar_t *SectionName, wchar_t *VariableName); 102 | bool GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, INI_VAR_STRING *Variable); 103 | bool GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, INI_VAR_DWORD *Variable); 104 | bool GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, bool *Variable); 105 | bool GetVariableInSection(wchar_t *SectionName, wchar_t *VariableName, INI_VAR_BYTEARRAY *Variable); 106 | bool GetSectionVariablesList(wchar_t *SectionName, INI_SECTION_VARLIST *VariablesList); 107 | 108 | private: 109 | DWORD FileSize; // Ini file size 110 | char *FileRaw; // Ini file raw dump 111 | DWORD FileStringsCount; // String-map length 112 | DWORD *FileStringsMap; // String-map 113 | INI_DATA IniData; // Parsed data 114 | 115 | // Common service functions 116 | int StrTrim(char* Str); 117 | 118 | // Class service functions 119 | bool CreateStringsMap(); // Create file string-map 120 | bool Parse(); // Parse file to class structures 121 | DWORD GetFileStringFromNum(DWORD StringNumber, char *RetString, DWORD Size); // Get string from string-map 122 | bool IsVariable(char *Str, DWORD StrSize); 123 | bool FillVariable(INI_SECTION_VARIABLE *Variable, char *Str, DWORD StrSize); // Fill INI_SECTION_VARIABLE struct (for Parse) 124 | PINI_SECTION GetSection(char *SectionName); 125 | bool GetVariableInSectionPrivate(char *SectionName, char *VariableName, INI_SECTION_VARIABLE *RetVariable); 126 | }; 127 | -------------------------------------------------------------------------------- /src-x86-x64-Fusix/RDPWrap.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RDPWrap", "RDPWrap.vcxproj", "{29E4E73B-EBA6-495B-A76C-FBB462196C64}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Debug|Win32.Build.0 = Debug|Win32 16 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Debug|Win32.Deploy.0 = Debug|Win32 17 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Debug|x64.ActiveCfg = Debug|x64 18 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Debug|x64.Build.0 = Debug|x64 19 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Debug|x64.Deploy.0 = Debug|x64 20 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Release|Win32.ActiveCfg = Release|Win32 21 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Release|Win32.Build.0 = Release|Win32 22 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Release|Win32.Deploy.0 = Release|Win32 23 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Release|x64.ActiveCfg = Release|x64 24 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Release|x64.Build.0 = Release|x64 25 | {29E4E73B-EBA6-495B-A76C-FBB462196C64}.Release|x64.Deploy.0 = Release|x64 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /src-x86-x64-Fusix/RDPWrap.v11.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-x86-x64-Fusix/RDPWrap.v11.suo -------------------------------------------------------------------------------- /src-x86-x64-Fusix/RDPWrap.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {29E4E73B-EBA6-495B-A76C-FBB462196C64} 23 | Win32Proj 24 | RDPWrap 25 | 26 | 27 | 28 | DynamicLibrary 29 | true 30 | v120 31 | Unicode 32 | 33 | 34 | DynamicLibrary 35 | true 36 | v120 37 | Unicode 38 | 39 | 40 | DynamicLibrary 41 | false 42 | v120 43 | true 44 | Unicode 45 | 46 | 47 | DynamicLibrary 48 | false 49 | v120 50 | true 51 | Unicode 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | 72 | 73 | true 74 | 75 | 76 | false 77 | 78 | 79 | false 80 | 81 | 82 | 83 | Use 84 | Level3 85 | Disabled 86 | WIN32;_DEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) 87 | true 88 | 89 | 90 | Windows 91 | true 92 | Export.def 93 | 94 | 95 | 96 | 97 | Use 98 | Level3 99 | Disabled 100 | WIN32;_DEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) 101 | true 102 | 103 | 104 | Windows 105 | true 106 | Export.def 107 | 108 | 109 | 110 | 111 | Use 112 | MaxSpeed 113 | true 114 | true 115 | WIN32;NDEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) 116 | true 117 | true 118 | Level3 119 | 1Byte 120 | MultiThreaded 121 | 122 | 123 | Windows 124 | false 125 | true 126 | true 127 | Export.def 128 | 129 | 130 | false 131 | true 132 | 133 | 134 | 135 | 136 | Use 137 | MaxSpeed 138 | true 139 | true 140 | WIN32;NDEBUG;_WINDOWS;_USRDLL;RDPWRAP_EXPORTS;%(PreprocessorDefinitions) 141 | true 142 | true 143 | Level3 144 | 1Byte 145 | MultiThreaded 146 | 147 | 148 | Windows 149 | false 150 | true 151 | true 152 | Export.def 153 | 154 | 155 | false 156 | true 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | false 170 | false 171 | 172 | 173 | 174 | 175 | false 176 | false 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | Create 186 | Create 187 | Create 188 | Create 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /src-x86-x64-Fusix/RDPWrap.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Заголовочные файлы 23 | 24 | 25 | Заголовочные файлы 26 | 27 | 28 | Заголовочные файлы 29 | 30 | 31 | 32 | 33 | Файлы исходного кода 34 | 35 | 36 | Файлы исходного кода 37 | 38 | 39 | Файлы исходного кода 40 | 41 | 42 | Файлы исходного кода 43 | 44 | 45 | 46 | 47 | Файлы исходного кода 48 | 49 | 50 | -------------------------------------------------------------------------------- /src-x86-x64-Fusix/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | БИБЛИОТЕКА ДИНАМИЧЕСКОЙ КОМПОНОВКИ. Обзор проекта RDPWrap 3 | ======================================================================== 4 | 5 | Эта библиотека DLL RDPWrap создана автоматически с помощью мастера приложений. 6 | 7 | В этом файле представлена сводка содержимого всех файлов, входящих в состав приложения RDPWrap. 8 | 9 | 10 | RDPWrap.vcxproj 11 | Это основной файл проекта VC++, создаваемый с помощью мастера приложений. Он содержит данные о версии языка Visual C++, использованной для создания файла, а также сведения о платформах, конфигурациях и функциях проекта, выбранных с помощью мастера приложений. 12 | 13 | RDPWrap.vcxproj.filters 14 | Это файл фильтров для проектов VC++, созданный с помощью мастера приложений. Он содержит сведения о сопоставлениях между файлами в вашем проекте и фильтрами. Эти сопоставления используются в среде IDE для группировки файлов с одинаковыми расширениями в одном узле (например CPP-файлы сопоставляются с фильтром "Исходные файлы"). 15 | 16 | RDPWrap.cpp 17 | Основной исходный файл библиотеки DLL. 18 | 19 | При создании этой библиотеки DLL не выполняется экспорт символов. Поэтому при ее построении не создается LIB-файл. Если в этом проекте требуется определить зависимость от другого проекта, необходимо добавить код для экспорта символов из библиотеки DLL, чтобы обеспечить создание библиотеки экспорта, или задать значение «Да» для свойства «Пропустить входную библиотеку» на странице общих свойств папки «Компоновщик» в диалоговом окне «Страницы свойств» проекта. 20 | 21 | ///////////////////////////////////////////////////////////////////////////// 22 | Другие стандартные файлы: 23 | 24 | StdAfx.h, StdAfx.cpp 25 | Эти файлы используются для построения файла предкомпилированного заголовка (PCH) с именем RDPWrap.pch и файла предкомпилированных типов с именем StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Прочие примечания. 29 | 30 | С помощью комментариев «TODO:» в мастере приложений обозначаются фрагменты исходного кода, которые необходимо дополнить или изменить. 31 | 32 | ///////////////////////////////////////////////////////////////////////////// 33 | -------------------------------------------------------------------------------- /src-x86-x64-Fusix/dllmain.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-x86-x64-Fusix/dllmain.cpp -------------------------------------------------------------------------------- /src-x86-x64-Fusix/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-x86-x64-Fusix/stdafx.cpp -------------------------------------------------------------------------------- /src-x86-x64-Fusix/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-x86-x64-Fusix/stdafx.h -------------------------------------------------------------------------------- /src-x86-x64-Fusix/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asmtron/rdpwrap/d973562ba338608de61fad22d41c82e0ef8f5494/src-x86-x64-Fusix/targetver.h --------------------------------------------------------------------------------