WFP 무력화

Kail-KM
|2016. 6. 21. 08:59
WFP (Windows File Protection)

WFP는 중요한 Windows 시스템 파일이 대체 또는 변경되는 것을 방지하기 위해 Windows에서 기본적으로 제공하는 기능(Vista부터는 WRP로 대체)으로, 프로그램들이 Windows 시스템의 중요한 파일들을 덮어씌울 수 없게 하여 프로그램과 운영체제로부터 발생할 수 있는 문제를 사전에 방지한다. WFP는 보호하고자 하는 시스템 파일이 올바른지 확인하기 위해 코드 서명에 의해 생성된 카탈로그와 파일 시그니쳐를 사용하여 확인한다. 그렇다면 정상적인 경우라도 이러한 파일의 변경이 일어날 수 없을까? 시스템 파일에 치명적인 취약점이 발견되었을 경우 WFP에 의해 해당 파일을 대체하지 못한다면 이는 위험을 품고 있는 OS가 되어버릴 것이다. 따라서 보호되고 있는 파일을 대체하기 위한 방법들이 존재하고 있으며, 오직 아래의 방법들을 통해서만 대체가 가능하다.

- Update.exs를 통한 Windows 서비스 팩 설치
- Update.exe나 Hotfix.exe를 통한 Hotfixes 설치
- Winnt32.exe를 통한 운영체제 업그레이드
- Windows 업데이트

만약 프로그램이 다른 방법으로 보호되고 있는 파일을 대체하고자 한다면 WFP는 원래의 파일로 복구하고자 한다. Windows Installer는 중요한 시스템 파일을 설치할 때 WFP를 준수하고, 보호된 파일 자체를 설치하거나 교체하는 대신 보호된 파일을 교체하라는 요청과 함께 WFP를 호출하게 된다.


How the WFP feature works

WFP는 두 가지 메커니즘을 통해 시스템 파일 보호 기능을 제공한다. 첫 번째 방법은 백그라운드에서 동작하는 것으로 보호되고 있는 디렉터리에서 변경이 일어난다면 변경에 대한 알림을 받은 후 동작하게 된다. 이러한 알림을 받은 WFP는 어떤 파일이 변경되었는지 결정하며 만약 그 파일이 보호되고 있다면 WFP는 파일 시그니쳐를 통해 해당 파일이 올바른 파일인지 확인하는 작업을 거치게 된다. 만약 파일이 올바르지 않다면 WFP는 새로운 파일을 Cache 폴더나 원본 설치 파일에 존재하고 있는 정상적인 파일로 바꾼다. 

1. Cache 폴더(Default : %SystemRoot%\system32\dllcache)
2. 네트워크 설치 경로(네트워크 설치를 사용하여 설치한 경우)
3. Windows CD-ROM(시스템이 CD-ROM으로부터 설치된 경우)

위의 표는 WFP가 정상 파일을 탐색하는 경로로 파일이 변조된 경우 해당 위치로부터 정상 파일을 찾아 복원한 뒤 다음과 같은 시스템 로그를 기록한다. 해당 로그에선 보호되고 있는 파일을 대체하고자 시도했다는 기록을 볼 수가 있다.

Event ID: 64001 
Source: Windows File Protection 
Description: File replacement was attempted on the protected system file c:\winnt\system32\file_name. This file was restored to the original version to maintain system stability. The file version of the system file is x.x:x.x.


How to bypass the WFP

WFP는 두 개의 DLL(SFC.DLL과 SFC_OS.DLL)을 통해 구현되며 ReadDirectoryChacnge API를 사용하여  주요 폴더의 변경 여부를 검사한다. Windows 시스템의 중요 프로세스인 winlogon.exe는 시스템 부팅시 SFC_OS.DLL을 로드시키고, 해당 라이브러리의 Ordinal#1(SfcInitProt)를 호출한다. 해당 함수는 새로운 스레드('SFC Watcher Thread)를 하나 생성하며 이 스레드는 보호 대상 파일이 존재하고 있는 폴더에 대한 Directory Change Notification 이벤트를 생성한다. 이러한 보호폴더 이벤트는 WaitForMultipleObjects 함수에 의해 동기화되며, 만약 보호 대상 파일이 변경 또는 삭제된 경우 Cache 폴더에서 해당 파일을 원상 복구하도록 한다. 만약 백업 폴더에 대상 파일이 존재하지 않다면 사용자에게 윈도우 CD를 삽입하라는 메시지를 출력하게 된다.


SFC.DLL : Windows 2000에서는 WFP의 핵심기능을 담당하지만 XP부터는 SFC_OS.DL의 보조 역할

SFC_OS.DLL : XP부터 WFP의 핵심 기능을 담당

SFCFILES.DLL : 현재 보호되고 있는 파일의 리스트를 관리

SFC.EXE : System File Checker Utility


이러한 WFP는 주요 Windows 파일을 보호하는 메커니즘이니 만큼 악성코드에 의한 타깃이 되고 있다. 최근에도 주요 시스템 파일을 교체 또는 패치하는 형태의 악성코드가 다수 등장하고 있으며, 이로 인한 시스템 불안정, BSOD 등이 발생하고 있다. 그렇다면 이제 WFP를 무력화하는 방법에 대하여 알아보자.


Method #1 


WFP를 무력화시키는 첫 번째 방법은 winlogon이 갖고 있는 Direcotry change notification handle을 종료시키는 방법으로 이 방법을 사용하면 시스템이 재부팅하기 전까지 특정 폴더에 대한 파일 보호가 이루어지지 않는다. 해당 핸들을 종료하기 위해서는 ntdll.NtDuplicateHandle이나 kernel32.DuplicateHandle을 통해 해당 핸들을 복제한 다음 CloseHandle을 통해 핸들을 닫으면 된다.

BOOL WINAPI DuplicateHandle(        // Duplicates an onject handle
  _In_  HANDLE   hSourceProcessHandle,
  _In_  HANDLE   hSourceHandle,
  _In_  HANDLE   hTargetProcessHandle,
  _Out_ LPHANDLE lpTargetHandle,
  _In_  DWORD    dwDesiredAccess,
  _In_  BOOL     bInheritHandle,
  _In_  DWORD    dwOptions
);


Method #2


WFP를 무력화하는 두 번째 방법은 Winlogin.exe가 SFC_OS.DLL을 로드한 뒤 생성하였던 'SFC Watcher Thread'를 종료시키는 것이다. 해당 스레드를 종료시키기 위해서는 SFC_OS.DLL이 export 하고 있는 #2(SfcTermintaeWatcherThread)를 이용하는 것으로 해당 API는 파라미터를 필요로 하지 않는다. winlogon.exe에서 해당 API를 호출하면 해당 스레드는 종료되고, 이로 인해 재부팅 전까지 WFP 기능은 무력화된다.


SfcTerminateWatcherThread를 호출하기 위해서는 SeDebugPrivilege 권한이 필요하며 해당 스레드를 생성한 프로세스인 winlogon.exe에서 실행되어야 한다. 그러므로 이를 위해 Injection의 기법을 사용하는 경우가 많다는 것을 알 수 있다.


Method #3


세 번째 방법은 SFC API를 이용하여 특정 파일에 대한 WFP를 1분 동안 무력화하는 방법으로, 실제로 악성코드가 주로 사용하는 방법이다. sfc_os.dll의 ordinal #5 : SfcFileException을 이용하는 방법으로, 해당 API는 특정 파일에 대하여 1분 동안 WFP 기능을 무력화시킨다. 이 방법을 사용하기 위해서는 LoadLibrary를 통해 sfc_os.dll을 로드한 뒤 GetProcAddress에 "#5"를 넘겨주어 호출하는 코드를 확인할 수 있을 것이다.

DWORD WINAPI SfcFileException(DWORD ?, PWCHAR pwszFileName, DWORD ?);

위 구조와 같이 두 번째 인자에 해당 파일의 이름을 넣어주면 되고 첫 번째 인자와 세 번째인자는 알 수 없는 인자지만 첫 번째에는 0을, 세 번째 인자에는 -1을 넣어주어야 한다. 해당 API가 성공할 경우 return value는 0이며 만약 성공하지 못한 경우에는 1이 반환된다.


Method #4


네 번째 방법은 Undocumented 레지스트리 값을 이용하는 방법으로 Windows 2000 SP1 이전 버전까지만 가능한 방법이다. 해당 레지스트리를 설정하면 WFP는 영구적으로 무력화된다. 

KEY : HKLM\Software\Policies\Microsoft\Windows NT\Windows File Protection 
Value Name : SFCDisable
Value : 0xFFFFFF9D


Method #5


마지막 방법은 Protected File List를 패치하여 특정 파일에 대한 WFP를 영구적으로 무력화하는 방법이다. WFP가 보호하고자 하는 대상은 SFCFILES.DLL에 정의되어 있음을 언급했다시피 해당 대상이 되는 파일의 내용을 패치하여 특정 파일에 대한 WFP를 영구적으로 무력화할 수 있다.


이를 위해선 SFCFILES.DLL을 복사하여 무력화하고자 하는 파일을 찾은 다음 해당 이름의 첫 바이트를 \x00으로 바꾸어 준다. 이렇게 내용을 수정한 뒤 'PEChkSum'를 이용하여 체크섬 문제를 해결하고, 'MoveLatr'를 통해 부팅 시에 원본 파일을 대신해 수정한 파일을 로드하도록 설정해주면 된다. 이러한 준비를 끝냈다면 프로세스를 완료하기 위해 재부팅해주어야 한다.



Reference


https://support.microsoft.com/en-us/kb/222193

https://bitsum.com/aboutwfp.asp

http://sinun.tistory.com/144


'Reversing > Theory' 카테고리의 다른 글

Memory Detection(메모리 진단)  (0) 2016.09.26
Assembly로 보는 코드, strcmp 문자열 비교  (0) 2016.08.08
DLL이란?  (4) 2016.05.29
PE구조의 이해  (0) 2016.05.04
윈도우 후킹 원리 [PDF]  (1) 2016.04.23