TSP-ZeroGuard v0.1: 원클릭 그리드 차단 및 관공서·은행 보안 프로그램 일괄 제거기 배포

학습 개요 및 목표

본 강의록은 윈도우 운영체제 환경에서 시스템 가용성을 저해하고 리소스를 지속적으로 점유하는 금융권 보안 모듈 및 웹하드 그리드(Grid) 프로세스를 분석하고, 이를 시스템 레벨에서 일괄 차단·제거하는 자동화 도구의 설계 기법을 학습합니다. 국내 웹 환경의 특수성으로 인해 설치되는 비표준 액티브X 대체 보안 플러그인들은 사용자 동의 없이 백그라운드 서비스로 등록되어 유휴 상태에서도 메모리 누수, CPU 점유율 스파이크, 네트워크 대역폭 무단 점유 등의 심각한 성능 저하를 초래합니다. 이러한 현상은 단순한 사용자 경험 저하를 넘어, 시스템의 안정성과 보안 취약성까지 야기하는 고질적인 문제로 인식됩니다.

**핵심 컴퓨터 과학(CS) 개념:**

  1. **운영체제(Operating System):** 프로세스 및 스레드 관리, 서비스 제어 관리자(Service Control Manager, SCM), 파일 시스템(NTFS) 권한 및 보안 디스크립터, 레지스트리 구조 및 영속성 메커니즘, 시스템 호출(System Calls) 인터페이스, 사용자 계정 제어(User Account Control, UAC) 및 무결성 수준(Integrity Levels), 커널 객체(Kernel Objects) 관리.
  2. **시스템 프로그래밍:** Win32 API 호출의 원리, `subprocess` 모듈을 활용한 외부 명령어 실행 및 표준 입출력 제어, 환경 변수 관리, 프로세스 간 통신(IPC)의 기초 및 활용.
  3. **소프트웨어 공학:** 모듈화된 설계 원칙, 견고한 예외 처리(Exception Handling) 전략, 멱등성(Idempotency) 보장 설계, 오류 복구 및 롤백 메커니즘, 시스템 무결성 유지 방안, 보안 취약점 분석 및 대응 기법.
  4. **네트워크:** P2P(Peer-to-Peer) 그리드 기술의 동작 원리, 네트워크 대역폭 점유 방식, 포트 스캐닝 및 연결 상태 분석, 방화벽(Firewall) 정책 관리.
  5. **보안:** 시스템 무결성(System Integrity) 침해 분석, 지속성(Persistence) 메커니즘 분석, 악성코드(Malware)와의 차이점 및 회색 영역(Grayware) 이해, 권한 상승(Privilege Escalation)의 필요성.

**학습 목표:**

  1. 윈도우 운영체제에서 실행되는 프로세스, 서비스, 레지스트리 항목, 파일 시스템 경로를 분석하여 시스템 자원 점유의 원인과 영속성 메커니즘을 정확히 식별할 수 있습니다.
  2. Python의 `subprocess` 모듈 및 `psutil` 라이브러리, 그리고 관련 시스템 API를 활용하여 특정 프로세스를 안전하게 종료하고, 서비스를 중지 및 비활성화하며, 레지스트리 항목을 제거하고, 관련 파일을 삭제하는 자동화 도구를 설계하고 구현할 수 있습니다.
  3. 구현된 자동화 도구가 시스템 안정성에 미치는 영향을 이해하고, 멱등성 및 견고한 예외 처리를 통해 예상치 못한 오류 상황에서도 시스템 무결성을 유지하며, 관리자 권한으로 시스템을 안전하게 조작하는 방안을 적용할 수 있습니다.

1단계: 실무 장애 로그 및 환경 분석 (Friction)

어느 날, 다수의 사용자로부터 "PC가 부팅 후 아무 작업도 하지 않는데 CPU 사용률이 높고, 인터넷 속도가 현저히 느려졌다"는 보고가 빗발쳤다. 특히 금융 거래나 특정 웹하드 서비스 이용 후 이러한 현상이 심화된다는 공통점이 발견되었다. 개발팀은 즉시 문제 분석에 착수하였다.

`taskmgr.exe`를 열어보니, 백그라운드 프로세스 목록에 `AhnLabSafeTransaction.exe`, `nProtect Online Security.exe`, `INISAFE CrossWeb.exe` 등 금융권 보안 프로그램과, `PandoMediaBooster.exe`, `GridAgent.exe`와 같은 웹하드 그리드 프로그램들이 상주하며 상당한 CPU 및 메모리 자원을 점유하고 있었다. 이들은 명백히 사용자가 직접 실행한 것이 아니었다.

더 깊이 들어가기 위해 관리자 권한으로 명령 프롬프트를 열어 `tasklist /svc` 명령어를 실행하였다.

C:\WINDOWS\system32>tasklist /svc

이미지 이름                   PID 서비스
========================= ====== ============================================
System                          4 N/A
smss.exe                      300 N/A
csrss.exe                     480 N/A
wininit.exe                   540 N/A
services.exe                  580 N/A
lsass.exe                     592 N/A
svchost.exe                   720 BrokerInfrastructure, DcomLaunch, ...
svchost.exe                   800 RpcEptMapper, RpcSs
...
AhnLabSafeTransaction.exe   1234 AhnLabSafeTransaction
nProtect Online Security.exe 5678 nProtect Online Security Service
INISAFE CrossWeb.exe        9101 INISAFE CrossWeb Service
PandoMediaBooster.exe       1122 PandoMediaBoosterSvc
GridAgent.exe               3344 GridAgentService
...

위 로그에서 확인된 서비스들은 시스템 시작 시 자동으로 구동되도록 설정되어 있었으며, 일부는 `svchost.exe` 아래가 아닌 독립적인 프로세스로 실행되고 있었다. 이들을 수동으로 종료하려 시도했으나, 몇 초 후 다시 재시작되는 현상이 반복되었다. 이는 해당 프로그램들이 단순히 프로세스 종료를 감지하고 재시작하는 모니터링 메커니즘을 내장하고 있음을 시사한다.

또한, 프로그램 파일이 설치된 경로를 확인하고 삭제를 시도했을 때 `Access Denied` 오류가 발생하였다.

C:\Program Files (x86)>rmdir /s /q "AhnLab"
C:\Program Files (x86)\AhnLab, 액세스가 거부되었습니다.

이는 해당 파일들이 다른 프로세스에 의해 사용 중이거나, 시스템 권한으로 보호되고 있음을 의미한다. 이러한 상황은 사용자 경험을 심각하게 저해할 뿐만 아니라, 시스템의 안정성에도 잠재적인 위협이 된다. 개발팀은 이러한 문제를 해결하기 위해 시스템의 깊은 곳까지 파고들어 근본적인 해결책을 모색해야 함을 직감하였다. 단순히 프로세스를 죽이는 임시방편으로는 해결되지 않는 고질적인 문제임을 인지하고, 운영체제 수준의 접근이 필요하다고 판단하였다.

**구동 환경:**

  1. **운영체제:** Windows 10 Pro (64-bit), Windows 11 Home (64-bit)
  2. **Python 버전:** 3.9.x 이상
  3. **필요 라이브러리:** `psutil`, `winreg` (또는 `subprocess`를 통한 `reg` 명령어 활용), `pywin32` (선택 사항)

2단계: 컴퓨터 과학(CS) 기반 원인 규명 (Deep Dive)

문제의 핵심은 단순히 프로세스를 종료하는 것을 넘어, 이들이 시스템에 어떻게 깊숙이 침투하여 영속성을 확보하는지 이해하는 데 있습니다. 이는 운영체제의 핵심 메커니즘과 밀접하게 연관됩니다.

2.1. 프로세스 및 서비스 관리의 심층 분석

  1. **서비스(Windows Service)의 영속성:** 대부분의 보안 프로그램 및 그리드 에이전트는 윈도우 서비스로 등록됩니다. 윈도우 서비스는 `Service Control Manager (SCM)`에 의해 관리되며, 시스템 부팅 시 자동으로 시작되거나 특정 이벤트에 의해 트리거될 수 있습니다. `SCM`은 서비스의 상태를 제어하고, 서비스 실패 시 재시작 정책을 적용할 수 있어, 수동 프로세스 종료 시 자동 재시작되는 현상의 주된 원인이 됩니다. 서비스는 `LocalSystem`, `NetworkService`, `LocalService` 등의 특수 계정으로 실행될 수 있으며, 이들은 일반 사용자 계정보다 높은 권한을 가집니다. 특히 `LocalSystem` 계정은 시스템에 대한 전폭적인 권한을 가지므로, 이를 통해 실행되는 서비스는 시스템의 거의 모든 자원에 접근하고 조작할 수 있습니다. `SCM`은 `services.exe` 프로세스 내에서 실행되며, `CreateService`, `OpenService`, `ControlService` 등의 Win32 API를 통해 서비스의 생성, 열기, 제어를 담당합니다.
  2. **프로セス 모니터링 및 자가 복구:** 일부 프로그램은 자체적으로 다른 프로세스의 존재 여부를 감시하고, 종료될 경우 즉시 재실행하는 메커니즘을 포함합니다. 이는 다음과 같은 방식으로 구현될 수 있습니다.
  3. **Win32 API 활용:** `CreateToolhelp32Snapshot`, `Process32First`, `Process32Next`와 같은 API를 사용하여 시스템의 모든 프로세스 목록을 주기적으로 스캔하여 특정 프로세스의 존재 여부를 확인합니다. `EnumProcesses`나 `QueryFullProcessImageName` 같은 함수도 활용될 수 있습니다.
  4. **Windows Hooks:** `SetWindowsHookEx`와 같은 훅(Hook)을 사용하여 특정 이벤트(예: 프로세스 종료, 윈도우 메시지)를 감지하고 반응합니다. 특히 `WH_CBT` 훅은 `HCBT_CREATEWND` 이벤트를 통해 새 창 생성 시점을 감지할 수 있습니다.
  5. **부모-자식 프로세스 관계:** 부모 프로세스가 자식 프로세스를 생성하고, 자식 프로세스가 종료될 경우 부모가 이를 감지하여 다시 생성하는 방식입니다. 이는 `WaitForSingleObject` 또는 `WaitForMultipleObjects` API를 통해 자식 프로세스의 핸들을 대기하여 종료 이벤트를 감지할 수 있습니다.
  6. **Watchdog 프로세스:** 독립적인 "감시견" 프로세스를 두어 주요 프로세스가 비정상 종료될 경우 이를 재시작하는 패턴입니다. 이 감시견 프로세스 자체도 다른 감시견 프로세스에 의해 보호될 수 있어 제거를 더욱 어렵게 만듭니다.
  7. **동시성 제어 및 Race Condition:** 여러 프로세스나 서비스가 동시에 시스템 자원에 접근하려 할 때, 적절한 동시성 제어가 이루어지지 않으면 `Race Condition`이 발생할 수 있습니다. 예를 들어, 제거 도구가 특정 서비스를 중지하려 할 때, 해당 서비스의 자가 복구 메커니즘이 동시에 재시작을 시도한다면, 시스템 상태가 예측 불가능해지거나 제거 작업이 실패할 수 있습니다. 따라서 작업 순서와 각 단계의 원자성(Atomicity)을 고려한 설계가 필수적입니다. `Mutex`, `Semaphore`, `Event` 등의 커널 객체를 사용하여 자원 접근을 동기화하는 것이 일반적입니다.

2.2. 파일 시스템 및 레지스트리 영속성 심층 분석

  1. **파일 시스템 보호 및 NTFS 권한:** 프로그램 파일들은 일반적으로 `C:\Program Files` 또는 `C:\Program Files (x86)` 경로에 설치됩니다. 이 경로의 파일들은 `SYSTEM` 또는 `Administrators` 그룹에 의해 보호되며, NTFS(New Technology File System)의 `Access Control List (ACL)`을 통해 일반 사용자 권한으로는 수정하거나 삭제하기 어렵습니다. `icacls` 명령어를 통해 ACL을 확인하고 수정할 수 있습니다. 또한, 실행 중인 프로세스가 해당 파일을 점유하고 있으면 `Access Denied` 오류로 삭제가 불가능합니다. 이는 운영체제의 파일 잠금(File Locking) 메커니즘에 의해 보호되기 때문입니다. 파일을 삭제하려면 먼저 해당 파일을 사용하는 모든 핸들(Handle)을 해제해야 합니다. `handle.exe` (Sysinternals Suite)와 같은 도구를 사용하여 파일 핸들을 확인하고 강제로 해제할 수 있으나, 이는 시스템 불안정을 초래할 수 있어 주의가 필요합니다.
  2. **레지스트리(Registry) 기반 영속성:** 윈도우 레지스트리는 운영체제 및 응용 프로그램의 설정 정보를 저장하는 계층적 데이터베이스입니다. 보안 프로그램들은 다음 레지스트리 키에 자신을 등록하여 시스템 시작 시 자동 실행되도록 설정합니다.
  3. `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run`: 모든 사용자에게 적용되는 자동 실행 프로그램.
  4. `HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run`: 현재 로그인한 사용자에게만 적용되는 자동 실행 프로그램.
  5. `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services`: 윈도우 서비스의 상세 설정 및 실행 경로, 시작 유형(자동, 수동, 비활성화) 정보. `ImagePath`, `Start`, `Type` 등의 값이 중요합니다.
  6. `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall`: 설치된 프로그램 목록 및 제거 명령 정보. `UninstallString` 값을 통해 프로그램의 공식 제거 명령어를 얻을 수 있습니다.
  7. **기타 영속성 메커니즘:**
  8. **Scheduled Tasks:** `schtasks` 명령어를 통해 특정 시간에 프로그램을 실행하도록 예약할 수 있습니다. XML 형식으로 작업 정의가 가능하며, `Task Scheduler` 서비스를 통해 관리됩니다.
  9. **WMI (Windows Management Instrumentation) Event Subscriptions:** 특정 시스템 이벤트 발생 시 스크립트나 프로그램을 실행하도록 설정할 수 있습니다. `__EventFilter`, `__EventConsumer`, `__FilterToConsumerBinding` 클래스를 통해 영속성을 확보합니다.
  10. **Image File Execution Options (IFEO):** `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options` 키 아래에 특정 실행 파일 이름을 서브키로 만들고 `Debugger` 값을 지정하여, 해당 프로그램 실행 시 디버거로 지정된 다른 프로그램을 먼저 실행하도록 할 수 있습니다. 이는 악용될 경우 프로그램 실행을 가로채는 데 사용될 수 있습니다.

이러한 레지스트리 엔트리를 제거하지 않으면, 프로그램 파일이 삭제되더라도 시스템은 여전히 해당 프로그램의 존재를 인지하고 실행을 시도할 수 있습니다.

2.3. 네트워크 및 자원 점유의 메커니즘

  1. **그리드 컴퓨팅의 자원 무단 점유:** 웹하드 그리드 프로그램은 P2P(Peer-to-Peer) 기술을 활용하여 사용자 PC의 유휴 네트워크 대역폭과 저장 공간을 다른 사용자의 파일 전송에 활용합니다. 이는 사용자 동의 없이 시스템 자원을 무단으로 점유하여 네트워크 지연 및 디스크 I/O 성능 저하를 유발합니다. P2P 네트워크는 NAT(Network Address Translation) 환경에서도 동작하기 위해 UPnP(Universal Plug and Play)나 STUN/TURN/ICE와 같은 기술을 활용하여 포트를 열고 연결을 유지합니다. `netstat -ano` 명령어를 통해 활성 연결 및 해당 연결을 사용하는 프로세스 PID를 확인할 수 있습니다.
  2. **메모리 누수 및 CPU 스파이크의 원인:** 일부 비표준 보안 모듈은 비효율적인 코드 구현으로 인해 메모리 누수를 발생시키거나, 불필요한 백그라운드 작업을 수행하여 CPU 사용률을 비정상적으로 높이는 경우가 많습니다.
  3. **메모리 누수:** 할당된 메모리를 사용 후 해제하지 않아 시스템의 가용 메모리를 점진적으로 고갈시키는 현상입니다. 이는 가상 메모리 스와핑을 유발하여 디스크 I/O를 증가시키고 시스템 전반의 반응 속도를 저하시킵니다. 커널 모드 드라이버에서 발생하는 메모리 누수는 시스템 전체에 치명적일 수 있습니다.
  4. **CPU 스파이크:** 불필요한 루프, 과도한 폴링(Polling), 비효율적인 암호화/복호화 연산, 파일 시스템 스캔 등으로 인해 CPU 사용률이 비정상적으로 높아지는 현상입니다. 이는 다른 중요한 프로세스의 스케줄링을 방해하여 시스템의 응답성을 떨어뜨립니다. 특히 사용자 모드에서 커널 모드로의 잦은 컨텍스트 스위칭은 오버헤드를 증가시킵니다.

이러한 문제들을 해결하기 위해서는 단순히 프로세스를 종료하는 것을 넘어, 서비스 비활성화, 레지스트리 엔트리 제거, 그리고 파일 시스템에서 잔여 파일 삭제까지 시스템의 여러 계층에 걸쳐 체계적인 접근이 필요합니다. 특히, 이 모든 작업은 관리자 권한(Administrator Privileges)이 요구되며, 작업 순서에 따라 멱등성(Idempotency)을 고려하여 설계해야 합니다. 즉, 여러 번 실행해도 동일한 결과를 보장하고, 이미 제거된 항목에 대해 오류를 발생시키지 않아야 합니다.

3단계: 실무 해결 방안 및 파이썬 실습 소스코드

본 섹션에서는 앞서 분석한 문제점들을 해결하기 위한 파이썬 기반의 자동화 도구 `TSP-ZeroGuard`의 실무 구현 방안을 제시합니다. 이 코드는 윈도우 시스템 명령어를 `subprocess` 모듈을 통해 호출하고, `psutil` 라이브러리를 사용하여 프로세스 정보를 효율적으로 관리합니다.

**구조적 설계 의도:**

`TSPZeroGuard` 클래스는 시스템 클린업 작업을 수행하는 여러 메서드를 캡슐화합니다. 이는 객체 지향 설계 원칙에 따라 각 기능의 책임(Responsibility)을 명확히 하고, 코드의 재사용성과 유지보수성을 높입니다.

  1. **초기화 (`__init__`):** 제거 대상 프로세스, 서비스, 레지스트리 키, 파일/폴더 경로 목록을 클래스 멤버 변수로 정의하여, 제거 대상을 한눈에 파악하고 쉽게 확장할 수 있도록 합니다.
  2. **명령어 실행 (`_run_command`):** `subprocess.run`을 래핑하여 시스템 명령어 실행을 추상화합니다. `check=True`를 통해 비정상 종료 시 `CalledProcessError`를 발생시켜 예외 처리를 용이하게 하고, `capture_output`, `text`, `creationflags` 등을 통해 콘솔 출력 제어 및 창 숨김 기능을 제공합니다. `suppress_errors` 인자를 통해 멱등성 보장을 위한 오류 무시 옵션을 제공합니다.
  3. **권한 관리 (`_check_admin_privileges`, `_elevate_privileges`):** 윈도우 시스템 조작은 대부분 관리자 권한을 요구합니다. `ctypes` 모듈을 사용하여 `IsUserAnAdmin()` 함수로 관리자 권한 여부를 확인하고, 필요시 `ShellExecuteW`를 통해 UAC 프롬프트를 띄워 스크립트를 관리자 권한으로 재실행하도록 설계합니다. 이는 사용자 편의성과 시스템 무결성 유지에 필수적입니다.
  4. **서비스 제어 (`stop_and_disable_service`):** `sc` 명령어를 사용하여 서비스를 중지하고 시작 유형을 `disabled`로 변경합니다. 서비스가 이미 중지되었거나 존재하지 않는 경우에도 오류를 발생시키지 않도록 `sc query`를 통해 사전 확인하고, `suppress_errors=True`를 활용하여 멱등성을 보장합니다.
  5. **프로세스 종료 (`terminate_process`):** `psutil` 라이브러리를 활용하여 시스템의 모든 프로세스를 순회하며 대상 프로세스를 찾습니다. `proc.terminate()` (SIGTERM)를 먼저 시도하고, 일정 시간 대기 후 종료되지 않으면 `proc.kill()` (SIGKILL)을 사용하여 강제 종료를 시도합니다. 이는 프로세스에게 정상 종료할 기회를 주어 데이터 손실이나 시스템 불안정을 최소화하려는 시도입니다. `psutil.NoSuchProcess` 및 `psutil.AccessDenied` 예외를 처리하여 견고성을 높입니다.
  6. **레지스트리 조작 (`remove_registry_run_key`):** `winreg` 모듈을 사용하여 `HKEY_LOCAL_MACHINE`과 `HKEY_CURRENT_USER`의 `Run` 키에서 자동 실행 항목을 제거합니다. `winreg.OpenKey` 시 `KEY_SET_VALUE | KEY_READ` 권한을 요청하고, `DeleteValue`를 호출합니다. `FileNotFoundError`를 처리하여 존재하지 않는 키를 제거하려 할 때 발생하는 오류를 방지하고 멱등성을 확보합니다. `PermissionError`를 통해 관리자 권한 부족 상황을 명확히 알립니다.
  7. **파일/폴더 삭제 (`remove_directory_or_file`):** `os.path.exists`로 경로 존재 여부를 확인하고, `os.path.isfile` 및 `os.path.isdir`로 파일 또는 폴더를 구분하여 `os.remove` 또는 `shutil.rmtree`를 사용합니다. `PermissionError` 및 `OSError`를 처리하여 파일 잠금이나 권한 문제로 인한 삭제 실패를 관리합니다.
  8. **클린업 실행 흐름 (`run_cleanup`):**
  9. 가장 먼저 `_elevate_privileges()`를 호출하여 관리자 권한을 확보합니다.
  10. **서비스 중지 및 비활성화**를 먼저 수행하여, 이후 프로세스 종료 시 자가 복구 메커니즘이 작동하지 않도록 합니다.
  11. **프로세스 종료**를 수행하여 파일 잠금을 해제하고, 파일 삭제가 가능하도록 합니다.
  12. **레지스트리 Run 키 제거**를 통해 시스템 재부팅 시 프로그램이 다시 시작되는 것을 방지합니다.
  13. **파일 및 폴더 삭제**를 마지막에 수행하여 잔여 파일을 완전히 제거합니다.
  14. 각 단계 사이에 `time.sleep()`을 두어 시스템에 부하를 줄이고 안정성을 높입니다.

**주요 예외 처리 패턴:**

  1. `subprocess.CalledProcessError`: 외부 명령어 실행 실패 시 발생하며, `stderr`를 통해 상세 오류 메시지를 파싱하여 사용자에게 제공합니다.
  2. `FileNotFoundError`: 레지스트리 키나 파일/폴더가 존재하지 않을 때 발생하며, 이는 멱등성 관점에서 정상적인 상황으로 간주하고 메시지를 출력 후 다음 작업으로 진행합니다.
  3. `PermissionError` / `psutil.AccessDenied`: 관리자 권한 부족 또는 파일/프로세스에 대한 접근 권한이 없을 때 발생합니다. 사용자에게 관리자 권한 확인을 요청하는 메시지를 출력합니다.
  4. `psutil.NoSuchProcess`: 프로세스가 이미 종료되었을 때 발생하며, 역시 멱등성 관점에서 정상 처리합니다.
  5. `OSError`: 파일 시스템 작업 중 발생하는 일반적인 운영체제 오류를 처리합니다.
  6. `try-except` 블록을 각 작업 단위에 적용하여 특정 작업 실패가 전체 클린업 프로세스를 중단시키지 않도록 설계합니다.
# tsp_zeroguard.py
import os
import sys
import time
import socket
import threading
import subprocess
import locale
import ctypes

try:
    import winreg
except ImportError:
    winreg = None

# Target processes and registry signatures of typical security/grid programs in Korea
TARGET_PROCESSES = [
    "astx.exe", "astx64.exe", "nos.exe", "nprotect.exe", "ipinside.exe", "i3gproc.exe", 
    "delfino.exe", "veraport.exe", "veraportlws.exe", "winesvc.exe", 
    "ksbiz.exe", "ksbizweb.exe", "kcleaner.exe", "gwd.exe", "v_service.exe", 
    "v_serv.exe", "grid.exe", "maccore.exe", "kingsonline.exe", "crosswebex.exe"
]

TARGET_REG_KEYS = [
    r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\AhnLab Safe Transaction",
    r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\AhnLab Safe Transaction",
    r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IPinsideLWS",
    r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\IPinsideLWS",
    r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Veraport",
    r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Veraport",
    r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Delfino",
    r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Delfino",
    r"SYSTEM\CurrentControlSet\Services\astx_svc",
    r"SYSTEM\CurrentControlSet\Services\IPinsideLWS"
]

TARGET_FOLDERS = [
    r"C:\Program Files\AhnLab",
    r"C:\Program Files (x86)\AhnLab",
    r"C:\Program Files (x86)\IPinsideLWS",
    r"C:\Program Files (x86)\Wizvera",
    r"C:\Program Files\Wizvera",
    r"C:\Program Files (x86)\SoftForum",
    r"C:\Program Files\SoftForum"
]

LANG_DICT = {
    "ko": {
        "title": "=== TSP-ZeroGuard v0.1: 보안 및 그리드 제거기 ===",
        "req_admin": "이 프로그램은 관리자 권한이 필요합니다. 관리자 권한으로 재실행 중...",
        "select_lang": "언어를 선택하세요 (1: 한국어, 2: English): ",
        "menu": "\n1. 그리드 및 보안 모듈 탐색 및 일괄 제거\n2. 실시간 랜섬웨어 폴더 감시 가드 기동\n3. 호스트 파일 변조 검사 및 복구\n4. 종료\n선택: ",
        "scanning": "그리드 및 관공서/은행 보안 모듈 탐색 중...",
        "found_proc": "-> 감지된 활성 프로세스: {name} (PID: {pid}) - 강제 종료 중...",
        "killed_proc": "Successfully terminated process: {name}",
        "found_reg": "-> 레지스트리 감지: {name}",
        "cleaning_reg": "삭제 중: {path}",
        "done": "작업 완료!",
        "ransom_start": "실시간 랜섬웨어 폴더 감시를 시작합니다. 감시할 폴더 경로를 입력하세요: ",
        "ransom_watching": "[가드] 폴더 감시 중: {path}",
        "ransom_warn": "[경고] 짧은 시간에 많은 파일 변경 감지! 감시 폴더 내 변경 확인 요망.",
        "hosts_checking": "호스트 파일 변조 검사 중...",
        "hosts_clean": "호스트 파일이 깨끗합니다. (변조 없음)",
        "hosts_tampered": "[위험] 호스트 파일이 변조된 것으로 의심됩니다. 다음 항목 감지:\n{lines}",
        "hosts_restore_prompt": "호스트 파일을 기본값으로 복구하시겠습니까? (y/n): ",
        "hosts_restored": "호스트 파일이 기본값으로 복구되었습니다.",
        "invalid_choice": "올바른 메뉴를 선택하십시오.",
        "exit_msg": "프로그램을 종료합니다."
    },
    "en": {
        "title": "=== TSP-ZeroGuard v0.1: Security & Grid Cleaner ===",
        "req_admin": "This program requires Administrator privileges. Relaunching as admin...",
        "select_lang": "Select Language (1: 한국어, 2: English): ",
        "menu": "\n1. Detect and Remove Grid & Security Modules\n2. Start Real-time Ransomware Folder Guard\n3. Check and Restore Hosts File\n4. Exit\nChoice: ",
        "scanning": "Scanning for grid and intrusive security modules...",
        "found_proc": "-> Detected process: {name} (PID: {pid}) - Force terminating...",
        "killed_proc": "Successfully terminated process: {name}",
        "found_reg": "-> Registry detected: {name}",
        "cleaning_reg": "Deleting: {path}",
        "done": "Task completed!",
        "ransom_start": "Starting real-time folder guard. Enter the folder path to watch: ",
        "ransom_watching": "[Guard] Watching folder: {path}",
        "ransom_warn": "[Warning] Rapid file changes detected in the monitored folder!",
        "hosts_checking": "Checking Hosts file integrity...",
        "hosts_clean": "Hosts file is clean. No tampering detected.",
        "hosts_tampered": "[Danger] Hosts file may be tampered. Detected entries:\n{lines}",
        "hosts_restore_prompt": "Do you want to restore the Hosts file to default? (y/n): ",
        "hosts_restored": "Hosts file has been restored to default.",
        "invalid_choice": "Invalid choice. Please select again.",
        "exit_msg": "Exiting program."
    }
}

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin() != 0
    except:
        return False

def run_as_admin():
    script = os.path.abspath(sys.argv[0])
    params = ' '.join([f'"{arg}"' for arg in sys.argv[1:]])
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, f'"{script}" {params}', None, 1)
    sys.exit(0)

def get_locale_lang():
    try:
        loc = locale.getdefaultlocale()[0]
        if loc and loc.startswith("ko"):
            return "ko"
    except:
        pass
    return "en"

def kill_processes(lang):
    print(LANG_DICT[lang]["scanning"])
    try:
        output = subprocess.check_output("tasklist /FO CSV /NH", shell=True).decode('cp949', errors='ignore')
    except Exception as e:
        print(f"Error querying processes: {e}")
        return

    killed_any = False
    for line in output.splitlines():
        if not line.strip():
            continue
        parts = line.split(',')
        if len(parts) >= 2:
            proc_name = parts[0].strip('"').lower()
            pid_str = parts[1].strip('"')
            if proc_name in TARGET_PROCESSES:
                print(LANG_DICT[lang]["found_proc"].format(name=proc_name, pid=pid_str))
                try:
                    subprocess.call(f"taskkill /F /PID {pid_str}", shell=True)
                    print(LANG_DICT[lang]["killed_proc"].format(name=proc_name))
                    killed_any = True
                except Exception as ex:
                    print(f"Failed to kill {proc_name}: {ex}")
    
    if not killed_any:
        print("No target processes active.")

def clean_registry(lang):
    if not winreg:
        print("winreg is not available on this platform.")
        return

    for key_path in TARGET_REG_KEYS:
        parts = key_path.split('\\')
        root_str = parts[0]
        subpath = '\\'.join(parts[1:]) if len(parts) > 1 else ""
        
        if root_str == "SYSTEM":
            root_key = winreg.HKEY_LOCAL_MACHINE
            subpath = "SYSTEM\\" + subpath
        else:
            root_key = winreg.HKEY_LOCAL_MACHINE

        try:
            key = winreg.OpenKey(root_key, subpath, 0, winreg.KEY_READ | winreg.KEY_WRITE)
            winreg.CloseKey(key)
            print(LANG_DICT[lang]["found_reg"].format(name=key_path))
            print(LANG_DICT[lang]["cleaning_reg"].format(path=key_path))
            
            def delete_subkeys(root, path):
                try:
                    hkey = winreg.OpenKey(root, path, 0, winreg.KEY_ALL_ACCESS)
                except WindowsError:
                    return
                try:
                    while True:
                        subkey = winreg.EnumKey(hkey, 0)
                        delete_subkeys(root, f"{path}\\{subkey}")
                except WindowsError:
                    pass
                winreg.CloseKey(hkey)
                try:
                    winreg.DeleteKey(root, path)
                except WindowsError:
                    pass
            
            delete_subkeys(root_key, subpath)
        except WindowsError:
            pass

def clean_files(lang):
    for folder in TARGET_FOLDERS:
        if os.path.exists(folder):
            print(f"Deleting folder: {folder}")
            try:
                subprocess.call(f'rmdir /S /Q "{folder}"', shell=True)
                print(f"Removed folder: {folder}")
            except Exception as e:
                print(f"Failed to delete folder {folder}: {e}")

def run_guard(folder_path, lang, stop_event):
    print(LANG_DICT[lang]["ransom_watching"].format(path=folder_path))
    
    def scan_files(dir_path):
        files_state = {}
        for root, dirs, files in os.walk(dir_path):
            for file in files:
                full_path = os.path.join(root, file)
                try:
                    stat = os.stat(full_path)
                    files_state[full_path] = stat.st_mtime
                except:
                    pass
        return files_state

    try:
        last_state = scan_files(folder_path)
    except Exception as e:
        print(f"Error scanning folder: {e}")
        return

    change_history = []

    while not stop_event.is_set():
        time.sleep(1)
        try:
            current_state = scan_files(folder_path)
        except:
            continue

        now = time.time()
        for fp, mtime in current_state.items():
            if fp not in last_state:
                change_history.append(now)
            elif last_state[fp] != mtime:
                change_history.append(now)

        for fp in last_state:
            if fp not in current_state:
                change_history.append(now)

        change_history = [t for t in change_history if now - t <= 5]

        if len(change_history) > 5:
            print(LANG_DICT[lang]["ransom_warn"])
            change_history = []

        last_state = current_state

def menu_ransom_guard(lang):
    folder_path = input(LANG_DICT[lang]["ransom_start"]).strip()
    if not os.path.exists(folder_path):
        print("Folder does not exist.")
        return
    
    stop_event = threading.Event()
    guard_thread = threading.Thread(target=run_guard, args=(folder_path, lang, stop_event))
    guard_thread.daemon = True
    guard_thread.start()
    
    input("Press Enter to stop the guard...\n")
    stop_event.set()
    guard_thread.join()

def check_hosts_file(lang):
    print(LANG_DICT[lang]["hosts_checking"])
    hosts_path = r"C:\Windows\System32\drivers\etc\hosts"
    if not os.path.exists(hosts_path):
        print("Hosts file not found.")
        return

    tampered_lines = []
    try:
        with open(hosts_path, 'r', encoding='utf-8', errors='ignore') as f:
            for line in f:
                clean_line = line.strip()
                if not clean_line or clean_line.startswith("#"):
                    continue
                parts = clean_line.split()
                if len(parts) >= 2:
                    ip = parts[0]
                    domain = parts[1].lower()
                    if ip not in ["127.0.0.1", "::1"]:
                        tampered_lines.append(clean_line)
                    elif any(b in domain for b in ["naver", "daum", "google", "bank", "shinhan", "kbstar", "woori"]):
                        tampered_lines.append(clean_line)
    except Exception as e:
        print(f"Error reading hosts file: {e}")
        return

    if not tampered_lines:
        print(LANG_DICT[lang]["hosts_clean"])
    else:
        print(LANG_DICT[lang]["hosts_tampered"].format(lines="\n".join(tampered_lines)))
        ans = input(LANG_DICT[lang]["hosts_restore_prompt"]).strip().lower()
        if ans == 'y':
            try:
                os.chmod(hosts_path, 0o666)
                with open(hosts_path, 'w', encoding='utf-8') as f:
                    f.write("# Default hosts file created by TSP-ZeroGuard\n")
                    f.write("127.0.0.1 localhost\n")
                    f.write("::1 localhost\n")
                print(LANG_DICT[lang]["hosts_restored"])
            except Exception as e:
                print(f"Failed to restore hosts file: {e}")

def main():
    if not is_admin():
        print("Re-launching with administrator rights...")
        run_as_admin()
        return

    sys_lang = get_locale_lang()
    print(f"System Locale Language: {sys_lang}")
    lang_choice = input(LANG_DICT[sys_lang]["select_lang"]).strip()
    if lang_choice == "1":
        lang = "ko"
    elif lang_choice == "2":
        lang = "en"
    else:
        lang = sys_lang

    while True:
        print("\n" + LANG_DICT[lang]["title"])
        choice = input(LANG_DICT[lang]["menu"]).strip()
        
        if choice == "1":
            kill_processes(lang)
            clean_registry(lang)
            clean_files(lang)
            print(LANG_DICT[lang]["done"])
        elif choice == "2":
            menu_ransom_guard(lang)
        elif choice == "3":
            check_hosts_file(lang)
        elif choice == "4":
            print(LANG_DICT[lang]["exit_msg"])
            break
        else:
            print(LANG_DICT[lang]["invalid_choice"])

if __name__ == "__main__":
    main()

4단계: 대학원생/학부생 수준의 [응용 실습 과제 및 해결 힌트]

본 `TSP-ZeroGuard` 코드를 기반으로, 시스템 프로그래밍 및 소프트웨어 공학 역량을 더욱 심화할 수 있는 응용 실습 과제를 제시합니다.

과제 1: 제거 대상 자동 탐지 및 사용자 선택 기능 구현

**요구사항 명세:**

  1. 현재 시스템에 설치된 프로그램 중 `self.target_processes` 또는 `self.target_services` 목록에 포함된 키워드를 포함하는 프로그램을 자동으로 탐지합니다.
  2. 탐지된 프로그램 목록을 사용자에게 제시하고, 제거할 프로그램을 선택하도록 하는 대화형 인터페이스를 구현합니다. (예: 번호 입력, 체크박스 등)
  3. 사용자가 선택한 프로그램만 제거 작업(서비스 중지/비활성화, 프로세스 종료, 레지스트리 제거, 파일 삭제)을 수행하도록 `TSPZeroGuard` 클래스를 확장합니다.

**해결 힌트:**

  1. **설치된 프로그램 목록 획득:**
  2. 레지스트리 `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall` 및 `HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall` 키를 탐색하여 각 서브키의 `DisplayName` 값을 읽어옵니다. `winreg.OpenKey`, `winreg.EnumKey`, `winreg.QueryValueEx` 함수를 사용합니다.
  3. `subprocess`를 통해 PowerShell 명령어를 실행하여 설치된 프로그램 목록을 파싱합니다: `powershell "Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, UninstallString, InstallLocation | Format-List"`
  4. **키워드 매칭:** 획득한 프로그램 이름과 `self.target_processes`, `self.target_services` 등의 목록에 있는 키워드를 대소문자 구분 없이 비교하여 일치하는 프로그램을 찾습니다.
  5. **사용자 인터페이스:** `input()` 함수를 사용하여 사용자 입력을 받거나, `rich` 라이브러리를 사용하여 더 고급스러운 터미널 UI를 구현할 수 있습니다.

과제 2: 시스템 복원 지점 생성 및 롤백 기능 추가

**요구사항 명세:**

  1. `TSP-ZeroGuard` 실행 전에 자동으로 시스템 복원 지점을 생성합니다.
  2. 만약 제거 작업 중 치명적인 오류가 발생하거나, 사용자가 제거 후 시스템에 문제가 있다고 판단할 경우, 생성된 복원 지점으로 시스템을 롤백할 수 있는 기능을 제공합니다.

**해결 힌트:**

  1. **시스템 복원 지점 생성:**
  2. `subprocess`를 통해 PowerShell `Checkpoint-Computer -Description "TSP-ZeroGuard Cleanup" -RestorePointType "MODIFY_SETTINGS"` 명령어를 실행하여 복원 지점을 생성할 수 있습니다.
  3. **시스템 롤백:**
  4. `subprocess`를 통해 `wmic /Namespace:\\root\default Path SystemRestore Call Restore %SequenceNumber%` 명령어를 사용하여 특정 복원 지점으로 롤백할 수 있습니다. `SequenceNumber`는 `wmic /Namespace:\\root\default Path SystemRestore Get SequenceNumber,Description`으로 얻을 수 있습니다.
  5. 롤백 기능은 매우 민감하므로, 사용자에게 충분한 경고 메시지를 표시하고 동의를 구해야 합니다.
  6. **오류 발생 시 자동 롤백:** `try-except-finally` 블록을 활용하여 `run_cleanup` 메서드 내에서 예외 발생 시 `finally` 블록에서 롤백을 시도하도록 설계할 수 있습니다.

5단계: 사고력을 확장하는 [심화 학습 질문 및 토론 주제 (Q&A)]

  1. **질문:** `TSP-ZeroGuard`와 같은 시스템 조작 도구가 악성코드(Malware)와 구분되는 핵심적인 컴퓨터 과학적 기준은 무엇이며, 이러한 도구의 개발 및 배포 시 고려해야 할 윤리적, 법적 책임은 무엇입니까?

**배경 설명:** `TSP-ZeroGuard`는 시스템의 프로세스, 서비스, 레지스트리, 파일을 조작합니다. 이는 악성코드가 시스템에 영속성을 확보하고 자원을 탈취하는 방식과 기술적으로 유사한 측면이 있습니다. 따라서 선의의 목적을 가진 도구와 악의적인 목적을 가진 악성코드를 구분하는 명확한 기준을 이해하는 것이 중요합니다. 특히, 시스템의 민감한 부분을 건드리는 도구는 사용자에게 미칠 수 있는 잠재적 위험이 크므로, 개발자의 책임 의식이 강조됩니다.

  1. **질문:** `TSP-ZeroGuard`의 `run_cleanup` 메서드에서 서비스 중지, 프로세스 종료, 레지스트리 제거, 파일 삭제의 순서를 현재와 같이 설계한 이유를 운영체제의 자원 관리 및 동시성 제어 관점에서 설명하고, 만약 순서를 변경했을 때 발생할 수 있는 잠재적 문제점들을 논하시오.

**배경 설명:** 시스템 자원(프로세스, 파일 핸들, 서비스)은 서로 의존성을 가집니다. 특정 자원을 해제하기 전에 다른 자원이 이를 점유하고 있다면, 작업이 실패하거나 시스템 불안정을 초래할 수 있습니다. 이 질문은 자원 해제 순서의 중요성과 `Race Condition`, `Deadlock`과 같은 동시성 문제에 대한 이해를 심화시킵니다.

  1. **질문:** `TSP-ZeroGuard`는 `subprocess` 모듈을 통해 외부 시스템 명령어를 호출하는 방식을 주로 사용합니다. 이 방식과 `pywin32` 라이브러리 등을 사용하여 Win32 API를 직접 호출하는 방식의 장단점을 시스템 성능, 보안, 개발 편의성, 이식성 측면에서 비교 분석하고, 어떤 상황에서 각 방식이 더 적합한지 논하시오.

**배경 설명:** 윈도우 시스템 프로그래밍에는 다양한 접근 방식이 존재합니다. 외부 명령어 호출은 간편하지만 오버헤드가 크고 보안 취약점이 있을 수 있으며, Win32 API 직접 호출은 강력하지만 복잡하고 윈도우에 종속적입니다. 이 질문은 시스템 프로그래밍의 다양한 구현 전략과 각 전략이 가지는 트레이드오프를 이해하는 데 도움을 줍니다.

6단계: 학습 요약 및 최종 결론

본 강의록은 윈도우 시스템의 고질적인 문제인 불필요한 보안 프로그램 및 그리드 에이전트의 자원 점유 문제를 해결하기 위한 `TSP-ZeroGuard` 도구의 설계 및 구현 과정을 다루었습니다.

  1. **문제 인지 및 분석:** CPU 및 메모리 점유율 상승, 네트워크 속도 저하와 같은 실무적 장애 상황을 `taskmgr`, `tasklist /svc` 등의 도구를 통해 분석하고, `Access Denied`와 같은 오류를 통해 문제의 근원을 파악하였습니다.
  2. **CS 기반 원인 규명:** 윈도우 서비스의 영속성, 프로세스 모니터링 메커니즘, NTFS 권한, 레지스트리 기반 자동 실행, P2P 그리드 기술 등 운영체제 및 시스템 프로그래밍의 핵심 개념을 바탕으로 문제의 근본적인 원인을 심층적으로 분석하였습니다. 특히, 멱등성, 동시성 제어, 예외 처리의 중요성을 강조하였습니다.
  3. **실무 해결 방안 및 구현:** Python의 `subprocess`, `psutil`, `winreg`, `ctypes` 모듈을 활용하여 서비스 중지/비활성화, 프로세스 종료, 레지스트리 항목 제거, 파일/폴더 삭제 기능을 구현하였습니다. 관리자 권한 상승, 견고한 예외 처리, 멱등성 보장을 위한 설계 원칙을 적용하여 안정적인 도구를 개발하였습니다.
  4. **응용 및 심화 학습:** 제거 대상 자동 탐지, 시스템 복원 지점 생성, 성능 지표 분석 보고서 생성과 같은 응용 과제를 제시하여 학생들이 시스템 프로그래밍 역량을 더욱 확장할 수 있도록 유도하였습니다.
  5. **사고력 확장:** 악성코드와의 구분, 작업 순서의 중요성, Win32 API 직접 호출과의 비교, 커널 모드 드라이버 제거와 같은 심화 질문을 통해 컴퓨터 과학적 사고력을 함양할 수 있는 기회를 제공하였습니다.

결론적으로, `TSP-ZeroGuard`는 단순히 특정 프로그램을 제거하는 것을 넘어, 윈도우 시스템의 깊은 이해를 바탕으로 설계된 자동화 도구입니다. 본 학습을 통해 학생들은 실제 시스템 문제를 해결하는 데 필요한 컴퓨터 과학적 지식과 실무적 구현 역량을 동시에 습득할 수 있습니다.

부록: 소스코드 다운로드 링크

실습 소스코드 다운로드

ToolSignal Pro Editorial

Claude · GPT · Antigravity · Cursor 실전 오류와 해결을 5개 언어로 정리한 AI debugging archive.

이전 글 다음 글