2017年7月3日 星期一

hack 完 iso 之後怎麼讓他從 usb 開機?(提示:使用 isohybrid 技術)


概述

到了最近才了解原來 live USB (用 USB 開機、甚至在 USB 裡面裝作業系統隨時可以插拔的技術)能夠開機是靠著「騙」 BIOS 以為他在開軟碟機(對就是 5.2 吋、3.5 吋磁片的那種軟碟機;應該很多人沒有看過了吧 @@??)

原本早期用 CD 開機是(live CD):
BIOS --> 直接支援光碟機

live USB 的話就是:
BIOS --> 掃到 USB port,「以為」這是一個「插了光碟」的軟碟機 --> 基於軟碟機的規格、表頭去 chianload 到光碟的開機檔案

透過指令 apt-get source genisoimage 就可以看到實做原始碼;對原始碼查找 "floppy" 這個字眼就可以取得相關資訊。

實際可以用的工具

然而,如果只是單純將從光碟 dump 出來存成 iso9660 格式的檔案再倒入 USB device 的話,不能透過該 USB device 開機也只是剛好。因為 BIOS 認為他不是在光碟機的光碟、也沒有在硬碟(或是 block device)裡面可以讀懂並且用來開機的檔案(MBR boot sectors 或是 boot files in EFI partition)。

因此要做兩件事情:
* 在把 iso 倒入 usb device 的時候,要使用某種「從軟碟跳到 iso 相關檔案」的工具做 mapping - 由 genisoimage 提供
* 如何讓 BIOS 認為「這是一個有開機檔案的軟碟」 - 由 isohybrid 提供

大概是像這樣

files in folder --> <genisoimage> --> iso associated to MBR or EFI structure

iso associated to MBR/EFI --> <isobybrid> --> bootable iso

更多 genisoimage 和 isohybrid 的使用細節可以參考 [1]

實際應用


想要改動基於 gparted 做出的 debian image[2]。下載該 image、修改、壓回去然後用 usb 載入。

genisoimage -A "GParted Live CD" -V "GParted-live" -publisher "GParted http://gparted.org" -input-charset iso8859-1 -f -r -hide-rr-moved -hide-joliet-trans-tbl -J -l -allow-limited-size -b syslinux/isolinux.bin -c syslinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -eltorito-alt-boot -efi-boot EFI/images/efiboot.img -no-emul-boot ./ > /tmp/gparted-live-amd64-iso8859-1.iso

上面的指令基本上含意如下,


-A "GParted Live CD" -V "GParted-live" -publisher "GParted http://gparted.org"

簡單的標籤名稱,很好理解

 -input-charset iso8859-1

檔案編碼,iso8859-1 是除了xx 以外常用的編碼,若是不指定就會用系統的

-f -r -hide-rr-moved -hide-joliet-trans-tbl -J -l -allow-limited-size

-b syslinux/isolinux.bin

isolinux binary image, 真正的開機 bootloader。指示要去哪裡找 isolinux.bin。

-c syslinux/boot.cat -no-emul-boot

boot.cat 就是 boot.catalog
參考 http://www.tldp.org/HOWTO/Bootdisk-HOWTO/cd-roms.html
模擬 floppy 的 image, 目的是把 BIOS 帶往 iso 真正用來開機的檔案(在這個案例是 isolinux.bin,因為我們上面的 -b 指示往要找 isolinux.bin)
要理解這個參數,請見上面的概述。
-no-emul-boot 指的是不要產生 floppy emulator image (就是 catalog, 因為已經有了,強制不要免得產生不預期的行為)

-boot-load-size 4

4 其實就對對應到一個硬碟磁區(sector)可能的位元組2*n, 對應一個典型 MBR 的大小 (128*4 = 512 bytes) ,這也是把開機會用到的檔案按照表頭指示的標準位置放置好而已。

-boot-info-table

塞 info table 進去 boot file(按照 EL TORITO spec,EL TORITO 規格是 iso9660 規格的擴充,是「可開機光碟」)


-eltorito-alt-boot
-efi-boot EFI/images/efiboot.img
-no-emul-boot ./

  • 後面這三個參數是三個一組,要一併使用。用來再生一個 iso filesystem (第二片光碟的意思,再這之前的選項生出給 MBR 格式用的,按照 MBR 會去找的位置放檔案),用於 UEFI 開機

到這邊就會打資料夾打包好變成一個符合 iso 9660 格式的 iso 檔案。最後再用 isohybrid 這個工具對此 iso 加工,使得我們可以引導 BIOS 把控制權交到 iso 中的那些可開機檔案(isolinux.bin 之類的)

isohybrid iso && isobybrid -u iso

前者使得 iso file 可以在 legacy mode 中開機,後者使得 iso file 可以在 UEFI mode 中開機。第一次 apply "isohybrid iso" 的時候,使用 disk 工具還看不到 EFI partition ,第二次 apply "isohybrid iso" 的時候,就可以看到 EFI partition 的結構出來了。

  • 題外話,稍微試了一下似乎
    • isohybrid iso && isobybrid -u iso
      • 可如預期開機(live usb 第二次完成後會有 EFI partition)
    • isobybrid -u iso && isohybrid iso
      • 不會如預期開機 (live usb 不會顯示 EFI partition)
    • 順序有關是有影響的。


最後把整個 iso dd 進去 usb stick 就可以了。

dd if=/tmp/$ISONAME of=/dev/sdb bs=4M && sync

零碎的資訊補充

  • genisoimage 就是 mkisofs 這個指令, 中間用 symbolic link

  • xorriso 就可以想成像是 genisoimage 和 isohbrid 兩個指令混合

題外話,曾經無意間發現 genisoimage 的功能限制(不太算是 bug),有回報在 Launchpad 上面 https://bugs.launchpad.net/ubuntu/+source/cdrkit/+bug/1475250 ,有空的話其實可以考慮送個 patch 增強一下該工具。

小結

整體而言,就是 "pack" ISO (get contents), and then make it bootable;要注意把原本可以 usb 開機的 iso 解開的時候往往已經拿掉 bootable 的資訊了,例如 bootable file and partition file system structure.



[1] http://www.syslinux.org/wiki/index.php?title=Isohybrid
[2] http://gparted.org/liveusb.php