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: ... ... ... ©SiNgle 0B137BC: 06D1 0028 0B137C0: 04D1 0028 0B13C0E: B0420ED1 CAF178ED #pragma enable old_equal_ff 0CDE700: 00402DE9060050E10500001AFF3F2DE9 0CDE710: 0FE0A0E10CF09FE5FF3FBDE80040BDE8 0CDE720: 04F09FE50080BDE8993BB4A0313CB1A0 #pragma disable old_equal_ff 1289627: D5 E0 ;0CDE70B: 1A 0A ;белый список (white list) ... ... ... Брал я фф от M65. Сначала ищем энтрипоинт (точку входа). 0B13C0E: B0420ED1 CAF178ED ... ... ... Идем в фф от M65 по этому адресу. Вот, что мы видим: ROM:A0B13C0E B0 42 CMP R0, R6 ROM:A0B13C10 0E D1 BNE loc_A0B13C30 ROM:A0B13C12 20 78 LDRB R0, [R4] ROM:A0B13C14 04 28 CMP R0, #4 ROM:A0B13C16 02 D1 BNE loc_A0B13C1E ROM:A0B13C18 09 20 MOV R0, #9 ROM:A0B13C1A 10 AB ADD R3, SP, #0x40 ROM:A0B13C1C 18 72 STRB R0, [R3,#8] ROM:A0B13C1E ROM:A0B13C1E loc_A0B13C1E ; CODE XREF: ROM:A0B13C1E 10 AB ADD R3, SP, #0x40 ROM:A0B13C20 18 7A LDRB R0, [R3,#8] ... ... ... Так как программная основа у всей серии x65 практически одинаковая, то на моем SK65 тоже есть такой кусок программного кода. Надо его найти. Единственное, команды Bxx (B, BL, BLX), а также команда LDR чаще всего «непостоянны» (т.е. в других телефонах они выглядят не совсем так). Открываем фф SK65 в WinHex’е и врубаем поиск шестнадцатеричных значений. Ставим маску 3F (это те байты, которые мы не знаем, т.е. вместо этого значения может быть любой байт), и пишем в строке поиска B0423F3F207804283F3F092010AB1872, здесь я вместо 0ED1 и 02D1 я написал 3F3F, т.к. в SK65 вполне могут быть другие значения (т.к. это функции бранча, т.е. Bxx). Находим нужный адрес в конечном фф (от SK65). Если найдено несколько адресов, то надо попробовать увеличить строку поиска (т.е. дописать туда еще 10AB187A). Если так не получается, то тут уж надо анализировать каждый адрес (открывать его в IDA). Для SK65 это адрес 07093F6. А теперь проверим на всякий случай. Идем в фф SK65 по этому адресу, жмем ‘C’ и видим: ... ... ... ROM:A07093F6 B0 42 CMP R0, R6 ROM:A07093F8 0E D1 BNE loc_A0709418 ROM:A07093FA ROM:A07093FA loc_A07093FA ; CODE XREF: ROM:A07093E8j ROM:A07093FA 20 78 LDRB R0, [R4] ROM:A07093FC 04 28 CMP R0, #4 ROM:A07093FE 02 D1 BNE loc_A0709406 ROM:A0709400 09 20 MOV R0, #9 ROM:A0709402 10 AB ADD R3, SP, #0x40 ROM:A0709404 18 72 STRB R0, [R3,#8] ROM:A0709406 ROM:A0709406 loc_A0709406 ; CODE XREF: ROM:A07093FEj ROM:A0709406 10 AB ADD R3, SP, #0x40 ROM:A0709408 18 7A LDRB R0, [R3,#8] ... ... ... Ура! Мы попали в цель. В данном случае на командах 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» и видим следующее: ... ... ... ROM:A0CDE700 ; --------------------------------------------------------------------------- ROM:A0CDE700 00 40 2D E9 STMFD SP!, {LR} ROM:A0CDE704 06 00 50 E1 CMP R0, R6 ROM:A0CDE708 05 00 00 1A BNE locret_A0CDE724 ROM:A0CDE70C FF 3F 2D E9 STMFD SP!, {R0-SP} ROM:A0CDE710 0F E0 A0 E1 MOV LR, PC ROM:A0CDE714 0C F0 9F E5 LDR PC, =unk_A0B43B99 ROM:A0CDE718 FF 3F BD E8 LDMFD SP!, {R0-SP} ROM:A0CDE71C 00 40 BD E8 LDMFD SP!, {LR} ROM:A0CDE720 04 F0 9F E5 LDR PC, =(loc_A0B13C30+1) ROM:A0CDE724 ; --------------------------------------------------------------------------- ROM:A0CDE724 ROM:A0CDE724 locret_A0CDE724 ; CODE XREF: ROM:A0CDE708j ROM:A0CDE724 00 80 BD E8 LDMFD SP!, {PC} ROM:A0CDE724 ; --------------------------------------------------------------------------- ROM:A0CDE728 99 3B B4 A0 off_A0CDE728 DCD unk_A0B43B99 ; DATA XREF: ROM:A0CDE714r ROM:A0CDE72C 31 3C B1 A0 off_A0CDE72C DCD loc_A0B13C30+1 ; DATA XREF: ROM:A0CDE720r ... ... ... Смотрим, что тут собственно происходит и понимаем, что есть 2 ссылки на ВНЕШНИЕ функции, а эти ссылки надо бы изменить (т.к. в SK65 эти функции находятся по другим адресам). Итак первый адрес 0xA0B43B99. Здесь в конце стоит 9, а не 8, т.к. эта функция написана в Thumb’е. Нажимаем «C» по адресу 0xA0B43B98 (предварительно «Alt+G» и пишем «1»), смотрим: ... ... ... ROM:A0B43B98 08 B5 PUSH {R3,LR} ; CODE XREF: ROM:A0CDE714j ROM:A0B43B98 ; DATA XREF: ROM:off_A0CDE728o ROM:A0B43B9A 00 22 MOV R2, #0 ROM:A0B43B9C 13 1C ADD R3, R2, #0 ROM:A0B43B9E 82 21 MOV R1, #0x82 ROM:A0B43BA0 00 92 STR R2, [SP] ROM:A0B43BA2 20 48 LDR R0, =0x4211 ROM:A0B43BA4 E3 F4 AE EF BLX sub_A0827B04 ROM:A0B43BA8 08 BD POP {R3,PC} ... ... ... Ищем следующую строку 08 B50022131C8221009220483F3F3F3F08BD. Я нашел ее по адресу 0xA075D8A8. Смотрим туда: ROM:A075D828 08 B5 PUSH {R3,LR} ROM:A075D82A 00 22 MOV R2, #0 ROM:A075D82C 13 1C ADD R3, R2, #0 ROM:A075D82E 82 21 MOV R1, #0x82 ROM:A075D830 00 92 STR R2, [SP,#8+var_8] ROM:A075D832 20 48 LDR R0, =0x4211 ROM:A075D834 98 F1 BC EC BLX sub_A08F61B0 ROM:A075D838 08 BD POP {R3,PC} Тут как раз видно то, о чем я говорил – внимательно посмотрите на адреса 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. Вот конечный вариант порта: 0708FA4: 06D1 0028 0708FA8: 04D1 0028 07093F6: B0420ED1 6AF584EC #pragma enable old_equal_ff 0473D00: 00402DE9060050E10500001AFF3F2DE9 0473D10: 0FE0A0E10CF09FE5FF3FBDE80040BDE8 0473D20: 04F09FE50080BDE829D875A0199470A0 #pragma disable old_equal_ff 09F96CF: D5 E0 ;0473D0B: 1A 0A ;белый список (white list) Сравни с оригиналом: 0B137BC: 06D1 0028 0B137C0: 04D1 0028 0B13C0E: B0420ED1 CAF178ED #pragma enable old_equal_ff 0CDE700: 00402DE9060050E10500001AFF3F2DE9 0CDE710: 0FE0A0E10CF09FE5FF3FBDE80040BDE8 0CDE720: 04F09FE50080BDE8993BB4A0313CB1A0 #pragma disable old_equal_ff 1289627: D5 E0 ;0CDE70B: 1A 0A ;белый список (white list) Как видите – отличия только в адресах, в вызове патча и в последних 8 байтах тела патча. 4. Мой первый патч. Теперь немного про мой патч. Его я делал на основе патча “Read SMS while keyboard locked”. Вот его оригинал: ;source for keil $arm9e HasNewSMS EQU 0xA0990660+1 HasFlashSMS EQU 0xA0935DB8+1 ReadNewSMS EQU 0xA0A2DBF8 ReadFlashSMS EQU 0xA098F63E+1 TempLigntOn EQU 0xA0B2C364+1 SetScreenSaver EQU 0xA0936A32+1 AREA STARTUPCODE, CODE CODE16 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 ExitOrg ReadSMS: MOV R0, #3 BL TempLigntOn LDR R0, =ReadNewSMS BLX R0 MOV R6, #2 B ExitOrg ReadFlash: MOV R0, #3 BL TempLigntOn BL ReadFlashSMS MOV R6, #1 ExitOrg: ADD R0, R6, #0 POP {R6, PC} Hook1: MOV R3, #2 LDRSH R0, [R5,R3] PUSH {LR} BL Main CMP R0, #0 BNE Hook1NewExit BL 0xA08D9D5C ;Org Ins POP {PC} Hook1NewExit: ADD SP, #4 LDR R1, =0xA08DAE28+1 ;return after processed BX R1 Hook2: MOV R3, #2 LDRSH R0, [R4,R3] PUSH {R0, LR} BL Main CMP R0, #0 BNE Hook2NewExit POP {R0, PC} Hook2NewExit: ADD SP, #8 CMP R0, #2 BNE Hook2Exit MOV R0, #0 BL SetScreenSaver ;0 Leave screensaver Hook2Exit: LDR R1, =0xA09909FA+1 ;return after processed BX R1 ; 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. Заключение. Ну вот, собственно, все, что я хотел написать. Конечно, этот материал рассчитан на человека, понимающего немного в программировании, однако даже если вы не обладаете такими знаниями, помните – главное – это желание научиться. Если будут какие-то вопросы – не стесняйтесь – задавайте (на форуме, в личке или еще где меня найдете ), я постараюсь на них ответить. Скорее всего, я буду дополнять эту статью в будущем, если она вызовет интерес.
Источник: http://www.siemens-club.org/faq/index.php?Action=showarticle&faqID=162 |