bug : 정책 문제로 app 차단 정책이 없으면 후킹이 동작하지 않아서 새로 추가된 정책도 포함해서 판단되도록 수정

bug : usb,usbtousb,bluetooth,cdrom,mtp
 - 목록차단만 설정시 파일이 차단 안되는 문제 수정
buf : recoverService 수정
 - 설치시 생성된 무결성 검증 파일 기준으로 체크하도록 변경
 - 최초 1회 동작, 그후 변경된 파일에 대해서만 확인 후 로그 전송
 - windows/system32/ecrmheserviced.dll의 경우 직접 모니터링하여 확인
feat : 보안모드/수면모드 문구 수정
 - 인증/미인증 모드
This commit is contained in:
mgkim 2026-03-26 17:42:38 +09:00
parent 826810ca06
commit 9c2ec0c432
434 changed files with 87352 additions and 87022 deletions

View File

@ -3,7 +3,7 @@
interface interface
const const
BUILD_DT = '2026-03-25 18:24:05'; BUILD_DT = '2026-03-26 17:32:45';
implementation implementation

View File

@ -207,6 +207,7 @@ begin
Inherited Create; Inherited Create;
// _Trace('Create() ..'); // _Trace('Create() ..');
CS_ := TCriticalSection.Create; CS_ := TCriticalSection.Create;
bUse_madCodeHook_ := IsUse_madCodeHook; bUse_madCodeHook_ := IsUse_madCodeHook;
@ -1528,10 +1529,12 @@ begin
if sTgApps_mad_ = '' then if sTgApps_mad_ = '' then
begin begin
_Trace('Start_madCodeHookInjection() .. Fail .. GlobalHook 대상 프로세스를 찾을 수 없음 ..', 1); _Trace('Start_madCodeHookInjection() .. Fail .. GlobalHook 대상 프로세스를 찾을 수 없음 ..', 1);
DVLOG('Start_madCodeHookInjection() .. Fail .. GlobalHook 대상 프로세스를 찾을 수 없음 ..', []);
exit; exit;
end; end;
mtx_madCode_ := TTgMutex.Create(MUTEX_MH); mtx_madCode_ := TTgMutex.Create(MUTEX_MH);
DVLOG('Start_madCodeHookInjection() .. mtx_madCode_(%d) ..', [DWORD(mtx_madCode_.MutexState)]);
if mtx_madCode_.MutexState = msCreateOk then if mtx_madCode_.MutexState = msCreateOk then
begin begin
// if not CreateIpcQueue(PAnsiChar(BS1HOOK_IPCMESSAGE_STRING), MadHookIpcMessageCallback) then // if not CreateIpcQueue(PAnsiChar(BS1HOOK_IPCMESSAGE_STRING), MadHookIpcMessageCallback) then
@ -1717,6 +1720,8 @@ begin
UpdatePreLoadInfo; UpdatePreLoadInfo;
OffExcelDDE; OffExcelDDE;
DVLOG('StartHookWatch....bUse_madCodeHook(%d) (%d)', [DWORD(bUse_madCodeHook_), CUSTOMER_TYPE]);
if bUse_madCodeHook_ then if bUse_madCodeHook_ then
Start_madCodeHookInjection; Start_madCodeHookInjection;

View File

@ -1670,7 +1670,12 @@ begin
(CaptureBlockUrlKind <> bkNone) or (CaptureBlockUrlKind <> bkNone) or
(bCaptureBlockApps_ and (CaptureBlockApps <> '')) or (bCaptureBlockApps_ and (CaptureBlockApps <> '')) or
(MtpBlockKind = ubkReadOnly) or (MtpBlockKind = ubkReadOnly) or
(ShFileCrMon.nKind <> 0); (ShFileCrMon.nKind <> 0) or
(IntMtpBlockNewFile.mode <> abkNone) or
(IntCdromBlockNewFile.mode <> abkNone) or
(IntUsbToUsbBlockNewFile.mode <> abkNone) or
(IntUsbBlockNewFile.mode <> abkNone) or
(IntBtBlockNewFile.mode <> abkNone);
end; end;
function TPrefModel.IsAbleCodePo: Boolean; function TPrefModel.IsAbleCodePo: Boolean;

View File

@ -5567,7 +5567,7 @@ begin
try try
PO := GetModePolicy; PO := GetModePolicy;
_Trace('[MGKIM] TimerProcessUsbDevTask .. use(%d), (%s)',[DWORD(PO.IntUsbDevBlock.use), PO.IntUsbDevBlock.execList]); //_Trace('[MGKIM] TimerProcessUsbDevTask .. use(%d), (%s)',[DWORD(PO.IntUsbDevBlock.use), PO.IntUsbDevBlock.execList]);
except except
on E: Exception do on E: Exception do

View File

@ -190,7 +190,8 @@ resourcestring
RS_MsgUpdateCompleted = '프로그램이 업데이트 되었습니다.'; RS_MsgUpdateCompleted = '프로그램이 업데이트 되었습니다.';
RS_FMT_Version = ' - 버전 : %s'; RS_FMT_Version = ' - 버전 : %s';
RS_WriteReport = '사용 보고서 작성'; RS_WriteReport = '사용 보고서 작성';
RS_MsgWriteReport1 = '다시 보안 모드에 진입하기 전에'; // RS_MsgWriteReport1 = '다시 보안 모드에 진입하기 전에';
RS_MsgWriteReport1 = '다시 인증 모드에 진입하기 전에';
RS_MsgWriteReport2 = '사용 보고서를 작성 해주십시오.'; RS_MsgWriteReport2 = '사용 보고서를 작성 해주십시오.';
RS_ClipCut = '클립보드 (복사, 캡쳐) 사용이 차단 되었습니다.'; RS_ClipCut = '클립보드 (복사, 캡쳐) 사용이 차단 되었습니다.';
RS_FMT_ClipCutApp = '사용 프로그램 : %s'; RS_FMT_ClipCutApp = '사용 프로그램 : %s';
@ -316,8 +317,10 @@ resourcestring
RS_BlockTethering = '네트워크가 차단 되었습니다.'; RS_BlockTethering = '네트워크가 차단 되었습니다.';
RS_MsgAppScrRcd = 'APP 사용이 감지되어 화면 녹화를 시작합니다.'; RS_MsgAppScrRcd = 'APP 사용이 감지되어 화면 녹화를 시작합니다.';
RS_DetectApp = '사용 감지 APP : '; RS_DetectApp = '사용 감지 APP : ';
RS_MsgModeSleep = '[수면 모드 입니다]'; // RS_MsgModeSleep = '[수면 모드 입니다]';
RS_MsgModeSecu = '[보안 모드 입니다]'; RS_MsgModeSleep = '[미인증 모드 입니다]';
// RS_MsgModeSecu = '[보안 모드 입니다]';
RS_MsgModeSecu = '[인증 모드 입니다]';
RS_MsgModeVul = '[취약 모드 입니다. 취약점을 조치해주세요]'; RS_MsgModeVul = '[취약 모드 입니다. 취약점을 조치해주세요]';
RS_RS_MsgModeNoId = '[미인증 모드 입니다. ID 인증이 필요합니다]'; RS_RS_MsgModeNoId = '[미인증 모드 입니다. ID 인증이 필요합니다]';
RS_MsgModeOff = '[오프라인 모드 입니다]'; RS_MsgModeOff = '[오프라인 모드 입니다]';

View File

@ -91,6 +91,9 @@ const
DIR_NAMES = 'bin|conf|Data|Language|Resource'; DIR_NAMES = 'bin|conf|Data|Language|Resource';
type type
TRecoverThread = class;
TRecoverService = class(TTgDirWatchBase) TRecoverService = class(TTgDirWatchBase)
private private
DataFiles_, DataFiles_,
@ -112,6 +115,7 @@ type
bRecovering_: Boolean; bRecovering_: Boolean;
referenceData_: TDictionary<string, string>; referenceData_: TDictionary<string, string>;
recoverThread_: TRecoverThread;
procedure OnLockFileNotify(Sender: TObject; const Item: TFileStream; Action: TCollectionNotification); procedure OnLockFileNotify(Sender: TObject; const Item: TFileStream; Action: TCollectionNotification);
procedure ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); override; procedure ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); override;
@ -124,6 +128,9 @@ type
out ActualHash, Reason: string): Boolean; out ActualHash, Reason: string): Boolean;
procedure CheckAndRecover(sResPath, sPath: String); procedure CheckAndRecover(sResPath, sPath: String);
function DoRecoverFile(const sTargetFilePath: string): string; function DoRecoverFile(const sTargetFilePath: string): string;
procedure PerformSingleAudit(const APath: string);
function IsRefrenceData(const APath: string): Boolean;
procedure PerformSingleRenameAudit(const APath: string; const ARpath: string; recover: Boolean);
public public
Constructor Create; Constructor Create;
Destructor Destroy; override; Destructor Destroy; override;
@ -135,6 +142,17 @@ type
procedure PerformInitialAudit; procedure PerformInitialAudit;
end; end;
TRecoverThread = class(TThread)
private
recoverService_: TRecoverService;
intervalMs_: Integer;
protected
procedure Execute; override;
public
constructor Create(AService: TRecoverService; AIntervalMs: Integer);
end;
implementation implementation
uses uses
@ -185,9 +203,11 @@ begin
referenceData_ := TDictionary<string, string>.Create; referenceData_ := TDictionary<string, string>.Create;
LoadReferenceJson(GetRunExePathDir + '' + 'Resource\rst.00'); LoadReferenceJson(GetRunExePathDir + '' + 'Resource\rst.00');
if recoverThread_ = nil then
recoverThread_ := TRecoverThread.Create(Self, 10000);
// RecoverAll; // RecoverAll;
PerformInitialAudit;
SetFilter(FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or SetFilter(FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or
FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE); FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE);
@ -206,7 +226,17 @@ begin
FreeAndNil(ConfFiles_); FreeAndNil(ConfFiles_);
FreeAndNil(HeBinFiles_); FreeAndNil(HeBinFiles_);
FreeAndNil(KvBinFiles_); FreeAndNil(KvBinFiles_);
if Assigned(recoverThread_) then
begin
recoverThread_.Terminate;
recoverThread_.WaitFor;
recoverThread_.Free;
recoverThread_ := nil;
end;
FreeAndNil(referenceData_); FreeAndNil(referenceData_);
end; end;
procedure TRecoverService.LoadReferenceJson(const JsonPath: string); procedure TRecoverService.LoadReferenceJson(const JsonPath: string);
@ -498,7 +528,7 @@ begin
JsonLog := Root.AsJSon(True); JsonLog := Root.AsJSon(True);
_Trace('[MGKIM] 생성된 JSON: %s', [JsonLog]); _Trace('[MGKIM] PerformInitialAudit JSON: %s', [JsonLog]);
if( gMgSvc <> nil ) then if( gMgSvc <> nil ) then
gMgSvc.SendIntegrityAuditLog(JsonLog) gMgSvc.SendIntegrityAuditLog(JsonLog)
@ -510,6 +540,177 @@ begin
end; end;
end; end;
procedure TRecoverService.PerformSingleAudit(const APath: string);
var
ExpectedHash, ActualHash, Reason: string;
Root, FileObj, SuccessArray, FailArray: ISuperObject;
JsonLog: string;
IsSuccess: Boolean;
RecoveResult: string;
path: string;
begin
try
Root := SO();
SuccessArray := SA([]);
FailArray := SA([]);
path:= Trim(APath);
path:= LowerCase(path);
if not referenceData_.TryGetValue(path, ExpectedHash) then
begin
IsSuccess := False;
Reason := 'Unknown File (Not in referenceData)';
// DVLOG('PerformSingleAudit, Unknown File (Not in referenceData (%s))', [path]);
exit;
end
else
begin
IsSuccess := CheckFileIntegrity(path, ExpectedHash, ActualHash, Reason);
end;
FileObj := SO();
FileObj.S['filePath'] := path;
if TFile.Exists(path) then
begin
FileObj.S['lastModifiedTime'] := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', TFile.GetLastWriteTime(path));
FileObj.I['size'] := TFile.GetSize(path);
end
else
begin
FileObj.S['lastModifiedTime'] := '';
FileObj.I['size'] := 0;
end;
if IsSuccess then
begin
SuccessArray.AsArray.Add(FileObj);
end
else
begin
if referenceData_.ContainsKey(path) then
RecoveResult := DoRecoverFile(path)
else
RecoveResult := 'Skipped (Not Managed)';
FileObj.S['reason'] := Reason + ' RecoveResult: ' + RecoveResult;
FailArray.AsArray.Add(FileObj);
end;
Root.O['fail'] := FailArray;
Root.O['success'] := SuccessArray;
JsonLog := Root.AsJSon(True);
DVLOG('PerformSingleAudit, JSON: %s', [JsonLog]);
_Trace('[MGKIM] PerformSingleAudit.. JSON: %s', [JsonLog]);
if (gMgSvc <> nil) then
gMgSvc.SendIntegrityAuditLog(JsonLog)
else
_Trace('[MGKIM] PerformSingleAudit gMgSvc.. not create ok!!');
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. PerformSingleAudit()');
end;
end;
procedure TRecoverService.PerformSingleRenameAudit(const APath: string; const ARpath: string; recover: Boolean);
var
ExpectedHash, ActualHash, Reason: string;
Root, FileObj, SuccessArray, FailArray: ISuperObject;
JsonLog: string;
IsSuccess: Boolean;
RecoveResult: string;
path: string;
begin
try
Root := SO();
SuccessArray := SA([]);
FailArray := SA([]);
path:= LowerCase(ARpath);
if not referenceData_.TryGetValue(path, ExpectedHash) then
begin
IsSuccess := False;
Reason := 'Unknown File (Not in referenceData)';
DVLOG('PerformSingleAudit, Unknown File (Not in referenceData (%s))', [path]);
exit;
end
else
begin
IsSuccess := CheckFileIntegrity(ARpath, ExpectedHash, ActualHash, Reason);
end;
FileObj := SO();
FileObj.S['filePath'] := ARpath;
if TFile.Exists(ARpath) then
begin
FileObj.S['lastModifiedTime'] := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', TFile.GetLastWriteTime(APath));
FileObj.I['size'] := TFile.GetSize(ARpath);
end
else
begin
FileObj.S['lastModifiedTime'] := '';
FileObj.I['size'] := 0;
end;
if IsSuccess then
begin
SuccessArray.AsArray.Add(FileObj);
end
else
begin
if not recover then
begin
RecoveResult := DoRecoverFile(path);
end
else
begin
RecoveResult := 'Recover file success, attempted to recover the file by renaming it';
end;
FileObj.S['reason'] := Reason + ' RecoveResult: ' + RecoveResult;
FailArray.AsArray.Add(FileObj);
end;
Root.O['fail'] := FailArray;
Root.O['success'] := SuccessArray;
JsonLog := Root.AsJSon(True);
_Trace('[MGKIM] PerformSingleRenameAudit.. JSON: %s', [JsonLog]);
if (gMgSvc <> nil) then
gMgSvc.SendIntegrityAuditLog(JsonLog)
else
_Trace('[MGKIM] PerformSingleRenameAudit gMgSvc.. not create ok!!');
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. PerformSingleAudit()');
end;
end;
function TRecoverService.IsRefrenceData(const APath: string): Boolean;
var
ExpectedHash: string;
path: string;
begin
Result:= False;
path:= LowerCase(APath);
if not referenceData_.TryGetValue(path, ExpectedHash) then
begin
Result := True;
end;
end;
procedure TRecoverService.CheckAndRecover(sResPath, sPath: String); procedure TRecoverService.CheckAndRecover(sResPath, sPath: String);
var var
zip: TAbUnZipper; zip: TAbUnZipper;
@ -810,29 +1011,39 @@ begin
sDir := ExtractFilePath(pInfo.sPath); sDir := ExtractFilePath(pInfo.sPath);
sFName := ExtractFileName(pInfo.sPath); sFName := ExtractFileName(pInfo.sPath);
sExt := GetFileExt(sFName); // sExt := GetFileExt(sFName);
sExt:= ExtractFileExt(sFName);
case pInfo.dwAction of case pInfo.dwAction of
// 1 , // Add // 1 , // Add
2 ,// Delete 2 ,// Delete
3 , 3 :
4 ,
5 :
begin begin
if (KvBinFiles_.IndexOf(sFName) <> -1) or // if (KvBinFiles_.IndexOf(sFName) <> -1) or
(HeBinFiles_.IndexOf(sFName) <> -1) or // (HeBinFiles_.IndexOf(sFName) <> -1) or
(ConfFiles_.IndexOf(sFName) <> -1) or // (ConfFiles_.IndexOf(sFName) <> -1) or
(LangFiles_.IndexOf(sFName) <> -1) or // (LangFiles_.IndexOf(sFName) <> -1) or
(SLCoreFiles_.IndexOf(sFName) <> -1) or // (SLCoreFiles_.IndexOf(sFName) <> -1) or
(DirNames_.IndexOf(sFName) <> -1) then // (DirNames_.IndexOf(sFName) <> -1) then
begin // begin
// ExpectedHash := referenceData_[KeyPath]; // // ExpectedHash := referenceData_[KeyPath];
// RecoverAll; //// RecoverAll;
PerformInitialAudit; // PerformInitialAudit;
end; // end;
if DataFiles_.IndexOf(sFName) <> -1 then if DataFiles_.IndexOf(sFName) <> -1 then
begin
RecoverData; RecoverData;
end
else
begin
if SameText(sExt, '.log') or SameText(sExt, '.upp') then //eCrmHomeEdition.log"
exit;
// DVLOG('ProcessDirWatchEnt action(%d), (%s), (%s)', [DWORD(pInfo.dwAction), sExt, pInfo.sPath]);
PerformSingleAudit(pInfo.sPath);
end;
// if (gClient <> nil) and gClient.Connected then // if (gClient <> nil) and gClient.Connected then
// begin // begin
@ -859,45 +1070,56 @@ begin
// PerformInitialAudit; // PerformInitialAudit;
// end; // end;
// end; // end;
// 4 : // Rename 4 : // Rename
// begin begin
// if sIgrBlkFRename_ = sFName then if sIgrBlkFRename_ = sFName then
// begin begin
// sIgrBlkFRename_ := ''; sIgrBlkFRename_ := '';
// exit; exit;
// end; end;
//
if SameText(sExt, '.log') then
exit;
_Trace('[MGKIM] ProcessDirWatchEnt Rename 4.. (%s)', [pInfo.sPath]);
if IsRefrenceData(pInfo.sPath) then
// if (KvBinFiles_.IndexOf(sFName) <> -1) or // if (KvBinFiles_.IndexOf(sFName) <> -1) or
// (HeBinFiles_.IndexOf(sFName) <> -1) or // (HeBinFiles_.IndexOf(sFName) <> -1) or
// (ConfFiles_.IndexOf(sFName) <> -1) or // (ConfFiles_.IndexOf(sFName) <> -1) or
// (LangFiles_.IndexOf(sFName) <> -1) or // (LangFiles_.IndexOf(sFName) <> -1) or
// (SLCoreFiles_.IndexOf(sFName) <> -1) or // (SLCoreFiles_.IndexOf(sFName) <> -1) or
// (DirNames_.IndexOf(sFName) <> -1) then // (DirNames_.IndexOf(sFName) <> -1) then
// begin begin
// sBlkFRename_ := sFName; sBlkFRename_ := sFName;
// bBlockRename_ := true; bBlockRename_ := true;
// end; end;
// end; end;
// 5 : 5 :
// begin begin
// // 이름 변경 복구 체크 // 이름 변경 복구 체크
// if sBlkFRename_ <> '' then _Trace('[MGKIM] ProcessDirWatchEnt Rename 5.. (%s)', [pInfo.sPath]);
// begin if sBlkFRename_ <> '' then
// if bBlockRename_ then begin
// begin var success: Boolean;
// sIgrBlkFRename_ := sFName; success:= False;
// bBlockRename_ := false; if bBlockRename_ then
// if MoveFile_wait(pInfo.sPath, sDir + sBlkFRename_, 5) then begin
// begin sIgrBlkFRename_ := sFName;
// sFName := sBlkFRename_; bBlockRename_ := false;
// pInfo.sPath := sDir + sFName; if MoveFile_wait(pInfo.sPath, sDir + sBlkFRename_, 5) then
// end; begin
// end; sFName := sBlkFRename_;
// pInfo.sPath := sDir + sFName;
// sBlkFRename_ := ''; success:= True;
// end; end;
// end;
// else exit; PerformSingleRenameAudit( pInfo.sPath, sDir + sBlkFRename_, success);
end;
sBlkFRename_ := '';
end;
end;
else exit;
end; end;
except except
on E: Exception do on E: Exception do
@ -905,4 +1127,53 @@ begin
end; end;
end; end;
constructor TRecoverThread.Create(AService: TRecoverService; AIntervalMs: Integer);
begin
inherited Create(False);
FreeOnTerminate := False;
recoverService_ := AService;
intervalMs_ := AIntervalMs;
end;
procedure TRecoverThread.Execute;
var
KeyPath: string;
WaitCount, i: Integer;
path: string;
begin
path:= 'C:\Windows\System32\eCrmHeServiced.dll';
DVLOG('TRecoverThread.Execute Start....(%s) (%d)', [path, DWORD(Terminated)]);
//최초 한번은 무조건 검사.
recoverService_.PerformInitialAudit;
while not Terminated do
begin
try
if not TFile.Exists(path) then
begin
DVLOG('TRecoverThread.Execute not Exists file (%s)', [path]);
recoverService_.PerformSingleAudit(path);
end;
except
on E: Exception do
begin
DVLOG('TRecoverThread Error: %s', [E.Message]);
end;
end;
WaitCount := intervalMs_ div 100;
for i := 1 to WaitCount do
begin
if Terminated then Break;
Sleep(100);
end;
end;
DVLOG('[MGKIM] TFileMonitorThread Terminated..', []);
end;
end. end.

Some files were not shown because too many files have changed in this diff Show More