このプロジェクトでは、GE WiFi に接続されたスマート電球を制御するための「C by GE」アプリをリバース エンジニアリングしました。これを行うために、まず Android アプリを逆コンパイルし、次にアプリがサーバーと通信するために使用するバイナリ プロトコルをリバース エンジニアリングしました。詳細については、「GE によるリバース エンジニアリング C」を参照してください。
このプロジェクトの最終製品は次のとおりです。
免責事項:このコードはリバース エンジニアリングの結果であり、プロトコル仕様によるものではありません。そのため、引き続き動作するという保証や、すべてのネットワークやスマート デバイスで動作するという保証はありません。他の人はこの API をうまく使用している場合もありますが、コードがあらゆるユースケースに当てはまらない誤った仮定を立てている可能性があります。
サーバー ディレクトリは、C by GE 電球用の自己完結型 Web アプリおよび JSON API エンドポイントです。 Web サイトは次のようになります。
-email
および-password
引数を指定して Web サイトを実行すると、Web サイトを初めてロードするときに 2 要素認証ページが表示されます。ボタンを押して、電子メールに送信された確認コードを入力します。あるいは、アカウント情報に-email
フラグと-password
フラグを設定して login_2fa コマンドを実行することで、事前にログインすることもできます。このコマンドにより、2FA 確認コードの入力が求められます。このコードを入力すると、コマンドはセッション情報を JSON BLOB として吐き出します。次に、この JSON をサーバーの-sessinfo
引数に、たとえば-sessinfo 'JSON HERE'
として渡すことができます。セッションの一部は 1 週間後に期限切れになりますが、セッションの期限切れ部分はデバイスの列挙に 1 回だけ使用されるため、実行中のサーバー インスタンスはこの後も動作し続けることに注意してください。
新しいアカウントでは 2 要素認証を使用する必要があります。次のように 2FA ハンドシェイクを実行してセッションを作成できます。
callback , err := cbyge . Login2FA ( "my_email" , "my_password" , "" )
// Handle error...
sessionInfo , err := callback ( "2FA code from email" )
// Handle error...
session , err := cbyge . NewController ( sessionInfo , 0 )
// Handle error...
これまで 2FA を使用したことがない古いアカウントの場合は、直接ログインできる場合があります。
session , err := cbyge . NewControllerLogin ( "my_email" , "my_password" )
// Handle error...
セッションを確立したら、次のようにデバイスを列挙できます。
devs , err := session . Devices ()
// Handle error...
for _ , x := range devs {
fmt . Println ( x . Name ())
}
次のように電球を制御できます。
x := devs [ 0 ]
session . SetDeviceStatus ( x , true ) // turn on
session . SetDeviceLum ( x , 50 ) // set brightness
session . SetDeviceCT ( x , 100 ) // set color tone (100=blue, 0=orange)
電球の現在の設定をクエリすることもできます。
status , err := session . DeviceStatus ( x )
// Handle error...
fmt . Println ( status . IsOn )
fmt . Println ( status . ColorTone )
このセクションでは、C by GE プロトコルの一部をリバース エンジニアリングした方法について説明します。
最初のステップは、Apktool を使用して Android アプリを逆アセンブルすることでした。これにより、アプリの Smali 逆アセンブリが生成されます。あちこち探し回って、URL とドメイン名を検索しました。最初に、私はこれを見つけました:
.field public static final API_VERSION : L java/lang/String ; = " v2/ "
.field public static final BASE_URL : L java/lang/String ; = " https://api-ge.xlink.cn:443/ "
この API エンドポイントがどこで使用されているかを確認すると、ログインやデバイスの一覧表示などのための一連の JSON ベースの HTTP 呼び出しがすぐに見つかりました。ただし、このエンドポイントは、1) デバイスのステータスを取得する方法、または2) デバイスの色または明るさを更新します。
アプリがスマート電球と通信するには、他の方法が必要でした。ただし、逆アセンブリには Bluetooth と LAN 通信用のコードが大量に含まれており、電球を制御するためのグローバル API エンドポイントがないのではないかと少し心配しました。さらに悪いことに、Bluetooth をオフにしてから使用しようとすると、C by GE アプリから苦情が発生しました。しかし、最終的には、アプリを開いてその動作に任せ、電球を制御したまま Bluetooth と WiFi をオフにできることがわかりました。アプリが「位置追跡をオンにする」(Bluetooth と WiFi の奇妙な名前です) を求めるポップアップが開くたびに、Android の「戻る」ボタンを押すだけでした。
この時点で、私はアプリが他の謎の HTTP(S) 接続を確立していないとかなり確信していました。しかし興味深いことに、Smali コードの別の場所でドメイン「xlink.cn」を見つけました。
.field public static final CM_SERVER_ADDRESS : L java/lang/String ; = " cm-ge.xlink.cn "
.field public static final CM_SERVER_PORT : I = 0x5ce2
なんと、これは生のソケットベースのプロトコルでしょうか?試してみたところ、確かにcm-ge.xlink.cn:23778
への TCP 接続を開くことができました。ただし、Smali にはUDPパケットのロジックも多かったので、アプリがどのプロトコルを使用するのかわかりませんでした。これを念頭に置いて、パケットプロキシを作成し、ポート 23778 でリッスンするように設定しました。次に、Smali コード内のドメインcm-ge.xlink.cn
を自分の IP アドレスに置き換え、アプリを APK に再コンパイルして、次の場所にインストールしました。私の電話。
案の定、パッチを適用した C by GE アプリはすぐにパケット プロキシ インスタンスに接続し、チャットを開始しました。特に、これは Bluetooth と WiFi がオフの場合にのみ行われました。それ以外の場合は、スマート電球とローカルで通信するためにこれらのいずれかを優先するようです。
アプリが使用することを選択したプロトコルは、対処するのがはるかに簡単な結果でした。1) UDP ではなく TCP であり、2) 完全に暗号化されていませんでした。最初のメッセージには、私のアカウントでは決して変更されないように見える認証トークンが含まれているため、暗号化がないことは後から考えるとかなり憂慮すべきことです。
アプリからサーバーへのメッセージを効果的に「再生」できることがわかりました。どのバイト (パケット プロキシのおかげで「パケット」) が照明のオン/オフに使用されているかがわかれば、新しいソケットを開いて同じパケットを送信するだけで、同じ結果が得られます。これは素晴らしい兆候でした。最悪のシナリオは、たとえそれがあまり一般的ではなかったとしても、私は自分が望むものを実装する方法をすでに持っていました。
この時点で、プロトコルをさらに深く掘り下げる時期が来ました。パケット プロキシの実験と Smali の逆アセンブリの詳細を組み合わせた結果、どのような通信が行われているかについてかなり一般的な理解を得ることができました。最初に気づいたのは、通信が「メッセージ」で行われ、タイプと長さのフィールド (ビッグ エンディアン) で始まるということでした。次にやるべきことは、どのパケット タイプがどこにあるか、そして最終的には特定のパケット自体がどのようにエンコードされているかを理解することでした。これは、3 つのデバイスのステータスを含むサーバーからのパケットの例です。
73 00 00 00 60 47 e2 be ab 00 37 00 7e 00 01 00 00 f9 52 4e
00 03 00 00 00 03 00 03 00 81 01 00 00 81 01 00 00 00 00 35
00 00 00 27 00 00 00 00 00 00 00 02 00 00 01 00 00 00 01 00
00 00 00 35 00 00 00 27 00 00 00 00 00 00 00 01 00 00 01 00
00 00 01 00 00 00 00 35 00 00 00 27 00 00 00 00 00 00 00 c8
7e
プロトコルを十分に理解したら、そのための API を作成しました。この API は、デバイスの一覧表示、ステータスの取得、デバイスのさまざまなプロパティ (明るさや色調など) の更新を行うことができます。驚いたことに、私の API はアプリ自体よりもはるかに高速で信頼性が高いことがわかりました。リモート サーバーにフォールバックする前に Bluetooth または WiFi を使用しようとすると、アプリが本来より不安定になり、信頼性が低下するようです。
最後に付け加えておきますが、私はこのアプリでサポートされているすべてのデバイスを所有しているわけではないため、これらのデバイスがどのように動作するかをリバース エンジニアリングする意欲はありませんでした(または簡単に実行できませんでした)。たとえば、同じ会社はスマート コンセント、センサー、照明スイッチを製造しています。