안드로이드에서 boot.img는 커널(kernel)과 램디스크(ramdisk)가 있는 이미지입니다. 만약 커널이나 램디스크를 변경하고 싶다면 boot.img를 unpack하고 파일을 수정한 뒤에 다시 repack하여 boot.img를 만들 수 있습니다.
unpack/repack하는데 사용하는 유틸리티의 이름은 unpackbootimg과 mkbootimg입니다. 이 툴들은 CyanogenMod에서 제공합니다.
이 글에서 다음과 같은 내용을 설명합니다.
- unpackbootimg, mkbootimg 툴 설치 방법
- boot.img를 얻는 방법
- boot.img를 unpackbootimg으로 unpack하는 방법
- Linux 코드 빌드 및 zImage 생성 방법
- 램디스크 수정하는 방법
- mkbootimg으로 수정한 램디스크 및 커널을 pack하는 방법
- 새로운 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 이미지로 부팅하는데 큰 문제가 없습니다.
참고
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력