BSOne.SFC/Tocsg.Module/RemoteSecu/EXE_RemoteSecuClient/ManagerRdpSecu.pas

460 lines
11 KiB
Plaintext
Raw Blame History

{*******************************************************}
{ }
{ 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.