Методы сокрытия вирусного кода.

Тема в разделе "Статьи", создана пользователем rijy, 20 июн 2007.

  1. rijy
    rijy Новичок
    Симпатии:
    33
    Упаковка
    Упаковка заключается в сжатии исполняемого файла и прикреплении к нему кода, необходимого для распаковки и исполнения. Упаковка как метод сокрытия представляет собой довольно грозное оружие. Достаточно привести пример: грамотно упакованный червь способен вызвать не менее серьезную, чем его первообраз, эпидемию — ведь такой червь распознается антивирусами как новый экземпляр. Не секрет, что большинство из ныне присутствующих в Сети вредоносных программ суть не что иное, как модификации посредством упаковки. Пример — широко известный троян Backdoor.Rbot, который распространяется упакованным множеством различных пакеров (Ezip, Exe32Pack, ExeStealth, PecBundle, PECompact, FSG, UPX, Morphine, ASPack, Petite, PE-Pack, PE-Diminisher, PELock, PESpin, TeLock, Molebox, Yoda, Ezip, Krypton и др.). Когда антивирусу попадается упакованный файл, он его, понятное дело, пытается распаковать. Получается, что с чем большим числом упаковщиков способен работать антивирус, тем больше у него шансов обнаружить упакованный код. Поддержка большого числа разновидностей упаковщиков и архиваторов особенно критична для проверки почтовых систем, так как подавляющая часть вирусов пересылается по почте в архивированном виде. Читателю наверняка станет интересна разница между архиватором и упаковщиком — а разница в том, что упакованное пакером разжимается в память, а архиватором — на диск. Понятно, что добраться до упакованного кода можно лишь распаковав его. Но и это не всегда просто. Давайте посмотрим, почему.
    Распаковщики делятся на динамические и статические. Динамические распаковщики (например, procdump или PEiD) запускают файл и создают распакованный вариант файла из образа, загруженного в память. Однако в случае, если этот файл содержал вирус (а он его содержит!), система может быть повреждена раньше, чем антивирус успеет что-либо сделать. Кроме того, у упаковщиков существует ряд приемов борьбы с динамической распаковкой: например, расшифровывать код не полностью, а лишь по мере исполнения, или, например, расшифровывать и запускать вирус целиком только в определенный день недели. Статические распаковщики — это те, которые пытаются распаковать файл, не запуская его (например, CUP386 или UNP). Очень часто статические распаковщики оказываются бесполезны, если алгоритм упаковки требует запуска файла. Для того, чтобы представить себе весь размах упаковки, достаточно привести этот скромный список упаковщиков, или, по-другому, пакеров, применяемых при сокрытии вирусного кода:
    Код:
    EP (ExE Pack) — v.1.4 lite final 
    ACProtect — v.1.32 Professional 
    Active PE Scrambler — v.1.0 
    AHTeam EP Protector — v.0.3 Private 
    AHTeam Punisher — v.1.5.Public 
    AHTeam UPX Mutanter — v.0.2 Private 
    Alex Protector — v.1.0 beta 2 
    Armadillo — v.4.00.0053 (Custom Build) 
    Armadillo — v.4.40 (Public Build) 
    Armadillo — v.4.40.0250 (Custom Build) 
    Armadillo — v.4.44 (Public Build) 
    Armadillo — v.4.48 (Public Build) 
    Armadillo — v.2.00 
    Armadillo SPS — v.1.90 
    ASPack — v.2.12 
    ASProtect — v.1.1 
    ASProtect — v.1.2 
    ASProtect — v.1.33 build 03.07 Release 
    ASProtect — v.1.35 build 04.25 Release 
    ASProtect — v.1.35 build 06.26 Release 
    ASProtect — v.1.35 build 06.26 Release (Purchased) 
    ASProtect — v.2.1 build 02.19 Release 
    ASProtect SKE — v.2.2 build 03.05 
    ASProtect SKE — v.2.3 build 03.19 Beta 
    ASProtect SKE — v.2.3 build 04.23 Beta 
    ASProtect SKE — v.2.3 build 06.26 Beta 
    aUS [Advanced UPX Scrambler] — v.0.5 beta 
    Beria — v.0.07 Public 
    DEF — v.1.0 + src 
    Enigma Protector — v.1.02 
    Exe Stealth — v.2.73 
    Exe32Pack — v.1.42 
    EXECryptor — v.2.2.6 
    EXERefactor — v.0.2 
    eXPressor — v.1.4.5.1 
    Fake Ninja — v.2.6 
    fileEncrypt — v.0.2a 
    FSG — v.2.0 
    FSG — v.2.0 Plus 
    GPcH Protect — v.1.0 
    Hide PE — v.1.1 
    HidePX — v.1.4 
    hyings PE-Armor — v.0.74 
    JDPack — v.1.01 
    KByS Packer — v.0.28 beta 
    kkrunchy — v.0.23 alpha 
    Krypton The Krypter — v.0.5 
    Mew 11 SE — v.1.1 
    MoleBox Pro — v.2.5.13.2201 Retail 
    MoleBox Pro — v.2.5.7.2164 Retail 
    Morphine — v.2.7 
    Morphine — v.3.3 
    mPack — v.0.0.2 
    MSLRH — v.0.31a 
    nPack — v.1.1.200.2006 Beta 
    NsPack — v.2.3 
    Obsidium — v.1.2.5.0 
    ORiEN — v.2.12 Registered 
    Packman — v.0.0.0.1 
    PC Guard — v.4.06 
    PE Diminisher — v.0.1 
    PECompact — v2.70 RC1 
    PELock — v.1.06 
    PEQuake — v.0.06 
    PESpin — v.1304 
    PeStubOEP — v.1.6 
    Petite — v.2.3 
    PeX — v.0.99 
    PoPa — Packer on Pascal 
    Private exe Protector — v.1.9.5 
    PseudoSigner — v.0.2 
    RLP — v.0.7.4 beta 
    SDProtector Pro — v.1.16 
    SEPP (Special EXE Password Protector) — v.1.0 
    SHProtector 
    ShrinkWrap — v.1.4 
    SLVc0deProtector — v.1.12 
    Spirits PE Crasher — v.2.1 
    Stealth PE — v.2.0 
    tElock — v.0.98 Special Build 
    tElock — v.0.99 
    Themida — v.1.5.0.0 (Custom Build) 
    Themida — v.1.7.3.0 
    TPPpack 
    TrueEP — v.0.1 
    Unopix — v.1.04 beta 
    UPX — v.1.93 beta 
    UPX — v.2.00 
    UPX — v.2.01 DOS 
    UPX — v.2.01 WIN 
    UPX-Scrambler + 
    VB AntiCrack — v.1.1 
    VMProtect — v.1.22.2 
    WinUpack — v.0.39 Final 
    WinUpack — v.0.399 
    yoda Crypter — v.1.3 
    yoda Protector — v.1.03.3 
    [G!X]s Protector — v.1.2
    Если кому-то из читателей этот список покажется большим, поспешу успокоить: это всего лишь десятая часть того, что применяется в настоящее время… Очень часто для того, чтобы запутать антивирус и сделать так, чтобы тот не смог распознать, чем запакован код, вирус дополнительно пропускают через утилиты типа PEiD, основной задачей которого является изменение точки входа в программу, но об этом более подробно в разделе «обфускация».

    Полиморфизм
    Полиморфизм — техника, позволяющая затруднить обнаружение вируса с помощью скан-строк (сигнатурное сканирование) и, возможно, эвристики. Вирус, использующий такую технику, называется полиморфным. Говоря простым языком, под полиморфизмом вируса понимается существование одного вируса в нескольких формах. Полиморфизм заключается в формировании кода вируса на лету — уже во время исполнения, при этом сама процедура, формирующая код, также не должна быть постоянной и видоизменяется при каждом новом заражении. Обнаружение по-настоящему полиморфных вирусов с помощью скан-строк невозможно. После появления полиморфизма антивирусные продукты, в свою очередь, также освоили новые техники: эвристика и эмуляторы кода. Первый известный полиморфный вирус был написан Марком Вашберном (Mark Washburn). Вирус, который назывался 1260, был создан в 1990 году. Более известный полиморфный вирус был внедрен в 1992 году болгарским взломщиком Dark Avenger (псевдоним), создавшим MtE (Mutation Engine). Один из самых простых способов реализации полиморфизма — побайтное шифрование основной части вируса операцией xor:
    Код:
    mov cx, code_length 
    mov si, offset begin_code 
    mov al, xor_key 
    _loop: 
    xor [si+cx], al ;расшифровываем байт 
    loop _loop ;берем следующий байт 
    jmp si 
    ;... 
    ;... 
    begin_code: 
    ;тут находится зашифрованная часть тела вируса 
    ;именно она ответственна за заражение новых файлов 
    ;и формирование новой процедуры расшифровки 
    ;при этом эта же часть тела вируса в новом файле должна быть заново 
    ;зашифрована, но уже с другим ключом 
    
    В качестве примера полиморфного вируса уместно привести описание следующего: Virus.Win32.Zombie представляет собой сложный полиморфный вирус. Использует уникальную технологию встраивания в файлы: вирус «разбирает» (дизассемблирует) PE EXE-файл на составные части, встраивает свой код и собирает заново, перемешивая при этом свой код и код заражаемого файла. Virus.Win32.Zombie использует уникальную технологию декриптования своего тела для обхода эвристических анализаторов.

    Обфускация
    Обфускация (от лат. obfuscare, «затенять, затемнять») — запутывание кода программы, то есть приведение исходного текста или исполняемого кода к виду, сохраняющему функциональность программы, но затрудняющему анализ, понимание алгоритмов работы и модификацию при декомпиляции. «Запутывание» кода может осуществляться на уровне алгоритма, на уровне исходного текста или ассемблерного текста. Для создания запутанного ассемблерного текста могут использоваться специализированные компиляторы, использующие неочевидные или недокументированные возможности среды исполнения программы. Существуют также специальные программы, производящие обфускацию, называемые обфускаторами (англ. Obfuscator). В контексте сокрытия вирусного кода суть метода заключается в том, чтобы запутать программный код и устранить большинство логических связей в нем, делая код максимально неузнаваемым для антивирусного ПО. Пример абфускации кода: Исходный текст:
    Код:
    int COUNT = 100; 
    float TAX_RATE = 0.2; 
    for (int i=0; i<COUNT; i++) 
    { 
    tax = orig_price * TAX_RATE; 
    price = orig_price + tax; 
    } 
    
    Код после обфускации: 
    
    for(int a=0;a<100;a++){b[a]=c[a]*0.2;d[a]=c[a]+b[a];} 
    
    И еще один пример(Perl): 
    
    my $filter; 
    
    if (@pod) { 
    my ($buffd, $buffer) = File::Temp::tempfile(UNLINK => 1); 
    print $buffd ""; 
    print $buffd @pod or die ""; 
    print $buffd 
    close $buffd or die ""; 
    @found = $buffer; 
    $filter = 1; 
    } 
    exit; 
    
    sub is_tainted { 
    my $arg = shift; 
    my $nada = substr($arg, 0, 0); # zero-length 
    local $@; # preserve caller's version 
    eval { eval "#" }; 
    return length($@) != 0; 
    } 
    
    sub am_taint_checking { 
    my($k,$v) = each %ENV; 
    return is_tainted($v); 
    } 
    


    После обфускации:
    Код:
    sub z109276e1f2 { ( my $z4fe8df46b1 = shift ( @_ ) ) ; ( my 
    $zf6f94df7a7 = substr ( $z4fe8df46b1 , 
    (0x1eb9+ 765-0x21b6) , (0x0849+ 1465-0x0e02) ) ) ; local $@ ; 
    eval { eval ( ( 
    "" ) ) ; } ; return ( ( length ( $@ ) != (0x26d2+ 59-0x270d) ) ) 
    ; } my ( $z9e5935eea4 ) ; if ( @z6a703c020a ) { ( my ( 
    $z5a5fa8125d , $zcc158ad3e0 ) = 
    File::Temp::tempfile ( "" , (0x196a+ 130-0x19eb) ) ) ; print ( 
    $z5a5fa8125d "" ) ; ( print ( $z5a5fa8125d @z6a703c020a 
    ) or die ( ( ( ( "" . $zcc158ad3e0 ) . "\x3a\x20" ) . $! ) ) ) ; 
    print ( $z5a5fa8125d "" ) ; ( close ( $z5a5fa8125d ) or die ( ( ( 
    ( "" ) ) ) ; ( @z8374cc586e = $zcc158ad3e0 ) ; ( $z9e5935eea4 = 
    (0x1209+ 1039-0x1617) ) ; } exit ; sub z021c43d5f3 { ( my ( 
    $z0f1649f7b5 , $z9e1f91fa38 ) = each ( %ENV ) ) ; return ( 
    z109276e1f2 ( $z9e1f91fa38 ) ) ; }
    Как видим, в простейшем случае процедура обфускации заключается в переделке кода в нечитаемое (но рабочее) состояние. Это примеры высокоуровневой обфускации «мирного назначения». Если же ее экстраполировать на вирусный код, то изменится не многое, разве что при маскировке вирусного кода используют в большинстве случаев низкоуровневую обфускацию (с использованием команд ассемблера) + программы для автоматической обфускации — например, Afx!AVSpoffer, EPProt и PETools. Технология обфускации может подразумевать следующие процедуры:
    . Порча и/или изменение таблиц импорта, экспорта и переадресации.
    . Маскировка оригинальной Entry Point (точка входа в программу).
    . Использование полиморфного варианта распаковки.

    (с)sinlab.3bb.ru​
     
    20 июн 2007
  2. Хел
    Хел Guest
    оч полезная инфа. интереснее былоб узнать о полиморфизме побольше)
     
    20 июн 2007
  3. rijy
    rijy Новичок
    Симпатии:
    33
    продолжение...

    вот еще на ту же тему:

    Руткит-технологии
    Термин Rootkit (руткит, от англ.: «root kit», то есть «набор для получения прав root») есть не что иное, как программа или набор программ для скрытного взятия под контроль взломанной системы. Термин Rootkit исторически пришел из мира UNIX, и под ним понимается набор утилит или специальный модуль ядра, которые взломщик устанавливает на взломанной им компьютерной системе после получения первичного доступа. Такой набор, как правило, включает в себя разнообразные утилиты для получения прав root (отсюда и название), для заметания следов вторжения в систему, сниферы, сканеры, регистраторы нажатия клавиатуры или кейлоггер (от англ.: «keylogger»), троянские программы, замещающие основные утилиты UNIX (в случае неядерного руткита). В контексте сокрытия вирусного кода под rootkit принято подразумевать такой код, который, будучи внедренным в систему, способен перехватывать системные функции (Windows API). Нетрудно догадаться, что перехват и модификация низкоуровневых API-функций, в первую очередь, позволяет такой программе достаточно эффективно маскировать свое присутствие в системе. Кроме того, как правило, rootkit может маскировать присутствие в системе любых зависимых от него процессов, каталогов и файлов на диске, ключей в реестре. Упрощенно все RootKit технологии сокрытия можно разделить на две категории:
    Модификация таблицы импорта. Данная методика сокрытия является одной из классических. Идея метода заключается в том, что RootKit находит в памяти таблицу импорта исполняемой программы и корректирует адреса интересующих его функций на адреса своих перехватчиков. Кажется, все достаточно просто… В момент вызова API-функции программа считывает ее адрес из таблицы импорта и передает по этому адресу управление. Поиск таблицы импорта в памяти несложен, поскольку для этого уже известны специализированные API-функции, позволяющие работать с образом программы в памяти. Данная методика достаточно универсальна, к тому же, она проста в реализации, но у нее есть существенный недостаток — при таком механизме перехватываются только статически импортируемые функции.

    Модификация машинного кода прикладной программы. Как следует из названия, суть метода заключается в модификации машинного кода, отвечающего в прикладной программе за вызов той или иной API-функции. Реализация методики достаточно сложна, и обусловлено это тем, что существует множество языков программирования и версий компиляторов, к тому же, реализация вызовов API-функций может быть различна.

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

    Перехват функций LoadLibrary и GetProcAddress. Это чаще всего выполняется путем модификации таблицы импорта: если перехватить GetProcAddress, то при запросе адреса можно выдавать программе не реальные адреса интересующих ее функций, а адреса своих перехватчиков. При вызове GetProcAddress она получает адрес и выполняет вызов функции.

    Перехват функций в режиме ядра (kernel mode). Для того, чтобы понять суть метода, будет полезным рассмотреть принципы взаимодействия библиотек user mode и kernel-mode. Базовое взаимодействие с ядром осуществляется посредством ntdll.dll, большинство функций которой обращаются к ядру через прерывание INT 2Eh. Дальнейшее обращение к функциям ядра базируется на структуре, именуемой KeServiceDescriptorTable (сокращенно SDT), расположенной в ntoskrnl.exe. SDT представляет собой таблицу, содержащую адреса точек входа сервисов ядра NT. Грубо говоря, можно сказать, что для перехвата функций необходимо написать драйвер, который и произведет модификацию таблицы SDT. Перед модификацией драйверу необходимо сохранить адреса перехватываемых функций и записать в таблицу SDT адреса своих обработчиков. Данный метод часто называют перехватом Native API, и работает он на NT-линейке (W2K, XP, W2003).

    «Protected Mode — там, где тепло и сухо…»
    А почему бы не создать вирус, работающий в защищенном режиме процессора?.. Действительно, обнаружить такой вирус антивирусной программе будет, мягко говоря, ну очень трудно… Одним из ярких примеров такого вируса является, пожалуй, файловый вирус PM.Wanderer, использующий защищенный режим. Он отличается тем, что способен корректно работать и взаимодействовать с другими кодами, выполняющимися в защищенном режиме. Являясь резидентным полиморфным вирусом, PM.Wanderer использует защищенный режим процессоров i386-Pentium. Для установки своей резидентной копии в память и переключения в защищенный режим процессора (Protected Mode) вирусом используется документированный интерфейс VCPI (Virtual Control Program Interface) драйвера расширенной памяти EMS (EMM386).
    Как работает такой вирус? При старте инфицированной программы вирусный полиморфный декриптор (о полиморфных вариантах распаковки мы говорили в первой части статьи) расшифровывает основное тело вируса и передает ему управление. Далее основной вирусный код копируется в участок памяти в верхних адресах. Затем вирус восстанавливает оригинальный код инфицированного файла в программном сегменте и приступает к непосредственному внедрению в память своей резидентной копии. Прежде всего, вирус пытается установить, есть ли в системе EMS-драйвер. Если этого драйвера в системе нет или вирусная резидентная копия уже находится в памяти, вирус просто-напросто отдает свое управление программе- вирусоносителю, и на этом все и заканчивается. В случае, если вирусной резидентной копии в памяти нет, и присутствует EMS-драйвер, вирус начинает переключение процессора в защищенный режим с наивысшим уровнем привилегий — режим супервизора! В защищенном режиме вирус устанавливает две аппаратные контрольные точки адресов входа в обработчик прерывания INT 21h (функции DOS) и перехода на процедуру перезагрузки компьютера. Помимо этого, вирус пытается изменить дескрипторную таблицу прерываний таким образом, чтобы на прерывания INT 1 (прерывание отладки) и INT 9 (прерывание клавиатуры) установить собственные дескрипторы обработчиков прерываний. Только после вышеописанных манипуляций вирус копирует свой код в страницу памяти, которую он использовал еще до входа в защищенный режим, и производит переключение процессора обратно в виртуальный режим работы. Затем происходит освобождение ранее выделенной памяти DOS в верхних адресах, и управление переходит инфицированной программе. С этого момента в защищенном режиме оказываются установленными ловушки на INT 1 и прерывания от клавиатуры на INT 9. Благодаря ловушкам вирус контролирует ни много ни мало все вызовы функций DOS, все нажатия клавиш на клавиатуре, попытки мягкой перезагрузки компьютера.
    При заражении файлов вирус использует прямой вызов ядра обработчика DOS INT 21h. Адрес этого ядра он выясняет при трассировке INT 21h во время своей установки в память. Вирусный код внедряется в начало СОM- или в середину ЕХЕ-файла (сразу же после заголовка). Оригинальный программный код запоминается в конце файла. Реальный рабочий код вируса составляет 3684 байт, но на практике инфицированные файлы имеют приращение длины более 3940 байт. В теле вируса содержится текст "WANDERER". Следует отметить, что вирус сохраняет способность к воспроизводству только в том случае, если в системе установлен драйвер EMS (EMM386). При установленном драйвере EMM386 с ключом NOEMS вирус перезагружает компьютер. Перезагрузка также возможна, если в системе используется драйвер QEMM386. При отсутствии VCPI под OS/2 вирус также нежизнеспособен. Обнаружить резидентную копию данного вируса, работающего в защищенном режиме процессора, обычными способами невозможно. Нетрудно догадаться, что для этого необходимо переключаться в защищенный режим с наивысшими привилегиями, хотя возможны и альтернативные варианты отлова вируса, техника которых выходит за рамки данной статьи. Приведенный ниже пример является кодом программы, позволяющим перевести процессор в защищенный режим. В этом режиме вирус может, например, расшифровать некоторые данные. Программа делает следующее:
    Код:
    .286 
    .model tiny 
    .code 
    org 100h 
    
    ; Определения для защищенного режима работы программы 
    ; Структура дескриптора 
    desc_struc STRUC 
    limit dw 0 
    baseJ dw 0 
    base_h db 0 
    access db 0 
    rsrv dw 0 
    desc_struc ENDS 
    
    ACC_PRESENT equ 10000000b 
    ACC_CSEG equ 01000000b 
    ACC_DSEG equ 00010000b 
    ACC_EXPDOWN equ 00001000b 
    ACC_CONFORM equ 00000100b 
    ACC_DATAWR equ 00000010b 
    
    DATA_ACC=ACC_PRESENT or ACC_DSEG or ACC_DATAWR 
    ; 10010010b 
    CODE_ACC=ACC_PRESENT or ACC.CSEG or ACC_CONFORM 
    ; 10011100b 
    STACK_ACC=ACC_PRESENT or ACC_DSEG or ACC_DATAWR or ACC.EXPDOWN 
    ; 1001011 Ob 
    
    ;Размеры сегментов (реальные размеры на единицу больше) 
    CSEG SIZE=65535 
    DSEG_SIZE=65535 
    STACK_SIZE=65535 
    ; Смещения используемых дескрипторов 
    CS_DESCR=(gdt_cs-gdt_0) 
    DS_DESCR=(gdt_ds-gdt_0) 
    SS_DESCR=(gdt_ss-gdt_0) 
    
    ; Константы значений портов ? 
    CMOS_PORT equ 070h 
    STATUS_PORT equ 064h 
    SHUTDOWN equ 0FEh 
    A20_PORT equ 0D1h 
    A20_ON equ 0DFh 
    A20_OFF equ 0DDh 
    INT_MASK_PORT equ 021h 
    KBD_PORT_A equ 060h 
    start: 
    ; Инициализируем необходимые данные для перехода 
    ; в защищенный режим 
    call init_protected_mode 
    ; Переходим в защищенный режим 
    call set_protected_mode 
    ; Теперь компьютер работает в защищенном режиме! 
    ; Так как таблица прерываний реального режима не может быть 
    ; использована в защищенном, прерывания запрещены! 
    ; Именно тут можно вставить инструкции, нужные вирусу 
    ; Возвращаемся в реальный режим 
    call set_real_mode 
    ; Печатаем сообщение "Light General" 
    mov ah, 09h 
    lea dx, qw 
    int 21h 
    ; Выходим в DOS 
    mov ax, 4C00h 
    int 21h 
    ; Макрокоманда для установки адреса для дескриптора 
    ; в глобальной таблице дескрипторов GDT. 
    ; На входе регистры DLAX должны содержать 
    ; абсолютный адрес сегмента 
    setgdtentry MACRO 
    mov [desc_struc.base_l][bx], ax 
    mov [desc_struc.base_h][bx], dl 
    ENDM 
    ; Процедура инициализации необходимых данных 
    ; для перехода в защищенный режим 
    init_protected_mode PROC 
    ; вычисляем абсолютный адрес для сегмента данных 
    ; в соответствии со значением регистра DS 
    mov ax, ds 
    mov dl, ah 
    shr dl, 4 
    shl ax, 4 
    ; Устанавливаем адрес сегмента данных 
    ; в глобальной таблице дескрипторов 
    mov bx, offset gdt_ds 
    setgdtentry 
    ; Вычисляем абсолютный адрес для сегмента GDT: прибавляем 
    ; к уже вычисленному абсолютному адресу сегмента данных 
    ; смещение в нем таблицы дескрипторов 
    add ax, offset gdtr 
    adc dl, 0 
    ; Останавливаем адрес сегмента GDT в глобальной таблице дескрипторов 
    mov bx, offset gdt_gdt 
    setgdtentry 
    ; Вычисляем абсолютный адрес для сегмента кода 
    ; в соответствии со значением регистра CS 
    mov ax, cs 
    mov dl, ah 
    shr dl, 4 
    shl ax, 4 
    ; Устанавливаем адрес сегмента кода 
    ; в глобальной таблице дескрипторов 
    mov bx, offset gdt_cs 
    setgdtentry 
    ; Вычисляем абсолютный адрес для сегмента стека 
    ; в соответствии со значением регистра SS 
    mov ax, ss 
    mov dl, ah 
    shr dl, 4 
    shl ax, 4 
    ; Останавливаем адрес сегмента стека 
    ; в глобальной таблице дескрипторов 
    mov bx, offset gdt_ss 
    setgdtentry 
    ; Перехватываем рестарт. Так как процессор i286 (а эта программа 
    ; рассчитана именно на такой процессор) не имеет возможности 
    ; возврата в реальный режим из защищенного, возврат в реальный 
    ; режим будем производить следующим образом: перехватим рестарт, 
    ; сгенерируем CPU Reset, после которого получим управление, когда 
    ; Процессор будет находится уже в реальном режиме. На процессоре 
    ; i386 возврат в реальный режим происходит значительно проще и 
    ; "естественнее". 
    push ds 
    mov ax, 40h 
    mov ds, ax 
    mov word ptr ds:[0067h], offset shutdown_return 
    mov word ptr ds:[0069h], cs 
    pop ds 
    ; Запрещаем маскируемые прерывания 
    cli 
    in al, INT_MASK_PORT 
    or al, OFFh 
    out INT_MASK_PORT, al 
    ; Запрещаем немаскируемые прерывания. Данная последовательность 
    ; команд не запрещает "незапрещаемые" прерывания в процессоре 
    ; (этого сделать по определению нельзя), а "не пускает" сигнал 
    ; немаскируемого прерывания к процессору 
    mov al, 8Fh 
    out CMOS_PORT, al 
    jmp $+2 
    mov al, 5 
    out CMOS_PORT+1, al 
    ret 
    init_protected_mode ENDP 
    
    ; Подпрограмма, переводящая процессор в защищенный режим 
    set_protected_mode PROC 
    ; Открываем адресную линию А20 для доступа свыше 1 Мб. 
    ; При закрытой линии адресное пространство 
    ; "зацикливается" в пределах 1 Мб 
    call enable_a20 
    ; Сохраняем значение регистра SS для реального режима 
    mov real_ss, ss 
    ; Переводим компилятор Turbo Assembler в улучшенный режим. 
    ; IDEAL — это не команда и не оператор, это директива, влияющая 
    ; только на интерпретацию дальнейших строк листинга 
    ideal 
    р286 
    ;Загружаем регистр глобальной таблицы дескрипторов GDTR 
    lgdt [QWORD gdt_gdt] ; db OFh,01h,16h dw offset gdt_gdt 
    ; Переводим процессор в защищенный режим 
    mov ax, 0001h 
    lmsw ax ; db OFh,01h,FOh 
    ; Переводим компилятор Turbo Assembler назад в режим MASM 
    masm 
    .286 
    ; Производим длинный переход для того, 
    ; чтобы очистить внутреннюю очередь команд процессора 
    jmp far flush 
    ; db 0EAh 
    ; dw offset flush 
    ; dw CS_DESCR 
    flush: 
    ; Останавливаем в регистр SS селектор сегмента стека 
    mov ax, SS_DESCR 
    mov ss, ax 
    ; Устанавливаем в регистр DS селектор сегмента данных 
    mov ax, DS_DESCR 
    mov ds, ax 
    ; Записываем в строку qw символ "L" и выходим из подпрограммы 
    mov byte ptr ds:[offset qw+2],"L" 
    ret 
    set_protected_mode ENDP 
    
    ; Подпрограмма, возвращающая процессор в реальный режим 
    set_real_mode PROC 
    ; Сохраняем значение регистра SP для реального режима 
    mov real_sp, sp 
    ; Выполняем CPU Reset (рестарт процессора) 
    mov al, SHUT_DOWN 
    out STATUS_PORT, al 
    ; Ждем, пока процессор перезапустится 
    wait_reset: 
    hlt 
    jmp wait_reset 
    ; C этого места программа выполняется после перезапуска процессора 
    shutdown_return: 
    
    ; Устанавливаем регистр DS в соответствии с регистром CS 
    push cs 
    pop ds 
    ; восстанавливаем указатели на стек 
    ; по ранее сохраненным значениям 
    mov ss, real_ss 
    mov sp, real_sp 
    ; Закрываем адресную линию А20 
    call disable_a20 
    ; Разрешаем немаскируемые прерывания 
    mov ax, 000dh 
    out CMOS_PORT, al 
    ; Разрешаем маскируемые прерывания 
    in al, INT_MASK_PORT 
    and al, 0 
    out INT_MASK_PORT, al 
    sti 
    ret 
    set_real_mode ENDP 
    ; Процедура, открывающая адресную линию А20. После открытия 
    ; адресной линии программам будет доступна память свыше 1 Мб 
    enable_a20 PROC 
    mov al, A20_PORT 
    out STATUS_PORT, al 
    mov al, A20_ON 
    out KBD_PORT_A, al 
    ret 
    enable_a20 ENDP 
    ; Процедура, закрывающая адресную линию А20. После закрытия 
    ; адресной линии программам будет недоступна память свыше 1 Мб. 
    ; Адресное пространство будет "зацикленным" в пределах 1 Мб 
    disable_a20 PROC 
    mov al, A20_PORT 
    out STATUS_PORT, al 
    mov al, A20_OFF 
    out KBD_PORT_A, al 
    ret 
    disable_a20 ENDP 
    
    ; Здесь сохраняется адрес стека 
    real_sp dw ? 
    real_ss dw ? 
    ; Эта строка выводится на экран после работы программы 
    ; Символ "?" заменяется на "L" в защищенном режиме 
    qw db 13,10,"?ight General",13,10,"$" 
    ; Глобальная таблица дескрипторов. Нулевой дескриптор 
    ; обязательно должен быть "пустым" 
    GDT_BEG=$ 
    gdtr label WORD 
    gdt_0 desc_struc <0,0,0,0,0>; 
    gdt_gdt desc_struc <GDT_SIZE-10,DATA_ACC,0> 
    gdt_ds desc_struc <DSEG_SIZE-10,DATA_ACC,0> 
    gdt_cs desc_struc <CSEG_SIZE-10,CODE_ACC,0> 
    gdt_ss desc_struc <STACK_SIZE-10,DATA_ACC,0> 
    GDT_SIZE=($-GDT_BEG) 
    END start
     
    21 июн 2007
Загрузка...