Better structure
This commit is contained in:
729
src-x86-binarymaster/rdpwrap.dpr
Normal file
729
src-x86-binarymaster/rdpwrap.dpr
Normal file
@ -0,0 +1,729 @@
|
||||
{
|
||||
Copyright 2014 Stas'M Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
}
|
||||
|
||||
library rdpwrap;
|
||||
|
||||
uses
|
||||
SysUtils,
|
||||
Windows,
|
||||
TlHelp32,
|
||||
LiteINI;
|
||||
|
||||
{$R rdpwrap.res}
|
||||
|
||||
// Hook core definitions
|
||||
|
||||
type
|
||||
OldCode = packed record
|
||||
One: DWORD;
|
||||
two: Word;
|
||||
end;
|
||||
|
||||
far_jmp = packed record
|
||||
PushOp: Byte;
|
||||
PushArg: Pointer;
|
||||
RetOp: Byte;
|
||||
end;
|
||||
|
||||
mov_far_jmp = packed record
|
||||
MovOp: Byte;
|
||||
MovArg: Byte;
|
||||
PushOp: Byte;
|
||||
PushArg: Pointer;
|
||||
RetOp: Byte;
|
||||
end;
|
||||
|
||||
TTHREADENTRY32 = packed record
|
||||
dwSize: DWORD;
|
||||
cntUsage: DWORD;
|
||||
th32ThreadID: DWORD;
|
||||
th32OwnerProcessID: DWORD;
|
||||
tpBasePri: LongInt;
|
||||
tpDeltaPri: LongInt;
|
||||
dwFlags: DWORD;
|
||||
end;
|
||||
//IntArray = Array of Integer;
|
||||
FILE_VERSION = record
|
||||
Version: record case Boolean of
|
||||
True: (dw: DWORD);
|
||||
False: (w: record
|
||||
Minor, Major: Word;
|
||||
end;)
|
||||
end;
|
||||
Release, Build: Word;
|
||||
bDebug, bPrerelease, bPrivate, bSpecial: Boolean;
|
||||
end;
|
||||
|
||||
const
|
||||
THREAD_SUSPEND_RESUME = 2;
|
||||
TH32CS_SNAPTHREAD = 4;
|
||||
var
|
||||
INI: INIFile;
|
||||
LogFile: String = '\rdpwrap.txt';
|
||||
bw: DWORD;
|
||||
IsHooked: Boolean = False;
|
||||
|
||||
// Unhooked import
|
||||
|
||||
function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL;
|
||||
dwThreadId: DWORD): DWORD; stdcall; external kernel32;
|
||||
|
||||
function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): DWORD;
|
||||
stdcall; external kernel32;
|
||||
|
||||
function Thread32First(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool;
|
||||
stdcall; external kernel32;
|
||||
|
||||
function Thread32Next(hSnapshot: THandle; var lpte: TTHREADENTRY32): bool;
|
||||
stdcall; external kernel32;
|
||||
|
||||
// Wrapped import
|
||||
|
||||
var
|
||||
TSMain: function(dwArgc: DWORD; lpszArgv: PWideChar): DWORD; stdcall;
|
||||
TSGlobals: function(lpGlobalData: Pointer): DWORD; stdcall;
|
||||
|
||||
// Hooked import and vars
|
||||
|
||||
var
|
||||
SLGetWindowsInformationDWORD: function(pwszValueName: PWideChar;
|
||||
pdwValue: PDWORD): HRESULT; stdcall;
|
||||
TermSrvBase: Pointer;
|
||||
FV: FILE_VERSION;
|
||||
|
||||
var
|
||||
Stub_SLGetWindowsInformationDWORD: far_jmp;
|
||||
Old_SLGetWindowsInformationDWORD: OldCode;
|
||||
|
||||
// Main code
|
||||
|
||||
procedure WriteLog(S: AnsiString);
|
||||
var
|
||||
F: TextFile;
|
||||
begin
|
||||
if not FileExists(LogFile) then
|
||||
Exit;
|
||||
AssignFile(F, LogFile);
|
||||
Append(F);
|
||||
Write(F, S+#13#10);
|
||||
CloseFile(F);
|
||||
end;
|
||||
|
||||
function GetModuleHandleEx(dwFlags: DWORD; lpModuleName: PWideChar;
|
||||
var phModule: HMODULE): BOOL; stdcall; external kernel32 name 'GetModuleHandleExW';
|
||||
|
||||
function GetCurrentModule: HMODULE;
|
||||
const
|
||||
GET_MODULE_HANDLE_EX_FLAG_PIN = 1;
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2;
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 4;
|
||||
begin
|
||||
Result := 0;
|
||||
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, @GetCurrentModule, Result);
|
||||
end;
|
||||
|
||||
function GetBinaryPath: String;
|
||||
var
|
||||
Buf: Array[0..511] of Byte;
|
||||
begin
|
||||
ZeroMemory(@Buf[0], Length(Buf));
|
||||
GetModuleFileName(GetCurrentModule, PWideChar(@Buf[0]), Length(Buf));
|
||||
Result := PWideChar(@Buf[0]);
|
||||
end;
|
||||
|
||||
procedure StopThreads;
|
||||
var
|
||||
h, CurrTh, ThrHandle, CurrPr: DWORD;
|
||||
Thread: TTHREADENTRY32;
|
||||
begin
|
||||
CurrTh := GetCurrentThreadId;
|
||||
CurrPr := GetCurrentProcessId;
|
||||
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if h <> INVALID_HANDLE_VALUE then
|
||||
begin
|
||||
Thread.dwSize := SizeOf(TTHREADENTRY32);
|
||||
if Thread32First(h, Thread) then
|
||||
repeat
|
||||
if (Thread.th32ThreadID <> CurrTh) and
|
||||
(Thread.th32OwnerProcessID = CurrPr) then
|
||||
begin
|
||||
ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false,
|
||||
Thread.th32ThreadID);
|
||||
if ThrHandle > 0 then
|
||||
begin
|
||||
SuspendThread(ThrHandle);
|
||||
CloseHandle(ThrHandle);
|
||||
end;
|
||||
end;
|
||||
until not Thread32Next(h, Thread);
|
||||
CloseHandle(h);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure RunThreads;
|
||||
var
|
||||
h, CurrTh, ThrHandle, CurrPr: DWORD;
|
||||
Thread: TTHREADENTRY32;
|
||||
begin
|
||||
CurrTh := GetCurrentThreadId;
|
||||
CurrPr := GetCurrentProcessId;
|
||||
h := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if h <> INVALID_HANDLE_VALUE then
|
||||
begin
|
||||
Thread.dwSize := SizeOf(TTHREADENTRY32);
|
||||
if Thread32First(h, Thread) then
|
||||
repeat
|
||||
if (Thread.th32ThreadID <> CurrTh) and
|
||||
(Thread.th32OwnerProcessID = CurrPr) then
|
||||
begin
|
||||
ThrHandle := OpenThread(THREAD_SUSPEND_RESUME, false,
|
||||
Thread.th32ThreadID);
|
||||
if ThrHandle > 0 then
|
||||
begin
|
||||
ResumeThread(ThrHandle);
|
||||
CloseHandle(ThrHandle);
|
||||
end;
|
||||
end;
|
||||
until not Thread32Next(h, Thread);
|
||||
CloseHandle(h);
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetModuleAddress(ModuleName: String; ProcessId: DWORD; var BaseAddr: Pointer; var BaseSize: DWORD): Boolean;
|
||||
var
|
||||
hSnap: THandle;
|
||||
md: MODULEENTRY32;
|
||||
begin
|
||||
Result := False;
|
||||
hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
|
||||
if hSnap = INVALID_HANDLE_VALUE Then
|
||||
Exit;
|
||||
md.dwSize := SizeOf(MODULEENTRY32);
|
||||
if Module32First(hSnap, md) then
|
||||
begin
|
||||
if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then
|
||||
begin
|
||||
Result := True;
|
||||
BaseAddr := Pointer(md.modBaseAddr);
|
||||
BaseSize := md.modBaseSize;
|
||||
CloseHandle(hSnap);
|
||||
Exit;
|
||||
end;
|
||||
while Module32Next(hSnap, md) Do
|
||||
begin
|
||||
if LowerCase(ExtractFileName(md.szExePath)) = LowerCase(ModuleName) then
|
||||
begin
|
||||
Result := True;
|
||||
BaseAddr := Pointer(md.modBaseAddr);
|
||||
BaseSize := md.modBaseSize;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
CloseHandle(hSnap);
|
||||
end;
|
||||
|
||||
{procedure FindMem(Mem: Pointer; MemSz: DWORD; Buf: Pointer; BufSz: DWORD;
|
||||
From: DWORD; var A: IntArray);
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
SetLength(A, 0);
|
||||
I:=From;
|
||||
if From>0 then
|
||||
Inc(PByte(Mem), From);
|
||||
while I < MemSz - BufSz + 1 do
|
||||
begin
|
||||
if (not IsBadReadPtr(Mem, BufSz)) and (CompareMem(Mem, Buf, BufSz)) then
|
||||
begin
|
||||
SetLength(A, Length(A)+1);
|
||||
A[Length(A)-1] := I;
|
||||
end;
|
||||
Inc(I);
|
||||
Inc(PByte(Mem));
|
||||
end;
|
||||
end;}
|
||||
|
||||
function GetModuleVersion(const ModuleName: String; var FileVersion: FILE_VERSION): Boolean;
|
||||
type
|
||||
VS_VERSIONINFO = record
|
||||
wLength, wValueLength, wType: Word;
|
||||
szKey: Array[1..16] of WideChar;
|
||||
Padding1: Word;
|
||||
Value: VS_FIXEDFILEINFO;
|
||||
Padding2, Children: Word;
|
||||
end;
|
||||
PVS_VERSIONINFO = ^VS_VERSIONINFO;
|
||||
const
|
||||
VFF_DEBUG = 1;
|
||||
VFF_PRERELEASE = 2;
|
||||
VFF_PRIVATE = 8;
|
||||
VFF_SPECIAL = 32;
|
||||
var
|
||||
hMod: HMODULE;
|
||||
hResourceInfo: HRSRC;
|
||||
VersionInfo: PVS_VERSIONINFO;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
if ModuleName = '' then
|
||||
hMod := GetModuleHandle(nil)
|
||||
else
|
||||
hMod := GetModuleHandle(PWideChar(ModuleName));
|
||||
if hMod = 0 then
|
||||
Exit;
|
||||
|
||||
hResourceInfo := FindResource(hMod, PWideChar(1), PWideChar($10));
|
||||
if hResourceInfo = 0 then
|
||||
Exit;
|
||||
|
||||
VersionInfo := Pointer(LoadResource(hMod, hResourceInfo));
|
||||
if VersionInfo = nil then
|
||||
Exit;
|
||||
|
||||
FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS;
|
||||
FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16);
|
||||
FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS);
|
||||
FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG;
|
||||
FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE;
|
||||
FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE;
|
||||
FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function GetFileVersion(const FileName: String; var FileVersion: FILE_VERSION): Boolean;
|
||||
type
|
||||
VS_VERSIONINFO = record
|
||||
wLength, wValueLength, wType: Word;
|
||||
szKey: Array[1..16] of WideChar;
|
||||
Padding1: Word;
|
||||
Value: VS_FIXEDFILEINFO;
|
||||
Padding2, Children: Word;
|
||||
end;
|
||||
PVS_VERSIONINFO = ^VS_VERSIONINFO;
|
||||
const
|
||||
VFF_DEBUG = 1;
|
||||
VFF_PRERELEASE = 2;
|
||||
VFF_PRIVATE = 8;
|
||||
VFF_SPECIAL = 32;
|
||||
var
|
||||
hFile: HMODULE;
|
||||
hResourceInfo: HRSRC;
|
||||
VersionInfo: PVS_VERSIONINFO;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
|
||||
if hFile = 0 then
|
||||
Exit;
|
||||
|
||||
hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10));
|
||||
if hResourceInfo = 0 then
|
||||
Exit;
|
||||
|
||||
VersionInfo := Pointer(LoadResource(hFile, hResourceInfo));
|
||||
if VersionInfo = nil then
|
||||
Exit;
|
||||
|
||||
FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS;
|
||||
FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16);
|
||||
FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS);
|
||||
FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG;
|
||||
FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE;
|
||||
FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE;
|
||||
FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function OverrideSL(ValueName: String; var Value: DWORD): Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
if INIValueExists(INI, 'SLPolicy', ValueName) then begin
|
||||
Value := INIReadDWord(INI, 'SLPolicy', ValueName, 0);
|
||||
Exit;
|
||||
end;
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function New_SLGetWindowsInformationDWORD(pwszValueName: PWideChar;
|
||||
pdwValue: PDWORD): HRESULT; stdcall;
|
||||
var
|
||||
dw: DWORD;
|
||||
begin
|
||||
// wrapped SLGetWindowsInformationDWORD function
|
||||
// termsrv.dll will call this function instead of original SLC.dll
|
||||
|
||||
// Override SL Policy
|
||||
|
||||
WriteLog('Policy query: ' + pwszValueName);
|
||||
if OverrideSL(pwszValueName, dw) then begin
|
||||
pdwValue^ := dw;
|
||||
Result := S_OK;
|
||||
WriteLog('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
|
||||
Sect: String;
|
||||
bServerSku,
|
||||
bRemoteConnAllowed,
|
||||
bFUSEnabled,
|
||||
bAppServerAllowed,
|
||||
bMultimonAllowed,
|
||||
lMaxUserSessions,
|
||||
ulMaxDebugSessions,
|
||||
bInitialized: PDWORD;
|
||||
begin
|
||||
bServerSku := nil;
|
||||
bRemoteConnAllowed := nil;
|
||||
bFUSEnabled := nil;
|
||||
bAppServerAllowed := nil;
|
||||
bMultimonAllowed := nil;
|
||||
lMaxUserSessions := nil;
|
||||
ulMaxDebugSessions := nil;
|
||||
bInitialized := nil;
|
||||
WriteLog('> CSLQuery::Initialize');
|
||||
Sect := IntToStr(FV.Version.w.Major)+'.'+IntToStr(FV.Version.w.Minor)+'.'+
|
||||
IntToStr(FV.Release)+'.'+IntToStr(FV.Build)+'-SLInit';
|
||||
if INISectionExists(INI, Sect) then begin
|
||||
bServerSku := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bServerSku.x86', 0));
|
||||
bRemoteConnAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bRemoteConnAllowed.x86', 0));
|
||||
bFUSEnabled := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bFUSEnabled.x86', 0));
|
||||
bAppServerAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bAppServerAllowed.x86', 0));
|
||||
bMultimonAllowed := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bMultimonAllowed.x86', 0));
|
||||
lMaxUserSessions := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'lMaxUserSessions.x86', 0));
|
||||
ulMaxDebugSessions := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'ulMaxDebugSessions.x86', 0));
|
||||
bInitialized := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'bInitialized.x86', 0));
|
||||
end;
|
||||
|
||||
if bServerSku <> nil then begin
|
||||
bServerSku^ := INIReadDWord(INI, 'SLInit', 'bServerSku', 1);
|
||||
WriteLog('[0x'+IntToHex(DWORD(bServerSku), 1)+'] bServerSku = ' + IntToStr(bServerSku^));
|
||||
end;
|
||||
if bRemoteConnAllowed <> nil then begin
|
||||
bRemoteConnAllowed^ := INIReadDWord(INI, 'SLInit', 'bRemoteConnAllowed', 1);
|
||||
WriteLog('[0x'+IntToHex(DWORD(bRemoteConnAllowed), 1)+'] bRemoteConnAllowed = ' + IntToStr(bRemoteConnAllowed^));
|
||||
end;
|
||||
if bFUSEnabled <> nil then begin
|
||||
bFUSEnabled^ := INIReadDWord(INI, 'SLInit', 'bFUSEnabled', 1);
|
||||
WriteLog('[0x'+IntToHex(DWORD(bFUSEnabled), 1)+'] bFUSEnabled = ' + IntToStr(bFUSEnabled^));
|
||||
end;
|
||||
if bAppServerAllowed <> nil then begin
|
||||
bAppServerAllowed^ := INIReadDWord(INI, 'SLInit', 'bAppServerAllowed', 1);
|
||||
WriteLog('[0x'+IntToHex(DWORD(bAppServerAllowed), 1)+'] bAppServerAllowed = ' + IntToStr(bAppServerAllowed^));
|
||||
end;
|
||||
if bMultimonAllowed <> nil then begin
|
||||
bMultimonAllowed^ := INIReadDWord(INI, 'SLInit', 'bMultimonAllowed', 1);
|
||||
WriteLog('[0x'+IntToHex(DWORD(bMultimonAllowed), 1)+'] bMultimonAllowed = ' + IntToStr(bMultimonAllowed^));
|
||||
end;
|
||||
if lMaxUserSessions <> nil then begin
|
||||
lMaxUserSessions^ := INIReadDWord(INI, 'SLInit', 'lMaxUserSessions', 0);
|
||||
WriteLog('[0x'+IntToHex(DWORD(lMaxUserSessions), 1)+'] lMaxUserSessions = ' + IntToStr(lMaxUserSessions^));
|
||||
end;
|
||||
if ulMaxDebugSessions <> nil then begin
|
||||
ulMaxDebugSessions^ := INIReadDWord(INI, 'SLInit', 'ulMaxDebugSessions', 0);
|
||||
WriteLog('[0x'+IntToHex(DWORD(ulMaxDebugSessions), 1)+'] ulMaxDebugSessions = ' + IntToStr(ulMaxDebugSessions^));
|
||||
end;
|
||||
if bInitialized <> nil then begin
|
||||
bInitialized^ := INIReadDWord(INI, 'SLInit', 'bInitialized', 1);
|
||||
WriteLog('[0x'+IntToHex(DWORD(bInitialized), 1)+'] bInitialized = ' + IntToStr(bInitialized^));
|
||||
end;
|
||||
Result := S_OK;
|
||||
end;
|
||||
|
||||
procedure HookFunctions;
|
||||
var
|
||||
Sect, FuncName: String;
|
||||
V: DWORD;
|
||||
TS_Handle, SLC_Handle: THandle;
|
||||
TermSrvSize: DWORD;
|
||||
SignPtr: Pointer;
|
||||
I: Integer;
|
||||
PatchList: SList;
|
||||
Patch: Array of TBytes;
|
||||
Jump: far_jmp;
|
||||
MovJump: mov_far_jmp;
|
||||
begin
|
||||
{ hook function ^^
|
||||
(called once) }
|
||||
IsHooked := True;
|
||||
TSMain := nil;
|
||||
TSGlobals := nil;
|
||||
SLGetWindowsInformationDWORD := nil;
|
||||
|
||||
WriteLog('Loading configuration...');
|
||||
INILoad(INI, ExtractFilePath(GetBinaryPath) + 'rdpwrap.ini');
|
||||
if Length(INI) = 0 then begin
|
||||
WriteLog('Error: Failed to load configuration');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
LogFile := INIReadString(INI, 'Main', 'LogFile', ExtractFilePath(GetBinaryPath) + 'rdpwrap.txt');
|
||||
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();
|
||||
|
||||
WriteLog('Loading patch codes...');
|
||||
PatchList := INIReadSection(INI, 'PatchCodes');
|
||||
SetLength(Patch, Length(PatchList));
|
||||
for I := 0 to Length(Patch) - 1 do begin
|
||||
Patch[I] := INIReadBytes(INI, 'PatchCodes', PatchList[I]);
|
||||
if Length(Patch[I]) > 16 then // for security reasons
|
||||
SetLength(Patch[I], 16); // not more than 16 bytes
|
||||
end;
|
||||
|
||||
if (V = $0600) and (INIReadBool(INI, 'Main', 'SLPolicyHookNT60', True)) then begin
|
||||
// Windows Vista
|
||||
// uses SL Policy API (slc.dll)
|
||||
|
||||
// load slc.dll and hook function
|
||||
SLC_Handle := LoadLibrary('slc.dll');
|
||||
SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD');
|
||||
|
||||
if @SLGetWindowsInformationDWORD <> nil then
|
||||
begin
|
||||
// rewrite original function to call our function (make hook)
|
||||
|
||||
WriteLog('Hook SLGetWindowsInformationDWORD');
|
||||
Stub_SLGetWindowsInformationDWORD.PushOp := $68;
|
||||
Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD;
|
||||
Stub_SLGetWindowsInformationDWORD.RetOp := $C3;
|
||||
ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
|
||||
@Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw);
|
||||
WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
|
||||
@Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw);
|
||||
end;
|
||||
end;
|
||||
if (V = $0601) and (INIReadBool(INI, 'Main', 'SLPolicyHookNT61', True)) then begin
|
||||
// Windows 7
|
||||
// uses SL Policy API (slc.dll)
|
||||
|
||||
// load slc.dll and hook function
|
||||
SLC_Handle := LoadLibrary('slc.dll');
|
||||
SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD');
|
||||
|
||||
if @SLGetWindowsInformationDWORD <> nil then
|
||||
begin
|
||||
// rewrite original function to call our function (make hook)
|
||||
|
||||
WriteLog('Hook SLGetWindowsInformationDWORD');
|
||||
Stub_SLGetWindowsInformationDWORD.PushOp := $68;
|
||||
Stub_SLGetWindowsInformationDWORD.PushArg := @New_SLGetWindowsInformationDWORD;
|
||||
Stub_SLGetWindowsInformationDWORD.RetOp := $C3;
|
||||
ReadProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
|
||||
@Old_SLGetWindowsInformationDWORD, SizeOf(OldCode), bw);
|
||||
WriteProcessMemory(GetCurrentProcess, @SLGetWindowsInformationDWORD,
|
||||
@Stub_SLGetWindowsInformationDWORD, SizeOf(far_jmp), bw);
|
||||
end;
|
||||
end;
|
||||
if V = $0602 then begin
|
||||
// Windows 8
|
||||
// uses SL Policy internal unexported function
|
||||
|
||||
// load slc.dll and get function
|
||||
// (will be used on intercepting undefined values)
|
||||
SLC_Handle := LoadLibrary('slc.dll');
|
||||
SLGetWindowsInformationDWORD := GetProcAddress(SLC_Handle, 'SLGetWindowsInformationDWORD');
|
||||
end;
|
||||
if V = $0603 then begin
|
||||
// Windows 8.1
|
||||
// uses SL Policy internal inline code
|
||||
end;
|
||||
if V = $0604 then begin
|
||||
// Windows 10
|
||||
// uses SL Policy internal inline code
|
||||
end;
|
||||
|
||||
Sect := IntToStr(FV.Version.w.Major)+'.'+IntToStr(FV.Version.w.Minor)+'.'+
|
||||
IntToStr(FV.Release)+'.'+IntToStr(FV.Build);
|
||||
|
||||
if INISectionExists(INI, Sect) then
|
||||
if GetModuleAddress('termsrv.dll', GetCurrentProcessId, TermSrvBase, TermSrvSize) then begin
|
||||
if INIReadBool(INI, Sect, 'LocalOnlyPatch.x86', False) then begin
|
||||
WriteLog('Patch CEnforcementCore::GetInstanceOfTSLicense');
|
||||
SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'LocalOnlyOffset.x86', 0));
|
||||
I := SListFind(PatchList, INIReadString(INI, Sect, 'LocalOnlyCode.x86', ''));
|
||||
if I >= 0 then
|
||||
WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw);
|
||||
end;
|
||||
if INIReadBool(INI, Sect, 'SingleUserPatch.x86', False) then begin
|
||||
WriteLog('Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled');
|
||||
SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SingleUserOffset.x86', 0));
|
||||
I := SListFind(PatchList, INIReadString(INI, Sect, 'SingleUserCode.x86', ''));
|
||||
if I >= 0 then
|
||||
WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw);
|
||||
end;
|
||||
if INIReadBool(INI, Sect, 'DefPolicyPatch.x86', False) then begin
|
||||
WriteLog('Patch CDefPolicy::Query');
|
||||
SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'DefPolicyOffset.x86', 0));
|
||||
I := SListFind(PatchList, INIReadString(INI, Sect, 'DefPolicyCode.x86', ''));
|
||||
if I >= 0 then
|
||||
WriteProcessMemory(GetCurrentProcess, SignPtr, @Patch[I][0], Length(Patch[I]), bw);
|
||||
end;
|
||||
if INIReadBool(INI, Sect, 'SLPolicyInternal.x86', False) then begin
|
||||
WriteLog('Hook SLGetWindowsInformationDWORDWrapper');
|
||||
SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SLPolicyOffset.x86', 0));
|
||||
MovJump.MovOp := $89; // mov eax, ecx
|
||||
MovJump.MovArg := $C8; // __msfastcall compatibility
|
||||
MovJump.PushOp := $68;
|
||||
MovJump.PushArg := @New_Win8SL;
|
||||
MovJump.RetOp := $C3;
|
||||
FuncName := INIReadString(INI, Sect, 'SLPolicyFunc.x86', 'New_Win8SL');
|
||||
if FuncName = 'New_Win8SL' then
|
||||
MovJump.PushArg := @New_Win8SL;
|
||||
if FuncName = 'New_Win8SL_CP' then
|
||||
MovJump.PushArg := @New_Win8SL_CP;
|
||||
WriteProcessMemory(GetCurrentProcess, SignPtr,
|
||||
@MovJump, SizeOf(mov_far_jmp), bw);
|
||||
end;
|
||||
if INIReadBool(INI, Sect, 'SLInitHook.x86', False) then begin
|
||||
WriteLog('Hook CSLQuery::Initialize');
|
||||
SignPtr := Pointer(Cardinal(TermSrvBase) + INIReadDWordHex(INI, Sect, 'SLInitOffset.x86', 0));
|
||||
Jump.PushOp := $68;
|
||||
Jump.PushArg := @New_CSLQuery_Initialize;
|
||||
Jump.RetOp := $C3;
|
||||
FuncName := INIReadString(INI, Sect, 'SLInitFunc.x86', 'New_CSLQuery_Initialize');
|
||||
if FuncName = 'New_CSLQuery_Initialize' then
|
||||
Jump.PushArg := @New_CSLQuery_Initialize;
|
||||
WriteProcessMemory(GetCurrentProcess, SignPtr,
|
||||
@Jump, SizeOf(far_jmp), bw);
|
||||
end;
|
||||
end;
|
||||
|
||||
// unfreeze threads
|
||||
WriteLog('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.
|
Reference in New Issue
Block a user