EFI System Partition และเรื่องที่เกี่ยวข้องกับการ Boot OS Windows+Linux

EFI System Partition และเรื่องที่เกี่ยวข้องกับการ Boot OS Windows+Linux

ก่อนหน้านี้ผมเคยเขียนบทความไว้ที่ Medium ก็จะขอย้ายจากการเขียนที่นั่น มาเขียนที่นี่เป็นหลักนะครับ
วันนี้จะมาแทรกเรื่อง reverse engineer นิดหน่อย ใครติดตามบทความเกี่ยวกับ reverse engineer ต้องขออภัย
โดยขอแทรกเรื่อง สรุป หรือ Quick summary หรือจะเป็น FAQs เบาๆ ก็ได้
- OS Boot Mechanism
- TPM Chip
- EFI Partition (ESP)
- Secure Boot
- Boot Loader (Grub2 , Windows Boot Manager)
- แนวคิดและความแตกต่างกัน

เริ่มต้นมาจาก ประวัติศาสตร์การบูต และปัญหาใหญ่ๆ 2 ปัญหา ของ Windows
ปัญหาที่ 1 คือ มี Malware ฝังตัว (persistence) ตอนบูตได้ ทำให้มีปัญหา เครื่องติด malware ตลอดเวลาทุกครั้งที่บูตเข้า Windows
ปัญหาที่ 2 คือ ความสามารถของ Hardware ที่มีมากขึ้นตามยุคตามสมัย แต่จะทนใช้ BIOS ไปตลอดมันก็ไม่ตอบโจทย์ เพราะมันมีข้อจำกัด (ผมเขียนอธิบายไว้ที่ Medium)

ปัญหาแรก แก้ไขโดยการใช้ Secure Boot คือจะมีการตรวจ Firmware Key ก่อนจะชี้ Boot Manager ว่า Firmware มี Integrity ที่ครบถ้วนถูกต้องมั้ย
ซึ่งถ้ามี Malware เข้าไปฝังตัวตั้งแต่จังหวะนี้ แปลว่า Firmware เสีย Integrity ไปแล้ว Secure boot ก็จะพบว่ามันไม่ปลอดภัยที่จะบูต ก็จะห้ามการบูต ไม่ decrypt BitLocker key ให้ทำให้เข้าใช้งาน OS ไม่ได้
กลไกพวกนี้มีตัวช่วยกันหลายตัว เช่น Chip TPM , UEFI Firmware , Microsoft OEM Key

เรื่องนี้เป็นเรื่องที่ทำให้ทิศทางต่างๆ แตกต่างกันไปมากครับ แตกต่างกันอย่างเห็นได้ชัด
ผมจะยกตัวอย่าง Windows กับ Linux ที่มีการบูต และธรรมชาติคนละแบบเลยนะครับ

โดยเราจะเริ่มจาก ESP ก่อน
ESP เป็น Partition สำหรับเก็บ UEFI Firmware เป็น File System ประเภท FAT32
OS ที่จะเข้ามาขอใช้การบูตจาก เมนบอร์ดนี้ คอมพิวเตอร์เครื่องนี้ จะต้องมีการ Interact กับ ESP นี้
หรือถ้าเป็นคอมใหม่ๆ OS ก็จะมีการสร้าง Partition นี้ขึ้นมาโดยอัตโนมัติ

เนื่องจากความสามารถชอง UEFI มีความสามารถสูงกว่า BIOS เดิมมาก
การอ้างอิง Partition จึงใช้แนวคิด GPT (ไม่ใช่ ChatGPT นะจ๊ะ) ย่อมาจาก
GUID Partition Table โดยหลักคิดก็คือ ให้แต่ละ Partition มีค่า GUID ของตัวเองไม่ซ้ำกัน ซึ่งมันเป็นค่าที่ยาวพอสมควร แต่นั่นก็ทำให้มันมีศักยภาพสูงกว่า BIOS เดิมมาก เช่นเดียวกัน
โดยหลายๆ Partition Type ในรูปแบบ GUID ได้ถูกระบุค่าไว้แล้วเรียบร้อยด้วย
https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs

ทำให้ผู้พัฒนา OS สามารถจัดการ Boot Mechnism ของตัวเองได้คนละแบบเลย รวมถึงคนที่วิเคราะห์และแก้ไขปัญหาด้วย ก็มีค่าไว้อ้างอิงได้ง่าย

มาเริ่มจาก "หลักคิด และ ปรัชญาที่แตกต่างกัน" ของ Windows และ Linux

Windows = API Based เน้นเรียกฟังก์ชั่นโปรแกรมโดยใช้ API ใน Library
Linux = File Based เน้นเรียกฟังก์ชั่นผ่าน File Dependency

Windows = ผู้ใช้ เน้นการติดตั้งที่ทำให้ผู้ใช้ ใช้งานได้ง่าย ปรับแต่งไม่ได้
Linux = ให้อิสระผู้ใช้ปรับแต่งสิ่งต่างๆได้ตามต้องการ การใช้งาน (เรื่อง boot) ทำความเข้าใจยากกว่า

Windows = จะครอบครอง Boot Loader แต่เพียงผู้เดียว
Linux = มีกลไก OS-Prober ตรวจสอบว่ามี OS อื่นอยู่มั้ยแล้วค่อยทำให้ Boot Mechanism มีทางเลือกมากขึ้น

Windows = Secure Boot สมบูรณ์มาก เพราะ Signed Key ในนามบริษัทลงใน TPM Chip มาจากโรงงาน ซึ่งมี Hardware Mainboard เป็น Partner มากมาย
Linux = Secure Boot ต้องทำความเข้าใจอย่างลึกซึ้ง , อาจจะเป็น Self Signed ในบาง Distro เช่น Arch Linux

จะเห็นว่า Windows มีการพัฒนากลไก Boot และ Secure Boot ไปไกล
https://learn.microsoft.com/en-us/windows/security/hardware-security/tpm/how-windows-uses-the-tpm

ส่วน Linux จะเติบโตจากแนวคิดของชุมชน (community) และ ปรัชญาของแต่ละ Distro ตามที่ Lead Developer ของ Distro นั้นๆกำหนด

ดังนั้นถ้าหากว่าเราต้องการติดตั้งใช้งาน 2 OS พร้อมกัน เช่น Windows + Linux มักจะเรียกกันว่า Multi Boot นั้น
เราจะต้องทำการ ติดตั้ง Windows OS ก่อนเสมอ , จากนั้นค่อยติดตั้ง Linux ทีหลัง
เพราะหากเราติดตั้ง Linux ก่อน แล้วติดตั้ง Windows ทีหลัง ขั้นตอนการติดตั้ง Boot Loader ของ Windows (ซึ่งก็คือ Windows Boot Manager)

จะ "ไม่สนใจ" Boot entry อื่นๆ เลย , Windows จะมอง OS ตัวเองสำคัญที่สุด และเขียนทับ Entry อื่นๆ แน่นอนผลที่เกิดขึ้นเราก็จะ Boot เข้า Windows ได้อย่างเดียว เลือก OS อื่นที่จะบูตไม่ได้
Windows Installer:
    ลบไฟล์ใน /EFI/ubuntu/ หรือ /EFI/<distro>/
    เขียน bootmgfw.efi ใหม่เสมอ
    อัปเดต NVRAM ให้ชี้ไปที่ Windows โดยตรง
    ประมาณนี้

ตรงกันข้าม ถ้าเราติดตั้ง Linux ทีหลัง ความสามารถของ Boot Loader ของ Linux (โดยเฉพาะ grub2) ก็มีวิธีการจัดการ OS ที่ลงไว้ก่อนหน้า นั่นก็คือ os-prober เมื่อเช็คเจอแล้วก็ทำการตัดสินใจและแทรกตัวเองเข้าไปเป็น entry ใหม่ได้ โดยไม่ลบ Windows ทิ้งแถมเรายังปรับแต่งได้มากมายกว่า Windows Boot Manager อีก บทความใน Internet จำนวนมากจึงบอกให้เราลง Windows ก่อนเสมอ แล้วค่อยลง Linux ตามหลัง

เข้ามาดู EFI Partition ของจริงกัน

ESP คือ EFI System Partition นะครับ ให้เข้าใจตรงกัน เวลาผมเขียน ESP นะ
เอาละ
คอมที่บ้านผม ใช้ Windows 10 + Ubutu 24.04
โดย ubuntu ของผม มันมอง ESP เป็น /dev/sda1 และมันทำ mount point ไว้ที่
/boot/efi นั่นเอง

uefi-01-uuid-esp

keng@kengUbuntu:~$ mount | grep sda1
/dev/sda1 on /boot/efi type vfat (rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
keng@kengUbuntu:~$

ดังนั้นด้วยความอิสระใน Linux ทำให้ผมเข้าไปดูข้อมูลใน ESP ได้ (หรือแม้แต่ copy file ออกมาเพื่อ reverse engineer ก็ได้)
ใน ESP ของผม มีอะไรบ้าง ? มาดูโครงสร้าง Directory กันครับ

keng@kengUbuntu:~$ sudo tree /boot/efi/EFI
/boot/efi/EFI
├── Boot
│   ├── bootx64.efi
│   ├── fbx64.efi
│   └── mmx64.efi
├── Microsoft
│   ├── Boot
│   │   ├── BCD
│   │   ├── BCD.bak
│   │   ├── BCD.LOG
│   │   ├── BCD.LOG1
│   │   ├── BCD.LOG2
│   │   ├── bg-BG
│   │   │   ├── bootmgfw.efi.mui
│   │   │   └── bootmgr.efi.mui
│   │   ├── bootmgfw.efi
│   │   ├── bootmgr.efi
│   │   ├── BOOTSTAT.DAT
│   │   ├── boot.stl
│   │   ├── cs-CZ
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
│   │   ├── da-DK
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
.....
.....
│   │   ├── et-EE
│   │   │   ├── bootmgfw.efi.mui
│   │   │   └── bootmgr.efi.mui
│   │   ├── fi-FI
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
│   │   ├── Fonts
│   │   │   ├── chs_boot.ttf
.....
.....
│   │   │   ├── segoe_slboot.ttf
│   │   │   └── wgl4_boot.ttf
│   │   ├── fr-CA
.....
.....
│   │   ├── ja-JP
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
│   │   ├── kd_02_10df.dll
│   │   ├── kd_02_10ec.dll
│   │   ├── kd_02_1137.dll
│   │   ├── kd_02_14e4.dll
│   │   ├── kd_02_15b3.dll
│   │   ├── kd_02_1969.dll
│   │   ├── kd_02_19a2.dll
│   │   ├── kd_02_1af4.dll
│   │   ├── kd_02_8086.dll
│   │   ├── kd_07_1415.dll
│   │   ├── kd_0C_8086.dll
│   │   ├── kdnet_uart16550.dll
│   │   ├── kdstub.dll
│   │   ├── ko-KR
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
.....
.....
│   │   ├── pt-PT
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
│   │   ├── qps-ploc
│   │   │   └── memtest.efi.mui
│   │   ├── Resources
│   │   │   ├── bootres.dll
│   │   │   └── en-US
│   │   │       └── bootres.dll.mui
│   │   ├── ro-RO
│   │   │   ├── bootmgfw.efi.mui
│   │   │   └── bootmgr.efi.mui
│   │   ├── ru-RU
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
.....
.....
│   │   ├── uk-UA
│   │   │   ├── bootmgfw.efi.mui
│   │   │   └── bootmgr.efi.mui
│   │   ├── winsipolicy.p7b
│   │   ├── zh-CN
│   │   │   ├── bootmgfw.efi.mui
│   │   │   ├── bootmgr.efi.mui
│   │   │   └── memtest.efi.mui
│   │   └── zh-TW
│   │       ├── bootmgfw.efi.mui
│   │       ├── bootmgr.efi.mui
│   │       └── memtest.efi.mui
│   └── Recovery
│       ├── BCD
│       ├── BCD.LOG
│       ├── BCD.LOG1
│       └── BCD.LOG2
├── Parrot
│   └── grubx64.efi
└── ubuntu
    ├── BOOTX64.CSV
    ├── grub.cfg
    ├── grubx64.efi
    ├── mmx64.efi
    └── shimx64.efi

46 directories, 148 files
keng@kengUbuntu:~$

จะเห็นว่า โครงสร้างแยกกันชัดเจนของ Directory Windows กับ Directory Linux
Windows - จะมีไฟล์ประกอบเยอะมากกว่า ไฟล์หลักของ UEFI Boot คือ bootmgfw.efi
Linux - จะมี grub.cfg เป็น boot loader ตัวชูโรง (สำคัญมาก) และมี gurbx64.efi เป็น UEFI Firmware ของ Linux Distro นั้นๆ
(Parrot ผมลบทิ้งไปแล้วครับ แต่ผมยังไม่ได้แก้ไข EFI Entry)

สรุป Multi boot กลไกเบื้องต้น

- EFI System Partition (ESP) ทำหน้าที่จัดเก็บ UEFI Firmware
- เมื่อเปิดเครื่อง UEFI จะอ่าน Boot Order จาก NVRAM (Non-Volatile RAM) ซึ่งเก็บไว้ใน firmware
- Boot Order นี้กำหนดลำดับการโหลด bootloader จากอุปกรณ์หรือ partition ที่กำหนด (เช่น ESP - EFI System Partition)
- หาก GRUB2 ถูกติดตั้งและกำหนดเป็น bootloader หลัก (default) UEFI จะโหลดไฟล์ EFI ของ GRUB2 (เช่น grubx64.efi) จาก ESP ก่อน

ยืนยันได้ด้วยเครื่องมือ efibootmgr ใน linux

keng@kengUbuntu:~$ sudo efibootmgr
BootCurrent: 0002
Timeout: 1 seconds
BootOrder: 0002,0000,0001,0003
Boot0000* Windows Boot Manager  HD(1,GPT,951f7b44-bad5-48fe-9e0d-c254b3535006,0x800,0x832000)/File(\EFI\MICROSOFT\BOOT\BOOTMGFW.EFI)57494e444f5753000100000088000000780000004200430044004f0042004a004500430054003d007b00390064006500610038003600320063002d0035006300640064002d0034006500370030002d0061006300630031002d006600330032006200330034003400640034003700390035007d00000000000100000010000000040000007fff0400
Boot0001* parrot        HD(1,GPT,951f7b44-bad5-48fe-9e0d-c254b3535006,0x800,0x832000)/File(\EFI\PARROT\GRUBX64.EFI)
Boot0002* Ubuntu        HD(1,GPT,951f7b44-bad5-48fe-9e0d-c254b3535006,0x800,0x832000)/File(\EFI\UBUNTU\SHIMX64.EFI)
Boot0003* Hard Drive    BBS(HD,,0x0)0000474f00004e4fb700000001000000750057004400430020002000570044005300350030003000470032004200300041002d003000300053004d003500300000000501090002000000007fff040002010c00d041030a0000000001010600010201010600010003120a000000ffff00007fff040001043e00ef47642dc93ba041ac194d51d01b4ce63000320036003000340032003000410046003100350041002000200020002000200020002000200000007fff04000000424f00004e4fab000000010000007500530054003500300030004c004d003000320031002d0031004b004a0031003500320000000501090002000000007fff040002010c00d041030a0000000001010600010201010600010003120a000100ffff00007fff040001043e00ef47642dc93ba041ac194d51d01b4ce62000200020002000200020002000200020002000200020003600570041003200380030004d00350000007fff04000000424f
keng@kengUbuntu:~$

อธิบายได้ว่า
UEFI จะพยายามโหลด SHIMX64.EFI ของ Ubuntu ก่อนทุกครั้ง (เพราะมันคือ BootEntry 0002 และอยู่ในลำดับแรกของ BootOrder) หากโหลดสำเร็จ GRUB2 จะแสดงเมนูเลือก OS และถ้าคุณเลือก Windows มันจะทำ Chainloading ไปที่ bootmgfw.efi ของ Windows

Secure Boot : เรื่องที่ Windows ทำได้ง่ายกว่า


กลไก Secure Boot ของ Windows ที่ดูเหมือน "ทำได้ดีกว่า" หรือ "ง่ายกว่า" Linux ส่วนใหญ่เกิดจากการออกแบบระบบที่รวมศูนย์ (centralized) และการผสานรวมกับฮาร์ดแวร์ (TPM) อย่างที่ผมแปะลิ้งไว้ข้างบน โดย Microsoft เป็นผู้ควบคุมหลัก ในขณะที่ Linux ต้องรองรับความหลากหลายของฮาร์ดแวร์และผู้พัฒนาจากหลายแหล่ง ตามปรัชญาความอิสระของพวกเค้า

1. การเซ็นต์คีย์ (Signing Keys) ที่เป็นมาตรฐานเดียวกัน
    1.1 Windows:
        1.1.1 Microsoft เป็นผู้ถือ Master Key (Microsoft UEFI CA) และเซ็นต์ไฟล์ Bootloader (bootmgfw.efi) ด้วยคีย์นี้โดยตรง
        1.1.2 OEM (ผู้ผลิตฮาร์ดแวร์) ส่วนใหญ่จะ ฝังคีย์ของ Microsoft ไว้ใน UEFI Firmware ล่วงหน้า → ทำให้ Windows ผ่าน Secure Boot ได้โดยอัตโนมัติ
        1.1.3 ไม่ต้องปรับแต่งใดๆ เพิ่มเติม

    1.2 Linux:
        1.2.1 ใช้ Shim Bootloader (ใน ubuntu ผมจะมีไฟล์ shimx64.efi ลองเลื่อนขึ้นไปดูครับ) ไฟล์นี้ Linux ได้มาใน Distro ตัวเองก็จริง แต่จริงๆแล้วก็เซ็นต์ด้วยคีย์ของ Microsoft นะครับ (เฉพาะ distro ที่ผ่านการอนุมัติ เช่น Ubuntu, Fedora)
        1.2.2 Distro อื่นๆ ที่ไม่ได้เซ็นต์ด้วย Microsoft ต้องปิด Secure Boot หรือเพิ่มคีย์เองใน UEFI
        1.2.3 ต้องผ่านหลายขั้นตอนกว่า (เช่น ใช้ MOK - Machine Owner Key เพื่อเซ็นต์ kernel อีกที)

        Windows ง่ายกว่าเพราะ Microsoft ควบคุมคีย์เดียว และ OEM สนับสนุนเต็มที่ (เลือก OS ให้เหมาะกับงานเรานะครับ)

2. การใช้ TPM (Trusted Platform Module)
    2.1 Windows:
        2.1.1 ใช้ TPM ร่วมกับ Secure Boot สำหรับ Measured Boot และ BitLocker Encryption
        2.1.2 ระบบตรวจสอบความสมบูรณ์ของ boot process โดยเก็บค่า PCR (Platform Configuration Registers) ใน TPM
        2.1.3 หากมีไฟล์ระบบถูกแก้ไข (เช่น malware โจมตี bootloader) TPM จะปฏิเสธการ decrypt disk

    2.2 Linux:
        2.2.1 แม้ Linux รองรับ TPM (ผ่าน tools เช่น tpm2-tools) แต่การใช้งานซับซ้อนกว่า
        2.2.2 การเข้ารหัส disk (เช่น LUKS) ส่วนใหญ่ไม่ผูกกับ Secure Boot/TPM โดยอัตโนมัติ (ต้องตั้งค่าเอง)

        Windows ง่ายกว่าเพราะออกแบบมาให้ TPM ทำงานแบบ end-to-end ตั้งแต่บูตจนถึง decrypt disk

ภาพตัวอย่าง : Mainboard ของคอมพิวเตอร์บ้านของผม Asrock B450 Steel Legend ก็มีช่องต่อ TPM Chip เพิ่มเติมด้วยได้ครับ

uefi-tpm-connector-of-b450-steel-legend

3. การจัดการ Bootloader ขอเขียนซ้ำอีกครั้งครับ
    3.1 Windows:
        3.1.1 มี bootloader เดียว (bootmgfw.efi) ที่ Microsoft เป็นผู้ดูแล
        3.1.2 ไม่ต้องจัดการหลายส่วน (GRUB, systemd-boot, etc.)
    3.2 Linux:
        3.2.1 มี bootloader หลายตัว (GRUB2, systemd-boot, rEFInd) แต่ละตัวต้องเซ็นต์แยกกัน
        3.2.2 บาง distro ใช้ Shim + GRUB + Kernel ซึ่งเพิ่มความซับซ้อน

        Windows ง่ายกว่าเพราะมี bootloader กลางที่ควบคุมโดย Microsoft

เครื่องมือในการวิเคราะห์ปัญหา Boot ไม่ขึ้น / Boot ไม่ได้
- SystemRescue CD
- Linux Live ต่างๆ ที่ทำงานใกล้เคียงกับเรื่องพวกนี้โดยตรงและบูตผ่าน USB ได้ เช่น Kali , CAINE
- Win10XPE Project ส่วนตัวยังไม่เคยลองในการไล่เรื่องบูต ใครลองดูก็ได้นะครับ


ถ้าจะ Reverse Engineer UEFI Firmware ละ ?

Linux คงไม่ต้องเพราะ open source อยู่แล้ว ส่วน Windows นั้นไฟล์ bootmgr.efi ผม copy ออกมาได้ และเอามา reverse engineer ได้นะครับ แต่จะไปหาอะไรหรือให้รู้อะไร
ก็เอาไว้ว่ากันต่อไปครับ

uefi-02-uuid-bootmgr.efi-rizin