Close
0%
0%

Cheapy 'rearview mirror' dashcam/Carplay/AAuto dev

Rooting, reverse engineering, and binary patching software on a closed device

Similar projects worth following
I wanted an Android Auto screen on my motorcycle to assist with navigation and a few other things (I figured I could write some Android app for my phone to display info I wanted). It's a large motorcycle but space is still obviously far too restricted for the typical double-din sized headunits for cars!

So I went shopping, and found a device intended to be strapped to a car's rear view mirror, with wireless Carplay and Android auto (ideal, no cables!), front and rear cameras (with recording facilities) and an FM transmitter to get audio back to the car ICE system. The trapezoidal shape was interesting, and sits above the bike's dashboard nicely. I'll need to make something to secure it and protect it from the worst of the weather, but this project mainly explores the software work needed to bend it to my will...

(Apologies, no photos yet, will try and rectify)

There are plenty of similar devices out there that appear to have similar screens and probably boards, judging by the form factor, features and port locations. There are more likely to be software differences between suppliers, but as with most of these sort of things, it's likely to be mostly different icons and skins, with only minor tweaks otherwise.

This is the device I purchased: https://www.amazon.co.uk/dp/B0C6M1ZQ44

Upon arrival, the device booted up nicely, and offers wireless Android Auto (and Carplay, but I don't have an iPhone so couldn't test that) and shows the AAuto stream on one side of the screen, and one of the cameras on the other half. It can also go full screen to display either or both of the cameras, has a 'parking monitor' function (continues recorded after ignition off) and records onto an included 64GB microSD card. Audio (from AAuto, and various beeps and dongs from the device itself) can be played through a speaker, or transmitted over FM to a car stereo, or output to a 3.5mm aux port. Alternatively, the device can not offer to sink audio from the AAuto stream, leaving your phone to connect to the headunit over USB (probably better quality, but the device beeps play over the inbuilt speaker still)

All pretty reasonable and useful for its intended purpose, but I wanted a few changes.

  • Wireless AAuto is great - no cables between phone and device, meaning I can leave my phone in my pocket (although the battery is then not charged of course)
  • Neither camera is needed (I already have a hardwired front/rear dashcam system on the bike, although if I hadn't, I'd be keeping the cameras!)
  • Not offering an AAuto audio sink is great, I was worried I'd have to hack a solution to this, but it's a setting accessible through the GUI
  • The device beeps and audio is really annoying...
  • Main issue - no GUI option for full-screen AAuto, so the already fairly small screen is half-wasted

How hard can it be...

  • Future work...

    mjc50608/30/2023 at 22:03 0 comments

    Ending up with a working device seems unnatural... I might need to fix it until it's broken...!

    So, future enhancements:

    • I could reduce the size of the side GUI buttons a bit and then increase the width of the frame. The GUI layouts are defined in xml files so fairly easy to play with, but the '1010' width is hardcoded in quite a few places throughout the sdvcam binary. Probably more work than it's worth, would only gain a few pixels.
    • Day/night mode doesn't seem too reliable. Or rather, it's broken. Not sure if this is a phone problem or device problem (the phone settings indicate that it should be set by the phone, but...). This might be resolved by a future update anyway, or I could just live with dark 'night' mode all the time.
    • Really, the main work now is to write an android/AAuto app for my phone to display some information from the bike and various sensors. That sounds like a separate project to me...
    • Only other thing I can think of is that it would be nice to get rid of the microSD card. This would mean building a new firmware image with the changed settings and binary and reflashing, but I'm not confident about a) flashing anything to that flash chip (nothing should go wrong, but there's definitely the potential to brick it) or b) building a working firmware image - the output from binwalk was such a mess I can't see it putting it all back together again successfully... I have the changed binary backed up, and microSD cards are cheap if a replacement is ever needed...

  • Success!

    mjc50608/30/2023 at 21:53 0 comments

    First problem now, assuming I hadn't mangled the binary with my amature hex editing, was getting the patched binary onto the device and overwrite the original. Copying onto the microSD was familiar habit by now, but the overlayfs was nowhere near big enough to allow overwriting of a 4.8MB binary.

    Best option I can see is to leave the patched binary on the microSD, but edit the init scripts to make sure the microSD is mounted, then bind mount the patched binary on top of the original before it tries to run sdvcam. If the microSD is ever removed (or fails, although we're not writing to it, so it should be ok) in the future, the original sdvcam will run and just display a small frame.

    Amazingly enough, the edited init script worked first try, and the device booted, the sdvcam executable loaded, and....

    Success!!! The AAuto stream was displayed in full-width glory! The horizontal stretching was visible, but really not too bad. The AAuto 'status bar' was still displayed at the bottom (of course, as far as my phone was aware, nothing had changed) but it was working! A few tedious edits to the cast_config.lua file (increasing the phy_width) found a good value that had the status bar on the side (more vertical room for the map) and reduced the stretching slightly too (still certainly noticeable, but really not too bad - it seems that AAuto, although only allowing certain stream resolutions, will attempt to correct for screen aspect ratio depending on the display physical size reported to it).

    I now have a device that fits on top of my dashboard nicely, shows a nice full-screen AAuto stream, and still allows my phone to connect to my helmet headset for audio.

  • Attacking sdvcam

    mjc50608/30/2023 at 21:39 0 comments

    Cat-ing /sys/devices/virtual/disp/disp/sys/attr displays some data about a couple of the virtual framebuffers. One of these covers the whole screen (shows the buttons etc?) and the other matches the 533 or 588x320 resolution. Unfortunately, I could not find any way of getting the system to change that size. The driver for the screen seems to be compiled into the kernel (and no luck with source code...) and no obvious libraries seem present or are opened by sdvcam (it 'opens' the display device directly). Hmm... Perhaps I could trace the calls, but that means getting gbd etc onto the system (and compiled for arm...) and without any external libraries I can call, would be no use anyway.

    I copied the sdvcam binary to the microSD card and transferred it to my laptop. The laptop is x86, and the binary is arm, but perhaps Ghidra can make some sense of it... After a good fight with Radare2, Ghidra and eventually Cutter, I had sdvcam loading into the disassembler. Taking a worryingly long time to load into the disassembler...

    Oh my. Of course, a binary this large and this complicated (and apparently all the libraries compiled in) is going to feel a little overwhelming... And I've not done much assembly work before, especially arm. How hard can it be... Fortunately, Ghidra (within Cutter) has managed to decompile the assembly (it was lovely seeing something vaguely understandable!) and I do have the rather helpful debug log from the running application, with logs such as 'requesting 1280x720 stream' and 'setting frame to...', also with what appeared to be function names and perhaps line numbers from the original source code. No function names and certainly no line numbers in the decompiler output, but those strings are there!!

    It didn't take too long to trace the section of code responsible for setting the frame size. It basically calculated the aspect ratio of the stream, and then made the frame as big as possible while fitting the screen (or rather, the 1010x320 'free space' between the buttons) and maintaining the aspect ratio. So far, so good, but if AAuto would only send 840x480, 1280x720 or 1920x1080 streams, the frame would never fill the screen. If the function sized the frame to fit the 1010x320 space, but allowing the edges to spill over the edge of the screen, that would work, but the top and bottom of the stream would be invisible, and I bravely decided that trying to edit the lylink binary to request blanking from AAuto that I'd only read a brief description of was probably beyond my abilities... Next best option was just stretching the frame to 1010x320 and hoping the distortion wasn't too bad (the 'stock' frame sizes already resulted in the stream being squashed slightly horizontally, so hopefully nearly doubling the frame width wouldn't make everything unreadable). Also, hopefully the rest of the software would handle the wider frame and translate touches correctly back to the AAuto app on my phone... (but not the absolute end of the world if not, most of it is voice controllable)

    The function was laid out in such a way that

    1. The aspect ratio of the stream was calculated, and compared to 1010x320
      1. If the stream was wide (in comparison with 1010x320) it set the width to 1010 and then calculated the height to maintain the aspect ratio
      2. If the stream was narrow compared to 1010x320, it set the height to 320 and then calculated the width.
    2. The next step was calculating an offset so the stream appears centered in the screen.

    The AAuto stream would always fall into the second group (b). If I removed the width calculation, and always set it to 1010, the frame should take up the whole (available) screen, and the offsets should be calculated to suit. After a bit of arm assembly revision, I managed to nop the calculation and set the width to an integer 1010...

  • Removing cruft, and cast settings

    mjc50608/30/2023 at 21:12 0 comments

    By now, the boot chime was getting a little annoying... Removing or overwriting the .wav file in /usr/share/res/audio may have worked, but that would use up space in the overlayfs, and an easier option was removing the wires from the speaker pads. I'd like to say I carefully desoldered them, but cutting the wires was far more satisfying... I also unplugged and removed the front facing camera (partly removing bulk, partly power consumption, but also on the faint hope that the absence of a camera would convince the device to show the Android Auto stream in full screen (no such luck, of course).

    Feeling better after that bit of tidying, I looked through the settings files again to see if it could be convinced...

    In /data/cast_config.lua (lua?!) was a json-like settings file (unlike the more ini-style settings elsewhere) that contained x and y resolutions and 'phy_x' and 'phy_y' (physical dimensions of the screen in mm) for various streams - Carplay, mirrorlink, hicar and android auto. A couple of resolutions listed for each, presumably to allow the phone to negotiate a resolution for a nice display. Android Auto had either 840x480 or 1280x720, followed by a comment in Chinese explaining that Android Auto only accepted 840x480, 1280x720 or 1920x1080 as resolutions. This seems to be the common wisdom, although is seems that some more recent car OEMs have got ultrawidescreen displays working (I think by requesting a 1080p resolution, but also blanking off top and bottom and other weird tricks) but it seems this lylink doesn't do clever things like that. It does seem to send the requested resolution and physical display size to my phone, but no matter the resolutions and screen dimensions I set in that file (and remember, that's quite a tedious process...) the displayed frame remained stubbornly small... (although if I set the physical dimensions large enough, it'll change into the 'new' widescreen layout - probably useful for this letterbox screen)

    Looking through the logs, lylink would either request a 840x480 stream (to which sdvcam would output a 'frame' of 533x320 (same aspect ratio as 840x480) - the overall screen dimensions are 1280x320, and there are GUI buttons to each side leaving 1010x320 available - the buttons take up the tapered portion of the screen, so I'm happy to leave them there) or 1280x720 (sdvcam outputs 588x320). The AAuto stream would be squashed to fit the output frame, and didn't always remain 'square' (I presume this is some interaction between the stream resolution and the apparent screen physical dimensions).

    It does look like sdvcam is responsible for setting the output frame dimensions. Perhaps I can find a way of changing the frame after it's created...

  • Exploring the filesystem

    mjc50608/30/2023 at 20:49 0 comments

    We're in!

    Honestly, that was easier than I expected :-)

    First things first, let's have a look around. We've got the flash binary, so shouldn't be able to irreversibly break anything, but better to be careful in case we can't reflash for whatever reason. I had formatted a microSD card to ext4, inserted, and tried to mount it to a directory (a handy existing directory /mnt/extsd/) but I got errors. Huh. Scrolling back through the boot messages, I see mentions for squashfs, vfat and exfat, but not ext4. No ext4 support? Reformatting the card as exFat seemed to help, as I could then mount it, and copied the entire root filesystem onto it - this allows my to look through the filesystem on the laptop while doing other stuff on the serial console - no multiuser support there...

    Next, a check on the commands available (busybox is there, the shell is ash, top, less and more and available, but no text editing binaries are present. Cat, awk and sed are there... this could be painful... Busybox is very minimal - ed is definitely not there, even the help isn't compiled in. Lucky we've got rm and cp and a microSD card...)

    top and ps show the running processes. Three interesting ones - sdvcam (killing this kills the GUI, and the device doesn't really recover without rebooting), lylink (appears to handle the wireless AAuto etc), and tc_daemon (a watchdog of sorts? killing this reboots the device after a couple of seconds).

    Boot is init.d and rc script based. rc.S10app in the init.d directory looks like it starts sdvcam, which must then start lylink - no other mention. There's mention of a /etc/flag_systemlog file which promised to trigger a script that copies various logs onto the microSD card. Be rude not to... "touch /etc/flag_systemlog" works, rebooting the device... ah, it doesn't automatically mount the microSD card while it's formatted in exFat, so I let the device reformat the disk as it likes (it offers to do so on the GUI) and try again. This results in various files dumped on the card, but are unreadable. A closer look at the 'log' script reveals that the log files are encrypted by an executable on the device... fortunately we can also decrypt using the same binary!

    The logs are quite useful, including boot messages, the output of 'free', 'ps', etc, and the sdvcam debug(!) logs. If the microSD card is left mounted, more logs are periodically stored, but encrypted again... let's sort that out.

    I copy the 'log' script across to the microSD card, mount it on my laptop, and comment out the lines that call the encryption binary. microSD card back to the device, mount, and overwrite those files... seems to succeed. The altered files survive a reboot (the overlay filesystem works!) and the log files written to the microSD card remain unencrypted. Good, that makes reading them easier, and also means we can make edits to various files (the overlayfs is only a few KB is size - plenty for config files and scripts, but not big enough for decent binaries... we'll worry about that later).

    The sdvcam logs mention some missing configuration settings (and the default values) so that means there must be some setting files somewhere. A quick look through the filesystem downloaded to the laptop finds /usr/share/res/ (mostly layout xml files for the GUI, also icons, fonts etc. Seems to use miniGUI.c) and /data/ - data contains various settings controlling the bluetooth names, wifi names and addresses, and also casting settings - Carplay, mirrorlink, HiCar and Android Auto! Included in these setting files is one labeled "andauto.fullscreen", set to 0. Changing that to '1' (copying the file to the microSD card, unmounting, mounting on the laptop, editing the file, unmounting, back to the device, remounting, rm and cp...) and rebooting...

    Partial success... the AAuto stream is now centred, and there's no camera 'frame' visible, but it doesn't take up the whole screen, leaving wide black bars left and right.

  • Finding the root password

    mjc50608/30/2023 at 20:21 0 comments

    So, how to get in...

    It's a small embedded-style device, so the possibility for there to be a non-root 'debug' account is vanishingly small. Still, even if we 'know' the account name, brute forcing the password over the serial connection through getty will be slow - about 3-4 seconds per attempt (but no 'locking' with too many attempts)... could take years...

    A more sensible option would be to look through the filesystem for clues... Of course, we can't log in (yet) and browse through, but perhaps we can download the flash... There's a 16MB (128Mbit) flash chip on the board, which is big enough for a compressed filesystem. The datasheet confirmed it was a SPI device, readable with a CH341a and an 8pin SOIC clip. I was fortunate as flashrom could download the flash successfully without having to remove the chip from the board, or even holding the reset button!

    Binwalk could read the resulting downloaded data and identified a number of different 'partitions', and various .xz compressed files. Not the simple root squashfs and overlay jffs2 partitions I'd hoped for, but... Better than nothing. Binwalk extracted everything happily. Some parts were easy to identify (the bootlogo was obvious) but the actual filesystem was a mess. Various text files all shmushed together.

    Ok, let's look for /etc/passwd and/or /etc/shadow... Grepping through the extracted files for "0:0::/root:/bin/" turned up what looked like /etc/password inside a text file (along with a load of other random files concated). Even better, the line grep found included an md5 password hash!!

    Hashcat was pressed into service and found the root password within a few minutes - "tc310".

    Back onto the serial console...

    login: root
    password: tc310
    root@tinalinux#

    Woohoo!!!

  • Talking to the device

    mjc50608/30/2023 at 19:59 0 comments

    So, step one, let's figure out how to talk to this thing. It's not running Android, but it's gotta be some form of Linux, so that means a shell somewhere, surely...

    The front of the device is taken up by the letterbox touch screen. There is a 'settings' section in the GUI, but this doesn't contain what we want.

    Left and right sides of the device are empty.

    Bottom of the device has a button (screen on/off) and there's a little microphone inside there.

    Rear of the device has a couple of 'grills' for the built in speaker and vents, a reset button (this just resets the device, no 'hold while powering on to get a shell') and the front facing camera (which can be gimballed a bit for aiming). It also has the stock 'straps' for attaching to the car rearview mirror - these can be unscrewed by removing the rubberised stickers/pads. The screws go into brass inserts in the plastic case - these will be useful for mounting properly.

    At the top of the device, we have 3.5mm aux output, microSD card slot, 2.5mm A/V in (rear camera, 4-way jack - 5V, Gnd, composite video, 12V 'reverse light detection') and a USB-C socket.

    Sticking a blank microSD card in results in the device offering to format it - partitionless fat32 with three directories - video, photos, events.

    Connecting to a laptop via a USB cable... the device boots fine, but there's no sign of any data connection to the computer. Power only :-( There must be some signalling going on, as the (included) hardwire power adapter allows the device to continue to receive power with the ignition off (parking monitor) but this is likely to be fairly basic stuff, no data being transferred across.

    Ok, next step...

    The case is clipped together quite well, no large gaps to get fingernails into, but once started unclips quite easily. There are two DSI style cables between the board and the screen (a DSI for video, and a much smaller once for the touchscreen), but everything else is mounted to the back case.

    The mainboard is pretty small, covering pretty much the whole height of the device, but about a third of the width. There is a tiny microphone at the bottom (connected by twisted pair into a removable connector), a small speaker (twisted pair, but soldered directly to the board), a small wifi antenna (perhaps also does bluetooth and FM), and that's pretty much it!

    The mainboard has a few markings in English and a couple in Chinese, but not obvious UART pins or pads.

    The rear of the mainboard has some interesting pads (a group of 8 and a group of 7, staggered), but most is covered by a metal shield.

    After a while of holding logic analyser wires against various pads, and powercycling, managed to identify a serial port on the front of the mainboard. This was the serial console, and provided boot messages, a banner (Tina Linux) and login prompt - no autologin to root... Tina Linux appears to be an Allwinner OpenWRT fork. No default passwords, and the few 'obvious' combinations (root, password, admin etc) didn't work. The board also doesn't use uboot, and there appears to be no uboot-style recovery console :-(

    Oh well. There is at least a shell there, waiting to be unlocked...

View all 7 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates