rdpwrap_v2/src-x86-binarymaster/src/rdpwrap.dpr

1502 lines
55 KiB
ObjectPascal
Raw Normal View History

2014-10-23 01:47:44 +02:00
library rdpwrap;
// RDP Wrapper Library project by Stas'M
// Terminal Services supported versions
// 6.0.X.X (Windows Vista, any) [policy hook only]
// 6.0.6000.16386 (Windows Vista) [policy hook + extended patch]
// 6.0.6001.18000 (Windows Vista SP1) [policy hook + extended patch]
// 6.0.6001.22565 (Windows Vista SP1 with KB977541) [todo]
// 6.0.6001.22635 (Windows Vista SP1 with KB970911) [todo]
// 6.0.6001.22801 (Windows Vista SP1 with KB2381675) [todo]
// 6.0.6002.18005 (Windows Vista SP2) [policy hook + extended patch]
// 6.0.6002.22269 (Windows Vista SP2 with KB977541) [todo]
// 6.0.6002.22340 (Windows Vista SP2 with KB970911) [todo]
// 6.0.6002.22515 (Windows Vista SP2 with KB2381675) [todo]
// 6.0.6002.22641 (Windows Vista SP2 with KB2523307) [todo]
// 6.1.X.X (Windows 7, any) [policy hook only]
// 6.1.7600.16385 (Windows 7) [policy hook + extended patch]
// 6.1.7600.20890 (Windows 7 with KB2479710) [todo]
// 6.1.7600.21316 (Windows 7 with KB2750090) [todo]
// 6.1.7601.17514 (Windows 7 SP1) [policy hook + extended patch]
// 6.1.7601.21650 (Windows 7 SP1 with KB2479710) [todo]
// 6.1.7601.21866 (Windows 7 SP1 with KB2647409) [todo]
// 6.1.7601.22104 (Windows 7 SP1 with KB2750090) [todo]
// 6.1.7601.18540 (Windows 7 SP1 with KB2984972 GDR) [policy hook + extended patch]
// 6.1.7601.22750 (Windows 7 SP1 with KB2984972 LDR) [policy hook + extended patch]
// 6.2.8102.0 (Windows 8 Developer Preview) [policy hook + extended patch]
// 6.2.8250.0 (Windows 8 Consumer Preview) [policy hook + extended patch]
// 6.2.8400.0 (Windows 8 Release Preview) [policy hook + extended patch]
// 6.2.9200.16384 (Windows 8) [policy hook + extended patch]
// 6.2.9200.17048 (Windows 8 with KB2973501 GDR) [policy hook + extended patch]
// 6.2.9200.21166 (Windows 8 with KB2973501 LDR) [policy hook + extended patch]
// 6.3.9431.0 (Windows 8.1 Preview) [init hook + extended patch]
// 6.3.9600.16384 (Windows 8.1) [init hook + extended patch]
// 6.3.9600.17095 (Windows 8.1 with KB2959626) [init hook + extended patch]
// 6.4.9841.0 (Windows 10 Technical Preview) [init hook + extended patch]
// Known failures
// 6.0.6000.16386 (Windows Vista RTM x86, crashes on logon attempt)
// Internal changelog:
// 2014.10.19 :
// - added support for version 6.0.6000.16386 (x64)
// - added support for version 6.0.6001.18000 (x64)
// - added support for version 6.1.7600.16385
// 2014.10.18 :
// - corrected some typos in source
// - simplified signature constants
// - added support for version 6.0.6000.16386 (x86)
// - added support for version 6.0.6001.18000 (x86)
// - added support for version 6.0.6002.18005
// - added support for version 6.1.7601.17514
// - added support for version 6.1.7601.18540
// - added support for version 6.1.7601.22750
// - added support for version 6.2.9200.17048
// - added support for version 6.2.9200.21166
// 2014.10.17 :
// - collecting information about all versions of Terminal Services beginning from Vista
// - added [todo] to the versions list
// 2014.10.16 :
// - got new updates: KB2984972 for Win 7 (still works with 2 concurrent users) and KB2973501 for Win 8 (doesn't work)
// 2014.10.02 :
// - researching Windows 10 TP Remote Desktop
// - done! even without debugging symbols ^^)
// 2014.07.20 :
// - added support for Windows 8 Release Preview
// - added support for Windows 8 Consumer Preview
// - added support for Windows 8 Developer Preview
// 2014.07.19 :
// - improved patching of Windows 8
// - added policy patches
// - will patch CDefPolicy::Query
// - will patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
// 2014.07.18 :
// - researched patched files from MDL forum
// - CSLQuery::GetMaxSessions requires no patching
// - it's better to change the default policy, so...
// - will patch CDefPolicy::Query
// - will patch CEnforcementCore::GetInstanceOfTSLicense
// - will patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
// - the function CSLQuery::Initialize is hooked correctly
// 2014.07.17 :
// - will hook only CSLQuery::Initialize function
// - CSLQuery::GetMaxSessions will be patched
// - added x86 signatures for 6.3.9431.0 (Windows 8.1 Preview)
// 2014.07.16 :
// - changing asm opcodes is bad, will hook CSL functions
// 2014.07.15 :
// - added x86 signatures for 6.3.9600.16384 (Windows 8.1)
// 2014.07.15 :
// - added x86 signatures for 6.3.9600.17095 (Windows 8.1 with KB2959626)
uses
SysUtils,
Windows,
TlHelp32;
{$R rdpwrap.res}
// Hook core definitions
type
OldCode = packed record
One: DWORD;
two: Word;
end;
far_jmp = packed record
PushOp: Byte;
PushArg: Pointer;
RetOp: Byte;
end;
mov_far_jmp = packed record
MovOp: Byte;
MovArg: Byte;
PushOp: Byte;
PushArg: Pointer;
RetOp: Byte;
end;
TTHREADENTRY32 = packed record
dwSize: DWORD;
cntUsage: DWORD;
th32ThreadID: DWORD;
th32OwnerProcessID: DWORD;
tpBasePri: LongInt;
tpDeltaPri: LongInt;
dwFlags: DWORD;
end;
IntArray = Array of Integer;
FILE_VERSION = record
Version: record case Boolean of
True: (dw: DWORD);
False: (w: record
Minor, Major: Word;
end;)
end;
Release, Build: Word;
bDebug, bPrerelease, bPrivate, bSpecial: Boolean;
end;
const
THREAD_SUSPEND_RESUME = 2;
TH32CS_SNAPTHREAD = 4;
var
bw: DWORD;
IsHooked: Boolean = False;
FCount: Cardinal = 0;
// Unhooked import
function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL;
dwThreadId: DWORD): DWORD; stdcall; external kernel32;
function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): DWORD;
stdcall; external kernel32;
function Thread32First(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool;
stdcall; external kernel32;
function Thread32Next(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool;
stdcall; external kernel32;
// Wrapped import
var
TSMain: function(dwArgc: DWORD; lpszArgv: PWideChar): DWORD; stdcall;
TSGlobals: function(lpGlobalData: Pointer): DWORD; stdcall;
// Hooked import and vars
var
SLGetWindowsInformationDWORD: function(pwszValueName: PWideChar;
pdwValue: PDWORD): HRESULT; stdcall;
TermSrvBase: Pointer;
FV: FILE_VERSION;
const
CDefPolicy_Query_edx_ecx: Array[0..12] of Byte =
($BA,$00,$01,$00,$00,$89,$91,$20,$03,$00,$00,$5E,$90);
CDefPolicy_Query_eax_esi: Array[0..11] of Byte =
($B8,$00,$01,$00,$00,$89,$86,$20,$03,$00,$00,$90);
CDefPolicy_Query_eax_ecx: Array[0..11] of Byte =
($B8,$00,$01,$00,$00,$89,$81,$20,$03,$00,$00,$90);
// ------------------- TermService build 6.0.6000.16386
// Original
// .text:6F335CD8 cmp edx, [ecx+320h]
// .text:6F335CDE pop esi
// .text:6F335CDF jz loc_6F3426F1
//_______________
//
// Changed
// .text:6F335CD8 mov edx, 100h
// .text:6F335CDD mov [ecx+320h], edx
// .text:6F335CE3 pop esi
// .text:6F335CE4 nop
// CDefPolicy_Query_edx_ecx
// ------------------- TermService build 6.0.6001.18000
// Original
// .text:6E817FD8 cmp edx, [ecx+320h]
// .text:6E817FDE pop esi
// .text:6E817FDF jz loc_6E826F16
//_______________
//
// Changed
// .text:6E817FD8 mov edx, 100h
// .text:6E817FDD mov [ecx+320h], edx
// .text:6E817FE3 pop esi
// .text:6E817FE4 nop
// CDefPolicy_Query_edx_ecx
// ------------------- TermService build 6.0.6002.18005
// Original
// .text:6F5979C0 cmp edx, [ecx+320h]
// .text:6F5979C6 pop esi
// .text:6F5979C7 jz loc_6F5A6F26
//_______________
//
// Changed
// .text:6F5979C0 mov edx, 100h
// .text:6F5979C5 mov [ecx+320h], edx
// .text:6F5979CB pop esi
// .text:6F5979CC nop
// CDefPolicy_Query_edx_ecx
// ------------------- TermService build 6.1.7600.16385
// Original
// .text:6F2F96F3 cmp eax, [esi+320h]
// .text:6F2F96F9 jz loc_6F30E256
//_______________
//
// Changed
// .text:6F2F96F3 mov eax, 100h
// .text:6F2F96F8 mov [esi+320h], eax
// .text:6F2F96FE nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.1.7601.17514
// Original
// .text:6F2F9D53 cmp eax, [esi+320h]
// .text:6F2F9D59 jz loc_6F30B25E
//_______________
//
// Changed
// .text:6F2F9D53 mov eax, 100h
// .text:6F2F9D58 mov [esi+320h], eax
// .text:6F2F9D5E nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.1.7601.18540
// Original
// .text:6F2F9D9F cmp eax, [esi+320h]
// .text:6F2F9DA5 jz loc_6F30B2AE
//_______________
//
// Changed
// .text:6F2F9D9F mov eax, 100h
// .text:6F2F9DA4 mov [esi+320h], eax
// .text:6F2F9DAA nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.1.7601.22750
// Original
// .text:6F2F9E21 cmp eax, [esi+320h]
// .text:6F2F9E27 jz loc_6F30B6CE
//_______________
//
// Changed
// .text:6F2F9E21 mov eax, 100h
// .text:6F2F9E26 mov [esi+320h], eax
// .text:6F2F9E2C nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.2.8102.0
// Original
// .text:1000E47C cmp eax, [esi+320h]
// .text:1000E482 jz loc_1002D775
//_______________
//
// Changed
// .text:1000E47C mov eax, 100h
// .text:1000E481 mov [esi+320h], eax
// .text:1000E487 nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.2.8250.0
// Original
// .text:10013520 cmp eax, [esi+320h]
// .text:10013526 jz loc_1002DB85
//_______________
//
// Changed
// .text:10013520 mov eax, 100h
// .text:10013525 mov [esi+320h], eax
// .text:1001352B nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.2.8400.0
// Original
// .text:10013E48 cmp eax, [esi+320h]
// .text:10013E4E jz loc_1002E079
//_______________
//
// Changed
// .text:10013E48 mov eax, 100h
// .text:10013E4D mov [esi+320h], eax
// .text:10013E53 nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.2.9200.16384
// Original
// .text:10013F08 cmp eax, [esi+320h]
// .text:10013F0E jz loc_1002E161
//_______________
//
// Changed
// .text:10013F08 mov eax, 100h
// .text:10013F0D mov [esi+320h], eax
// .text:10013F13 nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.2.9200.17048
// Original
// .text:1001F408 cmp eax, [esi+320h]
// .text:1001F40E jz loc_1002E201
//_______________
//
// Changed
// .text:1001F408 mov eax, 100h
// .text:1001F40D mov [esi+320h], eax
// .text:1001F413 nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.2.9200.21166
// Original
// .text:10013F30 cmp eax, [esi+320h]
// .text:10013F36 jz loc_1002E189
//_______________
//
// Changed
// .text:10013F30 mov eax, 100h
// .text:10013F35 mov [esi+320h], eax
// .text:10013F3B nop
// CDefPolicy_Query_eax_esi
// ------------------- TermService build 6.3.9431.0
// Original
// .text:1002EA25 cmp eax, [ecx+320h]
// .text:1002EA2B jz loc_100348C1
//_______________
//
// Changed
// .text:1002EA25 mov eax, 100h
// .text:1002EA2A mov [ecx+320h], eax
// .text:1002EA30 nop
// CDefPolicy_Query_eax_ecx
// ------------------- TermService build 6.3.9600.16384
// Original
// .text:10016115 cmp eax, [ecx+320h]
// .text:1001611B jz loc_10034DE1
//_______________
//
// Changed
// .text:10016115 mov eax, 100h
// .text:1001611A mov [ecx+320h], eax
// .text:10016120 nop
// CDefPolicy_Query_eax_ecx
// ------------------- TermService build 6.3.9600.17095
// Original
// .text:10037529 cmp eax, [ecx+320h]
// .text:1003752F jz loc_10043662
//_______________
//
// Changed
// .text:10037529 mov eax, 100h
// .text:1003752E mov [ecx+320h], eax
// .text:10037534 nop
// CDefPolicy_Query_eax_ecx
// ------------------- TermService build 6.4.9841.0
// Original
// .text:1003B989 cmp eax, [ecx+320h]
// .text:1003B98F jz loc_1005E809
//_______________
//
// Changed
// .text:1003B989 mov eax, 100h
// .text:1003B98E mov [ecx+320h], eax
// .text:1003B994 nop
// CDefPolicy_Query_eax_ecx
var
Stub_SLGetWindowsInformationDWORD: far_jmp;
Old_SLGetWindowsInformationDWORD: OldCode;
// Main code
procedure WriteLog(S: AnsiString);
const
LogFile = '\rdpwrap.txt';
var
F: TextFile;
begin
if not FileExists(LogFile) then
Exit;
AssignFile(F, LogFile);
Append(F);
Write(F, S+#13#10);
CloseFile(F);
end;
procedure StopThreads;
var
h, CurrTh, ThrHandle, CurrPr: DWORD;
Thread: TTHREADENTRY32;
begin
CurrTh := GetCurrentThreadId;
CurrPr := GetCurrentProcessId;
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if h <> INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TTHREADENTRY32);
if Thread32First(h, Thread) then
repeat
if (Thread.th32ThreadID <> CurrTh) and
(Thread.th32OwnerProcessID = CurrPr) then
begin
ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false,
Thread.th32ThreadID);
if ThrHandle > 0 then
begin
SuspendThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h, Thread);
CloseHandle(h);
end;
end;
procedure RunThreads;
var
h, CurrTh, ThrHandle, CurrPr: DWORD;
Thread: TTHREADENTRY32;
begin
CurrTh := GetCurrentThreadId;
CurrPr := GetCurrentProcessId;
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if h <> INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TTHREADENTRY32);
if Thread32First(h, Thread) then
repeat
if (Thread.th32ThreadID <> CurrTh) and
(Thread.th32OwnerProcessID = CurrPr) then
begin
ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false,
Thread.th32ThreadID);
if ThrHandle > 0 then
begin
ResumeThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h, Thread);
CloseHandle(h);
end;
end;
function GetModuleAddress(ModuleName: String; ProcessId: DWORD; var BaseAddr: Pointer; var BaseSize: DWORD): Boolean;
var
hSnap: THandle;
md: MODULEENTRY32;
begin
Result := False;
hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
if hSnap = INVALID_HANDLE_VALUE Then
Exit;
md.dwSize := SizeOf(MODULEENTRY32);
if Module32First(hSnap, md) then
begin
if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then
begin
Result := True;
BaseAddr := Pointer(md.modBaseAddr);
BaseSize := md.modBaseSize;
CloseHandle(hSnap);
Exit;
end;
while Module32Next(hSnap, md) Do
begin
if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then
begin
Result := True;
BaseAddr := Pointer(md.modBaseAddr);
BaseSize := md.modBaseSize;
Break;
end;
end;
end;
CloseHandle(hSnap);
end;
{procedure FindMem(Mem: Pointer; MemSz: DWORD; Buf: Pointer; BufSz: DWORD;
From: DWORD; var A: IntArray);
var
I: Integer;
begin
SetLength(A, 0);
I:=From;
if From>0 then
Inc(PByte(Mem), From);
while I < MemSz - BufSz + 1 do
begin
if (not IsBadReadPtr(Mem, BufSz)) and (CompareMem(Mem, Buf, BufSz)) then
begin
SetLength(A, Length(A)+1);
A[Length(A)-1] := I;
end;
Inc(I);
Inc(PByte(Mem));
end;
end;}
function GetModuleVersion(const ModuleName: TFileName; var FileVersion: FILE_VERSION): Boolean;
type
VS_VERSIONINFO = record
wLength, wValueLength, wType: Word;
szKey: Array[1..16] of WideChar;
Padding1: Word;
Value: VS_FIXEDFILEINFO;
Padding2, Children: Word;
end;
PVS_VERSIONINFO = ^VS_VERSIONINFO;
const
VFF_DEBUG = 1;
VFF_PRERELEASE = 2;
VFF_PRIVATE = 8;
VFF_SPECIAL = 32;
var
hMod: HMODULE;
hResourceInfo: HRSRC;
VersionInfo: PVS_VERSIONINFO;
begin
Result := False;
if ModuleName = '' then
hMod := GetModuleHandle(nil)
else
hMod := GetModuleHandle(PWideChar(ModuleName));
if hMod = 0 then
Exit;
hResourceInfo := FindResource(hMod, PWideChar(1), PWideChar($10));
if hResourceInfo = 0 then
Exit;
VersionInfo := Pointer(LoadResource(hMod, hResourceInfo));
if VersionInfo = nil then
Exit;
FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS;
FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16);
FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS);
FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG;
FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE;
FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE;
FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL;
Result := True;
end;
function GetFileVersion(const FileName: TFileName; var FileVersion: FILE_VERSION): Boolean;
type
VS_VERSIONINFO = record
wLength, wValueLength, wType: Word;
szKey: Array[1..16] of WideChar;
Padding1: Word;
Value: VS_FIXEDFILEINFO;
Padding2, Children: Word;
end;
PVS_VERSIONINFO = ^VS_VERSIONINFO;
const
VFF_DEBUG = 1;
VFF_PRERELEASE = 2;
VFF_PRIVATE = 8;
VFF_SPECIAL = 32;
var
hFile: HMODULE;
hResourceInfo: HRSRC;
VersionInfo: PVS_VERSIONINFO;
begin
Result := False;
hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
if hFile = 0 then
Exit;
hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10));
if hResourceInfo = 0 then
Exit;
VersionInfo := Pointer(LoadResource(hFile, hResourceInfo));
if VersionInfo = nil then
Exit;
FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS;
FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16);
FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS);
FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG;
FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE;
FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE;
FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL;
Result := True;
end;
function OverrideSL(ValueName: String; var Value: DWORD): Boolean;
begin
Result := True;
// Allow Remote Connections
if ValueName = 'TerminalServices-RemoteConnectionManager-AllowRemoteConnections' then begin
Value := 1;
Exit;
end;
// Allow Multiple Sessions
if ValueName = 'TerminalServices-RemoteConnectionManager-AllowMultipleSessions' then begin
Value := 1;
Exit;
end;
// Allow Multiple Sessions (Application Server Mode)
if ValueName = 'TerminalServices-RemoteConnectionManager-AllowAppServerMode' then begin
Value := 1;
Exit;
end;
// Allow Multiple Monitors
if ValueName = 'TerminalServices-RemoteConnectionManager-AllowMultimon' then begin
Value := 1;
Exit;
end;
// Max User Sessions (0 = unlimited)
if ValueName = 'TerminalServices-RemoteConnectionManager-MaxUserSessions' then begin
Value := 0;
Exit;
end;
// Max Debug Sessions (Win 8, 0 = unlimited)
if ValueName = 'TerminalServices-RemoteConnectionManager-ce0ad219-4670-4988-98fb-89b14c2f072b-MaxSessions' then begin
Value := 0;
Exit;
end;
// Max Sessions
// 0 - logon not possible even from console
// 1 - only one active user (console or remote)
// 2 - allow concurrent sessions
if ValueName = 'TerminalServices-RemoteConnectionManager-45344fe7-00e6-4ac6-9f01-d01fd4ffadfb-MaxSessions' then begin
Value := 2;
Exit;
end;
// Allow Advanced Compression with RDP 7 Protocol
if ValueName = 'TerminalServices-RDP-7-Advanced-Compression-Allowed' then begin
Value := 1;
Exit;
end;
// IsTerminalTypeLocalOnly = 0
if ValueName = 'TerminalServices-RemoteConnectionManager-45344fe7-00e6-4ac6-9f01-d01fd4ffadfb-LocalOnly' then begin
Value := 0;
Exit;
end;
// Max Sessions (hard limit)
if ValueName = 'TerminalServices-RemoteConnectionManager-8dc86f1d-9969-4379-91c1-06fe1dc60575-MaxSessions' then begin
Value := 1000;
Exit;
end;
// Allow Easy Print
if ValueName = 'TerminalServices-DeviceRedirection-Licenses-TSEasyPrintAllowed' then begin
Value := 1;
Exit;
end;
Result := False;
end;
function New_SLGetWindowsInformationDWORD(pwszValueName: PWideChar;
pdwValue: PDWORD): HRESULT; stdcall;
var
dw: DWORD;
begin
// wrapped SLGetWindowsInformationDWORD function
// termsrv.dll will call this function instead of original SLC.dll
// Override SL Policy
WriteLog('Policy query: ' + pwszValueName);
if OverrideSL(pwszValueName, dw) then begin
pdwValue^ := dw;
Result := S_OK;
WriteLog('Rewrite: ' + IntToStr(pdwValue^));
Exit;
end;
// If the requested value name is not defined above
// revert to original SL Policy function
WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
@Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw);
// get result
Result := SLGetWindowsInformationDWORD(pwszValueName, pdwValue);
if Result = S_OK then
WriteLog('Result: ' + IntToStr(pdwValue^))
else
WriteLog('Failed');
// wrap it back
WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
@Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw);
end;
function New_Win8SL(pwszValueName: PWideChar; pdwValue: PDWORD): HRESULT; register;
var
dw: DWORD;
begin
// wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll
// for Windows 8 support
// Override SL Policy
WriteLog('Policy query: ' + pwszValueName);
if OverrideSL(pwszValueName, dw) then begin
pdwValue^ := dw;
Result := S_OK;
WriteLog('Rewrite: ' + IntToStr(pdwValue^));
Exit;
end;
// If the requested value name is not defined above
// use function from SLC.dll
Result := SLGetWindowsInformationDWORD(pwszValueName, pdwValue);
if Result = S_OK then
WriteLog('Result: ' + IntToStr(pdwValue^))
else
WriteLog('Failed');
end;
function New_Win8SL_CP(eax: DWORD; pdwValue: PDWORD; ecx: DWORD; pwszValueName: PWideChar): HRESULT; register;
begin
// wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll
// for Windows 8 Consumer Preview support
Result := New_Win8SL(pwszValueName, pdwValue);
end;
function New_CSLQuery_Initialize: HRESULT; stdcall;
var
bServerSku,
bRemoteConnAllowed,
bFUSEnabled,
bAppServerAllowed,
bMultimonAllowed,
lMaxUserSessions,
ulMaxDebugSessions,
bInitialized: PDWORD;
begin
bServerSku := nil;
bRemoteConnAllowed := nil;
bFUSEnabled := nil;
bAppServerAllowed := nil;
bMultimonAllowed := nil;
lMaxUserSessions := nil;
ulMaxDebugSessions := nil;
bInitialized := nil;
WriteLog('> CSLQuery::Initialize');
if (FV.Release = 9431) and (FV.Build = 0) then begin
bFUSEnabled := Pointer(Cardinal(TermSrvBase) + $A22A8);
lMaxUserSessions := Pointer(Cardinal(TermSrvBase) + $A22AC);
bAppServerAllowed := Pointer(Cardinal(TermSrvBase) + $A22B0);
bInitialized := Pointer(Cardinal(TermSrvBase) + $A22B4);
bMultimonAllowed := Pointer(Cardinal(TermSrvBase) + $A22B8);
bServerSku := Pointer(Cardinal(TermSrvBase) + $A22BC);
ulMaxDebugSessions := Pointer(Cardinal(TermSrvBase) + $A22C0);
bRemoteConnAllowed := Pointer(Cardinal(TermSrvBase) + $A22C4);
end;
if (FV.Release = 9600) and (FV.Build = 16384) then begin
bFUSEnabled := Pointer(Cardinal(TermSrvBase) + $C02A8);
lMaxUserSessions := Pointer(Cardinal(TermSrvBase) + $C02AC);
bAppServerAllowed := Pointer(Cardinal(TermSrvBase) + $C02B0);
bInitialized := Pointer(Cardinal(TermSrvBase) + $C02B4);
bMultimonAllowed := Pointer(Cardinal(TermSrvBase) + $C02B8);
bServerSku := Pointer(Cardinal(TermSrvBase) + $C02BC);
ulMaxDebugSessions := Pointer(Cardinal(TermSrvBase) + $C02C0);
bRemoteConnAllowed := Pointer(Cardinal(TermSrvBase) + $C02C4);
end;
if (FV.Release = 9600) and (FV.Build = 17095) then begin
bFUSEnabled := Pointer(Cardinal(TermSrvBase) + $C12A8);
lMaxUserSessions := Pointer(Cardinal(TermSrvBase) + $C12AC);
bAppServerAllowed := Pointer(Cardinal(TermSrvBase) + $C12B0);
bInitialized := Pointer(Cardinal(TermSrvBase) + $C12B4);
bMultimonAllowed := Pointer(Cardinal(TermSrvBase) + $C12B8);
bServerSku := Pointer(Cardinal(TermSrvBase) + $C12BC);
ulMaxDebugSessions := Pointer(Cardinal(TermSrvBase) + $C12C0);
bRemoteConnAllowed := Pointer(Cardinal(TermSrvBase) + $C12C4);
end;
if (FV.Release = 9841) and (FV.Build = 0) then begin
bFUSEnabled := Pointer(Cardinal(TermSrvBase) + $BF9F0);
lMaxUserSessions := Pointer(Cardinal(TermSrvBase) + $BF9F4);
bAppServerAllowed := Pointer(Cardinal(TermSrvBase) + $BF9F8);
bInitialized := Pointer(Cardinal(TermSrvBase) + $BF9FC);
bMultimonAllowed := Pointer(Cardinal(TermSrvBase) + $BFA00);
bServerSku := Pointer(Cardinal(TermSrvBase) + $BFA04);
ulMaxDebugSessions := Pointer(Cardinal(TermSrvBase) + $BFA08);
bRemoteConnAllowed := Pointer(Cardinal(TermSrvBase) + $BFA0C);
end;
if bServerSku <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(bServerSku), 1)+'] bServerSku = 1');
bServerSku^ := 1;
end;
if bRemoteConnAllowed <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(bRemoteConnAllowed), 1)+'] bRemoteConnAllowed = 1');
bRemoteConnAllowed^ := 1;
end;
if bFUSEnabled <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(bFUSEnabled), 1)+'] bFUSEnabled = 1');
bFUSEnabled^ := 1;
end;
if bAppServerAllowed <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(bAppServerAllowed), 1)+'] bAppServerAllowed = 1');
bAppServerAllowed^ := 1;
end;
if bMultimonAllowed <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(bMultimonAllowed), 1)+'] bMultimonAllowed = 1');
bMultimonAllowed^ := 1;
end;
if lMaxUserSessions <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(lMaxUserSessions), 1)+'] lMaxUserSessions = 0');
lMaxUserSessions^ := 0;
end;
if ulMaxDebugSessions <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(ulMaxDebugSessions), 1)+'] ulMaxDebugSessions = 0');
ulMaxDebugSessions^ := 0;
end;
if bInitialized <> nil then begin
WriteLog('[0x'+IntToHex(DWORD(bInitialized), 1)+'] bInitialized = 1');
bInitialized^ := 1;
end;
Result := S_OK;
end;
procedure HookFunctions;
var
V: DWORD;
TS_Handle, SLC_Handle: THandle;
TermSrvSize: DWORD;
SignPtr: Pointer;
Results: IntArray;
Jump: far_jmp;
MovJump: mov_far_jmp;
nop: DWORD;
b: Byte;
begin
{ hook function ^^
(called once) }
IsHooked := True;
nop := $90909090;
TSMain := nil;
TSGlobals := nil;
SLGetWindowsInformationDWORD := nil;
WriteLog('init');
// load termsrv.dll and get functions
TS_Handle := LoadLibrary('termsrv.dll');
if TS_Handle = 0 then begin
WriteLog('Error: Failed to load Terminal Services library');
Exit;
end;
WriteLog('Base addr: 0x'+IntToHex(TS_Handle, 8));
TSMain := GetProcAddress(TS_Handle, 'ServiceMain');
WriteLog('SvcMain: termsrv.dll+0x'+IntToHex(Cardinal(@TSMain) - TS_Handle, 1));
TSGlobals := GetProcAddress(TS_Handle, 'SvchostPushServiceGlobals');
WriteLog('SvcGlobals: termsrv.dll+0x'+IntToHex(Cardinal(@TSGlobals) - TS_Handle, 1));
V := 0;
// check termsrv version
if GetModuleVersion('termsrv.dll', FV) then
V := Byte(FV.Version.w.Minor) or (Byte(FV.Version.w.Major) shl 8)
else begin
// check NT version
// V := GetVersion; // deprecated
// V := ((V and $FF) shl 8) or ((V and $FF00) shr 8);
end;
if V = 0 then begin
WriteLog('Error: Failed to detect Terminal Services version');
Exit;
end;
WriteLog('Version: '+IntToStr(FV.Version.w.Major)+'.'+IntToStr(FV.Version.w.Minor));
WriteLog('Release: '+IntToStr(FV.Release));
WriteLog('Build: '+IntToStr(FV.Build));
// temporarily freeze threads
WriteLog('freeze');
StopThreads();
if (V = $0600) then begin
// Windows Vista
// uses SL Policy API (slc.dll)
// load slc.dll and hook function
SLC_Handle := LoadLibrary('slc.dll');
SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD');
if @SLGetWindowsInformationDWORD <> nil then
begin
// rewrite original function to call our function (make hook)
WriteLog('Hook SLGetWindowsInformationDWORD');
Stub_SLGetWindowsInformationDWORD.PushOp := $68;
Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD;
Stub_SLGetWindowsInformationDWORD.RetOp := $C3;
ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
@Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw);
WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
@Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw);
end;
if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin
// Patch functions:
// CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
// CDefPolicy::Query
if (FV.Release = 6000) and (FV.Build = 16386) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// Imagebase: 6F320000
// .text:6F3360B9 lea eax, [ebp+VersionInformation]
// .text:6F3360BF inc ebx <- nop
// .text:6F3360C0 push eax ; lpVersionInformation
// .text:6F3360C1 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:6F3360CB mov [esi], ebx
// .text:6F3360CD call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $160BF);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $15CD8);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_edx_ecx[0],
SizeOf(CDefPolicy_Query_edx_ecx), bw);
end;
if (FV.Release = 6001) and (FV.Build = 18000) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// Imagebase: 6E800000
// .text:6E8185DE lea eax, [ebp+VersionInformation]
// .text:6E8185E4 inc ebx <- nop
// .text:6E8185E5 push eax ; lpVersionInformation
// .text:6E8185E6 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:6E8185F0 mov [esi], ebx
// .text:6E8185F2 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $185E4);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $17FD8);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_edx_ecx[0],
SizeOf(CDefPolicy_Query_edx_ecx), bw);
end;
if (FV.Release = 6002) and (FV.Build = 18005) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// Imagebase: 6F580000
// .text:6F597FA2 lea eax, [ebp+VersionInformation]
// .text:6F597FA8 inc ebx <- nop
// .text:6F597FA9 push eax ; lpVersionInformation
// .text:6F597FAA mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:6F597FB4 mov [esi], ebx
// .text:6F597FB6 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $17FA8);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $179C0);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_edx_ecx[0],
SizeOf(CDefPolicy_Query_edx_ecx), bw);
end;
end;
end;
if (V = $0601) then begin
// Windows 7
// uses SL Policy API (slc.dll)
// load slc.dll and hook function
SLC_Handle := LoadLibrary('slc.dll');
SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD');
if @SLGetWindowsInformationDWORD <> nil then
begin
// rewrite original function to call our function (make hook)
WriteLog('Hook SLGetWindowsInformationDWORD');
Stub_SLGetWindowsInformationDWORD.PushOp := $68;
Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD;
Stub_SLGetWindowsInformationDWORD.RetOp := $C3;
ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
@Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw);
WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
@Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw);
end;
if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin
// Patch functions:
// CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
// CDefPolicy::Query
if (FV.Release = 7600) and (FV.Build = 16385) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// Imagebase: 6F2E0000
// .text:6F2F9E1F lea eax, [ebp+VersionInformation]
// .text:6F2F9E25 inc ebx <- nop
// .text:6F2F9E26 push eax ; lpVersionInformation
// .text:6F2F9E27 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:6F2F9E31 mov [esi], ebx
// .text:6F2F9E33 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $19E25);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $196F3);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
end;
if (FV.Release = 7601) and (FV.Build = 17514) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// Imagebase: 6F2E0000
// .text:6F2FA497 lea eax, [ebp+VersionInformation]
// .text:6F2FA49D inc ebx <- nop
// .text:6F2FA49E push eax ; lpVersionInformation
// .text:6F2FA49F mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:6F2FA4A9 mov [esi], ebx
// .text:6F2FA4AB call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $1A49D);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $19D53);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
end;
if (FV.Release = 7601) and (FV.Build = 18540) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// Imagebase: 6F2E0000
// .text:6F2FA4DF lea eax, [ebp+VersionInformation]
// .text:6F2FA4E5 inc ebx <- nop
// .text:6F2FA4E6 push eax ; lpVersionInformation
// .text:6F2FA4E7 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:6F2FA4F1 mov [esi], ebx
// .text:6F2FA4F3 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $1A4E5);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $19D9F);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
end;
if (FV.Release = 7601) and (FV.Build = 22750) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// Imagebase: 6F2E0000
// .text:6F2FA64F lea eax, [ebp+VersionInformation]
// .text:6F2FA655 inc ebx <- nop
// .text:6F2FA656 push eax ; lpVersionInformation
// .text:6F2FA657 mov [ebp+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:6F2FA661 mov [esi], ebx
// .text:6F2FA663 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $1A655);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $19E21);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
end;
end;
end;
if V = $0602 then begin
// Windows 8
// uses SL Policy internal unexported function
// load slc.dll and get function
// (will be used on intercepting undefined values)
SLC_Handle := LoadLibrary('slc.dll');
SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD');
if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin
// Patch functions:
// CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
// CDefPolicy::Query
// Hook function:
// SLGetWindowsInformationDWORDWrapper
if (FV.Release = 8102) and (FV.Build = 0) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:1000F7E5 lea eax, [esp+150h+VersionInformation]
// .text:1000F7E9 inc esi <- nop
// .text:1000F7EA push eax ; lpVersionInformation
// .text:1000F7EB mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:1000F7F3 mov [edi], esi
// .text:1000F7F5 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $F7E9);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $E47C);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
WriteLog('Hook SLGetWindowsInformationDWORDWrapper');
SignPtr := Pointer(Cardinal(TermSrvBase) + $1B909);
MovJump.MovOp := $89; // mov eax, ecx
MovJump.MovArg := $C8; // __msfastcall compatibility
MovJump.PushOp := $68;
MovJump.PushArg := @New_Win8SL;
MovJump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@MovJump, SizeOf(mov_far_jmp), bw);
end;
if (FV.Release = 8250) and (FV.Build = 0) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:100159C5 lea eax, [esp+150h+VersionInformation]
// .text:100159C9 inc esi <- nop
// .text:100159CA push eax ; lpVersionInformation
// .text:100159CB mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:100159D3 mov [edi], esi
// .text:100159D5 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $159C9);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $13520);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
WriteLog('Hook SLGetWindowsInformationDWORDWrapper');
SignPtr := Pointer(Cardinal(TermSrvBase) + $1A0A9);
MovJump.MovOp := $89; // mov eax, ecx
MovJump.MovArg := $C8; // __msfastcall compatibility
MovJump.PushOp := $68;
MovJump.PushArg := @New_Win8SL_CP;
MovJump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@MovJump, SizeOf(mov_far_jmp), bw);
end;
if (FV.Release = 8400) and (FV.Build = 0) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:1001547E lea eax, [esp+150h+VersionInformation]
// .text:10015482 inc esi <- nop
// .text:10015483 push eax ; lpVersionInformation
// .text:10015484 mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:1001548C mov [edi], esi
// .text:1001548E call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $15482);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $13E48);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
WriteLog('Hook SLGetWindowsInformationDWORDWrapper');
SignPtr := Pointer(Cardinal(TermSrvBase) + $19629);
MovJump.MovOp := $89; // mov eax, ecx
MovJump.MovArg := $C8; // __msfastcall compatibility
MovJump.PushOp := $68;
MovJump.PushArg := @New_Win8SL;
MovJump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@MovJump, SizeOf(mov_far_jmp), bw);
end;
if (FV.Release = 9200) and (FV.Build = 16384) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:1001554E lea eax, [esp+150h+VersionInformation]
// .text:10015552 inc esi <- nop
// .text:10015553 push eax ; lpVersionInformation
// .text:10015554 mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:1001555C mov [edi], esi
// .text:1001555E call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $15552);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $13F08);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
WriteLog('Hook SLGetWindowsInformationDWORDWrapper');
SignPtr := Pointer(Cardinal(TermSrvBase) + $19559);
MovJump.MovOp := $89; // mov eax, ecx
MovJump.MovArg := $C8; // __msfastcall compatibility
MovJump.PushOp := $68;
MovJump.PushArg := @New_Win8SL;
MovJump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@MovJump, SizeOf(mov_far_jmp), bw);
end;
if (FV.Release = 9200) and (FV.Build = 17048) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:1002058E lea eax, [esp+150h+VersionInformation]
// .text:10020592 inc esi <- nop
// .text:10020593 push eax ; lpVersionInformation
// .text:10020594 mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:1002059C mov [edi], esi
// .text:1002059E call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $20592);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $1F408);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
WriteLog('Hook SLGetWindowsInformationDWORDWrapper');
SignPtr := Pointer(Cardinal(TermSrvBase) + $17059);
MovJump.MovOp := $89; // mov eax, ecx
MovJump.MovArg := $C8; // __msfastcall compatibility
MovJump.PushOp := $68;
MovJump.PushArg := @New_Win8SL;
MovJump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@MovJump, SizeOf(mov_far_jmp), bw);
end;
if (FV.Release = 9200) and (FV.Build = 21166) then begin
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:10015576 lea eax, [esp+150h+VersionInformation]
// .text:1001557A inc esi <- nop
// .text:1001557B push eax ; lpVersionInformation
// .text:1001557C mov [esp+154h+VersionInformation.dwOSVersionInfoSize], 11Ch
// .text:10015584 mov [edi], esi
// .text:10015586 call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $1557A);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $13F30);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_esi[0],
SizeOf(CDefPolicy_Query_eax_esi), bw);
WriteLog('Hook SLGetWindowsInformationDWORDWrapper');
SignPtr := Pointer(Cardinal(TermSrvBase) + $19581);
MovJump.MovOp := $89; // mov eax, ecx
MovJump.MovArg := $C8; // __msfastcall compatibility
MovJump.PushOp := $68;
MovJump.PushArg := @New_Win8SL;
MovJump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@MovJump, SizeOf(mov_far_jmp), bw);
end;
end;
end;
if V = $0603 then begin
// Windows 8.1
// uses SL Policy internal inline code
if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin
// Patch functions:
// CEnforcementCore::GetInstanceOfTSLicense
// CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
// CDefPolicy::Query
// Hook function:
// CSLQuery::Initialize
if (FV.Release = 9431) and (FV.Build = 0) then begin
WriteLog('Patch CEnforcementCore::GetInstanceOfTSLicense');
// .text:1008A604 call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *)
// .text:1008A609 test eax, eax
// .text:1008A60B js short loc_1008A628
// .text:1008A60D cmp [ebp+var_8], 0
// .text:1008A611 jz short loc_1008A628 <- jmp
SignPtr := Pointer(Cardinal(TermSrvBase) + $8A611);
b := $EB;
WriteProcessMemory(GetCurrentProcess, SignPtr, @b, 1, bw);
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:100306A4 lea eax, [esp+150h+VersionInformation]
// .text:100306A8 inc ebx <- nop
// .text:100306A9 mov [edi], ebx
// .text:100306AB push eax ; lpVersionInformation
// .text:100306AC call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $306A8);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $2EA25);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_ecx[0],
SizeOf(CDefPolicy_Query_eax_ecx), bw);
WriteLog('Hook CSLQuery::Initialize');
SignPtr := Pointer(Cardinal(TermSrvBase) + $196B0);
Jump.PushOp := $68;
Jump.PushArg := @New_CSLQuery_Initialize;
Jump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@Jump, SizeOf(far_jmp), bw);
end;
if (FV.Release = 9600) and (FV.Build = 16384) then begin
WriteLog('Patch CEnforcementCore::GetInstanceOfTSLicense');
// .text:100A271C call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *)
// .text:100A2721 test eax, eax
// .text:100A2723 js short loc_100A2740
// .text:100A2725 cmp [ebp+var_8], 0
// .text:100A2729 jz short loc_100A2740 <- jmp
SignPtr := Pointer(Cardinal(TermSrvBase) + $A2729);
b := $EB;
WriteProcessMemory(GetCurrentProcess, SignPtr, @b, 1, bw);
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:10018024 lea eax, [esp+150h+VersionInformation]
// .text:10018028 inc ebx <- nop
// .text:10018029 mov [edi], ebx
// .text:1001802B push eax ; lpVersionInformation
// .text:1001802C call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $18028);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $16115);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_ecx[0],
SizeOf(CDefPolicy_Query_eax_ecx), bw);
WriteLog('Hook CSLQuery::Initialize');
SignPtr := Pointer(Cardinal(TermSrvBase) + $1CEB0);
Jump.PushOp := $68;
Jump.PushArg := @New_CSLQuery_Initialize;
Jump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@Jump, SizeOf(far_jmp), bw);
end;
if (FV.Release = 9600) and (FV.Build = 17095) then begin
WriteLog('Patch CEnforcementCore::GetInstanceOfTSLicense');
// .text:100A36C4 call ?IsLicenseTypeLocalOnly@CSLQuery@@SGJAAU_GUID@@PAH@Z ; CSLQuery::IsLicenseTypeLocalOnly(_GUID &,int *)
// .text:100A36C9 test eax, eax
// .text:100A36CB js short loc_100A36E8
// .text:100A36CD cmp [ebp+var_8], 0
// .text:100A36D1 jz short loc_100A36E8 <- jmp
SignPtr := Pointer(Cardinal(TermSrvBase) + $A36D1);
b := $EB;
WriteProcessMemory(GetCurrentProcess, SignPtr, @b, 1, bw);
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:10036BA5 lea eax, [esp+150h+VersionInformation]
// .text:10036BA9 inc ebx <- nop
// .text:10036BAA mov [edi], ebx
// .text:10036BAC push eax ; lpVersionInformation
// .text:10036BAD call ds:__imp__GetVersionExW@4 ; GetVersionExW(x)
SignPtr := Pointer(Cardinal(TermSrvBase) + $36BA9);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $37529);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_ecx[0],
SizeOf(CDefPolicy_Query_eax_ecx), bw);
WriteLog('Hook CSLQuery::Initialize');
SignPtr := Pointer(Cardinal(TermSrvBase) + $117F1);
Jump.PushOp := $68;
Jump.PushArg := @New_CSLQuery_Initialize;
Jump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@Jump, SizeOf(far_jmp), bw);
end;
end;
end;
if V = $0604 then begin
// Windows 10
// uses SL Policy internal inline code
if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin
// Patch functions:
// CEnforcementCore::GetInstanceOfTSLicense
// CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
// CDefPolicy::Query
// Hook function:
// CSLQuery::Initialize
if (FV.Release = 9841) and (FV.Build = 0) then begin
WriteLog('Patch CEnforcementCore::GetInstanceOfTSLicense');
// .text:1009569B call sub_100B7EE5
// .text:100956A0 test eax, eax
// .text:100956A2 js short loc_100956BF
// .text:100956A4 cmp [ebp+var_C], 0
// .text:100956A8 jz short loc_100956BF <- jmp
SignPtr := Pointer(Cardinal(TermSrvBase) + $956A8);
b := $EB;
WriteProcessMemory(GetCurrentProcess, SignPtr, @b, 1, bw);
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
// .text:10030121 lea eax, [esp+150h+VersionInformation]
// .text:10030125 inc ebx <- nop
// .text:10030126 mov [edi], ebx
// .text:10030128 push eax ; lpVersionInformation
// .text:10030129 call ds:GetVersionExW
SignPtr := Pointer(Cardinal(TermSrvBase) + $30125);
WriteProcessMemory(GetCurrentProcess, SignPtr, @nop, 1, bw);
WriteLog('Patch CDefPolicy::Query');
SignPtr := Pointer(Cardinal(TermSrvBase) + $3B989);
WriteProcessMemory(GetCurrentProcess, SignPtr,
@CDefPolicy_Query_eax_ecx[0],
SizeOf(CDefPolicy_Query_eax_ecx), bw);
WriteLog('Hook CSLQuery::Initialize');
SignPtr := Pointer(Cardinal(TermSrvBase) + $46A68);
Jump.PushOp := $68;
Jump.PushArg := @New_CSLQuery_Initialize;
Jump.RetOp := $C3;
WriteProcessMemory(GetCurrentProcess, SignPtr,
@Jump, SizeOf(far_jmp), bw);
end;
end;
end;
// unfreeze threads
WriteLog('resume');
RunThreads();
end;
function TermServiceMain(dwArgc: DWORD; lpszArgv: PWideChar): DWORD; stdcall;
begin
// wrap ServiceMain function
WriteLog('> ServiceMain');
if not IsHooked then
HookFunctions;
Result := 0;
if @TSMain <> nil then
Result := TSMain(dwArgc, lpszArgv);
end;
function TermServiceGlobals(lpGlobalData: Pointer): DWORD; stdcall;
begin
// wrap SvchostPushServiceGlobals function
WriteLog('> SvchostPushServiceGlobals');
if not IsHooked then
HookFunctions;
Result := 0;
if @TSGlobals <> nil then
Result := TSGlobals(lpGlobalData);
end;
// export section
exports
TermServiceMain index 1 name 'ServiceMain';
exports
TermServiceGlobals index 2 name 'SvchostPushServiceGlobals';
begin
// DllMain procedure is not used
end.