RobomasterS1をハックしたい ①ルート化とファイル構成確認


# 概要

何をしたか

- Robomasters1をPCとのUSB接続し，adbを使ってルートにアクセスする。
- 中身のファイル構成を覗いてみた


何ができるか？

- わからない…（情弱）
- コマンドライン上でPython環境を制限なしで走らせられる（アプリ経由すると使えないライブラリがある）

何がしたいか？

- 下記参照

## 本記事の最終目的

- RobomasterS1へPCから司令を送ったり，画像やセンサデータを収集したい [参考：Ishikawa氏の記事](https://qiita.com/tatsuyai713/items/aa338d6b07af11bde88a)
- 有志の[デモ](https://forum.dji.com/forum.php?mod=viewthread&tid=219160)のようにRobomasterの画像をPCで処理して制御信号を送るといったことに使いたい。

ボールトラッキングのデモ動画を以下に添付します。こういうのをやりたいです。

[![こういうのをやりたい](http://img.youtube.com/vi/KSxQl7B45UA/0.jpg)](http://www.youtube.com/watch?v=KSxQl7B45UA)

## 方針
RobomasterS1の後継となるEPという機種があり，そちらは今言ったようなことができます。SDKも配布されています。（Documentは[こちら](https://robomaster-dev.readthedocs.io/zh_CN/latest/sdk/connection.html)）

https://github.com/dji-sdk/RoboMaster-SDK/tree/master/sample_code

この件に詳しいBruno氏に寄ればこのSDKでは本来S1のサポートはしていませんが，構成が似通っているため上手くやると流用できるとのことです。

参照：

- [Bruno氏のリポジトリ](https://github.com/brunoga/robomaster)
- [Bruno氏のDJIForum](https://forum.dji.com/home.php?mod=space&uid=2633017&uuid=acd7745041d1ff)



## 実際にやったこと
ひとまず，rootアクセスが必要そうなので

- [ここのDiscussionを参考に](https://forum.dji.com/thread-212767-1-1.html)rootアクセスを行う。
- Systemの中身を覗いてみる


# Windows10 PC からadbを用いてrootアクセスする

Windows10 HomeのPCからmicroUSBコネクタを用いてRobomasters1に接続します。

[ここのPDF](https://forum.dji.com/forum.php?mod=attachment&aid=MTYwMDA5fDE3Yjc2YmE5fDE1OTcyMTcyODJ8MzM3Njg3M3wyMTI3Njc%3D)をもとに進めていきますが，注意として**ファームウェアが新しいとroot化できないなどの報告があるのでアップデートはしないこと**が挙げられます。

## 前準備
以下のものを準備します。

- PC，microUSB変換ケーブル
- [Android SDK Platform Tools](https://developer.android.com/studio/releases/platform-tools)

Platform Toolsは解凍してフォルダの場所を記憶しておきます。PCとRobomasters1を接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188863/7da3ad54-0882-360c-dad8-e1a8baf5b39e.png)

**次の工程に行く前にPCに接続されているAndroid機器を取り外しておいてください。**

## PCとRobomasters1の接続

1. Robomasters1の電源を入れ，PC側もソフトを起動して接続します。（自分はWifi接続）

2. 「ラボ」→「DIYプログラミング」からPythonスクリプトを書くページに行きます。

3. 新規作成で下記のコードをコピペし，実行します。（adbを有効化するshを叩いているっぽい）

```python
def root_me(module):
 __import__=rm_log.__dict__['__builtins__']['__import__']
 return __import__(module,globals(),locals(),[],0)
builtins=root_me('builtins')
subprocess=root_me('subprocess')
proc=subprocess.Popen('/system/bin/adb_en.sh',shell=True,executable='/system/bin/sh',stdout=subprocess.PIPE,stderr=subprocess.PIPE)
```

## adbを用いた接続

次に先程解凍した，Platform Toolsのフォルダ（adbが実行可能なフォルダ）に行き，Powershellを起動します。（Linuxの人はTerminal）

```
.\adb.exe devices
```

を実行した後に，

```
.\adb.exe shell
```

を実行します。
上手く行けば以下のようにrootでは入れているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188863/30424446-ef99-4be0-4143-dafc9088c2c5.png)



# 次にやること（多分）

- ~~なんとかしてRobomasters1側の`ConnectionRefusedError: [WinError 10061]`を解除してSDKのサンプルプログラムを試す~~
- どうやらRobomaster s1 にはSDKのトリガーとなるソケットのポートが開かれていないのでEPからファイルをコピーしてくる必要がある…EPも買うお金はない…

追記：[ここのやり取り](https://github.com/dji-sdk/RoboMaster-SDK/issues/10)を見るに，Robomaster EPからファイルをコピーする必要があるようで自分の手持ちでは実現できなそう…となっています。


## 説明

2020年8月12日現在のSDKを見た感じでは，Robomasters1のアドレスの特定のポートに信号を送ることでSDKモードを有効にし，様々な司令を出しているようです。

例えば，SDKを有効にして各種命令をPCから実行するテストファイルではソケット通信で40923ポートに信号を投げています。


<details><summary>SDKサンプルコード</summary><div>

```python
# -*- encoding: utf-8 -*-
# 测试环境: Python 3.6 版本

import socket
import sys

# 直连模式下，机器人默认 IP 地址为 192.168.2.1, 控制命令端口号为 40923
host = "192.168.100.111"
port = 40923

def main():

        address = (host, int(port))

        # 与机器人控制命令端口建立 TCP 连接
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        print("Connecting...")

        s.connect(address)

        print("Connected!")

        while True:

                # 等待用户输入控制指令
                msg = input(">>> please input SDK cmd: ")

                # 当用户输入 Q 或 q 时，退出当前程序
                if msg.upper() == 'Q':
                        break

                # 添加结束符
                msg += ';'

                # 发送控制命令给机器人
                s.send(msg.encode('utf-8'))

                try:
                        # 等待机器人返回执行结果
                        buf = s.recv(1024)

                        print(buf.decode('utf-8'))
                except socket.error as e:
                        print("Error receiving :", e)
                        sys.exit(1)
                if not len(buf):
                        break

        # 关闭端口连接
        s.shutdown(socket.SHUT_WR)
        s.close()

if __name__ == '__main__':
        main()
```

</div></details>



しかし，Client側からConnectする際に以下のようにエラーを出されてしまいます。

```
ConnectionRefusedError: [WinError 10061] 対象のコンピューターによって拒否されたため、接続できませんでした。
```

hostsか何か編集したり，Permissionをいじるとかが必要なのでしょうか？ちょっと調べている所です。（詳しい方に教わりたい。）

追記：試した所どうやら，EPには開かれているPortが，S1では開かれていないというのが問題のようです。


根拠として下記のサーバをRobomaster s1 で立ち上げてPCから接続できることを確認したためです。

```python
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(("192.168.100.111", 1235))
s.listen(5)

timeout=60## run 60 sec
s.settimeout(timeout)

while True: 
    clientsocket, address = s.accept()
    print(f"Connection from {address} has been established!")
    clientsocket.send(bytes("Welcome to the server!", 'utf-8'))
    clientsocket.close()

print("Exit!")
```

# 補足：中身を探索する

自分はLinuxもこういったHackもズブの素人なので中身を覗いて理解するのも一苦労でした。一応記録までに載せておきます。

## システム情報

一応Linuxシステムではあるようです。

```
$ cat /proc/version
```

```
Linux version 3.10.62 (jenkins@APServer01) (gcc version 4.7 (GCC) ) #1 SMP PREEMPT Tue Jul 16 04:08:11 CST 2019
```

## `/`直下

なんもわからんのでこれを見てもって感じですが一応メモしておきます。

<details><summary>クリックして展開</summary><div>

```
amt
blackbox
cache
data
default.prop
dev
etc
file_contexts
ftp
init
init.environ.rc
init.lc1860.3connective.rc
init.rc
init.trace.rc
init.usb.rc
proc
property_contexts
root
sbin
sdcard
seapp_contexts
sepolicy
sys
system
system.md5
tmp
ueventd.rc
var
vendor
```
</div></details>


## Python環境

`data/python_flies`の中にPythonのフォルダがあります。

binの中身は以下の通り，

```
2to3
idle
pydoc
python
python-config
python3.6m
pyvenv
```

実際に実行もできます。環境は3.6のようです。

```
126|root@xw607_dz_ap0002_v4:/data/python_files/bin # ./python
Python 3.6.6 (default, Jul 16 2018, 17:22:20)
[GCC 4.8.3 20140320 (prerelease)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
```

robomasterのアプリとの違いは，特定のパッケージが使えることです。


例えば，アプリで作成したコードでは**socketなどはimportした時点でエラーとして弾かれるのに対してrootのコマンドライン実行では普通に実行できます。**



viなどのエディタがあればいいのですが，`ls /system/bin`の出力を見る限りエディタはないのでファイル転送などをする必要がありそうです。

アプリで作成したファイルがどこにあるかがわかればroot上である程度操作ができそうですね。


## devの中身

ttyとかは省略。video0とかはありますね。

<details><summary>クリックして展開</summary><div>

```
alarm
android_adb
apple_roleswitch
applecp
ashmem
binder
block
bulk_usb
bus
comip-snd-lowpower
comip-ureg
console
cpu_dma_latency
cuse
full
fuse
graphics
hx170dec
hx280enc
hx280enc_h1
i2c-0
i2c-1
i2c-3
i2c-4
input
ion
kmsg
lcmem
log
loop-control
mem
modem
mtp_usb
network_latency
network_throughput
null
on2map
on2psm
ptmx
pts
random
rtc0
sdpr
sdps
snd
socket
spidev0.0
spidev1.0
spidev2.0
uio0
uio1
uio2
urandom
vcs
vcs1
vcsa
vcsa1
video0
zero
```
</div></details>