UEFI 스터디 2회차

4 minute read

Published:

오늘은 졸업 프로젝트 관련으로 어제 나왔던 얘기들 중, 처음 듣는 단어에 대해 제미나이를 통해 공부한 내용을 공부한 것이다. 현재 마이크로소프트 PE 헤더 specification을보고 수정중이라 혹시라도 이쪽부분은 참고 하지 말아주세요

PE 헤더

DXE 단계의 드라이버와 실행 파일들(.efi)파일들은 본질적으로 PE 파일 형식을 따른다.
pe 파일 형식은 윈도우 운영체제에서 사용하는 실행파일(.exe, .dll, .sys…)의 표준 포맷으로 UEFI의 .efi 파일도 이를 그대로 사용한다.
(UEFI에 대한 약속을 할때 pe로 하기로 한 것으로, 펌웨어 제조사, 디스크의 운영체제 그런것과 상관 없다.)

PE 헤더의 구성

  • DOS Header& stub -> 파일 맨 앞에 MZ(0x54AD) 서명으로 시작.
  • COFF File Header -> machine type(어떤 cpu 용인가), numberof sections (뒤에 나올 섹션 개수 ex) .test, .data…)
  • Optional Header(가장 중요) -> UEFI DXE CORE가 드라이버 로드시 가장 많이 참조.
  • addressOfEntryPoint -> 드라이버가 메모리 로드 후 CPU가 처음 실행할 코드의 시작 주소(offset). 예를 들면 해당 드라이버의 진입점 함수(UEFIMain)위치
  • imageBase -> 컴파일 될때 가정된 메모리 시작 주소(메모리 올라가며 보통 재배치)
  • sectionAlingment, FileAlignment -> 메모리/파일 의 정렬단위.
  • Subsystem -> 서브시스템 맞는지 확인용 (pe 파일 형식은 윈도우 내부에서 실행될 파일, UEFI에서 실행될 파일 모두 동일하다. 서브 시스템 확인 없이 윈도우용 pe 파일을 사용한다 생각해봐라.)

이뒤에는 실제 데이터가 온다.

펌웨어에 저장된 파일 구조

DXE Core

DXE를 관장하는 커널이다. 역시 처음은 .efi 실행파일 형태로 존재. (이는 PEI 단계 마지막에 메모리 로드 및 실행됨, 이 과정은 별로 중요치 않다고 함. )

DXE 코어가 pe 해더로 하는 것

  • 헤더파싱 -> efi 파일의 pe 헤더 파싱
  • 검증 -> cpu 맞는지, 서브시스템 맞는지.
  • 메모리할당 -> SizeOfImage 만큼.
  • 섹션 복사 -> .text, .data, .reloc 의 내용파일을 메모리 복사.
  • 제배치 ImageBase와 실제 로드된 주소가 다르므로 reloc 보고 메모리주소 수정.
  • 실행 -> AddressOfEntryPoint 메모리 주소로 점프헤서 드라이버를 실행.

(이미지 베이스는 컴파일 시에 컴파일러가 이 코드가 메모리 어디에 로딩될 지 몰라서 일단 가정하기 위한 값. 코드는 여기가 시작이라 가정하고 하드코딩.
실제 올라갈때는 이미지 베이스와 실제 로드주소를 비교해 그 값을 다시 계산.
그리고 그때 수정해야하는 주소 위치를 relec에 적어둠.)

데이터 베이스
시스템에 존제하는 모든 드라이버, 그들의 기능을 관리하는 링크드 리스트 형태의 레지스트리.

  • 핸들 -> 어떤 드라이버를 가리키는 id(EFI_HANDLE 타입)
  • 프로토콜 -> 핸들에 붙어 있는 기능(함수 포인터 테이블)

서비스 테이블(API) DXE 코어가 드라이버에게 재공하는 전역 함수 포인터 배열. 드라이버 코드 분석할때 많이 마주칠 gBs, gRT가 그 예시라고함.

디스패쳐 드라이버 파일을 메모리에 올리고 실행시키는 관리자.

  • dependency Evaluator(DEOEX) DXE 드라이버의 헤더에 있는 의존성 식을 해석해서 의존관계를 파악.
  • PE/COFF 로더(이미지 로더) -> PE 파일구조를 해석해서 메모리 올림.

FFS FV(firmware volume)에 많은 FSS 파일이 들어있음. fss파일 내부에는 pe파일 섹션 , pe 파일의 의존성정보를 저장한 DEPEX 섹션으로 되어있음.


이외에 해외 영상에서 찾은 영상에서 나온 내용들 (이쪽부터는 믿을만 합니다)

UEFI의 문제점(알아만 두기)

  • 드라이버 중복 -> (중요도 낮음) 부팅시 32/64비트 환경도 지원하니 *UEFI드라이버를 OS도 유용히 쓸수 있지 않을까 했으나, DXE 단계에서 하드웨어 초기화 후 OS 진입시 (ExitBootServices()) 대부분 버리고 OS전용 드라이버 재로드 -> 하나의 기기 위한 두종류의 드라이버 = 비효율.
  • 벤더 종속적 성격. -> (중요도 낮음) UEFI의 secure 부트는 전자서명을 체크하여 부팅시 허락된 소프트웨어만 실행시킬 수 있도록함, 펌웨어속 UEFI의 서명 데이터 베이스는 벤더가 만들었으므로 우리는 우리가 허가한 OS가 아닌 벤더가 허가한 OS만 실행가능. (+ 낮을 확률로 서명된 소프트웨어에 문제가 있다면 속수 무책. 2020년도 Boot hole 사건) 드라이버가 램에 로드 후 실행은 dxe 페이즈 이후이니 외부 소프트웨어(드라이버)의 취약점은 큰 관련 없을 듯 싶습니다.
  • 상용 UEFI는 참조구현인 EDK2를 기반으로 vendor-specific 하게 만들어진 closed-source 이므로 서로 공유되지 않는(backported) 취약점이 존재. 공통적인 업데이트가 반영되지 않을 수도 있음 -> 취약점을 찾을 여지가 있는 이유.

UEFI 관련 용어들

UEFI PI와 UEFI의 specification
해당 명세들은 UEFI 포럼에 의해서 관리됨.

  • UEFI PI는 부팅을 위한 하드웨어 통합 명세(별개의 하드웨어들이 하나의 부팅 가능한 플랫폼으로 묶이는 것을 정의한 사양). 주로 자원 하드웨어를 초기화하는 PEI/DXE 페이즈, 펌웨어 내부 공유된 자원등을 깊게 다룸. => 펌웨어의 볼륨과 그 내부 파일들의 구조도 잘 설명됨.
  • UEFI 명세는 펌웨어의 os간의 인터페이스를 다루는 명세 => uefi에 호환되는 os를 만들고 싶다면 이 함수는 이렇게 구현해 (우리와는 조금 먼 얘기), 단 os 업데이트 등 외부 소프트웨어가 UEFI와 접촉할이 있기 때문에 DXE 쪽은 그나마 이거 볼일이 있을거임.

UEFI 포럼
여러 유망한 기술 기업들의 연합으로 UEFI관련한 여러 명세를 관리 (위에나온 저두개 포함)

tianocore
UEFI의 오픈소스 구현체인 edk2를 이끌어나가는 커뮤니티 UEFI 포럼이 운영하는 것이 아닌 그냥 오픈소스임. uefi * spec은 좀더 명세쪽, tianocore는 좀 더 구현쪽.
edk2가 완전 작동하는 펌웨어로는 부족하지만 펌웨어로서 필수 조건들은 다 갖추고 있으니 필요하다면 참고해 보아요 ( = pi specification에 나온건 다 있다)

더 찾아볼 용어들

  • GUID -> UEFI 이미지를 깠을때 나옴. 이걸로 원하는 곳을 찾아가야할것 같은데… 혹시 이용한적있거나 이미 DXE 부분 뽑아낸사람들 도움!
  • SMM

UEFItool로 UEFI 펌웨어 파일 직접 까보기

알게된 점

  • 펌웨어 설치 파일은 os 설치를 위한 윈도우용 exe 파일로, 우리가 원하는건 내부의 바이너리 이미지 파일.
  • 이를 UEFItool로 추가로 봐야하는 것은 이는 플래시 드라이버에 들어간 펌웨어의 모습 (파일시스템 등등 다 섞인 이진수 뭉탱이) 이기 때문.
  • 이렇게 설치파일에서 UEFI 부분만 뽑아내는걸 바이오스 이미지 추출이라고한다.
  • 지금은 DXE 부분의 펌웨어 볼륨을 찾는 중 (암호화 된건지 ,GUID를 인식 못하는 건지 RAW 파일로 뜸. 잘 아시는 분은 도움 부탁드려용)

    다음 주 할것

  • 개괄적인 것이 파악됐으므로 본격적인 취약점 탐구
  • PE/COFF 헤더 부분 정리하고 직접 이를 바탕으로 바이오스용 PE 파일의 정보 파악해보기
  • 아무 펌웨어나 DXE 펌웨어 볼륨 찾아보기
  • 공부시간 늘리기…