mirror of
https://github.com/stascorp/rdpwrap.git
synced 2024-11-21 04:50:19 -08:00
870 lines
26 KiB
C++
870 lines
26 KiB
C++
/*
|
|
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.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "IniFile.h"
|
|
#include <stdlib.h>
|
|
|
|
typedef struct
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
WORD Minor;
|
|
WORD Major;
|
|
} wVersion;
|
|
DWORD dwVersion;
|
|
};
|
|
WORD Release;
|
|
WORD Build;
|
|
} FILE_VERSION;
|
|
|
|
#ifdef _WIN64
|
|
typedef unsigned long long PLATFORM_DWORD;
|
|
struct FARJMP
|
|
{ // x64 far jump | opcode | assembly
|
|
BYTE MovOp; // 48 mov rax, ptr
|
|
BYTE MovRegArg; // B8
|
|
DWORD64 MovArg; // PTR
|
|
BYTE PushRaxOp; // 50 push rax
|
|
BYTE RetOp; // C3 retn
|
|
};
|
|
#else
|
|
typedef unsigned long PLATFORM_DWORD;
|
|
struct FARJMP
|
|
{ // x86 far jump | opcode | assembly
|
|
BYTE PushOp; // 68 push ptr
|
|
DWORD PushArg; // PTR
|
|
BYTE RetOp; // C3 retn
|
|
};
|
|
#endif
|
|
|
|
FARJMP Old_SLGetWindowsInformationDWORD, Stub_SLGetWindowsInformationDWORD;
|
|
SLGETWINDOWSINFORMATIONDWORD _SLGetWindowsInformationDWORD;
|
|
|
|
INI_FILE *IniFile;
|
|
wchar_t LogFile[256] = L"\\rdpwrap.txt\0";
|
|
HMODULE hTermSrv;
|
|
HMODULE hSLC;
|
|
PLATFORM_DWORD TermSrvBase;
|
|
FILE_VERSION FV;
|
|
SERVICEMAIN _ServiceMain;
|
|
SVCHOSTPUSHSERVICEGLOBALS _SvchostPushServiceGlobals;
|
|
bool AlreadyHooked = false;
|
|
|
|
DWORD INIReadDWordHex(INI_FILE *IniFile, char *Sect, char *VariableName, PLATFORM_DWORD Default)
|
|
{
|
|
INI_VAR_DWORD Variable;
|
|
|
|
if(IniFile->GetVariableInSection(Sect, VariableName, &Variable))
|
|
{
|
|
return Variable.ValueHex;
|
|
}
|
|
return Default;
|
|
}
|
|
|
|
void INIReadString(INI_FILE *IniFile, char *Sect, char *VariableName, char *Default, char *Ret, DWORD RetSize)
|
|
{
|
|
INI_VAR_STRING Variable;
|
|
|
|
memset(Ret, 0x00, RetSize);
|
|
if(!IniFile->GetVariableInSection(Sect, VariableName, &Variable))
|
|
{
|
|
strcpy_s(Ret, RetSize, Default);
|
|
return;
|
|
}
|
|
strcpy_s(Ret, RetSize, Variable.Value);
|
|
}
|
|
|
|
void WriteToLog(LPSTR Text)
|
|
{
|
|
DWORD dwBytesOfWritten;
|
|
|
|
HANDLE hFile = CreateFile(LogFile, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) return;
|
|
|
|
SetFilePointer(hFile, 0, 0, FILE_END);
|
|
WriteFile(hFile, Text, strlen(Text), &dwBytesOfWritten, NULL);
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
HMODULE GetCurrentModule()
|
|
{
|
|
HMODULE hModule = NULL;
|
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)GetCurrentModule, &hModule);
|
|
return hModule;
|
|
}
|
|
|
|
/*PLATFORM_DWORD SearchAddressBySignature(char *StartPosition, PLATFORM_DWORD Size, char *Signature, int SignatureSize)
|
|
{
|
|
PLATFORM_DWORD AddressReturn = -1;
|
|
|
|
for (PLATFORM_DWORD i = 0; i < Size; i++)
|
|
{
|
|
for (int j = 0; StartPosition[i+j] == Signature[j] && j < SignatureSize; j++)
|
|
{
|
|
if (j == SignatureSize-1) AddressReturn = (PLATFORM_DWORD)&StartPosition[i];
|
|
}
|
|
}
|
|
|
|
return AddressReturn;
|
|
}*/
|
|
|
|
bool GetModuleCodeSectionInfo(HMODULE hModule, PLATFORM_DWORD *BaseAddr, PLATFORM_DWORD *BaseSize)
|
|
{
|
|
PIMAGE_DOS_HEADER pDosHeader;
|
|
PIMAGE_FILE_HEADER pFileHeader;
|
|
PIMAGE_OPTIONAL_HEADER pOptionalHeader;
|
|
|
|
if (hModule == NULL) return false;
|
|
|
|
pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
|
pFileHeader = (PIMAGE_FILE_HEADER)(((PBYTE)hModule)+pDosHeader->e_lfanew+4);
|
|
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)(pFileHeader+1);
|
|
|
|
*BaseAddr = (PLATFORM_DWORD)hModule;
|
|
*BaseSize = (PLATFORM_DWORD)pOptionalHeader->SizeOfCode;
|
|
|
|
if (*BaseAddr <= 0 || *BaseSize <= 0) return false;
|
|
return true;
|
|
}
|
|
|
|
void SetThreadsState(bool Resume)
|
|
{
|
|
HANDLE h, hThread;
|
|
DWORD CurrTh, CurrPr;
|
|
THREADENTRY32 Thread;
|
|
|
|
CurrTh = GetCurrentThreadId();
|
|
CurrPr = GetCurrentProcessId();
|
|
|
|
h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
{
|
|
Thread.dwSize = sizeof(THREADENTRY32);
|
|
Thread32First(h, &Thread);
|
|
do
|
|
{
|
|
if (Thread.th32ThreadID != CurrTh && Thread.th32OwnerProcessID == CurrPr)
|
|
{
|
|
hThread = OpenThread(THREAD_SUSPEND_RESUME, false, Thread.th32ThreadID);
|
|
if (hThread != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (Resume) ResumeThread(hThread);
|
|
else SuspendThread(hThread);
|
|
CloseHandle(hThread);
|
|
}
|
|
}
|
|
} while (Thread32Next(h, &Thread));
|
|
CloseHandle(h);
|
|
}
|
|
}
|
|
|
|
BOOL __stdcall GetModuleVersion(LPCWSTR lptstrModuleName, FILE_VERSION *FileVersion)
|
|
{
|
|
typedef struct
|
|
{
|
|
WORD wLength;
|
|
WORD wValueLength;
|
|
WORD wType;
|
|
WCHAR szKey[16];
|
|
WORD Padding1;
|
|
VS_FIXEDFILEINFO Value;
|
|
WORD Padding2;
|
|
WORD Children;
|
|
} VS_VERSIONINFO;
|
|
|
|
HMODULE hMod = GetModuleHandle(lptstrModuleName);
|
|
if(!hMod)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
HRSRC hResourceInfo = FindResourceW(hMod, (LPCWSTR)1, (LPCWSTR)0x10);
|
|
if(!hResourceInfo)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VS_VERSIONINFO *VersionInfo = (VS_VERSIONINFO*)LoadResource(hMod, hResourceInfo);
|
|
if(!VersionInfo)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FileVersion->dwVersion = VersionInfo->Value.dwFileVersionMS;
|
|
FileVersion->Release = (WORD)(VersionInfo->Value.dwFileVersionLS >> 16);
|
|
FileVersion->Build = (WORD)VersionInfo->Value.dwFileVersionLS;
|
|
|
|
return true;
|
|
}
|
|
|
|
BOOL __stdcall GetFileVersion(LPCWSTR lptstrFilename, FILE_VERSION *FileVersion)
|
|
{
|
|
typedef struct
|
|
{
|
|
WORD wLength;
|
|
WORD wValueLength;
|
|
WORD wType;
|
|
WCHAR szKey[16];
|
|
WORD Padding1;
|
|
VS_FIXEDFILEINFO Value;
|
|
WORD Padding2;
|
|
WORD Children;
|
|
} VS_VERSIONINFO;
|
|
|
|
HMODULE hFile = LoadLibraryExW(lptstrFilename, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
if(!hFile)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
HRSRC hResourceInfo = FindResourceW(hFile, (LPCWSTR)1, (LPCWSTR)0x10);
|
|
if(!hResourceInfo)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
VS_VERSIONINFO *VersionInfo = (VS_VERSIONINFO*)LoadResource(hFile, hResourceInfo);
|
|
if(!VersionInfo)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FileVersion->dwVersion = VersionInfo->Value.dwFileVersionMS;
|
|
FileVersion->Release = (WORD)(VersionInfo->Value.dwFileVersionLS >> 16);
|
|
FileVersion->Build = (WORD)VersionInfo->Value.dwFileVersionLS;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverrideSL(LPWSTR ValueName, DWORD *Value)
|
|
{
|
|
INI_VAR_DWORD Variable = {0};
|
|
|
|
if (IniFile->VariableExists(L"SLPolicy", ValueName))
|
|
{
|
|
if (!(IniFile->GetVariableInSection(L"SLPolicy", ValueName, &Variable))) *Value = 0;
|
|
else *Value = Variable.ValueDec;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
HRESULT WINAPI New_SLGetWindowsInformationDWORD(PWSTR pwszValueName, DWORD *pdwValue)
|
|
{
|
|
// wrapped SLGetWindowsInformationDWORD function
|
|
// termsrv.dll will call this function instead of original SLC.dll
|
|
|
|
// Override SL Policy
|
|
|
|
extern FARJMP Old_SLGetWindowsInformationDWORD, Stub_SLGetWindowsInformationDWORD;
|
|
extern SLGETWINDOWSINFORMATIONDWORD _SLGetWindowsInformationDWORD;
|
|
|
|
char *Log;
|
|
DWORD dw;
|
|
SIZE_T bw;
|
|
HRESULT Result;
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Policy query: %S\r\n", pwszValueName);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
|
|
if (OverrideSL(pwszValueName, &dw))
|
|
{
|
|
*pdwValue = dw;
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Policy rewrite: %i\r\n", dw);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
WriteProcessMemory(GetCurrentProcess(), _SLGetWindowsInformationDWORD, &Old_SLGetWindowsInformationDWORD, sizeof(FARJMP), &bw);
|
|
Result = _SLGetWindowsInformationDWORD(pwszValueName, pdwValue);
|
|
if (Result == S_OK)
|
|
{
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Policy result: %i\r\n", dw);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
} else {
|
|
WriteToLog("Policy request failed\r\n");
|
|
}
|
|
WriteProcessMemory(GetCurrentProcess(), _SLGetWindowsInformationDWORD, &Stub_SLGetWindowsInformationDWORD, sizeof(FARJMP), &bw);
|
|
|
|
return Result;
|
|
}
|
|
|
|
HRESULT __fastcall New_Win8SL(PWSTR pwszValueName, DWORD *pdwValue)
|
|
{
|
|
// wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll
|
|
// for Windows 8 support
|
|
|
|
// Override SL Policy
|
|
|
|
extern SLGETWINDOWSINFORMATIONDWORD _SLGetWindowsInformationDWORD;
|
|
|
|
char *Log;
|
|
DWORD dw;
|
|
HRESULT Result;
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Policy query: %S\r\n", pwszValueName);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
|
|
if (OverrideSL(pwszValueName, &dw))
|
|
{
|
|
*pdwValue = dw;
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Policy rewrite: %i\r\n", dw);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
Result = _SLGetWindowsInformationDWORD(pwszValueName, pdwValue);
|
|
if (Result == S_OK)
|
|
{
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Policy result: %i\r\n", dw);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
} else {
|
|
WriteToLog("Policy request failed\r\n");
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
#ifndef _WIN64
|
|
HRESULT __fastcall New_Win8SL_CP(DWORD arg1, DWORD *pdwValue, PWSTR pwszValueName, DWORD arg4)
|
|
{
|
|
// wrapped unexported function SLGetWindowsInformationDWORDWrapper in termsrv.dll
|
|
// for Windows 8 Consumer Preview support
|
|
|
|
return New_Win8SL(pwszValueName, pdwValue);
|
|
}
|
|
#endif
|
|
|
|
HRESULT WINAPI New_CSLQuery_Initialize()
|
|
{
|
|
extern PLATFORM_DWORD TermSrvBase;
|
|
extern FILE_VERSION FV;
|
|
|
|
char *Log;
|
|
DWORD *bServerSku = NULL;
|
|
DWORD *bRemoteConnAllowed = NULL;
|
|
DWORD *bFUSEnabled = NULL;
|
|
DWORD *bAppServerAllowed = NULL;
|
|
DWORD *bMultimonAllowed = NULL;
|
|
DWORD *lMaxUserSessions = NULL;
|
|
DWORD *ulMaxDebugSessions = NULL;
|
|
DWORD *bInitialized = NULL;
|
|
|
|
WriteToLog(">>> CSLQuery::Initialize\r\n");
|
|
|
|
char *Sect;
|
|
Sect = new char[256];
|
|
memset(Sect, 0x00, 256);
|
|
wsprintfA(Sect, "%d.%d.%d.%d-SLInit", FV.wVersion.Major, FV.wVersion.Minor, FV.Release, FV.Build);
|
|
|
|
if (IniFile->SectionExists(Sect))
|
|
{
|
|
#ifdef _WIN64
|
|
bServerSku = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bServerSku.x64", 0));
|
|
bRemoteConnAllowed = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bRemoteConnAllowed.x64", 0));
|
|
bFUSEnabled = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bFUSEnabled.x64", 0));
|
|
bAppServerAllowed = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bAppServerAllowed.x64", 0));
|
|
bMultimonAllowed = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bMultimonAllowed.x64", 0));
|
|
lMaxUserSessions = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "lMaxUserSessions.x64", 0));
|
|
ulMaxDebugSessions = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "ulMaxDebugSessions.x64", 0));
|
|
bInitialized = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bInitialized.x64", 0));
|
|
#else
|
|
bServerSku = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bServerSku.x86", 0));
|
|
bRemoteConnAllowed = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bRemoteConnAllowed.x86", 0));
|
|
bFUSEnabled = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bFUSEnabled.x86", 0));
|
|
bAppServerAllowed = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bAppServerAllowed.x86", 0));
|
|
bMultimonAllowed = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bMultimonAllowed.x86", 0));
|
|
lMaxUserSessions = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "lMaxUserSessions.x86", 0));
|
|
ulMaxDebugSessions = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "ulMaxDebugSessions.x86", 0));
|
|
bInitialized = (DWORD*)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "bInitialized.x86", 0));
|
|
#endif
|
|
}
|
|
delete[] Sect;
|
|
|
|
if (bServerSku)
|
|
{
|
|
*bServerSku = INIReadDWordHex(IniFile, "SLInit", "bServerSku", 1);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] bServerSku = %d\r\n", bServerSku, *bServerSku);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
if (bRemoteConnAllowed)
|
|
{
|
|
*bRemoteConnAllowed = INIReadDWordHex(IniFile, "SLInit", "bRemoteConnAllowed", 1);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] bRemoteConnAllowed = %d\r\n", bRemoteConnAllowed, *bRemoteConnAllowed);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
if (bFUSEnabled)
|
|
{
|
|
*bFUSEnabled = INIReadDWordHex(IniFile, "SLInit", "bFUSEnabled", 1);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] bFUSEnabled = %d\r\n", bFUSEnabled, *bFUSEnabled);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
if (bAppServerAllowed)
|
|
{
|
|
*bAppServerAllowed = INIReadDWordHex(IniFile, "SLInit", "bAppServerAllowed", 1);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] bAppServerAllowed = %d\r\n", bAppServerAllowed, *bAppServerAllowed);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
if (bMultimonAllowed)
|
|
{
|
|
*bMultimonAllowed = INIReadDWordHex(IniFile, "SLInit", "bMultimonAllowed", 1);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] bMultimonAllowed = %d\r\n", bMultimonAllowed, *bMultimonAllowed);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
if (lMaxUserSessions)
|
|
{
|
|
*lMaxUserSessions = INIReadDWordHex(IniFile, "SLInit", "lMaxUserSessions", 0);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] lMaxUserSessions = %d\r\n", lMaxUserSessions, *lMaxUserSessions);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
if (ulMaxDebugSessions)
|
|
{
|
|
*ulMaxDebugSessions = INIReadDWordHex(IniFile, "SLInit", "ulMaxDebugSessions", 0);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] ulMaxDebugSessions = %d\r\n", ulMaxDebugSessions, *ulMaxDebugSessions);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
if (bInitialized)
|
|
{
|
|
*bInitialized = INIReadDWordHex(IniFile, "SLInit", "bInitialized", 1);
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "SLInit [0x%p] bInitialized = %d\r\n", bInitialized, *bInitialized);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
}
|
|
WriteToLog("<<< CSLQuery::Initialize\r\n");
|
|
return S_OK;
|
|
}
|
|
|
|
void Hook()
|
|
{
|
|
extern FARJMP Old_SLGetWindowsInformationDWORD, Stub_SLGetWindowsInformationDWORD;
|
|
extern SLGETWINDOWSINFORMATIONDWORD _SLGetWindowsInformationDWORD;
|
|
extern HMODULE hTermSrv;
|
|
extern HMODULE hSLC;
|
|
extern PLATFORM_DWORD TermSrvBase;
|
|
extern FILE_VERSION FV;
|
|
extern wchar_t LogFile[256];
|
|
|
|
AlreadyHooked = true;
|
|
char *Log;
|
|
|
|
wchar_t ConfigFile[256] = { 0x00 };
|
|
WriteToLog("Loading configuration...\r\n");
|
|
|
|
GetModuleFileName(GetCurrentModule(), ConfigFile, 255);
|
|
for (DWORD i = wcslen(ConfigFile); i > 0; i--)
|
|
{
|
|
if (ConfigFile[i] == '\\')
|
|
{
|
|
memset(&ConfigFile[i + 1], 0x00, ((256 - (i + 1))) * 2);
|
|
memcpy(&ConfigFile[i + 1], L"rdpwrap.ini", strlen("rdpwrap.ini") * 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Configuration file: %S\r\n", ConfigFile);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
|
|
IniFile = new INI_FILE(ConfigFile);
|
|
// TODO: implement this
|
|
if (IniFile == NULL)
|
|
{
|
|
WriteToLog("Error: Failed to load configuration\r\n");
|
|
return;
|
|
}
|
|
|
|
INI_VAR_STRING LogFileVar;
|
|
|
|
if(!(IniFile->GetVariableInSection("Main", "LogFile", &LogFileVar)))
|
|
{
|
|
GetModuleFileName(GetCurrentModule(), LogFile, 255);
|
|
for(DWORD i = wcslen(LogFile); i > 0; i--)
|
|
{
|
|
if(LogFile[i] == '\\')
|
|
{
|
|
memset(&LogFile[i+1], 0x00, ((256-(i+1)))*2);
|
|
memcpy(&LogFile[i+1], L"rdpwrap.txt", strlen("rdpwrap.txt")*2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: Change it before add UNICODE in IniFile
|
|
wchar_t wcLogFile[256];
|
|
memset(wcLogFile, 0x00, 256);
|
|
mbstowcs(wcLogFile, LogFileVar.Value, 255);
|
|
wcscpy(LogFile, wcLogFile);
|
|
}
|
|
|
|
SIZE_T bw;
|
|
WORD Ver = 0;
|
|
PLATFORM_DWORD TermSrvSize, SignPtr;
|
|
FARJMP Jump;
|
|
|
|
WriteToLog("Initializing RDP Wrapper...\r\n");
|
|
|
|
hTermSrv = LoadLibrary(L"termsrv.dll");
|
|
if (hTermSrv == 0)
|
|
{
|
|
WriteToLog("Error: Failed to load Terminal Services library\r\n");
|
|
return;
|
|
}
|
|
_ServiceMain = (SERVICEMAIN)GetProcAddress(hTermSrv, "ServiceMain");
|
|
_SvchostPushServiceGlobals = (SVCHOSTPUSHSERVICEGLOBALS)GetProcAddress(hTermSrv, "SvchostPushServiceGlobals");
|
|
|
|
Log = new char[4096];
|
|
wsprintfA(Log,
|
|
"Base addr: 0x%p\r\n"
|
|
"SvcMain: termsrv.dll+0x%p\r\n"
|
|
"SvcGlobals: termsrv.dll+0x%p\r\n",
|
|
hTermSrv,
|
|
(PLATFORM_DWORD)_ServiceMain - (PLATFORM_DWORD)hTermSrv,
|
|
(PLATFORM_DWORD)_SvchostPushServiceGlobals - (PLATFORM_DWORD)hTermSrv);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
|
|
// check termsrv version
|
|
if (GetModuleVersion(L"termsrv.dll", &FV))
|
|
{
|
|
Ver = (BYTE)FV.wVersion.Minor | ((BYTE)FV.wVersion.Major << 8);
|
|
} else {
|
|
// check NT version
|
|
// Ver = GetVersion(); // deprecated
|
|
// Ver = ((Ver & 0xFF) << 8) | ((Ver & 0xFF00) >> 8);
|
|
}
|
|
if (Ver == 0)
|
|
{
|
|
WriteToLog("Error: Failed to detect Terminal Services version\r\n");
|
|
return;
|
|
}
|
|
|
|
Log = new char[1024];
|
|
wsprintfA(Log, "Version: %d.%d.%d.%d\r\n", FV.wVersion.Major, FV.wVersion.Minor, FV.Release, FV.Build);
|
|
WriteToLog(Log);
|
|
delete[] Log;
|
|
|
|
// temporarily freeze threads
|
|
WriteToLog("Freezing threads...\r\n");
|
|
SetThreadsState(false);
|
|
|
|
bool Bool;
|
|
if (!(IniFile->GetVariableInSection("Main", "SLPolicyHookNT60", &Bool))) Bool = true;
|
|
|
|
if ((Ver == 0x0600) && Bool)
|
|
{
|
|
// Windows Vista
|
|
// uses SL Policy API (slc.dll)
|
|
|
|
// load slc.dll and hook function
|
|
hSLC = LoadLibrary(L"slc.dll");
|
|
_SLGetWindowsInformationDWORD = (SLGETWINDOWSINFORMATIONDWORD)GetProcAddress(hSLC, "SLGetWindowsInformationDWORD");
|
|
if (_SLGetWindowsInformationDWORD != INVALID_HANDLE_VALUE)
|
|
{
|
|
// rewrite original function to call our function (make hook)
|
|
|
|
WriteToLog("Hook SLGetWindowsInformationDWORD\r\n");
|
|
#ifdef _WIN64
|
|
Stub_SLGetWindowsInformationDWORD.MovOp = 0x48;
|
|
Stub_SLGetWindowsInformationDWORD.MovRegArg = 0xB8;
|
|
Stub_SLGetWindowsInformationDWORD.MovArg = (PLATFORM_DWORD)New_SLGetWindowsInformationDWORD;
|
|
Stub_SLGetWindowsInformationDWORD.PushRaxOp = 0x50;
|
|
Stub_SLGetWindowsInformationDWORD.RetOp = 0xC3;
|
|
#else
|
|
Stub_SLGetWindowsInformationDWORD.PushOp = 0x68;
|
|
Stub_SLGetWindowsInformationDWORD.PushArg = (PLATFORM_DWORD)New_SLGetWindowsInformationDWORD;
|
|
Stub_SLGetWindowsInformationDWORD.RetOp = 0xC3;
|
|
#endif
|
|
|
|
ReadProcessMemory(GetCurrentProcess(), _SLGetWindowsInformationDWORD, &Old_SLGetWindowsInformationDWORD, sizeof(FARJMP), &bw);
|
|
WriteProcessMemory(GetCurrentProcess(), _SLGetWindowsInformationDWORD, &Stub_SLGetWindowsInformationDWORD, sizeof(FARJMP), &bw);
|
|
}
|
|
}
|
|
|
|
if (!(IniFile->GetVariableInSection("Main", "SLPolicyHookNT61", &Bool))) Bool = true;
|
|
|
|
if ((Ver == 0x0601) && Bool)
|
|
{
|
|
// Windows 7
|
|
// uses SL Policy API (slc.dll)
|
|
|
|
// load slc.dll and hook function
|
|
hSLC = LoadLibrary(L"slc.dll");
|
|
_SLGetWindowsInformationDWORD = (SLGETWINDOWSINFORMATIONDWORD)GetProcAddress(hSLC, "SLGetWindowsInformationDWORD");
|
|
if (_SLGetWindowsInformationDWORD != INVALID_HANDLE_VALUE)
|
|
{
|
|
// rewrite original function to call our function (make hook)
|
|
|
|
WriteToLog("Hook SLGetWindowsInformationDWORD\r\n");
|
|
#ifdef _WIN64
|
|
Stub_SLGetWindowsInformationDWORD.MovOp = 0x48;
|
|
Stub_SLGetWindowsInformationDWORD.MovRegArg = 0xB8;
|
|
Stub_SLGetWindowsInformationDWORD.MovArg = (PLATFORM_DWORD)New_SLGetWindowsInformationDWORD;
|
|
Stub_SLGetWindowsInformationDWORD.PushRaxOp = 0x50;
|
|
Stub_SLGetWindowsInformationDWORD.RetOp = 0xC3;
|
|
#else
|
|
Stub_SLGetWindowsInformationDWORD.PushOp = 0x68;
|
|
Stub_SLGetWindowsInformationDWORD.PushArg = (PLATFORM_DWORD)New_SLGetWindowsInformationDWORD;
|
|
Stub_SLGetWindowsInformationDWORD.RetOp = 0xC3;
|
|
#endif
|
|
|
|
ReadProcessMemory(GetCurrentProcess(), _SLGetWindowsInformationDWORD, &Old_SLGetWindowsInformationDWORD, sizeof(FARJMP), &bw);
|
|
WriteProcessMemory(GetCurrentProcess(), _SLGetWindowsInformationDWORD, &Stub_SLGetWindowsInformationDWORD, sizeof(FARJMP), &bw);
|
|
}
|
|
}
|
|
if (Ver == 0x0602)
|
|
{
|
|
// Windows 8
|
|
// uses SL Policy internal unexported function
|
|
|
|
// load slc.dll and get function
|
|
// (will be used on intercepting undefined values)
|
|
hSLC = LoadLibrary(L"slc.dll");
|
|
_SLGetWindowsInformationDWORD = (SLGETWINDOWSINFORMATIONDWORD)GetProcAddress(hSLC, "SLGetWindowsInformationDWORD");
|
|
}
|
|
if (Ver == 0x0603)
|
|
{
|
|
// Windows 8.1
|
|
// uses SL Policy internal inline code
|
|
}
|
|
if (Ver == 0x0604)
|
|
{
|
|
// Windows 10
|
|
// uses SL Policy internal inline code
|
|
}
|
|
|
|
char *Sect;
|
|
INI_VAR_STRING PatchName;
|
|
INI_VAR_BYTEARRAY Patch;
|
|
Sect = new char[256];
|
|
memset(Sect, 0x00, 256);
|
|
wsprintfA(Sect, "%d.%d.%d.%d", FV.wVersion.Major, FV.wVersion.Minor, FV.Release, FV.Build);
|
|
|
|
if (IniFile->SectionExists(Sect))
|
|
{
|
|
if (GetModuleCodeSectionInfo(hTermSrv, &TermSrvBase, &TermSrvSize))
|
|
{
|
|
#ifdef _WIN64
|
|
if (!(IniFile->GetVariableInSection(Sect, "LocalOnlyPatch.x64", &Bool))) Bool = false;
|
|
#else
|
|
if (!(IniFile->GetVariableInSection(Sect, "LocalOnlyPatch.x86", &Bool))) Bool = false;
|
|
#endif
|
|
if (Bool)
|
|
{
|
|
WriteToLog("Patch CEnforcementCore::GetInstanceOfTSLicense\r\n");
|
|
Bool = false;
|
|
#ifdef _WIN64
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "LocalOnlyOffset.x64", 0));
|
|
Bool = IniFile->GetVariableInSection(Sect, "LocalOnlyCode.x64", &PatchName);
|
|
#else
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "LocalOnlyOffset.x86", 0));
|
|
Bool = IniFile->GetVariableInSection(Sect, "LocalOnlyCode.x86", &PatchName);
|
|
#endif
|
|
if (Bool) Bool = IniFile->GetVariableInSection("PatchCodes", PatchName.Value, &Patch);
|
|
if (Bool && (SignPtr > TermSrvBase)) WriteProcessMemory(GetCurrentProcess(), (LPVOID)SignPtr, Patch.Value, Patch.ArraySize, &bw);
|
|
}
|
|
#ifdef _WIN64
|
|
if (!(IniFile->GetVariableInSection(Sect, "SingleUserPatch.x64", &Bool))) Bool = false;
|
|
#else
|
|
if (!(IniFile->GetVariableInSection(Sect, "SingleUserPatch.x86", &Bool))) Bool = false;
|
|
#endif
|
|
if (Bool)
|
|
{
|
|
WriteToLog("Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled\r\n");
|
|
Bool = false;
|
|
#ifdef _WIN64
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "SingleUserOffset.x64", 0));
|
|
Bool = IniFile->GetVariableInSection(Sect, "SingleUserCode.x64", &PatchName);
|
|
#else
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "SingleUserOffset.x86", 0));
|
|
Bool = IniFile->GetVariableInSection(Sect, "SingleUserCode.x86", &PatchName);
|
|
#endif
|
|
if (Bool) Bool = IniFile->GetVariableInSection("PatchCodes", PatchName.Value, &Patch);
|
|
if (Bool && (SignPtr > TermSrvBase)) WriteProcessMemory(GetCurrentProcess(), (LPVOID)SignPtr, Patch.Value, Patch.ArraySize, &bw);
|
|
}
|
|
#ifdef _WIN64
|
|
if (!(IniFile->GetVariableInSection(Sect, "DefPolicyPatch.x64", &Bool))) Bool = false;
|
|
#else
|
|
if (!(IniFile->GetVariableInSection(Sect, "DefPolicyPatch.x86", &Bool))) Bool = false;
|
|
#endif
|
|
if (Bool)
|
|
{
|
|
WriteToLog("Patch CDefPolicy::Query\r\n");
|
|
Bool = false;
|
|
#ifdef _WIN64
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "DefPolicyOffset.x64", 0));
|
|
Bool = IniFile->GetVariableInSection(Sect, "DefPolicyCode.x64", &PatchName);
|
|
#else
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "DefPolicyOffset.x86", 0));
|
|
Bool = IniFile->GetVariableInSection(Sect, "DefPolicyCode.x86", &PatchName);
|
|
#endif
|
|
if (Bool) Bool = IniFile->GetVariableInSection("PatchCodes", PatchName.Value, &Patch);
|
|
if (Bool && (SignPtr > TermSrvBase)) WriteProcessMemory(GetCurrentProcess(), (LPVOID)SignPtr, Patch.Value, Patch.ArraySize, &bw);
|
|
}
|
|
#ifdef _WIN64
|
|
if (!(IniFile->GetVariableInSection(Sect, "SLPolicyInternal.x64", &Bool))) Bool = false;
|
|
#else
|
|
if (!(IniFile->GetVariableInSection(Sect, "SLPolicyInternal.x86", &Bool))) Bool = false;
|
|
#endif
|
|
if (Bool)
|
|
{
|
|
WriteToLog("Hook SLGetWindowsInformationDWORDWrapper\r\n");
|
|
char *FuncName;
|
|
FuncName = new char[1024];
|
|
#ifdef _WIN64
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "SLPolicyOffset.x64", 0));
|
|
Jump.MovOp = 0x48;
|
|
Jump.MovRegArg = 0xB8;
|
|
Jump.MovArg = (PLATFORM_DWORD)New_Win8SL;
|
|
Jump.PushRaxOp = 0x50;
|
|
Jump.RetOp = 0xC3;
|
|
|
|
INIReadString(IniFile, Sect, "SLPolicyFunc.x64", "New_Win8SL", FuncName, 1024);
|
|
|
|
if (strcmp(FuncName, "New_Win8SL"))
|
|
{
|
|
Jump.MovArg = (PLATFORM_DWORD)New_Win8SL;
|
|
}
|
|
#else
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "SLPolicyOffset.x86", 0));
|
|
Jump.PushOp = 0x68;
|
|
Jump.PushArg = (PLATFORM_DWORD)New_Win8SL;
|
|
Jump.RetOp = 0xC3;
|
|
|
|
INIReadString(IniFile, Sect, "SLPolicyFunc.x86", "New_Win8SL", FuncName, 1024);
|
|
|
|
if (strcmp(FuncName, "New_Win8SL"))
|
|
{
|
|
Jump.PushArg = (PLATFORM_DWORD)New_Win8SL;
|
|
}
|
|
if (strcmp(FuncName, "New_Win8SL_CP"))
|
|
{
|
|
Jump.PushArg = (PLATFORM_DWORD)New_Win8SL_CP;
|
|
}
|
|
#endif
|
|
delete[] FuncName;
|
|
if (SignPtr > TermSrvBase) WriteProcessMemory(GetCurrentProcess(), (LPVOID)SignPtr, &Jump, sizeof(FARJMP), &bw);
|
|
}
|
|
#ifdef _WIN64
|
|
if (!(IniFile->GetVariableInSection(Sect, "SLInitHook.x64", &Bool))) Bool = false;
|
|
#else
|
|
if (!(IniFile->GetVariableInSection(Sect, "SLInitHook.x86", &Bool))) Bool = false;
|
|
#endif
|
|
if (Bool)
|
|
{
|
|
WriteToLog("Hook CSLQuery::Initialize\r\n");
|
|
char *FuncName;
|
|
FuncName = new char[1024];
|
|
#ifdef _WIN64
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "SLInitOffset.x64", 0));
|
|
Jump.MovOp = 0x48;
|
|
Jump.MovRegArg = 0xB8;
|
|
Jump.MovArg = (PLATFORM_DWORD)New_CSLQuery_Initialize;
|
|
Jump.PushRaxOp = 0x50;
|
|
Jump.RetOp = 0xC3;
|
|
|
|
INIReadString(IniFile, Sect, "SLInitFunc.x64", "New_CSLQuery_Initialize", FuncName, 1024);
|
|
|
|
if (strcmp(FuncName, "New_CSLQuery_Initialize"))
|
|
{
|
|
Jump.MovArg = (PLATFORM_DWORD)New_CSLQuery_Initialize;
|
|
}
|
|
#else
|
|
SignPtr = (PLATFORM_DWORD)(TermSrvBase + INIReadDWordHex(IniFile, Sect, "SLInitOffset.x86", 0));
|
|
Jump.PushOp = 0x68;
|
|
Jump.PushArg = (PLATFORM_DWORD)New_CSLQuery_Initialize;
|
|
Jump.RetOp = 0xC3;
|
|
|
|
INIReadString(IniFile, Sect, "SLInitFunc.x86", "New_CSLQuery_Initialize", FuncName, 1024);
|
|
|
|
if (strcmp(FuncName, "New_CSLQuery_Initialize"))
|
|
{
|
|
Jump.PushArg = (PLATFORM_DWORD)New_CSLQuery_Initialize;
|
|
}
|
|
#endif
|
|
delete[] FuncName;
|
|
if (SignPtr > TermSrvBase) WriteProcessMemory(GetCurrentProcess(), (LPVOID)SignPtr, &Jump, sizeof(FARJMP), &bw);
|
|
}
|
|
}
|
|
}
|
|
delete[] Sect;
|
|
|
|
WriteToLog("Resumimg threads...\r\n");
|
|
SetThreadsState(true);
|
|
return;
|
|
}
|
|
|
|
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
|
|
{
|
|
WriteToLog(">>> ServiceMain\r\n");
|
|
if (!AlreadyHooked) Hook();
|
|
|
|
if (_ServiceMain != NULL) _ServiceMain(dwArgc, lpszArgv);
|
|
WriteToLog("<<< ServiceMain\r\n");
|
|
}
|
|
|
|
void WINAPI SvchostPushServiceGlobals(void *lpGlobalData)
|
|
{
|
|
WriteToLog(">>> SvchostPushServiceGlobals\r\n");
|
|
if (!AlreadyHooked) Hook();
|
|
|
|
if (_SvchostPushServiceGlobals != NULL) _SvchostPushServiceGlobals(lpGlobalData);
|
|
WriteToLog("<<< SvchostPushServiceGlobals\r\n");
|
|
}
|