Manually editing uboot-elf in the name of DHCP and SSH

Once I fell into the hands of an AEWIN SCB-3240 piece of iron, which should have settled in the server rack forever with the goal of never touching it again. It was planned to be used not for its intended purpose, but for the purpose of testing our product. Kaspersky Lab has a tradition - to release an anti-virus SDK for all conceivable platforms, if only there is something capable of compiling the code in C. Accordingly, the SDK needs anti-virus databases, which, despite the fact that they are the same for all products, nevertheless you need to test - in case of an error in the SDK itself, or the database loader, or some platform features, or ... In general, a million reasons. And so that we learn about the problems a little earlier than from the new support cases, the last line of defense are dozens of glands that check each set of anti-virus databases for performance.

That is, the interest was not AEWIN's ability to work with the network, but only its essence in the form of MIPS / Linux. The problem was that the piece of iron did not provide for any adequate connection. All that was offered to me was the console port, telnet and no dhcp.

Unfortunately, the worst fears were not in vain. The device had no permanent storage, and it lived only from power on to reboot, each time deploying a reference image.

Total that I needed. Teach you how to get the address via DHCP, teach her how to accept SSH connections, and try not to break on the way.

Part one. Ssh.
As an SSH server, it was decided to take dropbear. In fact, no comparative testing and analysis of features was carried out - I chose what I already worked with. For the first step, we will need the dropbear source code - https://matt.ucc.asn.au/dropbear/ and OcteonSDK - the latter is available only for partners, so we will assume that we already have it.
The process itself is simple. Unpack the toolchain from the SDK, unpack the dropbear sources, we are going to:

export CC=/home/pony/octeon_sdk/tools-gcc-4.1/bin/mips64-octeon-linux-gnu-gcc
./configure --host=mips64-octeon-linux-gnu --prefix=/home/pony/dropbear --exec-prefix=/home/pony/dropbear/bin --disable-zlib
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
make install

We take binaries from / home / pony / dropbear / bin

Part two. Firmware.
Here we need a TFTP server and, to facilitate overwork, an OpenDHCP server.

We connect the hardware with the first network port (so it will get ip faster) to the working machine, start TFTP + OpenDHCP

Connect to the console port - in my case it was a pair of CiscoConsole + TrendNet COM2USB , turn on the hardware. We skip the first “Hit any key to stop autoboot”, wait for the second -
Interface 3 has 4 ports (LOOP)
Interface 4 has 1 ports (AGL)
Hit any key to stop autoboot: 0
Get the

DHCP address
Octeon aewin3240 (ram) # dhcp

We look how it loads:
Octeon aewin3240 (ram) # grepenv boot
bootcmd = fatload mmc 1: 2 0x100000 vmlinux.64; bootoctlinux 0x100000 coremask = 0xf mem = 0


That is, the system image is stored on the internal MMC card. We need to take this image to ourselves.

We read the image from the hardware into memory - we have the name and path from the file (mmc 1: 2 vmlinux.64), judging by the boot command, it is expected that the address 0x100000 is free:
Octeon aewin3240 (ram) # fatload mmc 1: 2 0x100000 vmlinux .64 Fill

it with TFTP (we get the size as the result in the console from the previous step, we just need to translate it into hex):
Octeon aewin3240 (ram) # tftpput 0x100000 0x332C650 192.168.0.1:vmlinux.64

Part Three. Vivisection.

The resulting file is a self-extracting ELF, with the initramfs image in the kit, which is also unpacked with the kernel at the boot stage. Accordingly, we need to get this image, make the necessary changes to it and assemble it back. Unfortunately, I do not have the original - with the kernel and other files from which ELF was built. Therefore, you will have to uncover the saw and surgical glue. Let's see what is in the file -

root @ ponybuntu: / home / root / uboot # objdump -h vmlinux.64
Sections:
Idx Name Size VMA LMA File off Algn
...
11 .init.text 0002a534 ffffffff8090e000 ffffffff8090e000 0080f000 2 ** 5
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .init.data 02aee0d0 ffffffff80938540 ffffffff80938540 00839540 2 ** 5
CONTENTS, ALLOC, LOAD, DATA
13 .exit.text 00,001,920 03,327,610 ffffffff83426610 ffffffff83426610 2 ** 2
the CONTENTS, ALLOC, the LOAD, READONLY, CODE

...
the only candidate for initramfs - .init.data section with a size 0x02aee0d0 = 45,015,248 bytes
For a start go cap in hand to Gentushnikam and learn , what that initramfs images are stored in gzip. We are looking for headers from the GZIP format inside the image:
root @ ponybuntu: / home / root / uboot # binwalk vmlinux.64 | grep gzip
5962904 0x5AFC98 gzip compressed data, from Unix, NULL date: Thu Jan 1 03:00:00 1970, max compression
8705696 0x84D6A0 gzip compressed data, from Unix, last modified: Mon Feb 2 19:15:12 2015, max compression


Only 0x84D6A0 is suitable for offset under .init.data - try to pull it out. The archive obviously does not go beyond the limits of the section, so the size is the start address of the next section minus the start address of gzip:
0x03327610 - 0x0084D6A0 = 0x02AD9F70 = 44932976 bytes. Cut it out:
root @ ponybuntu: / home / root / uboot # dd if = vmlinux.64 bs = 1 oflag = seek_bytes skip = 8705696 count = 44932976> ramfs.gz.orig

Unpack:
root @ ponybuntu: / home / root / uboot # gunzip <ramfs.gz.orig> initramfs.cpio
gzip: stdin: decompression OK, trailing garbage ignored


And here the file awaits us. Judging by the "trailing garbage ignored", not everything in the cut piece turned out to be an archive. This still comes back to us, but for now, suppose everything is in order.

Remember the size of initramfs.cpio = 143785984

Part Four We are preparing an image.
Mount initramfs in a temporary folder:
root @ ponybuntu: / tmp / ramfs # cpio -i -d -H newc --no-absolute-filenames <initramfs.cpio
root @ ponybuntu: / tmp / ramfs # ls
bin dev etc examples home init lib lib32 lib32-fp lib64 lib64-fp linuxrc mnt mnth proc root sbin share sys tmp usr var


We add Dropbear binaries to / bin and / sbin and configure it to autostart + raise eth0 + get IP in / sbin / rc - add
echo Setting up network
ifconfig eth0 up
udhcpc -i eth0
#Start sshd if it exists
if [ -e /sbin/dropbear ]; then
  echo Generating Drpbear keys
  if [ ! -e /etc/ssh_host_rsa_key ]; then
    /bin/dropbearkey -t rsa -f /etc/ssh_host_rsa_key
  fi
  if [ ! -e /etc/ssh_host_dsa_key ]; then
    /bin/dropbearkey -t dss -f /etc/ssh_host_dsa_key
  fi
  echo Starting Dropbear
  /sbin/dropbear -d /etc/ssh_host_dsa_key -r /etc/ssh_host_rsa_key
fi

We clean / examples - the hardworking Chinese forgot to do this, which gives us extra space that can be used for our files so that the resulting archive does not crawl beyond the original ELF.

We collect this back into the image initramfs:
root @ ponybuntu: / tmp / ramfs # find. | cpio -H newc -o> /home/root/uboot/initramfs.cpio We pack the

image in gzip:
root @ ponybuntu: / home / root / uboot # gzip --best <initramfs.cpio> ramfs

Glue the resulting gzip to the old one:
root @ ponybuntu: / home / root / uboot # dd conv = notrunc if = ramfs of = vmlinux.64 oflag = seek_bytes seek = 8705696
87758 + 1 records in
87758 + 1 records out
44932351 bytes (45 MB) copied, 0.130304 s, 345 MB / s


Here I will get ahead of myself. This image after pouring on a piece of iron quickly falls into kernel panic with complaints about unpacking. And the thing is definitely that the “unpacker” from ELF is not as phlegmatic as his colleague gzip, and clearly expects that he will know the size of the archive absolutely exactly. We recall that above we already received "trailing garbage", subtly hinting to us that not everything that we considered an archive was such. According to gzip specs, the last archive entry is the size of the unpacked data in LittleEndian. Recall the size of initramfs.cpio = 143785984 = 0x08920000 . We are looking for this at the supposed end of the archive:

root @ ponybuntu: / home / root / uboot # tail -c 24 ramfs.gz.orig | hexdump -C
00000000 1f ff a9 e3 5f 8e 5b 98 18 00 00 92 08 00 00 00 | ...._. [......... |
00000010 00 00 00 00 00 02 ad 9f 65 | ....... e |


We find: 00 00 92 08 - 11 bytes earlier than the current end of the file.

So the real gzip size is with initramfs = 44932976 - 11 = 44932965 = 0x02AD9F65. We look above and see that the last bytes of the archive that we originally pulled out are exactly 02 ad 9f 65. That means that “from the beginning of the archive to the end of the .init.data section” not only the archive is placed, but also a bit of zeros and the size of the archive. Which, apparently, is read by the kernel at boot, and an attempt is made to unpack.

The “our” archive prepared with initramfs prepared above is slightly smaller than the original - that means we can paste it in the place of the old one, and then adjust the size at the end of the section:

root @ ponybuntu: / home / root / uboot # dd conv = notrunc if = ramfs of = vmlinux.64 oflag = seek_bytes seek = 8705696
87758 + 1 records in
87758 + 1 records out
44932351 bytes (45 MB) copied, 0.130304 s, 345 MB / s


Check that the file did not break due to our manipulations:

root @ ponybuntu: / home / root / uboot # readelf -h vmlinux .64
ELF Header:
Magic: 7f 45 4c 46 02 02 01 00 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, big endian
Version: 1 (current)
OS / ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0xffffffff8067f330
Start of program headers: 64 (bytes into file)
Start of section headers: 53657872 (bytes into file)
Flags: 0x808b0001, noreorder, octeon, mips64r2
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 2
Size of section headers: 64 (bytes)
Number of section headers: 21
Section header string table index: 20


There are no complaints, let's hope that everything works. Now we need to fix the archive size expected by the kernel. Then I got bogus and used the Windows HexEdit, with the mouse and guis - go to the address 0x0332760C and change 02 AD 9F 65 to the size of our new archive - 44932351 = 02 AD 9C FF

Save, put on the tftp server, turn on the piece of iron, get to the second again Hit any key to stop autoboot, again we get the address by dhcp. Download the new image from tftp to memory:

Octeon aewin3240 (ram) # tftp 0x100000 192.168.0.1:vmlinux.64
Using octeth0 device
TFTP from server 192.168.0.1; our IP address is 192.168.0.2
Filename 'vmlinux.64'.
Load address: 0x100000
Loading: ############################################### ######
10.4 MiB / s
done
Bytes transferred = 53659216 (332c650 hex)


Recall how it was loaded before:
Octeon aewin3240 (ram) # grepenv boot
bootcmd = fatload mmc 1: 2 0x100000 vmlinux.64; bootoctlinux 0x100000 coremask = 0xf mem = 0


You don’t need to read from the flash drive, the image is already in memory along the path 0x100000, so we just start it - bootoctlinux 0x100000 coremask = 0xf mem = 0 , we see:
BusyBox v1.20.2 (2015-02-02 22:37:53 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
~ #


Great, it loads. SSH is working. You can replace the original image with ours.
Again, we overload the piece of iron to the “received dhcp” stage, download the new image again, write it from the memory to the MMC next to the original. Just in case:

Octeon aewin3240 (ram) # fatwrite mmc 1: 2 0x100000 vmlinux.64.new 332c650
writing vmlinux.64.new
53659216 bytes written


Change the hardware boot command:
Octeon aewin3240 (ram) # setenv bootcmd 'fatload mmc 1: 2 0x100000 vmlinux.64.new; bootoctlinux 0x100000 coremask = 0xf mem = 0 '
Octeon aewin3240 (ram) # saveenv


Done.

I don’t know if this success-story will help anyone in the future, but if I came across something similar, it would save me a day or two spent on Google. The vast majority of manuals found on the network are designed for the presence of original files - the kernel, descriptions and other things, from which you can assemble a u-boot image with one command.

Also popular now: