460 lines
11 KiB
Plaintext
460 lines
11 KiB
Plaintext
{*******************************************************}
|
||
{ }
|
||
{ ManagerRdpSecu }
|
||
{ }
|
||
{ Copyright (C) 2022 kku }
|
||
{ }
|
||
{*******************************************************}
|
||
|
||
unit ManagerRdpSecu;
|
||
|
||
interface
|
||
|
||
uses
|
||
System.SysUtils, System.Classes, Winapi.Windows, Tocsg.Obj, Tocsg.Thread,
|
||
Winapi.Messages;
|
||
|
||
const
|
||
WM_RDPSECU_LOG = WM_USER + 6483;
|
||
|
||
REG_RDP_PORT = 'SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp';
|
||
NAME_RDPSVC = 'TermService';
|
||
NAME_RDPRSVC = 'UmRdpService';
|
||
|
||
type
|
||
TManagerRdpSecu = class;
|
||
TThdPreventRdp = class(TTgThread)
|
||
protected
|
||
MgRdp_: TManagerRdpSecu;
|
||
procedure Execute; override;
|
||
public
|
||
Constructor Create(aMgRdp: TManagerRdpSecu);
|
||
end;
|
||
|
||
TRdpSecuState = (rssNone, rssRqPrevent, rssPrevent, rssOpenRdp, rssFail);
|
||
TManagerRdpSecu = class(TTgObject)
|
||
private
|
||
hRcvWnd_: HWND;
|
||
nRdpPort_: Integer;
|
||
State_: TRdpSecuState;
|
||
ThdPrevent_: TThdPreventRdp;
|
||
procedure SetRdpSecuState(aState: TRdpSecuState);
|
||
procedure Log(sLog: String); overload;
|
||
procedure Log(sFormat: String; const Args: array of const); overload;
|
||
public
|
||
Constructor Create(hRcvWnd: HWND);
|
||
Destructor Destroy; override;
|
||
|
||
function OpenSafeRdp: Boolean;
|
||
function CloseSafeRdp: Boolean;
|
||
|
||
property State: TRdpSecuState read State_ write SetRdpSecuState;
|
||
property RdpPort: Integer read nRdpPort_;
|
||
end;
|
||
|
||
function GetRdpPort: Integer; inline;
|
||
function PreventRdp: Boolean;
|
||
|
||
implementation
|
||
|
||
uses
|
||
Tocsg.Registry, System.IniFiles, Tocsg.Safe, Tocsg.Firewall, NetFwTypeLib_TLB,
|
||
Tocsg.Path, Tocsg.Trace, Winapi.WinSvc, Tocsg.Service, Tocsg.Process,
|
||
IdTCPClient, Tocsg.Exception, Winapi.ActiveX;
|
||
|
||
function GetRandomPort(bCheck: Boolean = true): Integer;
|
||
var
|
||
CheckClt: TIdTCPClient;
|
||
begin
|
||
Randomize;
|
||
Result := Random(30000) + 30000;
|
||
|
||
if bCheck then
|
||
begin
|
||
Guard(CheckClt, TIdTCPClient.Create(nil));
|
||
CheckClt.ConnectTimeout := 1000;
|
||
CheckClt.ReadTimeout := 1000;
|
||
while True do
|
||
begin
|
||
if Result > 65000 then
|
||
begin
|
||
Result := 0;
|
||
exit;
|
||
end;
|
||
|
||
try
|
||
CheckClt.Connect('127.0.0.1', Result);
|
||
CheckClt.Disconnect;
|
||
except
|
||
exit;
|
||
end;
|
||
|
||
Inc(Result);
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function GetRdpPort: Integer; inline;
|
||
begin
|
||
Result := GetRegValueAsInteger(HKEY_LOCAL_MACHINE, REG_RDP_PORT, 'PortNumber');
|
||
end;
|
||
|
||
procedure RecoveryRdpSetting;
|
||
var
|
||
nPort, nOldPort: Integer;
|
||
ini: TIniFile;
|
||
dwPid: DWORD;
|
||
begin
|
||
try
|
||
nPort := GetRdpPort;
|
||
RemoveFwRule(Format('RSecu-I%d', [nPort]));
|
||
|
||
Guard(ini, TIniFile.Create(CutFileExt(GetRunExePath) + '.ini'));
|
||
nOldPort := ini.ReadInteger('Setting', 'RecoverPort', 0);
|
||
if (nOldPort = 0) or (nPort = nOldPort) then
|
||
begin
|
||
ServiceStart(NAME_RDPSVC);
|
||
ini.WriteInteger('Setting', 'RecoverPort', 0);
|
||
TTgTrace.T('RecoveryRdpSetting() .. <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
nPort := nOldPort;
|
||
|
||
if not ServiceExists(NAME_RDPSVC) then
|
||
begin
|
||
TTgTrace.T('RecoveryRdpSetting() .. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
|
||
dwPid := GetSerivcePid(NAME_RDPSVC);
|
||
if dwPid <> 0 then
|
||
begin
|
||
if TerminateProcessByPid(dwPid, true) then
|
||
begin
|
||
ServiceStop(NAME_RDPRSVC);
|
||
Sleep(500);
|
||
if not ServiceStop(NAME_RDPSVC, 3) then
|
||
exit;
|
||
Sleep(500);
|
||
end;
|
||
end;
|
||
|
||
SetRegValueInteger(HKEY_LOCAL_MACHINE, REG_RDP_PORT, 'PortNumber', nPort);
|
||
if ServiceStart(NAME_RDPSVC) or
|
||
(GetServiceStatus(NAME_RDPSVC) = SERVICE_RUNNING) then
|
||
begin
|
||
ini.WriteInteger('Setting', 'RecoverPort', 0);
|
||
TTgTrace.T('RecoveryRdpSetting() .. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (%d)', [nPort]);
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(E, 'Fail .. RecoveryRdpSetting()');
|
||
end;
|
||
end;
|
||
|
||
function PreventRdp: Boolean;
|
||
var
|
||
nPort, nOldPort: Integer;
|
||
ini: TIniFile;
|
||
dwPid: DWORD;
|
||
FwRule: TFwRule;
|
||
begin
|
||
Result := false;
|
||
try
|
||
RemoveFwRule(Format('RSecu-I%d', [GetRdpPort]));
|
||
|
||
if not ServiceExists(NAME_RDPSVC) then
|
||
begin
|
||
TTgTrace.T('PreventRdp() .. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
|
||
dwPid := GetSerivcePid(NAME_RDPSVC);
|
||
if dwPid <> 0 then
|
||
begin
|
||
if TerminateProcessByPid(dwPid, true) then
|
||
begin
|
||
if not ServiceStop(NAME_RDPRSVC) then
|
||
begin
|
||
TTgTrace.T('PreventRdp() .. Fail .. Stop SVC2');
|
||
exit;
|
||
end;
|
||
Sleep(500);
|
||
if not ServiceStop(NAME_RDPSVC, 3) then
|
||
begin
|
||
TTgTrace.T('PreventRdp() .. Fail .. Stop SVC');
|
||
exit;
|
||
end;
|
||
Result := true;
|
||
end else
|
||
TTgTrace.T('PreventRdp() .. Fail .. Terminate SVC PID=%d', [dwPid]);
|
||
end else Result := true;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(E, 'Fail .. PreventRdp()');
|
||
end;
|
||
end;
|
||
|
||
function OpenRdpSecu: Integer;
|
||
var
|
||
nPort, nOldPort: Integer;
|
||
ini: TIniFile;
|
||
dwPid: DWORD;
|
||
FwRule: TFwRule;
|
||
begin
|
||
Result := -1;
|
||
|
||
try
|
||
nPort := GetRdpPort;
|
||
ASSERT(nPort <> 0);
|
||
|
||
Guard(ini, TIniFile.Create(CutFileExt(GetRunExePath) + '.ini'));
|
||
nOldPort := ini.ReadInteger('Setting', 'RecoverPort', 0);
|
||
if (nOldPort <> 0) and (nOldPort <> nPort) then
|
||
begin
|
||
TTgTrace.T('OpenRdpSecu() .. <20>̹<EFBFBD> <20><><EFBFBD><EFBFBD> <20><>');
|
||
exit;
|
||
end;
|
||
ini.WriteInteger('Setting', 'RecoverPort', nPort);
|
||
|
||
nPort := GetRandomPort;
|
||
if nPort = 0 then
|
||
begin
|
||
TTgTrace.T('OpenRdpSecu() .. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>Ʈ <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
|
||
if not ServiceExists(NAME_RDPSVC) then
|
||
begin
|
||
TTgTrace.T('OpenRdpSecu() .. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
|
||
dwPid := GetSerivcePid(NAME_RDPSVC);
|
||
if dwPid = 0 then
|
||
begin
|
||
TTgTrace.T('OpenRdpSecu() .. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>μ<EFBFBD><CEBC><EFBFBD> <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
|
||
if TerminateProcessByPid(dwPid, true) then
|
||
begin
|
||
ServiceStop(NAME_RDPRSVC);
|
||
Sleep(500);
|
||
if not ServiceStop(NAME_RDPSVC, 3) then
|
||
exit;
|
||
Sleep(500);
|
||
|
||
SetRegValueInteger(HKEY_LOCAL_MACHINE, REG_RDP_PORT, 'PortNumber', nPort);
|
||
if ServiceStart(NAME_RDPSVC) or
|
||
(GetServiceStatus(NAME_RDPSVC) = SERVICE_RUNNING) then
|
||
begin
|
||
ZeroMemory(@FwRule, SizeOf(FwRule));
|
||
with FwRule do
|
||
begin
|
||
sName := Format('RSecu-I%d', [nPort]);
|
||
sGroup := 'ToCSG';
|
||
sDesc := 'RdpSecu by ToCSG';
|
||
sLocalPorts := IntToStr(nPort);
|
||
nProtocol := NET_FW_IP_PROTOCOL_TCP;
|
||
nProfiles := FW_PROFILE_ANY;
|
||
nAction := NET_FW_ACTION_ALLOW;
|
||
nDirection := NET_FW_RULE_DIR_IN;
|
||
bEnabled := true;
|
||
end;
|
||
AddFwRule(FwRule);
|
||
TTgTrace.T('OpenRdpSecu() .. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (%d)', [nPort]);
|
||
end;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(E, 'Fail .. OpenRdpSecu()');
|
||
end;
|
||
end;
|
||
|
||
{ TThdPreventRdp }
|
||
|
||
Constructor TThdPreventRdp.Create(aMgRdp: TManagerRdpSecu);
|
||
begin
|
||
Inherited Create;
|
||
MgRdp_ := aMgRdp;
|
||
end;
|
||
|
||
procedure TThdPreventRdp.Execute;
|
||
begin
|
||
CoInitialize(nil);
|
||
try
|
||
while not Terminated and not GetWorkStop do
|
||
begin
|
||
if GetServiceStatus(NAME_RDPSVC) = SERVICE_RUNNING then
|
||
begin
|
||
if PreventRdp then
|
||
MgRdp_.SetRdpSecuState(rssPrevent)
|
||
else
|
||
MgRdp_.SetRdpSecuState(rssFail);
|
||
end else
|
||
MgRdp_.SetRdpSecuState(rssPrevent);
|
||
Sleep(1000);
|
||
end;
|
||
finally
|
||
CoUninitialize;
|
||
end;
|
||
end;
|
||
|
||
{ TManagerRdpSecu }
|
||
|
||
Constructor TManagerRdpSecu.Create(hRcvWnd: HWND);
|
||
begin
|
||
Inherited Create;
|
||
hRcvWnd_ := hRcvWnd;
|
||
State_ := rssNone;
|
||
nRdpPort_ := GetRdpPort;
|
||
ThdPrevent_ := nil;
|
||
CoInitialize(nil);
|
||
end;
|
||
|
||
Destructor TManagerRdpSecu.Destroy;
|
||
begin
|
||
if ThdPrevent_ <> nil then
|
||
FreeAndNil(ThdPrevent_);
|
||
RecoveryRdpSetting;
|
||
CoUninitialize;
|
||
Inherited;
|
||
end;
|
||
|
||
procedure TManagerRdpSecu.Log(sLog: String);
|
||
begin
|
||
if hRcvWnd_ <> 0 then
|
||
SendMessage(hRcvWnd_, WM_RDPSECU_LOG, 0, NativeUInt(PChar(sLog)));
|
||
end;
|
||
|
||
procedure TManagerRdpSecu.Log(sFormat: String; const Args: array of const);
|
||
var
|
||
str: String;
|
||
begin
|
||
FmtStr(str, sFormat, Args);
|
||
Log(str);
|
||
end;
|
||
|
||
procedure TManagerRdpSecu.SetRdpSecuState(aState: TRdpSecuState);
|
||
begin
|
||
if State_ = aState then
|
||
exit;
|
||
State_ := aState;
|
||
|
||
case aState of
|
||
rssNone :
|
||
begin
|
||
if ThdPrevent_ <> nil then
|
||
FreeAndNil(ThdPrevent_);
|
||
RecoveryRdpSetting;
|
||
nRdpPort_ := GetRdpPort;
|
||
Log('RDP<44><50><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>.');
|
||
end;
|
||
rssRqPrevent :
|
||
begin
|
||
if ThdPrevent_ = nil then
|
||
begin
|
||
ThdPrevent_ := TThdPreventRdp.Create(Self);
|
||
ThdPrevent_.StartThread;
|
||
end;
|
||
end;
|
||
rssPrevent : Log('RDP<44><50><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>.');
|
||
rssOpenRdp :
|
||
begin
|
||
nRdpPort_ := GetRdpPort;
|
||
Log('RDP<44><50><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>û <20>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>.');
|
||
end;
|
||
rssFail : Log('RDP<44><50><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>߽<EFBFBD><DFBD>ϴ<EFBFBD>..');
|
||
end;
|
||
end;
|
||
|
||
function TManagerRdpSecu.OpenSafeRdp: Boolean;
|
||
var
|
||
nPort: Integer;
|
||
ini: TIniFile;
|
||
dwPid: DWORD;
|
||
FwRule: TFwRule;
|
||
PreState: TRdpSecuState;
|
||
begin
|
||
Result := false;
|
||
|
||
try
|
||
Guard(ini, TIniFile.Create(CutFileExt(GetRunExePath) + '.ini'));
|
||
nPort := ini.ReadInteger('Setting', 'RecoverPort', 0);
|
||
if nPort = 0 then
|
||
ini.WriteInteger('Setting', 'RecoverPort', GetRdpPort);
|
||
|
||
nPort := GetRandomPort;
|
||
if nPort = 0 then
|
||
begin
|
||
TTgTrace.T('OpenRdpSecu() .. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>Ʈ <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
|
||
if not ServiceExists(NAME_RDPSVC) then
|
||
begin
|
||
TTgTrace.T('OpenRdpSecu() .. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>');
|
||
exit;
|
||
end;
|
||
|
||
PreState := State_;
|
||
if ThdPrevent_ <> nil then
|
||
FreeAndNil(ThdPrevent_);
|
||
|
||
dwPid := GetSerivcePid(NAME_RDPSVC);
|
||
if dwPid <> 0 then
|
||
begin
|
||
if TerminateProcessByPid(dwPid, true) then
|
||
begin
|
||
ServiceStop(NAME_RDPRSVC);
|
||
Sleep(500);
|
||
if not ServiceStop(NAME_RDPSVC, 3) then
|
||
exit;
|
||
Sleep(500);
|
||
end;
|
||
end;
|
||
|
||
SetRegValueInteger(HKEY_LOCAL_MACHINE, REG_RDP_PORT, 'PortNumber', nPort);
|
||
if ServiceStart(NAME_RDPSVC) or
|
||
(GetServiceStatus(NAME_RDPSVC) = SERVICE_RUNNING) then
|
||
begin
|
||
ZeroMemory(@FwRule, SizeOf(FwRule));
|
||
with FwRule do
|
||
begin
|
||
sName := Format('RSecu-I%d', [nPort]);
|
||
sGroup := 'ToCSG';
|
||
sDesc := 'RdpSecu by ToCSG';
|
||
sLocalPorts := IntToStr(nPort);
|
||
nProtocol := NET_FW_IP_PROTOCOL_TCP;
|
||
nProfiles := FW_PROFILE_ANY;
|
||
nAction := NET_FW_ACTION_ALLOW;
|
||
nDirection := NET_FW_RULE_DIR_IN;
|
||
bEnabled := true;
|
||
end;
|
||
AddFwRule(FwRule);
|
||
TTgTrace.T('OpenRdpSecu() .. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (%d)', [nPort]);
|
||
SetRdpSecuState(rssOpenRdp);
|
||
Result := true;
|
||
end;
|
||
|
||
if not Result and (PreState = rssPrevent) then
|
||
SetRdpSecuState(rssRqPrevent);
|
||
except
|
||
on E: Exception do
|
||
ETgException.TraceException(E, 'Fail .. OpenRdpSecu()');
|
||
end;
|
||
end;
|
||
|
||
function TManagerRdpSecu.CloseSafeRdp: Boolean;
|
||
begin
|
||
Result := false;
|
||
if State_ = rssOpenRdp then
|
||
begin
|
||
SetRdpSecuState(rssRqPrevent);
|
||
Result := true;
|
||
end;
|
||
end;
|
||
|
||
end.
|