894 lines
25 KiB
Plaintext
894 lines
25 KiB
Plaintext
unit bs1DeviceControl;
|
|
|
|
interface
|
|
|
|
uses
|
|
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, ShellAPI, Vcl.Graphics, System.StrUtils,
|
|
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, SuperObject,
|
|
System.Generics.Collections, DefineHelper, GlobalDefine, Bs1FltCtrl, bs1PolicyUnit, DataFlowSettingForm, Bs1MadHookInject,
|
|
MessageBoxFrom, DeviceGuard.Logic;
|
|
|
|
const
|
|
// 윈도우 장치 변경 메시지 상수
|
|
DBT_DEVNODES_CHANGED = $0007;
|
|
WM_DEVICECHANGE = $0219;
|
|
|
|
// 편의상 GUID 상수를 여기에 정의 (혹은 Logic 유닛 상수를 써도 됨)
|
|
GUID_DEVCLASS_USB = '{36fc9e60-c465-11cf-8056-444553540000}';
|
|
GUID_DEVCLASS_PORTS = '{4d36e978-e325-11ce-bfc1-08002be10318}';
|
|
GUID_DEVCLASS_MODEM = '{4d36e96d-e325-11ce-bfc1-08002be10318}';
|
|
GUID_DEVCLASS_BLUETOOTH = '{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}';
|
|
GUID_DEVCLASS_NET = '{4d36e972-e325-11ce-bfc1-08002be10318}';
|
|
GUID_DEVCLASS_INFRARED = '{6bdd1fc5-810f-11d0-bec7-08002be2092f}';
|
|
GUID_DEVCLASS_1394 = '{6bdd1fc1-810f-11d0-bec7-08002be2092f}';
|
|
GUID_DEVCLASS_PCMCIA = '{4d36e977-e325-11ce-bfc1-08002be10318}';
|
|
GUID_DEVCLASS_WPD = '{eec5ad98-8080-425f-922a-dabf3de3f69a}';
|
|
GUID_DEVCLASS_DISKDRIVE = '{4d36e967-e325-11ce-bfc1-08002be10318}';
|
|
|
|
WM_REFRESH_VIEW = WM_USER + 3951;
|
|
WM_POPUP_MSG2 = WM_REFRESH_VIEW + 1;
|
|
type
|
|
TScrollablePanel = class(TPanel)
|
|
public
|
|
property OnMouseWheel;
|
|
end;
|
|
|
|
TUIItem = class
|
|
public
|
|
Panel: TPanel;
|
|
RgControl: TRadioGroup;
|
|
RgLog: TRadioGroup;
|
|
Flag: DWORD;
|
|
constructor Create(APanel: TPanel; ARgControl, ARgLog: TRadioGroup; AFlag: DWORD);
|
|
end;
|
|
|
|
TForm1 = class(TForm)
|
|
PanelTop: TPanel;
|
|
MemoLog: TMemo;
|
|
ScrollBoxDevices: TScrollBox;
|
|
Splitter1: TSplitter;
|
|
ButtonAllEnumDevice: TButton;
|
|
ButtonRunDeviceManager: TButton;
|
|
btnDataFlowConfig: TButton;
|
|
btnOpenRegedit: TButton;
|
|
grpUsbPortExcept: TGroupBox;
|
|
lblVendor: TLabel;
|
|
lblProduct: TLabel;
|
|
lblSerial: TLabel;
|
|
edtVendor: TEdit;
|
|
edtProduct: TEdit;
|
|
edtSerial: TEdit;
|
|
btnUsbPortExceptAdd: TButton;
|
|
btnPortExceptDel: TButton;
|
|
btnLogClear: TButton;
|
|
btnDataFlowStart: TButton;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure BtnApplyClick(Sender: TObject);
|
|
procedure ButtonAllEnumDeviceClick(Sender: TObject);
|
|
procedure PanelMouseWheelHandler(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
procedure ButtonRunDeviceManagerClick(Sender: TObject);
|
|
procedure btnDriveControlClick(Sender: TObject);
|
|
procedure btnDataFlowConfigClick(Sender: TObject);
|
|
procedure btnOpenRegeditClick(Sender: TObject);
|
|
procedure btnUsbPortExceptAddClick(Sender: TObject);
|
|
procedure btnPortExceptDelClick(Sender: TObject);
|
|
procedure btnLogClearClick(Sender: TObject);
|
|
procedure OnDataFlowStartClick(Sender: TObject);
|
|
private
|
|
FEngine: TDeviceGuardEngine;
|
|
FUIList: TObjectList<TUIItem>;
|
|
Fbs1MadHookInject_: TBs1MadHookInject;
|
|
// 윈도우 메시지 훅
|
|
procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
|
|
procedure CreateDefaultPolicies;
|
|
procedure BuildUIFromEngine;
|
|
|
|
procedure AddDeviceUI(const Name: string; Flag: DWORD; state : TDeviceState; log: Boolean; IsBT: Boolean = False);
|
|
procedure OnEngineLog(const Msg: string);
|
|
procedure OnEnginePopup(const Msg: string);
|
|
procedure OnUIChange(Sender: TObject);
|
|
procedure ModelessClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure ShowMessageModeless(const Msg: string);
|
|
procedure process_WM_COPYDATA(var msg: TMessage); Message WM_COPYDATA;
|
|
procedure process_WM_POPUP_MSG2(var msg: TMessage); Message WM_POPUP_MSG2;
|
|
protected
|
|
// [중요] 윈도우 생성 파라미터를 조작하여 클래스명을 변경하는 메서드
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
public
|
|
{ Public declarations }
|
|
end;
|
|
|
|
var
|
|
Form1: TForm1;
|
|
|
|
implementation
|
|
|
|
{$R *.dfm}
|
|
|
|
uses
|
|
DriveControlForm;
|
|
{ TUIItem }
|
|
|
|
constructor TUIItem.Create(APanel: TPanel; ARgControl, ARgLog: TRadioGroup; AFlag: DWORD);
|
|
begin
|
|
Panel := APanel;
|
|
RgControl := ARgControl;
|
|
RgLog := ARgLog;
|
|
Flag := AFlag;
|
|
end;
|
|
|
|
{ TForm1 }
|
|
|
|
procedure TForm1.ShowMessageModeless(const Msg: string);
|
|
var
|
|
Dlg: TForm;
|
|
i: Integer;
|
|
begin
|
|
// 1. 메시지 다이얼로그 폼 생성 (화면에 띄우지는 않음)
|
|
Dlg := CreateMessageDialog(Msg, mtInformation, [mbOK]);
|
|
Dlg.FormStyle := fsStayOnTop;
|
|
Dlg.Color := clBlue;
|
|
for i := 0 to Dlg.ComponentCount - 1 do
|
|
begin
|
|
// 메시지 텍스트(TLabel) 찾기
|
|
if Dlg.Components[i] is TLabel then
|
|
TLabel(Dlg.Components[i]).Font.Color := clWhite;
|
|
end;
|
|
|
|
Dlg.OnClose := ModelessClose;
|
|
Dlg.Show;
|
|
end;
|
|
|
|
procedure TForm1.ModelessClose(Sender: TObject; var Action: TCloseAction);
|
|
begin
|
|
Action := caFree; // 폼이 닫힐 때 메모리 해제
|
|
end;
|
|
|
|
procedure TForm1.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited CreateParams(Params);
|
|
|
|
// 델파이 기본 클래스명(TfrmReceiver) 대신 내가 원하는 이름으로 변경
|
|
// StrCopy를 사용하여 PChar 배열에 복사해야 합니다.
|
|
StrCopy(Params.WinClassName, PChar(BS1DC_CLASS_NAME));
|
|
end;
|
|
|
|
procedure TForm1.FormCreate(Sender: TObject);
|
|
//var
|
|
// LMessageBoxForm: TMessageBoxForm;
|
|
begin
|
|
Caption := 'Advanced Device Guard (Event & Flag Based)';
|
|
|
|
//ScrollBoxDevices.Align := alLeft; // 왼쪽 정렬 (창 늘려도 너비 유지)
|
|
// ScrollBoxDevices.Width := 600; // 원하는 너비로 고정 (예: 600px)
|
|
// 앵커 설정: 위/아래로 폼 크기 변경 시 높이는 따라가되, 너비는 고정akBottom
|
|
ScrollBoxDevices.Anchors := [akLeft, akTop];
|
|
|
|
btnDataFlowStart.Caption := '파일 유출 제어 시작';
|
|
btnDataFlowStart.Tag := 1;
|
|
|
|
FEngine := TDeviceGuardEngine.Create;
|
|
FEngine.OnLog := OnEngineLog;
|
|
FEngine.OnPopup := OnEnginePopup;
|
|
FUIList := TObjectList<TUIItem>.Create;
|
|
|
|
gBs1Policy:= TBs1Policy.Create;
|
|
gBs1Policy.LoadDataControlConfig;
|
|
FEngine.TriggerScan;
|
|
if gBs1Policy.Policies.Count = 0 then
|
|
begin
|
|
ShowMessage('저장된 정책이 없어 기본 정책을 생성합니다.');
|
|
CreateDefaultPolicies;
|
|
end;
|
|
|
|
ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);
|
|
|
|
BuildUIFromEngine;
|
|
|
|
FEngine.Start;
|
|
Fbs1MadHookInject_:= TBs1MadHookInject.Create;
|
|
Fbs1MadHookInject_.OnLog := OnEngineLog;
|
|
Fbs1MadHookInject_.StartInject();
|
|
OnEngineLog('감시 엔진이 시작되었습니다 (Event 대기 중).');
|
|
end;
|
|
|
|
procedure TForm1.FormDestroy(Sender: TObject);
|
|
begin
|
|
|
|
OutputDebugStringW('[Bs1dc] Destory!!!++++++++++++++');
|
|
if Assigned(Fbs1MadHookInject_) then
|
|
begin
|
|
Fbs1MadHookInject_.StopInject();
|
|
FreeAndNil(Fbs1MadHookInject_);
|
|
end;
|
|
|
|
FEngine.Stop;
|
|
FEngine.Free;
|
|
FUIList.Free;
|
|
gBs1Policy.Free;
|
|
|
|
OutputDebugStringW('[Bs1dc] Destory!!!--------------');
|
|
ShowMessage('종료 되었습니다.');
|
|
|
|
end;
|
|
|
|
procedure TForm1.CreateDefaultPolicies;
|
|
var
|
|
P: TPolicyItem;
|
|
begin
|
|
|
|
//드라이브 제어
|
|
P := gBs1Policy.CreatePolicy('BDC_CDROM', BDC_CDROM);
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('BDC_FLOOPY', BDC_FLOOPY);
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('BDC_USB_DISK', BDC_USB_DISK);
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('BDC_NETWORKDRIVEOUT', BDC_NETWORKDRIVEOUT);
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('BDC_NETWORKDRIVEIN', BDC_NETWORKDRIVEIN);
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('BDC_EXTERNALHDD', BDC_EXTERNALHDD);
|
|
gBs1Policy.AddPolicyObject(P);
|
|
///
|
|
///
|
|
|
|
//
|
|
// P := gBs1Policy.CreatePolicy('PCMCIA', BDC_PCMCIA);
|
|
// P.AddMatch(SPDRP_SERVICE, 'PCMCIA', 'PCI');
|
|
// gBs1Policy.AddPolicyObject(P);
|
|
//
|
|
// P := gBs1Policy.CreatePolicy('SERIAL', BDC_SERIAL);
|
|
// P.AddMatch(SPDRP_SERVICE, 'Serial', 'ACPI');
|
|
// gBs1Policy.AddPolicyObject(P);
|
|
//
|
|
// P := gBs1Policy.CreatePolicy('1394', BDC_1394);
|
|
// P.AddMatch(SPDRP_SERVICE, '1394', '1394');
|
|
// gBs1Policy.AddPolicyObject(P);
|
|
//
|
|
// P := gBs1Policy.CreatePolicy('IRDA', BDC_IRDA);
|
|
// P.AddMatch(SPDRP_SERVICE, 'IRDA', 'IRDA');
|
|
// gBs1Policy.AddPolicyObject(P);
|
|
//
|
|
// P := gBs1Policy.CreatePolicy('WIBRO', BDC_WIBRO);
|
|
// P.AddMatch(SPDRP_SERVICE, 'WIBRO', 'WIBRO');
|
|
// gBs1Policy.AddPolicyObject(P);
|
|
//
|
|
// P := gBs1Policy.CreatePolicy('PARALLEL', BDC_PARALLEL);
|
|
// P.AddMatch(SPDRP_SERVICE, 'parport', 'ACPI');
|
|
// gBs1Policy.AddPolicyObject(P);
|
|
//
|
|
// P := gBs1Policy.CreatePolicy('MODEM', BDC_MODEM);
|
|
// P.AddMatch(SPDRP_SERVICE, 'MODEM', 'MODEM');
|
|
// gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('USB', BDC_USB);
|
|
P.AddMatch(SPDRP_SERVICE, 'USBSTOR', 'USB');
|
|
P.AddMatch(SPDRP_SERVICE, 'USBAAPL', 'USB');
|
|
P.AddMatch(SPDRP_SECURITY, 'Apple', 'USB');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('MTP', BDC_MTP, GUID_DEVCLASS_WPD);
|
|
P.AddMatch(SPDRP_HARDWAREID, '_mtp', 'USB');
|
|
P.AddMatch(SPDRP_COMPATIBLEIDS, '_mtp', 'USB');
|
|
P.AddMatch(SPDRP_DEVICEDESC, 'apple', 'USB');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('TETHERING', BDC_TETHERING);
|
|
P.AddMatch(SPDRP_SERVICE, 'usb_rndisx', 'USB');
|
|
P.AddMatch(SPDRP_SERVICE, 'usb_rndisk', 'USB');
|
|
P.AddMatch(SPDRP_SERVICE, 'Netaapl', 'USB');
|
|
P.AddMatch(SPDRP_SERVICE, 'andnetndis', 'USB');
|
|
P.AddMatch(SPDRP_SERVICE, 'lgwqmindis', 'USB');
|
|
P.AddMatch(SPDRP_SERVICE, 'usbrndis6', 'USB');
|
|
P.AddMatch(SPDRP_SERVICE, 'BthPan', 'BTH');
|
|
P.AddMatch(SPDRP_SERVICE, 'RFCOMM', 'BTH');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('SDCARD', BDC_SDCARD);
|
|
P.AddMatch(SPDRP_SERVICE, 'risdxc', 'PCI');
|
|
P.AddMatch(SPDRP_SERVICE, 'disk', 'RISD');
|
|
P.AddMatch(SPDRP_SERVICE, 'sffdisk', 'SD');
|
|
P.AddMatch(SPDRP_SERVICE, 'sdbus', 'PCI');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('WIRELESS', BDC_WIRELESS);
|
|
P.AddMatch(SPDRP_SERVICE, 'mtkwlex', 'PCI');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('WEBCAM', BDC_WEBCAM);
|
|
P.AddMatch(SPDRP_SERVICE, 'usbvideo', 'USB');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
P := gBs1Policy.CreatePolicy('Bluetooth', BDC_BLUETOOTH, '');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
// P := gBs1Policy.CreatePolicy('Bluetooth File', BDC_BLUETOOTH_FILE, '');
|
|
// P.AddMatch(SPDRP_SERVICE, 'BTHUSB', 'USB');
|
|
// P.AddMatch(SPDRP_SERVICE, 'BTWUSB', 'USB');
|
|
// P.AddMatch(SPDRP_SERVICE, 'BTMUSB', 'USB');
|
|
gBs1Policy.AddPolicyObject(P);
|
|
|
|
end;
|
|
|
|
procedure TForm1.BuildUIFromEngine;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
// 1. FUIList 초기화 (TUIItem 객체들 해제)
|
|
FUIList.Clear;
|
|
|
|
// 2. ScrollBox 내의 기존 컨트롤(패널들) 제거
|
|
// 역순으로 지워야 인덱스 오류가 안 납니다.
|
|
if ScrollBoxDevices <> nil then
|
|
begin
|
|
// ScrollBoxDevices의 스크롤 위치 초기화 (UI 깨짐 방지)
|
|
ScrollBoxDevices.VertScrollBar.Position := 0;
|
|
|
|
for i := ScrollBoxDevices.ControlCount - 1 downto 0 do
|
|
begin
|
|
// TScrollablePanel만 골라서 제거
|
|
if ScrollBoxDevices.Controls[i] is TPanel then
|
|
ScrollBoxDevices.Controls[i].Free;
|
|
end;
|
|
end;
|
|
|
|
// 3. 정책 개수 확인 (디버깅용)
|
|
// if FEngine.Policies.Count = 0 then
|
|
// ShowMessage('표시할 정책(장치)이 없습니다.');
|
|
|
|
// 4. UI 생성 루프
|
|
for var Policy in gBs1Policy.Policies do
|
|
begin
|
|
|
|
case Policy.flag_ of
|
|
DWORD(BDC_CDROM),
|
|
DWORD(BDC_FLOOPY),
|
|
DWORD(BDC_USB_DISK),
|
|
DWORD(BDC_NETWORKDRIVEOUT),
|
|
DWORD(BDC_NETWORKDRIVEIN),
|
|
DWORD(BDC_EXTERNALHDD):
|
|
continue;
|
|
end;
|
|
|
|
AddDeviceUI(Policy.Name, Policy.flag_, Policy.state_, Policy.isLog_, Policy.isBluetooth_);
|
|
|
|
// 방금 추가된 UI 아이템 가져오기
|
|
// if FUIList.Count > 0 then
|
|
// begin
|
|
// var LastUI := FUIList.Last;
|
|
//
|
|
// // 제어 상태 반영 (ItemIndex: 0=사용, 1=차단)
|
|
// if Policy.state_ = dsDisable then
|
|
// LastUI.RgControl.ItemIndex := 1
|
|
// else
|
|
// LastUI.RgControl.ItemIndex := 0;
|
|
//
|
|
// // 로그 상태 반영 (ItemIndex: 0=미사용, 1=사용)
|
|
// if Policy.isLog_ then
|
|
// LastUI.RgLog.ItemIndex := 1
|
|
// else
|
|
// LastUI.RgLog.ItemIndex := 0;
|
|
|
|
OnEngineLog(Format('BuildUIFromEngine, state_(%d), isLog_(%d)', [DWORD(Policy.state_), DWORD(Policy.isLog_)]));
|
|
// end;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.WMDeviceChange(var Msg: TMessage);
|
|
begin
|
|
inherited;
|
|
if Msg.WParam = DBT_DEVNODES_CHANGED then
|
|
begin
|
|
OnEngineLog('[System] 하드웨어 변경 감지 -> 재검사 요청');
|
|
FEngine.TriggerScan;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.process_WM_POPUP_MSG2(var msg: TMessage);
|
|
begin
|
|
TMessageBoxForm.Create(nil, string(msg.LParam)).Show;
|
|
end;
|
|
|
|
|
|
procedure TForm1.process_WM_COPYDATA(var msg: TMessage);
|
|
var
|
|
sReceivedText: string;
|
|
dwData: DWORD;
|
|
pCpData: PCopyDataStruct;
|
|
O: ISuperObject;
|
|
begin
|
|
msg.Result := 0;
|
|
pCpData := PCopyDataStruct(msg.LParam);
|
|
OnEngineLog('process_WM_COPYDATA');
|
|
try
|
|
dwData := pCpData.dwData;
|
|
OnEngineLog('process_WM_COPYDATA : ' + dwData.ToString);
|
|
case dwData of
|
|
HPCMD_FILE_OPERATION_NOTI:
|
|
begin
|
|
O := SO(Copy(PChar(pCpData.lpData), 1, pCpData.cbData));
|
|
|
|
if O.B['N'] then
|
|
begin
|
|
var Code: DWORD;
|
|
var Summary: string;
|
|
var sDstPath: string;
|
|
var sSrcPath: string;
|
|
var deviceName: string;
|
|
var evt: Integer;
|
|
|
|
OnEngineLog('process_WM_COPYDATA : HPCMD_FILE_OPERATION_NOTI');
|
|
|
|
evt:= O.I['E'];
|
|
sSrcPath:= O.S['S'];
|
|
sDstPath:= O.S['D'];
|
|
deviceName:= O.S['T'];
|
|
Summary:= '[Folder]' + ExtractFileName(O.S['D']);
|
|
OnEngineLog(Format('[FILE_OPER] (%s)(%s), (%d), (%s)->(%s)', [deviceName, Summary, DWORD(evt), sSrcPath, sDstPath]));
|
|
|
|
if O.B['B'] then
|
|
begin
|
|
SendMessage(Handle, WM_POPUP_MSG2, 0, NativeInt(O.AsString));
|
|
end;
|
|
// begin
|
|
// Code:= PREVENT_NETFOLDER_FILE;
|
|
// Summary:= 'Block : ';
|
|
//
|
|
// if MgSvc_.ModePolicy.ShFileCrMon.bBlkNoti then
|
|
// MgSvc_.PopupMessage(TYPE_MSG_PREVENT_FILEOPER, O.AsJSon);
|
|
// end else begin
|
|
// Code:= MONITOR_NETFOLDER_FILE;
|
|
// Summary:= 'Monitor : ';
|
|
//
|
|
// if MgSvc_.ModePolicy.ShFileCrMon.bMonNoti then
|
|
// MgSvc_.PopupMessage(TYPE_MSG_MONITOR_FILEOPER, O.AsJSon);
|
|
// end;
|
|
// LogInfo.sSummary := LogInfo.sSummary + ExtractFileName(O.S['D']);
|
|
// LogInfo.sAppName := 'explorer.exe';
|
|
// LogInfo.sPath := O.S['D'];
|
|
// MgSvc_.SendEventLogEx(@LogInfo, O.B['B']);
|
|
end;
|
|
|
|
msg.Result := 1;
|
|
end;
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
OnEngineLog('process_WM_COPYDATA except');
|
|
// ETgException.TraceException(Self, E, 'Fail .. process_WM_CTTSCH_REQUEST()');
|
|
end;
|
|
|
|
//
|
|
//
|
|
// //case dwData of
|
|
// // 1. 전달받은 데이터가 있는지 확인
|
|
// if Msg.CopyDataStruct.lpData <> nil then
|
|
// begin
|
|
// // 2. lpData 포인터에서 문자열을 가져옴
|
|
// // (보내는 쪽에서 Null-Terminated String으로 보냈다고 가정)
|
|
// sReceivedText := PChar(Msg.CopyDataStruct.lpData);
|
|
//
|
|
// // 3. 화면에 표시
|
|
// OnEngineLog(Format('[%s] %s', [FormatDateTime('hh:mm:ss', Now), sReceivedText]));
|
|
//
|
|
// // 4. 처리 결과 반환 (일반적으로 처리가 잘 되었으면 1 또는 True 반환)
|
|
// Msg.Result := 1;
|
|
// end
|
|
// else
|
|
// begin
|
|
// Msg.Result := 0;
|
|
// end;
|
|
end;
|
|
|
|
// 정책 저장 버튼
|
|
procedure TForm1.BtnApplyClick(Sender: TObject);
|
|
begin
|
|
gBs1Policy.SavePolicyToFile;
|
|
OnEngineLog('정책 저장 완료.');
|
|
FEngine.TriggerScan;
|
|
end;
|
|
|
|
|
|
procedure TForm1.ButtonAllEnumDeviceClick(Sender: TObject);
|
|
begin
|
|
FEngine.AllEnumSystemDevice;
|
|
end;
|
|
|
|
procedure TForm1.btnOpenRegeditClick(Sender: TObject);
|
|
begin
|
|
ShellExecute( 0, 'open', 'regedit.exe', nil, nil, SW_SHOWNORMAL );
|
|
end;
|
|
|
|
function StrToHexOrInt(const StrValue: string): Integer;
|
|
var
|
|
S: string;
|
|
begin
|
|
S := Trim(StrValue); // 앞뒤 공백 제거
|
|
|
|
if TryStrToInt(S, Result) then Exit;
|
|
if StartsText('0x', S) then
|
|
begin
|
|
S := StringReplace(S, '0x', '$', [rfIgnoreCase]);
|
|
if TryStrToInt(S, Result) then Exit;
|
|
end;
|
|
|
|
if TryStrToInt('$' + S, Result) then Exit;
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TForm1.btnPortExceptDelClick(Sender: TObject);
|
|
var
|
|
InputStrVid: string;
|
|
InputStrPid: string;
|
|
LsVid: string;
|
|
LsPid: string;
|
|
LSerial: string;
|
|
LProdoct: string;
|
|
state: DWORD;
|
|
LVid: DWORD;
|
|
LPid: DWORD;
|
|
begin
|
|
InputStrVid:= edtVendor.Text;
|
|
InputStrPid:= edtProduct.Text;
|
|
LSerial:= edtSerial.Text;
|
|
|
|
|
|
if StartsText('0x', InputStrVid) then
|
|
begin
|
|
LsVid := Copy(InputStrVid, 3, Length(InputStrVid));
|
|
LVid := StrToInt('$' + LsVid);
|
|
end
|
|
else
|
|
begin
|
|
LsVid := InputStrVid;
|
|
LVid := StrToInt(LsVid);
|
|
end;
|
|
|
|
if StartsText('0x', InputStrPid) then
|
|
begin
|
|
LsPid := Copy(InputStrPid, 3, Length(InputStrPid));
|
|
LPid := StrToInt('$' + LsPid);
|
|
end
|
|
else
|
|
begin
|
|
LsPid := InputStrPid;
|
|
LPid := StrToInt(LsPid);
|
|
end;
|
|
|
|
gBs1Policy.RemoveUsbPortExcept(LsVid, LsPid, LSerial);
|
|
state:= gBs1fltControl.DelUsbPortException(LVid, LPid, 0, PWideChar(LSerial));
|
|
if state = 0 then
|
|
begin
|
|
ShowMessage('제거 되었습니다');
|
|
end
|
|
else
|
|
ShowMessage('제거 실패 하였습니다.');
|
|
end;
|
|
|
|
procedure TForm1.btnUsbPortExceptAddClick(Sender: TObject);
|
|
var
|
|
InputStrVid: string;
|
|
InputStrPid: string;
|
|
LsVid: string;
|
|
LsPid: string;
|
|
LSerial: string;
|
|
LProdoct: string;
|
|
state: DWORD;
|
|
LVid: DWORD;
|
|
LPid: DWORD;
|
|
begin
|
|
InputStrVid:= edtVendor.Text;
|
|
InputStrPid:= edtProduct.Text;
|
|
LSerial:= edtSerial.Text;
|
|
|
|
|
|
if StartsText('0x', InputStrVid) then
|
|
begin
|
|
LsVid := Copy(InputStrVid, 3, Length(InputStrVid));
|
|
LVid := StrToInt('$' + LsVid);
|
|
end
|
|
else
|
|
begin
|
|
LsVid := InputStrVid;
|
|
LVid := StrToInt(LsVid);
|
|
end;
|
|
|
|
if StartsText('0x', InputStrPid) then
|
|
begin
|
|
LsPid := Copy(InputStrPid, 3, Length(InputStrPid));
|
|
LPid := StrToInt('$' + LsPid);
|
|
end
|
|
else
|
|
begin
|
|
LsPid := InputStrPid;
|
|
LPid := StrToInt(LsPid);
|
|
end;
|
|
|
|
// LVid:= StrToHexOrInt(LVendor);
|
|
// LPid:= StrToHexOrInt(LProdoct);
|
|
|
|
gBs1Policy.AddUsbPortExcept(LsVid, LsPid, LSerial);
|
|
state:= gBs1fltControl.SetUsbPortException(LVid, LPid, 0, PWideChar(LSerial));
|
|
if state = 0 then
|
|
begin
|
|
ShowMessage('추가 되었습니다');
|
|
|
|
end
|
|
else
|
|
ShowMessage('추가 실패 하였습니다.');
|
|
|
|
end;
|
|
|
|
procedure TForm1.ButtonRunDeviceManagerClick(Sender: TObject);
|
|
begin
|
|
ShellExecute( 0, 'open', 'devmgmt.msc', nil, nil, SW_SHOWNORMAL );
|
|
end;
|
|
|
|
procedure TForm1.OnUIChange(Sender: TObject);
|
|
var
|
|
Rg: TRadioGroup;
|
|
NewState: TDeviceState;
|
|
NewLogState: Boolean;
|
|
begin
|
|
Rg := Sender as TRadioGroup;
|
|
|
|
for var UI in FUIList do
|
|
begin
|
|
if (UI.RgControl = Rg) or (UI.RgLog = Rg) then
|
|
begin
|
|
// 현재 UI의 상태 읽기
|
|
if UI.RgControl.ItemIndex = 1 then
|
|
NewState := dsDisable
|
|
else
|
|
NewState := dsEnable;
|
|
|
|
if UI.RgLog.ItemIndex = 1 then
|
|
NewLogState := True
|
|
else
|
|
NewLogState := False;
|
|
|
|
// 엔진 업데이트 호출 (UpdatePolicyState 시그니처 수정 필요할 수 있음)
|
|
gBs1Policy.UpdatePolicyState(UI.Flag, NewState, NewLogState);
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.AddDeviceUI(const Name: string; Flag: DWORD; state : TDeviceState; log: Boolean; IsBT: Boolean);
|
|
var
|
|
Pnl: TPanel; // TScrollablePanel 대신 TPanel 사용 권장 (가볍음)
|
|
RightPnl: TPanel;
|
|
RgCtrl, RgLog: TRadioGroup;
|
|
Lbl: TLabel;
|
|
|
|
// 배율 적용을 위한 변수
|
|
ScaleF: Single;
|
|
RadioWidth: Integer;
|
|
RightPanelWidth: Integer;
|
|
PanelHeight: Integer;
|
|
begin
|
|
if ScrollBoxDevices = nil then Exit;
|
|
|
|
// 1. [핵심] 현재 화면 배율 계산 (기본 96 DPI 기준)
|
|
// 델파이 최신 버전(10.x 이상)에서는 ScaleFactor 속성을 지원합니다.
|
|
// 구버전이라면 GetDeviceCaps(Canvas.Handle, LOGPIXELSX) / 96.0; 을 쓰세요.
|
|
ScaleF := Self.ScaleFactor;
|
|
|
|
// 2. [핵심] 고정값에 배율 곱하기
|
|
RadioWidth := Round(120 * ScaleF); // 120 -> 240 (200%일 때)
|
|
RightPanelWidth := (RadioWidth * 2) + Round(20 * ScaleF);
|
|
PanelHeight := Round(55 * ScaleF);
|
|
|
|
// 3. 메인 행 패널 생성
|
|
Pnl := TPanel.Create(ScrollBoxDevices);
|
|
Pnl.Parent := ScrollBoxDevices;
|
|
Pnl.Align := alTop;
|
|
Pnl.Height := PanelHeight; // 높이도 배율 적용
|
|
Pnl.BevelOuter := bvNone;
|
|
Pnl.BevelKind := bkTile;
|
|
Pnl.BevelEdges := [beBottom];
|
|
Pnl.AlignWithMargins := True;
|
|
Pnl.Margins.SetBounds(2, 2, 2, 0);
|
|
Pnl.ParentBackground := False;
|
|
Pnl.Color := clWhite;
|
|
// Panel은 캡션이 가운데 뜨므로 지워줌
|
|
Pnl.Caption := '';
|
|
Pnl.Visible := True;
|
|
|
|
// 4. 오른쪽 버튼 컨테이너 패널
|
|
RightPnl := TPanel.Create(Pnl);
|
|
RightPnl.Parent := Pnl;
|
|
RightPnl.Align := alRight;
|
|
RightPnl.Width := RightPanelWidth; // 너비도 배율 적용
|
|
RightPnl.BevelOuter := bvNone;
|
|
RightPnl.ParentBackground := False;
|
|
RightPnl.Color := clWhite;
|
|
RightPnl.Caption := '';
|
|
RightPnl.Margins.Right := Round(10 * ScaleF);
|
|
RightPnl.AlignWithMargins := True;
|
|
|
|
// 5. 로그 라디오 그룹 (오른쪽)
|
|
RgLog := TRadioGroup.Create(RightPnl);
|
|
RgLog.Parent := RightPnl;
|
|
RgLog.Caption := '로그';
|
|
RgLog.Align := alRight;
|
|
RgLog.Width := RadioWidth; // 너비 배율 적용
|
|
RgLog.Columns := 2;
|
|
RgLog.Items.Add('OFF');
|
|
RgLog.Items.Add('ON');
|
|
|
|
// 로그 상태 반영 (ItemIndex: 0=미사용, 1=사용)
|
|
if log then
|
|
RgLog.ItemIndex := 1
|
|
else
|
|
RgLog.ItemIndex := 0;
|
|
|
|
RgLog.OnClick := OnUIChange; // 이벤트 연결 필요하면 주석 해제
|
|
RgLog.Margins.SetBounds(Round(5 * ScaleF), Round(2 * ScaleF), 0, Round(2 * ScaleF));
|
|
RgLog.AlignWithMargins := True;
|
|
|
|
// 6. 제어 라디오 그룹 (왼쪽 채우기)
|
|
RgCtrl := TRadioGroup.Create(RightPnl);
|
|
RgCtrl.Parent := RightPnl;
|
|
RgCtrl.Caption := '제어';
|
|
RgCtrl.Align := alClient;
|
|
RgCtrl.Columns := 2;
|
|
RgCtrl.Items.Add('허용');
|
|
RgCtrl.Items.Add('차단');
|
|
|
|
if state = dsDisable then
|
|
RgCtrl.ItemIndex := 1
|
|
else
|
|
RgCtrl.ItemIndex := 0;
|
|
|
|
// RgCtrl.ItemIndex := 0;
|
|
RgCtrl.OnClick := OnUIChange; // 이벤트 연결 필요하면 주석 해제
|
|
RgCtrl.Margins.SetBounds(0, Round(2 * ScaleF), Round(5 * ScaleF), Round(2 * ScaleF));
|
|
RgCtrl.AlignWithMargins := True;
|
|
|
|
// 7. 장치 이름 라벨 (왼쪽)
|
|
Lbl := TLabel.Create(Pnl);
|
|
Lbl.Parent := Pnl;
|
|
Lbl.Caption := Name;
|
|
Lbl.AutoSize := False;
|
|
Lbl.Align := alClient;
|
|
Lbl.Layout := tlCenter;
|
|
Lbl.Font.Size := 9; // 폰트 크기는 OS가 알아서 배율 적용함 (보통 안 건드려도 됨)
|
|
Lbl.Font.Style := [fsBold];
|
|
Lbl.Margins.Left := Round(15 * ScaleF);
|
|
Lbl.AlignWithMargins := True;
|
|
Lbl.Transparent := True;
|
|
|
|
// 리스트에 추가
|
|
FUIList.Add(TUIItem.Create(Pnl, RgCtrl, RgLog, Flag));
|
|
end;
|
|
|
|
procedure TForm1.OnDataFlowStartClick(Sender: TObject);
|
|
begin
|
|
//
|
|
if btnDataFlowStart.Tag = 0 then
|
|
begin
|
|
|
|
btnDataFlowStart.Caption := '파일 유출 제어 시작';
|
|
btnDataFlowStart.Tag := 1;
|
|
|
|
Fbs1MadHookInject_.StopInject();
|
|
end
|
|
else
|
|
begin
|
|
btnDataFlowStart.Caption := '파일 유출 제어 중지';
|
|
btnDataFlowStart.Tag := 0;
|
|
|
|
Fbs1MadHookInject_.StartInject();
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TForm1.OnEngineLog(const Msg: string);
|
|
begin
|
|
MemoLog.Lines.BeginUpdate;
|
|
try
|
|
MemoLog.Lines.Add(Format('[%s] %s', [FormatDateTime('hh:nn:ss', Now), Msg]));
|
|
|
|
// 스크롤도 여기서 처리해야 안전함
|
|
SendMessage(MemoLog.Handle, WM_VSCROLL, SB_BOTTOM, 0);
|
|
finally
|
|
MemoLog.Lines.EndUpdate;
|
|
end;
|
|
// TThread.Queue(nil, procedure
|
|
// var
|
|
// LForm: TMessageBoxForm;
|
|
// begin
|
|
// // 1. 메모 로그 출력 (이제 안전함)
|
|
// MemoLog.Lines.BeginUpdate;
|
|
// try
|
|
// MemoLog.Lines.Add(Format('[%s] %s', [FormatDateTime('hh:nn:ss', Now), Msg]));
|
|
//
|
|
// // 스크롤도 여기서 처리해야 안전함
|
|
// SendMessage(MemoLog.Handle, WM_VSCROLL, SB_BOTTOM, 0);
|
|
// finally
|
|
// MemoLog.Lines.EndUpdate;
|
|
// end;
|
|
//
|
|
// // 2. 특정 조건 시 메시지 창 띄우기
|
|
// if ContainsText(Msg, 'MATCHING!!!!!BLOCK!!!!!') then
|
|
// begin
|
|
// LForm := TMessageBoxForm.Create(Application);
|
|
// try
|
|
// LForm.lblMessage.Caption := Msg;
|
|
// LForm.Show;
|
|
// except
|
|
// LForm.Free;
|
|
// end;
|
|
// end;
|
|
// end);
|
|
end;
|
|
|
|
procedure TForm1.OnEnginePopup(const Msg: string);
|
|
begin
|
|
self.Caption := '경고: ' + Msg;
|
|
end;
|
|
|
|
procedure TForm1.PanelMouseWheelHandler(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
var
|
|
ScrollCode: Integer;
|
|
begin
|
|
|
|
if WheelDelta > 0 then
|
|
ScrollCode := SB_LINEUP
|
|
else
|
|
ScrollCode := SB_LINEDOWN;
|
|
|
|
PostMessage(ScrollBoxDevices.Handle, WM_VSCROLL, ScrollCode, 0);
|
|
Handled := True;
|
|
end;
|
|
|
|
procedure TForm1.btnDataFlowConfigClick(Sender: TObject);
|
|
var
|
|
dlg: TDataFlowSettingForm;
|
|
begin
|
|
dlg := TDataFlowSettingForm.Create(Self);
|
|
try
|
|
|
|
dlg.SetEngine(gBs1Policy);
|
|
|
|
if dlg.ShowModal = mrOk then
|
|
begin
|
|
OnEngineLog('DataFlow 설정이 변경되었습니다.');
|
|
end;
|
|
finally
|
|
dlg.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.btnDriveControlClick(Sender: TObject);
|
|
var
|
|
DriveForm: TDriveControlForm;
|
|
begin
|
|
DriveForm := TDriveControlForm.Create(Self);
|
|
try
|
|
// 엔진 참조 전달 (필요 시)
|
|
DriveForm.Engine := FEngine;
|
|
DriveForm.OnLog := OnEngineLog;
|
|
DriveForm.LoadSettings;
|
|
DriveForm.ShowModal;
|
|
finally
|
|
DriveForm.Free;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TForm1.btnLogClearClick(Sender: TObject);
|
|
begin
|
|
MemoLog.Lines.Clear;
|
|
end;
|
|
|
|
end.
|