Imagine a scenario where you have a device running an embedded Linux system, but you flashed a bad firmware which doesn’t let you to have access to Ethernet/WiFi on this device. You only have access to it is using serial cable.
First thing you think is to use U-Boot transfer support over serial, but unfortunately you don’t have this option:
U-Boot 1.1.4 (Feb 27 2009 - 12:06:20)
AP94 (ar7100) U-boot 0.0.12
(sic)
In: serial
Out: serial
Err: serial
Net: eth0, eth1
### main_loop entered: bootdelay=1
### main_loop: bootcmd="bootm 0xbf050000"
Hit any key to stop autoboot: 0
### main_loop: got key string, abort boot
### main_loop: no define CONFIG_AUTOBOOT_KEYED
### main_loop: CFG_HUSH_PARSER
### main_loop: parse_string_outer
## Booting image at bf050000 ...
checksum:743d0796
Image Name: MIPS OpenWrt Linux-2.6.39.4
Image Type: MIPS Linux Kernel Image (lzma compressed)
Data Size: 873389 Bytes = 852.9 kB
Load Address: 80060000
Entry Point: 80060000
Verifying Checksum ... OK
LZMA Umcompressing Kernel Image ... Image loaded from 80060000-802e82d8
As you can see it is not entering on U-Boot prompt because CONFIG_AUTOBOOT_KEYED is not defined.
Then we need to find another alternative.
Unfortunately we are not lucky, the linux system on this router doesn’t have “lrz” program installed.
But all is not lost, I have an idea!!!
The “lrz” program is relatively small, about 60KB, then I can convert it to text and past on Linux terminal running inside de box (using echo and pasting text). Unfortunately I cannot use base64 program, because it also is not install on this Linux system.
The remaining option is using hexdump (xxd) to convert the binary on text bytes and the recover it, as I suggested some times ago (link in Portuguese).
So, let to do it, first thing to do is download the package containing the lrz program (lrzsz_0.12.20-1_ar71xx.ipk).
Hmm, this is 59792 bytes long, no problem I hope.
Now let to convert it from binary to text:
$ xxd -g1 lrz > output.txt
We need to remove the “00xxxxx: ” from beginning of each line and the 16 chars representation at end of each line:
$ sed -i 's/^\(.\)\{9\}//g' output.txt
$ sed -i 's/\(.\)\{16\}$//g' output.txt
Now let to convert this text back to binary to confirm it is working:
$ for i in $(cat output.txt) ; do printf "\x$i" ; done > mylrz
Let to check if they are have same binary sequence:
$ md5sum mylrz
08334803ce751a1f021a4de0c9c0e849 mylrz
$ md5sum lrz
08334803ce751a1f021a4de0c9c0e849 lrz
Now just let to copy and past this content of text to linux box terminal.
I suggest you to use picocom instead minicom to do it:
$ picocom -b 115200 -l -r /dev/ttyUSB0
I started trying to send line by line this way:
root@OpenWrt:/# echo "7f 45 4c 46 01 02 01 00 01 00 00 00 00 00 00 00" >> mylrz.txt
In few seconds it became a very boring task and very prone to fail.
Then I decide to send commands directly to terminal over serial using shell script.
Leave picocom…
After some tests I noticed it is not possible to send many characters to terminal (over /dev/ttyUSB0), no more 2 bytes by time.
Then the command became this long line:
$ j=0; echo -n -e "ec" > /dev/ttyUSB0; echo -n -e "ho" > /dev/ttyUSB0; echo -n -e " \"" > /dev/ttyUSB0; for i in $(cat output.txt); do j=$(($j+1)); echo -n -e "$i" > /dev/ttyUSB0; echo -n -e " " > /dev/ttyUSB0; if [ $(expr $j % 16) -eq 0 ]; then echo -n -e "\" " > /dev/ttyUSB0; echo -n -e ">>" > /dev/ttyUSB0; echo -n -e "lr" > /dev/ttyUSB0; echo -n -e "z" > /dev/ttyUSB0; echo " " > /dev/ttyUSB0; echo -n -e "ec" > /dev/ttyUSB0; echo -n -e "ho" > /dev/ttyUSB0; echo -n -e " \"" > /dev/ttyUSB0; fi; done; echo -n -e "ec" > /dev/ttyUSB0; echo -n -e "ho" > /dev/ttyUSB0; echo "\"" > /dev/ttyUSB0
Verify if file lrz file was created:
root@OpenWrt:/# ls -l lrz
-rw-r--r-- 1 root root 183113 Jan 1 01:19 lrz
Rename it to lrz.txt:
root@OpenWrt:/# mv lrz lrz.txt
Convert the text file to binary:
root@OpenWrt:/# for i in $(cat lrz.txt) ; do printf "\x$i" ; done > lrz
root@OpenWrt:/# md5sum lrz
08334803ce751a1f021a4de0c9c0e849 lrz
Give it permission to execute and move to /usr/bin:
root@OpenWrt:/# chmod 555 lrz
root@OpenWrt:/# mv lrz /usr/bin/
Execute the lrz command to receive file:
root@OpenWrt:/# lrz -Z
Leave picocom program (Ctrl+A+X)
In you computer execute this command to transfer firmware to your router:
$ sz --zmodem /tmp/openwrt-ar71xx-dir825.bin > /dev/ttyUSB0 < /dev/ttyUSB0
Check with md5sum to verify if it is correct:
root@OpenWrt:/tmp# md5sum openwrt-ar71xx-dir825.bin
90e938ed4a5aa825495c2b0b099655e7 openwrt-ar71xx-dir825.bin
alan@aureo:~/Desktop/serial$ md5sum /tmp/openwrt-ar71xx-dir825.bin
90e938ed4a5aa825495c2b0b099655e7 /tmp/openwrt-ar71xx-dir825.bin
Now just update your system using this new firmware:
root@OpenWrt:/# sysupgrade /tmp/openwrt-ar71xx-dir825.bin