В этом посте продолжение разбора микропрограммы жесткого диска WD21000. Этот жесткий диск выбран для демонстрации повторения платы электроники на современной элементной базе. Чтобы это сделать нужно подробнейшим образом разобрать его программу управления в дизассемблере IDA.
Так что продолжаем разбор программ.
В прошлый раз мы смотрели команду 0xEC. Вот она:
И сейчас интересно вот что посмотреть… У жесткого диска есть микросхема ОЗУ непосредственно подключенная к процессору. В этой микросхеме расположен сегмент данных, а также явно какой-то оверлей. Вот обращения к нему просматриваются в коде:
Хорошо бы понять, что именно это за оверлей и считать его из оперативной памяти.
Для начала нужно выдвинуть какие-то гипотезы, каким образом диск может позволять через технологический режим обращаться к сегменту данных/оверлею.
Автор предположил, что выдача данных наружу командой чтения будет производиться при помощи той же самой функции, что и в комане 0xЕС. То есть, команда 0xЕС один сектор отдает и, соответственно, эта предполагаемая технологическая команда, скорее всего, отдает данные в через ту же функцию. Нужно эту гипотезу проверить.
Если присмотреться, то вот эта функция из команды 0xEC, возвращает АТА сектора хосту принимает два параметра ВХ и АХ.
В АХ здесь передаются просто нули, а в ВХ передается размер — 0x200 шестнадцатиричных байт или 512 байт. То есть, фактически, эта функция возвращает один сектор.
Давайте посмотрим список всех ссылок на на вызов этой функции, который открывается при нажатии клавиши «x».
Нам нужно сделать обзор всех этих мест.
Начнем с первой. Смотрим ее.
Здесь видно тоже, что возвращается один сектор. Листаем вверх, чтобы посмотреть что это может быть за команда. Это команда 0xАD.
Ранее я разобрал всю таблицу команд, чтобы посмотреть какая из них какая.
Что за команда 0xАD мы пока не будем изучать, видно, что она формирует один сектор и его возвращает. Идем по второй ссылке. Открывается тоже какая-то команда — 0xЕ9.
Это, по всей видимости, стандартная команда и она не технологическая, скорее всего в ней ничего интересного.
Посмотрим третью ссылку.
Это у нас стандартная команда Е4 — читать/писать сектор.
Четвертая ссылка — команда ЕС.
По пятой ссылке находится уже более интересная команда.
Она тоже возвращает один сектор, но в АХ попадают данные из наших регистров АТА команды. Фактически, размер ВХ прибит гвоздями, то есть он всегда возвращает один сектор, а АХ, по всей видимости, адрес или что-то на это похожее. Эта команда явно отдает какие-то сектора из памяти, а потому похожа на то, что мы ищем.
Я проверил эту команду и обнаружил, что в ней нет никаких данных, которые касаются микропрограммы, так что она передает не сегмент данных, а память кэширования секторов. Но то, как эта функция используется, уже интересно. А именно — то, что в один из параметров передаются регистры от АТА команды. Теперь наша задача проверить, а есть ли команда, в которой оба параметра этой функции берутся из регистра?
Смотрим шестую ссылку.
А вот здесь интересно.
Здесь несмотря на то, что в АХ передается ноль, в этом месте используются сразу 4 байта из АТА команды, передаваемой из компьютера. Это 4й и 5й регистр, то есть младший цилиндр и старший цилиндр, 2й и 3й — количество секторов и номер сектора. При этом видно, что они идут парами и образуют два шестнадцатиразрядных параметра в функцию sx_ret_ATA_sectors.
Причем здесь интересно, что количество (регистр ЕВХ) по функции and объединяется с FFFE потому, что это 16-битная операция. Получается, что функция sx_ret_ATA_sectors может отдавать только слова. То есть байты она не может отдавать потому, что младший бит количества будет всегда ноль.
Теперь интересно, а что это за команда такая. Видно, что есть два варианта ее вызова в зависимости от 7го бита регистра СХ.
Если он сброшен, то идем по ветке loc_8808.
По ней выполняется какой-то цикл копирования.
Смотрим дальше. У нас есть точка входа в команду loc_87F6 .
Смотрим куда она нас ведет. Фактически это команда Е1.
При этом, если сброшен бит 6, то мы попадаем сразу не в ту точку входа, по которой мы только что пошли, а в еще одну — loc_87EA.
В этот кусочек всего две точки входа. Если в первой точке входа значение первого регистра 0 (это регистр feature, в спецификации называется set features) и в ЕАХ мы загрузили значение этого же регистра и убрали у него два старших бита.
В команде loc_87F6 очищается ЕСХ, ему передается 0, это означает, что вот эта ветка
пойдет через вот эту функцию
В команде loc_87EA мы помним, что в АХ лежит АТА регистр+1. Здесь мы его сравниваем с единичкой
если значение больше 1 мы перепрыгиваем сюда
То есть сразу на выход идем — lc_factory_exit. Это означает, что у нас в этом регистре может быть только 0 или 1. Соответственно, если равно единице, то мы идем вот сюда
по второй ветке.
Но там много всего происходит, пока не будем смотреть.
Если же равно 0, то идем по первой ветке, которая продолжается где loc_87F6. В ЕВХ полностью загружаются 2й, 3й, 4й, 5й регистры. Так как
ЕСХ здесь очищен и обнулен, соответственно, то мы всегда будем выполнять функцию sub_512А.
А здесь видно, что у нас ЕАХ и ЕВХ как параметры этой функции используются. То есть достаточно плотно это все происходит. Скорее всего эта функция sub_512А что-то копирует. Собственно у нас есть одна очень подходящая функция на то, что нам нужно.
Давайте посмотрим другие вызовы. Смотрим седьмую ссылку.
Здесь не очень похоже что идет работа с АТА регистром.
Вот первый регистр, который здесь встречается ide_p6p1 в 88СЕ, он здесь всего один и используется как флаги.
Что-то довольно сложное. Предыдущая функция довольно простая. Пришли какие-то значения в регистр и сразу пошли на выполнение, а в этой какая-то кухня, причем если внимательно посмотреть — здесь выдается зонная таблица, которая лежит в ПЗУ.
Последняя восьмая ссылка. И у нас здесь какая-то странная таблица, просто все функции перечислены.
Получается, что у нас всего один кандидат. Это шестая ссылка — команда Е1. У нее в +1 регистре должен быть 0. А, соответственно, 2й, 3й, 4й, 5й регистры содержат какие-то параметры.
Переходим теперь в PC-3000 и будем щупать, что же это за параметры такие. Открываем в PC-3000 АТА Commander.
Подаем питание на жесткий диск.
После того, как он запустился подаем команду 0xЕС.
Вот наш паспорт.
Подаем техноключ.
Еще раз смотрим паспорт. При этом у нас появились значения, которые при техноключе отдаются.
И вот наша команда 0xE1.
Как мы помним, регистр +1 у нас 00, +2, +3 содержат какое-то число, допустим зададим первое и второе число 10. Эта команда с забором данных. Подаем ее.
У нас что-то прочиталось.
Причем, прочиталась 10 шестнадцатиричная байт. То есть первая цифра у нас – счетчик байтов. Соответственно, давайте сделаем так, чтобы оно один сектор возвращало.
Еще раз подаем и видим, что команда вернула сектор.
То что это счетчик мы угадали правильно. Что такое вторая цифра? Установим на ней не 10, а 00.
Подаем команду, ответ:
Видно, что выдаваемый сектор сдвинулся — появилась еще одна строчка. Значит вторая цифра задает смещение в байтах. Самое интересное у нас находится с 8000. Посмотрим что там.
Там лежит какая-то таблица.
Причем, если указать не один сектор, а всю вторую половину сегмента данных, то команда отдаст 32 килобайта и отобразит их. Оверлей у нас находится как раз с адреса 8000 и до конца.
В этих данных можно увидеть версию микропрограммы.
Серийный номер.
Он находится в служебной зоне, но никак не в ПЗУ. Еще есть участки с множеством нулей. То есть это явно сегмент данных потому, что ПЗУ, как мы знаем, иначе выглядит. Сейчас мы все это сохраним в файл вот этой кнопкой.
Далее подключим к дизассемблеру и посмотрим что это за данные. У меня уже есть во вкладке Programm Segmentation заготовка под сегмент данных.
Сюда загружаем наш файлик File → Load file → Additional binary file.
Вот он наш считанный сегмент.
Указываем нужные настройки.
Данные загружаются. Теперь давайте пойдем в команду чтения паспорта.
Вот они команды 0xЕx.
Далее:
Здесь есть функция формирования ID сектора.
Просмотрим ее и найдем участок, где выдается серийный номер.
Это 20 байт или 10 слов. Переходим в процедуру sub_40D9, которая копирует серийный номер с попарной перестановкой байт, как это требует АТА спецификация.
Теперь перейдем по адресу #unk_922А и попадем в сегмент кода.
В нем ничего нету, а вот что будет у нас в сегменте данных?
Давайте изменим адрес, добавив к нему единицу в начале и запишем его как комментарий по нажатию «;».
Теперь наш комментарий указывает на сегмент данных.
Нажимаем Enter на комментарии в открывшемся адресе прямо видно серийный номер.
То есть получается, по этой ссылке #unk_922A у нас берется адрес в ОЗУ, где он считан уже из служебной зоны и функция sub_40D9 ее выдает. Если служебка не читается, то серийный номер жесткий диск не отдает. Это все доказывает, что мы считали именно наш сегмент данных. А теперь интересно, а что там с оверлеями?
Вернемся к команде lc_cmd_EC нажав ESC.
Там дальше явно идет вызов в оверлей.
Раньше там было пустое место, а сейчас что там? Заходим нажав Enter и там код появился. Нажимаем букву «С» и есть переход на возврат.
Видно, что здесь код осмысленный. Функция unk_190CC вызывается и тут же возвращается. То есть у нас оверлей фактически подключился.
Кратко резюмируем что у нас вышло: у нас была выдвинута гипотеза о том, что сегмент данных микропрограмма отдает через ту же самую функцию, что и чтение паспорта и эта гипотеза подтвердилась. Но гипотеза читается ли через эту функцию служебная зона показала, что читается не через нее. То есть служебная зона у диска отдается другим способом, не таким, как чтение паспорта. Это интересно. В какой-нибудь из следующих статей попробуем найти в коде программы именно чтение служебной зоны.
А теперь, все то же самое, только кино:
А на сегодня все. До новых встреч!
Интересно, чем все закончилось? У самого есть подобный диск который время от времени запускается. Прочитал все посты, но видимо автор от этой темы подустал… жаль…
Нет, автор работает над постами по теме электроники жесткого диска и дизассемблировании. Подобных дисков для опытов получилось найти достаточно. В ближайшие дни будет продолжение.