HOME > android > tips

안드로이드 boot.img의 커널과 램디스크를 수정하는 방법

JSFollow18 Aug 2019

안드로이드에서 boot.img는 커널(kernel)과 램디스크(ramdisk)가 있는 이미지입니다. 만약 커널이나 램디스크를 변경하고 싶다면 boot.img를 unpack하고 파일을 수정한 뒤에 다시 repack하여 boot.img를 만들 수 있습니다.

unpack/repack하는데 사용하는 유틸리티의 이름은 unpackbootimg과 mkbootimg입니다. 이 툴들은 CyanogenMod에서 제공합니다.

이 글에서 다음과 같은 내용을 설명합니다.

  1. unpackbootimg, mkbootimg 툴 설치 방법
  2. boot.img를 얻는 방법
  3. boot.img를 unpackbootimg으로 unpack하는 방법
  4. Linux 코드 빌드 및 zImage 생성 방법
  5. 램디스크 수정하는 방법
  6. mkbootimg으로 수정한 램디스크 및 커널을 pack하는 방법
  7. 새로운 boot.img를 디바이스에 넣는 방법

unpackbootimg, mkbootimg 툴 설치 방법

다음과 같이 git으로 소스를 다운받으세요. mkbootimg폴더를 보시면 컴파일된 mkbootimg와 unpackbootimg가 있습니다.

$ git clone https://github.com/CyanogenMod/android_system_core.git
$ ls android_system_core/mkbootimg/
mkbootimg  unpackbootimg

이 파일들을 사용하시면 됩니다. 저는 두개의 파일을 /usr/local/bin/에 복사하여 어떤 경로에서든 사용할 수 있도록 만들었습니다.

$ cp android_system_core/mkbootimg/mkbootimg /usr/local/bin/
$ cp android_system_core/mkbootimg/unpackbootimg /usr/local/bin/

boot.img를 얻는 방법

인터넷에 떠돌아 다니는 자신의 스마트폰의 순정이미지를 다운받으시면, 거기에 boot.img가 있습니다. 예를 들어, 삼성 스마트폰은 "AP_XXXX" 처럼 AP로 시작하는 tar파일이 있는데요. 압축을 풀면 안에 boot.img가 있습니다.

두번째 방법은, 디바이스에서 직접 boot.img를 추출하는 것입니다. 디바이스의 boot.img는 /dev/block/~에 있기 때문에 rooting이 되어야 추출이 가능합니다.

adb shell에 들어가서 다음과 같이 ls 명령어를 입력합니다. 디바이스마다 정확한 패스가 다를 수 있습니다.

shell@slteskt:/ $ ls /dev/block/platform/*/by-name/
BOOT
....

이 디바이스의 boot.img는 BOOT라고 추측할 수 있고, 정확한 패스는 다음과 같이 구할 수 있습니다.

shell@slteskt:/ $ ls /dev/block/platform/*/by-name/BOOT                        
/dev/block/platform/15540000.dwmmc0/by-name/BOOT

이 파일을 adb pull 명령어로 로컬에 다운받으면 됩니다.

boot.img를 unpackbootimg으로 unpack하는 방법

boot.img를 구했다면 unpackbootimg로 unpack할 수 있습니다.

다음 명령어처럼 입력하면 boot.img에 있는 커널과 램디스크 파일을 추출할 수 있습니다.

$ unpackbootimg -i boot.img

그럼 커널 BASE 주소 등, 이미지에서 파일들이 위치하는 주소와 관련된 값들이 파일로 저장됩니다.

$ unpackbootimg -i boot.img
Android magic found at: 0
BOARD_KERNEL_CMDLINE buildvariant=userdebug
BOARD_KERNEL_BASE 00008000
BOARD_RAMDISK_OFFSET 01000000
BOARD_SECOND_OFFSET 00f00000
BOARD_TAGS_OFFSET 00000100
BOARD_PAGE_SIZE 2048
BOARD_SECOND_SIZE 0
BOARD_DT_SIZE 256000

$ ls
boot.img          boot.img-kernel_offset   boot.img-pagesize        boot.img-second_offset
boot.img-base     boot.img-name            boot.img-ramdisk.gz      boot.img-tags_offset
boot.img-cmdline  boot.img-os_patch_level  boot.img-ramdisk_offset  boot.img-zImage
boot.img-dt       boot.img-os_version      boot.img-second

여기서 램디스크 파일은 boot.img-ramdisk.gz입니다. 커널 파일은 boot.img-zImage입니다. boot.img-XXX 파일들은 관련 값들이 저장된 파일입니다.

Linux 코드 빌드 및 zImage 생성 방법

안드로이드 폰마다 리눅스 코드가 다르기 때문에 제조사에서 제공하는 소스를 받으셔야 합니다. 수정하고 싶은 코드를 수정하고 빌드를 하면 zImage가 생성됩니다.

새로운 커널을 다시 repack하여 boot.img를 만들 것이고, 그 이미지를 다시 디바이스에 넣을 것입니다.

램디스크 수정하는 방법

램디스크는 boot.img-ramdisk.gz 파일로 압축되어 있습니다. 다음과 같은 명령어로 압축을 풉니다.

$ mkdir ./ramdisk
$ cd ./ramdisk
$ gzip -dc ../boot.img-ramdisk.gz | cpio -imd

그럼 다음처럼 많은 파일들이 보입니다. 여기서 수정하고 싶은 것을 수정하고 다시 압축을 합니다.

ramdisk$ ls
acct               fstab.universal5430             init.universal5430.usb.rc   seapp_contexts
cache              init                            init.universal5430.wifi.rc  selinux_version
charger            init.cm.rc                      init.usb.configfs.rc        sepolicy
config             init.environ.rc                 init.usb.rc                 service_contexts
d                  init.goldfish.rc                init.zygote32.rc            storage
data               init.ranchu.rc                  mnt                         sys
default.prop       init.rc                         oem                         system
dev                init.recovery.universal5430.rc  proc                        ueventd.goldfish.rc
etc                init.recovery.usb.rc            property_contexts           ueventd.ranchu.rc
file_contexts.bin  init.universal5430.baseband.rc  res                         ueventd.rc
fstab.goldfish     init.universal5430.power.rc     sbin                        ueventd.universal5430.rc
fstab.ranchu       init.universal5430.rc           sdcard                      vendor

압축은 다음 명령어로 하시면 됩니다. new-boot.img-ramdisk.gz라는 파일이 생성됩니다.

ramdisk$ find . ! -name . | LC_ALL=C sort | cpio -o -H newc -R root:root | gzip > ../new-boot.img-ramdisk.gz
5228 blocks

mkbootimg으로 수정한 램디스크 및 커널을 pack하는 방법

수정한 커널 파일 이름은 zImage이고, 램디스크 파일 이름은 new-boot.img-ramdisk.gz입니다. repack할 때 주의해야 할 것은 커널 오프셋 등 이전과 동일한 값을 입력해야 한다는 것입니다. 이 툴은 그런 변수들을 파일로 이미 추출해주었습니다.

변수 파일들과 우리가 수정한 커널, 램디스크 파일들을 같은 폴더에 넣었는지 다시 확인해주세요.

그리고 다음과 같은 명령어로 repack을 해주세요.

$ mkbootimg --kernel ./zImage --ramdisk ./new-boot.img-ramdisk.gz --cmdline "$(cat ./boot.img-cmdline)" --base "$(cat ./boot.img-base)" --pagesize "$(cat ./boot.img-pagesize)" --dt ./boot.img-dt --ramdisk_offset "$(cat ./boot.img-ramdisk_offset)" --tags_offset "$(cat ./boot.img-tags_offset)" --output ./new-boot.img

명령어를 보시면 --kernel옵션에 커널 파일 위치가 들어가고 --ramdisk옵션에 램디스크 파일 위치가 들어갑니다. 그리고 --output옵션에 생성될 파일의 이름 및 위치가 들어갑니다. 나머지 옵션들은 기존에 파일로 추출된 값들이 들어가기 때문에 변경해줄 것은 없습니다.

명령어를 실행하면 new-boot.img파일이 생성됩니다.

새로운 boot.img를 디바이스에 넣는 방법

이제 new-boot.img파일을 다시 디바이스에 넣어주면 끝입니다.

fastboot로 다음처럼 디바이스에 이미지를 flash할 수 있습니다.

$ fastboot flash boot ./new-boot.img

만약 삼성 갤럭시 폰이라면 boot.img를 tar로 압축하여 Odin으로 넣는 방법이 있고, 우분투에서는 Heimdall이라는 툴을 이용하여 flash할 수 있습니다.

Heimdall에서 다음과 같은 명령어로 flash할 수 있습니다.

$ heimdall flash --BOOT new-boot.img

정리

boot.img를 unpack하고, 커널과 램디스크를 수정하여 다시 repack하는 과정을 알아보았습니다. 기존의 BOARD 관련 변수들을 변경하지 않으면 repack 이미지로 부팅하는데 큰 문제가 없습니다.

참고