Общее·количество·просмотров·страницы

четверг, 7 февраля 2013 г.

Первый пост в 2013.Продолжаем тему загрузчиков.

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

Инструментарий:
1)ассемблер,си
2)виртуальная машина
3)отладчик bochs
4)winhex
5)daemon tools
6)образ windows
7)ultraiso
8)эмулятор микропроцессора emu8086

Итак целью было написать загрузчик,который перед запуском венды проделывал бы какие то действия в реальном режиме,а после давал запуск венды.Зачем такое ебание мозгов я объясню в конце.

Парился я парился,из-за того что не мог отладить загрузчик с жесткого диска(ведь как мы знаем загрузчик получает управление задолго до запуска операционной системы,а отладчиков такого уровня попросту не существует)и получилось у меня написать загрузчик с дискеты,его работу можно посмотреть вот тут
http://www.youtube.com/watch?v=x99_7sB_hXk
Но так как это меня не устраивало,я решил продолжить работу и все таки заставить запускаться венду с жесткого диска.Алгоритм написания загрузчика у нас таков:

1)Заполнить bios parameter block для файловой системы NTFS (по правильному фс должен определять дроппер и заменять соответствующие байты,но мне во-первых лень,во-вторых почти все венды сейчас работают именно в этой ФС)
2)скопироваться из памяти 0x7c00 в память выше
3)запустить код из этой памяти(а-ля резидент)
4)в запускаемом коде произвести установленные в загрузчике действия
(у нас это выдать сообщение и ожидать нажатия)
5)передать управление загрузчику windows

Алгоритм написания дроппера таков:
1)Захексить бинарник и перенести его в массив
2)Сохранить оригинал загрузочного сектора в другом секторе(обязательно,дальше будет рассказано как сам вендовый загрузчик работает)
3)Спарсить с оригинала таблицу разделов
4)Записать таблицу разделов в массив бинарника
5)записать новый массив в нулевой сектор.

Начнем по порядку.
Заполнение bpb.
Для NTFS он представляет собой следующее

начинаем,делаем все точь в точь как в таблице,при просмотре в хекс-редакторе мы должны получить первые байты такие же как у mbr wndows (проверки на Хрюше)


org 07C00h
jmp short start
nop

oemID dq 'NTFS    '
bytespersector dw 512
sectorsperclaster db 8
reserved_sectors dw 2
db 0,0,0
dw 0
db 0F8h
dw 0
dw 0
dw 0
hidden dd 0
dd 0
dd 0
dq 0
dq 2
dq 0
dd 0
dd 0
dq 0
dd 0
что у нас тут происходит: первая команда джамп и ноп для 3 байт перехода.далее заполнение BPB по таблице.Тут ничего не надо говорить, акцентирую внимание на том что ОЭМ идентификатор всегда 8 байтовый должен быть.

Далее все по стандарту для загрузчика,настройка сегментов:


start:
       cli                
       xor ax,ax           
       mov ss,ax
       mov sp,7c00h       
       mov si,sp  
       push ax
       pop es 
       push ax
       pop ds
       
       sti   
       cld


тут опять же все по стандарту,отключаем прерывания что бы ничего не "повесить", сегмент стека ставим в 0 и потом в 7c00h после чего получаем сегмент:смещение 0000:7с00 , включаем прерывания и очищаем флаг направления.

Дальше идет довольно важный момент из-за которого я тоже немного затормозился в написании-копирование себя в верхнюю память.Это нужно для того что бы по старому адресу ничего не было когда мы будем туда передавать управление,иначе мы будем затирать сами себя своим же кодом и в итоге провал.


     push dx      
     mov di,0600h    
     mov cx,100h     
     repnz movsw                          
     jmp     0000:0672h  

в чем тут подвохи:
первое с чего я охренел это куда писать наш сектор,потому что как вы знаете есть логический и физический диск,и что откуда грузится без отладки мне было пока не ясно,вот винхекс нам это показывает:
Путем тыкания было установлено что запись все же следует проводить в физический диск.
С самого начала я забыл запушить dx (туда кладется номер первого диска найденного биосом) и конечно начал не понимать какого хрена не происходит загрузка,потом я записал его в прерывании,но ввиду того что где то в коде регистр очищался,загрузка опять проваливалась соответственно.По этому для лучшей безопасности я решил его запушить и восстанавливать в прерывании,так ничего никуда точно не исчезнет.Далее почему мы копируемся в 0600h- ну во-первых нам надо скопироваться в память выше размером > 200h (размер сектора),а во вторых-я посмотрел что так делает mbr windows и решил тоже спиздить этот участок памяти :D. копируем 256 слов иными словами 512 байт,и передаем управление в память по этому адресу.Вот тут то и случилась подстава номер два: нельзя просто прыгать на метку,потому что в зависимости от кода в метке-смещается адрес.Слеш сказал надо отнимать адрес старта+адрес памяти куда копируемся,парился парился-нихрена не работало,и тут мне пришло в голову в emu его прогнать,вот он то меня и спас,всегда надо смотреть адрес прыжка в отладчике,это 100% надежность что вы не промажете:

хорошо,мы скопировались,теперь можем выполнять код который захотим.


read:
          mov ax,03
          int 10h


          mov ah,13h
          xor al,al
          mov bx,00001010b
          xor dx,dx
          mov cx,msgend-msg
          call msgend

msg db 'Do u really wanna boot ur fucking windows?..ok press any key to do this'
msgend:
          pop bp
          int 10h


          xor ax,ax
          int 16h


тут ничего особенного,включаем видео режим, задаем атрибуты цветов и сообщение-выводим на экран и ожидаем нажатие клавиши.

когда клавиша нажата,будет выполняться следующий код:


           mov ax,0201h
           mov bx,7c00h
           mov cl,10
           pop dx
           int 13h
           jmp far 0000:7C00h

а именно-чтение сектора.Я захотел скопировать mbr windows в 9 сектор,вы можете копировать в любой(лучше от 2 до 63).Хотя правильнее было бы искать чистый сектор на ЛОГИЧЕСКОМ диске и записывать его туда,потом преобразовывать в физический и оттуда вычитывать,но лень,и так сойдет.

Тут опять параша: сначала я делал просто джамп на адрес-загрузки не было.засунул в эму- показал левый адрес,так как фасм единственный компилятор,нормально переваривающий длинные прыжки,то все решилось добавлением банального far.Тут с загрузчиком покончено.Сверим заголовки в секторе windows и нашем:
как видим все совпадает.

Переходим к части на Си.Я думал сделать на делфи,но решил что раз я начал осваивать си,то сделаю на си.
Возникли некоторые трудности с визуал студио,настроенной по статье Слеша,по этому я использовал не менее хорошую на мой взгляд IDE Pelles C поддерживаемая Пелле Ориниусом.Рассказывать про нее я не буду,все гуглится.

Итак по алгоритму, хексим наш бинарник.в винхексе есть такая замечательная штука,позволяющая скопировать блок сразу в исходник на С.

(подсветило паскаль-си на строку выше).Получаем что то вроде этого:

0xEB, 0x52, 0x90, 0x4E, 0x54, 0x46, 0x53, 0x20, 0x20, 0x20, 0x20, 0x00, 0x02, 0x08, 0x02, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xF8...

Дальше нам надо переместить сектор mbr с ФИЗИЧЕСКОГО диска с 0 в 9 сектор.
(все на апи)


hout=CreateFile(TEXT("\\\\.\\PhysicalDrive0"),GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);


    ReadFile(hout,&buf,512,&nr,NULL); 

    SetFilePointer(hout,9*512,NULL,FILE_BEGIN); 

    WriteFile(hout,&buf,512,&nw,NULL); 



тут все просто-что бы читать\писать сектора в венде,достаточно открыть диск как файл. мы указываем physicaldrive0 то есть 1-й ФИЗИЧЕСКИЙ диск в системе,если мы хотим издеваться над логическим диском,то пишем просто букву диска,например: \\\\.\\C: в таком плане.
далее читаем мбр-переходим в сектор 9 и там его записываем.

Теперь надо спарсить таблицу разделов.Зачем спрашивается?-Поясню, отлаживая mbr windows, я заметил странную штуку-он ищет что то по смещению 1BEh в ПЕРВОМ секторе,пошарив в нете я нашел структуру загрузочного сектора:
то есть он искал там таблицы разделов.значит нам надо спарсить последние 66 байтов mbr windows.На самом деле это упрощенная схема mbr так как есть еще extended pt так называемая расширенная таблица разделов,вы видите что разрешается 4 таблицы разделов,но наверняка видели намного больше разделов,создаваемых спец. программами.вот это и есть EPT. ну нам для чистоты исследования хватит и такого.

        SetFilePointer(hout,9*512,NULL,FILE_BEGIN);

ReadFile(hout,&buf,512,&nr,NULL);

for(i=446;i<=512;i++)
{
mbr[i]=buf[i];
}

переходим на сохраненный в 9 секторе mbr. Я долго искал возможно ли прочитать сектор "по кусочкам" как говорится- в мсдн четко указано-апи функции читают\пишут сектора только размером КРАТНЫМ СЕКТОРУ т.е. 512,1024 и т.д., но не меньше.по этому читаем все 512 байтов в буфер,в цикле из одного массива,заменяем в наш бинарник-массив последние 66 байтов.


SetFilePointer(hout,0,NULL,FILE_BEGIN); 

WriteFile(hout,&mbr,sizeof(mbr),&nw,NULL);
переходим на смещение 0x00 и записываем видоизмененный массив бинарника в качестве mbr windows.ВСЕЕЕ!!! ее!)
можно посмотреть на его работу вот тут:
http://www.youtube.com/watch?v=5sC5o_yeoek&feature=youtu.be
.

Теперь я расскажу вам о отладке mbr в отладчике бош.
Что хочу сказать сразу-отладка крайне неудобная,бош работает крайне медленно,но каких то альтернатив я и не знаю.пробовал мучаться с идой и плагинами на питоне,но что то не получилось.
Ну во первых,поставить венду на бош вам скорее всего не удасться,по меньшей мере я пытался-не получилось,он застопорялся на распаковке файлов уже в gui режиме.
По этому лучше создать образ windows уже установленной.я его не создавал,а просто скачал на 4pda.ru (при желании гуглится).Смотрите на совместимость с бошем.
Дальше я только расскажу как все настроить и приступить к отладке.
запускаем бош,видим настройки.Пройдемся по порядку:

1)CPU
-cpu configuration- bx_generic
-emulated instructions per second 10 000 000
enable CPU reset- да
inore RDMSR- да

2)MEMORY
standart options:
- memory size (megabytes) -1
-host allocated memory size - тут устанавливаете столько,сколько можете себе позволить.Лично я установил гигабайт.

дальше до disc & boot я ничего не менял, т.к. не требуется

3) DISC & BOOT
ata channel 0:
first hd/cd on channel 0:
-enable this device - да
-type of ata device - disk
-path or physical device  name - тут путь к образу венды
-type of disk image- flat
на счет геометрии диска- сложно сказать, попробуйте поменять type of disk image на sparse если не будет запускаться,так я указал рандомное число С|H|S и при запуске просто жал continue simulation.

second hd/cd on channel 0- тут я советую вам подключить дисковод с нужными программами, что бы создать образ просто запихните папку с программами в ultra iso и сохраните образ.
тут все просто
-enable this device- да
-type of ata device- cdrom
-path- путь к образу с программами.
-inserted- да

после всех настроек сохраните конфигурационный файл и поместите в папку с бошем.
отладка у боша консольная-это конечно ужасно. теперь что бы запустить отладчик наберите в командной строке bochsdbg.exe -q -f bochsrc.bxrc где bochsrc это ваш конфигурационный файл.
увидите примерно следующее:

дальше с помощью команды help можно узнать в деталях о том какая команда что делает.
для отладки mbr пишем lb 0x7c00 что поставит брэйкпоинт на загрузку и cont что продолжит выполнение кода,до точки останова.дальше трассирующими командами и командами просмотра регистров,флагов etc мы и отлаживаем наш загрузчик(или любой другой).
Как выглядит отладка:
На этом все друзья.
Большой опыт полученный от всего этого можно применить как для создания буткитов так и для написания своей операционки либо отладки чужого кода и еще много много всего.
Всем удачного кода.


ПОСТ СКРИПТУМ я выполнил хорошую работу и гордо иду пить пиво и смотреть фильм с Милой Йовович и Сиенной гиллори
ПОСТ СКРИПТУМ 2
Поросенок Петр съябует из этой страны