As my old chinese vacuum robot die due to bearing failure I was not sad - it was time to find sth hackable (the old one did not have any WiFi connection, thus was not very hackable). I've looked on some auctions and found Conga 5090 for 40 EUR.
Conga brand was already hacked by Congatudo community, although 5090 model was not listed as hacked yet. I have treated it as challenge, thus went to buy it. I am glad that Termux exists, so I was not looking weird to old men selling this vacuum (yeah, some ppl have weird reactions when they see terminal, especially on laptop with tiling WM).
This was not the biggest challenge of my life: robot had default SSH password, thus logging into it was easy. I am curious how many Congas are part of botnet. Nevertheless this robot used old ssh-rsa algorithm, deprecated in OpenSSH 8.8, and that was the biggest obstacle getting inside, as well as my very first contribution to Congatudo.
Later we needed to connect Conga to my IoT WiFi network. There was dedicated tool to do this, named Agnoc. As I confirmed that it worked without any issues on my Conga 5090, I have created another PR. Next step was editing /etc/hosts to cheat my conga on DNS records force it to use my LAN. WAN access is forbidden by default on my IoT network (and I am glad - my SamsungTV is flooding this VLAN with requests, for what they need that much data?)
Though the bad times happened: my robot suffers from some kind of Alzheimer disease. It forgets the map every month. I have created an issue, where the Maintainer pointed it as invalid (the robot bug), though another user wrote that he have similar issue (but not the same).
There is my journey with reverse engineering of my robot begins, but it is not finished yet. I have decided to post it on my blog, just to save it for the future, or maybe sb would help me with it.
All text below are my WIP notes, so they are a little noisy.
/mnt/UDISK/log/9886_0_20250830-194802_logfile.temp indicates:
2025/08/30,19:49:32.619333[LogFandy][LogNormal][CAppIdleState] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
2025/08/30,19:49:37.636435[LogFandy][LogNormal][CAppIdleState] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
2025/08/30,19:49:42.653939[LogFandy][LogNormal][CAppIdleState] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
2025/08/30,19:49:47.674457[LogFandy][LogNormal][CAppIdleState] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
2025/08/30,19:49:52.692091[LogFandy][LogNormal][CAppIdleState] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
Thus it seems that there is an issue to save the map, and there is high possibility that the map is simply kept on cloud.
Searching for the strings in everest-server via Radare2 after aaaa command resulted in:
strings everest-server | grep RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
[CRobotApp] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
[CAppIdleState] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
Thus I had to find exact addresses:
[0x0026f544]> izz~RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED
23460 0x008e611c 0x008e611c 61 62 ascii [CRobotApp] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED \n
23709 0x008e9608 0x008e9608 65 66 ascii [CAppIdleState] send RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED \n
And running pd -20 0x008e611c seems to confirm the issue: robot wants to save the map to the server, but cant do it, as it is not
connected to the real server, only to Congatudo:
[0x008f612d]> pd -20 0x008e611c
0x008f60dd .string "_CAppCleanState__handleUploadHistoryMapToServer__d__remind_app__d_m_clean_task_info.time_begin__d_scheme_list__d" ; len=113
0x008f6119 000000 unaligned
;-- str._CRobotApp__send_RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED_:
; DATA XREF from everest::manager::CAppCleanState::handleUploadHistoryMapToServer(everest::manager::CRobotApp*, CMsgHead*) @ 0x26f544(r)
0x008f611c .string "_CRobotApp__send_RS_EVEREST_MAPID_PUSH_HAS_WAITING_BE_SAVED_" ; len=61
0x008f6159 000000 unaligned
;-- str._CRobotApp__waiting_map_type:__d_:
; DATA XREF from everest::manager::CAppCleanState::handleUploadHistoryMapToServer(everest::manager::CRobotApp*, CMsgHead*) @ 0x26f55c(r)
0x008f615c .string "_CRobotApp__waiting_map_type:__d_" ; len=34
0x008f617e 0000 unaligned
;-- str._CRobotApp__getTestFlag_true:
; DATA XREF from everest::manager::CAppCleanState::handleUploadHistoryMapToServer(everest::manager::CRobotApp*, CMsgHead*) @ 0x26f6d8(r)
0x008f6180 .string "_CRobotApp__getTestFlag_true" ; len=29
0x008f619d 000000 unaligned
;-- str._CRobotApp__handleUploadHistoryMapToServer_map_size__d_m_save_map_id___d_:
; DATA XREF from everest::manager::CAppCleanState::handleUploadHistoryMapToServer(everest::manager::CRobotApp*, CMsgHead*) @ 0x26f654(r)
0x008f61a0 .string "_CRobotApp__handleUploadHistoryMapToServer_map_size__d_m_save_map_id___d_" ; len=74
0x008f61ea 0000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_msg_len__d__seq__lld:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fad8(r)
0x008f61ec .string "_CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_msg_len__d__seq__lld" ; len=77
0x008f6239 000000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_here_:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fb14(r)
0x008f623c .string "_CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_here_" ; len=62
0x008f627a 0000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_task_id__d:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x270430(r)
0x008f627c .string "_CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_task_id__d" ; len=67
0x008f62bf 00 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_erro__s_:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x27040c(r)
0x008f62c0 .string "_CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_erro__s_" ; len=65
0x008f6301 000000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_error__d___has_mapbindata__d:
; DATA XREFS from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fb50(r), 0x26fb74(r), 0x26fb98(r), 0x26fbbc(r)
0x008f6304 .string "_CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_error__d___has_mapbindata__d" ; len=85
0x008f6359 000000 unaligned
It runs TinaLinux - OpenWRT based distro - quite funny that my vacuum and my router runs so close related software.
# uname -a
Linux TinaLinux 3.4.39 #356 SMP PREEMPT Fri Jun 28 11:50:38 UTC 2019 armv7l GNU/Linux
It have 7 years old kernel - pretty outdated.
https://github.com/mrpt-ros-pkg/mrpt_slam
# ls /usr/lib/
libmrpt-slam.so
using strings Monitor outputs:
[%dm
Mobile Robot Programming Toolkit (MRPT)
http://www.mrpt.org/
Copyright (c) 2005-%Y, Individual contributors, see AUTHORS file
See: http://www.mrpt.org/Authors - All rights reserved.
Released under BSD License. See details in http://www.mrpt.org/License
Thus now I can be sure that the robot is using Mobile Robot Programming Toolkit
root@TinaLinux:~# netstat -plant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:5037 0.0.0.0:* LISTEN 486/adbd
tcp 0 0 0.0.0.0:8111 0.0.0.0:* LISTEN 4019/RobotApp
tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN 605/everest-server
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 444/dnsmasq
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 469/dropbear
tcp 0 0 secret:15255 secret:4030 ESTABLISHED 4019/RobotApp
tcp 0 720 secret:22 secret:21341 ESTABLISHED 1279/dropbear
tcp 0 0 secret:18472 secret:4010 ESTABLISHED 4019/RobotApp
RobotApp is connected to my Congatudo instance.
It is quite funny that it does have dnsmasq working, probably for initial configuration, when
the robot is the Access Point.
After searching for / CRL-300
I have found tons of paths like:
/home/ziven/work/CRL-300/otherlibs/carto.
Now I know that Ziven wrote at least part of my robot's firmware.
Thus there is high probability that it is similar to 3irobotix CRL300S, and it looks like 3irobotix CRL-300S
During research on the internet I have found a repo where Harishankar did reverse engineering to 3irobotix CRL-200S. He also wrote an article about his robot was bricked.
Nevertheless, he wrote that AuxCtrl is an program to control the whole robot. I also have AuxCtrl on my robot, thus at least I know for sure that AuxCtrl
is responsible for controlling the robot.
Moreover it seems that his robot is very close to mine
Monitor (/usr/sbin/Monitor) - Main supervisor process RobotApp (/usr/sbin/RobotApp) - Main robot control application AuxCtrl (/usr/sbin/AuxCtrl) - Auxiliary control process everest-server (/usr/sbin/everest-server) - Server component log-server (/usr/sbin/log-server) - Logging service
All processes are forked by Monitor and run continuously. The Monitor binary checks for both debug_mode and PowerOn files during operation.
It is generally the same architecture that I do have, thus I can learn from his experiences.
I have found these binary/ELF files on my Conga 5090
-rwxr-xr-x 1 10315693 Aug 27 16:19 everest-server
-rwxr-xr-x 1 4631677 Jun 25 19:33 RobotApp
-rwxrwxr-x 1 3356824 Jun 25 19:10 uImage
-rwxr-xr-x 1 607451 Jun 25 19:32 Monitor
-rwxr-xr-x 1 12441 Jun 25 19:08 init
-rwxrwxr-x 1 512 Jun 25 19:09 magic.bin
everest-server seems to be the biggest, thus main app of the vacuum
funny thing - it has gdb-server preinstalled
I am looking for info when the map gets resetted
Radare2 found [CRobotApp] handleUploadHistoryMapToServer map size %d m_save_map_id %d in everest-server, and
[CManagerMap] device_ctrl_save_map. was in the RobotApp
strings * | grep -ni save_map
22023:[CRobotApp] handleUploadHistoryMapToServer map size %d m_save_map_id %d
57114:[CManagerMap] device_ctrl_save_map.
Radare2 showed save_map string @ 0x008f61d9
> / save_map
0x008f61d9 hit0_0 .r map size %d m_save_map_id %d [CApp.
> pd -10
0x008f61b1 .string "[CRobotApp] handleUploadHistoryMapToServer map size %d m_save_map_id %d \n" ; len=74
0x008f61ea 0000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_msg_len__d__seq__lld:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fad8(r)
0x008f61ec .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp msg len %d! seq %lld\n" ; len=77
0x008f6239 000000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_here_:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fb14(r)
0x008f623c .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp here!\n" ; len=62
0x008f627a 0000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_task_id__d:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x270430(r)
0x008f627c .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp task_id %d\n" ; len=67
0x008f62bf 00 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_erro__s_:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x27040c(r)
0x008f62c0 .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp erro %s!\n" ; len=65
0x008f6301 000000 unaligned
> pd 10
;-- hit0_0:
0x008f61d9 .string "[CRobotApp] handleUploadHistoryMapToServer map size %d m_save_map_id %d \n" ; len=74
0x008f61ea 0000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_msg_len__d__seq__lld:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fad8(r)
0x008f61ec .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp msg len %d! seq %lld\n" ; len=77
0x008f6239 000000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_here_:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fb14(r)
0x008f623c .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp here!\n" ; len=62
0x008f627a 0000 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_task_id__d:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x270430(r)
0x008f627c .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp task_id %d\n" ; len=67
0x008f62bf 00 unaligned
;-- str._CAppCleanState__handleMapIDDownloadServerHistoryMapRsp_erro__s_:
; DATA XREF from everest::manager::CAppCleanState::handleMapIDDownloadServerHistoryMapRsp(everest::manager::CRobotApp*, CMsgHead*) @ 0x27040c(r)
0x008f62c0 .string "[CAppCleanState] handleMapIDDownloadServerHistoryMapRsp erro %s!\n" ; len=65
0x008f6301 000000 unaligned
(everest::manager::CRobotApp*, CMsgHead*) @ 0x26fad8(r) shows us that probably CRobotApp is responsible for managing the map, which actually makes sense
/ save_map shows 0x0042b48a hit4_0 .ap] device_ctrl_save_map.[CManagerM.
`
so seeking that address shows everest::manager::CManagerMap::handleMessage function
[0x00235664]> s 0x0042b48a
[0x0042b48a]> pd -10
0x0042b462 .string "[CManagerMap] handle clean task report add.\n" ; len=44
│ 0x0042b46c 00000000 andeq r0, r0, r0
│ ;-- str._CManagerMap__device_ctrl_save_map.:
│ ; DATA XREF from everest::manager::CManagerMap::handleMessage(CMsgHead const&) @ 0x2355d8(r)
│ 0x0042b470 .string "[CManagerMap] device_ctrl_save_map.\n" ; len=36
│ 0x0042b494 00000000 andeq r0, r0, r0
│ ;-- str._CManagerMap__handleMessages_failed__d_:
To be continued!