Close
0%
0%

Shark Robot Vacuum Reverse Engineering

Reverse engineering the Shark RV1001AED series Robot Vacuum

Public Chat
Similar projects worth following
An ongoing project to reverse engineer the Shark RV1001 hardware and firmware to implement custom functionality, and provisioning on a private network.

I want to add my own functionality to a robot vacuum, and also provision it on my own network.

proto - 2.48 kB - 06/30/2022 at 16:55

Download

proto - 2.65 kB - 06/30/2022 at 16:55

Download

proto - 695.00 bytes - 06/30/2022 at 16:55

Download

proto - 866.00 bytes - 06/30/2022 at 16:55

Download

proto - 3.03 kB - 06/30/2022 at 16:55

Download

View all 17 files

  • 3 × SparkFun FTDI basic USB to UART adapter capable of 1500000 baud
  • 1 × Dupont single row connector kit 2.54mm pitch (0.1")
  • 1 × JST-XH single row connector kit 2.54mm pitch (0.1")
  • 1 × Hirose DF11-12DEP-2C Dual row 12 position rectangular connector housing
  • 12 × Hirose DF11-EP2428PC crimp 24-28awg pin

View all 6 components

  • Protobuf goodness!

    Jon Steel5 hours ago 0 comments

    In playing around with the Shark Clean App version 2.5.35 for android, I found that they left the  *.proto files in the resources directory. I have already verified that some of the base64 MQTT messages I captured in the system log translate accurately. 

    I do have a large number of messages that are only partial, and I have yet to figure out the method to identify the message type.

  • In case of trouble, call strace

    Jon Steel06/14/2022 at 05:58 0 comments

    Using Ghidra to look over the files of the OEM partition, it seems the Roboeye_server application is central to the Visual and Odometry navigation. Data from the RVC_Base is piped in to Roboeye through /dev/ttyS0. Trying to use a USB to serial adapter connected to the traces on the RVC_Base that I anticipate are the same as ttyS0, I was met with unformatted junk that seemed to have string contained within that also would escape the terminal. Oddly enough, there was occasionally legible ascii string.

    Trying to figure out how I can make sense out of that mess, I stumbled across strace, and how to use it to parse serial data within an application.

    The information that I collected was inspiring! The problem I have is that I have only the mainboard for this robot vacuum, and the robot vacuum I do have has fewer sensors than what the new board uses. 

    This seems to be causing the board to enter an error state soon after boot that just ends up being a loop.

    So I have on the way an appropriate fully functional robot of the correct model to experiment further.

    Here is a sample of the output from the strace

    read(4,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\0\0
    \0\0\0\0\0\0\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0\0OFSIniErr\0\0\24\0~\320\0\0\252U\r\362\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0", 265) = 265
    read(4, "###########################\346\255\244\346\226\207\344\273\266\345
    \217\252\350\257\273\344\270\215\345\217\257\346\224\271
    ######################################\n
    \n
    ###############################################################################\n
    # Debug Configurations\n
    ###############################################################################\n
    \n
    ## LOG 
    \350\256\260\345\275\225\344\275\215\347\275\256\357\274\214\351\273\230\350
    \256\244 
    /tmp/   /mnt/udisk/ /mnt/sdcard/\nlog_file_prefix = /tmp/\n
    \n
    ## LOG level # DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3, FATAL = 4\n
    log_level = 0\n
    \n
    ## LOG line constrain , <= 0 - no constrain\n
    log_size_constrain = 50000\n
    \n
    ## \350\260\203\350\257\225\345\264\251\346\272\203\346\214\202\350\265\267\n
    enable_backtrace = true\n
    \n
    ## 
    \345\274\272\345\210\266\351\207\215\345\206\231\347\211\210\346\234\254\345
    \217\267\357\274\214\346\255\243\345\274\217\345\205\263\351\227\255,\350\260
    \203\350\257\225\345\274\200\345\220\257\n
    #version = 3.6.0\n
    \n
    ## webSocket 9003\345\217\221\351\200\201\346\227\245\345\277\227 \351\227\264\351\232\2241\347\247\222\n
    enableLogWebsocekt = true\n
    ##
    \n
    \n
    ###############################################################################\n
    # DataSender Configurations\n
    # data_sender_trans_img_scheme: 'ALL':trans all key frame, 'EVERY2PIC', 'EVERY4PIC', 8 16 also ok
    \n
    # data_sender_buffer_size_mb: can be 1 2 4 8 16 32 64\n
    ###########################################################", 1024) = 1024
    read(4, "####################\n
    \n
    ## \345\205\250\345\261\200\344\275\277\350\203\275 DataSender\n
    use_data_sender             = true\n
    ## \344\275\277\347\224\250DataSender\346\234\254\345\234\260\350\256\260\345\275\225\345\212\237\350\203\275 
    true: \346\234\254\345\234\260\350\256\260\345\275\225\357\274\214false\357\274\232\345\261\200\345\237\237
    \347\275\221\344\274\240\350\276\223\n
    data_sender_local_mode      = false\n
    ## \346\234\254\345\234\260\345\255\230\345\202\250\350\267\257\345\276\204\n
    data_sender_local_path      = /tmp/oem/data/data_all.pak\n
    \n
    data_sender_host_ip         =  192.168.1.100\n
    data_sender_host_port       = 7000\n
    data_sender_buffer_size_mb  = 8\n
    data_sender_trans_img_scheme = EVERY16PIC\n
    data_sender_trans_log       = true\n
    data_sender_trans_rvc       = true\n
    data_sender_trans_img       = true\n
    data_sender_trans_imu...
    Read more »

  • Forget you ADB! Hi GDB!

    Jon Steel06/09/2022 at 16:10 0 comments

    After wasting too much time with ADB, I decided to move on. Next on the list is to use GDB and Ghidra to RE some of the applications. The main application I am interested in is the RoboEyeServer. Initial analysis shows this is where all of the VSLAM calculations are done, and the RVC_Base inputs are polled. 

    This will be a fun weekend!

  • Pulling My hair out!

    Jon Steel06/05/2022 at 07:29 0 comments

    So a problem I have had for some time is getting ADB to work.

    I have it setup in init.d for ADB to work, and I can run ADB on my computer to see the device SN, but it says UNAUTHORIZED.

    I have tried all I can think of as for the common issues with ADB giving an Unauthorized.

    The main culprit I think it there is no mechanism on the Robot to accept the ADB connection request like you would with a phone or tablet.

    I can't find anything in the ADC keys or GPIO keys in relation to ADB, but then again I can't find anything about the ADC key I found to get into recovery mode...

    Any suggestions?

  • Custom Sounds! Woot!

    Jon Steel06/04/2022 at 06:40 0 comments

    Wow, this was a quick one! Other than a simple check, there are no major blocks to changing the default sounds.

    As of right now, a custom sound has to replace an existing sound, and take its name. In my example I replaced s01_ power_on.mp3 with my own mono mp3. I hade to mount the userdata partition in the tmp directory, and replace the desired mp3 in the /tmp/userdata/music directory. 

    It also seemed that I needed to replace the same file in /mnt/udisk/music directory, or else I had issues where it would grab the original, or not play at all.

    Here is a video example:


  • SSH Fun!

    Jon Steel06/03/2022 at 14:17 0 comments

    Finally got SSH working, and it was fun!!!

    Once the sshd config, and ssh starting script in init.d were modified I tried starting sshd. I was presented with a notification that /var/empty must be owned by root, and cannot be group or world writable.

    checking permissions with ls -lah, it seems that nearly every directory is owned by sshd..... I certainly did not do that.

    With the unsquashed fs I  did chown root:root on the /var/empty directory, then squashed and flashed.

    Made some progress, but despite the config files, sshd does not want to point to the host keys.... I broke that I bet. Simply grab host keys and put them where sshd thinks they should be... okay, oh wait, the pub keys are in an  invalid format?

    Using ssh-keygen I created a new keypair, and saved them to the /tmp directory. Manually copied them from the terminal, and added them to the squashfs image, and flashed. Looking at the pub key I generated, it is much longer than the key that was already in the robot.

    Ok, SSH to the robot.... YAY!  Now I can easily move files around in the R/W directories, and no more serial cables... the robot is now free of its umbilical!

    Next will be playing with the mp3 sound bank... I think it should be pretty easy.

    Then I will look at some of the applications in the /res directory... it looks interesting!

    Yeah, sorry, I know I don't have any screen shots... I was in the zone.

  • An Interesting find

    Jon Steel06/01/2022 at 15:05 0 comments

    When looking around the OEM partition, I found an interesting file. I completely forgot where the file was located, and what it was called, but it contained a link to an Amazon AWS bucket for shark. The link was for a zipped compressed upgrade firmware. I posted the FW here on my github as a multi-part RAR.


    This makes things much easier as this is the firmware as a proper update for all parts.

    The update.img can be unpacked with the RKDevtool or the imgRepackerRK from RedScorpion on XDA Dev forums. The imgRepackerRK is a great option, but must use the option to not checkchip id. When the image in unpacked with this tool, it creates some config files for repacking the image.

    Do not unsquash the rootfs.img on a Windows machine as it breaks the symlinks.

    Make the changes in a unix compatible text editor, run a mksquashfs, repack with imgRepackerRK. 

    Use RKDevtool to load the update.img with the upgrade tab, and upgrade.

    It seems all checks are only done when doing an OTA update, and nothing I have seen is checked at boot time.

  • WE GOT ROOT!

    Jon Steel05/30/2022 at 09:48 0 comments

    Well I decided to play some risky biscuits, and  reading up on rockchip documentation I found I can do an upgrade without over writing the entire firmware... Grabbed all the rootfs files, modified passwd and shadow to add my own root user... used the Rkdevtool to upgrade, and all was good!

    Did a wget spider to see what it would do...

    [root@rk3326_robot64:/]# wget --spider -S http://www.hackaday.io
    Connecting to www.hackaday.io (198.54.96.98:80)
      HTTP/1.1 301 Moved Permanently
      Date: Mon, 30 May 2022 09:41:54 GMT
      Content-Type: text/html
      Content-Length: 178
      Connection: close
      Location: http://hackaday.io/
    Connecting to hackaday.io (198.54.96.130:80)
      HTTP/1.1 301 Moved Permanently
      Content-length: 0
      Location: https://hackaday.io/
    Connecting to hackaday.io (198.54.96.130:443)
    wget: TLS error from peer (alert code 40): handshake failure
    wget: error getting response: Connection reset by peer

    next job is to get ssh working, and then I can update the lame voice packs. 

  • Shadow Boxing

    Jon Steel05/30/2022 at 05:57 0 comments

    So I got in 2 more sample for a total of 3.

    I have all 3 with the emmc dump up to the 32Mb mark due to the loader limitation. 

    I can also mount the oem and rootfs partitions to play around.

    I copied the shadow file from /etc , and two of them have the same hashed password.

    ImageType: 1
    root:$1$8BiNnKgf$.pPHAXF9DfcGAIHku3PTT.:10933:0:99999:7:::
    	#1 SMP PREEMPT Tue Jul 7 17:42:53 CST 2020
    	
    ImageType: 2
    root:$1$xXxyYETk$/HJDhqXC6k/MtR0ayrM6K1:10933:0:99999:7:::
    	#1 SMP PREEMPT Mon Sep 7 14:58:09 CST 2020

    The ImageType 2 is where I have the shared password hash. Comparing the two, they are identical until the root file system. Since I can't dump the rootfs easily yet, I had to manually compare. It was quickly evident that the rootfs saw some differences.

    Trying to crack the hashes has not worked out.... I am guessing that the password is derived from a hash of the kernel, in the area of the dump past the 32Mb limit, or some other method. 

  • Getting to know your Robot Vacuum

    Jon Steel05/24/2022 at 19:04 0 comments

    STEP1: Communication, sprechen sie beep boop?

    So a great place to start with almost any reverse engineering project is finding the UARTS. 

    One difference with the L02 PCB vs the L01 is the lack of silk screen information besides some model info text.

    Lucky for us, the UART test pads stick out like poorly hidden UART test pads. Three test pads in a row with no other pads around, and one of the pads is tied to ground. 

    Solder on some test leads, connect to USB/UART adapter. Set serial port to 1500000,8,N,1 

    Pull the lever Kronk!

    DDR V1.14 20190925
    D3,512MB,333MHz
    bw	col	bk	row	cs	dbw
    32	10	8	14	1	16
    OUT
    Boot1 Release Time: Sep 24 2019 13:27:46, version: 1.20
    chip_id:524b3326_0,0
    ChipType = 0x12, 460
    mmc2:cmd19,100
    SdmmcInit=2 0
    BootCapSize=1000
    UserCapSize=3776MB
    FwPartOffset=2000 , 1000
    SdmmcInit=0 NOT PRESENT
    StorageInit ok = 27271
    SecureMode = 0
    Secure read PBA: 0x4
    Secure read PBA: 0x404
    Secure read PBA: 0x804
    Secure read PBA: 0xc04
    Secure read PBA: 0x1004
    SecureInit ret = 0, SecureMode = 0
    atags_set_bootdev: ret:(0)
    GPT part:  0, name:            uboot, start:0x4000, size:0x2000
    GPT part:  1, name:            trust, start:0x6000, size:0x2000
    GPT part:  2, name:             misc, start:0x8000, size:0x2000
    GPT part:  3, name:             boot, start:0xa000, size:0x10000
    GPT part:  4, name:         recovery, start:0x1a000, size:0x10000
    GPT part:  5, name:           backup, start:0x2a000, size:0x10000
    GPT part:  6, name:              oem, start:0x3a000, size:0x3c000
    GPT part:  7, name:           rootfs, start:0x76000, size:0x200000
    GPT part:  8, name:              sys, start:0x276000, size:0x5000
    GPT part:  9, name:         userdata, start:0x27b000, size:0x4e4fdf
    find part:uboot OK. first_lba:0x4000.
    find part:trust OK. first_lba:0x6000.
    LoadTrust Addr:0x6000
    No find bl30.bin
    No find bl32.bin
    Load uboot, ReadLba = 4000
    Load OK, addr=0x200000, size=0xcafd4
    RunBL31 0x40000 @ 74562 us
    INFO:    Preloader serial: 2
    NOTICE:  BL31: v1.3(debug):ca3dd02
    NOTICE:  BL31: Built : 10:15:38, Sep 23 2019
    NOTICE:  BL31:Rockchip release version: v1.0
    INFO:    ARM GICv2 driver initialized
    INFO:    Using opteed sec cpu_context!
    INFO:    boot cpu mask: 1
    INFO:    plat_rockchip_pmu_init: pd status f00e
    INFO:    BL31: Initializing runtime services
    WARNING: No OPTEE provided by BL2 boot loader, Booting device without OPTEE initialization. SMC`s destined for OPTEE will return SMC_UNK
    ERROR:   Error initializing runtime service opteed_fast
    INFO:    BL31: Preparing for EL3 exit to normal world
    INFO:    Entry point address = 0x200000
    INFO:    SPSR = 0x3c9
    
    
    U-Boot 2017.09 (Jul 07 2020 - 18:40:52 +0800)
    
    Model: Rockchip RK3326 EVB
    PreSerial: 2
    DRAM:  510 MiB
    Sysmem: init
    Relocation Offset is: 1dbef000
    Using default environment
    
    dwmmc@ff370000: 1, dwmmc@ff390000: 0
    Bootdev(atags): mmc 0
    MMC0: High Speed, 52Mhz
    PartType: EFI
    boot mode: None
    Load FDT from boot part
    DTB: rk-kernel.dtb
    I2c speed: 400000Hz
    PMIC:  RK8090 (on=0x40, off=0x00)
    vdd_logic 1100000 uV
    vdd_arm 1100000 uV
    Model: Rockchip rk3326 evb lpddr3 v10 board for robot linux
    CLK: (sync kernel. arm: enter 600000 KHz, init 600000 KHz, kernel 600000 KHz)
      apll 600000 KHz
      dpll 664000 KHz
      cpll 24000 KHz
      npll 1188000 KHz
      gpll 1200000 KHz
      aclk_bus 200000 KHz
      hclk_bus 150000 KHz
      pclk_bus 100000 KHz
      aclk_peri 200000 KHz
      hclk_peri 150000 KHz
      pclk_pmu 100000 KHz
    Net:   Net Initialization Skipped
    No ethernet found.
    Hit key to stop autoboot('CTRL+C'):  0 
    ANDROID: reboot reason: "(none)"
    Fdt Ramdisk skip relocation
    Booting LZ4 kernel at 0x03e80000(Uncompress to 0x00280000) with fdt at 0x8300000...
    
    
    ## Booting Android Image at 0x03e7f800 ...
    Kernel load addr 0x00280000 size 4179 KiB
    ## Flattened Device Tree blob at 08300000
       Booting using the fdt blob at 0x8300000
       Uncompressing Kernel Image ... OK
      'reserved-memory' ramoops@00000000: addr=8000000 size=a0000
       Using Device Tree in place at 0000000008300000, end 0000000008317ef7
    Adding bank: 0x00200000 - 0x20000000 (size: 0x1fe00000)
    Total: 391.595 ms
    
    Starting kernel ...
    
    [    0.000000] Booting Linux on physical CPU 0x0
    [    0.000000] Initializing cgroup subsys cpuset
    [ 0.000000] Initializing cgroup subsys...
    Read more »

View all 11 project logs

Enjoy this project?

Share

Discussions

Jon Steel wrote 06/05/2022 at 20:17 point

Well, that's why I am a proponent for open, self provisioned IOT/Smart Devices.

  Are you sure? yes | no

dearuserhron wrote 06/05/2022 at 18:20 point

Those vacuum cleaners are about to takeover the planet. They got ssh, they got cameras, actuators and more. Maybe it is possible to mess with charging control to let battery overheat and explode.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

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