[Из песочницы] Исследование устройства WiFi Led Controller
Сегодня к осмотру представлено устройство, созданное для того, чтобы сделать нашу жизнь проще.
Однако, при включени моя жизнь проще не стала. Даже наоборот, усложнилась. Причиной этого стало приложение MagicColor v1.0, вошедшее в комплект поставки. Несмотря на то, что эта программа работала на телефонах HTC и LG, на моих устройствах Samsung Galaxy Note 10.1 и Galaxy Nexus она не заработала, что заставило ее немного препарировать, а вместе с ней и сам чудный девайс. Первое, что было установлено, о чем не упомянуто в инструкции, наличие у устройства WEB-интерфейса c логином: admin и паролем 1234, что конечно обрадовало.
Как видно из скриншотов по умолчанию устройство работает в режиме Ad hoc с незащищенным доступом к сети. Протокол по умолчанию TCP и порт 5000.
Надо сказать, что такая ситуация меня ни в коем случае не устроила. Во первых, это безопасность, ее просто нет. Любой желающий может получить доступ к данному устройству. Во вторых, хотелось бы видеть это устройство в моей домашней сети, в которой уже есть свой DHCP сервер, и защита от внешних посягательств. К сожалению у программы MagicColor нет возможности изменить IP-адрес устройства. Кроме того, как выяснилось позже, в программе существует проверка имени сети ssid.
Теперь давайте разберемся с программой. Для распаковки файла MagicColor.apk я использовал APK Manager v.4.9. Для этого достаточно скопировать .apk в папку “place-apk-here-for-modding” и запустить скрипт Script.bat. После этих манипуляций в корневой папке программы появляется папка “projects” а в ней папка с таким же названием как и у файла .apk. Теперь нужно получить .jar файл из файла classes.dex для чего был использован скрипт dex2jar. Достаточно мышкой перетащить .dex файл на dex2jar.bat и мы получаем то что хотели.
Следующий шаг, декомпилировать полученный файл classes_dex2jar.jar. Сначала, я попробовал декомпилятор JD-gui. Но, он не оправдал надежд, выдав не корректный код. Зато следующий декомпилятор AndroChef полностью справился с задачей.
Разберемся с полученными исходниками. Для разборок я использовал Eclipse Standart версии Kepler, с установленным на нее плагином ADT Plugin. Установить его можно из оболочки Eclipse вызвав меню “Help” — “Install New Software…”. далее нажать кнопку “Add” и в поле “Name” ввести ADT Plugin”, а в поле “Location:” dl-ssl.google.com/android/eclipse/. Выбираем все компоненты и жмем “Finish”.
Для начала я создал пустой проект Android Application Project. Где установил Application Name: Color, Project Name: MagicColor2, Package Name: com.android.color. Далее убрал галочки с пунктов «Create custom launcher icon» и «Create activity».
В папку src поместил полученные при декомпиляции папки “cn” и “com”. Из “com/android/color” файл R.java переносим с заменой в папку “gen/com/android/color”.
Не забываем перенести все файлы из папки “res” в одноименную папку проекта. И AndroidManifest.xml. Которые я получил с помощью скрипта apktool c патаметрами java -jar apktool.jar d MagicColor.apk out. После работы скрипта создается папка “out” в которой присутствует папка “res” и AndroidManifest.xml
Можно приступать к анализу кода программы. В программе Eclipse находит несколько ошибок, которые нужно исправить. Как я это сделал можно посмотреть в исходных кодах, которые я приложил к статье ниже.
В StaticClass.java мы видим, настройки программы по умолчанию. Некоторые из этих параметров нам пригодятся далее. В файле Protocol.java описан алгоритм формирования команды для устройства, основой кототого является функцией getAll(), в которой формируется команда.
<b>public byte[] getAll() { this.all[0] = this.frameHead[0]; this.all[1] = this.frameHead[1]; this.all[2] = 0; this.all[3] = this.mode; this.all[4] = this.keyNumber; this.all[5] = this.keyValue; this.all[6] = this.colorRGB[0]; this.all[7] = this.colorRGB[1]; this.all[8] = this.colorRGB[2]; this.all[9] = this.checkValue; return this.all; }</b> Исходя из этого данных видим, что первые два байта всегда одинаковые, и равны -86 и 85, образующие в бинарном виде 10101010 и 1010101 последовательность бит, позволяющие определить подлинность и корректность команды. Так же для определения корректности в команду включена контрольная сумма, которая находится в самом конце, 9 байте команды. Вычисляется она функцией getCurCheckValue(int paramInt1, int paramInt2, int paramInt3, int paramInt4, int paramInt5) следующим оригинальным способом: Key_Num + (blue +(green + (red +(bar_No + 255))) +mode)%255Где: paramint1 – StaticClass.bar_No, paramint2 — StaticClass.red, paramint3 — StaticClass.green, paramin4 – StaticClass.blue, paramint5 — StaticClass.Key_Num
Как вы уже догадались поля red, green и blue — это значение от 1 до 255 для 1,2,3 канала соответственно. При подключении RGB освещения, изменяется цвет, а при подключении обычных диодных ламп изменяется яркость. Поле Key_Num определяет режим работы устройства. Режимы таковы: 1- выключение освещения, 2 — включение освещения, 3 последовательное переключение встроенных режимов устройства, от частого мигания, до постоянного свечения. Имея в своем распоряжении только один канал с лампой ознакомиться со всем разнообразием режимов мне не удалось. Поле mode = 1, поле bar_No всегда равно 50.
Перед отправкой команда изменяется функциями exchangeBytes и exchangeInt видимо для того, чтобы слегка зашифровать протокол передачи. Идея этих функций в том, что части крайних симметричных относительно центра байт переставляются местами, к примеру если мы имеем изначальное сообщение AB CD то после преобразования получим AC BD, а если 12 34 56 78 то получим 17 35 46 28. Вот так хитро!!!
Теперь о той проблеме, которая не позволяла пользоваться программой для моих устройств Samsung. Как выяснилось при отладке приложения, SSID сети заключается в кавычки и его длина увеличивается на 2 символа, чего программа не ожидает, и проверяя длину SSID ожидает получить 5 вместо 7. Функции проверки, которые находятсся в файле ColorActivity.java рассмотрены ниже. Их две: private void getWifiInfo()и protected void isWifiInfo(). В обоих функциях присутствует код:
<b>if(this.ssid != null) { if(this.ssid.length() != 5) { StaticClass.wifi_correct = false; return; } if(!this.ssid.substring(0, 2).equals("LN")) { StaticClass.wifi_correct = false; return; }</b> Жирным я выделил те самве проверки. Зачем проверять длину SSID и первые два символа имени SSID, а они всегда одинаковые, не знаю. В SSID отличаются только последние 3 символа, и зависят они от положения переключателя SSID на устройстве. Положение 0 на переключателе соответствует имени SSID “LN001”. Для того, чтобы программа заработала на моем телефоне, оказалось достаточно убрать эти проверки.
Далее мне удалось добавить дополнительное поле на страничку настроек программы в котором можно ввести IP-адрес устройства. Теперь стало возможным переключить устройство из «ad hoc» в режим «infrastructure», настроить безопасность и подключить его с своей домашней сети, оставив возможность управления освещением с мобильного устройства.
Готовый проект и рабочую программу в папке «bin» с добавленным в настройки полем IP адреса устройства можно взять здесь: проект Magic Color 2.