ipTIME 공유기 커스텀 펌웨어 플래싱 방법

◎테스트 장비: ipTIME A1004 (Entry Point Address: 0x8000C150)
◎신 이미지: openwrt-18.06.5-ramips-mt7620-mt7620a_mt7530-squashfs-sysupgrade.bin
◎준비물: HxD Hexa Editor, CRC32 체크섬 (https://emn178.github.io/online-tools/crc32_checksum.html)

※uImage Header
/*
 * Legacy format image header,
 * all data in network byte order (aka natural aka bigendian).
 */
typedef struct image_header {
        uint32_t        ih_magic;       /* Image Header Magic Number    */
        uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
        uint32_t        ih_time;        /* Image Creation Timestamp     */
        uint32_t        ih_size;        /* Image Data Size              */
        uint32_t        ih_load;        /* Data  Load  Address          */
        uint32_t        ih_ep;          /* Entry Point Address          */
        uint32_t        ih_dcrc;        /* Image Data CRC Checksum      */
        uint8_t         ih_os;          /* Operating System             */
        uint8_t         ih_arch;        /* CPU architecture             */
        uint8_t         ih_type;        /* Image Type                   */
        uint8_t         ih_comp;        /* Compression Type             */
        uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
} image_header_t;

※ipTIME 공유기의 Original uImage Header 부분 
iptime_uimage_header.png
※OpenWRT의 Original uImage Header 부분

openwrt_uimage_header.png

 

1. 공식 펌웨어를 다운로드 하여 Hexa 에디터로 모델명을 확인한다. 아래 그림은 헤더의 Image Name 및 모델명 부분이다.
iptime_image_name.png

 

2. 신 이미지의 Image name 부분을 공유기 모델명으로 변경해 준다. 또한 필요할 경우 Entry Point 값도 변경해 준다.

3. 아래 그림과 같이 신 이미지의 uImage Header CRC Checksum 부분을 0으로 처리하고 uImage Header만 별도의 바이너리 파일로 만들어 저장한 후 CRC32 체크섬 값을 알아낸다.
openwrt_modify_header.png

 

4. 알아낸 체크섬을 신 이미지의 uImage Header CRC Checksum 부분에 기록하고 저장한다.
iptime_crc32_header_checksum.png

 

5. ipTIME 공유기에 USB-TTL 시리얼을 연결한 후 아래와 같은 방법으로 플래싱 한다.

============================================
Ralink UBoot Version: 4.1.2.0
--------------------------------------------
ASIC 7620_MP (Port5<->GigaSW)
DRAM component: 512 Mbits DDR, width 16
DRAM bus: 16 bit
Total memory: 64 MBytes
Flash component: SPI Flash
Date:Mar 11 2014  Time:14:18:46
============================================
icache: sets:512, ways:4, linesz:32 ,total:65536
dcache: sets:256, ways:4, linesz:32 ,total:32768

 ##### The CPU freq = 580 MHZ ####
 estimate memory size =64 Mbytes
#Reset_MT7530
Disable WAN port....
          cur reg0 =  00001040
          new reg0 =  00001840

Please choose the operation: (t:tftp server/b(boot now)/f(flash test)) ← 여기서 연속하여 t를 누른다.

ETH_STATE_ACTIVE!!
TFTP server start
IP address: 192.168.0.1
Load address: 0x80100000
Reading: ..... ← 플래싱 대기 상태

윈도우 명령행 프롬프트에서 tftp를 써서 이미지를 플래싱 한다.

tftp -i 192.168.0.1 put openwrt-18.06.5-ramips-mt7620-mt7620a_mt7530-squashfs-sysupgrade.bin

###########... ← 플래싱
done
Bytes transferred = 7078067 (6c00b3 hex)
Check Firmware:80100000 =>[ Check Alias ... [a1004],[a1004] ] ->[ RUN : OK ]
Run Firmware Found!!
raspi_erase_write: offs:30000, count:6c00b3
Abort: image size larger than 3997696!

신 이미지가 3997696바이트 보다 커서 플래싱 실패. 크기를 줄여도 sysupgrade가 아닌 ramdisk 이미지를 사용하여 플래싱해야 할듯 하다.

하지만 이러한 방법으로 ipTIME의 u-boot 내부 체크 프로세스를 우회하여 플래싱은 가능하다.
아래는 이 과정을 일괄처리 할 수 있는 스크립트 이다.
 
#!/bin/bash
######################################################################
#
# OpenWRT 이미지를 ipTIME 공유기가 인식하도록 uImage 헤더를 수정한다.
#
######################################################################
IMAGE_NAME="a1004"
CMD_CRC32="crc32"
TMP_FILE="/tmp/__tmp_file__"

IMAGE_NAME_LEN=${#IMAGE_NAME}
######################################################################
#
# 사용방법 출력
#
######################################################################
function usage() {
  echo ""
  echo "$0 (bin file)"
  echo ""
}

######################################################################
#
# uImage 헤더를 패치한다.
#
######################################################################
function patch_uimage_header() {
  if [ ! -f ${1} ]
  then
    echo "File not found !"
    exit 1
  fi

  # Header CRC checksum과 Image Name 초기화
  dd if=/dev/zero of=${1} bs=1 seek=4 count=4 conv=notrunc
  dd if=/dev/zero of=${1} bs=1 seek=32 count=32 conv=notrunc

  # Image Name 기록
  echo -n "${IMAGE_NAME}" | dd of=${1} bs=1 seek=32 conv=notrunc
  dd if=${1} of=${TMP_FILE} bs=1 seek=0 count=64 conv=notrunc

  # CRC32 checksum 연산
  CRC32_CHECKSUM=$(${CMD_CRC32} ${TMP_FILE})
  echo "*** CRC32 Checksum: ${CRC32_CHECKSUM}"

  # CRC32 checksum 기록
  echo "${CRC32_CHECKSUM}" | xxd -r -p > ${TMP_FILE}
  dd if=${TMP_FILE} of=${1} bs=1 seek=4 count=4 conv=notrunc

  rm -f ${TMP_FILE}
  xxd -g 1 -c 16 -l 64 ${1}
}

######################################################################
#
# arguments가 1과 다르면 잘못된 옵션 지정이므로 끝낸다.
#
######################################################################
if [ $# -ne 1 ]
then
  usage
  exit 1
fi

echo "*** Filename: ${1}"
patch_uimage_header ${1}
위로 스크롤