その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

Estimote Beacon をリバースエンジニアリング


Estimote のビーコン、「2014年初頭にはSDKから加速度センサや温度センサの情報にもアクセスできるようになる」って言ってた *1 のでずっと楽しみにしてるのですが、まだその気配がありません


で、最近 Core Bluetooth のプロファイルまわりをいろいろ調べてるうちに *2 、ふと


「もしかしたらもう普通に加速度センサや温度センサの値がアドバタイジングされてるんじゃないの?」


と思いつき、どんな Service / Characteristic がアドバタイジングされてるのか、 Core Bluetooth から観測してみました。


が、こんなのもう誰かがとっくにやってそうだ、と思いググってみると、Estimote をいろんな切り口からリバースエンジニアリングした海外記事を発見しました。


貴重な情報が載っていて、解析方法もおもしろかったのでかいつまんで紹介します。

使用チップ

ガッチリ接着されているカバーが容赦なく剥がされ、高解像度で基盤写真が晒されています。


使われているチップは、

The Estimote is built around the Nordic Semiconductor nRF51822, which explains their presence on the Nordic booth at CES. It’s a nice chip, basically a 32-bit ARM Cortex M0 CPU with 256KB of flash and 16KB of RAM with a built-in 2.4GHz radio supporting both Bluetooth LE as well as 2.4GHz operation―where the 2.4GHz mode is on air compatible with the nRF24L series products from Nordic.

とのこと。


他のビーコンモジュールとスペック上で比較する際に参考になりそうです。

アドバタイジングデータの解析

下記のように推測されていました。

  • First two bytes are the Apple Company Identifier (Little Endian) 0×0042.
  • The third byte―at least most likely―specifies the data type, which is 2.
  • The fourth byte specifies the remaining data length, 21 bytes.
  • Estimote Beacons have a fixed iBeacon UUID of B9407F30-F5F8-466E-AFF9-25556B57FE6D.
  • The next two bytes after the iBeacon UUID are the iBeacon Major (Big Endian), i.e. 0xED4E, 60750.
  • The next two bytes after the iBeacon Major are the iBeacon Minor (Big Endian), i.e. 0×8931, 35121.
  • The final byte is the measured RSSI at 1 meter away, i.e. 0xB6, -74.


UUID, Major, Minor, RSSIなど、いたって一般的なiBeaconモジュールがアドバタイジングする内容です。

Method Swizzling や class-dump で SDK を解析

Estimote の iOS SDK はバイナリとして提供されているので中身がわからないのですが、この記事ではSDK内部で用いられているCore BluetoothフレームワークのメソッドをMethod Swizzlingして処理内容を出力させ解析しています。


具体的には、CBXpcConnection というCoreBluetoothフレームワーク内のクラスの

- (void)handleMsg:(int)arg1 args:(id)arg2;
- (void)sendMsg:(int)arg1 args:(id)arg2;

というメソッドを

- (void)handleMsgSwizzled:(int)arg1 args:(id)arg2;
- (void)sendMsgSwizzled:(int)arg1 args:(id)arg2;

に置き換え、

- (void)handleMsgSwizzled:(int)arg1 args:(id)arg2
{
    NSLog(@"handleMsg: %d, %@", arg1, arg2);
    
    [self handleMsgSwizzled:arg1 args:arg2];
}

- (void)sendMsgSwizzled:(int)arg1 args:(id)arg2
{
    NSLog(@"sendMsg: %d, %@", arg1, arg2);
    
    [self sendMsgSwizzled:arg1 args:arg2];
}

- swizzle CBXpcConnection methods · sandeepmistry/EstimoteEditor@726691f · GitHub


このようにNSLogで内容を出力するようにしています。


で、さらに詳しく解析できるようにしたり、

- (void)handleMsgSwizzled:(int)arg1 args:(id)arg2
{
    int msgId = arg1;
    NSDictionary *args = arg2;
    
    NSString *deviceUUID = [[args objectForKey:@"kCBMsgArgDeviceUUID"] UUIDString];
    
    if (msgId == 4) {
        NSLog(@"state change: %@", [args objectForKey:@"kCBMsgArgState"]);
        
    } else if (msgId == 34) {
        NSDictionary *advertisementData = [args objectForKey:@"kCBMsgArgAdvertisementData"];
        
        NSLog(@"device discovered: %@, name = %@", deviceUUID, [advertisementData objectForKey:@"kCBAdvDataLocalName"]);
        
    } else if (msgId == 35) {
        NSLog(@"device connected: %@", deviceUUID);
    } else if (msgId == 51) {
        NSLog(@"device services discovered: %@", deviceUUID);
    } else if (msgId == 59) {
        NSLog(@"device service characteristics discovered: %@", deviceUUID);
    } else if (msgId == 65) {
        NSLog(@"device characteristic read: %@, handle = %@, value = %@", deviceUUID, [args objectForKey:@"kCBMsgArgCharacteristicHandle"], [args objectForKey:@"kCBMsgArgData"]);
    } else if (msgId == 66) {
        NSLog(@"device characteristic written: %@, handle = %@", deviceUUID, [args objectForKey:@"kCBMsgArgCharacteristicHandle"]);
    } else {
        NSLog(@"handleMsg: %d, %@", arg1, arg2);
    }
    
    [self handleMsgSwizzled:arg1 args:arg2];
}

- interpret XPC messages · sandeepmistry/EstimoteEditor@3605a7d · GitHub


この結果を踏まえて ESTBeacon クラスの下記メソッドもSwizzlingしたり、

- (void)pairSensorFirstPart;
- (void)pairSensorSecondPart;


class-dumpして非公開クラスのメソッドを出力して、そこで見つけた気になるメソッドをまたswizzling したりしてSDKの処理内容を解析しています。



で、以上の解析結果をもとにまとめられた Estimote の Characteristics 仕様がこちら。


node-bleacon/estimote.txt at master · sandeepmistry/node-bleacon · GitHub


バッテリーレベルなどはありますが、どうやら 加速度センサや温度センサの情報はまだ現段階のファームではアドバタイジングされてない ようです(まだ???となっている未開のCharacteristicsもありますが)。

所感

当初の目的だった「加速度センサや温度センサのアドバタイジングデータ」は結局見つかりませんでしたが、個人的には「バイナリの解析ってこうやってやるのかー」と非常に勉強になりました。