Я решил пересмотреть прошивки некоторых поколений Samsung (включая CDMA), кроме смартфонов. Абсолютно во всех телефонах samsung используется ARM-совместимый процессор с набором команд ARM7TDMI. Прошивки строятся на основе трех ОС: RTCX, RTK и Nucleus. И компилировались на разных компиляторах. Я встречал прошивки скомпилированые на ADS (SDT) и IAR. Поколения самсунгов именуют на форумах абсолютно по-разному, кто-то любит делить просто на "Гуми"/"Сувон"(два города в Корее), кто-то делит на кодовые названия "Sysol", "Agere", "VLSI", "Conexant" и "Древние". Я пришел к выводу что правильнее делить их по процессору телефона. Процессор - Модели OM6357(aka Sysol) - E100, E700, E720, E800, E820, S50x, X100, X460, X60x M46 (aka Conexant) - A100, A110, A200, A300, A400, M100, T208 SkyWorks (aka Conexant) - C100, C108, C110, P510, P518 ONE-C (aka VLSI) - R2XX, Nxxx, Txxx (кроме T208) Trident (aka Agere) - Dxxx, Qxxx, Sxxx(кроме S50x), Vxxx, C200, E105, E310, E400, E600, E710, E810, X105, X400, X42x, X450 и т.д. MSMxxxx - все CDMA Соответственно, прошивки поколений очень похожи друг на друга, а иногда просто вообще близнецы с перебитыми строками версий. Например, в x100 есть следы от E100/E700/X600, иначе зачем в прошивке есть код для работы со вторым дисплеем, камерой и IRDA которых у него в жизни не было ? ab.gif Естественно и OS выбирается одна на все поколение: OM6357 - RTK OSE M46 - RTCX SkyWorks - RTCX ONE-C - RTK OSE Trident - Nucleus MSMxxxx - неизвестно, какая-то ОС от Qualcomm известно только, что собирают их в ADS/SDT. Если вы собрались разбираться в низком уровне, то конечно же SDK от соответсвующей ОС будет как никогда к стати. Еще очень поможет символьная информация которая встречается в некоторых архивах с прошивками. Иногда попадаются прошивки с файлами lst, sym, map, out, которые содержат информацию о прошивке очень сильно помагающую в исследованиях. В частности такие файлы встречаются практически во всех прошивках c100, s500. Для остальных моделей все более запущено и приходится довольствоваться сигнатурами сделаными с символов какой-нить прошивки из этого же поколения. Так, для M46 я смог найти только одну прошивку с символами, это была прошивка от A110. Но сигнатуры, сделаные с нее, прекрасно ложатся на A200, A300 и т.д. Интерпретация символьной информации Формат MAP Map файлы содержат информацию о модулях которые вошли в прошивку и имеют вид типа: Base Size Type RO? Name 0 20 CODE RO AAA_vectors from object file obj/isr.o 20 38e8 CODE RO C$$code from object file ../../src/t9latin.o 3908 30 CODE RO C$$code from object file obj/mmi_date.o 3938 5a4 CODE RO C$$code from object file hw_slow.o 3edc 874 CODE RO C$$code from object file rtkgo.o и т.д. Base - это смещение в файле прошивки. Size - длина. Type тип региона. RO? - тип доступа к региону. Name - имя оригинального файла, часть которого вошла в прошивку Как это интерпритировать? Например так(вторая строка): Начиная со смещения 20 идет блок кода(CODE) длиной 38e8 доступ к блоку Read Only. То, что блок имеет атрибут CODE далеко не означает, что можно эту область ВСЮ сделать кодом. На самом деле это код + данные. Точно также если у блока тип DATA. Это не означает, что нужно ее делать всю данными. Без файла имен/символов эту информацию можно применять разве, что только для определения размера кода прошивки (т.е. чтобы не залезть на графику). Поэтому, рассмотрим формат SYM Формат SYM Sym файлы это просто кладезь информации. Имеют вид типа: Symbol Table AAA_vectors$$Base 000000 AAA_vectors$$Limit 000020 VectorMap$$Base 1006a3c VectorMap$$Limit 1006a60 isr$$Base 12774c isr$$Limit 127bb0 gl_MaskIT 1000078 Rtk_RegionCount 100564c rtk_WorthItSched 10056a0 Rtk11_Schedule 11f5c8 и т.д. Здесь немного проще. Соответствие имя - адрес. Но вот с адресами есть некоторые заморочки. Есть набор имен, которые содержат знак доллара, они имеют особый статус. Символы заканчивающиеся $$Base - начало области виртуального адресного пространства, $$Limit - конец. Т.е. это информация о сегментам. Из этих сегментов можно составить карту памяти и увидеть как раскидываются части бинарника на различные адреса. Начинать строить карту памяти надо с вот таких символов: Image$$RO$$Base 000000 Image$$RO$$Limit 1afef4 Image$$RW$$Base 1000000 Image$$RW$$Limit 107dad4 Image$$ZI$$Base 1006a60 Image$$ZI$$Limit 107dad4 RO - Read Only т.е. это адреса где располагается код. RW - Read/Write т.е. это RAM. ZI - Zero Initialized, опять RAM которую забивают при включении мобилы нолями. Т.е. можно смело создавать сегменты по этим адресам. Теперь идем дальше AAA_vectors$$Base 000000 AAA_vectors$$Limit 000020 C$$code$$Base 000020 C$$code$$Limit 127310 C$$code$$__call_via$$Base 127310 C$$code$$__call_via$$Limit 127320 Example$$Base 127320 Example$$Limit 127324 HAL_boot$$Base 127324 HAL_boot$$Limit 12735c RtkCode$$Base 12735c RtkCode$$Limit 127408 SysSupportCode$$Base 127408 SysSupportCode$$Limit 12744c boot$$Base 12744c boot$$Limit 127654 clib$$Base 127654 clib$$Limit 12774c isr$$Base 12774c isr$$Limit 127bb0 C$$constdata$$Base 127bb0 C$$constdata$$Limit 1afef4 C$$data$$Base 1000000 C$$data$$Limit 1005a38 Stacks$$Base 1005a38 Stacks$$Limit 1006a3c VectorMap$$Base 1006a3c VectorMap$$Limit 1006a60 C$$zidata$$Base 1006a60 C$$zidata$$Limit 107dad4 Вот так интересно они друг за другом идут. Если хочется - можно поразделять на сегменты по соответствующим адресам. Но это чисто логическое разделение. Только вот в sym файле эти строки раскиданы черти как. И еще рано или поздно возникает вопрос: "почему размер кода 1afef4, если длина файла прошивки 1b6950, куда девать еще 6a60 байт?". Смотрим опять на начальную карту памяти: Image$$RW$$Base 1000000 Image$$RW$$Limit 107dad4 Image$$ZI$$Base 1006a60 Image$$ZI$$Limit 107dad4 RAM заканчивается адресом 107dad4, блок 1006a60 - 107dad4 Zero Initialized, а чем же инициализируется блок 1000000-1006a60 размер которого, как раз 6a60? Правильно, вот теми самыми оставшимися байтами. Если проанализировать стартовый код ОС, то в процедуре инициализации RAM вы найдете это самое копирование. В более новых прошивках можно встретить вот такие надписи: Load$$IRAM$$Base 639a74 Image$$IRAM$$Base 2010000 Image$$IRAM$$Length 0015a4 Это следует понимать так: данные длиной 15a4 грузятся с файлового смещения 639a74 по адресу 2010000. Продолжаем анализ символов со знаком доллара: x$litpool$ - Literal Pool, это куски данных от функций. В конце многих функций лежат указатели, строки, константы - вот x$litpool$ указывает на начало таких констант. x$litpool_e$ - конец Literal Pool. $T - чисто для дебагера это адреса где происходит изменение регистра PC. Т.е. по этим адресам есть команды перехода BL/BEQ/B/BX и т.д. $$ - адреса где происходит смена режима ARM/THUMB. Есть еще символы C$$code, что это такое определить не смог. Остальные имена без знака доллара - это имена констант и функций. Их можно смело юзать. Если в архиве с прошивкой идет и MAP и SYM, то это идеальный вариант т.к. когда задаешь имя взятое из Sym можно проверить лежит ли оно в области кода по данным из Map. Если да то можно смело делать ее кодом не боясь, что будут неправильно определено код/данные. Формат LST Это вообще рай для реверсера в этих файлах лежит все сразу. Состоят они из пяти частей: Image Symbol Table - символы... их смысл пока не понял Local Symbols - понятно из имени. Global Symbols - аналог sym файла. Memory Map of the image - карта памяти! Вся и сразу! Image component sizes - аналог map файла. Информация настолько подробная, что даже указан режим процессора для каждой функции. Формат OUT Встретил только прошивках на Nucleus. Там могут быть два файла tlink.out и tsymb.out. tsymb.out - обычный SYM tlink.out - MAP файл к которому примешана какая-та, большей частью бесполезная, информация линкера. Теперь таки вооружившись символьной информацией можно грузить прошивку в IDA. Что делать если символов нету вообще "Когда зубной щетки нет под рукой..." правильно, берем IDA и эмулирующий дебагер и мозги в руки. Эмулирующий отладчик для ARM можно взять тут: http://www.lauterbach.com называется Trace32. IDA - это "must have". Для начала грузим прошивку в IDA на адрес 0. Т.е. всю прошивку грузим на адреса поумолчанию. Дальше смотрим что по адресу 0. BOOT:00000000 B ResetHandler BOOT:00000004 B loc_3B4 BOOT:00000008 B loc_410 BOOT:0000000C B loc_42C BOOT:00000010 B loc_488 и т.д. Код начинается в любом случае с нулевого адреса. Во всех samsung, и как я догадываюсь в не самсугах тоже, прошивка начинается с векторов прерываний. Это 8 команд B в ARM режиме. Т.е. 8 векторов. Адрес 0 - это вектор нулевого прерывания т.е. перезагрузки или старта прошивки. Это нулевое прерывание просто стартует мобилу, соответственно в обработчик должен вести в загрузчик системы: BOOT:00000048 ResetHandler ; CODE XREF: BOOT:loc_0j BOOT:00000048 MRS R0, CPSR BOOT:0000004C BIC R0, R0, #0x1F BOOT:00000050 ORR R0, R0, #0x13 BOOT:00000054 ORR R0, R0, #0xC0 BOOT:00000058 MSR CPSR_cxsf, R0 BOOT:0000005C LDR R3, =(InitialHWConfig+1) BOOT:00000060 MOV LR, PC BOOT:00000064 BX R3 Если прыжок с адреса 0 идет на несуществующий адрес - это означает что остальной код прошивки мапится на какие-то другие адреса. На какие можно довольно легко определить. К примеру есть вот такое начало: BOOT:00000000 B 0x4003CE А кода по адресу 4003CE нет. Смотрим тогда по смещению 3СE. Видим ARM-код. Значит получается что остальная часть прошивки смещена на 0x400000. То есть надо скопировать кусок прошивки с обработчиками перерываний, загрузить их по адресу 0, а дальше грузить прошивку с адреса 400000. Теперь код наместе. Идем дальше. Надо узнать где RAM и область портов ввода вывода. Порты обычно находятся либо в конце (адреса в районе e0000000 и выше) либо в начале памяти (до 0x200000), в зависимости от того куда грузится прошивка. Областей RAM может быть несколько. Первым делом идет инициализация портов: BOOT:00000588 MOV R1, #1 BOOT:0000058A LDR R0, =0xE0006000 BOOT:0000058C LSL R1, R1, #0x1B BOOT:0000058E STR R1, [R0] BOOT:00000590 STR R1, [R0,#0x10] BOOT:00000592 STR R1, [R0,#0x20] BOOT:00000594 LDR R1, =loc_20102 BOOT:00000596 LDR R0, =0xE0003040 BOOT:00000598 STR R1, [R0,#4] BOOT:0000059A LDR R1, =0x20003 BOOT:0000059C STR R1, [R0,#8] BOOT:0000059E LDR R0, =0xE0003000 BOOT:000005A0 MOV R1, #0xC BOOT:000005A2 STR R1, [R0,#0x24] То есть примерно начиная с E0000000 это область портов ввода вывода, размер ее не больше сегмента поэтому можно создать сегмент размером 0x10000. Теперь идем дальше. В любой прошивке есть в RAM область, которая инициализируется нолями и область которая заполняется начальными настройками которые берутся из прошивки. Ищем циклы копирования для этого нам и понадобится дебагер. Вот и копирование: BOOT:000000D4 LDR R0, =0x63B018 BOOT:000000D8 LDR R1, =0x1000000 BOOT:000000DC LDR R3, =0x1045B38 BOOT:000000E0 CMP R1, R3 BOOT:000000E4 BEQ loc_F8 BOOT:000000E8 BOOT:000000E8 loc_E8 ; CODE XREF: BOOT:000000F4j BOOT:000000E8 CMP R1, R3 BOOT:000000EC LDRCC R2, [R0],#4 BOOT:000000F0 STRCC R2, [R1],#4 BOOT:000000F4 BCC loc_E8 Копируется блок из прошивки с адреса 63B018 на 1000000. Длина = 45B38. Это первая область RAM. Теперь ищем вторую, ее инициализация нолями должна быть рядом: BOOT:000000F8 LDR R1, =0x11ED9E4 BOOT:000000FC MOV R2, #0 BOOT:00000100 CMP R3, R1 BOOT:00000104 BOOT:00000104 loc_104 ; BOOT:00000108j BOOT:00000104 BOOT:00000104 STRCC R2, [R3],#4 BOOT:00000108 BCC loc_100 Так и есть, забивают область с 1045B38 по 11ED9E4 нолями вот и вторая часть. Если есть какие-то области, значит будет еще инициализация нолями или копированием. Остальные кусочки памяти можно будет находить только аналитически но основа уже есть. Дальнейшее исследование зависит от наличия символов/сигнатур. Если есть то, все сводится к поиску нужной функции в списке имен. Что делать если нету? Для начала нужно примерно определить пределы кода и по возможности найти в коде функции. Самый примитивный и действенный способ - искать команду push, с которой начинается 60% кода в прошивке. Код прошивки обычно состоит на 90% из Thumb кода так что надо искать байт B5 (push) и пытаться сделать его кодом. Код прошивки обычно занимает менее 50 % размера, дальше идут графика и языковые ресурсы. Еще могу сказать, что очень часто в конце кода встречаются строки копирайтов, типа "Samsung corp 199x-200x ARM ADS 1.2". Кое какой код проявился, где-то 20% будет загажено самой идой, т.к. она часто не справляется с переходом THUMB/ARM. А дальше надо брать то что плохо лежит, т.е. то что оставили программисты. А что они оставили? Оставили Trace и Assert. А любой trace и assert не обходится без sprintf/printf. Надо ее найти. Найти sprintf/printf легко, нужно просто поискать строку "%s". И найти такую которая явно содержит шаблон сообщения об ошибке. По Xref находим где используется эта строка, это как раз будет sprintf, а следующая после нее будет Trace или Assert. Дальше можно исходя из сообщений об ошибках именовать функции, т.е. пройдясь по xref на функцию Trace/Assert можно найти вывод почти половины ошибок. Дальше именовать функции можно сделав поиск следующих слов: Bad Fail Incorrect Invalid Error Memory File Null No Critical Abnormal и т.д. Вы также можете найти еще несколько функций вывода ошибок. Таким образом постепенно обретете информацию не основываясь ни на чем кроме самой прошивки. автор: dem2n