Prefetch 개요

프리패치는 Windows 운영체제에서 소프트웨어 활동과 관련된 정보를 저장하기 위해 사용하는 메모리 관리 기법 중 하나이다. 이를 사용할 경우 자주 사용될 프로그램들을 미리 메모리에 로드해두기 때문에 더 빠른 실행이 가능하다.

프리패치는 파일 형태로 데이터를 저장하는데, 이렇게 저장된 파일은 다음의 용도로 활용될 수 있다.

  • Windows 및 응용 프로그램 시작 성능 향상
  • 응용 프로그램(바이러스)의 행위 연구, 포렌식 분석

 

물론 prefetch의 동작 방식 때문에 오히려 불필요하게 RAM을 사용하게 될 수 있어 이미 PC 성능이 좋거나 SSD를 사용하고 있는 경우에는 RAM 공간 확보를 위해 비활성화를 추천하기도 한다.

그렇기에 prefetch는 무조건 활성화되어 있지 않을 수 있으며 다음의 레지스트리 경로를 이용하여 prefetch 활성화 여부를 확인할 수 있다.

HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters [EnablePrefetcher]

EnablePrefetcher의 값은 0~3 중 하나로 설정할 수 있으며, 각각의 값은 다음과 같은 의미를 가진다.

  • 0: Prefetch 사용 안함
  • 1: ALP만 사용
  • 2: BP만 사용
  • 3 (기본값): ALP와 BP 모두 사용

 

여기에서 확인할 수 있듯이 prefetch에는 다음의 두 가지 유형이 존재한다. 기본적으로 두 가지를 모두 사용하도록 설정되어 있으나, 필요에 따라 레지스트리의 값을 변경하여 원하는 옵션으로 사용할 수 있다.

  • ALP(Application-Launch Prefetching): 사용자가 자주 사용하는 응용프로그램의 정보를 prefetching 하는 것으로, 응용 프로그램의 실행 속도를 높일 수 있다.
  • BP(Boot Prefetching): 부팅 시 사용하는 파일이나 프로그램의 정보를 prefetching 하는 것으로, 부팅 속도를 높일 수 있다.

 

Prefetching된 데이터는 파일 형태로 저장되어 있다가, 부팅 시 저장해둔 prefetch 파일을 메모리에 로드해두고, 실제 프로그램 사용 시 메모리에서 해당 데이터를 불러와 사용할 수 있게 한다. 저장된 프리패치 파일은 %SystemRoot%\Prefetch 폴더에서 확인할 수 있다.

(Windows 10 기준) Prefetch 폴더 내 저장된 파일 및 폴더 유형은 다음과 같다.

  • ReadyBoot
  • Layout.ini
  • Prefetch Files (.pf)

 

ReadyBoot 폴더는 Boot Prefetch에 필요한 파일들을 저장하는데 사용된다. 매 부팅 시 Trace#.fx 이름으로 부팅에 필요한 파일 및 데이터 정보가 포함된 파일이 생성된다. 이 파일은 ReadyBoot 폴더 내에 생성되며 가장 최근에 생성된 파일을 기준으로 최대 5개까지 저장된다. 이외에도 1개의 rblayout.xin 파일이 ReadyBoot 폴더 내에 저장되는데, 이 파일을 이용하여 ReadyBoot 시 필요한 정보 및 캐시 파일을 관리한다.

 

Layout.ini 파일에서는 프리패치 버전과 프리패치 파일의 목록을 확인할 수 있다. Layout.ini 파일은 부팅이나 응용 프로그램 시 참조되는 순서대로 파일의 경로가 기록되며, 약 3일 마다 내용이 업데이트된다. 그렇기 때문에 실제 Prefetch 폴더에 저장된 prefetch 파일의 저장 여부와 일치하지 않을 수 있으며, 오래전에 실행된 적 있는 파일에 대한 항목도 존재할 수 있다.

 

Prefetch 파일은 한번 이상 실행된 적 있는 응용 프로그램에 대한 데이터가 저장된다. 이러한 점을 이용하여 PC에서 사용자의 응용 프로그램 사용 흔적 또는 악성 프로그램 실행 기록을 추적할 수 있다.

각 프리패치 파일에 포함되는 정보는 다음과 같다.

  • 프리패치 파일의 MAC 타임스탬프
  • 프리패치 파일의 크기
  • 프리패치 파일에 해당하는 프로세스
  • 파일이 실행된 volume 또는 논리 드라이브 경로
  • 프로그램 실행 횟수
  • 프로그램의 마지막 실행 시간에 대한 타임스탬프
  • 프리패치 파일에 의해 로드된 추가 파일

 

여기에서 파일의 생성 시각과 수정 시각 정보는 각각 다음과 같은 의미로 해석될 수 있다.

  • 파일의 생성 시각: exe 프로그램 최초 실행 시각
  • 파일의 수정 시각: exe 프로그램의 마지막 실행 시각

 

프리패치 파일은 Prefetch 폴더 내에 모두 존재하며, prefetch 파일의 개수가 운영체제 별 최대 제한 개수에 도달하면 가장 오래전에 실행된 순으로 파일을 삭제한다. 운영체제별로 유지하는 최대 prefetch 파일 개수는 다음과 같다.

  • Windows XP, 7: 128개
  • Windows 8, 10: 1024개

 

Prefetch File Format

Prefetch 파일의 file format은 파일의 압축 여부에 따라 두 가지 형태를 가진다.

먼저 압축되어 있는 prefetch 파일의 구조는 다음과 같다.

  • Offset 0x00 (4bytes): File Signature (4D 41 4D 04)
  • Offset 0x04 (4bytes): Uncompressed Data Size
  • Offset 0x08 ~: Compressed Data

Prefetch 파일의 자세한 정보를 얻기 위해서는 압축된 내용을 풀어야 한다. Windows prefetch 압축에는 LZXPRESS Huffman 압축 방식이 사용되며, 원본 내용을 보기 위해 Github에서 공유되고 있는 압축 해제 코드를 이용하여 해제하였다.

압축되지 않은 prefetch 파일의 형식은 크게 File Header와 File Body로 구분할 수 있다. File Header는 운영체제에 관계없이 공통된 구조를 가지지만 Body의 경우 운영체제 버전에 따라 서로 다른 형식을 가진다.

  • File Header: offset 0x00 (84bytes)
  • File Body: offset 0x54 ~

 

먼저, 버전에 관계없이 공통되는 부분인 File Header는 다음과 같은 구조를 가진다.

  • Offset 0x00 (4bytes): Format Version (Little-Endian)
  • Offset 0x04 (4bytes): File Signature (53 43 43 41)
  • Offset 0x0C (4bytes): File Size (Little-Endian)
  • Offset 0x10 (60bytes): File Name (실행 파일 이름)
  • Offset 0x4C (4bytes): Prefetch Hash (Prefetch 파일 이름에 기재된 해시값)
    • Prefetch Hash는 실행 파일 경로에 대한 해시값을 가지며 Windows 버전에 따라 서로 다른 해시 함수를 사용한다.
      • Windows XP, 2003: SCCA XP hash function
      • Windows Vista, 10: SCCA Vista hash function
      • Windows 2008, 7, 2012, 8: SCCA 2008 hash function

 

Format Version으로 사용되는 값의 종류는 총 4가지이며, 각각은 다음과 같은 정보를 가리킨다.

  • 0x11: Windows XP, Windows 2003
  • 0x17: Windows Vista, Windows 7
  • 0x1A: Windows 8.1
  • 0x1E: Windows 10

 

Prefetch 파일은 기재된 format version에 따라 서로 다른 구조를 가진다. Windows 11도 Windows 10 비슷한 부분이 많은 운영체제임에 따라 0x1E version을 사용한다. 다음은 각 버전에 따른 전체 Format 구조이다.

 

  • 0x11: Windows XP, Windows 2003

 

  • 0x17: Windows Vista, Windows 7

 

  • 0x1A: Windows 8.1

 

  • 0x1E: Windows 10

 

위 format을 통해 알 수 있는 것과 같이, Windows 10과 8.1의 경우는 최근 실행 시간을 가장 최근 시간을 기준으로 8개까지 저장한다는 특징을 가진다.

여기까지가 각 운영체제별로 가지는 기본적인 prefetch의 파일 포맷이었다. 이후의 내용은 포맷 내 각 필드가 가리키는 값을 추적하는 과정을 정리하였다.

 

File metrics array

각 프리패치 파일별로, 해당 파일을 실행시키기 위해 필요한 다른 파일들을 함께 기록해두는데 이에 대한 내용은 File metrics array로 관리된다. File metrics array 내에 있는 각 entry를 탐색하기 위해서는 File metrics array offset과 Filename strings offset을 필요로 한다.

File metrics array는 File metrics array offset 필드에 정의된 offset 위치에서 시작한다. File metrics array의 각 entry는 일정한 형식을 갖추고 있는데, 이 형식은 운영체제에 따라 약간의 차이를 가진다.

  • 0x11: Windows XP, Windows 2003

  • 0x17, 0x1A, 0x1E: Windows Vista, Windows 7, Windows 8.1, Windows 10

Unknown의 경우는 확실하지 않은 값이므로 그 쓰임을 명시해두지 못했지만
Windows 7, 8, 10에서의 Unknown 간에는 다음과 같은 규칙을 가지고 있음을 확인하였다.

  • Unknown1은 초기값 0에서 시작하여 다음 entry로 넘어갈 때마다 Unknown2 만큼 더해진 값을 갖는다.
  • 2번째 필드와 3번째 필드는 매 entry 내에서 서로 동일한 값을 갖는다.

 

이러한 필드를 제외한 채, Filename string offset과 Filename string number 필드값을 이용하면 각 entry에 해당하는 파일명을 찾을 수 있다. 다음은 Windows 10 환경의 프리패치 파일에서 직접 entry 내 파일명을 확인하기까지의 과정이다.

 

Volumes information

Prefetch 파일을 통해 이 실행 파일이 어느 볼륨에서 실행된 것인지 확인할 수 있으며, 파일에 할당된 file reference를 실행된 볼륨의 데이터와 매핑시켜볼 수 있다.

Volumes information 데이터 추적도 기본 file format의 필드로부터 시작한다. 파일의 시작 지점으로부터 offset 0x6C 위치에서 4바이트 크기의 volume information offset 정보를 확인할 수 있다. 이 offset을 따라가면 volume information entry를 찾을 수 있는데, 여기서의 entry 구조 역시 운영체제 버전에 따라 다르다.

  • 0x11: Windows XP, Windows 2003

 

  • 0x17, 0x1A: Windows Vista, Windows 7, Windows 8.1

 

  • 0x1E: Windows 10

 

다음은 Windows 10 환경의 프리패치 파일에서 직접 entry 내 볼륨 정보를 확인하기까지의 과정이다. 

 

요약

  1. Windows의 Prefetch는 자주 사용될 프로그램들을 미리 메모리에 로드해두어 빠른 실행을 가능하게 하는 메모리 관리 기법 중 하나
  2. 실행된 적 있는 프로그램은 프리패치 파일로 남기 때문에 응용 프로그램(바이러스)에 대한 행위 연구, 포렌식 분석 활용 가능
  3. Prefetch는 비활성화 설정도 가능하기 때문에 무조건 남는 아티팩트가 아니며, 안티 포렌식 목적으로 실행 후 프리패치 파일을 삭제할 수도 있음
  4. 최근 운영체제의 prefetch 파일의 경우 LZXPRESS Huffman 압축이 되어있는 경우가 많아 내용 확인 시 압축 해제 또는 전용 도구 필요

 


참고 자료

 

Windows Registry 내에서 시스템의 Timezone을 확인하기 위해서는 다음과 같은 키의 값을 확인하면 된다.

HKLM\SYSTEM\CurrentControlSet\Control\TimezoneInformation [TimeZoneKeyName]

 

그러나 간혹 레지스트리 경로 내 CurrentControlSet 을 찾을 수 없는 경우를 발견한 적이 있었다.
이런 경우 CurrentControlSet 대신 ControlSet001과 ControlSet002만을 가지고 있는 경우도 있었다.

이름이 비슷하게 생긴 것을 힌트 삼아 이 두 경로가 CurrentControlSet을 대신할 수 있을까 라는 생각을 하게 되었다. 그리고 실제로 각각의 경로를 탐색한 결과 두 경로 모두 현재 시스템의 시간대 정보를 가지고 있는 것을 확인할 수 있었다.

CurrentControlSet
ControlSet001
ControlSet002

이들 간에 어떠한 차이가 있는지 알아보기 위해 우선 관련 정보를 인터넷에 검색하였다.

https://stackoverflow.com/questions/291519/how-does-currentcontrolset-differ-from-controlset001-and-controlset002

stackoverflow 내 답변에 의하면 ControlSet001과 ControlSet002는 CurrentControlSet의 백업으로 사용하는 key라고 한다.여기서 궁금했던 점은 백업용이면 한개만 있으면 될텐데 왜 굳이 2개의 백업용 key를 두었을까? 하는 부분이었다.  이를 확인하기 위해 몇가지 테스트를 진행하였다.

 


 

실습을 위해 사용한 운영체제는 Windows 7 이며 VMware 를 이용한 가상환경에서 테스트하였다.

테스트한 case는 다음과 같다.

  1. 시간대 변경 이후 재부팅하지 않을 경우
  2. 시간대 변경 후 시스템을 정상적으로 종료하는 경우
  3. 시간대 변경 후 시스템을 비정상적으로 종료하는 경우

 

case 1: 시간대 변경 이후 재부팅하지 않을 경우

초기 실습용 OS의 표준시간대는 UTC+9 이다. 이를 UTC+7로 변경하였다.

그 후 차례로 CurrentControlSet과 ControlSet001, 그리고 ControlSet002의 표준시간대 반영 결과를 확인하였다.

CurrentControlSet
ControlSet001
ControlSet002

결과는, CurrentControlSet과 ControlSet001에만 변경된 시간대가 적용이 되었고 ControlSet002에는 초기 UTC+9가 그대로 남아있었다.

이 상태에서 한번 더 시간대를 변경하였다. 이번에는 UTC+5로 변경하였다.

CurrentControlSet
ControlSet001
ControlSet002

이번에도 변경된 사항은 CurrentControlSet과 ControlSet001에만 적용되었으며, ControlSet002에는 처음의 UTC+9 시간대가 그대로 남아있었다.

 

case 2: 시간대 변경 후 시스템을 정상적으로 종료하는 경우

이제 시스템을 롤백시켜 시간대 변경을 할 때마다 시스템을 정상적으로 종료 후 부팅하는 방식을 테스트해보려고 한다.

ControlSet001
ControlSet002
CurrentControlSet

초기 상태인 UTC+9에서 UTC+7로 변경하였다.

시간대 변경 직후, 재부팅을 안한 상태에서는 앞선 결과와 마찬가지로 CurrentControlSet과 ControlSet001만 변경되고 ControlSet002는 여전히 원래 시간대인 UTC+9로 기록되어 있는 것을 볼 수 있다.

ControlSet001
ControlSet002
CurrentControlSet

위 상태에서 정상적으로 재부팅을 한 후 다시 각 결과를 확인하였을 때, ControlSet001 외에 ControlSet002 까지도 모두 같은 시간대 정보를 가지고 있는 것을 확인할 수 있었다.

ControlSet001
ControlSet002
CurrentControlSet

 

case 3: 시간대 변경 후 시스템을 비정상적으로 종료하는 경우

case 2에와 마찬가지로 시스템을 초기 환경으로 롤백 후 다시 테스트하였다.

시간대를 변경한 후 비정상적 종료를 유발하기 위해 간단한 스크립트를 작성하여 일부 시스템 프로세스를 강제종료 시켰다...ㅎ

그 결과로 탐색기가 안열리는 상황

그 후 안전 모드로 접속하여 확인했을 때, ControlSet001과 CurrentControlSet은 변경한 시각을 가지고 있었지만, ControlSet002의 경우 정상적인 상태일때 저장된 상태값인 UTC+9를 그대로 가지고 있었다.

 

ControlSet001
ControlSet002
CurrentControlSet

비정상적으로 종료된 케이스에서도 정상적으로 재부팅을 한다면, ControlSet002의 시간대도 다시 시스템의 표준 시간대와 동일한 값을 가지는 것을 확인하였다.

 

여기서 만약 안전 모드가 아닌 표준 모드로 재부팅을 한다면?

테스트를 위해 이번에는 ControlSet001과 CurrentControlSet의 시간대를 UTC+9로 설정하고, ControlSet002만 UTC+7로 설정되어 있는 상태에서 시스템의 비정상 종료를 유발했다.

 

그 결과, ControlSet001과 CurrentControlSet의 표준 시간대가 모두 ControlSet002의 표준 시간대와 동일한 상태로 부팅이 되었다.

ControlSet001
ControlSet002
CurrentControlSet

 

물론 CurrentControlSet 에 설정된 UTC+7 대로 라면 가상머신의 시간이 현재 한국 시간보다 2시간 느려야하는데 호스트 컴퓨터의 시간과 동일하게 표시되는 것으로 봐서 어딘가 문제가 생긴건 맞는 것 같다.ㅎㅎ.. 이런 현상은 재부팅을 해도 마찬가지였고, 


각 케이스의 결과를 비교하였을 때,

대체로 ControlSet001은 CurrentControlSet과 동일한 값을 가지며

ControlSet002은 가장 최근에 정상적으로 종료된 Control값을 가지는 것을 알 수 있다.

그리고 비정상적 상태로 종료하였을 경우 ControlSet002는 가장 최근에 저장된 정상 Control 상태를 저장하였다가 복구 시 시스템의 상태를 이 ControlSet002에 저장된 상태로 설정한다.

그렇다면 CurrentControlSet을 사용하지 않고 ControlSet001을 사용하면 되는것 아닌가? 라는 의문이 들 수 있다.

이러한 의문에 대한 답은 아래 링크를 통해 해결할 수 있었다.

 

What are Control Sets? What is CurrentControlSet?

A control set contains system configuration information such as device drivers and services. You may notice several instances of control sets when viewing the Registry. Some are duplicates or mirror images of others and some are unique. This article descri

web.archive.org

 

위 내용에 따르면

CurrentControlSet, ControlSet001, ControlSet002 간의 관계를 정의하는 레지스트리가 존재한다.

그것은 바로 HKLM/SYSTEM/Select subkey 내에 있는 key들이다.

여기에는 Current, Default, Failed, LastKnownGood 과 같이, 총 4개의 서로 다른 상태를 저장할 수 있는 key가 있으며 각각은 다음과 같은 의미를 가진다.

 

● Current는 현재 CurrentControlSet이 가리키고 있는 ControlSet의 번호를 나타낸다. Current key의 값이 0x01 일 경우 CurrentControlSet의 값은 ControlSet001과 같게 된다.

● Default는 기본적으로 CurrentControlSet이 가리키고 있는 ControlSet의 번호를 나타낸다. Default key의 값이 0x01 일 경우 CurrentControlSet의 값은 ControlSet001과 같게 된다.

● Failed는 정상적으로 사용하기 어려운 ControlSet의 번호를 가리키게 된다. Failed key의 값이 0x00일 경우 모든 ControlSet 을 정상적으로 사용할 수 있다는 것을 가리킨다.

● LastKnownGood는 Current key에서 가리키고 있는 번호의 ControlSet이 설정되기 이전으로부터 가장 최근에 설정된 정상 ControlSet의 번호를 나타낸다.

 

결과적으로 현재 시스템의 Control 정보를 보고자 한다면 CurrentControlSet의 내용을 보는 것이 맞으며, 이는 Current key가 가리키고 있는 ControlSet001로부터 가져온 정보를 가진다. 만약 복구가 필요할 경우 LastKnownGood key가 가리키고 있는 ControlSet002로부터 가져온 정보를 사용하게 된다.


 

시작은 Timezone 분석으로 하였지만, 이외에도 시스템 내에 있는 다른 정보들의 백업을 위해 총 3개의 Set(CurrentControlSet, ControlSet001, ControlSet002)이 사용되고 있는 것을 알게 되었다. 

또한 글의 초입에서 언급했던 상황과 같이, CurrentControlSet을 확인할 수 없는 경우에는 Select subkey 설정값을 확인하여 CurrentControlSet과 같은 값을 가지는 백업 Set이 어느것인지 확인하고 CurrentControlSet을 대신하여 참고할 수 있을 것으로 생각된다.

 

+ Recent posts