연재를 시작할 때 설치된 앱 목록을 날짜순으로 정렬해 보았다. 인터넷 뱅킹을 시작한 날 하루에만 네 개가 들어와 있었다. 지금 다시 세어 보니 금융·공공 사이트가 남긴 항목은 앱 목록에서 스무 개, 서비스 열세 개, 커널 드라이버 스물두 개, 루트 인증서 열여섯 개였다. 하나씩 찾아다니기에는 너무 많아서, 마지막 편은 이것을 한 번에 뽑아 보는 스크립트로 시작한다.

읽기 전용 목록 스크립트

아래 스크립트는 레지스트리와 서비스, 인증서 저장소를 읽어 화면에 보여 줄 뿐 아무것도 바꾸지 않는다. 관리자 권한도 필요 없다. 지우는 일은 결과를 보고 사람이 한다.

$p = 'AhnLab|Wizvera|RAON|TouchEn|RaonSecure|nProtect|INCA|IPinside|Interezen|MagicLine|Dream|AnySign|SoftForum|HANCOM WITH|iniLINE|CrossEX|INISAFE|Initech|SignKorea|KICA|Crosscert|ExEcm|CoreB2b|MarkAny|ezPDF|Unidocs|VOICEYE|Penta'
$u = 'Microsoft\Windows\CurrentVersion'

'== 설치된 앱 =='
Get-ItemProperty "HKLM:\SOFTWARE\$u\Uninstall\*", "HKLM:\SOFTWARE\WOW6432Node\$u\Uninstall\*",
                 "HKCU:\SOFTWARE\$u\Uninstall\*" -ErrorAction SilentlyContinue |
    Where-Object { "$($_.DisplayName) $($_.Publisher)" -match $p } |
    Sort-Object DisplayName | Format-Table DisplayName, DisplayVersion, UninstallString -AutoSize

'== 서비스 =='
Get-CimInstance Win32_Service | Where-Object { "$($_.Name) $($_.PathName)" -match $p } |
    Format-Table Name, StartMode, State, PathName -AutoSize

'== 시작 프로그램(Run) =='
foreach ($k in "HKLM:\SOFTWARE\$u\Run", "HKLM:\SOFTWARE\WOW6432Node\$u\Run", "HKCU:\SOFTWARE\$u\Run") {
    (Get-ItemProperty $k -ErrorAction SilentlyContinue).PSObject.Properties |
        Where-Object { $_.Name -notlike 'PS*' -and "$($_.Name) $($_.Value)" -match $p } |
        ForEach-Object { '{0} | {1}' -f $_.Name, $_.Value }
}

'== 예약 작업 =='
Get-ScheduledTask | Where-Object { "$($_.TaskName) $($_.Actions.Execute)" -match $p } |
    Format-Table TaskName, State -AutoSize

'== 커널 드라이버 =='
Get-CimInstance Win32_SystemDriver |
    Where-Object { $_.Name -match '^TK|SafeTransaction|^nos|^np_' -or $_.PathName -match $p } |
    Format-Table Name, StartMode, State -AutoSize

'== 로컬 포트 =='
$n = @{}; Get-Process | ForEach-Object { $n[$_.Id] = $_.ProcessName }
Get-NetTCPConnection -State Listen | Where-Object LocalAddress -in '127.0.0.1', '0.0.0.0' |
    Sort-Object LocalPort |
    Format-Table LocalAddress, LocalPort, @{ n = 'Process'; e = { $n[[int]$_.OwningProcess] } } -AutoSize

'== 루트 인증서(컴퓨터) =='
Get-ChildItem Cert:\LocalMachine\Root |
    Where-Object Subject -match "$p|ASTx|Hancom|Kings Information|KWIC" | Sort-Object NotBefore |
    Format-Table @{ n = 'Name'; e = { $_.GetNameInfo('SimpleName', $false) } }, NotBefore, NotAfter -AutoSize

'== 폴더 =='
Get-ChildItem 'C:\Program Files', 'C:\Program Files (x86)', 'C:\ProgramData' -Directory -ErrorAction SilentlyContinue |
    Where-Object Name -match $p | Select-Object -ExpandProperty FullName

PowerShell 창에 통째로 붙여 넣으면 바로 돈다. .ps1 파일로 저장해서 쓸 때는 인코딩을 "UTF-8(BOM)" 으로 저장해야 Windows PowerShell 5.1 에서 한글 제목이 깨지지 않는다. 첫 줄의 $p 는 이 연재에 나온 회사·제품 이름이고, 다른 이름은 | 로 이어 붙이면 된다. 이름으로 거르는 방식이라 엉뚱한 것이 섞일 수 있다. 처음에 Kings 를 넣었더니 DialogBlockingService 가 걸려 나와 인증서 쪽으로만 옮겼다. 로컬 포트는 거르지 않고 전부 보여 주니 앞 편의 표와 견주어 읽는다.

관리 프로그램부터 지운다

스크립트 결과의 첫 번째 표를 보고 지울 프로그램을 고른다. 기준은 이 연재 내내 같았다. 그 사이트를 PC 로 다시 쓸 일이 있는가. 인터넷 뱅킹과 민원 업무를 휴대폰으로만 한다면 모두 지워도 PC 동작에는 문제가 없고, 필요해지면 사이트가 설치 안내를 다시 띄운다. 자주 쓰는 은행이 하나 있다면 그 은행이 요구하는 것만 남기는 것도 방법이다.

지우는 순서는 다른 프로그램을 감시하거나 설치해 주는 쪽이 먼저다.

  1. WIZVERA Process Manager 처럼 다른 프로세스를 되살리는 관리 프로그램
  2. Veraport 처럼 보안 모듈을 설치해 주는 설치 관리자
  3. 나머지 개별 프로그램(키보드 보안, 방화벽, 인증서, 파일 전송, 단말 정보 확인 등)
  4. 재부팅 후 스크립트를 다시 돌려 남은 것 확인

관리 프로그램이 남아 있으면 나머지를 지우는 동안 프로세스가 되살아날 수 있다. 브라우저도 모두 닫아 둔다.

제거는 설정 → 앱 → 설치된 앱에서 한다. 제거 프로그램 위치가 특이한 것만 따로 적어 둔다.

프로그램 등록된 제거 명령
AhnLab Safe Transaction ...\AhnLab\Safe Transaction\V3Medic.exe -Uninstall
RAON K 2018 C:\ProgramData\RAONWIZ\RAON K\uninstall.exe /u
TouchEn nxKey C:\WINDOWS\SysWOW64\CKSetup32.exe /uninstall appm
nProtect Online Security ...\INCAInternet UnInstall\nProtect Online Security\nProtectUninstaller.exe
CrossEX ...\iniLINE\CrossEX\crossex\UnInstallCrossEXLocal.exe (현재 사용자 항목)

CrossEX 는 제거 정보를 현재 사용자 쪽(HKCU)에 등록해 두어, 컴퓨터 쪽만 뒤지는 도구에서는 보이지 않는다. 스크립트가 세 군데를 모두 읽는 이유다.

제거 뒤에 다시 돌린다

재부팅한 다음 같은 스크립트를 다시 돌려, 지운 프로그램의 항목이 사라졌는지 본다.

서비스가 남아 있으면 시작 유형과 경로를 본다. 이 PC 에서는 RAON K 서비스가 사용 안 함 상태로 옛 경로를 가리킨 채 남아 있었다. 이런 것은 직접 지우기보다 그 회사가 배포하는 제거 도구를 찾는 편이 안전하다. 커널 드라이버는 20편에 적은 대로 직접 손대지 않는다.

루트 인증서는 제거 프로그램이 같이 지우지 않는 경우가 있다. 18편의 방법대로 certlm.msc 에서 지운 프로그램의 회사 이름이 붙은 것만 골라 지우고, certmgr.msc 에서 다시 확인한다.

폴더는 마지막이다. Program Files 나 ProgramData 에 회사 폴더가 남아 있으면 재부팅한 뒤 지운다. 이 PC 에는 TouchEn 폴더 아래에 설치된 앱 목록에 대응하는 항목이 없는 AntiVirus 폴더도 있었다. 무엇이 남긴 것인지 분명하지 않은 폴더는 그 회사 제품을 모두 지운 뒤에 정리하는 편이 안전하다.

지우는 스크립트를 만들지 않은 이유가 여기 있다. 같은 회사 이름 아래에도 쓰는 것과 지울 것이 섞여 있고, 드라이버나 루트 인증서를 잘못 지우면 부팅이나 사이트 접속이 깨진다. 무엇을 지울지는 내 사용 패턴을 아는 사람이 정해야 한다.

스물한 편을 마치며

작업 관리자의 이름 하나가 궁금해서 시작했다. 파일과 서명, 포트와 인증서를 따라가 보니 회사도 목적도 달랐지만 모양은 거의 같았다. 웹 페이지가 할 수 없는 일을 대신 하려고 PC 에 포트를 열고, 그 포트를 브라우저가 믿게 하려고 루트 인증서를 넣고, 서비스·Run 키·예약 작업·드라이버로 늘 떠 있다. 그리고 쓰는 날은 일 년에 몇 번인데 지우는 날은 오지 않는다.

이 프로그램들을 나쁘게만 볼 이유는 없다. 상당수는 브라우저만으로 같은 일을 하기 어려웠던 시절의 해법이다. 다만 쓰지 않는 프로그램을 남겨 두면 그 포트와 신뢰 목록도 같이 남는다. 몇 달에 한 번 이 스크립트를 돌려 보고, 기억나지 않는 이름이 있으면 이 연재에서 찾아보길 바란다. 그동안 읽어 주셔서 고맙다.

본편은 여기까지다. 이 글을 마무리하며 스크립트를 한 번 더 돌렸더니, 본편에서 이름만 지나간 인증서 프로그램 네 개와 지운 뒤 흔적만 남은 프로그램 하나가 눈에 걸렸다. 다음 편부터 번외로 이 다섯을 본다. 첫 번째는 증권사 사이트에서 자주 만나는 코스콤 SignKorea 다.