[The device tree been reviewed and succesfully merged. Snapshot are now available!](https://git.openwrt.org/?p=openwrt/openwrt.git;a=commit;h=b108ed0ab09492d8d5a1775714da1ee34ce475ee)
Recently, some network devices caught my attention both on Aliexpress and Alibaba. Specifically, I found some interesting outdoor equipment for a very low price, ranging between 10-25$.
These are 2.4ghz AR9330 based boards, powered via POE (although on a nonstandard voltage), with two 10/100/1000 Ethernet ports, an integrated antenna, and a waterproof enclosure.
I received the first one from Aliexpress but I plan to get some other to test as well.
From the PCB picture it is clear that the board has an easily accessible serial header and that it has a SOIC8 flash chip (Winbond 25Q64). Given this info, there are two possibilities to start learning about the board via hardware: connecting to the serial console and get whatever the oem firmware prints out and do a direct hardware image of the flash chip.
Before even trying the SOIC clip or the serial port I wanted to check around the stock firmware. It looks like the device has no DHCP server but it has a fixed `192.168.0.1` IP address and default `admin:admin` credentials.
By default, there's only the web interface and a telnet server listening on the public interface. The credentials for the telnet interface are `root` without a password.
While upon collecting the user is dropped in a restricted prompt with few commands available, it is possible to inject commands in almost any of it via common shell separators `|;&`.
By knowing the size of each mtd partition, we get to know that it has a 8MiB flash chip. This makes sense given that the chip has written on it `25Q64`, where `64` is the size in Megabits.
When the device boots up, a lot of custom scripts and services will run. The most custom part of the firmware, which means the web interface and their custom binaries are somehow encrypted or more simply obfuscated and loaded at runtime in ram. At rest, the obfuscated files are called `/usr/web.bin`, `/usr/sbin.bin`, `/usr/apps.bin`. The executable responsible for decrypting them to more simpler `tgz` archives is called `ap_monitor`. Ghidra successfully decompile this binary and the obfuscation mechanism is not very complicated and could be reversed with not too much effort but there's probably no reason to do so.
Since I was unable to find the manufacturer both on the package or anywhere else, I'll refer to it as `ZiKing` as it seems that's the name stated in their own proprietary config file. On Aliexpress, the same device is also often said to be made by `ANDDEAR`. Both do not seem to have any presence on the English internet.
The only thing actually existing, given that as of now the website shows a default page, is [their IANA assignment number](https://oidref.com/1.3.6.1.4.1.37260).
_WARNING: The Raspberry VCC will five some power also to the SoC. This means that there might be interference given the unknown state of the SoC while working on the flash chip. In my case, that lead to some verifying errors after a write, but the write itself never failed._
Check that all the checksums do match (also with the dump obtained via `dd` and `cat`). In case they don't there's probably something wrong in the clip position or in the wiring. Remember that no pin should left floating even if it's not useful for the operation. /WP and /HOLD should be always connected to something like GND or VCC.
The serial header is easy to work with and has clearly written the pinout on it. Any cheap USB adapter will probably work. In my case the baud rate is 115200, however, a script like [baudare.py](https://github.com/somu1795/baudrate) should do the trick.
The total size is of course 8192KiB. The partitions are not partitions in an EXT or NTFS sense. The data is just contiguous on the flash but the bootloader and the kernel are responsible for considering the different regions separate.
Since for vanilla OpenWrt a custom partition for configuration is not needed, and two rootfs aren't useful and everything can be packed in a single partition with more space for packages and user data our target could be:
On some other devices this is not needed because maybe the partition layout already makes sense: ie there's already a single partition with kernel and data. They are a bit easier to play with because in that case there's probably no need to manipulate the boot environment. Furthermore, in this case, building an image for flashing trough the OEM web interface might be not possible.
U-boot is an Open Source Bootloader mainly for embedded devices. While it is actively developed, the actual version depends on the SDK a vendor provides for its SoC.
This confirms most of what we have got to know from the OEM firmware, 8MiB flash, 32MiB RAM, AR9330 SoC. Hornet is the codename for a [specific ALFA board](https://openwrt.org/toh/alfa_network/hornet-ub), and probably its target has been recycled for this U-Boot build.
U-Boot has the possibility to drop the user to an interactive command prompt if a key is pressed on the early boot phase:
_Note: `ar7240>` is probably there just because someone forgot to edit the prompt to the correct chipset name. It's just a static name and it is irrelevant._
The `printenv` prints out the current u-boot environment:
As seen above, the `bootargs` variable contains the serial console information, the partition scheme, and the init information. So any change in the partition scheme must be reflected in this variable.
The other important value is `bootcmd`: it contains the actual boot command. The address there is the starting address of the partition that contains the kernel image (with a `0x9f` prefix).
So, given 0x0038000 which is `3670016/1024=3584KiB`. So by summing up the size of `mtd0`, `mtd1`, and `mtd2` the total should be the `mtd3` starting address: `64+64+3456=3584KiB`.
Where, `root=31:02` stands for the `mtd2` partition which is labelled `firmware`. The `bootcmd` address is `0x0002000` which is 128KiB. `8000k` is the OpenWrt partition size.
However, it looks like now the `root` and `mtdparts` parameters are no longer needed since the DTS is built into the image (more on this later). Also, the default init for OpenWrt is `/sbin/init` so that may be omitted too.
U-boot ships also with the commands `setenv` and `saveenv`. The first one will change or add a variable in the current session, the second one will write the current state on the u-boot-env partition.
As for the u-boot environment, it is possible to create an entirely new `u-boot-env` data using an utility called `mkenvimage` which is shipped within the u-boot source.
Simply write all the parameters in a file called `env.txt`
One of the best ways to understand the process is to look at recent commits that add supports for some device, especially if with the same SoC. As an example reference, I used the [Comfast CF-EW72 target](https://git.openwrt.org/?p=openwrt/openwrt.git;a=commit;h=7daab6286110b95167e291409395494f18edc9dc).
I copied a DTS of the same SoC, specifically `./target/linux/ath79/dts/ar9330_glinet_gl-ar150.dts` in the OpenWrt source tree, adjusted the partition scheme, removed the GPIO info that I don't have yet, checked that the ART partition offsets do match with mine. Here's the result:
`8000k` is the size of the partition chosen before. It should be now possible to select the new target using the standard `make menuconfig` and following normal OpenWrt build instructions.
The result should be the file called `./bin/targets/ath79/generic/openwrt-ath79-generic-ziking_cpe46b-squashfs-sysupgrade.bin`
## Putting it all together
Technically, there are at least three methods to flash back the newly obtained images:
* Flash from a running system, using `mtd`
* Flash from U-Boot via tftp
* Flash using the SOIC Clip
As of now, I have yet to try the first two. This document will be updated accordingly.
### Flash via Soic
_Warning: the `du` command do not report exact file sizes but round instead in order to follow the sector size in use._
In order to flash using `flashrom` the target image needs to be exctly 8192KiB. So what needs to be done is to assemble a full image and add NULL padding where necessary.
Firstly, dump the new u-boot-env partition with the new parameters written using `setenv` as described in the U-Boot specific section.
Out final layout should be:
*`u-boot` 64KiB, the exact same file as dumped (`mtd0`)
*`u-boot-env` 64KiB, newly dumped with the changes
*`firmware` 8000KiB, the OpenWrt image padded with 0x00
*`ART` 64KiB, the exact same file as dumped (`mtd6`)
```
# cat u-boot > flash
# cat u-boot-env >> flash
# ls -l openwrt-ath79-generic-ziking_cpe46b-squashfs-sysupgrade.bin
-rwxrwxrwx 1 user user 3998478 Apr 14 01:11 openwrt-ath79-generic-ziking_cpe46b-squashfs-sysupgrade.bin
Now it is possible to reboot the device and hope everything has worked as expected. While the serial console is still useful in order to see the boot process, the debug messages and eventual problems, OpenWrt will now work normally and it is possible to connect via ethernet and get an IP Address assigned (by default there's `odhcpd` running).
`#openwrt-devel` on `irc.freenode.net` has been very helpful. The channel is well populated and people try to do their best to answer technical questions.
MIPS has different areas, called "kseg", some are cached, some are uncached and some are mapped somewhere, some are not. In this SoC there's a special integrated peripheral that knows how to read from SPI NOR memory and it provides the results in a memory-mapped way, that is, CPU can execute from it directly. I think 0x9f is one of the regions where it's mapped to (another common region is 0xbf).