CodeNet / Языки программирования / Ассемблер / "Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.
"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.
гл.4 СОЗДАНИЕ РЕЗИДЕНТНЫХ ПРОГРАММ (практическая реализация) ============================================================ Итак, мы познакомились с механизмом работы прерываний и научились реали- зовывать вызов прерываний на уровне обычный JMP-ов и CALL-ов и даже не ис- пользовать при этом таблицу векторов. Чудесно! Теперь об создании резидентных программ (именно таковыми являются 'дра- коны' и 90% всех 'вирусов'). Что такое резидентная программа (в дальнейшем - просто - резидент) ? Это такая программа, которая находится в оперативной памяти постоянно (обычные, нерезидентные программы присутствуют в памяти лишь во время их не- посредственного исполнения; когда их выполнение заканчивается -- они "умира- ют" - память занятая ими - освобождается . Резидент же может обитать в ОЗУ, [кстати rezide - по англ. 'обитать'] не будучи в данный момент исполняем, но в то же время, - готовый к действию). Вот как распределяется память при выполнении обычных и резидент. прог- рамм (КРАЙНЕ упрощенно): -----------------------------------------------------------¬ ¦ рис.2 ¦: L----------------------------------------------------------- обычная программа: До загрузки чего-либо: ---------T--------------T---------------------------------------- ¦таблица ¦ ¦ ¦векторов¦ область DOS ¦ свободная память . . . . . . . . . . ¦прерыв-й¦ ¦ L--------+--------------+---------------------------------------- 0:0 ----> старшие адреса Загрузили и исполняем обычную программу: ¦ ----------------- ---------T--------------T--------V----------T-------------------- ¦таблица ¦ ¦ TETRIS.EXE ¦ ¦векторов¦ область DOS ¦(есть такая глупая ¦ свободная память . ¦прерыв-й¦ ¦ игрушка) ¦ L--------+--------------+-------------------+-------------------- 0:0 После того, как прогр-а завершилась: ---------T--------------T---------------------------------------- ¦таблица ¦ ¦ ¦векторов¦ область DOS ¦ свободная память . . . . . . . . . . ¦прерыв-й¦ ¦ (все вернулось на кругИ своя...) L--------+--------------+---------------------------------------- 0:0 =========================================================================== Теперь - что касается резидентов: До загрузки чего-либо: ---------T--------------T---------------------------------------- ¦таблица ¦ ¦ ¦векторов¦ область DOS ¦ свободная память . . . . . . . . . . ¦прерыв-й¦ ¦ L--------+--------------+---------------------------------------- 0:0 Загрузили резидент:-------------¬ ¦ ----------------- ---------T--------------T--------V----------T-------------------- ¦таблица ¦ ¦ KEYR23.COM ¦ ¦векторов¦ область DOS ¦(драйвер рус. кла- ¦ свободная память . ¦прерыв-й¦ ¦ виатуры) ¦ L--------+--------------+-------------------+-------------------- 0:0 --------------------------- ¦ И так- -- до окончания работы на PC! Резидент будет сидеть в ОЗУ и быть всегда готов вам услужить. Если Вы теперь загрУзите tetris, он попадет вот куда: ---------T--------------T-------------------T----------T--------- ¦таблица ¦ ¦ KEYR23.COM ¦ ¦ ¦векторов¦ область DOS ¦(драйвер рус. кла- ¦TETRIS.EXE¦свободная ¦прерыв-й¦ ¦ ¦ виатуры) ¦ ¦память... L--------+--------------+-¦-----------------+----------+--------- 0:0 Lстал резидентом Только программы типа Volkov Comander могут безболезненно удалять рези- денты из памяти (и то лишь те, которые были загружены после них {удаляющих}). Сделать программу резидентной (постоянно присутствующей в памяти) -- ЭЛЕМЕНТАРНО. Вот один из способов (в дальнейшем мы рассмотрим их все): (прокоментируем ниже) -----------------------------------------------------------¬ ¦ пример 4 ¦: L----------------------------------------------------------- TITLE Это - COM. программа N4 для демонстрации посадки резидента ASSUME CS:CodeSegment ;--------------------------------------------------------------------------- CodeSegment SEGMENT PARA ORG(100h) Start: MainProcedure PROC NEAR ; ; ; ; ; MOV AX,0E61h ; напечатать INT 10h ; символ 'a' resident_end: ; ; MOV DX,OFFSET resident_end ; DXвыполняется ¦ \ ¦ / +TTTTT+ ¦ п/п-ма L - * - --------> -+++++++ ¦ обработки / ¦ \ ¦+++++++ ¦ (стандартная) возник ¦¦ ¦ ¦ IRET------------¬ сигнал -- ¦L------ ¦ ¦ -- прерывание Lв таблице ---------T---- ¦ векторов делается ¦ ---------------¬ найден адрес переход ¦ V L¬ обработчика по этому ¦ ¦ (стандартного) адресу ¦ ¦ ¦ L------T------------------------------------------ делается переход обратно - в пользовательскую программу, в ту точку, перед которой прерыв-е возникло А вот какая стала цепочка после того, как мы перехватили прерыв-е ¦ г================================¬ ¦ ------¬ ¦ ------>выполняется ¦ ¦ \ ¦ / +TTTTT+ ¦ ¦ ---НАША---- ¦ L - * - --------> -+++++++ ¦ ¦ п/п-ма обработки ¦ / ¦ \ ¦+++++++ ¦ ¦ (она резидентна) ¦ возник ¦¦ ¦ ¦ ¦ ¦ ¦ сигнал -- ¦L------ ¦ ¦ L---->------¬ ¦ -- прерывание Lв таблице ---->----T---- ¦ ¦ векторов ¦ делается ¦ ¦ ------------¬ найден адрес ¦ переход ¦ ¦ ¦ L¬ ---НАШЕГО---- ¦ по этому ¦ ¦ V L¬ обработчика ¦ адресу ¦ ¦ ¦ ¦ возвращаем ¦ ¦ ¦ ¦ управление ¦ ¦ ¦ ¦ стандартно- ----+ ¦ ¦ ¦ му обработ- ¦ ¦ ¦ наше новое-¦ чику (JMP Far) ¦ ¦ ¦ звено L=============================¦==- ¦ --------- сделаем для него резидентный обработчик. Какое прерывание выбрать? Предложим для простоты прерывание N 5 (печать экрана). Оно возникает, если Вы нажмете клавишу Print Scrin. Вызываемая при этом п/п-ма печатает на принтере копию экрана PC. Прерывание N 5 не требует и не возвращает никаких параметров (чУдно!), и еще его не обязательно возвра- щать стандартному обработчику; ничего не случится, если Вы его зажмете (весь- ма редкое свойство). Вы наверное не раз замечали что если Вы нажмете Print Scrin, а принтер не готов -- раздается гудок, -- это стандартный обработчик прерывания N 5 'назвал' Вас раздолбаем). Создадим-ка резидент, который, перехватывая прерывание N 5 , ну ска- жем,.. выведет на экран 'сердечко' (символ с кодом 3), и после этого возвра- тит управление стандартному обработчику (вежливость - высшая добродетель). Таким образом, при нажатии Print Scrin сначала будет напечатано 'сердечко' (работает наш резидентный обработчик), а уже потом раздастся гудок (заработа- ет стандартный обработчик и обругает Вас за отключенный принтер). Итак -- вперед! (подробно прокоментируем ниже) -----------------------------------------------------------¬ ¦ пример 5 ¦: L----------------------------------------------------------- TITLE Это - COM. программа N5 для демонстрации посадки резидента ASSUME CS:CodeSegment ;----------------------------------------------------------------- CodeSegment SEGMENT PARA ORG(100h) Start: MainProcedure PROC NEAR ; ; JMP initial ; перепрыгнем через данные ; ; и наш обработчик прер-я 05 ; ; на инициализирующую часть ; ; saved_int05: DD 0 ; данные (хранилище для ; ; адреса стандартного обра- ; ; ботчика прерывания 05 -- ; ; -- 2 слова) ; ;-----------наша п/п-а обработки прерывания 05------------------¬ ;¦ (она останется резидентной в памяти) ¦ ;¦ здесь мы можем приколоться как хотим.. ¦ ;¦ ; ¦ int05_treater:PUSH AX ; ¦ ; ; ¦ MOV AH,0Eh ;входные параметры прерыв-я 10h:¦ MOV AL,03h ; (печатать 'сердечко' - код 03) INT 10h ;печатаем 'сердечко' ¦ ; ; ¦ POP AX ;PUSH и POP ОЧЕНЬ важны (см. ко-¦ ; ; ментарий после примера) ¦ ; ; ¦ ; ; ¦ JMP dword ptr CS:[saved_int05] ; длин. JMP по адресу, котор. ¦ rezident_end: ;¦ ; находится теперь в хранилище ¦ ;¦ ; saved_int05 (возвращаем управ-¦ ;¦ ; ление стандартному обработчику¦ ;¦ ; прерывания 05) ¦ ;L--------------------------------------------------------------- ; ; ;-----------инициализирующая часть------------------------------¬ ;¦ (здесь мы сажаем резидент, переопределяя адреса) ¦ ;¦ ; ¦ initial: XOR DX,DX ; ---¬ ¦ MOV DS,DX ; ---+--> DS = 0 ¦ ; ; ¦ MOV AX,DS:[5*4] ;сохраняем в хранилище saved_ MOV word ptr CS:[saved_int05 ],AX ; int05 адрес стандартного ¦ MOV AX,DS:[5*4+2] ; обработчика прерывания 05¦ MOV word ptr CS:[saved_int05+2],AX ; ( OFFSET и SEGMENT ) ¦ ; ; ¦ ; ; ¦ CLI ;запрещаем прерывания ¦ MOV AX,OFFSET int05_treater ; ¦ MOV word ptr DS:[5*4],AX ;кладем в таблицу векторов ¦ PUSH CS ; адрес нашего обработчика ¦ POP AX ; прерывания 05 ¦ MOV word ptr DS:[5*4+2],AX ; ¦ STI ;разрешаем прерывания ¦ ; ; ¦ ; ; ¦ MOV DX,OFFSET rezident_end ;DX=======>====>¬ перепрыгнем через данные L------------- ¦ и наш обработчик прер-я 05 saved_int05: -----------------------------¬ V на инициализирующую часть ¦данные: (хранилище для ¦ ¦ L---------T---------- ¦адреса стандартного обра - ¦ ¦-------------- ¦ботчика прерывания 05 -- ¦ ¦ ¦-- 2 слова) ¦ ¦ L----------------------------- ¦ V int05_treater:----------------------------¬ ¦ ¦наша п/п-ма обработки ¦ ¦ ¦прерывания 05 (она оста- ¦ ¦ ¦нется резидентной в памяти) ¦ V rezident_end:L----------------------------- ¦ ¦ г========= -----------------------------¬ initial: ¦инициализирующая часть ¦ ¦(здесь мы сажаем резидент, ¦ ¦переопределяя адреса ¦ ¦ ¦ ¦MOV DX,OFFSET rezident_end ¦ ¦INT 27h (выход в DOS) ¦ L----------------------------- Как видно из рисунка, прогр-ма состоит из двух главных частей: той, что остается в памяти резидентно и не выполняется при запуске самой прогр-мы (данные + наша п/п-ма обработки прерывания 05), и -- инициализирующей части. Почему порядок следования этих частей именно такой? Почему инициализирующая часть не остается в памяти резидентно? Почему наша п/п-ма обработки прерывания 05 начинается оператором PUSH AX и заканчивается оператором POP AX? Что за новые операторы CLI и STI?