⬆️ ⬇️

Multi-user mode for Terminal Server in Windows XP x64

In the wake of a recent upgrade, I happened to face the unpleasant limitation of Windows XP x64 on the number of users simultaneously connected via Remote Desktop. Namely, at any given time, no more than one user can work with a computer. When connecting via RDP, the local user is disabled; when you log on locally, the remote is disabled. It's a shame, given that the machine’s resources would be more than enough for several clients.



As far as I know, this problem is inherent in all desktop (non-server) versions of Windows. For the 32-bit version of Windows XP, there is a solution in the form of a TS-Free patch, which replaces several system libraries with older, but unlimited, versions. For 64-bit systems, the solution usually comes down either to switching to the server version of the OS (respectively, considerable expenses), or to using third-party programs like WinConnect Server VS (however, WinXP x64 is still not supported). I already had time to despair, when in one Dutch blog I accidentally came across an article " Windows XP x64 Terminal Server patch ". Unlike TS-Free, for which all antiviruses swear, in this article the author describes in detail which bytes are changing and why, so that the reader can independently verify the security of the patch.

Below is a free translation of the article.



Windows XP x64 is based on the same files as Windows 2003 x64, however Terminal Server in XP has some limitations. This article demonstrates how to get rid of them. The basis of the ideas cw2k from the original patch for Windows XP Terminal Server.

')

1) Winlogon.exe contains the function EnumerateMatchingUsers , which calls IsProfessionalTerminalServer . The last one needs to be fixed so that it returns zero (FALSE):
.text: 0000000100042F77 IsProfessionalTerminalServer proc near ; CODE XREF: EnumerateMatchingUsers: loc_10002B44Bp

.text: 0000000100042F77 ; DATA XREF: .pdata: 00000001000D01DCo ...

.text: 0000000100042F77

.text: 0000000100042F77 VersionInformation = _OSVERSIONINFOW ptr -138h

.text: 0000000100042F77 var_20 = word ptr -20h

.text: 0000000100042F77 var_ 1E = byte ptr -1Eh

.text: 0000000100042F77 var_18 = qword ptr -18h

.text: 0000000100042F77

.text: 0000000100042F77 48 81 EC 58 01 00 00 sub rsp, 158h => 31 C0 C3 xor eax, eax; retn

.text: 0000000100042F7E 48 8B 05 F3 3A 08 00 mov rax, cs: __ security_cookie

.text: 0000000100042F85 48 89 84 24 40 01 00 00 mov [rsp + 158h + var_18 ], rax

.text: 0000000100042F8D 48 8D 4C 24 20 lea rcx, [rsp + 158h + VersionInformation ] ; void *

.text: 0000000100042F92 33 D2 xor edx, edx ; int


But that is not all. There is also a function IsPerOrProTerminalServer ; it is used in several places, but we will only edit its calls from the MultiUserLogonAttempt :
.text: 0000000100044A91 E8 71 E5 FF FF call IsPerOrProTerminalServer

.text: 0000000100044A96 85 C0 test eax, eax

.text: 0000000100044A98 0F 84 C9 00 00 00 jz loc_100044B67 => 0F 8D C9 00 00 00 jmp loc_100044B67

.text: 0000000100044B13 E8 EF E4 FF FF call IsPerOrProTerminalServer

.text: 0000000100044B18 85 C0 test eax, eax

.text: 0000000100044B1A 74 0C jz short loc_100044B28 => EB 0C jmp short loc_100044B28


2) Termsrv.dll . Let's make Terminal Server think that it is running on the server OS. In ServiceMain, termsrv.dll initializes a global variable called gbServer . We need it to be TRUE (1):
.text: 000007FF7B877F77 33 C9 xor ecx, ecx ; ConditionMask

.text: 000007FF7B877F79 C7 05 9D 2C 05 00 1C 01 00 00 mov cs: gOsVersion.dwOSVersionInfoSize, 11Ch

.text: 000007FF7B877F83 C6 05 B0 2D 05 00 01 mov cs: gOsVersion.wProductType, 1

.text: 000007FF7B877F8A FF 15 F8 9A FF FF call cs: __ imp_VerSetConditionMask

.text: 000007FF7B877F90 48 8D 0D 89 2C 05 00 lea rcx, gOsVersion ; lpVersionInformation

.text: 000007FF7B877F97 BA 80 00 00 00 mov edx, 80h ; dwTypeMask

.text: 000007FF7B877F9C 4C 8B C0 mov r8, rax ; dwlConditionMask

.text: 000007FF7B877F9F FF 15 73 95 FF FF call cs: __ imp_VerifyVersionInfoW

.text: 000007FF7B877FA5 8B CF mov ec ec, ed => 31 C9 x ec ec , ecx

.text: 000007FF7B877FA7 48 8D 15 B2 AE FF FF lea rdx, SubKey ; "System \\ CurrentControlSet \\ Control \\ Termin" ...

.text: 000007FF7B877FAE 85 C0 test eax, eax

.text: 000007FF7B877FB0 48 8D 44 24 60 lea rax, [rsp + 78h + hKey ]

.text: 000007FF7B877FB5 41 B9 19 00 02 00 mov r9d, 20019h ; samDesired

.text: 000007FF7B877FBB 0F 94 C1 setz cl => FF C1 90 inc ecx; nop

.text: 000007FF7B877FBE 45 33 C0 xor r8d, r8d ; ulOptions

.text: 000007FF7B877FC1 48 89 44 24 20 mov [rsp + 78h + var_58 ], rax

.text: 000007FF7B877FC6 89 0D 30 B0 04 00 mov cs: gbServer, ecx


So, we "upgraded" to the server. However, it is forbidden to disable the console on the server OS (STATUS_CTX_CONSOLE_DISCONNECT = $ C00A0027), so we need to fix two more places where this code is used:
.text: 000007FF7B889D99 85 C0 test eax, eax

.text: 000007FF7B889D9B 75 21 jnz short loc_7FF7B889DBE => EB 21 jmp short loc_7FF7B889DBE

.text: 000007FF7B889D9D 48 8D 4B 18 lea rcx, [rbx + 18h ]

.text: 000007FF7B889DA1 BF 27 00 0A C0 mov ed, 0C00A0027h
once again:
.text: 000007FF7B88AA1B 45 85 E4 test r12d, r12d

.text: 000007FF7B88AA1E 74 0A jz short loc_7FF7B88AA2A => EB 21 jmp short loc_7FF7B88AA2A

.text: 000007FF7B88AA20 BB 27 00 0A C0 mov ebx, 0C00A0027h


On this with all the patches! To apply them, do the following:



Registry edit : make sure that the following keys have the specified values.

Some nuances still remain: you cannot connect to localhost (solved by connecting to 127.0.0.2), and if you block your computer from the RDP session (not the console), you will simply disconnect (in the case of Fast User Switching, fast user switching). The following article will be devoted to solving these problems.



PS “Donate” button turned out to be just the way, in order to thank the author for his joy :)

PPS No, we are not in the lobe :)

Source: https://habr.com/ru/post/47956/



All Articles