На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Запрещается обсуждать написание вирусов, троянов и других вредоносных программ!
2. Помните, что у нас есть FAQ раздела Assembler и Полезные ссылки. Посмотрите, возможно, там уже имеется решение вашего вопроса.

3. Настоятельно рекомендуем обратить особое внимание на правила форума, которые нарушаются чаще всего:
  3.1. Заголовок темы должен кратко отражать её суть. Темы с заголовками типа "Срочно помогите!" или "Ассемблер" будут отправляться в Корзину для мусора.
  3.2. Исходники программ обязательно выделяйте тегами [code]...[/code] (одиночные инструкции можно не выделять).
  3.3. Нежелательно поднимать старые темы (не обновлявшиеся более года) без веской на то причины.

Не забывайте также про главные Правила форума!

Добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: Jin X, Qraizer
  
> ASM DOS Создание TSR без PSP , Непонятки в использование INT 21H функции 55H и другие пояснения авторов на похожие темы.
    Я умудрился найти метод создания TSR без PSP.
    Проверил его на WMVARE и на реальных компьютерах. Работает в MS-DOS 6, MS-DOS 7.10, WINDOWS-98(DOS-окно)
    В литературе рекомендуют использовать функции DOS 50H и 55H (INT 21H)
    Некоторые авторы не рекомендуют использовать функцию DOS 55H.
    Хорошего описания этой функции не нашел.
    Может кто знает отличие функции 55H от функции 26H.
    Я проверил в своем методе их оба, и не заметил различий.
      Вообще говоря, PSP резиденту часто просто не нужен. Самое важное, что там есть – открытые файлы, и если резидент выполняет дисковые операции, то да, о PSP ему надо заботиться. В противном случае можно легко затереть PSP собственными данными и не париться.
      Что касается разницы в фукциях, вот тут хороший справочник.
        Цитата andr00 @
        кто знает отличие функции 55H от функции 26H.

        Согласно описанию
        Цитата
        INT 21 - DOS Internal - CREATE PSP

        AH = 55h
        DX = Segment number to set up PSP at
        Note: Like func 26h but creates "child" PSP rather than copying existing one.

        Цитата andr00 @
        Я умудрился найти метод создания TSR без PSP.

        Тоже мне проблема. ВСЕ TSR, ставящиеся в верхние блоки памяти, не используют PSP. В частности, подавляющее большинство бутовых вирусов.
        Реально PSP нужен в основном для того, чтобы соотв. функции DOS смогли правильно завершить работу программы (с оставлением резидентной части или без таковой). Плюс там располагается строка запуска с параметрами, откуда их можно обработать. И практически всё...
        Цитата Qraizer @
        если резидент выполняет дисковые операции, то да, о PSP ему надо заботиться.

        Нафига? Если TSR имеет глупость использовать старые (0Fh-17h) функции работы с файлами, достаточно зарезервировать 20 байт под FCB. Если же хэндловые - то и FCB не нужен.
          Причём тут устаревшие FCB? Речь о расширенных FCB внутри DOS, которые торчат наружу в лице параметра FILES в CONFIG.SYS. В PSP лежит массив соответствий между открытыми приложением handle и этими самыми FILES, и если резидент не озаботится охраной своих handles от handles приложений, будет большой бадабум.
            В PSP? ничего не путаешь? потому как у меня было много программ, которые ставились резидентно в верхние адреса, полностью освобождая MCB инсталлера, и, работая с файлами, ни про какой PSP даже не думали - это забота DOS...

            Цитата Qraizer @
            массив соответствий между открытыми приложением handle и этими самыми FILES

            :blink: Таблица открытых файлов находится в области данных DOS... может, я даже найду функцию (MS-DOS Internal), которая возвращает указатель на неё, если, конечно, вспомню, в какой доке она описана...

            Добавлено
            fn 52h
              Ничего не путаю. Попробуй открыть файл, получишь хендл, эдак, 5, затем останься резидентом, потом в обычной программе открой другой файл, получишь внезапно 5-ый хендл. Для пущего теста всплыви резидентом и запиши чё-нить в свой 5-ый хендл.
                Могу точно сказать, что после 30h можно спокойно всё затирать даже на этапе инсталляции резидента. По крайней мере, если не используется int 21h. После 80h, понятное дело, можно стирать всё при любом раскладе. Я себе ещё в заготовке для резидента сделал отметку 40h, но уже не помню зачем :)
                ExpandedWrap disabled
                  .MODEL Tiny
                  .286
                  .CODE
                  .STARTUP
                   
                  LOCALS
                   
                  IntNo       =   08h     ; номер прерывания
                  HandlerOfs  =   30h;40h;80h ; смещение, по которому будет копироваться обработчик (с отступом в 2-3 байта на инструкцию jmp), должно быть кратно 10h
                  HandlerShift    =   HandlerOfs-100h ; разница нового и исходного смещения обработчика
                   
                          jmp InstallTSR
                   
                  ;-----------------------------------------------------------------------------------------------------------------------
                   
                  HandlerStart:               ; начало обработчика прерывания (между этой меткой и HandlerEntry могут храниться данные)
                  ORG $-2
                  VentilOfs   DB  ?
                  VentilOfs1  DB  ?
                  VentilChars DB  '\|/-'
                  HandlerEntry:               ; точка входа обработчика прерывания
                          push    ax
                          push    bx
                          push    ds
                          
                          push    cs
                          pop ds
                          mov al,VentilOfs
                          inc ax
                          and al,3
                          mov VentilOfs,al
                          lea bx,VentilChars
                          xlat
                          mov ah,1Eh
                          push    0B800h
                          pop ds
                          mov ds:[0],ax
                   
                          pop ds
                          pop bx
                          pop ax
                   
                  RealInt     DB  0EAh        ; возвращаем управление прерыванию (jmp far)
                  RealAddr    DW  ?,?
                  HandlerEnd:
                  ORG     $-4
                   
                  ;-----------------------------------------------------------------------------------------------------------------------
                   
                  InstallTSR:
                          mov ah,9
                          lea dx,msgOk
                          int 21h
                   
                          ; копируем наш код со смещением HandlerShift
                          mov si,offset HandlerStart
                          mov di,offset HandlerStart+HandlerShift
                          mov cx,(HandlerEnd-HandlerStart+1)/2
                          rep movsw
                   
                          ; Освобождаем Environment
                          mov ah,49h
                          mov es,ds:[2Ch]
                          int 21h
                   
                          ; Сдвигаем сегментный адрес
                          mov ax,cs
                          add ax,HandlerShift/16
                          mov ds,ax
                   
                          ; Получаем старый вектор прерывания
                          mov ax,3500h + IntNo
                          int 21h
                          mov RealAddr[0],bx
                          mov RealAddr[2],es
                   
                          ; Перехватываем прерывание
                          mov ah,25h
                          mov dx,offset HandlerEntry
                          int 21h
                   
                          ; Остаёмся резидентными
                          mov dx,offset HandlerEnd+HandlerShift
                          int 27h
                   
                  msgOk       DB  'TSR is installed!',13,10,'$'
                   
                  END
                  Цитата int 21h, Fn=50h
                  Info: This function tells DOS that the PID▲ in BX identifies the
                  current active process. It is used in TSR programs to inform DOS
                  which process is running; i.e., after popping up.

                  Several DOS fns (including file handle operations and memory
                  allocation functions), refer to and make changes to the PSP of
                  the current process.

                  A TSR should call Fn 51H and save its PSP during initialization.
                  Before popping up, the TSR should use fn 51H to get the ID of the
                  interrupted program, then use fn 50H to set the PID to the saved
                  value. Be sure to change the PID back before popping down.


                  Добавлено
                  Цитата
                  PspRec
                    Offset Size Contents
                    ▀▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
                    +0       2  wInt20       INT 20H instruction (cd 20) (old way to exit)
                    +2       2  wNextSeg     Segment addr just beyond end of program image
                    +4       1  res1         (reserved)
                    +5       5  abDispatch   FAR CALL to DOS function dispatcher (obs)
                   +0aH      4  pfTerminate  terminate address.       See INT 22H
                   +0eH      4  pfCtlBrk     Ctrl-Break handler address   INT 23H
                   +12H      4  pfCritErr    Critical Error handler addr  INT 24H
                   +16H     22  res2         DOS reserved area
                             2  wParentPsp   ◄undoc► segment of parent's PSP
                   +2cH      2  wEnvSeg      segment address of DOS environment
                   +2eH     46  res3         DOS reserved area (handle table, et al.)
                   +5cH     16  rFCB_1       an unopened FCB for 1st cmd parameter
                   +6cH     20  rFCB_2       an unopened FCB for 2nd cmd parameter
                   +80H      1  bCmdTailLen  count of characters in command tail at 81H (also
                                             default setting for the DTA)
                   +81H     127 abCmdTail    characters from DOS command line
                            256              size of a PspRec structure
                  Сообщение отредактировано: Qraizer -
                    Вообще то мне нужно было создать кучу маленьких TSR без PSP, и желательно в нижней памяти.
                    При этом желательно разместить их в фрагментированных свободных блоках памяти.
                    Это мне удалось, все работает. Но гложет мысль, а вдруг где то сглючит из-за нерекомендуемого использования функции 55H.
                    Чуть позже прикреплю файл описание работы программы и сам листинг.
                      Спасибо Qraizer за хороший справочник.
                      Прилагаю описание работы и ASM файл.
                      Но остались небольшие вопросы.

                      Если освободить всю память и присвоить ее обратно, не получится ли,
                      что в этот момент кто то вмешается и испортит всю картину распределения памяти ?
                      Прикреплённый файлПрикреплённый файлPSP_00.ASM (2,42 Кбайт, скачиваний: 193)
                      Прикреплённый файлПрикреплённый файлTSR________PSP.txt (2,37 Кбайт, скачиваний: 176)

                      Добавлено
                      Подумал о создание нового PSP.
                      А не лутше ли просто скопировать (MOVS) в нужное место и объявить его текущим ?
                        Цитата Qraizer @
                        Для пущего теста всплыви резидентом и запиши чё-нить в свой 5-ый хендл.

                        Ну ты меня за идиота-то не держи! Если нужна работа с файлом из TSR, то открытие-работа-закрытие выполняются в одном потоке по выставленному флагу в обработчике DOS Idle. И если там при открытии будет получен хендл 5 - то он будет правильный.
                          andr00, для чего резиденту нужен PSP? В нём используются функции DOS?
                          Если нет, в топку PSP! Резидентный модуль обычно – это просто обработчик прерывания. У BIOS'а нет PSP, и его "резидентные" функции (int 8, int 9 и пр) прекрасно работают :)
                            Jin X, мне не нужен PSP только из за того, что он занимает в памяти 256 байт.
                            Но избавится от PSP не так уж просто.

                            Добавлено
                            Да, иногда я работаю с файлами из TSR, для этого я создаю и использую временный PSP, который сразу же удаляю когда он не нужен. Здесь нет никаких проблем.
                              Цитата Jin X @
                              для чего резиденту нужен PSP?

                              Не нужен. Более того - после постановки резидентной части и передачи управления командному процессору он уже не PSP, а просто блок в памяти, содержимое которого чертовски похоже на PSP.

                              Цитата andr00 @
                              иногда я работаю с файлами из TSR, для этого я создаю и использую временный PSP

                              Лишняя забота. И ненужная.
                                andr00, а в чём проблема? Если "кусочки" резидента заполняют свободные дырки, то проблем вообще нет. Просто выходим из программы через int 20h и всё.
                                А если свободных дыр нет, значит берём исходник выше и оставляем только 30h байт от PSP (после int 27h, уверен, можно спокойно скопировать себя на 30h ниже, уменьшив в таблице векторов сегментный адрес на 3). Ну или проделать всё это с 80h для надёжности.
                                Кстати, если резидент используется int 21h, то какой при этом используется PSP? Надо думать, что программы, которая исполняется в данный момент, не иначе. А если нужен свой PSP, тогда создаём его динамически (собственно, тут возникает вопрос: а надо ли было его удалять?)
                                  Цитата Jin X @
                                  если резидент используется int 21h, то какой при этом используется PSP? Надо думать, что программы, которая исполняется в данный момент, не иначе.

                                  Именно так. Поэтому обработчик, отдавая управление (неважно, обратно или вниз), не должен оставлять открытый файл.
                                  Сообщение отредактировано: Akina -
                                    Повторяюсь, PSP в TSR (или даже его часть) мне не нужен. Каждый байт на счету.
                                    Тема выяснена на 90% . Спасибо за советы.
                                      andr00
                                      А в чём тогда суть и вообще смысл создания темы-то?
                                        Цитата Akina @
                                        не должен оставлять открытый файл.
                                        ...без переключения PSP (ah=50h/int 21h) ;)
                                          Akina, ты знаешь, то предыдущего поста не держал. Так ты попробовал? Только пробуй на ненужных файлах.

                                          Добавлено
                                          Цитата Jin X @
                                          Кстати, если резидент используется int 21h, то какой при этом используется PSP? Надо думать, что программы, которая исполняется в данный момент, не иначе.
                                          Именно. И где тогда твои открытые ранее хендлы? А если ты каждый раз будешь всплывать под разными приложениями, включая других резидентов? А если у прерываемого приложения кончатся его 20 дефолтных хендлов?

                                          Добавлено
                                          И в конце концов: кто-нибудь знает, что именно лежит в reserved-областях PSP и для чего ей это нужно там хранить? И какие ещё структуры данных в DOS и её драйверах завязаны на этот PID, каковым адрес PSP является?
                                            Цитата Qraizer @
                                            Именно. И где тогда твои открытые ранее хендлы? А если ты каждый раз будешь всплывать под разными приложениями, включая других резидентов? А если у прерываемого приложения кончатся его 20 дефолтных хендлов?
                                            Ну, так переключай PSP на свой, когда это нужно, а потом возвращай обратно.
                                            В этих байтах хранится Job File Table
                                              Цитата Qraizer @
                                              И где тогда твои открытые ранее хендлы?

                                              Какие это "ранее открытые"??? ты читаешь, что я пишу?

                                              Цитата Akina @
                                              Если нужна работа с файлом из TSR, то открытие-работа-закрытие выполняются в одном потоке по выставленному флагу в обработчике DOS Idle.

                                              Так что какая мне в пень разница, где тот хэндл, который я давным-давно закрыл?
                                                Попробовал тупо скопировать старый PSP в нужное место. Отлично работает и дешевле
                                                обходится (не надо применять функцию INT 21H AH=55H или AH=26H), так же не надо
                                                никаких корректировок нового PSP.

                                                Добавлено
                                                Попробовал запустить программу TSR в DOS окне WINDOWS-XP.
                                                Вроде работает. MEM.EXE указывает, что TSR существует.
                                                Но, просматривая DEBUG, обнаружил в этом сегменте одни нули ?
                                                  Цитата Jin X @
                                                  Ну, так переключай PSP на свой, когда это нужно, а потом возвращай обратно.
                                                  Ну а я что сказал вначале?
                                                    Цитата andr00 @
                                                    просматривая DEBUG, обнаружил в этом сегменте одни нули ?

                                                    Правильно. Ты же ничего не сделал, чтобы именно этот блок использовался под твоим кодом в качестве PSP.
                                                      Цитата andr00 @
                                                      Попробовал тупо скопировать старый PSP в нужное место. Отлично работает и дешевле
                                                      обходится (не надо применять функцию INT 21H AH=55H или AH=26H), так же не надо
                                                      никаких корректировок нового PSP.
                                                      А там, в общем-то, и нет никаких абсолютных адресов, указывающих на область самой программы, поэтому и корректировки не нужны :)
                                                      Главное, чтобы не было утечки памяти при всех этих манипуляциях с перемещением, выделением памяти и пр.

                                                      Цитата Qraizer @
                                                      Ну а я что сказал вначале?
                                                      Так, никто ж и не спорит, коллега! ;)
                                                        Akina, все таки непонятки. Программа TSR (в окне DOS, WINDOWS-XP) работает, MEM.EXE указывает правильный размер и сегмент в памяти, а DEBUG в этом сегменте видит нули. Даже в MCB нули ?

                                                        Добавлено
                                                        Опа ! Оказывается DEBUG.EXE (а так-же TD.EXE) в окне DOS, под WINDOWS-XP вообще ничего не видит (т.е. видит какой то мусор)
                                                        Может кто посоветует, какой программой мне просмотреть память ?
                                                          Цитата andr00 @
                                                          Программа TSR (в окне DOS, WINDOWS-XP) работает, MEM.EXE указывает правильный размер и сегмент в памяти, а DEBUG в этом сегменте видит нули. Даже в MCB нули ?

                                                          MCB вообще-то на 16 байт ниже...

                                                          Цитата andr00 @
                                                          Оказывается DEBUG.EXE (а так-же TD.EXE) в окне DOS, под WINDOWS-XP вообще ничего не видит (т.е. видит какой то мусор)

                                                          :blink: Да ладно! у меня TD нормально всё показывает...
                                                            Akina, Предлагаю посмотреть скрины. Программка Выводит на экран в верхнюю строку (по прерыванию 09h) строку "ABCDEFGHIJKLMNOP"
                                                            Это видно на всех скринах. TD.EXE (1992 год) то же самое )

                                                            Добавлено
                                                            Не могу отправить скрин.
                                                              Последний скрин.
                                                              Прикреплённый файлПрикреплённый файлDEBUG.EXE.rar (58,21 Кбайт, скачиваний: 90)
                                                                Цитата andr00 @
                                                                Может кто посоветует, какой программой мне просмотреть память ?
                                                                Есть peek.exe - резидент для просмотра памяти.
                                                                Ну или да, TD...
                                                                Прикреплённый файлПрикреплённый файлPEEK.7z (5,21 Кбайт, скачиваний: 104)
                                                                  Jin X, вообще моя задача полностью избавится от PSP. Т.к. есть довольно много маленьких TSR (даже всего 4 байта (ссылки на буфер в области памяти >1Мб)).
                                                                  Ваше предложение оставить всего 30H PSP не всегда проходит корректно. Некоторые конфигурации DOS, после установки TSR, портят исходные файлы (даже исходники *.asm).
                                                                  Я обнаружил, что после установки TSR (с остатком PSP в 30H байт) и после этого немедленного включения просмотра (по F3), практически все файлы с именем запускного
                                                                  файла портятся. Я не использую в TSR (пока) файловые операции. Все что я выяснил, это оставить остаток PSP = 40H, вроде не глючит. Но для большей уверенности,
                                                                  (если не использовать командную строку) это 80H.

                                                                  Добавлено
                                                                  Akina, TD при запуск программы исходника (в окне DOS под Windows-XP) работает отлично. Но если ей указать сегмент:смещение этой TSR (полученной с помощью MEM.EXE)- какой то мусор.
                                                                    Цитата andr00 @
                                                                    Некоторые конфигурации DOS, после установки TSR, портят исходные файлы (даже исходники *.asm).
                                                                    Это как?! :blink:
                                                                    Про 30h я же написал, что "по крайней мере,если не использовать int 21h внутри обработчика".

                                                                    Вообще, я бы следовал следующему алгоритму:

                                                                    0. Расположить обработчики в программе друг за другом, а первый из них выровнять по границе параграфа (16 байт).
                                                                    1. Удалить environment.
                                                                    2. Попытаться выделить блок памяти нужного размера (по размеру обработчиков).

                                                                    3а. Если блок выделился (это может бы только что освободившийся блок или дырка, оставленная кем-то ранее), то:
                                                                    3а.1. Подменяем служебную информацию (MCB) этого блока (чтобы при завершении программы он не освободился автоматически).
                                                                    3а.2. Копируем туда наш обработчик.
                                                                    3а.3. Перехватываем прерывания.
                                                                    3а.4. Выходим обычным образом (int 20h).

                                                                    3б. Если блок НЕ выделился, то:
                                                                    3б.1. Корректируем SS:SP (конец нашей программы + 100h).
                                                                    3б.2. Максимально уменьшаем размер памяти, выделенную под нашу программу (т.е. размер нашей программы + 100h под стек).
                                                                    3б.3. Выделяем новый блок такого же размера, как получился.
                                                                    3б.4. Копируем туда наш код, включая PSP.
                                                                    3б.5. Корректируем SS:SP.
                                                                    3б.6. Устанавливаем PSP на этот блок.
                                                                    3б.7. Прыгаем на то же место нашей программы, но в новом блоке.
                                                                    3б.8. Освобождаем область памяти, в которой была наша программа изначально.
                                                                    3б.9. Выделяем блок памяти нужного размера (по размеру обработчиков).
                                                                    3б.10а. Если блок выделился, goto 3а.1
                                                                    3б.10б. Если блок не выделился, значит мы где-то накосячили, можно вывести Error и помахать ручкой. Это крайне маловероятный сценарий в случае, если всё сделано правильно.
                                                                      Отъёлки...Program Segment Prefix.
                                                                        Интереса ради сделал то, что описал выше.
                                                                        Лови, andr00 ;)

                                                                        updated 31.07.2018:
                                                                        ExpandedWrap disabled
                                                                          ; TSR with no PSP (c) 2017 by Jin X
                                                                          ; Установка резидентных обработчиков прерываний, занимающих минимальное кол-во памяти (ровно столько, сколько требуется + 16 байт на MCB), без PSP !!!
                                                                           
                                                                          .MODEL Tiny
                                                                          .286
                                                                          .CODE
                                                                          .STARTUP
                                                                           
                                                                          IFDEF       ??Version           ; TASM
                                                                            LOCALS
                                                                          ENDIF
                                                                           
                                                                          ; Заполните эти константы любыми удобными вам значениями
                                                                          MuxFunc     =   0F1h            ; номер функции MUX Interrupt (Int 2Fh), должен быть в зиапазоне от 0C0h до 0FFh
                                                                          MuxAuthorID =   '7x'            ; идентификатор автора (BX)
                                                                          MuxProgID   =   'np'            ; идентификатор программы (DX)
                                                                          MuxAnswer   =   77FFh           ; ответ в AX, если программа установлена (любое значение)
                                                                           
                                                                          ProgStart   =   offset $        ; начало нашей программы
                                                                           
                                                                                  call    PreCheck        ; 3 байта - предварительная проверка (может, мы уже есть в памяти?)
                                                                                  
                                                                                  mov ah,49h          ; 2 байта
                                                                                  mov es,ds:[2Ch]     ; 4 байта
                                                                                  int 21h         ; 2 байта - освобождаем переменные окружения
                                                                           
                                                                                  ; Выделяем память для нашего резидента
                                                                                  mov ah,48h          ; 2 байта
                                                                           
                                                                                  jmp TSRInstall      ; 2-3 байта, итого 15-16 байт - прыгаем на продолжение установщика
                                                                           
                                                                          EVEN                        ; добиваем до 16 байт, если jmp оказался коротким (2-байтовым short)
                                                                           
                                                                          ;-- Начало резидентного кода обработчиков прерываний -------------------------------------------------------------------
                                                                          ; Эта метка должна быть выровнена по границе параграфа (16 байт) !!!
                                                                          TSRStart:
                                                                           
                                                                          ; Данные резидентного кода
                                                                          VentilChars DB  '|/-\'          ; таблица символов (вентилятора)
                                                                          VentilOfs   DB  -1          ; номер предыдущего символа (начиная с 0)
                                                                          VentilColor DB  1Eh         ; цвет вентилятора
                                                                           
                                                                          ; Обработчик прерывания 8 (системный таймер)
                                                                          HandlerInt8 PROC
                                                                                  push    ax
                                                                                  push    bx
                                                                                  push    ds
                                                                                  
                                                                                  push    cs
                                                                                  pop ds
                                                                                  mov al,[VentilOfs]
                                                                                  inc ax
                                                                                  and al,3
                                                                                  mov [VentilOfs],al      ; новое смещение
                                                                                  mov bx,offset VentilChars
                                                                                  xlat                ; AL = символ
                                                                                  mov ah,[VentilColor]    ; AH = цвет вентилятора
                                                                                  push    0B800h
                                                                                  pop ds
                                                                                  mov ds:[0],ax       ; выводим символ в левый верхний угол
                                                                           
                                                                                  pop ds
                                                                                  pop bx
                                                                                  pop ax
                                                                            OldInt8:
                                                                                  DB  0EAh            ; возвращаем управление прерыванию
                                                                            OldAddr8  DW  ?,?         ; адрес прерывания
                                                                          HandlerInt8 ENDP
                                                                           
                                                                          ; Обработчик прерывания 9 (клавиатура)
                                                                          HandlerInt9 PROC
                                                                                  push    ax
                                                                                  in  al,60h          ; читаем скан-код нажатой клавиши
                                                                                  cmp al,39h          ; пробел?
                                                                                  jne @@CheckEnter
                                                                           
                                                                                  ; Если пробел, меняем местами символы вентилятора (меняем направление вращения)
                                                                                  mov al,cs:[VentilChars+1]
                                                                                  xchg    al,cs:[VentilChars+3]
                                                                                  mov cs:[VentilChars+1],al
                                                                                  jmp @@exit
                                                                              @@CheckEnter:
                                                                                  cmp al,1Ch          ; Enter?
                                                                                  jne @@exit
                                                                                  xor byte ptr cs:[VentilColor],(1Eh xor 21h) ; если Enter, меняем цвет
                                                                              @@exit:
                                                                                  pop ax
                                                                            OldInt9:
                                                                                  DB  0EAh            ; возвращаем управление прерыванию
                                                                            OldAddr9  DW  ?,?         ; адрес прерывания
                                                                          HandlerInt9 ENDP
                                                                           
                                                                          ; Обработчик прерывания 2Fh (MUX Interrupt)
                                                                          HandlerInt2F    PROC
                                                                                  cmp ah,MuxFunc      ; проверяем номер функции
                                                                                  jne OldInt2F
                                                                                  cmp bx,MuxAuthorID      ; проверяем идентификатор автора
                                                                                  jne OldInt2F
                                                                                  cmp dx,MuxProgID        ; проверяем идентификатор программы
                                                                                  jne OldInt2F
                                                                           
                                                                                  test    al,al           ; проверяем номер подфункции
                                                                                  jne @@WrongFunc
                                                                           
                                                                                  mov ax,MuxAnswer        ; если AL=0, возвращаем наш ответ
                                                                                  iret
                                                                           
                                                                              @@WrongFunc:
                                                                                  xor ax,ax           ; если номер подфункции неверный, возвращаем 0 в AX
                                                                                  iret
                                                                           
                                                                            OldInt2F:
                                                                                  DB  0EAh            ; возвращаем управление прерыванию
                                                                            OldAddr2F DW  ?,?         ; адрес прерывания
                                                                          HandlerInt2F    ENDP
                                                                           
                                                                          TSREnd      =   $           ; конец резидентного кода (вместе с его данными)
                                                                           
                                                                          ;-----------------------------------------------------------------------------------------------------------------------
                                                                           
                                                                          TSRSize     =   TSREnd-TSRStart     ; размер резидентного кода
                                                                          TSRParaSize =   (TSRSize+15)/16     ; размер резидентного кода в параграфах
                                                                           
                                                                          ; Структура данных о перехватываемом прерывании
                                                                          TSRItem     STRUC
                                                                            TSRIntNo  DB  ?           ; номер прерывания
                                                                            TSRAddrOfs    DW  ?           ; смещение переменной с адресом старого обработчика
                                                                            TSRHandlerOfs DW  ?           ; смещение нашего обработчика прерывания
                                                                          TSRItem     ENDS
                                                                           
                                                                          ; Таблица прерываний, адресов обработчиков и переменных для хранения старых адресов
                                                                          TSRTables   TSRItem <8,OldAddr8,HandlerInt8>, <9,OldAddr9,HandlerInt9>, <2Fh,OldAddr2F,HandlerInt2F>
                                                                          TSRIntCount =   ($-TSRTables)/(size TSRItem)
                                                                           
                                                                          ;-----------------------------------------------------------------------------------------------------------------------
                                                                           
                                                                          ; Проверка - есть ли уже наш код в памяти?
                                                                          ; Если есть, то выходим из программы (int 20h)
                                                                          PreCheck    PROC
                                                                                  mov ax,MuxFunc shl 8
                                                                                  mov bx,MuxAuthorID
                                                                                  mov dx,MuxProgID
                                                                                  int 2Fh         ; проверяем нашу программу
                                                                           
                                                                                  cmp ax,MuxAnswer
                                                                                  jne @@NotInstalled      ; прыгаем, если не установлена
                                                                           
                                                                                  mov ah,9
                                                                                  mov dx,offset MsgTSRAlrInst
                                                                                  int 21h         ; выводим сообщение
                                                                           
                                                                                  int 20h         ; выходим из программы
                                                                              @@NotInstalled:
                                                                                  ret
                                                                          PreCheck    ENDP
                                                                           
                                                                          ; Установка резидентного кода и перехват прерываний
                                                                          TSRInstall  PROC
                                                                                  mov bx,TSRParaSize
                                                                                  int 21h         ; выделяем память нужного нам размера
                                                                                  jnc @@Allocated     ; если память выделилась, идём на перехват!
                                                                           
                                                                                  ; Переносим наш код выше, освобождая память текущего кода (чтобы выделить память по меньшему адресу для резидентного кода)
                                                                                  mov sp,offset @Startup+ProgParaSize*16+100h ; корректируем SP (оставляем под стек 256 байт)
                                                                                  
                                                                                  mov ah,4Ah
                                                                                  push    cs
                                                                                  pop es
                                                                                  mov bx,ProgParaSize+20h ; кол-во параграфов, включая PSP и стек
                                                                                  int 21h         ; сжимаем размер выделенной нашей программе области памяти
                                                                                  jc  @@Error         ; ошибка... что за бред?
                                                                           
                                                                                  mov ah,48h
                                                                                  int 21h         ; выделяем ещё один такой же блок
                                                                                  jc  @@Error         ; ошибка... неужели у нас всё так плохо с памятью?
                                                                           
                                                                                  cld             ; устанавливаем прямой порядок обработки строк
                                                                                  mov es,ax           ; ES = адрес нового блока
                                                                                  xor si,si
                                                                                  xor di,di
                                                                                  mov cx,(ProgEnd-@Startup+100h+1)/2
                                                                                  rep movsw           ; копируем наш код по новому адресу
                                                                           
                                                                                  push    es
                                                                                  pop ss          ; меняем SS на новый
                                                                           
                                                                                  push    es
                                                                                  push    offset @@Continue
                                                                                  retf                ; прыгаем по новому адресу :)
                                                                              @@Continue:
                                                                                  mov ah,50h
                                                                                  mov bx,es
                                                                                  int 21h         ; устанавливаем новый PSP
                                                                           
                                                                                  mov ah,49h
                                                                                  push    ds
                                                                                  pop es          ; ES = старый PSP
                                                                                  int 21h         ; освобождаем память, которую мы занимали ранее
                                                                           
                                                                                  push    cs
                                                                                  pop ds          ; DS = наш новый (текущий) PSP
                                                                           
                                                                                  mov ah,48h
                                                                                  mov bx,TSRParaSize
                                                                                  int 21h         ; ещё раз пытаемся выделить память нужного нам размера
                                                                                  jc  @@Error         ; ошибка... что за бред?
                                                                           
                                                                              @@Allocated:
                                                                                  ; Переносим наш код в выделенную память
                                                                                  sub ax,(TSRStart-@Startup+100h)/16
                                                                                  mov es,ax           ; ES = сегмент резидентного кода
                                                                                  mov word ptr es:[TSRStart-0Fh],40h  ; помечаем в MCB выделенный участок как принадлежащий сегменту 40h (этот сегмент принадлежит BIOS и никогда не будет освобождён)
                                                                           
                                                                                  mov si,offset TSRStart
                                                                                  mov di,si
                                                                                  mov cx,(TSRSize+1)/2
                                                                                  rep movsw           ; копируем наш резидентный код в выделенную память
                                                                           
                                                                           
                                                                                  ; Перехват прерываний
                                                                                  mov si,offset TSRTables
                                                                          IF  TSRIntCount gt 1
                                                                                  mov cx,TSRIntCount
                                                                              @@SetTSRLoop:
                                                                          ENDIF
                                                                                  lodsb               ; читаем номер прерывания
                                                                                  push    ax
                                                                                  push    es
                                                                                  mov ah,35h
                                                                                  int 21h         ; получаем старый обработчик в ES:BX
                                                                                  mov dx,es           ; сохраняем сегмент в DX
                                                                                  pop es
                                                                                  lodsw
                                                                                  xchg    di,ax           ; DI = адрес переменной
                                                                                  xchg    ax,bx
                                                                                  stosw               ; записываем в неё смещение
                                                                                  xchg    ax,dx
                                                                                  stosw               ; и сегмент
                                                                           
                                                                                  lodsw
                                                                                  xchg    dx,ax           ; DX = адрес нашего обработчика
                                                                                  pop ax          ; восстанавливаем номер прерывания
                                                                                  mov ah,25h
                                                                                  push    ds
                                                                                  push    es
                                                                                  pop ds          ; DS = ES = сегмент резидентного кода
                                                                                  int 21h         ; устанавливаем наш обработчик
                                                                                  pop ds
                                                                           
                                                                          IF  TSRIntCount gt 1
                                                                                  loop    @@SetTSRLoop        ; повторяем цикл
                                                                          ENDIF
                                                                                  mov dx,offset MsgTSRInstOk  ; сообщение, что всё ok
                                                                              @@Message:
                                                                                  mov ah,9
                                                                                  int 21h         ; выводим сообщение
                                                                           
                                                                                  int     20h         ; выходим из программы (int 27h нам тут не нужен, т.к. резидентный код находится в автономном блоке памяти, уже не связанном с текущей программой) :)
                                                                           
                                                                              @@Error:
                                                                                  mov dx,offset MsgTSRInstErr ; сообщение об ошибке
                                                                                  jmp @@Message
                                                                           
                                                                          TSRInstall  ENDP
                                                                           
                                                                          ;-----------------------------------------------------------------------------------------------------------------------
                                                                           
                                                                          ; Сообщения
                                                                          MsgTSRInstOk    DB  'TSR is successfully installed !!!',13,10,'$'
                                                                          MsgTSRAlrInst   DB  'TSR is already installed !!!',13,10,'$'
                                                                          MsgTSRInstErr   DB  'TSR installation is failed :(',13,10,'$'
                                                                           
                                                                          ProgEnd     =   $           ; конец всей нашей программы
                                                                          ProgParaSize    =   (ProgEnd-@Startup+15)/16    ; размер всей нашей программы (без PSP) в параграфах
                                                                           
                                                                          END

                                                                        Прикреплённый файлПрикреплённый файлTsrNoPsp.zip (3,76 Кбайт, скачиваний: 70)

                                                                        Старый: Прикреплённый файлПрикреплённый файлTsrNoPsp.zip (3,78 Кбайт, скачиваний: 87)
                                                                        Сообщение отредактировано: Jin X -
                                                                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                        0 пользователей:


                                                                        Рейтинг@Mail.ru
                                                                        [ Script execution time: 0,0905 ]   [ 24 queries used ]   [ Generated: 28.03.24, 19:59 GMT ]