Итак, вот моя история. Хочу упомянуть имена трех людей, которые мне сильно помогали и помогают сейчас. Если есть проблемы, всегда можно обратиться к ним. Это avkiev, KiRiK и AsteriX. Огромные им респекты!
1. Предыстория.
В мае понял, что мой S55 морально устарел и решил брать новый телефон. Сразу понял, что это будет Сименс. Вот только какой? Не A, не CX, не M65 – т.к. там нет Bluetooth. Долго колебался между S65 и SK65. И выбрал последний (мне камера в телефоне не нужна, да и кнопки на S65 не очень). Надо сказать, выбери я все-таки S65, наверно и не знал бы сейчас ничего про программирование под телефоны.
Остался сильно довольным своей покупкой, огорчился было сначала, что прошивка 34, но потом понял, что патчи ставить можно. И вот тут настало сильное разочарование. Патчей под мой телефон оказалось совсем мало – а те, что были были, в основном, сгенерированы Смелтером. А я привык к их обилию на S55. Вот тут-то и родилось желание сделать что-то самому.
2. Мои первые шаги.
В начале июля начал искать в Интернете информацию, как стать патчером. В итоге наткнулся на 2 форума: siemens-club и allsiemens. Выбрал я сименс-клаб, потому что здесь есть раздел «Патчи для SK65» :). Но как копаться в фф на самом-самом начальном уровне я научился после прочтения темы на allsiemens.com.
Итак, я вооружился Win-Hex’ом, IDA и открыл свой фф. Открыл – и ничего почти не понял. Точнее понял, что надо учить ассемблер. В итоге числа 15 случайно наткнулся на справочник по ассемблеру для компа. Почитал вступление и немного понял принципы работы процессора.
И тут, еще до прочтения справочника, я портанул первый патч! Это был патч на отключение сообщений о вкл/выкл GPRS и Bluetooth (Смелтер генерирует их неправильно для моего телефона). Посмотрел, что меняются данные 32F1 на 80BD. Пошел в фф по адресу патча на откл. сообщений о вкл/выкл IrDA. Посмотрел чуть дальше и нашел те самые 32F1. Заменил на 80BD. Все заработало!
Но посмотрев на другие патчи, понял, что простым поиском исходной строки и ее замены не обойтись. Пытался посмотреть, что делают некоторые патчи, но в IDA получал какие-то непонятные команды (типа, BL 0x90000000 – таких адресов-то нет, кстати адреса в прошивке начинаются с A0xxxxxx или A1xxxxxx). Спросил у avkiev’а и узнал, что есть две кодировки команд – ARM и Thumb. Чтобы переключиться между ними, надо в IDA нажать Alt+G и написать «0», если переходим в ARM, а «1», если – в Thumb. В патчах чаще всего используется Thumb. И вот когда я это понял, понеслась!
3. Мои первые порты.
Первым более серьезным патчем был «Расширенный список вызовов». Но его я портанул с исходника – это не интересно. Рассмотрим патч «Черный/Белый список».
Сначала настроим IDA. Идем в Options->General и ставим в поле Number of opcode bytes цифру «4». Далее, открываем папку, куда установлен IDA. Идем в папку cfg. Открываем idagui.cfg. Ищем строчку DISPLAY_PATCH_SUBMENU и ставим после знака равно «YES». Ищем строку "PatchByte", раскомментируем ее и ставим справа любую кнопку, я сделал у себя так:
"PatchByte" = "i"
Все, вроде настроили. Как открыть фф, думаю, вы уже знаете, если что, можно посмотреть на allsiemens.com. Вот этот патч для M65:
Так как программная основа у всей серии x65 практически одинаковая, то на моем SK65 тоже есть такой кусок программного кода. Надо его найти. Единственное, команды Bxx (B, BL, BLX), а также команда LDR чаще всего «непостоянны» (т.е. в других телефонах они выглядят не совсем так). Открываем фф SK65 в WinHex’е и врубаем поиск шестнадцатеричных значений. Ставим маску 3F (это те байты, которые мы не знаем, т.е. вместо этого значения может быть любой байт), и пишем в строке поиска B0423F3F207804283F3F092010AB1872, здесь я вместо 0ED1 и 02D1 я написал 3F3F, т.к. в SK65 вполне могут быть другие значения (т.к. это функции бранча, т.е. Bxx). Находим нужный адрес в конечном фф (от SK65). Если найдено несколько адресов, то надо попробовать увеличить строку поиска (т.е. дописать туда еще 10AB187A). Если так не получается, то тут уж надо анализировать каждый адрес (открывать его в IDA). Для SK65 это адрес 07093F6. А теперь проверим на всякий случай. Идем в фф SK65 по этому адресу, жмем ‘C’ и видим:
Ура! Мы попали в цель. В данном случае на командах Bxx значения байт такие же, но помните, они могут иногда меняться, поэтому вместо них ставьте всегда ‘3F’.
Адреса для первых двух и для последней строки находим аналогично.
Теперь беремся собственно за тело патча (те строки, которые пишутся вместо FF). Идем в исходном фф (от M65) по адресу патча, нажимаем «I» (или какую-либо другую кнопку, которую мы выставили в настройках в строке «Patch Byte»). В появившемся окошке вводим строки патча, только ставим пробел через каждые 2 символа (т.е. каждый байт пишем отдельно). И так для каждой строки патча (всего в данном патче их 3). Есть альтернативный способ: с помощью скриптов от AlexSid. Нажмите File->IDC file…, выберите файл Apply Patch.idc, затем в открывшемся окошке выберите патч (он должен быть НЕ в rtf формате) и нажмите “Open”, а затем при запросе скрипта нажмите “Yes”. Теперь идем в начало патча (адрес 0xA0CDE700), нажимаем Alt+G, ставим «0» (этот патч написан в кодировке ARM). Нажимаем «C» и видим следующее:
Смотрим, что тут собственно происходит и понимаем, что есть 2 ссылки на ВНЕШНИЕ функции, а эти ссылки надо бы изменить (т.к. в SK65 эти функции находятся по другим адресам). Итак первый адрес 0xA0B43B99. Здесь в конце стоит 9, а не 8, т.к. эта функция написана в Thumb’е. Нажимаем «C» по адресу 0xA0B43B98 (предварительно «Alt+G» и пишем «1»), смотрим:
Тут как раз видно то, о чем я говорил – внимательно посмотрите на адреса ROM:A0B43BA4 в M65 и ROM:A075D834 в SK65 – там стоят разные байты.
Переворачиваем байты нашего адреса и не забываем прибавить в конце единичку (т.к. Thumb). Получаем 29D875A0. Далее ищем вторую функцию по аналогии (попробуйте сами в качестве тренировки). Соответственно, заменяем адреса в конце тела патча полученными. Теперь надо найти место, куда воткнуть патч. Надо искать пустые блоки (где стоят сплошняком FF’ы), причем важно помнить, что ссылки по «бранчам» (функциям Bxx) действительны только в пределах +-4Mb или 0x400000. Нам надо дотянуться до патча с адреса 07093F6, поэтому мы его можем воткнуть в пределах 0x03093F6-0x0B093F6. Обычно патчи втыкают туда, где много свободного места, т.е. где в WinHex’е несколько страиц одни FF’ы. В указанных мной пределах я столько места не нашел, поэтому пришлось вставлять патч туда, где мало места, но ничего – хватило. Воткнул я сюда: 0473D00.
Ну и последнее: нам надо вызвать тело патча. То есть надо выполнить по адресу 0x07093F6 процедуру BLX 0x0473D00 (тут именно BLX потому, что в исходном сегменте команды написаны в Thumb’е, а нам надо перейти в ARM). Чтобы знать, что вписать, можно воспользоваться прогой ABraGen (но она у меня глючит), можно – дебаггером, но лучше всего - написать свою микропрограмму в Keil ARM. Так я вышел именно на строку 6AF584EC.
; Hook keyhandle of IDLE AREA HOOK1, CODE, AT 0xA08DAEC6 CODE16 BL Hook1
; Hook KeyHandle of ScreenSaver AREA HOOK2, CODE, AT 0xA099090E CODE16 BL Hook2
END
Как видите, здесь идет ссылка на процедуру Hook1 (если залоченная клава) или Hook2 (если скринсейвер). Далее вызывается функция Main. Ее я чутка поменял. Видите, в регистре R0 содержится код нажатой кнопки. Далее идет его сравнение с числом 5 (это зеленая кнопка – полный список см. в теме «Обсуждение патча Говорящий Телефон»). Если в регистре НЕ число 5 (BNE – Branch if Non Equal), то идет ссылка на функцию выхода (ExitOrg), если же оно – то идем далее, идет проверка на наличие входящих непрочитанных СМС и флеш-СМС, если их нет, опять идем на ExitOrg. Если есть – вызывается встроенная в прошивку функция просмотра входящих СМС, а далее идем на все тот же ExitOrg. Что у нас в функции выхода? А там мы заносим в регистр R0 содержимое регистра R6 (если в R0 будет НОЛЬ, то будет показываться экранчик «Блокировка клавиатуры вкл, нажми #, чтобы вырубить», а если ЕДИНИЦА – то не будет). Далее идет команда pop {PC}. Этой командой мы возвращаемся к команде, вызвавшей функцию Main (т.е. дальше по функциям Hook1 и Hook2). Там уже вызываем замененную вызовом патча функцию и еще что-то (честно говоря, так еще и не понял что). Команды push и pop связаны с понятием СТЕК. Чтобы понять что это приведу пример П. Нортона. Представьте себе машину для мойки тарелок. Мы кладем тарелку наверх, на другие тарелки, потом сверху кладем еще несколько тарелок. Далее они помылись и мы забираем тарелки, причем ПЕРВАЯ тарелка, которую мы возьмем, будет ПОСЛЕДНЕЙ, положенной в машину. Т.е. действует правил «Последним вошел – первым вышел». Команда push «кладет» содержимое регистра в стек, а команда pop «вынимает» его оттуда.
Итак, что сделал я? Сначала (в версии 2 – версию 1 можно не вспоминать ) я просто заменил выход из патча при отсутствии входящих СМС на вызов проговаривания времени, примерно вот так:
Main: PUSH {R6, LR} MOV R6, #0 CMP R0, #05 BNE ExitOrg BL HasFlashSMS CMP R0, #1 BEQ ReadFlash BL HasNewSMS CMP R0, #1 BNE ReadTime … … … ReadTime: BL 0x019D520 ;это у меня адрес функции проговаривания времени B ExitOrg ;выход
Потом я пошел дальше и решил, что буду делать патч на основе буфера настройки (как у avkiev’а в патчах «Ежечасные события» и «Динамический провайдер»). Стал по его исходникам разбираться, как с ним (с буфером) работать. Делается это так:
PUSH {R4} ;заносим в стек регистр R4, т.к. он где-то еще используется CMP R0, #1 BEQ Krasnaja_Knopka CMP R0, #5 BEQ Zelenaja_Knopka … ;делаем проверку нажатой кнопки и заносим в регистр R4 СМЕЩЕНИЕ в буфере (т.е. например, если нажата красная кнопка – то это 0, если зеленая – то 1 (это можно самому сделать как хочешь – т.е. можно и наоборот)) Krasnaja_Knopka: MOV R4, #0 ;в регистр R4 пишем смещение в буфере, здесь оно равно 0 B Continue ;идем дальше Zelenaja_Knopka: MOV R4, #1 ;здесь смещение 1 B Continue ;идем дальше … … … AdrReg 3, aBuffer ;адресуем регистр R3 в наш буфер (здесь выбран он, т.к. он не используется в патче и в процедурах телефона рядом с той, из которой мы вызывали патч) LDRB R0, [R3, R4] ;теперь регистр R0 нам не нужен (кнопку мы вычислили), заносим в него байт в буфере (команда LDRB; а можно в принципе и в R3 – тогда будет LDRB R3, [R3, R4]), находящемся по адресу, прописанному в R3, и по смещению, количественно равному значению R4. Надеюсь, понятно объяснил… Все, теперь в R0 у нас нужный байт, так что теперь делаем проверку, что же это за байт и вызываем нужную функцию. ;В конце патча надо дописать сам буфер: aBuffer: dd 0x01, 0x0AB, 0x00…
Конечно, написал я тут про патч версии 7.5, хотя уже есть более поздние версии, но для получения начальных представлений, я думаю, и его сойдет.
5. Заключение.
Ну вот, собственно, все, что я хотел написать. Конечно, этот материал рассчитан на человека, понимающего немного в программировании, однако даже если вы не обладаете такими знаниями, помните – главное – это желание научиться.