Notice
Recent Posts
Recent Comments
Link
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

방망이

[프로젝트]UEFI DXE 바이너리 취약점 분석기 1주차 - UEFI/DXE/PE 본문

2026_졸업프로젝트

[프로젝트]UEFI DXE 바이너리 취약점 분석기 1주차 - UEFI/DXE/PE

망구입니다 2026. 2. 26. 14:33

 

UEFI (Unified Extensible Firmware Interface)

UEFI는 운영체제와 플랫폼 펌웨어 사이의 소프트웨어 인터페이스를 정의하는 규격.

기존의 레거시 BIOS를 대체하기 위해 등장하였으며, 하드웨어 초기화와 운영체제 부팅을 담당.

C언어 기반으로 개발이 가능하며, 모듈화 된 구조를 가지고 있어 확장성이 매우 뛰어남.

 

현재 진행하는 [UEFI DXE 바이너리 취약점 분석기]에서 DXE는 UEFI 부팅 과정 중 하나.

 

[UEFI 부팅 과정]

  1. SEC (Security)
  2. PEI (Pre-EFI Initialization)
  3. DXE (Driver Execution Environment)
  4. BDS (boot Device Selection)
  5. TSL (Transient System Load)
  6. RT (Runtime)
UEFI 부팅 흐름 [자료 출처 :  https://uefi.org ]

위 과정 중 DXE 단계에서는 메모리가 초기화 된 상태 이므로, 대부분의 하드웨어 드라이버와 런타임 서비스들이 이 때 로드되고 실행됨.

즉, 분석 대상인 바이너리들이 가장 많이 실행되는 단계이므로 취약점이 발생할 가능성도 가장 높음.

 


DXE (Driver Execution Environment)

  1. DXE Dispatcher 및 DEPEX(Dependency Expression)
    • UEFI 드라이버들은 순차적으로 실행되는 것이 아니라, 조건부로 실행 됨. 각 DXE 드라이버는 자신의 PE 헤더 내부나 별도의 섹션에 DEPEX라는 데이터를 가짐.
    • DEPEX에 조건을 명시하고, DXE Dispatcher는 이 조건을 만족하는 드라이버를 찾아 실행함.
    • 분석기는 각 바이너리의 DEPEX 섹션을 파싱할 수 있어야 함. 만약 공격자가 악성 드라이버를 심어두면, DEPEX 조작을 통해 정상적인 보안 모듈보다 먼저 실행되게 하거나, 특정 보안 모듈의 로드를 방해하는 취약점이 존재할 수 있기 때문.
    • 즉, 분석기는 드라이버 파일의 DEPEX 섹션을 들여다보고 의심스러운 권한을 가지거나 모순된 의존성을 가진 관계 등을 찾아내야 함.

2. 핸들 데이터베이스 및 프로토콜

    • 모든 드라이버와 장치는 핸들(handle)이라는 객체로 관리되며, 이 핸들에 프로토콜(protocol)이라는 인터페이스가 부착됨.
    • 프로토콜은 특정 기능을 수행하는 함수 포인터들의 집합체. 모든 프로토콜은 고유한 128비트 GUID(Globally Unique Identifier)로 식별.
    • 분석기는 바이너리 내부에서 프로토콜을 등록하거나 사용하는 등 부트 서비스 함수 호출을 추적해야 함.(예 : InstallProtocolInterface, LocateProtocol)

3. 부트 서비스 및 런타임 서비스

    • DXE 단계에서는 두 가지 형태의 시스템 서비스 테이블이 생성됨.
      • Boot Services (BS) : OS가 부팅되기 전까지만 유효한 서비스. (메모리 할당, 이벤트 처리 등) OS가 로드되면 이 메모리는 회수 됨.
      • Runtime Services (RT) : OS가 부팅된 이후에도 계속 살아있는 서비스. (시간 설정, 변수 저장 등)
    • 런타임 서비스 관련 코드에 취약점이 있다면, OS가 실행 중일 때도 공격자가 펌웨어 레벨에서 시스템을 장악할 수 있음.
    • 분석기는 해당 드라이버가 런타임 드라이버인지 식별하는 것이 중요.

4. SMM (System Management Mode) 진입 준비

    • DXE 단계는 x86 프로세서의 SMM 환경을 설정하고 관련 드라이버를 로드하는 시기이기도 함.
    • SMM 드라이버는 DXE 단계에서 로드되지만, 실제로는 SMRAM이라는 격리된 메모리 영역에 복사되어 실행 됨.
    • SMM 드라이버의 취약점은 OS의 모든 보안 기능을 우회할 수 있다는 것.
장치 핸들과 프로토콜 핸들러 매핑 [자료 출처 :  https://uefi.org ]

[그림 설명]

  1. Device Handle
    • "모든 드라이버와 장치는 핸들(Handle)이라는 객체로 관리"
    • 핸들이 서로 연결된 리스트(Linked List) 형태, 즉 '핸들 데이터베이스'를 의미

2. GUID Interface

    • "모든 프로토콜은 고유한 128비트 GUID로 식별"
    • 핸들에 프로토콜을 붙일 때, 그냥 붙이는 게 아니라 이 GUID를 꼬리표처럼 달아서 붙임.

3. Protocol Interface

    • "특정 기능을 수행하는 함수 포인터들의 집합체"
    • 실제 기능을 수행하는 코드가 담긴 곳

4. Instance Data

    • 드라이버가 사용하는 Private Data
    • 취약점 분석 시 공격자가 이곳의 데이터를 오버플로우 시키려 시도하는 경우가 많으므로, 분석 관점에서도 매우 중요

PE (Portable Executable) 헤더

[용어 정리]

  1. PE 포맷
    • ' 규격'
    • 윈도우 운영체제나 UEFI 환경에서 실행 가능한 파일을 어떻게 만들고 저장해야 하는지 정의한 것.
    • 윈도우 운영체제에서 실행 파일(.exe), 객체 코드(.obj), 라이브러리 파일(.dll) 등을 위해 사용되는 파일 형식.

2. PE 파일

    • '실체'
    • PE 포맷이라는 규격에 맞춰서 실제로 만들어진 파일.
    • .efi 파일, .exe 파일, .dll 파일 등이 모두 PE 파일.

3. PE 헤더

    • '정보'
    • PE 파일의 가장 앞부분에 위치하며, 이 파일이 어떻게 실행되어야 하는지 알려주는 요약 정보.
    • 코드나 데이터가 어디에 있는지 알려주는 지도 역할을 함.

 

이번 프로젝트에서 PE를 공부해야 하는 가장 큰 이유는 UEFI 이미지(.efi 파일)가 PE 포맷을 따르기 때문.

  • '바이너리 취약점 분석기'가 UEFI 바이너리를 분석하려면 먼저 파일을 읽어서 메모리 구조를 파악해야 함.
  • 이 때 PE 헤더를 파싱해야만 실제 실행 코드와 데이터가 어디 있는지 알 수 있음.
 
 
PE 파일 구조 [자료 출처 :  https://drdisexon.medium.com/understanding-the-pe-file-structure-part-1-eef7b916e358 ]

 

[구조체 (Structures)]

  1. IMAGE_DOS_HEADER
    • 파일의 가장 첫 부분(64 bytes)
    • 이 파일이 PE 파일임을 알리는 식별자 역할
    • 핵심 필드
      • e_magic : 매직 넘버. 반드시 MZ(0x5A4D)여야 함.
      • e_lfanew : 실제 NT Header가 위치한 파일 오프셋을 가리킴.

2. MS-DOS stub

    • "This program cannot be run in DOS mode" 라는 문자열이 들어있는 잉여 영역.

3. IMAGE_NT_HEADERS

    • 3개의 하위 구조체로 구성됨.
      • Sginature : 값이 PE\0\0(0x00004550)인지 확인해야 함. (PE파일이라는 증명)
      • File Header (IMAGE_FILE_HEADER)
        • Machine : CPU 아키텍쳐 정보. UEFI는 주로 0x8664 값을 가짐
        • NumberOfSections : 섹션의 개수
        • SizeOfOptinalHeader : 바로 뒤에 이어질 Optional Header의 크기를 알려줌
      • Optional Header (IMAGE_OPTIONAL_HEADER)
        • AddressOfEntryPoint : 프로그램이 처음 시작되는 코드의 즈소.
        • ImageBase : 메모리에 로드될 떄의 기준 주소
        • SectionAlignmnet & FileAlignment : 메모리상의 섹션 간격과 파일상의 섹션 간격. 이 둘이 다르기 때문에 주소 변환 (RVA <-> RAW) 공식이 필요.
        • DataDirectory : 익스포트, 임포트, 재배치 테이블 등 주요 데이터의 위치 배열. 악성 코드는 이 곳을 조작하여 특정 함수를 숨기기도 함.

4. IMAGE _SECTION_HEADER

    • 각 섹션에 대한 정보를 담은 구조체 배열
      • Name : 섹션 이름 (예: .text, .data, .rdata)
      • VirtualAddress (RVA) : 메모리에 로드 되었을 때의 시작 주소
      • PointerToRawData : 파일상의 시작 위치
      • SizeOfRawData : 파일상에서의 크기
      • Characteristics : 속성